Replace ContentProvider SQL args w/ Bundle & Constants.
Test: cts-tradefed run cts-dev -m CtsContentTestCases
Bug: 30927484
Change-Id: Idb9dbc2b80896e9f8474a0db71353b7a3810d597
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index f369409..cda98e5 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -97,6 +97,7 @@
* developer guide.</p>
*/
public abstract class ContentProvider implements ComponentCallbacks2 {
+
private static final String TAG = "ContentProvider";
/*
@@ -118,7 +119,7 @@
private boolean mNoPerms;
private boolean mSingleUser;
- private final ThreadLocal<String> mCallingPackage = new ThreadLocal<String>();
+ private final ThreadLocal<String> mCallingPackage = new ThreadLocal<>();
private Transport mTransport = new Transport();
@@ -205,9 +206,8 @@
}
@Override
- public Cursor query(String callingPkg, Uri uri, String[] projection,
- String selection, String[] selectionArgs, String sortOrder,
- ICancellationSignal cancellationSignal) {
+ public Cursor query(String callingPkg, Uri uri, @Nullable String[] projection,
+ @Nullable Bundle queryArgs, @Nullable ICancellationSignal cancellationSignal) {
validateIncomingUri(uri);
uri = maybeGetUriWithoutUserId(uri);
if (enforceReadPermission(callingPkg, uri, null) != AppOpsManager.MODE_ALLOWED) {
@@ -225,9 +225,9 @@
// However, the caller may be expecting to access them my index. Hence,
// we have to execute the query as if allowed to get a cursor with the
// columns. We then use the column names to return an empty cursor.
- Cursor cursor = ContentProvider.this.query(uri, projection, selection,
- selectionArgs, sortOrder, CancellationSignal.fromTransport(
- cancellationSignal));
+ Cursor cursor = ContentProvider.this.query(
+ uri, projection, queryArgs,
+ CancellationSignal.fromTransport(cancellationSignal));
if (cursor == null) {
return null;
}
@@ -238,7 +238,7 @@
final String original = setCallingPackage(callingPkg);
try {
return ContentProvider.this.query(
- uri, projection, selection, selectionArgs, sortOrder,
+ uri, projection, queryArgs,
CancellationSignal.fromTransport(cancellationSignal));
} finally {
setCallingPackage(original);
@@ -893,6 +893,7 @@
* (Content providers do not usually care about things like screen
* orientation, but may want to know about locale changes.)
*/
+ @Override
public void onConfigurationChanged(Configuration newConfig) {
}
@@ -904,9 +905,11 @@
* <p>The default content provider implementation does nothing.
* Subclasses may override this method to take appropriate action.
*/
+ @Override
public void onLowMemory() {
}
+ @Override
public void onTrimMemory(int level) {
}
@@ -1039,6 +1042,45 @@
}
/**
+ * Implement this to handle query requests where the arguments are packed into a {@link Bundle}.
+ * Arguments may include traditional SQL style query arguments. When present these
+ * should be handled according to the contract established in
+ * {@link #query(Uri, String[], String, String[], String, CancellationSignal).
+ *
+ * <p>Traditional SQL arguments can be found in the bundle using the following keys:
+ * <li>{@link ContentResolver#QUERY_ARG_SELECTION}
+ * <li>{@link ContentResolver#QUERY_ARG_SELECTION_ARGS}
+ * <li>{@link ContentResolver#QUERY_ARG_SORT_ORDER}
+ *
+ * @see #query(Uri, String[], String, String[], String, CancellationSignal) for
+ * implementation details.
+ *
+ * @param uri The URI to query. This will be the full URI sent by the client.
+ * TODO: Me wonders about this use case, and how we adapt it.
+ * 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 {@code null} provide a default set of columns.
+ * @param queryArgs A Bundle containing all additional information necessary for the query.
+ * Values in the Bundle may include SQL style arguments.
+ * @param cancellationSignal A signal to cancel the operation in progress,
+ * or {@code null}.
+ * @return a Cursor or {@code null}.
+ */
+ public @Nullable Cursor query(@NonNull Uri uri, @Nullable String[] projection,
+ @Nullable Bundle queryArgs, @Nullable CancellationSignal cancellationSignal) {
+ queryArgs = queryArgs != null ? queryArgs : Bundle.EMPTY;
+ return query(
+ uri,
+ projection,
+ queryArgs.getString(ContentResolver.QUERY_ARG_SELECTION),
+ queryArgs.getStringArray(ContentResolver.QUERY_ARG_SELECTION_ARGS),
+ queryArgs.getString(ContentResolver.QUERY_ARG_SORT_ORDER),
+ cancellationSignal);
+ }
+
+ /**
* 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,
@@ -1412,7 +1454,7 @@
* no file associated with the given URI or the mode is invalid.
* @throws SecurityException Throws SecurityException if the caller does
* not have permission to access the file.
- *
+ *
* @see #openFile(Uri, String)
* @see #openFileHelper(Uri, String)
* @see #getType(android.net.Uri)
@@ -1851,7 +1893,7 @@
/**
* Implement this to shut down the ContentProvider instance. You can then
* invoke this method in unit tests.
- *
+ *
* <p>
* Android normally handles ContentProvider startup and shutdown
* automatically. You do not need to start up or shut down a