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