add complete java side of sqlite implementation

Mostly taken from https://www.sqlite.org/android which is forked from
AOSPs implementation
This commit is contained in:
Julian Winkler
2023-08-24 12:43:13 +02:00
parent b861c86f0d
commit 2e0c18d755
58 changed files with 12959 additions and 685 deletions

View File

@@ -0,0 +1,165 @@
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class android_database_CursorWindow */
#ifndef _Included_android_database_CursorWindow
#define _Included_android_database_CursorWindow
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: android_database_CursorWindow
* Method: nativeCreate
* Signature: (Ljava/lang/String;I)J
*/
JNIEXPORT jlong JNICALL Java_android_database_CursorWindow_nativeCreate
(JNIEnv *, jclass, jstring, jint);
/*
* Class: android_database_CursorWindow
* Method: nativeDispose
* Signature: (J)V
*/
JNIEXPORT void JNICALL Java_android_database_CursorWindow_nativeDispose
(JNIEnv *, jclass, jlong);
/*
* Class: android_database_CursorWindow
* Method: nativeGetName
* Signature: (J)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_android_database_CursorWindow_nativeGetName
(JNIEnv *, jclass, jlong);
/*
* Class: android_database_CursorWindow
* Method: nativeGetBlob
* Signature: (JII)[B
*/
JNIEXPORT jbyteArray JNICALL Java_android_database_CursorWindow_nativeGetBlob
(JNIEnv *, jclass, jlong, jint, jint);
/*
* Class: android_database_CursorWindow
* Method: nativeGetString
* Signature: (JII)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_android_database_CursorWindow_nativeGetString
(JNIEnv *, jclass, jlong, jint, jint);
/*
* Class: android_database_CursorWindow
* Method: nativeCopyStringToBuffer
* Signature: (JIILandroid/database/CharArrayBuffer;)V
*/
JNIEXPORT void JNICALL Java_android_database_CursorWindow_nativeCopyStringToBuffer
(JNIEnv *, jclass, jlong, jint, jint, jobject);
/*
* Class: android_database_CursorWindow
* Method: nativePutBlob
* Signature: (J[BII)Z
*/
JNIEXPORT jboolean JNICALL Java_android_database_CursorWindow_nativePutBlob
(JNIEnv *, jclass, jlong, jbyteArray, jint, jint);
/*
* Class: android_database_CursorWindow
* Method: nativePutString
* Signature: (JLjava/lang/String;II)Z
*/
JNIEXPORT jboolean JNICALL Java_android_database_CursorWindow_nativePutString
(JNIEnv *, jclass, jlong, jstring, jint, jint);
/*
* Class: android_database_CursorWindow
* Method: nativeClear
* Signature: (J)V
*/
JNIEXPORT void JNICALL Java_android_database_CursorWindow_nativeClear
(JNIEnv *, jclass, jlong);
/*
* Class: android_database_CursorWindow
* Method: nativeGetNumRows
* Signature: (J)I
*/
JNIEXPORT jint JNICALL Java_android_database_CursorWindow_nativeGetNumRows
(JNIEnv *, jclass, jlong);
/*
* Class: android_database_CursorWindow
* Method: nativeSetNumColumns
* Signature: (JI)Z
*/
JNIEXPORT jboolean JNICALL Java_android_database_CursorWindow_nativeSetNumColumns
(JNIEnv *, jclass, jlong, jint);
/*
* Class: android_database_CursorWindow
* Method: nativeAllocRow
* Signature: (J)Z
*/
JNIEXPORT jboolean JNICALL Java_android_database_CursorWindow_nativeAllocRow
(JNIEnv *, jclass, jlong);
/*
* Class: android_database_CursorWindow
* Method: nativeFreeLastRow
* Signature: (J)V
*/
JNIEXPORT void JNICALL Java_android_database_CursorWindow_nativeFreeLastRow
(JNIEnv *, jclass, jlong);
/*
* Class: android_database_CursorWindow
* Method: nativeGetType
* Signature: (JII)I
*/
JNIEXPORT jint JNICALL Java_android_database_CursorWindow_nativeGetType
(JNIEnv *, jclass, jlong, jint, jint);
/*
* Class: android_database_CursorWindow
* Method: nativeGetLong
* Signature: (JII)J
*/
JNIEXPORT jlong JNICALL Java_android_database_CursorWindow_nativeGetLong
(JNIEnv *, jclass, jlong, jint, jint);
/*
* Class: android_database_CursorWindow
* Method: nativeGetDouble
* Signature: (JII)D
*/
JNIEXPORT jdouble JNICALL Java_android_database_CursorWindow_nativeGetDouble
(JNIEnv *, jclass, jlong, jint, jint);
/*
* Class: android_database_CursorWindow
* Method: nativePutLong
* Signature: (JJII)Z
*/
JNIEXPORT jboolean JNICALL Java_android_database_CursorWindow_nativePutLong
(JNIEnv *, jclass, jlong, jlong, jint, jint);
/*
* Class: android_database_CursorWindow
* Method: nativePutDouble
* Signature: (JDII)Z
*/
JNIEXPORT jboolean JNICALL Java_android_database_CursorWindow_nativePutDouble
(JNIEnv *, jclass, jlong, jdouble, jint, jint);
/*
* Class: android_database_CursorWindow
* Method: nativePutNull
* Signature: (JII)Z
*/
JNIEXPORT jboolean JNICALL Java_android_database_CursorWindow_nativePutNull
(JNIEnv *, jclass, jlong, jint, jint);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,231 @@
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class android_database_sqlite_SQLiteConnection */
#ifndef _Included_android_database_sqlite_SQLiteConnection
#define _Included_android_database_sqlite_SQLiteConnection
#ifdef __cplusplus
extern "C" {
#endif
#undef android_database_sqlite_SQLiteConnection_DEBUG
#define android_database_sqlite_SQLiteConnection_DEBUG 0L
/*
* Class: android_database_sqlite_SQLiteConnection
* Method: nativeOpen
* Signature: (Ljava/lang/String;ILjava/lang/String;ZZ)J
*/
JNIEXPORT jlong JNICALL Java_android_database_sqlite_SQLiteConnection_nativeOpen
(JNIEnv *, jclass, jstring, jint, jstring, jboolean, jboolean);
/*
* Class: android_database_sqlite_SQLiteConnection
* Method: nativeClose
* Signature: (J)V
*/
JNIEXPORT void JNICALL Java_android_database_sqlite_SQLiteConnection_nativeClose
(JNIEnv *, jclass, jlong);
/*
* Class: android_database_sqlite_SQLiteConnection
* Method: nativeRegisterCustomFunction
* Signature: (JLandroid/database/sqlite/SQLiteCustomFunction;)V
*/
JNIEXPORT void JNICALL Java_android_database_sqlite_SQLiteConnection_nativeRegisterCustomFunction
(JNIEnv *, jclass, jlong, jobject);
/*
* Class: android_database_sqlite_SQLiteConnection
* Method: nativeRegisterLocalizedCollators
* Signature: (JLjava/lang/String;)V
*/
JNIEXPORT void JNICALL Java_android_database_sqlite_SQLiteConnection_nativeRegisterLocalizedCollators
(JNIEnv *, jclass, jlong, jstring);
/*
* Class: android_database_sqlite_SQLiteConnection
* Method: nativePrepareStatement
* Signature: (JLjava/lang/String;)J
*/
JNIEXPORT jlong JNICALL Java_android_database_sqlite_SQLiteConnection_nativePrepareStatement
(JNIEnv *, jclass, jlong, jstring);
/*
* Class: android_database_sqlite_SQLiteConnection
* Method: nativeFinalizeStatement
* Signature: (JJ)V
*/
JNIEXPORT void JNICALL Java_android_database_sqlite_SQLiteConnection_nativeFinalizeStatement
(JNIEnv *, jclass, jlong, jlong);
/*
* Class: android_database_sqlite_SQLiteConnection
* Method: nativeGetParameterCount
* Signature: (JJ)I
*/
JNIEXPORT jint JNICALL Java_android_database_sqlite_SQLiteConnection_nativeGetParameterCount
(JNIEnv *, jclass, jlong, jlong);
/*
* Class: android_database_sqlite_SQLiteConnection
* Method: nativeIsReadOnly
* Signature: (JJ)Z
*/
JNIEXPORT jboolean JNICALL Java_android_database_sqlite_SQLiteConnection_nativeIsReadOnly
(JNIEnv *, jclass, jlong, jlong);
/*
* Class: android_database_sqlite_SQLiteConnection
* Method: nativeGetColumnCount
* Signature: (JJ)I
*/
JNIEXPORT jint JNICALL Java_android_database_sqlite_SQLiteConnection_nativeGetColumnCount
(JNIEnv *, jclass, jlong, jlong);
/*
* Class: android_database_sqlite_SQLiteConnection
* Method: nativeGetColumnName
* Signature: (JJI)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_android_database_sqlite_SQLiteConnection_nativeGetColumnName
(JNIEnv *, jclass, jlong, jlong, jint);
/*
* Class: android_database_sqlite_SQLiteConnection
* Method: nativeBindNull
* Signature: (JJI)V
*/
JNIEXPORT void JNICALL Java_android_database_sqlite_SQLiteConnection_nativeBindNull
(JNIEnv *, jclass, jlong, jlong, jint);
/*
* Class: android_database_sqlite_SQLiteConnection
* Method: nativeBindLong
* Signature: (JJIJ)V
*/
JNIEXPORT void JNICALL Java_android_database_sqlite_SQLiteConnection_nativeBindLong
(JNIEnv *, jclass, jlong, jlong, jint, jlong);
/*
* Class: android_database_sqlite_SQLiteConnection
* Method: nativeBindDouble
* Signature: (JJID)V
*/
JNIEXPORT void JNICALL Java_android_database_sqlite_SQLiteConnection_nativeBindDouble
(JNIEnv *, jclass, jlong, jlong, jint, jdouble);
/*
* Class: android_database_sqlite_SQLiteConnection
* Method: nativeBindString
* Signature: (JJILjava/lang/String;)V
*/
JNIEXPORT void JNICALL Java_android_database_sqlite_SQLiteConnection_nativeBindString
(JNIEnv *, jclass, jlong, jlong, jint, jstring);
/*
* Class: android_database_sqlite_SQLiteConnection
* Method: nativeBindBlob
* Signature: (JJI[B)V
*/
JNIEXPORT void JNICALL Java_android_database_sqlite_SQLiteConnection_nativeBindBlob
(JNIEnv *, jclass, jlong, jlong, jint, jbyteArray);
/*
* Class: android_database_sqlite_SQLiteConnection
* Method: nativeResetStatementAndClearBindings
* Signature: (JJ)V
*/
JNIEXPORT void JNICALL Java_android_database_sqlite_SQLiteConnection_nativeResetStatementAndClearBindings
(JNIEnv *, jclass, jlong, jlong);
/*
* Class: android_database_sqlite_SQLiteConnection
* Method: nativeExecute
* Signature: (JJ)V
*/
JNIEXPORT void JNICALL Java_android_database_sqlite_SQLiteConnection_nativeExecute
(JNIEnv *, jclass, jlong, jlong);
/*
* Class: android_database_sqlite_SQLiteConnection
* Method: nativeExecuteForLong
* Signature: (JJ)J
*/
JNIEXPORT jlong JNICALL Java_android_database_sqlite_SQLiteConnection_nativeExecuteForLong
(JNIEnv *, jclass, jlong, jlong);
/*
* Class: android_database_sqlite_SQLiteConnection
* Method: nativeExecuteForString
* Signature: (JJ)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_android_database_sqlite_SQLiteConnection_nativeExecuteForString
(JNIEnv *, jclass, jlong, jlong);
/*
* Class: android_database_sqlite_SQLiteConnection
* Method: nativeExecuteForBlobFileDescriptor
* Signature: (JJ)I
*/
JNIEXPORT jint JNICALL Java_android_database_sqlite_SQLiteConnection_nativeExecuteForBlobFileDescriptor
(JNIEnv *, jclass, jlong, jlong);
/*
* Class: android_database_sqlite_SQLiteConnection
* Method: nativeExecuteForChangedRowCount
* Signature: (JJ)I
*/
JNIEXPORT jint JNICALL Java_android_database_sqlite_SQLiteConnection_nativeExecuteForChangedRowCount
(JNIEnv *, jclass, jlong, jlong);
/*
* Class: android_database_sqlite_SQLiteConnection
* Method: nativeExecuteForLastInsertedRowId
* Signature: (JJ)J
*/
JNIEXPORT jlong JNICALL Java_android_database_sqlite_SQLiteConnection_nativeExecuteForLastInsertedRowId
(JNIEnv *, jclass, jlong, jlong);
/*
* Class: android_database_sqlite_SQLiteConnection
* Method: nativeExecuteForCursorWindow
* Signature: (JJLandroid/database/CursorWindow;IIZ)J
*/
JNIEXPORT jlong JNICALL Java_android_database_sqlite_SQLiteConnection_nativeExecuteForCursorWindow
(JNIEnv *, jclass, jlong, jlong, jobject, jint, jint, jboolean);
/*
* Class: android_database_sqlite_SQLiteConnection
* Method: nativeGetDbLookaside
* Signature: (J)I
*/
JNIEXPORT jint JNICALL Java_android_database_sqlite_SQLiteConnection_nativeGetDbLookaside
(JNIEnv *, jclass, jlong);
/*
* Class: android_database_sqlite_SQLiteConnection
* Method: nativeCancel
* Signature: (J)V
*/
JNIEXPORT void JNICALL Java_android_database_sqlite_SQLiteConnection_nativeCancel
(JNIEnv *, jclass, jlong);
/*
* Class: android_database_sqlite_SQLiteConnection
* Method: nativeResetCancel
* Signature: (JZ)V
*/
JNIEXPORT void JNICALL Java_android_database_sqlite_SQLiteConnection_nativeResetCancel
(JNIEnv *, jclass, jlong, jboolean);
/*
* Class: android_database_sqlite_SQLiteConnection
* Method: nativeHasCodec
* Signature: ()Z
*/
JNIEXPORT jboolean JNICALL Java_android_database_sqlite_SQLiteConnection_nativeHasCodec
(JNIEnv *, jclass);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,23 @@
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class android_database_sqlite_SQLiteDebug */
#ifndef _Included_android_database_sqlite_SQLiteDebug
#define _Included_android_database_sqlite_SQLiteDebug
#ifdef __cplusplus
extern "C" {
#endif
#undef android_database_sqlite_SQLiteDebug_DEBUG_LOG_SLOW_QUERIES
#define android_database_sqlite_SQLiteDebug_DEBUG_LOG_SLOW_QUERIES 0L
/*
* Class: android_database_sqlite_SQLiteDebug
* Method: nativeGetPagerStats
* Signature: (Landroid/database/sqlite/SQLiteDebug/PagerStats;)V
*/
JNIEXPORT void JNICALL Java_android_database_sqlite_SQLiteDebug_nativeGetPagerStats
(JNIEnv *, jclass, jobject);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,21 @@
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class android_database_sqlite_SQLiteGlobal */
#ifndef _Included_android_database_sqlite_SQLiteGlobal
#define _Included_android_database_sqlite_SQLiteGlobal
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: android_database_sqlite_SQLiteGlobal
* Method: nativeReleaseMemory
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_android_database_sqlite_SQLiteGlobal_nativeReleaseMemory
(JNIEnv *, jclass);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -6,4 +6,13 @@ import android.net.Uri;
public class ContentResolver {
public final void registerContentObserver(Uri uri, boolean notifyForDescendants, ContentObserver observer) {
}
public final void unregisterContentObserver(ContentObserver observer) {
}
public void notifyChange(Uri uri, ContentObserver observer) {
}
public int getUserId() {
return 0;
}
public final void registerContentObserver(Uri uri, boolean notifyForDescendants, ContentObserver observer, int userHandle) {
}
}

View File

@@ -360,4 +360,11 @@ public class Context extends Object {
}
public boolean isRestricted() {return false;}
public File getDatabasePath(String dbName) {
File databaseDir = new File(getDataDirFile(), "databases");
if (!databaseDir.exists())
databaseDir.mkdirs();
return new File(databaseDir, dbName);
}
}

View File

@@ -0,0 +1,484 @@
/*
* 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.content.ContentResolver;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import dalvik.system.CloseGuard;
import java.lang.ref.WeakReference;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
/**
* This is an abstract cursor class that handles a lot of the common code
* that all cursors need to deal with and is provided for convenience reasons.
*/
public abstract class AbstractCursor implements CrossProcessCursor {
private static final String TAG = "Cursor";
/**
* @removed This field should not be used.
*/
protected HashMap<Long, Map<String, Object>> mUpdatedRows;
/**
* @removed This field should not be used.
*/
protected int mRowIdColumnIndex;
/**
* @removed This field should not be used.
*/
protected Long mCurrentRowID;
/**
* @deprecated Use {@link #getPosition()} instead.
*/
@Deprecated
protected int mPos;
/**
* @deprecated Use {@link #isClosed()} instead.
*/
@Deprecated
protected boolean mClosed;
/**
* @deprecated Do not use.
*/
@Deprecated
protected ContentResolver mContentResolver;
private Uri mNotifyUri;
private List<Uri> mNotifyUris;
private final Object mSelfObserverLock = new Object();
private ContentObserver mSelfObserver;
private boolean mSelfObserverRegistered;
private final DataSetObservable mDataSetObservable = new DataSetObservable();
private final ContentObservable mContentObservable = new ContentObservable();
private Bundle mExtras = Bundle.EMPTY;
/** CloseGuard to detect leaked cursor **/
private final CloseGuard mCloseGuard = CloseGuard.get();
/* -------------------------------------------------------- */
/* These need to be implemented by subclasses */
@Override
abstract public int getCount();
@Override
abstract public String[] getColumnNames();
@Override
abstract public String getString(int column);
@Override
abstract public short getShort(int column);
@Override
abstract public int getInt(int column);
@Override
abstract public long getLong(int column);
@Override
abstract public float getFloat(int column);
@Override
abstract public double getDouble(int column);
@Override
abstract public boolean isNull(int column);
@Override
public int getType(int column) {
// Reflects the assumption that all commonly used field types (meaning everything
// but blobs) are convertible to strings so it should be safe to call
// getString to retrieve them.
return FIELD_TYPE_STRING;
}
// TODO implement getBlob in all cursor types
@Override
public byte[] getBlob(int column) {
throw new UnsupportedOperationException("getBlob is not supported");
}
/* -------------------------------------------------------- */
/* Methods that may optionally be implemented by subclasses */
/**
* If the cursor is backed by a {@link CursorWindow}, returns a pre-filled
* window with the contents of the cursor, otherwise null.
*
* @return The pre-filled window that backs this cursor, or null if none.
*/
@Override
public CursorWindow getWindow() {
return null;
}
@Override
public int getColumnCount() {
return getColumnNames().length;
}
@Override
public void deactivate() {
onDeactivateOrClose();
}
/** @hide */
protected void onDeactivateOrClose() {
if (mSelfObserver != null) {
mContentResolver.unregisterContentObserver(mSelfObserver);
mSelfObserverRegistered = false;
}
mDataSetObservable.notifyInvalidated();
}
@Override
public boolean requery() {
if (mSelfObserver != null && mSelfObserverRegistered == false) {
final int size = mNotifyUris.size();
for (int i = 0; i < size; ++i) {
final Uri notifyUri = mNotifyUris.get(i);
mContentResolver.registerContentObserver(notifyUri, true, mSelfObserver);
}
mSelfObserverRegistered = true;
}
mDataSetObservable.notifyChanged();
return true;
}
@Override
public boolean isClosed() {
return mClosed;
}
@Override
public void close() {
mClosed = true;
mContentObservable.unregisterAll();
onDeactivateOrClose();
mCloseGuard.close();
}
/**
* This function is called every time the cursor is successfully scrolled
* to a new position, giving the subclass a chance to update any state it
* may have. If it returns false the move function will also do so and the
* cursor will scroll to the beforeFirst position.
*
* @param oldPosition the position that we're moving from
* @param newPosition the position that we're moving to
* @return true if the move is successful, false otherwise
*/
@Override
public boolean onMove(int oldPosition, int newPosition) {
return true;
}
@Override
public void copyStringToBuffer(int columnIndex, CharArrayBuffer buffer) {
// Default implementation, uses getString
String result = getString(columnIndex);
if (result != null) {
char[] data = buffer.data;
if (data == null || data.length < result.length()) {
buffer.data = result.toCharArray();
} else {
result.getChars(0, result.length(), data, 0);
}
buffer.sizeCopied = result.length();
} else {
buffer.sizeCopied = 0;
}
}
/* -------------------------------------------------------- */
/* Implementation */
public AbstractCursor() {
mPos = -1;
mCloseGuard.open("AbstractCursor.close");
}
@Override
public final int getPosition() {
return mPos;
}
@Override
public final boolean moveToPosition(int position) {
// Make sure position isn't past the end of the cursor
final int count = getCount();
if (position >= count) {
mPos = count;
return false;
}
// Make sure position isn't before the beginning of the cursor
if (position < 0) {
mPos = -1;
return false;
}
// Check for no-op moves, and skip the rest of the work for them
if (position == mPos) {
return true;
}
boolean result = onMove(mPos, position);
if (result == false) {
mPos = -1;
} else {
mPos = position;
}
return result;
}
@Override
public void fillWindow(int position, CursorWindow window) {
DatabaseUtils.cursorFillWindow(this, position, window);
}
@Override
public final boolean move(int offset) {
return moveToPosition(mPos + offset);
}
@Override
public final boolean moveToFirst() {
return moveToPosition(0);
}
@Override
public final boolean moveToLast() {
return moveToPosition(getCount() - 1);
}
@Override
public final boolean moveToNext() {
return moveToPosition(mPos + 1);
}
@Override
public final boolean moveToPrevious() {
return moveToPosition(mPos - 1);
}
@Override
public final boolean isFirst() {
return mPos == 0 && getCount() != 0;
}
@Override
public final boolean isLast() {
int cnt = getCount();
return mPos == (cnt - 1) && cnt != 0;
}
@Override
public final boolean isBeforeFirst() {
if (getCount() == 0) {
return true;
}
return mPos == -1;
}
@Override
public final boolean isAfterLast() {
if (getCount() == 0) {
return true;
}
return mPos == getCount();
}
@Override
public int getColumnIndex(String columnName) {
// Hack according to bug 903852
final int periodIndex = columnName.lastIndexOf('.');
if (periodIndex != -1) {
Exception e = new Exception();
Log.e(TAG, "requesting column name with table name -- " + columnName, e);
columnName = columnName.substring(periodIndex + 1);
}
String columnNames[] = getColumnNames();
int length = columnNames.length;
for (int i = 0; i < length; i++) {
if (columnNames[i].equalsIgnoreCase(columnName)) {
return i;
}
}
if (false) {
if (getCount() > 0) {
Log.w("AbstractCursor", "Unknown column " + columnName);
}
}
return -1;
}
@Override
public int getColumnIndexOrThrow(String columnName) {
final int index = getColumnIndex(columnName);
if (index < 0) {
String availableColumns = "";
try {
availableColumns = Arrays.toString(getColumnNames());
} catch (Exception e) {
Log.d(TAG, "Cannot collect column names for debug purposes", e);
}
throw new IllegalArgumentException("column '" + columnName
+ "' does not exist. Available columns: " + availableColumns);
}
return index;
}
@Override
public String getColumnName(int columnIndex) {
return getColumnNames()[columnIndex];
}
@Override
public void registerContentObserver(ContentObserver observer) {
mContentObservable.registerObserver(observer);
}
@Override
public void unregisterContentObserver(ContentObserver observer) {
// cursor will unregister all observers when it close
if (!mClosed) {
mContentObservable.unregisterObserver(observer);
}
}
@Override
public void registerDataSetObserver(DataSetObserver observer) {
mDataSetObservable.registerObserver(observer);
}
@Override
public void unregisterDataSetObserver(DataSetObserver observer) {
mDataSetObservable.unregisterObserver(observer);
}
/**
* Subclasses must call this method when they finish committing updates to notify all
* observers.
*
* @param selfChange
*/
protected void onChange(boolean selfChange) {
synchronized (mSelfObserverLock) {
mContentObservable.dispatchChange(selfChange, null);
if (mNotifyUris != null && selfChange) {
final int size = mNotifyUris.size();
for (int i = 0; i < size; ++i) {
final Uri notifyUri = mNotifyUris.get(i);
mContentResolver.notifyChange(notifyUri, mSelfObserver);
}
}
}
}
/**
* Specifies a content URI to watch for changes.
*
* @param cr The content resolver from the caller's context.
* @param notifyUri The URI to watch for changes. This can be a
* specific row URI, or a base URI for a whole class of content.
*/
@Override
public void setNotificationUri(ContentResolver cr, Uri notifyUri) {
setNotificationUris(cr, Arrays.asList(notifyUri));
}
// @Override
public void setNotificationUris(ContentResolver cr, List<Uri> notifyUris) {
Objects.requireNonNull(cr);
Objects.requireNonNull(notifyUris);
setNotificationUris(cr, notifyUris, cr.getUserId(), true);
}
/**
* Set the notification uri but with an observer for a particular user's view. Also allows
* disabling the use of a self observer, which is sensible if either
* a) the cursor's owner calls {@link #onChange(boolean)} whenever the content changes, or
* b) the cursor is known not to have any content observers.
* @hide
*/
public void setNotificationUris(ContentResolver cr, List<Uri> notifyUris, int userHandle,
boolean registerSelfObserver) {
synchronized (mSelfObserverLock) {
mNotifyUris = notifyUris;
mNotifyUri = mNotifyUris.get(0);
mContentResolver = cr;
if (mSelfObserver != null) {
mContentResolver.unregisterContentObserver(mSelfObserver);
mSelfObserverRegistered = false;
}
if (registerSelfObserver) {
mSelfObserver = new SelfContentObserver(this);
final int size = mNotifyUris.size();
for (int i = 0; i < size; ++i) {
final Uri notifyUri = mNotifyUris.get(i);
mContentResolver.registerContentObserver(
notifyUri, true, mSelfObserver, userHandle);
}
mSelfObserverRegistered = true;
}
}
}
@Override
public Uri getNotificationUri() {
synchronized (mSelfObserverLock) {
return mNotifyUri;
}
}
// @Override
public List<Uri> getNotificationUris() {
synchronized (mSelfObserverLock) {
return mNotifyUris;
}
}
@Override
public boolean getWantsAllOnMoveCalls() {
return false;
}
// @Override
public void setExtras(Bundle extras) {
mExtras = (extras == null) ? Bundle.EMPTY : extras;
}
@Override
public Bundle getExtras() {
return mExtras;
}
@Override
public Bundle respond(Bundle extras) {
return Bundle.EMPTY;
}
/**
* @deprecated Always returns false since Cursors do not support updating rows
*/
@Deprecated
protected boolean isFieldUpdated(int columnIndex) {
return false;
}
/**
* @deprecated Always returns null since Cursors do not support updating rows
*/
@Deprecated
protected Object getUpdatedField(int columnIndex) {
return null;
}
/**
* This function throws CursorIndexOutOfBoundsException if
* the cursor position is out of bounds. Subclass implementations of
* the get functions should call this before attempting
* to retrieve data.
*
* @throws CursorIndexOutOfBoundsException
*/
protected void checkPosition() {
if (-1 == mPos || getCount() == mPos) {
// throw new CursorIndexOutOfBoundsException(mPos, getCount());
throw new IndexOutOfBoundsException("index = " + mPos + " count = " + getCount());
}
}
@Override
protected void finalize() {
if (mSelfObserver != null && mSelfObserverRegistered == true) {
mContentResolver.unregisterContentObserver(mSelfObserver);
}
try {
if (mCloseGuard != null) mCloseGuard.warnIfOpen();
if (!mClosed) close();
} catch(Exception e) { }
}
/**
* Cursors use this class to track changes others make to their URI.
*/
protected static class SelfContentObserver extends ContentObserver {
WeakReference<AbstractCursor> mCursor;
public SelfContentObserver(AbstractCursor cursor) {
super(null);
mCursor = new WeakReference<AbstractCursor>(cursor);
}
@Override
public boolean deliverSelfNotifications() {
return false;
}
@Override
public void onChange(boolean selfChange) {
AbstractCursor cursor = mCursor.get();
if (cursor != null) {
cursor.onChange(false);
}
}
}
}

View File

@@ -0,0 +1,209 @@
/*
* 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;
/**
* A base class for Cursors that store their data in {@link CursorWindow}s.
* <p>
* The cursor owns the cursor window it uses. When the cursor is closed,
* its window is also closed. Likewise, when the window used by the cursor is
* changed, its old window is closed. This policy of strict ownership ensures
* that cursor windows are not leaked.
* </p><p>
* Subclasses are responsible for filling the cursor window with data during
* {@link #onMove(int, int)}, allocating a new cursor window if necessary.
* During {@link #requery()}, the existing cursor window should be cleared and
* filled with new data.
* </p><p>
* If the contents of the cursor change or become invalid, the old window must be closed
* (because it is owned by the cursor) and set to null.
* </p>
*/
public abstract class AbstractWindowedCursor extends AbstractCursor {
/**
* The cursor window owned by this cursor.
*/
protected CursorWindow mWindow;
@Override
public byte[] getBlob(int columnIndex) {
checkPosition();
return mWindow.getBlob(mPos, columnIndex);
}
@Override
public String getString(int columnIndex) {
checkPosition();
return mWindow.getString(mPos, columnIndex);
}
@Override
public void copyStringToBuffer(int columnIndex, CharArrayBuffer buffer) {
checkPosition();
mWindow.copyStringToBuffer(mPos, columnIndex, buffer);
}
@Override
public short getShort(int columnIndex) {
checkPosition();
return mWindow.getShort(mPos, columnIndex);
}
@Override
public int getInt(int columnIndex) {
checkPosition();
return mWindow.getInt(mPos, columnIndex);
}
@Override
public long getLong(int columnIndex) {
checkPosition();
return mWindow.getLong(mPos, columnIndex);
}
@Override
public float getFloat(int columnIndex) {
checkPosition();
return mWindow.getFloat(mPos, columnIndex);
}
@Override
public double getDouble(int columnIndex) {
checkPosition();
return mWindow.getDouble(mPos, columnIndex);
}
@Override
public boolean isNull(int columnIndex) {
checkPosition();
return mWindow.getType(mPos, columnIndex) == Cursor.FIELD_TYPE_NULL;
}
/**
* @deprecated Use {@link #getType}
*/
@Deprecated
public boolean isBlob(int columnIndex) {
return getType(columnIndex) == Cursor.FIELD_TYPE_BLOB;
}
/**
* @deprecated Use {@link #getType}
*/
@Deprecated
public boolean isString(int columnIndex) {
return getType(columnIndex) == Cursor.FIELD_TYPE_STRING;
}
/**
* @deprecated Use {@link #getType}
*/
@Deprecated
public boolean isLong(int columnIndex) {
return getType(columnIndex) == Cursor.FIELD_TYPE_INTEGER;
}
/**
* @deprecated Use {@link #getType}
*/
@Deprecated
public boolean isFloat(int columnIndex) {
return getType(columnIndex) == Cursor.FIELD_TYPE_FLOAT;
}
@Override
public int getType(int columnIndex) {
checkPosition();
return mWindow.getType(mPos, columnIndex);
}
@Override
protected void checkPosition() {
super.checkPosition();
if (mWindow == null) {
throw new /*StaleDataException*/RuntimeException("Attempting to access a closed CursorWindow." +
"Most probable cause: cursor is deactivated prior to calling this method.");
}
}
@Override
public CursorWindow getWindow() {
return mWindow;
}
/**
* Sets a new cursor window for the cursor to use.
* <p>
* The cursor takes ownership of the provided cursor window; the cursor window
* will be closed when the cursor is closed or when the cursor adopts a new
* cursor window.
* </p><p>
* If the cursor previously had a cursor window, then it is closed when the
* new cursor window is assigned.
* </p>
*
* @param window The new cursor window, typically a remote cursor window.
*/
public void setWindow(CursorWindow window) {
if (window != mWindow) {
closeWindow();
mWindow = window;
}
}
/**
* Returns true if the cursor has an associated cursor window.
*
* @return True if the cursor has an associated cursor window.
*/
public boolean hasWindow() {
return mWindow != null;
}
/**
* Closes the cursor window and sets {@link #mWindow} to null.
* @hide
*/
protected void closeWindow() {
if (mWindow != null) {
mWindow.close();
mWindow = null;
}
}
/**
* If there is a window, clear it.
* Otherwise, creates a new window.
*
* @param name The window name.
* @hide
*/
protected void clearOrCreateWindow(String name) {
if (mWindow == null) {
mWindow = new CursorWindow(name);
} else {
mWindow.clear();
}
}
/** @hide */
@Override
protected void onDeactivateOrClose() {
super.onDeactivateOrClose();
closeWindow();
}
}

View File

@@ -0,0 +1,33 @@
/*
* Copyright (C) 2008 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;
/**
* This is used for {@link Cursor#copyStringToBuffer}
*/
public final class CharArrayBuffer {
public CharArrayBuffer(int size) {
data = new char[size];
}
public CharArrayBuffer(char[] buf) {
data = buf;
}
public char[] data; // In and out parameter
public int sizeCopied; // Out parameter
}

View File

@@ -0,0 +1,91 @@
/*
* Copyright (C) 2007 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.net.Uri;
/**
* A specialization of {@link Observable} for {@link ContentObserver}
* that provides methods for sending notifications to a list of
* {@link ContentObserver} objects.
*/
public class ContentObservable extends Observable<ContentObserver> {
// Even though the generic method defined in Observable would be perfectly
// fine on its own, we can't delete this overridden method because it would
// potentially break binary compatibility with existing applications.
@Override
public void registerObserver(ContentObserver observer) {
super.registerObserver(observer);
}
/**
* Invokes {@link ContentObserver#dispatchChange(boolean)} on each observer.
* <p>
* If <code>selfChange</code> is true, only delivers the notification
* to the observer if it has indicated that it wants to receive self-change
* notifications by implementing {@link ContentObserver#deliverSelfNotifications}
* to return true.
* </p>
*
* @param selfChange True if this is a self-change notification.
*
* @deprecated Use {@link #dispatchChange(boolean, Uri)} instead.
*/
@Deprecated
public void dispatchChange(boolean selfChange) {
dispatchChange(selfChange, null);
}
/**
* Invokes {@link ContentObserver#dispatchChange(boolean, Uri)} on each observer.
* Includes the changed content Uri when available.
* <p>
* If <code>selfChange</code> is true, only delivers the notification
* to the observer if it has indicated that it wants to receive self-change
* notifications by implementing {@link ContentObserver#deliverSelfNotifications}
* to return true.
* </p>
*
* @param selfChange True if this is a self-change notification.
* @param uri The Uri of the changed content, or null if unknown.
*/
public void dispatchChange(boolean selfChange, Uri uri) {
synchronized(mObservers) {
for (ContentObserver observer : mObservers) {
if (!selfChange || observer.deliverSelfNotifications()) {
observer.dispatchChange(selfChange, uri);
}
}
}
}
/**
* Invokes {@link ContentObserver#onChange} on each observer.
*
* @param selfChange True if this is a self-change notification.
*
* @deprecated Use {@link #dispatchChange} instead.
*/
@Deprecated
public void notifyChange(boolean selfChange) {
synchronized(mObservers) {
for (ContentObserver observer : mObservers) {
observer.onChange(selfChange, null);
}
}
}
}

View File

@@ -1,11 +1,251 @@
/*
* Copyright (C) 2007 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.net.Uri;
import android.os.Handler;
import android.os.UserHandle;
import java.util.Arrays;
import java.util.Collection;
/**
* Receives call backs for changes to content.
* Must be implemented by objects which are added to a {@link ContentObservable}.
*/
public abstract class ContentObserver {
/**
* Starting in {@link android.os.Build.VERSION_CODES#R}, there is a new
* public API overload {@link #onChange(boolean, Uri, int)} that delivers a
* {@code int flags} argument.
* <p>
* Some apps may be relying on a previous hidden API that delivered a
* {@code int userId} argument, and this change is used to control delivery
* of the new {@code int flags} argument in its place.
*/
private static final long ADD_CONTENT_OBSERVER_FLAGS = 150939131L;
private final Object mLock = new Object();
Handler mHandler;
public class ContentObserver {
public ContentObserver() {
}
/**
* Creates a content observer.
*
* @param handler The handler to run {@link #onChange} on, or null if none.
*/
public ContentObserver(Handler handler) {
mHandler = handler;
}
}
/**
* Returns true if this observer is interested receiving self-change notifications.
*
* Subclasses should override this method to indicate whether the observer
* is interested in receiving notifications for changes that it made to the
* content itself.
*
* @return True if self-change notifications should be delivered to the observer.
*/
public boolean deliverSelfNotifications() {
return false;
}
/**
* This method is called when a content change occurs.
* <p>
* Subclasses should override this method to handle content changes.
* </p>
*
* @param selfChange True if this is a self-change notification.
*/
public void onChange(boolean selfChange) {
// Do nothing. Subclass should override.
}
/**
* This method is called when a content change occurs.
* Includes the changed content Uri when available.
* <p>
* Subclasses should override this method to handle content changes. To
* ensure correct operation on older versions of the framework that did not
* provide richer arguments, applications should implement all overloads.
* <p>
* Example implementation:
* <pre><code>
* // Implement the onChange(boolean) method to delegate the change notification to
* // the onChange(boolean, Uri) method to ensure correct operation on older versions
* // of the framework that did not have the onChange(boolean, Uri) method.
* {@literal @Override}
* public void onChange(boolean selfChange) {
* onChange(selfChange, null);
* }
*
* // Implement the onChange(boolean, Uri) method to take advantage of the new Uri argument.
* {@literal @Override}
* public void onChange(boolean selfChange, Uri uri) {
* // Handle change.
* }
* </code></pre>
* </p>
*
* @param selfChange True if this is a self-change notification.
* @param uri The Uri of the changed content.
*/
public void onChange(boolean selfChange, Uri uri) {
onChange(selfChange);
}
/**
* This method is called when a content change occurs. Includes the changed
* content Uri when available.
* <p>
* Subclasses should override this method to handle content changes. To
* ensure correct operation on older versions of the framework that did not
* provide richer arguments, applications should implement all overloads.
*
* @param selfChange True if this is a self-change notification.
* @param uri The Uri of the changed content.
* @param flags Flags indicating details about this change.
*/
public void onChange(boolean selfChange, Uri uri, int flags) {
onChange(selfChange, uri);
}
/**
* This method is called when a content change occurs. Includes the changed
* content Uris when available.
* <p>
* Subclasses should override this method to handle content changes. To
* ensure correct operation on older versions of the framework that did not
* provide richer arguments, applications should implement all overloads.
*
* @param selfChange True if this is a self-change notification.
* @param uris The Uris of the changed content.
* @param flags Flags indicating details about this change.
*/
public void onChange(boolean selfChange, Collection<Uri> uris,
int flags) {
for (Uri uri : uris) {
onChange(selfChange, uri, flags);
}
}
/**
* This method is called when a content change occurs. Includes the changed
* content Uris when available.
* <p>
* Subclasses should override this method to handle content changes. To
* ensure correct operation on older versions of the framework that did not
* provide richer arguments, applications should implement all overloads.
*
* @param selfChange True if this is a self-change notification.
* @param uris The Uris of the changed content.
* @param flags Flags indicating details about this change.
* @param user The corresponding {@link UserHandle} for the current notification.
*
* @hide
*/
public void onChange(boolean selfChange, Collection<Uri> uris,
int flags, UserHandle user) {
onChange(selfChange, uris, user.getIdentifier());
}
/** @hide */
public void onChange(boolean selfChange, Collection<Uri> uris,
int flags, int userId) {
// There are dozens of people relying on the hidden API inside the
// system UID, so hard-code the old behavior for all of them; for
// everyone else we gate based on a specific change
// if (!CompatChanges.isChangeEnabled(ADD_CONTENT_OBSERVER_FLAGS)
// || android.os.Process.myUid() == android.os.Process.SYSTEM_UID) {
// // Deliver userId through argument to preserve hidden API behavior
// onChange(selfChange, uris, flags, UserHandle.of(userId));
// } else {
onChange(selfChange, uris, flags);
// }
}
/**
* Dispatches a change notification to the observer.
* <p>
* If a {@link Handler} was supplied to the {@link ContentObserver}
* constructor, then a call to the {@link #onChange} method is posted to the
* handler's message queue. Otherwise, the {@link #onChange} method is
* invoked immediately on this thread.
*
* @deprecated Callers should migrate towards using a richer overload that
* provides more details about the change, such as
* {@link #dispatchChange(boolean, Collection, int)}.
*/
@Deprecated
public final void dispatchChange(boolean selfChange) {
dispatchChange(selfChange, null);
}
/**
* Dispatches a change notification to the observer. Includes the changed
* content Uri when available.
* <p>
* If a {@link Handler} was supplied to the {@link ContentObserver}
* constructor, then a call to the {@link #onChange} method is posted to the
* handler's message queue. Otherwise, the {@link #onChange} method is
* invoked immediately on this thread.
*
* @param selfChange True if this is a self-change notification.
* @param uri The Uri of the changed content.
*/
public final void dispatchChange(boolean selfChange, Uri uri) {
dispatchChange(selfChange, uri, 0);
}
/**
* Dispatches a change notification to the observer. Includes the changed
* content Uri when available.
* <p>
* If a {@link Handler} was supplied to the {@link ContentObserver}
* constructor, then a call to the {@link #onChange} method is posted to the
* handler's message queue. Otherwise, the {@link #onChange} method is
* invoked immediately on this thread.
*
* @param selfChange True if this is a self-change notification.
* @param uri The Uri of the changed content.
* @param flags Flags indicating details about this change.
*/
public final void dispatchChange(boolean selfChange, Uri uri,
int flags) {
dispatchChange(selfChange, Arrays.asList(uri), flags);
}
/**
* Dispatches a change notification to the observer. Includes the changed
* content Uris when available.
* <p>
* If a {@link Handler} was supplied to the {@link ContentObserver}
* constructor, then a call to the {@link #onChange} method is posted to the
* handler's message queue. Otherwise, the {@link #onChange} method is
* invoked immediately on this thread.
*
* @param selfChange True if this is a self-change notification.
* @param uris The Uri of the changed content.
* @param flags Flags indicating details about this change.
*/
public final void dispatchChange(boolean selfChange, Collection<Uri> uris,
int flags) {
dispatchChange(selfChange, uris, flags, UserHandle.getCallingUserId());
}
/** @hide */
public final void dispatchChange(final boolean selfChange, final Collection<Uri> uris,
final int flags, final int userId) {
if (mHandler == null) {
onChange(selfChange, uris, flags, userId);
} else {
mHandler.post(new Runnable(){
@Override
public void run() {
onChange(selfChange, uris, flags, userId);
}
});
}
}
}

View File

@@ -0,0 +1,78 @@
/*
* Copyright (C) 2008 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;
/**
* A cross process cursor is an extension of a {@link Cursor} that also supports
* usage from remote processes.
* <p>
* The contents of a cross process cursor are marshalled to the remote process by
* filling {@link CursorWindow} objects using {@link #fillWindow}. As an optimization,
* the cursor can provide a pre-filled window to use via {@link #getWindow} thereby
* obviating the need to copy the data to yet another cursor window.
*/
public interface CrossProcessCursor extends Cursor {
/**
* Returns a pre-filled window that contains the data within this cursor.
* <p>
* In particular, the window contains the row indicated by {@link Cursor#getPosition}.
* The window's contents are automatically scrolled whenever the current
* row moved outside the range covered by the window.
* </p>
*
* @return The pre-filled window, or null if none.
*/
CursorWindow getWindow();
/**
* Copies cursor data into the window.
* <p>
* Clears the window and fills it with data beginning at the requested
* row position until all of the data in the cursor is exhausted
* or the window runs out of space.
* </p><p>
* The filled window uses the same row indices as the original cursor.
* For example, if you fill a window starting from row 5 from the cursor,
* you can query the contents of row 5 from the window just by asking it
* for row 5 because there is a direct correspondence between the row indices
* used by the cursor and the window.
* </p><p>
* The current position of the cursor, as returned by {@link #getPosition},
* is not changed by this method.
* </p>
*
* @param position The zero-based index of the first row to copy into the window.
* @param window The window to fill.
*/
void fillWindow(int position, CursorWindow window);
/**
* This function is called every time the cursor is successfully scrolled
* to a new position, giving the subclass a chance to update any state it
* may have. If it returns false the move function will also do so and the
* cursor will scroll to the beforeFirst position.
* <p>
* This function should be called by methods such as {@link #moveToPosition(int)},
* so it will typically not be called from outside of the cursor class itself.
* </p>
*
* @param oldPosition The position that we're moving from.
* @param newPosition The position that we're moving to.
* @return True if the move is successful, false otherwise.
*/
boolean onMove(int oldPosition, int newPosition);
}

View File

@@ -17,13 +17,10 @@
package android.database;
import android.content.ContentResolver;
import android.database.ContentObserver;
import android.net.Uri;
import android.os.Bundle;
import java.io.Closeable;
class CharArrayBuffer {}
/**
* This interface provides random read-write access to the result set returned
* by a database query.
@@ -80,7 +77,7 @@ public interface Cursor extends Closeable {
*
* @return the current cursor position.
*/
// int getPosition();
int getPosition();
/**
* Move the cursor by a relative amount, forward or backward, from the
@@ -97,7 +94,7 @@ public interface Cursor extends Closeable {
* @param offset the offset to be applied from the current position.
* @return whether the requested move fully succeeded.
*/
// boolean move(int offset);
boolean move(int offset);
/**
* Move the cursor to an absolute position. The valid
@@ -109,7 +106,7 @@ public interface Cursor extends Closeable {
* @param position the zero-based position to move to.
* @return whether the requested move fully succeeded.
*/
// boolean moveToPosition(int position);
boolean moveToPosition(int position);
/**
* Move the cursor to the first row.
@@ -127,7 +124,7 @@ public interface Cursor extends Closeable {
*
* @return whether the move succeeded.
*/
// boolean moveToLast();
boolean moveToLast();
/**
* Move the cursor to the next row.
@@ -147,21 +144,21 @@ public interface Cursor extends Closeable {
*
* @return whether the move succeeded.
*/
// boolean moveToPrevious();
boolean moveToPrevious();
/**
* Returns whether the cursor is pointing to the first row.
*
* @return whether the cursor is pointing at the first entry.
*/
// boolean isFirst();
boolean isFirst();
/**
* Returns whether the cursor is pointing to the last row.
*
* @return whether the cursor is pointing at the last entry.
*/
// boolean isLast();
boolean isLast();
/**
* Returns whether the cursor is pointing to the position before the first
@@ -169,7 +166,7 @@ public interface Cursor extends Closeable {
*
* @return whether the cursor is before the first result.
*/
// boolean isBeforeFirst();
boolean isBeforeFirst();
/**
* Returns whether the cursor is pointing to the position after the last
@@ -202,7 +199,7 @@ public interface Cursor extends Closeable {
* @see #getColumnIndex(String)
* @throws IllegalArgumentException if the column does not exist
*/
// int getColumnIndexOrThrow(String columnName) throws IllegalArgumentException;
int getColumnIndexOrThrow(String columnName) throws IllegalArgumentException;
/**
* Returns the column name at the given zero-based column index.
@@ -210,7 +207,7 @@ public interface Cursor extends Closeable {
* @param columnIndex the zero-based index of the target column.
* @return the column name for the given column index.
*/
// String getColumnName(int columnIndex);
String getColumnName(int columnIndex);
/**
* Returns a string array holding the names of all of the columns in the
@@ -218,13 +215,13 @@ public interface Cursor extends Closeable {
*
* @return the names of the columns returned in this query.
*/
// String[] getColumnNames();
String[] getColumnNames();
/**
* Return total number of columns
* @return number of columns
*/
// int getColumnCount();
int getColumnCount();
/**
* Returns the value of the requested column as a byte array.
@@ -236,7 +233,7 @@ public interface Cursor extends Closeable {
* @param columnIndex the zero-based index of the target column.
* @return the value of that column as a byte array.
*/
// byte[] getBlob(int columnIndex);
byte[] getBlob(int columnIndex);
/**
* Returns the value of the requested column as a String.
@@ -258,7 +255,7 @@ public interface Cursor extends Closeable {
* if the target column is null, return buffer
* @param buffer the buffer to copy the text into.
*/
// void copyStringToBuffer(int columnIndex, CharArrayBuffer buffer);
void copyStringToBuffer(int columnIndex, CharArrayBuffer buffer);
/**
* Returns the value of the requested column as a short.
@@ -271,7 +268,7 @@ public interface Cursor extends Closeable {
* @param columnIndex the zero-based index of the target column.
* @return the value of that column as a short.
*/
// short getShort(int columnIndex);
short getShort(int columnIndex);
/**
* Returns the value of the requested column as an int.
@@ -310,7 +307,7 @@ public interface Cursor extends Closeable {
* @param columnIndex the zero-based index of the target column.
* @return the value of that column as a float.
*/
// float getFloat(int columnIndex);
float getFloat(int columnIndex);
/**
* Returns the value of the requested column as a double.
@@ -323,7 +320,7 @@ public interface Cursor extends Closeable {
* @param columnIndex the zero-based index of the target column.
* @return the value of that column as a double.
*/
// double getDouble(int columnIndex);
double getDouble(int columnIndex);
/**
* Returns data type of the given column's value.
@@ -344,7 +341,7 @@ public interface Cursor extends Closeable {
* @param columnIndex the zero-based index of the target column.
* @return column value type
*/
// int getType(int columnIndex);
int getType(int columnIndex);
/**
* Returns <code>true</code> if the value in the indicated column is null.
@@ -352,7 +349,7 @@ public interface Cursor extends Closeable {
* @param columnIndex the zero-based index of the target column.
* @return whether the column value is null.
*/
// boolean isNull(int columnIndex);
boolean isNull(int columnIndex);
/**
* Deactivates the Cursor, making all calls on it fail until {@link #requery} is called.
@@ -390,7 +387,7 @@ public interface Cursor extends Closeable {
* return true if the cursor is closed
* @return true if the cursor is closed.
*/
// boolean isClosed();
boolean isClosed();
/**
* Register an observer that is called when changes happen to the content backing this cursor.
@@ -399,7 +396,7 @@ public interface Cursor extends Closeable {
* @param observer the object that gets notified when the content backing the cursor changes.
* @see #unregisterContentObserver(ContentObserver)
*/
// void registerContentObserver(ContentObserver observer);
void registerContentObserver(ContentObserver observer);
/**
* Unregister an observer that has previously been registered with this
@@ -408,7 +405,7 @@ public interface Cursor extends Closeable {
* @param observer the object to unregister.
* @see #registerContentObserver(ContentObserver)
*/
// void unregisterContentObserver(ContentObserver observer);
void unregisterContentObserver(ContentObserver observer);
/**
* Register an observer that is called when changes happen to the contents
@@ -418,7 +415,7 @@ public interface Cursor extends Closeable {
* @param observer the object that gets notified when the cursors data set changes.
* @see #unregisterDataSetObserver(DataSetObserver)
*/
// void registerDataSetObserver(DataSetObserver observer);
void registerDataSetObserver(DataSetObserver observer);
/**
* Unregister an observer that has previously been registered with this
@@ -427,7 +424,7 @@ public interface Cursor extends Closeable {
* @param observer the object to unregister.
* @see #registerDataSetObserver(DataSetObserver)
*/
// void unregisterDataSetObserver(DataSetObserver observer);
void unregisterDataSetObserver(DataSetObserver observer);
/**
* Register to watch a content URI for changes. This can be the URI of a specific data row (for
@@ -437,7 +434,7 @@ public interface Cursor extends Closeable {
* this resolver will be notified.
* @param uri The content URI to watch.
*/
// void setNotificationUri(ContentResolver cr, Uri uri);
void setNotificationUri(ContentResolver cr, Uri uri);
/**
* Return the URI at which notifications of changes in this Cursor's data
@@ -447,13 +444,13 @@ public interface Cursor extends Closeable {
* ContentResolver.registerContentObserver} to find out about changes to this Cursor's
* data. May be null if no notification URI has been set.
*/
// Uri getNotificationUri();
Uri getNotificationUri();
/**
* onMove() will only be called across processes if this method returns true.
* @return whether all cursor movement should result in a call to onMove().
*/
// boolean getWantsAllOnMoveCalls();
boolean getWantsAllOnMoveCalls();
/**
* Returns a bundle of extra values. This is an optional way for cursors to provide out-of-band
@@ -464,7 +461,7 @@ public interface Cursor extends Closeable {
* @return cursor-defined values, or {@link android.os.Bundle#EMPTY Bundle.EMPTY} if there
* are no values. Never <code>null</code>.
*/
// Bundle getExtras();
Bundle getExtras();
/**
* This is an out-of-band way for the the user of a cursor to communicate with the cursor. The
@@ -477,5 +474,5 @@ public interface Cursor extends Closeable {
* @return extra values, or {@link android.os.Bundle#EMPTY Bundle.EMPTY}.
* Never <code>null</code>.
*/
// Bundle respond(Bundle extras);
Bundle respond(Bundle extras);
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,117 @@
/*
* Copyright (C) 2010 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.
*/
/*
** Modified to support SQLite extensions by the SQLite developers:
** sqlite-dev@sqlite.org.
*/
package android.database;
import java.io.File;
import java.util.List;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
import android.util.Log;
import android.util.Pair;
/**
* Default class used to define the action to take when database corruption is reported
* by sqlite.
* <p>
* An application can specify an implementation of {@link DatabaseErrorHandler} on the
* following:
* <ul>
* <li>{@link SQLiteDatabase#openOrCreateDatabase(String,
* android.database.sqlite.SQLiteDatabase.CursorFactory, DatabaseErrorHandler)}</li>
* <li>{@link SQLiteDatabase#openDatabase(String,
* android.database.sqlite.SQLiteDatabase.CursorFactory, int, DatabaseErrorHandler)}</li>
* </ul>
* The specified {@link DatabaseErrorHandler} is used to handle database corruption errors, if they
* occur.
* <p>
* If null is specified for the DatabaseErrorHandler param in the above calls, this class is used
* as the default {@link DatabaseErrorHandler}.
*/
public final class DefaultDatabaseErrorHandler implements DatabaseErrorHandler {
private static final String TAG = "DefaultDatabaseErrorHandler";
/**
* defines the default method to be invoked when database corruption is detected.
* @param dbObj the {@link SQLiteDatabase} object representing the database on which corruption
* is detected.
*/
public void onCorruption(SQLiteDatabase dbObj) {
Log.e(TAG, "Corruption reported by sqlite on database: " + dbObj.getPath());
// If this is a SEE build, do not delete any database files.
// It may be that the user has specified an incorrect password.
if( SQLiteDatabase.hasCodec() ) return;
// is the corruption detected even before database could be 'opened'?
if (!dbObj.isOpen()) {
// database files are not even openable. delete this database file.
// NOTE if the database has attached databases, then any of them could be corrupt.
// and not deleting all of them could cause corrupted database file to remain and
// make the application crash on database open operation. To avoid this problem,
// the application should provide its own {@link DatabaseErrorHandler} impl class
// to delete ALL files of the database (including the attached databases).
deleteDatabaseFile(dbObj.getPath());
return;
}
List<Pair<String, String>> attachedDbs = null;
try {
// Close the database, which will cause subsequent operations to fail.
// before that, get the attached database list first.
try {
attachedDbs = dbObj.getAttachedDbs();
} catch (SQLiteException e) {
/* ignore */
}
try {
dbObj.close();
} catch (SQLiteException e) {
/* ignore */
}
} finally {
// Delete all files of this corrupt database and/or attached databases
if (attachedDbs != null) {
for (Pair<String, String> p : attachedDbs) {
deleteDatabaseFile(p.second);
}
} else {
// attachedDbs = null is possible when the database is so corrupt that even
// "PRAGMA database_list;" also fails. delete the main database file
deleteDatabaseFile(dbObj.getPath());
}
}
}
private void deleteDatabaseFile(String fileName) {
if (fileName.equalsIgnoreCase(":memory:") || fileName.trim().length() == 0) {
return;
}
Log.e(TAG, "deleting the database file: " + fileName);
try {
SQLiteDatabase.deleteDatabase(new File(fileName));
} catch (Exception e) {
/* print warning and ignore exception */
Log.w(TAG, "delete failed: " + e.getMessage());
}
}
}

View File

@@ -0,0 +1,37 @@
/*
* 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.
*/
/*
** Modified to support SQLite extensions by the SQLite developers:
** sqlite-dev@sqlite.org.
*/
package android.database;
/**
* An exception that indicates there was an error with SQL parsing or execution.
*/
public class SQLException extends RuntimeException {
public SQLException() {
}
public SQLException(String error) {
super(error);
}
public SQLException(String error, Throwable cause) {
super(error, cause);
}
}

View File

@@ -0,0 +1,35 @@
/*
* 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.
*/
/*
** Modified to support SQLite extensions by the SQLite developers:
** sqlite-dev@sqlite.org.
*/
package android.database.sqlite;
/**
* An exception that indicates that garbage-collector is finalizing a database object
* that is not explicitly closed
* @hide
*/
public class DatabaseObjectNotClosedException extends RuntimeException {
private static final String s = "Application did not close the cursor or database object " +
"that was opened here";
public DatabaseObjectNotClosedException() {
super(s);
}
}

View File

@@ -0,0 +1,34 @@
/*
* Copyright (C) 2008 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.
*/
/*
** Modified to support SQLite extensions by the SQLite developers:
** sqlite-dev@sqlite.org.
*/
package android.database.sqlite;
/**
* An exception that indicates that the SQLite program was aborted.
* This can happen either through a call to ABORT in a trigger,
* or as the result of using the ABORT conflict clause.
*/
public class SQLiteAbortException extends SQLiteException {
public SQLiteAbortException() {}
public SQLiteAbortException(String error) {
super(error);
}
}

View File

@@ -0,0 +1,33 @@
/*
* Copyright (C) 2010 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.
*/
/*
** Modified to support SQLite extensions by the SQLite developers:
** sqlite-dev@sqlite.org.
*/
package android.database.sqlite;
/**
* This exception class is used when sqlite can't access the database file
* due to lack of permissions on the file.
*/
public class SQLiteAccessPermException extends SQLiteException {
public SQLiteAccessPermException() {}
public SQLiteAccessPermException(String error) {
super(error);
}
}

Some files were not shown because too many files have changed in this diff Show More