blob: 44bd88376c4fd3c39ef9f3836ceda6270ed9a70e [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
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
17package android.database;
18
Fyodor Kupolov6bb32a92017-10-10 10:36:43 -070019import android.annotation.BytesLong;
Mathew Inwood41b31942018-08-10 16:00:53 +010020import android.annotation.UnsupportedAppUsage;
Vasu Nori34ad57f02010-12-21 09:32:36 -080021import android.content.res.Resources;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080022import android.database.sqlite.SQLiteClosable;
Jeff Brown3bc6bbc2011-10-06 13:11:04 -070023import android.database.sqlite.SQLiteException;
Vasu Nori6141e132010-12-23 20:46:46 -080024import android.os.Binder;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080025import android.os.Parcel;
26import android.os.Parcelable;
Vasu Nori6141e132010-12-23 20:46:46 -080027import android.os.Process;
28import android.util.Log;
Ashok Bhat738702d2014-01-02 13:42:56 +000029import android.util.LongSparseArray;
Fyodor Kupolov6bb32a92017-10-10 10:36:43 -070030import android.util.SparseIntArray;
31
Chris Craik0834e352017-06-16 10:34:11 -070032import dalvik.annotation.optimization.FastNative;
Fyodor Kupolov6bb32a92017-10-10 10:36:43 -070033import dalvik.system.CloseGuard;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080034
35/**
36 * A buffer containing multiple cursor rows.
Jeff Brown0cde89f2011-10-10 14:50:10 -070037 * <p>
Jeff Brown5e5d6d82011-10-12 15:41:34 -070038 * A {@link CursorWindow} is read-write when initially created and used locally.
39 * When sent to a remote process (by writing it to a {@link Parcel}), the remote process
Jeff Brown0cde89f2011-10-10 14:50:10 -070040 * receives a read-only view of the cursor window. Typically the cursor window
41 * will be allocated by the producer, filled with data, and then sent to the
42 * consumer for reading.
43 * </p>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080044 */
45public class CursorWindow extends SQLiteClosable implements Parcelable {
Vasu Nori6141e132010-12-23 20:46:46 -080046 private static final String STATS_TAG = "CursorWindowStats";
47
yingying1ec4f362014-05-07 17:12:25 +080048 // This static member will be evaluated when first used.
Mathew Inwood41b31942018-08-10 16:00:53 +010049 @UnsupportedAppUsage
yingying1ec4f362014-05-07 17:12:25 +080050 private static int sCursorWindowSize = -1;
Vasu Nori34ad57f02010-12-21 09:32:36 -080051
Jeff Brown3bc6bbc2011-10-06 13:11:04 -070052 /**
53 * The native CursorWindow object pointer. (FOR INTERNAL USE ONLY)
54 * @hide
Vasu Nori6141e132010-12-23 20:46:46 -080055 */
Mathew Inwood41b31942018-08-10 16:00:53 +010056 @UnsupportedAppUsage
Ashok Bhat738702d2014-01-02 13:42:56 +000057 public long mWindowPtr;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080058
59 private int mStartPos;
Jeff Brown650de3d2011-10-27 14:52:28 -070060 private final String mName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080061
Jeff Brownd2183652011-10-09 12:39:53 -070062 private final CloseGuard mCloseGuard = CloseGuard.get();
63
Ashok Bhat738702d2014-01-02 13:42:56 +000064 private static native long nativeCreate(String name, int cursorWindowSize);
65 private static native long nativeCreateFromParcel(Parcel parcel);
66 private static native void nativeDispose(long windowPtr);
67 private static native void nativeWriteToParcel(long windowPtr, Parcel parcel);
Jeff Brown3bc6bbc2011-10-06 13:11:04 -070068
Chris Craik0834e352017-06-16 10:34:11 -070069 private static native String nativeGetName(long windowPtr);
Ashok Bhat738702d2014-01-02 13:42:56 +000070 private static native byte[] nativeGetBlob(long windowPtr, int row, int column);
71 private static native String nativeGetString(long windowPtr, int row, int column);
Ashok Bhat738702d2014-01-02 13:42:56 +000072 private static native void nativeCopyStringToBuffer(long windowPtr, int row, int column,
Jeff Brown3bc6bbc2011-10-06 13:11:04 -070073 CharArrayBuffer buffer);
Ashok Bhat738702d2014-01-02 13:42:56 +000074 private static native boolean nativePutBlob(long windowPtr, byte[] value, int row, int column);
Chris Craik0834e352017-06-16 10:34:11 -070075 private static native boolean nativePutString(long windowPtr, String value,
76 int row, int column);
77
78 // Below native methods don't do unconstrained work, so are FastNative for performance
79
80 @FastNative
81 private static native void nativeClear(long windowPtr);
82
83 @FastNative
84 private static native int nativeGetNumRows(long windowPtr);
85 @FastNative
86 private static native boolean nativeSetNumColumns(long windowPtr, int columnNum);
87 @FastNative
88 private static native boolean nativeAllocRow(long windowPtr);
89 @FastNative
90 private static native void nativeFreeLastRow(long windowPtr);
91
92 @FastNative
93 private static native int nativeGetType(long windowPtr, int row, int column);
94 @FastNative
95 private static native long nativeGetLong(long windowPtr, int row, int column);
96 @FastNative
97 private static native double nativeGetDouble(long windowPtr, int row, int column);
98
99 @FastNative
Ashok Bhat738702d2014-01-02 13:42:56 +0000100 private static native boolean nativePutLong(long windowPtr, long value, int row, int column);
Chris Craik0834e352017-06-16 10:34:11 -0700101 @FastNative
Ashok Bhat738702d2014-01-02 13:42:56 +0000102 private static native boolean nativePutDouble(long windowPtr, double value, int row, int column);
Chris Craik0834e352017-06-16 10:34:11 -0700103 @FastNative
Ashok Bhat738702d2014-01-02 13:42:56 +0000104 private static native boolean nativePutNull(long windowPtr, int row, int column);
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700105
Jeff Brown650de3d2011-10-27 14:52:28 -0700106
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800107 /**
Jeff Brown0cde89f2011-10-10 14:50:10 -0700108 * Creates a new empty cursor window and gives it a name.
109 * <p>
110 * The cursor initially has no rows or columns. Call {@link #setNumColumns(int)} to
111 * set the number of columns before adding any rows to the cursor.
112 * </p>
113 *
114 * @param name The name of the cursor window, or null if none.
Jeff Brown0cde89f2011-10-10 14:50:10 -0700115 */
Jeff Brown5e5d6d82011-10-12 15:41:34 -0700116 public CursorWindow(String name) {
Fyodor Kupolov6bb32a92017-10-10 10:36:43 -0700117 this(name, getCursorWindowSize());
118 }
119
120 /**
121 * Creates a new empty cursor window and gives it a name.
122 * <p>
123 * The cursor initially has no rows or columns. Call {@link #setNumColumns(int)} to
124 * set the number of columns before adding any rows to the cursor.
125 * </p>
126 *
127 * @param name The name of the cursor window, or null if none.
128 * @param windowSizeBytes Size of cursor window in bytes.
129 * <p><strong>Note:</strong> Memory is dynamically allocated as data rows are added to the
130 * window. Depending on the amount of data stored, the actual amount of memory allocated can be
131 * lower than specified size, but cannot exceed it.
132 */
133 public CursorWindow(String name, @BytesLong long windowSizeBytes) {
Jeff Brown0cde89f2011-10-10 14:50:10 -0700134 mStartPos = 0;
Jeff Brown5a05c232012-01-12 12:04:22 -0800135 mName = name != null && name.length() != 0 ? name : "<unnamed>";
Fyodor Kupolov6bb32a92017-10-10 10:36:43 -0700136 mWindowPtr = nativeCreate(mName, (int) windowSizeBytes);
Jeff Brown0cde89f2011-10-10 14:50:10 -0700137 if (mWindowPtr == 0) {
138 throw new CursorWindowAllocationException("Cursor window allocation of " +
Fyodor Kupolov6bb32a92017-10-10 10:36:43 -0700139 windowSizeBytes + " bytes failed. " + printStats());
Jeff Brown0cde89f2011-10-10 14:50:10 -0700140 }
141 mCloseGuard.open("close");
142 recordNewWindow(Binder.getCallingPid(), mWindowPtr);
143 }
144
145 /**
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700146 * Creates a new empty cursor window.
147 * <p>
148 * The cursor initially has no rows or columns. Call {@link #setNumColumns(int)} to
149 * set the number of columns before adding any rows to the cursor.
150 * </p>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800151 *
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700152 * @param localWindow True if this window will be used in this process only,
Jeff Brown5e5d6d82011-10-12 15:41:34 -0700153 * false if it might be sent to another processes. This argument is ignored.
154 *
155 * @deprecated There is no longer a distinction between local and remote
156 * cursor windows. Use the {@link #CursorWindow(String)} constructor instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800157 */
Jeff Brown5e5d6d82011-10-12 15:41:34 -0700158 @Deprecated
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800159 public CursorWindow(boolean localWindow) {
Jeff Brown5e5d6d82011-10-12 15:41:34 -0700160 this((String)null);
Vasu Nori6141e132010-12-23 20:46:46 -0800161 }
162
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700163 private CursorWindow(Parcel source) {
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700164 mStartPos = source.readInt();
Jeff Brown0cde89f2011-10-10 14:50:10 -0700165 mWindowPtr = nativeCreateFromParcel(source);
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700166 if (mWindowPtr == 0) {
167 throw new CursorWindowAllocationException("Cursor window could not be "
168 + "created from binder.");
169 }
Jeff Brown650de3d2011-10-27 14:52:28 -0700170 mName = nativeGetName(mWindowPtr);
Jeff Brownd2183652011-10-09 12:39:53 -0700171 mCloseGuard.open("close");
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700172 }
173
174 @Override
Jeff Brown7ce74522011-10-07 13:29:37 -0700175 protected void finalize() throws Throwable {
176 try {
Jeff Brownd2183652011-10-09 12:39:53 -0700177 if (mCloseGuard != null) {
178 mCloseGuard.warnIfOpen();
179 }
Jeff Brown7ce74522011-10-07 13:29:37 -0700180 dispose();
181 } finally {
182 super.finalize();
183 }
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700184 }
185
186 private void dispose() {
Jeff Brownd2183652011-10-09 12:39:53 -0700187 if (mCloseGuard != null) {
188 mCloseGuard.close();
189 }
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700190 if (mWindowPtr != 0) {
191 recordClosingOfWindow(mWindowPtr);
192 nativeDispose(mWindowPtr);
193 mWindowPtr = 0;
Vasu Nori6141e132010-12-23 20:46:46 -0800194 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800195 }
196
197 /**
Jeff Brown5a05c232012-01-12 12:04:22 -0800198 * Gets the name of this cursor window, never null.
Jeff Brown650de3d2011-10-27 14:52:28 -0700199 * @hide
200 */
201 public String getName() {
202 return mName;
203 }
204
205 /**
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700206 * Clears out the existing contents of the window, making it safe to reuse
207 * for new data.
208 * <p>
209 * The start position ({@link #getStartPosition()}), number of rows ({@link #getNumRows()}),
210 * and number of columns in the cursor are all reset to zero.
211 * </p>
212 */
213 public void clear() {
214 acquireReference();
215 try {
216 mStartPos = 0;
217 nativeClear(mWindowPtr);
218 } finally {
219 releaseReference();
220 }
221 }
222
223 /**
224 * Gets the start position of this cursor window.
Jeff Brown7ce74522011-10-07 13:29:37 -0700225 * <p>
226 * The start position is the zero-based index of the first row that this window contains
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700227 * relative to the entire result set of the {@link Cursor}.
Jeff Brown7ce74522011-10-07 13:29:37 -0700228 * </p>
Brad Fitzpatrick9ffdfa02010-03-09 13:18:02 -0800229 *
Jeff Brown7ce74522011-10-07 13:29:37 -0700230 * @return The zero-based start position.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800231 */
232 public int getStartPosition() {
233 return mStartPos;
234 }
235
236 /**
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700237 * Sets the start position of this cursor window.
Jeff Brown7ce74522011-10-07 13:29:37 -0700238 * <p>
239 * The start position is the zero-based index of the first row that this window contains
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700240 * relative to the entire result set of the {@link Cursor}.
Jeff Brown7ce74522011-10-07 13:29:37 -0700241 * </p>
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700242 *
Jeff Brown7ce74522011-10-07 13:29:37 -0700243 * @param pos The new zero-based start position.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800244 */
245 public void setStartPosition(int pos) {
246 mStartPos = pos;
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700247 }
248
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800249 /**
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700250 * Gets the number of rows in this window.
251 *
252 * @return The number of rows in this cursor window.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800253 */
254 public int getNumRows() {
255 acquireReference();
256 try {
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700257 return nativeGetNumRows(mWindowPtr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800258 } finally {
259 releaseReference();
260 }
261 }
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700262
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800263 /**
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700264 * Sets the number of columns in this window.
265 * <p>
266 * This method must be called before any rows are added to the window, otherwise
267 * it will fail to set the number of columns if it differs from the current number
268 * of columns.
269 * </p>
270 *
271 * @param columnNum The new number of columns.
272 * @return True if successful.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800273 */
274 public boolean setNumColumns(int columnNum) {
275 acquireReference();
276 try {
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700277 return nativeSetNumColumns(mWindowPtr, columnNum);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800278 } finally {
279 releaseReference();
280 }
281 }
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700282
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800283 /**
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700284 * Allocates a new row at the end of this cursor window.
285 *
286 * @return True if successful, false if the cursor window is out of memory.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800287 */
288 public boolean allocRow(){
289 acquireReference();
290 try {
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700291 return nativeAllocRow(mWindowPtr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800292 } finally {
293 releaseReference();
294 }
295 }
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700296
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800297 /**
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700298 * Frees the last row in this cursor window.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800299 */
300 public void freeLastRow(){
301 acquireReference();
302 try {
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700303 nativeFreeLastRow(mWindowPtr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800304 } finally {
305 releaseReference();
306 }
307 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800308
309 /**
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700310 * Returns true if the field at the specified row and column index
311 * has type {@link Cursor#FIELD_TYPE_NULL}.
312 *
Jeff Brown80e7b802011-10-12 17:42:41 -0700313 * @param row The zero-based row index.
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700314 * @param column The zero-based column index.
315 * @return True if the field has type {@link Cursor#FIELD_TYPE_NULL}.
316 * @deprecated Use {@link #getType(int, int)} instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800317 */
Vasu Nori8b0dd7d2010-05-18 11:54:31 -0700318 @Deprecated
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700319 public boolean isNull(int row, int column) {
320 return getType(row, column) == Cursor.FIELD_TYPE_NULL;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800321 }
322
Daniel Trebbienadf41942010-10-31 12:21:05 -0700323 /**
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700324 * Returns true if the field at the specified row and column index
325 * has type {@link Cursor#FIELD_TYPE_BLOB} or {@link Cursor#FIELD_TYPE_NULL}.
Daniel Trebbienadf41942010-10-31 12:21:05 -0700326 *
Jeff Brown80e7b802011-10-12 17:42:41 -0700327 * @param row The zero-based row index.
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700328 * @param column The zero-based column index.
329 * @return True if the field has type {@link Cursor#FIELD_TYPE_BLOB} or
330 * {@link Cursor#FIELD_TYPE_NULL}.
331 * @deprecated Use {@link #getType(int, int)} instead.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800332 */
Vasu Nori8b0dd7d2010-05-18 11:54:31 -0700333 @Deprecated
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700334 public boolean isBlob(int row, int column) {
335 int type = getType(row, column);
Vasu Nori0a2c6cc2010-06-14 15:57:30 -0700336 return type == Cursor.FIELD_TYPE_BLOB || type == Cursor.FIELD_TYPE_NULL;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800337 }
338
Fred Quintana03d94902009-05-22 14:23:31 -0700339 /**
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700340 * Returns true if the field at the specified row and column index
341 * has type {@link Cursor#FIELD_TYPE_INTEGER}.
Fred Quintana03d94902009-05-22 14:23:31 -0700342 *
Jeff Brown80e7b802011-10-12 17:42:41 -0700343 * @param row The zero-based row index.
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700344 * @param column The zero-based column index.
345 * @return True if the field has type {@link Cursor#FIELD_TYPE_INTEGER}.
346 * @deprecated Use {@link #getType(int, int)} instead.
Fred Quintana03d94902009-05-22 14:23:31 -0700347 */
Vasu Nori8b0dd7d2010-05-18 11:54:31 -0700348 @Deprecated
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700349 public boolean isLong(int row, int column) {
350 return getType(row, column) == Cursor.FIELD_TYPE_INTEGER;
Fred Quintana03d94902009-05-22 14:23:31 -0700351 }
352
353 /**
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700354 * Returns true if the field at the specified row and column index
355 * has type {@link Cursor#FIELD_TYPE_FLOAT}.
Fred Quintana03d94902009-05-22 14:23:31 -0700356 *
Jeff Brown80e7b802011-10-12 17:42:41 -0700357 * @param row The zero-based row index.
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700358 * @param column The zero-based column index.
359 * @return True if the field has type {@link Cursor#FIELD_TYPE_FLOAT}.
360 * @deprecated Use {@link #getType(int, int)} instead.
Fred Quintana03d94902009-05-22 14:23:31 -0700361 */
Vasu Nori8b0dd7d2010-05-18 11:54:31 -0700362 @Deprecated
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700363 public boolean isFloat(int row, int column) {
364 return getType(row, column) == Cursor.FIELD_TYPE_FLOAT;
Fred Quintana03d94902009-05-22 14:23:31 -0700365 }
366
367 /**
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700368 * Returns true if the field at the specified row and column index
369 * has type {@link Cursor#FIELD_TYPE_STRING} or {@link Cursor#FIELD_TYPE_NULL}.
Fred Quintana03d94902009-05-22 14:23:31 -0700370 *
Jeff Brown80e7b802011-10-12 17:42:41 -0700371 * @param row The zero-based row index.
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700372 * @param column The zero-based column index.
373 * @return True if the field has type {@link Cursor#FIELD_TYPE_STRING}
374 * or {@link Cursor#FIELD_TYPE_NULL}.
375 * @deprecated Use {@link #getType(int, int)} instead.
Fred Quintana03d94902009-05-22 14:23:31 -0700376 */
Vasu Nori8b0dd7d2010-05-18 11:54:31 -0700377 @Deprecated
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700378 public boolean isString(int row, int column) {
379 int type = getType(row, column);
Vasu Nori0a2c6cc2010-06-14 15:57:30 -0700380 return type == Cursor.FIELD_TYPE_STRING || type == Cursor.FIELD_TYPE_NULL;
Fred Quintana03d94902009-05-22 14:23:31 -0700381 }
382
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800383 /**
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700384 * Returns the type of the field at the specified row and column index.
385 * <p>
386 * The returned field types are:
387 * <ul>
388 * <li>{@link Cursor#FIELD_TYPE_NULL}</li>
389 * <li>{@link Cursor#FIELD_TYPE_INTEGER}</li>
390 * <li>{@link Cursor#FIELD_TYPE_FLOAT}</li>
391 * <li>{@link Cursor#FIELD_TYPE_STRING}</li>
392 * <li>{@link Cursor#FIELD_TYPE_BLOB}</li>
393 * </ul>
394 * </p>
395 *
Jeff Brown80e7b802011-10-12 17:42:41 -0700396 * @param row The zero-based row index.
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700397 * @param column The zero-based column index.
398 * @return The field type.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800399 */
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700400 public int getType(int row, int column) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800401 acquireReference();
402 try {
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700403 return nativeGetType(mWindowPtr, row - mStartPos, column);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800404 } finally {
405 releaseReference();
406 }
407 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800408
409 /**
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700410 * Gets the value of the field at the specified row and column index as a byte array.
411 * <p>
412 * The result is determined as follows:
413 * <ul>
414 * <li>If the field is of type {@link Cursor#FIELD_TYPE_NULL}, then the result
415 * is <code>null</code>.</li>
416 * <li>If the field is of type {@link Cursor#FIELD_TYPE_BLOB}, then the result
417 * is the blob value.</li>
418 * <li>If the field is of type {@link Cursor#FIELD_TYPE_STRING}, then the result
419 * is the array of bytes that make up the internal representation of the
420 * string value.</li>
421 * <li>If the field is of type {@link Cursor#FIELD_TYPE_INTEGER} or
422 * {@link Cursor#FIELD_TYPE_FLOAT}, then a {@link SQLiteException} is thrown.</li>
423 * </ul>
424 * </p>
425 *
Jeff Brown80e7b802011-10-12 17:42:41 -0700426 * @param row The zero-based row index.
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700427 * @param column The zero-based column index.
428 * @return The value of the field as a byte array.
429 */
430 public byte[] getBlob(int row, int column) {
431 acquireReference();
432 try {
433 return nativeGetBlob(mWindowPtr, row - mStartPos, column);
434 } finally {
435 releaseReference();
436 }
437 }
438
439 /**
440 * Gets the value of the field at the specified row and column index as a string.
441 * <p>
442 * The result is determined as follows:
443 * <ul>
444 * <li>If the field is of type {@link Cursor#FIELD_TYPE_NULL}, then the result
445 * is <code>null</code>.</li>
446 * <li>If the field is of type {@link Cursor#FIELD_TYPE_STRING}, then the result
447 * is the string value.</li>
448 * <li>If the field is of type {@link Cursor#FIELD_TYPE_INTEGER}, then the result
449 * is a string representation of the integer in decimal, obtained by formatting the
450 * value with the <code>printf</code> family of functions using
451 * format specifier <code>%lld</code>.</li>
452 * <li>If the field is of type {@link Cursor#FIELD_TYPE_FLOAT}, then the result
453 * is a string representation of the floating-point value in decimal, obtained by
454 * formatting the value with the <code>printf</code> family of functions using
455 * format specifier <code>%g</code>.</li>
456 * <li>If the field is of type {@link Cursor#FIELD_TYPE_BLOB}, then a
457 * {@link SQLiteException} is thrown.</li>
458 * </ul>
459 * </p>
460 *
Jeff Brown80e7b802011-10-12 17:42:41 -0700461 * @param row The zero-based row index.
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700462 * @param column The zero-based column index.
463 * @return The value of the field as a string.
464 */
465 public String getString(int row, int column) {
466 acquireReference();
467 try {
468 return nativeGetString(mWindowPtr, row - mStartPos, column);
469 } finally {
470 releaseReference();
471 }
472 }
473
474 /**
475 * Copies the text of the field at the specified row and column index into
476 * a {@link CharArrayBuffer}.
477 * <p>
478 * The buffer is populated as follows:
479 * <ul>
480 * <li>If the buffer is too small for the value to be copied, then it is
481 * automatically resized.</li>
482 * <li>If the field is of type {@link Cursor#FIELD_TYPE_NULL}, then the buffer
483 * is set to an empty string.</li>
484 * <li>If the field is of type {@link Cursor#FIELD_TYPE_STRING}, then the buffer
485 * is set to the contents of the string.</li>
486 * <li>If the field is of type {@link Cursor#FIELD_TYPE_INTEGER}, then the buffer
487 * is set to a string representation of the integer in decimal, obtained by formatting the
488 * value with the <code>printf</code> family of functions using
489 * format specifier <code>%lld</code>.</li>
490 * <li>If the field is of type {@link Cursor#FIELD_TYPE_FLOAT}, then the buffer is
491 * set to a string representation of the floating-point value in decimal, obtained by
492 * formatting the value with the <code>printf</code> family of functions using
493 * format specifier <code>%g</code>.</li>
494 * <li>If the field is of type {@link Cursor#FIELD_TYPE_BLOB}, then a
495 * {@link SQLiteException} is thrown.</li>
496 * </ul>
497 * </p>
498 *
Jeff Brown80e7b802011-10-12 17:42:41 -0700499 * @param row The zero-based row index.
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700500 * @param column The zero-based column index.
501 * @param buffer The {@link CharArrayBuffer} to hold the string. It is automatically
502 * resized if the requested string is larger than the buffer's current capacity.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800503 */
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700504 public void copyStringToBuffer(int row, int column, CharArrayBuffer buffer) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800505 if (buffer == null) {
506 throw new IllegalArgumentException("CharArrayBuffer should not be null");
507 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800508 acquireReference();
509 try {
Jeff Brown07720072011-10-27 19:12:31 -0700510 nativeCopyStringToBuffer(mWindowPtr, row - mStartPos, column, buffer);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800511 } finally {
512 releaseReference();
513 }
514 }
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700515
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800516 /**
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700517 * Gets the value of the field at the specified row and column index as a <code>long</code>.
518 * <p>
519 * The result is determined as follows:
520 * <ul>
521 * <li>If the field is of type {@link Cursor#FIELD_TYPE_NULL}, then the result
522 * is <code>0L</code>.</li>
523 * <li>If the field is of type {@link Cursor#FIELD_TYPE_STRING}, then the result
524 * is the value obtained by parsing the string value with <code>strtoll</code>.
525 * <li>If the field is of type {@link Cursor#FIELD_TYPE_INTEGER}, then the result
526 * is the <code>long</code> value.</li>
527 * <li>If the field is of type {@link Cursor#FIELD_TYPE_FLOAT}, then the result
528 * is the floating-point value converted to a <code>long</code>.</li>
529 * <li>If the field is of type {@link Cursor#FIELD_TYPE_BLOB}, then a
530 * {@link SQLiteException} is thrown.</li>
531 * </ul>
532 * </p>
Daniel Trebbienadf41942010-10-31 12:21:05 -0700533 *
Jeff Brown80e7b802011-10-12 17:42:41 -0700534 * @param row The zero-based row index.
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700535 * @param column The zero-based column index.
536 * @return The value of the field as a <code>long</code>.
Daniel Trebbienadf41942010-10-31 12:21:05 -0700537 */
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700538 public long getLong(int row, int column) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800539 acquireReference();
540 try {
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700541 return nativeGetLong(mWindowPtr, row - mStartPos, column);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800542 } finally {
543 releaseReference();
544 }
545 }
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700546
Daniel Trebbienadf41942010-10-31 12:21:05 -0700547 /**
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700548 * Gets the value of the field at the specified row and column index as a
549 * <code>double</code>.
550 * <p>
551 * The result is determined as follows:
552 * <ul>
553 * <li>If the field is of type {@link Cursor#FIELD_TYPE_NULL}, then the result
554 * is <code>0.0</code>.</li>
555 * <li>If the field is of type {@link Cursor#FIELD_TYPE_STRING}, then the result
556 * is the value obtained by parsing the string value with <code>strtod</code>.
557 * <li>If the field is of type {@link Cursor#FIELD_TYPE_INTEGER}, then the result
558 * is the integer value converted to a <code>double</code>.</li>
559 * <li>If the field is of type {@link Cursor#FIELD_TYPE_FLOAT}, then the result
560 * is the <code>double</code> value.</li>
561 * <li>If the field is of type {@link Cursor#FIELD_TYPE_BLOB}, then a
562 * {@link SQLiteException} is thrown.</li>
563 * </ul>
564 * </p>
Daniel Trebbienadf41942010-10-31 12:21:05 -0700565 *
Jeff Brown80e7b802011-10-12 17:42:41 -0700566 * @param row The zero-based row index.
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700567 * @param column The zero-based column index.
568 * @return The value of the field as a <code>double</code>.
Daniel Trebbienadf41942010-10-31 12:21:05 -0700569 */
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700570 public double getDouble(int row, int column) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800571 acquireReference();
572 try {
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700573 return nativeGetDouble(mWindowPtr, row - mStartPos, column);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800574 } finally {
575 releaseReference();
576 }
577 }
578
579 /**
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700580 * Gets the value of the field at the specified row and column index as a
581 * <code>short</code>.
582 * <p>
583 * The result is determined by invoking {@link #getLong} and converting the
584 * result to <code>short</code>.
585 * </p>
586 *
Jeff Brown80e7b802011-10-12 17:42:41 -0700587 * @param row The zero-based row index.
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700588 * @param column The zero-based column index.
589 * @return The value of the field as a <code>short</code>.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800590 */
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700591 public short getShort(int row, int column) {
592 return (short) getLong(row, column);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800593 }
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700594
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800595 /**
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700596 * Gets the value of the field at the specified row and column index as an
597 * <code>int</code>.
598 * <p>
599 * The result is determined by invoking {@link #getLong} and converting the
600 * result to <code>int</code>.
601 * </p>
602 *
Jeff Brown80e7b802011-10-12 17:42:41 -0700603 * @param row The zero-based row index.
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700604 * @param column The zero-based column index.
605 * @return The value of the field as an <code>int</code>.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800606 */
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700607 public int getInt(int row, int column) {
608 return (int) getLong(row, column);
609 }
610
611 /**
612 * Gets the value of the field at the specified row and column index as a
613 * <code>float</code>.
614 * <p>
615 * The result is determined by invoking {@link #getDouble} and converting the
616 * result to <code>float</code>.
617 * </p>
618 *
Jeff Brown80e7b802011-10-12 17:42:41 -0700619 * @param row The zero-based row index.
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700620 * @param column The zero-based column index.
621 * @return The value of the field as an <code>float</code>.
622 */
623 public float getFloat(int row, int column) {
624 return (float) getDouble(row, column);
625 }
626
627 /**
628 * Copies a byte array into the field at the specified row and column index.
629 *
630 * @param value The value to store.
Jeff Brown80e7b802011-10-12 17:42:41 -0700631 * @param row The zero-based row index.
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700632 * @param column The zero-based column index.
633 * @return True if successful.
634 */
635 public boolean putBlob(byte[] value, int row, int column) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800636 acquireReference();
637 try {
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700638 return nativePutBlob(mWindowPtr, value, row - mStartPos, column);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800639 } finally {
640 releaseReference();
641 }
642 }
643
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700644 /**
645 * Copies a string into the field at the specified row and column index.
646 *
647 * @param value The value to store.
Jeff Brown80e7b802011-10-12 17:42:41 -0700648 * @param row The zero-based row index.
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700649 * @param column The zero-based column index.
650 * @return True if successful.
651 */
652 public boolean putString(String value, int row, int column) {
653 acquireReference();
654 try {
655 return nativePutString(mWindowPtr, value, row - mStartPos, column);
656 } finally {
657 releaseReference();
658 }
659 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800660
661 /**
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700662 * Puts a long integer into the field at the specified row and column index.
663 *
664 * @param value The value to store.
Jeff Brown80e7b802011-10-12 17:42:41 -0700665 * @param row The zero-based row index.
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700666 * @param column The zero-based column index.
667 * @return True if successful.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800668 */
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700669 public boolean putLong(long value, int row, int column) {
670 acquireReference();
671 try {
672 return nativePutLong(mWindowPtr, value, row - mStartPos, column);
673 } finally {
674 releaseReference();
Vasu Nori0e453d12011-01-06 09:52:51 -0800675 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800676 }
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700677
678 /**
679 * Puts a double-precision floating point value into the field at the
680 * specified row and column index.
681 *
682 * @param value The value to store.
Jeff Brown80e7b802011-10-12 17:42:41 -0700683 * @param row The zero-based row index.
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700684 * @param column The zero-based column index.
685 * @return True if successful.
686 */
687 public boolean putDouble(double value, int row, int column) {
688 acquireReference();
689 try {
690 return nativePutDouble(mWindowPtr, value, row - mStartPos, column);
691 } finally {
692 releaseReference();
693 }
694 }
695
696 /**
697 * Puts a null value into the field at the specified row and column index.
698 *
Jeff Brown80e7b802011-10-12 17:42:41 -0700699 * @param row The zero-based row index.
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700700 * @param column The zero-based column index.
701 * @return True if successful.
702 */
703 public boolean putNull(int row, int column) {
704 acquireReference();
705 try {
706 return nativePutNull(mWindowPtr, row - mStartPos, column);
707 } finally {
708 releaseReference();
709 }
710 }
711
Jeff Sharkey9e8f83d2019-02-28 12:06:45 -0700712 public static final @android.annotation.NonNull Parcelable.Creator<CursorWindow> CREATOR
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800713 = new Parcelable.Creator<CursorWindow>() {
714 public CursorWindow createFromParcel(Parcel source) {
715 return new CursorWindow(source);
716 }
717
718 public CursorWindow[] newArray(int size) {
719 return new CursorWindow[size];
720 }
721 };
722
723 public static CursorWindow newFromParcel(Parcel p) {
724 return CREATOR.createFromParcel(p);
725 }
726
727 public int describeContents() {
728 return 0;
729 }
730
731 public void writeToParcel(Parcel dest, int flags) {
Jeff Brown03bd3022012-03-06 13:48:56 -0800732 acquireReference();
733 try {
734 dest.writeInt(mStartPos);
735 nativeWriteToParcel(mWindowPtr, dest);
736 } finally {
737 releaseReference();
738 }
Jeff Brownd2183652011-10-09 12:39:53 -0700739
740 if ((flags & Parcelable.PARCELABLE_WRITE_RETURN_VALUE) != 0) {
741 releaseReference();
742 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800743 }
744
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800745 @Override
746 protected void onAllReferencesReleased() {
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700747 dispose();
Vasu Nori6141e132010-12-23 20:46:46 -0800748 }
749
Mathew Inwood41b31942018-08-10 16:00:53 +0100750 @UnsupportedAppUsage
Ashok Bhat738702d2014-01-02 13:42:56 +0000751 private static final LongSparseArray<Integer> sWindowToPidMap = new LongSparseArray<Integer>();
Vasu Nori6141e132010-12-23 20:46:46 -0800752
Ashok Bhat738702d2014-01-02 13:42:56 +0000753 private void recordNewWindow(int pid, long window) {
Vasu Nori6141e132010-12-23 20:46:46 -0800754 synchronized (sWindowToPidMap) {
755 sWindowToPidMap.put(window, pid);
756 if (Log.isLoggable(STATS_TAG, Log.VERBOSE)) {
757 Log.i(STATS_TAG, "Created a new Cursor. " + printStats());
758 }
759 }
760 }
761
Ashok Bhat738702d2014-01-02 13:42:56 +0000762 private void recordClosingOfWindow(long window) {
Vasu Nori6141e132010-12-23 20:46:46 -0800763 synchronized (sWindowToPidMap) {
764 if (sWindowToPidMap.size() == 0) {
765 // this means we are not in the ContentProvider.
766 return;
767 }
768 sWindowToPidMap.delete(window);
769 }
770 }
Jeff Brown3bc6bbc2011-10-06 13:11:04 -0700771
Mathew Inwood41b31942018-08-10 16:00:53 +0100772 @UnsupportedAppUsage
Vasu Nori6141e132010-12-23 20:46:46 -0800773 private String printStats() {
774 StringBuilder buff = new StringBuilder();
775 int myPid = Process.myPid();
776 int total = 0;
777 SparseIntArray pidCounts = new SparseIntArray();
778 synchronized (sWindowToPidMap) {
779 int size = sWindowToPidMap.size();
780 if (size == 0) {
781 // this means we are not in the ContentProvider.
782 return "";
783 }
784 for (int indx = 0; indx < size; indx++) {
785 int pid = sWindowToPidMap.valueAt(indx);
786 int value = pidCounts.get(pid);
787 pidCounts.put(pid, ++value);
788 }
789 }
790 int numPids = pidCounts.size();
791 for (int i = 0; i < numPids;i++) {
792 buff.append(" (# cursors opened by ");
793 int pid = pidCounts.keyAt(i);
794 if (pid == myPid) {
795 buff.append("this proc=");
796 } else {
797 buff.append("pid " + pid + "=");
798 }
799 int num = pidCounts.get(pid);
800 buff.append(num + ")");
801 total += num;
802 }
803 // limit the returned string size to 1000
804 String s = (buff.length() > 980) ? buff.substring(0, 980) : buff.toString();
805 return "# Open Cursors=" + total + s;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800806 }
Jeff Brown650de3d2011-10-27 14:52:28 -0700807
Fyodor Kupolov6bb32a92017-10-10 10:36:43 -0700808 private static int getCursorWindowSize() {
809 if (sCursorWindowSize < 0) {
810 // The cursor window size. resource xml file specifies the value in kB.
811 // convert it to bytes here by multiplying with 1024.
812 sCursorWindowSize = Resources.getSystem().getInteger(
813 com.android.internal.R.integer.config_cursorWindowSize) * 1024;
814 }
815 return sCursorWindowSize;
816 }
817
Jeff Brown650de3d2011-10-27 14:52:28 -0700818 @Override
819 public String toString() {
Ashok Bhat738702d2014-01-02 13:42:56 +0000820 return getName() + " {" + Long.toHexString(mWindowPtr) + "}";
Jeff Brown650de3d2011-10-27 14:52:28 -0700821 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800822}