summaryrefslogtreecommitdiffstats
path: root/core/java/android/content
diff options
context:
space:
mode:
Diffstat (limited to 'core/java/android/content')
-rw-r--r--core/java/android/content/AsyncTaskLoader.java20
-rw-r--r--core/java/android/content/CancelationSignal.java164
-rw-r--r--core/java/android/content/ContentProvider.java93
-rw-r--r--core/java/android/content/ContentProviderClient.java15
-rw-r--r--core/java/android/content/ContentProviderNative.java41
-rw-r--r--core/java/android/content/ContentResolver.java52
-rw-r--r--core/java/android/content/CursorLoader.java39
-rw-r--r--core/java/android/content/ICancelationSignal.aidl24
-rw-r--r--core/java/android/content/IContentProvider.java5
-rw-r--r--core/java/android/content/OperationCanceledException.java32
10 files changed, 465 insertions, 20 deletions
diff --git a/core/java/android/content/AsyncTaskLoader.java b/core/java/android/content/AsyncTaskLoader.java
index 0b54396..944ca6b 100644
--- a/core/java/android/content/AsyncTaskLoader.java
+++ b/core/java/android/content/AsyncTaskLoader.java
@@ -173,6 +173,7 @@ public abstract class AsyncTaskLoader<D> extends Loader<D> {
if (DEBUG) Slog.v(TAG, "cancelLoad: cancelled=" + cancelled);
if (cancelled) {
mCancellingTask = mTask;
+ onCancelLoadInBackground();
}
mTask = null;
return cancelled;
@@ -256,6 +257,25 @@ public abstract class AsyncTaskLoader<D> extends Loader<D> {
}
/**
+ * Override this method to try to abort the computation currently taking
+ * place on a background thread.
+ *
+ * Note that when this method is called, it is possible that {@link #loadInBackground}
+ * has not started yet or has already completed.
+ */
+ protected void onCancelLoadInBackground() {
+ }
+
+ /**
+ * Returns true if the current execution of {@link #loadInBackground()} is being canceled.
+ *
+ * @return True if the current execution of {@link #loadInBackground()} is being canceled.
+ */
+ protected boolean isLoadInBackgroundCanceled() {
+ return mCancellingTask != null;
+ }
+
+ /**
* Locks the current thread until the loader completes the current load
* operation. Returns immediately if there is no load operation running.
* Should not be called from the UI thread: calling it from the UI
diff --git a/core/java/android/content/CancelationSignal.java b/core/java/android/content/CancelationSignal.java
new file mode 100644
index 0000000..58cf59d
--- /dev/null
+++ b/core/java/android/content/CancelationSignal.java
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2012 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.content;
+
+import android.os.RemoteException;
+
+/**
+ * Provides the ability to cancel an operation in progress.
+ */
+public final class CancelationSignal {
+ private boolean mIsCanceled;
+ private OnCancelListener mOnCancelListener;
+ private ICancelationSignal mRemote;
+
+ /**
+ * Creates a cancelation signal, initially not canceled.
+ */
+ public CancelationSignal() {
+ }
+
+ /**
+ * Returns true if the operation has been canceled.
+ *
+ * @return True if the operation has been canceled.
+ */
+ public boolean isCanceled() {
+ synchronized (this) {
+ return mIsCanceled;
+ }
+ }
+
+ /**
+ * Throws {@link OperationCanceledException} if the operation has been canceled.
+ *
+ * @throws OperationCanceledException if the operation has been canceled.
+ */
+ public void throwIfCanceled() {
+ if (isCanceled()) {
+ throw new OperationCanceledException();
+ }
+ }
+
+ /**
+ * Cancels the operation and signals the cancelation listener.
+ * If the operation has not yet started, then it will be canceled as soon as it does.
+ */
+ public void cancel() {
+ synchronized (this) {
+ if (!mIsCanceled) {
+ mIsCanceled = true;
+ if (mOnCancelListener != null) {
+ mOnCancelListener.onCancel();
+ }
+ if (mRemote != null) {
+ try {
+ mRemote.cancel();
+ } catch (RemoteException ex) {
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Sets the cancelation listener to be called when canceled.
+ * If {@link CancelationSignal#cancel} has already been called, then the provided
+ * listener is invoked immediately.
+ *
+ * The listener is called while holding the cancelation signal's lock which is
+ * also held while registering or unregistering the listener. Because of the lock,
+ * it is not possible for the listener to run after it has been unregistered.
+ * This design choice makes it easier for clients of {@link CancelationSignal} to
+ * prevent race conditions related to listener registration and unregistration.
+ *
+ * @param listener The cancelation listener, or null to remove the current listener.
+ */
+ public void setOnCancelListener(OnCancelListener listener) {
+ synchronized (this) {
+ mOnCancelListener = listener;
+ if (mIsCanceled && listener != null) {
+ listener.onCancel();
+ }
+ }
+ }
+
+ /**
+ * Sets the remote transport.
+ *
+ * @param remote The remote transport, or null to remove.
+ *
+ * @hide
+ */
+ public void setRemote(ICancelationSignal remote) {
+ synchronized (this) {
+ mRemote = remote;
+ if (mIsCanceled && remote != null) {
+ try {
+ remote.cancel();
+ } catch (RemoteException ex) {
+ }
+ }
+ }
+ }
+
+ /**
+ * Creates a transport that can be returned back to the caller of
+ * a Binder function and subsequently used to dispatch a cancelation signal.
+ *
+ * @return The new cancelation signal transport.
+ *
+ * @hide
+ */
+ public static ICancelationSignal createTransport() {
+ return new Transport();
+ }
+
+ /**
+ * Given a locally created transport, returns its associated cancelation signal.
+ *
+ * @param transport The locally created transport, or null if none.
+ * @return The associated cancelation signal, or null if none.
+ *
+ * @hide
+ */
+ public static CancelationSignal fromTransport(ICancelationSignal transport) {
+ if (transport instanceof Transport) {
+ return ((Transport)transport).mCancelationSignal;
+ }
+ return null;
+ }
+
+ /**
+ * Listens for cancelation.
+ */
+ public interface OnCancelListener {
+ /**
+ * Called when {@link CancelationSignal#cancel} is invoked.
+ */
+ void onCancel();
+ }
+
+ private static final class Transport extends ICancelationSignal.Stub {
+ final CancelationSignal mCancelationSignal = new CancelationSignal();
+
+ @Override
+ public void cancel() throws RemoteException {
+ mCancelationSignal.cancel();
+ }
+ }
+}
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index 116ca48..adbeb6a 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -29,6 +29,7 @@ import android.os.Binder;
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
import android.os.Process;
+import android.os.RemoteException;
import android.util.Log;
import java.io.File;
@@ -174,28 +175,33 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
return getContentProvider().getClass().getName();
}
+ @Override
public Cursor query(Uri uri, String[] projection,
- String selection, String[] selectionArgs, String sortOrder) {
+ String selection, String[] selectionArgs, String sortOrder,
+ ICancelationSignal cancelationSignal) {
enforceReadPermission(uri);
- return ContentProvider.this.query(uri, projection, selection,
- selectionArgs, sortOrder);
+ return ContentProvider.this.query(uri, projection, selection, selectionArgs, sortOrder,
+ CancelationSignal.fromTransport(cancelationSignal));
}
+ @Override
public String getType(Uri uri) {
return ContentProvider.this.getType(uri);
}
-
+ @Override
public Uri insert(Uri uri, ContentValues initialValues) {
enforceWritePermission(uri);
return ContentProvider.this.insert(uri, initialValues);
}
+ @Override
public int bulkInsert(Uri uri, ContentValues[] initialValues) {
enforceWritePermission(uri);
return ContentProvider.this.bulkInsert(uri, initialValues);
}
+ @Override
public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations)
throws OperationApplicationException {
for (ContentProviderOperation operation : operations) {
@@ -210,17 +216,20 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
return ContentProvider.this.applyBatch(operations);
}
+ @Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
enforceWritePermission(uri);
return ContentProvider.this.delete(uri, selection, selectionArgs);
}
+ @Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
enforceWritePermission(uri);
return ContentProvider.this.update(uri, values, selection, selectionArgs);
}
+ @Override
public ParcelFileDescriptor openFile(Uri uri, String mode)
throws FileNotFoundException {
if (mode != null && mode.startsWith("rw")) enforceWritePermission(uri);
@@ -228,6 +237,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
return ContentProvider.this.openFile(uri, mode);
}
+ @Override
public AssetFileDescriptor openAssetFile(Uri uri, String mode)
throws FileNotFoundException {
if (mode != null && mode.startsWith("rw")) enforceWritePermission(uri);
@@ -235,6 +245,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
return ContentProvider.this.openAssetFile(uri, mode);
}
+ @Override
public Bundle call(String method, String arg, Bundle extras) {
return ContentProvider.this.call(method, arg, extras);
}
@@ -251,6 +262,11 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
return ContentProvider.this.openTypedAssetFile(uri, mimeType, opts);
}
+ @Override
+ public ICancelationSignal createCancelationSignal() throws RemoteException {
+ return CancelationSignal.createTransport();
+ }
+
private void enforceReadPermission(Uri uri) {
final int uid = Binder.getCallingUid();
if (uid == mMyUid) {
@@ -541,6 +557,75 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
String selection, String[] selectionArgs, String sortOrder);
/**
+ * Implement this to handle query requests from clients with support for cancelation.
+ * This method can be called from multiple threads, as described in
+ * <a href="{@docRoot}guide/topics/fundamentals/processes-and-threads.html#Threads">Processes
+ * and Threads</a>.
+ * <p>
+ * Example client call:<p>
+ * <pre>// Request a specific record.
+ * Cursor managedCursor = managedQuery(
+ ContentUris.withAppendedId(Contacts.People.CONTENT_URI, 2),
+ projection, // Which columns to return.
+ null, // WHERE clause.
+ null, // WHERE clause value substitution
+ People.NAME + " ASC"); // Sort order.</pre>
+ * Example implementation:<p>
+ * <pre>// SQLiteQueryBuilder is a helper class that creates the
+ // proper SQL syntax for us.
+ SQLiteQueryBuilder qBuilder = new SQLiteQueryBuilder();
+
+ // Set the table we're querying.
+ qBuilder.setTables(DATABASE_TABLE_NAME);
+
+ // If the query ends in a specific record number, we're
+ // being asked for a specific record, so set the
+ // WHERE clause in our query.
+ if((URI_MATCHER.match(uri)) == SPECIFIC_MESSAGE){
+ qBuilder.appendWhere("_id=" + uri.getPathLeafId());
+ }
+
+ // Make the query.
+ Cursor c = qBuilder.query(mDb,
+ projection,
+ selection,
+ selectionArgs,
+ groupBy,
+ having,
+ sortOrder);
+ c.setNotificationUri(getContext().getContentResolver(), uri);
+ return c;</pre>
+ * <p>
+ * If you implement this method then you must also implement the version of
+ * {@link #query(Uri, String[], String, String[], String)} that does not take a cancelation
+ * provider to ensure correct operation on older versions of the Android Framework in
+ * which the cancelation signal overload was not available.
+ *
+ * @param uri The URI to query. This will be the full URI sent by the client;
+ * if the client is requesting a specific record, the URI will end in a record number
+ * that the implementation should parse and add to a WHERE or HAVING clause, specifying
+ * that _id value.
+ * @param projection The list of columns to put into the cursor. If
+ * null all columns are included.
+ * @param selection A selection criteria to apply when filtering rows.
+ * If null then all rows are included.
+ * @param selectionArgs You may include ?s in selection, which will be replaced by
+ * the values from selectionArgs, in order that they appear in the selection.
+ * The values will be bound as Strings.
+ * @param sortOrder How the rows in the cursor should be sorted.
+ * If null then the provider is free to define the sort order.
+ * @param cancelationSignal A signal to cancel the operation in progress, or null if none.
+ * If the operation is canceled, then {@link OperationCanceledException} will be thrown
+ * when the query is executed.
+ * @return a Cursor or null.
+ */
+ public Cursor query(Uri uri, String[] projection,
+ String selection, String[] selectionArgs, String sortOrder,
+ CancelationSignal cancelationSignal) {
+ return query(uri, projection, selection, selectionArgs, sortOrder);
+ }
+
+ /**
* Implement this to handle requests for the MIME type of the data at the
* given URI. The returned MIME type should start with
* <code>vnd.android.cursor.item</code> for a single record,
diff --git a/core/java/android/content/ContentProviderClient.java b/core/java/android/content/ContentProviderClient.java
index 0540109..9a1fa65 100644
--- a/core/java/android/content/ContentProviderClient.java
+++ b/core/java/android/content/ContentProviderClient.java
@@ -47,7 +47,20 @@ public class ContentProviderClient {
/** See {@link ContentProvider#query ContentProvider.query} */
public Cursor query(Uri url, String[] projection, String selection,
String[] selectionArgs, String sortOrder) throws RemoteException {
- return mContentProvider.query(url, projection, selection, selectionArgs, sortOrder);
+ return query(url, projection, selection, selectionArgs, sortOrder, null);
+ }
+
+ /** See {@link ContentProvider#query ContentProvider.query} */
+ public Cursor query(Uri url, String[] projection, String selection,
+ String[] selectionArgs, String sortOrder, CancelationSignal cancelationSignal)
+ throws RemoteException {
+ ICancelationSignal remoteCancelationSignal = null;
+ if (cancelationSignal != null) {
+ remoteCancelationSignal = mContentProvider.createCancelationSignal();
+ cancelationSignal.setRemote(remoteCancelationSignal);
+ }
+ return mContentProvider.query(url, projection, selection, selectionArgs, sortOrder,
+ remoteCancelationSignal);
}
/** See {@link ContentProvider#getType ContentProvider.getType} */
diff --git a/core/java/android/content/ContentProviderNative.java b/core/java/android/content/ContentProviderNative.java
index b089bf2..e0e277a 100644
--- a/core/java/android/content/ContentProviderNative.java
+++ b/core/java/android/content/ContentProviderNative.java
@@ -21,7 +21,6 @@ import android.database.BulkCursorNative;
import android.database.BulkCursorToCursorAdaptor;
import android.database.Cursor;
import android.database.CursorToBulkCursorAdaptor;
-import android.database.CursorWindow;
import android.database.DatabaseUtils;
import android.database.IBulkCursor;
import android.database.IContentObserver;
@@ -41,8 +40,6 @@ import java.util.ArrayList;
* {@hide}
*/
abstract public class ContentProviderNative extends Binder implements IContentProvider {
- private static final String TAG = "ContentProvider";
-
public ContentProviderNative()
{
attachInterface(this, descriptor);
@@ -108,8 +105,11 @@ abstract public class ContentProviderNative extends Binder implements IContentPr
String sortOrder = data.readString();
IContentObserver observer = IContentObserver.Stub.asInterface(
data.readStrongBinder());
+ ICancelationSignal cancelationSignal = ICancelationSignal.Stub.asInterface(
+ data.readStrongBinder());
- Cursor cursor = query(url, projection, selection, selectionArgs, sortOrder);
+ Cursor cursor = query(url, projection, selection, selectionArgs, sortOrder,
+ cancelationSignal);
if (cursor != null) {
CursorToBulkCursorAdaptor adaptor = new CursorToBulkCursorAdaptor(
cursor, observer, getProviderName());
@@ -295,6 +295,16 @@ abstract public class ContentProviderNative extends Binder implements IContentPr
}
return true;
}
+
+ case CREATE_CANCELATION_SIGNAL_TRANSACTION:
+ {
+ data.enforceInterface(IContentProvider.descriptor);
+
+ ICancelationSignal cancelationSignal = createCancelationSignal();
+ reply.writeNoException();
+ reply.writeStrongBinder(cancelationSignal.asBinder());
+ return true;
+ }
}
} catch (Exception e) {
DatabaseUtils.writeExceptionToParcel(reply, e);
@@ -324,7 +334,8 @@ final class ContentProviderProxy implements IContentProvider
}
public Cursor query(Uri url, String[] projection, String selection,
- String[] selectionArgs, String sortOrder) throws RemoteException {
+ String[] selectionArgs, String sortOrder, ICancelationSignal cancelationSignal)
+ throws RemoteException {
BulkCursorToCursorAdaptor adaptor = new BulkCursorToCursorAdaptor();
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
@@ -352,6 +363,7 @@ final class ContentProviderProxy implements IContentProvider
}
data.writeString(sortOrder);
data.writeStrongBinder(adaptor.getObserver().asBinder());
+ data.writeStrongBinder(cancelationSignal != null ? cancelationSignal.asBinder() : null);
mRemote.transact(IContentProvider.QUERY_TRANSACTION, data, reply, 0);
@@ -620,5 +632,24 @@ final class ContentProviderProxy implements IContentProvider
}
}
+ public ICancelationSignal createCancelationSignal() throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ try {
+ data.writeInterfaceToken(IContentProvider.descriptor);
+
+ mRemote.transact(IContentProvider.CREATE_CANCELATION_SIGNAL_TRANSACTION,
+ data, reply, 0);
+
+ DatabaseUtils.readExceptionFromParcel(reply);
+ ICancelationSignal cancelationSignal = ICancelationSignal.Stub.asInterface(
+ reply.readStrongBinder());
+ return cancelationSignal;
+ } finally {
+ data.recycle();
+ reply.recycle();
+ }
+ }
+
private IBinder mRemote;
}
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 0debb84..e79475a 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -22,6 +22,7 @@ import android.accounts.Account;
import android.app.ActivityManagerNative;
import android.app.ActivityThread;
import android.app.AppGlobals;
+import android.content.ContentProvider.Transport;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.AssetFileDescriptor;
import android.content.res.Resources;
@@ -302,13 +303,62 @@ public abstract class ContentResolver {
*/
public final Cursor query(Uri uri, String[] projection,
String selection, String[] selectionArgs, String sortOrder) {
+ return query(uri, projection, selection, selectionArgs, sortOrder, null);
+ }
+
+ /**
+ * <p>
+ * Query the given URI, returning a {@link Cursor} over the result set.
+ * </p>
+ * <p>
+ * For best performance, the caller should follow these guidelines:
+ * <ul>
+ * <li>Provide an explicit projection, to prevent
+ * reading data from storage that aren't going to be used.</li>
+ * <li>Use question mark parameter markers such as 'phone=?' instead of
+ * explicit values in the {@code selection} parameter, so that queries
+ * that differ only by those values will be recognized as the same
+ * for caching purposes.</li>
+ * </ul>
+ * </p>
+ *
+ * @param uri The URI, using the content:// scheme, for the content to
+ * retrieve.
+ * @param projection A list of which columns to return. Passing null will
+ * return all columns, which is inefficient.
+ * @param selection A filter declaring which rows to return, formatted as an
+ * SQL WHERE clause (excluding the WHERE itself). Passing null will
+ * return all rows for the given URI.
+ * @param selectionArgs You may include ?s in selection, which will be
+ * replaced by the values from selectionArgs, in the order that they
+ * appear in the selection. The values will be bound as Strings.
+ * @param sortOrder How to order the rows, formatted as an SQL ORDER BY
+ * clause (excluding the ORDER BY itself). Passing null will use the
+ * default sort order, which may be unordered.
+ * @param cancelationSignal A signal to cancel the operation in progress, or null if none.
+ * If the operation is canceled, then {@link OperationCanceledException} will be thrown
+ * when the query is executed.
+ * @return A Cursor object, which is positioned before the first entry, or null
+ * @see Cursor
+ */
+ public final Cursor query(final Uri uri, String[] projection,
+ String selection, String[] selectionArgs, String sortOrder,
+ CancelationSignal cancelationSignal) {
IContentProvider provider = acquireProvider(uri);
if (provider == null) {
return null;
}
try {
long startTime = SystemClock.uptimeMillis();
- Cursor qCursor = provider.query(uri, projection, selection, selectionArgs, sortOrder);
+
+ ICancelationSignal remoteCancelationSignal = null;
+ if (cancelationSignal != null) {
+ cancelationSignal.throwIfCanceled();
+ remoteCancelationSignal = provider.createCancelationSignal();
+ cancelationSignal.setRemote(remoteCancelationSignal);
+ }
+ Cursor qCursor = provider.query(uri, projection,
+ selection, selectionArgs, sortOrder, remoteCancelationSignal);
if (qCursor == null) {
releaseProvider(provider);
return null;
diff --git a/core/java/android/content/CursorLoader.java b/core/java/android/content/CursorLoader.java
index 7af535b..6e4aca8 100644
--- a/core/java/android/content/CursorLoader.java
+++ b/core/java/android/content/CursorLoader.java
@@ -19,7 +19,6 @@ package android.content;
import android.database.ContentObserver;
import android.database.Cursor;
import android.net.Uri;
-import android.os.AsyncTask;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -49,18 +48,42 @@ public class CursorLoader extends AsyncTaskLoader<Cursor> {
String mSortOrder;
Cursor mCursor;
+ CancelationSignal mCancelationSignal;
/* Runs on a worker thread */
@Override
public Cursor loadInBackground() {
- Cursor cursor = getContext().getContentResolver().query(mUri, mProjection, mSelection,
- mSelectionArgs, mSortOrder);
- if (cursor != null) {
- // Ensure the cursor window is filled
- cursor.getCount();
- registerContentObserver(cursor, mObserver);
+ synchronized (this) {
+ if (isLoadInBackgroundCanceled()) {
+ throw new OperationCanceledException();
+ }
+ mCancelationSignal = new CancelationSignal();
+ }
+ try {
+ Cursor cursor = getContext().getContentResolver().query(mUri, mProjection, mSelection,
+ mSelectionArgs, mSortOrder, mCancelationSignal);
+ if (cursor != null) {
+ // Ensure the cursor window is filled
+ cursor.getCount();
+ registerContentObserver(cursor, mObserver);
+ }
+ return cursor;
+ } finally {
+ synchronized (this) {
+ mCancelationSignal = null;
+ }
+ }
+ }
+
+ @Override
+ protected void onCancelLoadInBackground() {
+ super.onCancelLoadInBackground();
+
+ synchronized (this) {
+ if (mCancelationSignal != null) {
+ mCancelationSignal.cancel();
+ }
}
- return cursor;
}
/**
diff --git a/core/java/android/content/ICancelationSignal.aidl b/core/java/android/content/ICancelationSignal.aidl
new file mode 100644
index 0000000..3f5a24d
--- /dev/null
+++ b/core/java/android/content/ICancelationSignal.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2012 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.content;
+
+/**
+ * @hide
+ */
+interface ICancelationSignal {
+ oneway void cancel();
+}
diff --git a/core/java/android/content/IContentProvider.java b/core/java/android/content/IContentProvider.java
index 2a67ff8..f52157f 100644
--- a/core/java/android/content/IContentProvider.java
+++ b/core/java/android/content/IContentProvider.java
@@ -34,7 +34,8 @@ import java.util.ArrayList;
*/
public interface IContentProvider extends IInterface {
public Cursor query(Uri url, String[] projection, String selection,
- String[] selectionArgs, String sortOrder) throws RemoteException;
+ String[] selectionArgs, String sortOrder, ICancelationSignal cancelationSignal)
+ throws RemoteException;
public String getType(Uri url) throws RemoteException;
public Uri insert(Uri url, ContentValues initialValues)
throws RemoteException;
@@ -50,6 +51,7 @@ public interface IContentProvider extends IInterface {
public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations)
throws RemoteException, OperationApplicationException;
public Bundle call(String method, String arg, Bundle extras) throws RemoteException;
+ public ICancelationSignal createCancelationSignal() throws RemoteException;
// Data interchange.
public String[] getStreamTypes(Uri url, String mimeTypeFilter) throws RemoteException;
@@ -71,4 +73,5 @@ public interface IContentProvider extends IInterface {
static final int CALL_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 20;
static final int GET_STREAM_TYPES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 21;
static final int OPEN_TYPED_ASSET_FILE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 22;
+ static final int CREATE_CANCELATION_SIGNAL_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 23;
}
diff --git a/core/java/android/content/OperationCanceledException.java b/core/java/android/content/OperationCanceledException.java
new file mode 100644
index 0000000..24afcfa
--- /dev/null
+++ b/core/java/android/content/OperationCanceledException.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2012 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.content;
+
+/**
+ * An exception type that is thrown when an operation in progress is canceled.
+ *
+ * @see CancelationSignal
+ */
+public class OperationCanceledException extends RuntimeException {
+ public OperationCanceledException() {
+ this(null);
+ }
+
+ public OperationCanceledException(String message) {
+ super(message != null ? message : "The operation has been canceled.");
+ }
+}