/* * Copyright (C) 2006 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.database; import android.annotation.BytesLong; import android.annotation.IntRange; import android.compat.annotation.UnsupportedAppUsage; import android.content.res.Resources; import android.database.sqlite.SQLiteClosable; import android.database.sqlite.SQLiteException; import android.os.Parcel; import android.os.Parcelable; import dalvik.annotation.optimization.FastNative; import dalvik.system.CloseGuard; /** * A buffer containing multiple cursor rows. *
* A {@link CursorWindow} is read-write when initially created and used locally. * When sent to a remote process (by writing it to a {@link Parcel}), the remote process * receives a read-only view of the cursor window. Typically the cursor window * will be allocated by the producer, filled with data, and then sent to the * consumer for reading. *
*/ @android.ravenwood.annotation.RavenwoodKeepWholeClass @android.ravenwood.annotation.RavenwoodNativeSubstitutionClass( "com.android.platform.test.ravenwood.nativesubstitution.CursorWindow_host") public class CursorWindow extends SQLiteClosable implements Parcelable { private static final String STATS_TAG = "CursorWindowStats"; // This static member will be evaluated when first used. @UnsupportedAppUsage private static int sCursorWindowSize = -1; /** * The native CursorWindow object pointer. (FOR INTERNAL USE ONLY) * @hide */ @UnsupportedAppUsage public long mWindowPtr; private int mStartPos; private final String mName; private final CloseGuard mCloseGuard; // May throw CursorWindowAllocationException private static native long nativeCreate(String name, int cursorWindowSize); // May throw CursorWindowAllocationException private static native long nativeCreateFromParcel(Parcel parcel); private static native void nativeDispose(long windowPtr); private static native void nativeWriteToParcel(long windowPtr, Parcel parcel); private static native String nativeGetName(long windowPtr); private static native byte[] nativeGetBlob(long windowPtr, int row, int column); private static native String nativeGetString(long windowPtr, int row, int column); private static native void nativeCopyStringToBuffer(long windowPtr, int row, int column, CharArrayBuffer buffer); private static native boolean nativePutBlob(long windowPtr, byte[] value, int row, int column); private static native boolean nativePutString(long windowPtr, String value, int row, int column); // Below native methods don't do unconstrained work, so are FastNative for performance @FastNative private static native void nativeClear(long windowPtr); @FastNative private static native int nativeGetNumRows(long windowPtr); @FastNative private static native boolean nativeSetNumColumns(long windowPtr, int columnNum); @FastNative private static native boolean nativeAllocRow(long windowPtr); @FastNative private static native void nativeFreeLastRow(long windowPtr); @FastNative private static native int nativeGetType(long windowPtr, int row, int column); @FastNative private static native long nativeGetLong(long windowPtr, int row, int column); @FastNative private static native double nativeGetDouble(long windowPtr, int row, int column); @FastNative private static native boolean nativePutLong(long windowPtr, long value, int row, int column); @FastNative private static native boolean nativePutDouble(long windowPtr, double value, int row, int column); @FastNative private static native boolean nativePutNull(long windowPtr, int row, int column); /** * Creates a new empty cursor window and gives it a name. ** The cursor initially has no rows or columns. Call {@link #setNumColumns(int)} to * set the number of columns before adding any rows to the cursor. *
* * @param name The name of the cursor window, or null if none. */ public CursorWindow(String name) { this(name, getCursorWindowSize()); } /** * Creates a new empty cursor window and gives it a name. ** The cursor initially has no rows or columns. Call {@link #setNumColumns(int)} to * set the number of columns before adding any rows to the cursor. *
* * @param name The name of the cursor window, or null if none. * @param windowSizeBytes Size of cursor window in bytes. * @throws IllegalArgumentException if {@code windowSizeBytes} is less than 0 * @throws AssertionError if created window pointer is 0 *Note: Memory is dynamically allocated as data rows are added to the
* window. Depending on the amount of data stored, the actual amount of memory allocated can be
* lower than specified size, but cannot exceed it.
*/
public CursorWindow(String name, @BytesLong long windowSizeBytes) {
if (windowSizeBytes < 0) {
throw new IllegalArgumentException("Window size cannot be less than 0");
}
mStartPos = 0;
mName = name != null && name.length() != 0 ? name : "
* The cursor initially has no rows or columns. Call {@link #setNumColumns(int)} to
* set the number of columns before adding any rows to the cursor.
*
* The start position ({@link #getStartPosition()}), number of rows ({@link #getNumRows()}),
* and number of columns in the cursor are all reset to zero.
*
* The start position is the zero-based index of the first row that this window contains
* relative to the entire result set of the {@link Cursor}.
*
* The start position is the zero-based index of the first row that this window contains
* relative to the entire result set of the {@link Cursor}.
*
* This method must be called before any rows are added to the window, otherwise
* it will fail to set the number of columns if it differs from the current number
* of columns.
*
* The result is determined as follows:
*
*
* null
.
* The result is determined as follows: *
null
.printf
family of functions using
* format specifier %lld
.printf
family of functions using
* format specifier %g
.* The buffer is populated as follows: *
printf
family of functions using
* format specifier %lld
.printf
family of functions using
* format specifier %g
.long
.
* * The result is determined as follows: *
0L
.strtoll
.
* long
value.long
.long
.
*/
public long getLong(@IntRange(from = 0) int row, @IntRange(from = 0) int column) {
acquireReference();
try {
return nativeGetLong(mWindowPtr, row - mStartPos, column);
} finally {
releaseReference();
}
}
/**
* Gets the value of the field at the specified row and column index as a
* double
.
* * The result is determined as follows: *
0.0
.strtod
.
* double
.double
value.double
.
*/
public double getDouble(@IntRange(from = 0) int row, @IntRange(from = 0) int column) {
acquireReference();
try {
return nativeGetDouble(mWindowPtr, row - mStartPos, column);
} finally {
releaseReference();
}
}
/**
* Gets the value of the field at the specified row and column index as a
* short
.
*
* The result is determined by invoking {@link #getLong} and converting the
* result to short
.
*
short
.
*/
public short getShort(@IntRange(from = 0) int row, @IntRange(from = 0) int column) {
return (short) getLong(row, column);
}
/**
* Gets the value of the field at the specified row and column index as an
* int
.
*
* The result is determined by invoking {@link #getLong} and converting the
* result to int
.
*
int
.
*/
public int getInt(@IntRange(from = 0) int row, @IntRange(from = 0) int column) {
return (int) getLong(row, column);
}
/**
* Gets the value of the field at the specified row and column index as a
* float
.
*
* The result is determined by invoking {@link #getDouble} and converting the
* result to float
.
*
float
.
*/
public float getFloat(@IntRange(from = 0) int row, @IntRange(from = 0) int column) {
return (float) getDouble(row, column);
}
/**
* Copies a byte array into the field at the specified row and column index.
*
* @param value The value to store.
* @param row The zero-based row index.
* @param column The zero-based column index.
* @return True if successful.
*/
public boolean putBlob(byte[] value,
@IntRange(from = 0) int row, @IntRange(from = 0) int column) {
acquireReference();
try {
return nativePutBlob(mWindowPtr, value, row - mStartPos, column);
} finally {
releaseReference();
}
}
/**
* Copies a string into the field at the specified row and column index.
*
* @param value The value to store.
* @param row The zero-based row index.
* @param column The zero-based column index.
* @return True if successful.
*/
public boolean putString(String value,
@IntRange(from = 0) int row, @IntRange(from = 0) int column) {
acquireReference();
try {
return nativePutString(mWindowPtr, value, row - mStartPos, column);
} finally {
releaseReference();
}
}
/**
* Puts a long integer into the field at the specified row and column index.
*
* @param value The value to store.
* @param row The zero-based row index.
* @param column The zero-based column index.
* @return True if successful.
*/
public boolean putLong(long value,
@IntRange(from = 0) int row, @IntRange(from = 0) int column) {
acquireReference();
try {
return nativePutLong(mWindowPtr, value, row - mStartPos, column);
} finally {
releaseReference();
}
}
/**
* Puts a double-precision floating point value into the field at the
* specified row and column index.
*
* @param value The value to store.
* @param row The zero-based row index.
* @param column The zero-based column index.
* @return True if successful.
*/
public boolean putDouble(double value,
@IntRange(from = 0) int row, @IntRange(from = 0) int column) {
acquireReference();
try {
return nativePutDouble(mWindowPtr, value, row - mStartPos, column);
} finally {
releaseReference();
}
}
/**
* Puts a null value into the field at the specified row and column index.
*
* @param row The zero-based row index.
* @param column The zero-based column index.
* @return True if successful.
*/
public boolean putNull(@IntRange(from = 0) int row, @IntRange(from = 0) int column) {
acquireReference();
try {
return nativePutNull(mWindowPtr, row - mStartPos, column);
} finally {
releaseReference();
}
}
public static final @android.annotation.NonNull Parcelable.Creator