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