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