1 /* 2 * Copyright (C) 2006 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.database; 18 19 import static java.util.Objects.requireNonNull; 20 21 import android.annotation.BytesLong; 22 import android.annotation.IntRange; 23 import android.compat.annotation.UnsupportedAppUsage; 24 import android.content.res.Resources; 25 import android.database.sqlite.SQLiteClosable; 26 import android.database.sqlite.SQLiteException; 27 import android.os.Parcel; 28 import android.os.Parcelable; 29 import android.ravenwood.annotation.RavenwoodKeepWholeClass; 30 import android.ravenwood.annotation.RavenwoodRedirect; 31 import android.ravenwood.annotation.RavenwoodRedirectionClass; 32 import android.ravenwood.annotation.RavenwoodThrow; 33 34 import dalvik.annotation.optimization.FastNative; 35 import dalvik.system.CloseGuard; 36 37 /** 38 * A buffer containing multiple cursor rows. 39 * <p> 40 * A {@link CursorWindow} is read-write when initially created and used locally. 41 * When sent to a remote process (by writing it to a {@link Parcel}), the remote process 42 * receives a read-only view of the cursor window. Typically the cursor window 43 * will be allocated by the producer, filled with data, and then sent to the 44 * consumer for reading. 45 * </p> 46 */ 47 @RavenwoodKeepWholeClass 48 @RavenwoodRedirectionClass("CursorWindow_ravenwood") 49 public class CursorWindow extends SQLiteClosable implements Parcelable { 50 private static final String STATS_TAG = "CursorWindowStats"; 51 52 // This static member will be evaluated when first used. 53 @UnsupportedAppUsage 54 private static int sCursorWindowSize = -1; 55 56 /** 57 * The native CursorWindow object pointer. (FOR INTERNAL USE ONLY) 58 * @hide 59 */ 60 @UnsupportedAppUsage 61 public long mWindowPtr; 62 63 private int mStartPos; 64 private final String mName; 65 66 private final CloseGuard mCloseGuard; 67 68 // May throw CursorWindowAllocationException 69 @RavenwoodRedirect nativeCreate(String name, int cursorWindowSize)70 private static native long nativeCreate(String name, int cursorWindowSize); 71 72 // May throw CursorWindowAllocationException 73 @RavenwoodRedirect nativeCreateFromParcel(Parcel parcel)74 private static native long nativeCreateFromParcel(Parcel parcel); 75 @RavenwoodRedirect nativeDispose(long windowPtr)76 private static native void nativeDispose(long windowPtr); 77 @RavenwoodRedirect nativeWriteToParcel(long windowPtr, Parcel parcel)78 private static native void nativeWriteToParcel(long windowPtr, Parcel parcel); 79 80 @RavenwoodRedirect nativeGetName(long windowPtr)81 private static native String nativeGetName(long windowPtr); 82 @RavenwoodRedirect nativeGetBlob(long windowPtr, int row, int column)83 private static native byte[] nativeGetBlob(long windowPtr, int row, int column); 84 @RavenwoodRedirect nativeGetString(long windowPtr, int row, int column)85 private static native String nativeGetString(long windowPtr, int row, int column); 86 @RavenwoodThrow nativeCopyStringToBuffer(long windowPtr, int row, int column, CharArrayBuffer buffer)87 private static native void nativeCopyStringToBuffer(long windowPtr, int row, int column, 88 CharArrayBuffer buffer); 89 @RavenwoodRedirect nativePutBlob(long windowPtr, byte[] value, int row, int column)90 private static native boolean nativePutBlob(long windowPtr, byte[] value, int row, int column); 91 @RavenwoodRedirect nativePutString(long windowPtr, String value, int row, int column)92 private static native boolean nativePutString(long windowPtr, String value, 93 int row, int column); 94 95 // Below native methods don't do unconstrained work, so are FastNative for performance 96 97 @FastNative 98 @RavenwoodThrow nativeClear(long windowPtr)99 private static native void nativeClear(long windowPtr); 100 101 @FastNative 102 @RavenwoodRedirect nativeGetNumRows(long windowPtr)103 private static native int nativeGetNumRows(long windowPtr); 104 @FastNative 105 @RavenwoodRedirect nativeSetNumColumns(long windowPtr, int columnNum)106 private static native boolean nativeSetNumColumns(long windowPtr, int columnNum); 107 @FastNative 108 @RavenwoodRedirect nativeAllocRow(long windowPtr)109 private static native boolean nativeAllocRow(long windowPtr); 110 @FastNative 111 @RavenwoodThrow nativeFreeLastRow(long windowPtr)112 private static native void nativeFreeLastRow(long windowPtr); 113 114 @FastNative 115 @RavenwoodRedirect nativeGetType(long windowPtr, int row, int column)116 private static native int nativeGetType(long windowPtr, int row, int column); 117 @FastNative 118 @RavenwoodRedirect nativeGetLong(long windowPtr, int row, int column)119 private static native long nativeGetLong(long windowPtr, int row, int column); 120 @FastNative 121 @RavenwoodRedirect nativeGetDouble(long windowPtr, int row, int column)122 private static native double nativeGetDouble(long windowPtr, int row, int column); 123 124 @FastNative 125 @RavenwoodRedirect nativePutLong(long windowPtr, long value, int row, int column)126 private static native boolean nativePutLong(long windowPtr, long value, int row, int column); 127 @FastNative 128 @RavenwoodRedirect nativePutDouble(long windowPtr, double value, int row, int column)129 private static native boolean nativePutDouble(long windowPtr, double value, int row, int column); 130 @FastNative 131 @RavenwoodThrow nativePutNull(long windowPtr, int row, int column)132 private static native boolean nativePutNull(long windowPtr, int row, int column); 133 134 135 /** 136 * Creates a new empty cursor window and gives it a name. 137 * <p> 138 * The cursor initially has no rows or columns. Call {@link #setNumColumns(int)} to 139 * set the number of columns before adding any rows to the cursor. 140 * </p> 141 * 142 * @param name The name of the cursor window, or null if none. 143 */ CursorWindow(String name)144 public CursorWindow(String name) { 145 this(name, getCursorWindowSize()); 146 } 147 148 /** 149 * Creates a new empty cursor window and gives it a name. 150 * <p> 151 * The cursor initially has no rows or columns. Call {@link #setNumColumns(int)} to 152 * set the number of columns before adding any rows to the cursor. 153 * </p> 154 * 155 * @param name The name of the cursor window, or null if none. 156 * @param windowSizeBytes Size of cursor window in bytes. 157 * @throws IllegalArgumentException if {@code windowSizeBytes} is less than 0 158 * @throws AssertionError if created window pointer is 0 159 * <p><strong>Note:</strong> Memory is dynamically allocated as data rows are added to the 160 * window. Depending on the amount of data stored, the actual amount of memory allocated can be 161 * lower than specified size, but cannot exceed it. 162 */ CursorWindow(String name, @BytesLong long windowSizeBytes)163 public CursorWindow(String name, @BytesLong long windowSizeBytes) { 164 if (windowSizeBytes < 0) { 165 throw new IllegalArgumentException("Window size cannot be less than 0"); 166 } 167 mStartPos = 0; 168 mName = name != null && name.length() != 0 ? name : "<unnamed>"; 169 mWindowPtr = nativeCreate(mName, (int) windowSizeBytes); 170 if (mWindowPtr == 0) { 171 throw new AssertionError(); // Not possible, the native code won't return it. 172 } 173 mCloseGuard = createCloseGuard(); 174 } 175 176 /** 177 * Creates a new empty cursor window. 178 * <p> 179 * The cursor initially has no rows or columns. Call {@link #setNumColumns(int)} to 180 * set the number of columns before adding any rows to the cursor. 181 * </p> 182 * 183 * @param localWindow True if this window will be used in this process only, 184 * false if it might be sent to another processes. This argument is ignored. 185 * 186 * @deprecated There is no longer a distinction between local and remote 187 * cursor windows. Use the {@link #CursorWindow(String)} constructor instead. 188 */ 189 @Deprecated CursorWindow(boolean localWindow)190 public CursorWindow(boolean localWindow) { 191 this((String)null); 192 } 193 CursorWindow(Parcel source)194 private CursorWindow(Parcel source) { 195 mStartPos = source.readInt(); 196 mWindowPtr = nativeCreateFromParcel(source); 197 if (mWindowPtr == 0) { 198 throw new AssertionError(); // Not possible, the native code won't return it. 199 } 200 mName = nativeGetName(mWindowPtr); 201 mCloseGuard = createCloseGuard(); 202 } 203 204 @android.ravenwood.annotation.RavenwoodReplace createCloseGuard()205 private CloseGuard createCloseGuard() { 206 final CloseGuard closeGuard = CloseGuard.get(); 207 closeGuard.open("CursorWindow.close"); 208 return closeGuard; 209 } 210 createCloseGuard$ravenwood()211 private CloseGuard createCloseGuard$ravenwood() { 212 return null; 213 } 214 215 @Override finalize()216 protected void finalize() throws Throwable { 217 try { 218 if (mCloseGuard != null) { 219 mCloseGuard.warnIfOpen(); 220 } 221 dispose(); 222 } finally { 223 super.finalize(); 224 } 225 } 226 dispose()227 private void dispose() { 228 if (mCloseGuard != null) { 229 mCloseGuard.close(); 230 } 231 if (mWindowPtr != 0) { 232 nativeDispose(mWindowPtr); 233 mWindowPtr = 0; 234 } 235 } 236 237 /** 238 * Gets the name of this cursor window, never null. 239 * @hide 240 */ getName()241 public String getName() { 242 return mName; 243 } 244 245 /** 246 * Clears out the existing contents of the window, making it safe to reuse 247 * for new data. 248 * <p> 249 * The start position ({@link #getStartPosition()}), number of rows ({@link #getNumRows()}), 250 * and number of columns in the cursor are all reset to zero. 251 * </p> 252 */ clear()253 public void clear() { 254 acquireReference(); 255 try { 256 mStartPos = 0; 257 nativeClear(mWindowPtr); 258 } finally { 259 releaseReference(); 260 } 261 } 262 263 /** 264 * Gets the start position of this cursor window. 265 * <p> 266 * The start position is the zero-based index of the first row that this window contains 267 * relative to the entire result set of the {@link Cursor}. 268 * </p> 269 * 270 * @return The zero-based start position. 271 */ getStartPosition()272 public @IntRange(from = 0) int getStartPosition() { 273 return mStartPos; 274 } 275 276 /** 277 * Sets the start position of this cursor window. 278 * <p> 279 * The start position is the zero-based index of the first row that this window contains 280 * relative to the entire result set of the {@link Cursor}. 281 * </p> 282 * 283 * @param pos The new zero-based start position. 284 */ setStartPosition(@ntRangefrom = 0) int pos)285 public void setStartPosition(@IntRange(from = 0) int pos) { 286 mStartPos = pos; 287 } 288 289 /** 290 * Gets the number of rows in this window. 291 * 292 * @return The number of rows in this cursor window. 293 */ getNumRows()294 public @IntRange(from = 0) int getNumRows() { 295 acquireReference(); 296 try { 297 return nativeGetNumRows(mWindowPtr); 298 } finally { 299 releaseReference(); 300 } 301 } 302 303 /** 304 * Sets the number of columns in this window. 305 * <p> 306 * This method must be called before any rows are added to the window, otherwise 307 * it will fail to set the number of columns if it differs from the current number 308 * of columns. 309 * </p> 310 * 311 * @param columnNum The new number of columns. 312 * @return True if successful. 313 */ setNumColumns(@ntRangefrom = 0) int columnNum)314 public boolean setNumColumns(@IntRange(from = 0) int columnNum) { 315 acquireReference(); 316 try { 317 return nativeSetNumColumns(mWindowPtr, columnNum); 318 } finally { 319 releaseReference(); 320 } 321 } 322 323 /** 324 * Allocates a new row at the end of this cursor window. 325 * 326 * @return True if successful, false if the cursor window is out of memory. 327 */ allocRow()328 public boolean allocRow(){ 329 acquireReference(); 330 try { 331 return nativeAllocRow(mWindowPtr); 332 } finally { 333 releaseReference(); 334 } 335 } 336 337 /** 338 * Frees the last row in this cursor window. 339 */ freeLastRow()340 public void freeLastRow(){ 341 acquireReference(); 342 try { 343 nativeFreeLastRow(mWindowPtr); 344 } finally { 345 releaseReference(); 346 } 347 } 348 349 /** 350 * Returns true if the field at the specified row and column index 351 * has type {@link Cursor#FIELD_TYPE_NULL}. 352 * 353 * @param row The zero-based row index. 354 * @param column The zero-based column index. 355 * @return True if the field has type {@link Cursor#FIELD_TYPE_NULL}. 356 * @deprecated Use {@link #getType(int, int)} instead. 357 */ 358 @Deprecated isNull(@ntRangefrom = 0) int row, @IntRange(from = 0) int column)359 public boolean isNull(@IntRange(from = 0) int row, @IntRange(from = 0) int column) { 360 return getType(row, column) == Cursor.FIELD_TYPE_NULL; 361 } 362 363 /** 364 * Returns true if the field at the specified row and column index 365 * has type {@link Cursor#FIELD_TYPE_BLOB} or {@link Cursor#FIELD_TYPE_NULL}. 366 * 367 * @param row The zero-based row index. 368 * @param column The zero-based column index. 369 * @return True if the field has type {@link Cursor#FIELD_TYPE_BLOB} or 370 * {@link Cursor#FIELD_TYPE_NULL}. 371 * @deprecated Use {@link #getType(int, int)} instead. 372 */ 373 @Deprecated isBlob(@ntRangefrom = 0) int row, @IntRange(from = 0) int column)374 public boolean isBlob(@IntRange(from = 0) int row, @IntRange(from = 0) int column) { 375 int type = getType(row, column); 376 return type == Cursor.FIELD_TYPE_BLOB || type == Cursor.FIELD_TYPE_NULL; 377 } 378 379 /** 380 * Returns true if the field at the specified row and column index 381 * has type {@link Cursor#FIELD_TYPE_INTEGER}. 382 * 383 * @param row The zero-based row index. 384 * @param column The zero-based column index. 385 * @return True if the field has type {@link Cursor#FIELD_TYPE_INTEGER}. 386 * @deprecated Use {@link #getType(int, int)} instead. 387 */ 388 @Deprecated isLong(@ntRangefrom = 0) int row, @IntRange(from = 0) int column)389 public boolean isLong(@IntRange(from = 0) int row, @IntRange(from = 0) int column) { 390 return getType(row, column) == Cursor.FIELD_TYPE_INTEGER; 391 } 392 393 /** 394 * Returns true if the field at the specified row and column index 395 * has type {@link Cursor#FIELD_TYPE_FLOAT}. 396 * 397 * @param row The zero-based row index. 398 * @param column The zero-based column index. 399 * @return True if the field has type {@link Cursor#FIELD_TYPE_FLOAT}. 400 * @deprecated Use {@link #getType(int, int)} instead. 401 */ 402 @Deprecated isFloat(@ntRangefrom = 0) int row, @IntRange(from = 0) int column)403 public boolean isFloat(@IntRange(from = 0) int row, @IntRange(from = 0) int column) { 404 return getType(row, column) == Cursor.FIELD_TYPE_FLOAT; 405 } 406 407 /** 408 * Returns true if the field at the specified row and column index 409 * has type {@link Cursor#FIELD_TYPE_STRING} or {@link Cursor#FIELD_TYPE_NULL}. 410 * 411 * @param row The zero-based row index. 412 * @param column The zero-based column index. 413 * @return True if the field has type {@link Cursor#FIELD_TYPE_STRING} 414 * or {@link Cursor#FIELD_TYPE_NULL}. 415 * @deprecated Use {@link #getType(int, int)} instead. 416 */ 417 @Deprecated isString(@ntRangefrom = 0) int row, @IntRange(from = 0) int column)418 public boolean isString(@IntRange(from = 0) int row, @IntRange(from = 0) int column) { 419 int type = getType(row, column); 420 return type == Cursor.FIELD_TYPE_STRING || type == Cursor.FIELD_TYPE_NULL; 421 } 422 423 /** 424 * Returns the type of the field at the specified row and column index. 425 * 426 * @param row The zero-based row index. 427 * @param column The zero-based column index. 428 * @return The field type. 429 */ getType(@ntRangefrom = 0) int row, @IntRange(from = 0) int column)430 public @Cursor.FieldType int getType(@IntRange(from = 0) int row, 431 @IntRange(from = 0) int column) { 432 acquireReference(); 433 try { 434 return nativeGetType(mWindowPtr, row - mStartPos, column); 435 } finally { 436 releaseReference(); 437 } 438 } 439 440 /** 441 * Gets the value of the field at the specified row and column index as a byte array. 442 * <p> 443 * The result is determined as follows: 444 * <ul> 445 * <li>If the field is of type {@link Cursor#FIELD_TYPE_NULL}, then the result 446 * is <code>null</code>.</li> 447 * <li>If the field is of type {@link Cursor#FIELD_TYPE_BLOB}, then the result 448 * is the blob value.</li> 449 * <li>If the field is of type {@link Cursor#FIELD_TYPE_STRING}, then the result 450 * is the array of bytes that make up the internal representation of the 451 * string value.</li> 452 * <li>If the field is of type {@link Cursor#FIELD_TYPE_INTEGER} or 453 * {@link Cursor#FIELD_TYPE_FLOAT}, then a {@link SQLiteException} is thrown.</li> 454 * </ul> 455 * </p> 456 * 457 * @param row The zero-based row index. 458 * @param column The zero-based column index. 459 * @return The value of the field as a byte array. 460 */ getBlob(@ntRangefrom = 0) int row, @IntRange(from = 0) int column)461 public byte[] getBlob(@IntRange(from = 0) int row, @IntRange(from = 0) int column) { 462 acquireReference(); 463 try { 464 return nativeGetBlob(mWindowPtr, row - mStartPos, column); 465 } finally { 466 releaseReference(); 467 } 468 } 469 470 /** 471 * Gets the value of the field at the specified row and column index as a string. 472 * <p> 473 * The result is determined as follows: 474 * <ul> 475 * <li>If the field is of type {@link Cursor#FIELD_TYPE_NULL}, then the result 476 * is <code>null</code>.</li> 477 * <li>If the field is of type {@link Cursor#FIELD_TYPE_STRING}, then the result 478 * is the string value.</li> 479 * <li>If the field is of type {@link Cursor#FIELD_TYPE_INTEGER}, then the result 480 * is a string representation of the integer in decimal, obtained by formatting the 481 * value with the <code>printf</code> family of functions using 482 * format specifier <code>%lld</code>.</li> 483 * <li>If the field is of type {@link Cursor#FIELD_TYPE_FLOAT}, then the result 484 * is a string representation of the floating-point value in decimal, obtained by 485 * formatting the value with the <code>printf</code> family of functions using 486 * format specifier <code>%g</code>.</li> 487 * <li>If the field is of type {@link Cursor#FIELD_TYPE_BLOB}, then a 488 * {@link SQLiteException} is thrown.</li> 489 * </ul> 490 * </p> 491 * 492 * @param row The zero-based row index. 493 * @param column The zero-based column index. 494 * @return The value of the field as a string. 495 */ getString(@ntRangefrom = 0) int row, @IntRange(from = 0) int column)496 public String getString(@IntRange(from = 0) int row, @IntRange(from = 0) int column) { 497 acquireReference(); 498 try { 499 return nativeGetString(mWindowPtr, row - mStartPos, column); 500 } finally { 501 releaseReference(); 502 } 503 } 504 505 /** 506 * Copies the text of the field at the specified row and column index into 507 * a {@link CharArrayBuffer}. 508 * <p> 509 * The buffer is populated as follows: 510 * <ul> 511 * <li>If the buffer is too small for the value to be copied, then it is 512 * automatically resized.</li> 513 * <li>If the field is of type {@link Cursor#FIELD_TYPE_NULL}, then the buffer 514 * is set to an empty string.</li> 515 * <li>If the field is of type {@link Cursor#FIELD_TYPE_STRING}, then the buffer 516 * is set to the contents of the string.</li> 517 * <li>If the field is of type {@link Cursor#FIELD_TYPE_INTEGER}, then the buffer 518 * is set to a string representation of the integer in decimal, obtained by formatting the 519 * value with the <code>printf</code> family of functions using 520 * format specifier <code>%lld</code>.</li> 521 * <li>If the field is of type {@link Cursor#FIELD_TYPE_FLOAT}, then the buffer is 522 * set to a string representation of the floating-point value in decimal, obtained by 523 * formatting the value with the <code>printf</code> family of functions using 524 * format specifier <code>%g</code>.</li> 525 * <li>If the field is of type {@link Cursor#FIELD_TYPE_BLOB}, then a 526 * {@link SQLiteException} is thrown.</li> 527 * </ul> 528 * </p> 529 * 530 * @param row The zero-based row index. 531 * @param column The zero-based column index. 532 * @param buffer The {@link CharArrayBuffer} to hold the string. It is automatically 533 * resized if the requested string is larger than the buffer's current capacity. 534 */ copyStringToBuffer(@ntRangefrom = 0) int row, @IntRange(from = 0) int column, CharArrayBuffer buffer)535 public void copyStringToBuffer(@IntRange(from = 0) int row, @IntRange(from = 0) int column, 536 CharArrayBuffer buffer) { 537 if (buffer == null) { 538 throw new IllegalArgumentException("CharArrayBuffer should not be null"); 539 } 540 acquireReference(); 541 try { 542 nativeCopyStringToBuffer(mWindowPtr, row - mStartPos, column, buffer); 543 } finally { 544 releaseReference(); 545 } 546 } 547 548 /** 549 * Gets the value of the field at the specified row and column index as a <code>long</code>. 550 * <p> 551 * The result is determined as follows: 552 * <ul> 553 * <li>If the field is of type {@link Cursor#FIELD_TYPE_NULL}, then the result 554 * is <code>0L</code>.</li> 555 * <li>If the field is of type {@link Cursor#FIELD_TYPE_STRING}, then the result 556 * is the value obtained by parsing the string value with <code>strtoll</code>. 557 * <li>If the field is of type {@link Cursor#FIELD_TYPE_INTEGER}, then the result 558 * is the <code>long</code> value.</li> 559 * <li>If the field is of type {@link Cursor#FIELD_TYPE_FLOAT}, then the result 560 * is the floating-point value converted to a <code>long</code>.</li> 561 * <li>If the field is of type {@link Cursor#FIELD_TYPE_BLOB}, then a 562 * {@link SQLiteException} is thrown.</li> 563 * </ul> 564 * </p> 565 * 566 * @param row The zero-based row index. 567 * @param column The zero-based column index. 568 * @return The value of the field as a <code>long</code>. 569 */ getLong(@ntRangefrom = 0) int row, @IntRange(from = 0) int column)570 public long getLong(@IntRange(from = 0) int row, @IntRange(from = 0) int column) { 571 acquireReference(); 572 try { 573 return nativeGetLong(mWindowPtr, row - mStartPos, column); 574 } finally { 575 releaseReference(); 576 } 577 } 578 579 /** 580 * Gets the value of the field at the specified row and column index as a 581 * <code>double</code>. 582 * <p> 583 * The result is determined as follows: 584 * <ul> 585 * <li>If the field is of type {@link Cursor#FIELD_TYPE_NULL}, then the result 586 * is <code>0.0</code>.</li> 587 * <li>If the field is of type {@link Cursor#FIELD_TYPE_STRING}, then the result 588 * is the value obtained by parsing the string value with <code>strtod</code>. 589 * <li>If the field is of type {@link Cursor#FIELD_TYPE_INTEGER}, then the result 590 * is the integer value converted to a <code>double</code>.</li> 591 * <li>If the field is of type {@link Cursor#FIELD_TYPE_FLOAT}, then the result 592 * is the <code>double</code> value.</li> 593 * <li>If the field is of type {@link Cursor#FIELD_TYPE_BLOB}, then a 594 * {@link SQLiteException} is thrown.</li> 595 * </ul> 596 * </p> 597 * 598 * @param row The zero-based row index. 599 * @param column The zero-based column index. 600 * @return The value of the field as a <code>double</code>. 601 */ getDouble(@ntRangefrom = 0) int row, @IntRange(from = 0) int column)602 public double getDouble(@IntRange(from = 0) int row, @IntRange(from = 0) int column) { 603 acquireReference(); 604 try { 605 return nativeGetDouble(mWindowPtr, row - mStartPos, column); 606 } finally { 607 releaseReference(); 608 } 609 } 610 611 /** 612 * Gets the value of the field at the specified row and column index as a 613 * <code>short</code>. 614 * <p> 615 * The result is determined by invoking {@link #getLong} and converting the 616 * result to <code>short</code>. 617 * </p> 618 * 619 * @param row The zero-based row index. 620 * @param column The zero-based column index. 621 * @return The value of the field as a <code>short</code>. 622 */ getShort(@ntRangefrom = 0) int row, @IntRange(from = 0) int column)623 public short getShort(@IntRange(from = 0) int row, @IntRange(from = 0) int column) { 624 return (short) getLong(row, column); 625 } 626 627 /** 628 * Gets the value of the field at the specified row and column index as an 629 * <code>int</code>. 630 * <p> 631 * The result is determined by invoking {@link #getLong} and converting the 632 * result to <code>int</code>. 633 * </p> 634 * 635 * @param row The zero-based row index. 636 * @param column The zero-based column index. 637 * @return The value of the field as an <code>int</code>. 638 */ getInt(@ntRangefrom = 0) int row, @IntRange(from = 0) int column)639 public int getInt(@IntRange(from = 0) int row, @IntRange(from = 0) int column) { 640 return (int) getLong(row, column); 641 } 642 643 /** 644 * Gets the value of the field at the specified row and column index as a 645 * <code>float</code>. 646 * <p> 647 * The result is determined by invoking {@link #getDouble} and converting the 648 * result to <code>float</code>. 649 * </p> 650 * 651 * @param row The zero-based row index. 652 * @param column The zero-based column index. 653 * @return The value of the field as an <code>float</code>. 654 */ getFloat(@ntRangefrom = 0) int row, @IntRange(from = 0) int column)655 public float getFloat(@IntRange(from = 0) int row, @IntRange(from = 0) int column) { 656 return (float) getDouble(row, column); 657 } 658 659 /** 660 * Copies a byte array into the field at the specified row and column index. 661 * 662 * @param value The value to store. 663 * @param row The zero-based row index. 664 * @param column The zero-based column index. 665 * @return True if successful. 666 */ putBlob(byte[] value, @IntRange(from = 0) int row, @IntRange(from = 0) int column)667 public boolean putBlob(byte[] value, 668 @IntRange(from = 0) int row, @IntRange(from = 0) int column) { 669 requireNonNull(value); 670 acquireReference(); 671 try { 672 return nativePutBlob(mWindowPtr, value, row - mStartPos, column); 673 } finally { 674 releaseReference(); 675 } 676 } 677 678 /** 679 * Copies a string into the field at the specified row and column index. 680 * 681 * @param value The value to store. 682 * @param row The zero-based row index. 683 * @param column The zero-based column index. 684 * @return True if successful. 685 */ putString(String value, @IntRange(from = 0) int row, @IntRange(from = 0) int column)686 public boolean putString(String value, 687 @IntRange(from = 0) int row, @IntRange(from = 0) int column) { 688 requireNonNull(value); 689 acquireReference(); 690 try { 691 return nativePutString(mWindowPtr, value, row - mStartPos, column); 692 } finally { 693 releaseReference(); 694 } 695 } 696 697 /** 698 * Puts a long integer into the field at the specified row and column index. 699 * 700 * @param value The value to store. 701 * @param row The zero-based row index. 702 * @param column The zero-based column index. 703 * @return True if successful. 704 */ putLong(long value, @IntRange(from = 0) int row, @IntRange(from = 0) int column)705 public boolean putLong(long value, 706 @IntRange(from = 0) int row, @IntRange(from = 0) int column) { 707 acquireReference(); 708 try { 709 return nativePutLong(mWindowPtr, value, row - mStartPos, column); 710 } finally { 711 releaseReference(); 712 } 713 } 714 715 /** 716 * Puts a double-precision floating point value into the field at the 717 * specified row and column index. 718 * 719 * @param value The value to store. 720 * @param row The zero-based row index. 721 * @param column The zero-based column index. 722 * @return True if successful. 723 */ putDouble(double value, @IntRange(from = 0) int row, @IntRange(from = 0) int column)724 public boolean putDouble(double value, 725 @IntRange(from = 0) int row, @IntRange(from = 0) int column) { 726 acquireReference(); 727 try { 728 return nativePutDouble(mWindowPtr, value, row - mStartPos, column); 729 } finally { 730 releaseReference(); 731 } 732 } 733 734 /** 735 * Puts a null value into the field at the specified row and column index. 736 * 737 * @param row The zero-based row index. 738 * @param column The zero-based column index. 739 * @return True if successful. 740 */ putNull(@ntRangefrom = 0) int row, @IntRange(from = 0) int column)741 public boolean putNull(@IntRange(from = 0) int row, @IntRange(from = 0) int column) { 742 acquireReference(); 743 try { 744 return nativePutNull(mWindowPtr, row - mStartPos, column); 745 } finally { 746 releaseReference(); 747 } 748 } 749 750 public static final @android.annotation.NonNull Parcelable.Creator<CursorWindow> CREATOR 751 = new Parcelable.Creator<CursorWindow>() { 752 public CursorWindow createFromParcel(Parcel source) { 753 return new CursorWindow(source); 754 } 755 756 public CursorWindow[] newArray(int size) { 757 return new CursorWindow[size]; 758 } 759 }; 760 newFromParcel(Parcel p)761 public static CursorWindow newFromParcel(Parcel p) { 762 return CREATOR.createFromParcel(p); 763 } 764 describeContents()765 public int describeContents() { 766 return 0; 767 } 768 writeToParcel(Parcel dest, int flags)769 public void writeToParcel(Parcel dest, int flags) { 770 acquireReference(); 771 try { 772 dest.writeInt(mStartPos); 773 nativeWriteToParcel(mWindowPtr, dest); 774 } finally { 775 releaseReference(); 776 } 777 778 if ((flags & Parcelable.PARCELABLE_WRITE_RETURN_VALUE) != 0) { 779 releaseReference(); 780 } 781 } 782 783 @Override onAllReferencesReleased()784 protected void onAllReferencesReleased() { 785 dispose(); 786 } 787 788 @android.ravenwood.annotation.RavenwoodReplace getCursorWindowSize()789 private static int getCursorWindowSize() { 790 if (sCursorWindowSize < 0) { 791 // The cursor window size. resource xml file specifies the value in kB. 792 // convert it to bytes here by multiplying with 1024. 793 sCursorWindowSize = Resources.getSystem().getInteger( 794 com.android.internal.R.integer.config_cursorWindowSize) * 1024; 795 } 796 return sCursorWindowSize; 797 } 798 getCursorWindowSize$ravenwood()799 private static int getCursorWindowSize$ravenwood() { 800 return 1024; 801 } 802 803 @Override toString()804 public String toString() { 805 return getName() + " {" + Long.toHexString(mWindowPtr) + "}"; 806 } 807 } 808