2 * Copyright (C) 2006 The Android Open Source Project
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package android.content;
19 import android.accounts.Account;
20 import android.annotation.IntDef;
21 import android.annotation.NonNull;
22 import android.annotation.Nullable;
23 import android.annotation.RequiresPermission;
24 import android.annotation.TestApi;
25 import android.annotation.UserIdInt;
26 import android.app.ActivityManager;
27 import android.app.ActivityThread;
28 import android.app.AppGlobals;
29 import android.content.pm.PackageManager.NameNotFoundException;
30 import android.content.res.AssetFileDescriptor;
31 import android.content.res.Resources;
32 import android.database.ContentObserver;
33 import android.database.CrossProcessCursorWrapper;
34 import android.database.Cursor;
35 import android.database.IContentObserver;
36 import android.graphics.Point;
37 import android.graphics.drawable.Drawable;
38 import android.net.Uri;
39 import android.os.Bundle;
40 import android.os.CancellationSignal;
41 import android.os.DeadObjectException;
42 import android.os.IBinder;
43 import android.os.ICancellationSignal;
44 import android.os.OperationCanceledException;
45 import android.os.ParcelFileDescriptor;
46 import android.os.RemoteException;
47 import android.os.ServiceManager;
48 import android.os.SystemClock;
49 import android.os.UserHandle;
50 import android.text.TextUtils;
51 import android.util.EventLog;
52 import android.util.Log;
54 import com.android.internal.util.ArrayUtils;
55 import com.android.internal.util.MimeIconUtils;
56 import com.android.internal.util.Preconditions;
58 import dalvik.system.CloseGuard;
61 import java.io.FileInputStream;
62 import java.io.FileNotFoundException;
63 import java.io.IOException;
64 import java.io.InputStream;
65 import java.io.OutputStream;
66 import java.lang.annotation.Retention;
67 import java.lang.annotation.RetentionPolicy;
68 import java.util.ArrayList;
69 import java.util.List;
70 import java.util.Random;
71 import java.util.concurrent.atomic.AtomicBoolean;
74 * This class provides applications access to the content model.
76 * <div class="special reference">
77 * <h3>Developer Guides</h3>
78 * <p>For more information about using a ContentResolver with content providers, read the
79 * <a href="{@docRoot}guide/topics/providers/content-providers.html">Content Providers</a>
80 * developer guide.</p>
82 public abstract class ContentResolver {
84 * @deprecated instead use
85 * {@link #requestSync(android.accounts.Account, String, android.os.Bundle)}
88 public static final String SYNC_EXTRAS_ACCOUNT = "account";
91 * If this extra is set to true, the sync request will be scheduled
92 * at the front of the sync request queue and without any delay
94 public static final String SYNC_EXTRAS_EXPEDITED = "expedited";
97 * If this extra is set to true, the sync request will be scheduled
98 * only when the device is plugged in. This is equivalent to calling
99 * setRequiresCharging(true) on {@link SyncRequest}.
101 public static final String SYNC_EXTRAS_REQUIRE_CHARGING = "require_charging";
104 * @deprecated instead use
105 * {@link #SYNC_EXTRAS_MANUAL}
108 public static final String SYNC_EXTRAS_FORCE = "force";
111 * If this extra is set to true then the sync settings (like getSyncAutomatically())
112 * are ignored by the sync scheduler.
114 public static final String SYNC_EXTRAS_IGNORE_SETTINGS = "ignore_settings";
117 * If this extra is set to true then any backoffs for the initial attempt (e.g. due to retries)
118 * are ignored by the sync scheduler. If this request fails and gets rescheduled then the
119 * retries will still honor the backoff.
121 public static final String SYNC_EXTRAS_IGNORE_BACKOFF = "ignore_backoff";
124 * If this extra is set to true then the request will not be retried if it fails.
126 public static final String SYNC_EXTRAS_DO_NOT_RETRY = "do_not_retry";
129 * Setting this extra is the equivalent of setting both {@link #SYNC_EXTRAS_IGNORE_SETTINGS}
130 * and {@link #SYNC_EXTRAS_IGNORE_BACKOFF}
132 public static final String SYNC_EXTRAS_MANUAL = "force";
135 * Indicates that this sync is intended to only upload local changes to the server.
136 * For example, this will be set to true if the sync is initiated by a call to
137 * {@link ContentResolver#notifyChange(android.net.Uri, android.database.ContentObserver, boolean)}
139 public static final String SYNC_EXTRAS_UPLOAD = "upload";
142 * Indicates that the sync adapter should proceed with the delete operations,
143 * even if it determines that there are too many.
144 * See {@link SyncResult#tooManyDeletions}
146 public static final String SYNC_EXTRAS_OVERRIDE_TOO_MANY_DELETIONS = "deletions_override";
149 * Indicates that the sync adapter should not proceed with the delete operations,
150 * if it determines that there are too many.
151 * See {@link SyncResult#tooManyDeletions}
153 public static final String SYNC_EXTRAS_DISCARD_LOCAL_DELETIONS = "discard_deletions";
155 /* Extensions to API. TODO: Not clear if we will keep these as public flags. */
156 /** {@hide} User-specified flag for expected upload size. */
157 public static final String SYNC_EXTRAS_EXPECTED_UPLOAD = "expected_upload";
159 /** {@hide} User-specified flag for expected download size. */
160 public static final String SYNC_EXTRAS_EXPECTED_DOWNLOAD = "expected_download";
162 /** {@hide} Priority of this sync with respect to other syncs scheduled for this application. */
163 public static final String SYNC_EXTRAS_PRIORITY = "sync_priority";
165 /** {@hide} Flag to allow sync to occur on metered network. */
166 public static final String SYNC_EXTRAS_DISALLOW_METERED = "allow_metered";
169 * Set by the SyncManager to request that the SyncAdapter initialize itself for
170 * the given account/authority pair. One required initialization step is to
171 * ensure that {@link #setIsSyncable(android.accounts.Account, String, int)} has been
172 * called with a >= 0 value. When this flag is set the SyncAdapter does not need to
173 * do a full sync, though it is allowed to do so.
175 public static final String SYNC_EXTRAS_INITIALIZE = "initialize";
178 public static final Intent ACTION_SYNC_CONN_STATUS_CHANGED =
179 new Intent("com.android.sync.SYNC_CONN_STATUS_CHANGED");
181 public static final String SCHEME_CONTENT = "content";
182 public static final String SCHEME_ANDROID_RESOURCE = "android.resource";
183 public static final String SCHEME_FILE = "file";
186 * An extra {@link Point} describing the optimal size for a requested image
187 * resource, in pixels. If a provider has multiple sizes of the image, it
188 * should return the image closest to this size.
190 * @see #openTypedAssetFileDescriptor(Uri, String, Bundle)
191 * @see #openTypedAssetFileDescriptor(Uri, String, Bundle,
192 * CancellationSignal)
194 public static final String EXTRA_SIZE = "android.content.extra.SIZE";
197 * An extra boolean describing whether a particular provider supports refresh
198 * or not. If a provider supports refresh, it should include this key in its
199 * returned Cursor as part of its query call.
202 public static final String EXTRA_REFRESH_SUPPORTED = "android.content.extra.REFRESH_SUPPORTED";
205 * Key for an SQL style selection string that may be present in the query Bundle argument
206 * passed to {@link ContentProvider#query(Uri, String[], Bundle, CancellationSignal)}
207 * when called by a legacy client.
209 * <p>Clients should never include user supplied values directly in the selection string,
210 * as this presents an avenue for SQL injection attacks. In lieu of this, a client
211 * should use standard placeholder notation to represent values in a selection string,
212 * then supply a corresponding value in {@value #QUERY_ARG_SQL_SELECTION_ARGS}.
214 * <p><b>Apps targeting {@link android.os.Build.VERSION_CODES#O} or higher are strongly
215 * encourage to use structured query arguments in lieu of opaque SQL query clauses.</b>
217 * @see #QUERY_ARG_SORT_COLUMNS
218 * @see #QUERY_ARG_SORT_DIRECTION
219 * @see #QUERY_ARG_SORT_COLLATION
221 public static final String QUERY_ARG_SQL_SELECTION = "android:query-arg-sql-selection";
224 * Key for SQL selection string arguments list.
226 * <p>Clients should never include user supplied values directly in the selection string,
227 * as this presents an avenue for SQL injection attacks. In lieu of this, a client
228 * should use standard placeholder notation to represent values in a selection string,
229 * then supply a corresponding value in {@value #QUERY_ARG_SQL_SELECTION_ARGS}.
231 * <p><b>Apps targeting {@link android.os.Build.VERSION_CODES#O} or higher are strongly
232 * encourage to use structured query arguments in lieu of opaque SQL query clauses.</b>
234 * @see #QUERY_ARG_SORT_COLUMNS
235 * @see #QUERY_ARG_SORT_DIRECTION
236 * @see #QUERY_ARG_SORT_COLLATION
238 public static final String QUERY_ARG_SQL_SELECTION_ARGS =
239 "android:query-arg-sql-selection-args";
242 * Key for an SQL style sort string that may be present in the query Bundle argument
243 * passed to {@link ContentProvider#query(Uri, String[], Bundle, CancellationSignal)}
244 * when called by a legacy client.
246 * <p><b>Apps targeting {@link android.os.Build.VERSION_CODES#O} or higher are strongly
247 * encourage to use structured query arguments in lieu of opaque SQL query clauses.</b>
249 * @see #QUERY_ARG_SORT_COLUMNS
250 * @see #QUERY_ARG_SORT_DIRECTION
251 * @see #QUERY_ARG_SORT_COLLATION
253 public static final String QUERY_ARG_SQL_SORT_ORDER = "android:query-arg-sql-sort-order";
256 * Specifies the list of columns against which to sort results. When first column values
257 * are identical, records are then sorted based on second column values, and so on.
259 * <p>Columns present in this list must also be included in the projection
260 * supplied to {@link ContentResolver#query(Uri, String[], Bundle, CancellationSignal)}.
262 * <p>Apps targeting {@link android.os.Build.VERSION_CODES#O} or higher:
264 * <li>{@link ContentProvider} implementations: When preparing data in
265 * {@link ContentProvider#query(Uri, String[], Bundle, CancellationSignal)}, if sort columns
266 * is reflected in the returned Cursor, it is strongly recommended that
267 * {@link #QUERY_ARG_SORT_COLUMNS} then be included in the array of honored arguments
268 * reflected in {@link Cursor} extras {@link Bundle} under {@link #EXTRA_HONORED_ARGS}.
270 * <li>When querying a provider, where no QUERY_ARG_SQL* otherwise exists in the
271 * arguments {@link Bundle}, the Content framework will attempt to synthesize
272 * an QUERY_ARG_SQL* argument using the corresponding QUERY_ARG_SORT* values.
274 public static final String QUERY_ARG_SORT_COLUMNS = "android:query-arg-sort-columns";
277 * Specifies desired sort order. When unspecified a provider may provide a default
278 * sort direction, or choose to return unsorted results.
280 * <p>Apps targeting {@link android.os.Build.VERSION_CODES#O} or higher:
282 * <li>{@link ContentProvider} implementations: When preparing data in
283 * {@link ContentProvider#query(Uri, String[], Bundle, CancellationSignal)}, if sort direction
284 * is reflected in the returned Cursor, it is strongly recommended that
285 * {@link #QUERY_ARG_SORT_DIRECTION} then be included in the array of honored arguments
286 * reflected in {@link Cursor} extras {@link Bundle} under {@link #EXTRA_HONORED_ARGS}.
288 * <li>When querying a provider, where no QUERY_ARG_SQL* otherwise exists in the
289 * arguments {@link Bundle}, the Content framework will attempt to synthesize
290 * a QUERY_ARG_SQL* argument using the corresponding QUERY_ARG_SORT* values.
292 * @see #QUERY_SORT_DIRECTION_ASCENDING
293 * @see #QUERY_SORT_DIRECTION_DESCENDING
295 public static final String QUERY_ARG_SORT_DIRECTION = "android:query-arg-sort-direction";
298 * Allows client to specify a hint to the provider declaring which collation
299 * to use when sorting text values.
301 * <p>Providers may support custom collators. When specifying a custom collator
302 * the value is determined by the Provider.
304 * <li>{@link ContentProvider} implementations: When preparing data in
305 * {@link ContentProvider#query(Uri, String[], Bundle, CancellationSignal)}, if sort collation
306 * is reflected in the returned Cursor, it is strongly recommended that
307 * {@link #QUERY_ARG_SORT_COLLATION} then be included in the array of honored arguments
308 * reflected in {@link Cursor} extras {@link Bundle} under {@link #EXTRA_HONORED_ARGS}.
310 * <li>When querying a provider, where no QUERY_ARG_SQL* otherwise exists in the
311 * arguments {@link Bundle}, the Content framework will attempt to synthesize
312 * a QUERY_ARG_SQL* argument using the corresponding QUERY_ARG_SORT* values.
314 * @see java.text.Collator#PRIMARY
315 * @see java.text.Collator#SECONDARY
316 * @see java.text.Collator#TERTIARY
317 * @see java.text.Collator#IDENTICAL
319 public static final String QUERY_ARG_SORT_COLLATION = "android:query-arg-sort-collation";
322 * Allows provider to report back to client which query keys are honored in a Cursor.
324 * <p>Key identifying a {@code String[]} containing all QUERY_ARG_SORT* arguments
325 * honored by the provider. Include this in {@link Cursor} extras {@link Bundle}
326 * when any QUERY_ARG_SORT* value was honored during the preparation of the
327 * results {@link Cursor}.
329 * <p>If present, ALL honored arguments are enumerated in this extra’s payload.
331 * @see #QUERY_ARG_SORT_COLUMNS
332 * @see #QUERY_ARG_SORT_DIRECTION
333 * @see #QUERY_ARG_SORT_COLLATION
335 public static final String EXTRA_HONORED_ARGS = "android.content.extra.HONORED_ARGS";
338 @IntDef(flag = false, value = {
339 QUERY_SORT_DIRECTION_ASCENDING,
340 QUERY_SORT_DIRECTION_DESCENDING
342 @Retention(RetentionPolicy.SOURCE)
343 public @interface SortDirection {}
344 public static final int QUERY_SORT_DIRECTION_ASCENDING = 0;
345 public static final int QUERY_SORT_DIRECTION_DESCENDING = 1;
348 * @see {@link java.text.Collector} for details on respective collation strength.
351 @IntDef(flag = false, value = {
352 java.text.Collator.PRIMARY,
353 java.text.Collator.SECONDARY,
354 java.text.Collator.TERTIARY,
355 java.text.Collator.IDENTICAL
357 @Retention(RetentionPolicy.SOURCE)
358 public @interface QueryCollator {}
361 * Specifies the offset row index within a Cursor.
363 public static final String QUERY_ARG_OFFSET = "android:query-arg-offset";
366 * Specifies the max number of rows to include in a Cursor.
368 public static final String QUERY_ARG_LIMIT = "android:query-arg-limit";
371 * Added to {@link Cursor} extras {@link Bundle} to indicate total row count of
372 * recordset when paging is supported. Providers must include this when
373 * implementing paging support.
375 * <p>A provider may return -1 that row count of the recordset is unknown.
377 * <p>Providers having returned -1 in a previous query are recommended to
378 * send content change notification once (if) full recordset size becomes
381 public static final String EXTRA_TOTAL_COUNT = "android.content.extra.TOTAL_COUNT";
384 * This is the Android platform's base MIME type for a content: URI
385 * containing a Cursor of a single item. Applications should use this
386 * as the base type along with their own sub-type of their content: URIs
387 * that represent a particular item. For example, hypothetical IMAP email
388 * client may have a URI
389 * <code>content://com.company.provider.imap/inbox/1</code> for a particular
390 * message in the inbox, whose MIME type would be reported as
391 * <code>CURSOR_ITEM_BASE_TYPE + "/vnd.company.imap-msg"</code>
393 * <p>Compare with {@link #CURSOR_DIR_BASE_TYPE}.
395 public static final String CURSOR_ITEM_BASE_TYPE = "vnd.android.cursor.item";
398 * This is the Android platform's base MIME type for a content: URI
399 * containing a Cursor of zero or more items. Applications should use this
400 * as the base type along with their own sub-type of their content: URIs
401 * that represent a directory of items. For example, hypothetical IMAP email
402 * client may have a URI
403 * <code>content://com.company.provider.imap/inbox</code> for all of the
404 * messages in its inbox, whose MIME type would be reported as
405 * <code>CURSOR_DIR_BASE_TYPE + "/vnd.company.imap-msg"</code>
407 * <p>Note how the base MIME type varies between this and
408 * {@link #CURSOR_ITEM_BASE_TYPE} depending on whether there is
409 * one single item or multiple items in the data set, while the sub-type
410 * remains the same because in either case the data structure contained
411 * in the cursor is the same.
413 public static final String CURSOR_DIR_BASE_TYPE = "vnd.android.cursor.dir";
416 * This is the Android platform's generic MIME type to match any MIME
417 * type of the form "{@link #CURSOR_ITEM_BASE_TYPE}/{@code SUB_TYPE}".
418 * {@code SUB_TYPE} is the sub-type of the application-dependent
419 * content, e.g., "audio", "video", "playlist".
421 public static final String ANY_CURSOR_ITEM_TYPE = "vnd.android.cursor.item/*";
424 public static final int SYNC_ERROR_SYNC_ALREADY_IN_PROGRESS = 1;
426 public static final int SYNC_ERROR_AUTHENTICATION = 2;
428 public static final int SYNC_ERROR_IO = 3;
430 public static final int SYNC_ERROR_PARSE = 4;
432 public static final int SYNC_ERROR_CONFLICT = 5;
434 public static final int SYNC_ERROR_TOO_MANY_DELETIONS = 6;
436 public static final int SYNC_ERROR_TOO_MANY_RETRIES = 7;
438 public static final int SYNC_ERROR_INTERNAL = 8;
440 private static final String[] SYNC_ERROR_NAMES = new String[] {
441 "already-in-progress",
442 "authentication-error",
446 "too-many-deletions",
452 public static String syncErrorToString(int error) {
453 if (error < 1 || error > SYNC_ERROR_NAMES.length) {
454 return String.valueOf(error);
456 return SYNC_ERROR_NAMES[error - 1];
460 public static int syncErrorStringToInt(String error) {
461 for (int i = 0, n = SYNC_ERROR_NAMES.length; i < n; i++) {
462 if (SYNC_ERROR_NAMES[i].equals(error)) {
468 return Integer.parseInt(error);
469 } catch (NumberFormatException e) {
470 Log.d(TAG, "error parsing sync error: " + error);
476 public static final int SYNC_OBSERVER_TYPE_SETTINGS = 1<<0;
477 public static final int SYNC_OBSERVER_TYPE_PENDING = 1<<1;
478 public static final int SYNC_OBSERVER_TYPE_ACTIVE = 1<<2;
480 public static final int SYNC_OBSERVER_TYPE_STATUS = 1<<3;
482 public static final int SYNC_OBSERVER_TYPE_ALL = 0x7fffffff;
487 NOTIFY_SYNC_TO_NETWORK,
488 NOTIFY_SKIP_NOTIFY_FOR_DESCENDANTS
490 @Retention(RetentionPolicy.SOURCE)
491 public @interface NotifyFlags {}
494 * Flag for {@link #notifyChange(Uri, ContentObserver, int)}: attempt to sync the change
497 public static final int NOTIFY_SYNC_TO_NETWORK = 1<<0;
500 * Flag for {@link #notifyChange(Uri, ContentObserver, int)}: if set, this notification
501 * will be skipped if it is being delivered to the root URI of a ContentObserver that is
502 * using "notify for descendants." The purpose of this is to allow the provide to send
503 * a general notification of "something under X" changed that observers of that specific
504 * URI can receive, while also sending a specific URI under X. It would use this flag
505 * when sending the former, so that observers of "X and descendants" only see the latter.
507 public static final int NOTIFY_SKIP_NOTIFY_FOR_DESCENDANTS = 1<<1;
509 // Always log queries which take 500ms+; shorter queries are
510 // sampled accordingly.
511 private static final boolean ENABLE_CONTENT_SAMPLE = false;
512 private static final int SLOW_THRESHOLD_MILLIS = 500;
513 private final Random mRandom = new Random(); // guarded by itself
515 public ContentResolver(Context context) {
516 mContext = context != null ? context : ActivityThread.currentApplication();
517 mPackageName = mContext.getOpPackageName();
518 mTargetSdkVersion = mContext.getApplicationInfo().targetSdkVersion;
522 protected abstract IContentProvider acquireProvider(Context c, String name);
525 * Providing a default implementation of this, to avoid having to change a
526 * lot of other things, but implementations of ContentResolver should
531 protected IContentProvider acquireExistingProvider(Context c, String name) {
532 return acquireProvider(c, name);
536 public abstract boolean releaseProvider(IContentProvider icp);
538 protected abstract IContentProvider acquireUnstableProvider(Context c, String name);
540 public abstract boolean releaseUnstableProvider(IContentProvider icp);
542 public abstract void unstableProviderDied(IContentProvider icp);
545 public void appNotRespondingViaProvider(IContentProvider icp) {
546 throw new UnsupportedOperationException("appNotRespondingViaProvider");
550 * Return the MIME type of the given content URL.
552 * @param url A Uri identifying content (either a list or specific type),
553 * using the content:// scheme.
554 * @return A MIME type for the content, or null if the URL is invalid or the type is unknown
556 public final @Nullable String getType(@NonNull Uri url) {
557 Preconditions.checkNotNull(url, "url");
559 // XXX would like to have an acquireExistingUnstableProvider for this.
560 IContentProvider provider = acquireExistingProvider(url);
561 if (provider != null) {
563 return provider.getType(url);
564 } catch (RemoteException e) {
566 } catch (java.lang.Exception e) {
567 Log.w(TAG, "Failed to get type for: " + url + " (" + e.getMessage() + ")");
570 releaseProvider(provider);
574 if (!SCHEME_CONTENT.equals(url.getScheme())) {
579 String type = ActivityManager.getService().getProviderMimeType(
580 ContentProvider.getUriWithoutUserId(url), resolveUserId(url));
582 } catch (RemoteException e) {
583 // Arbitrary and not worth documenting, as Activity
584 // Manager will kill this process shortly anyway.
586 } catch (java.lang.Exception e) {
587 Log.w(TAG, "Failed to get type for: " + url + " (" + e.getMessage() + ")");
593 * Query for the possible MIME types for the representations the given
594 * content URL can be returned when opened as as stream with
595 * {@link #openTypedAssetFileDescriptor}. Note that the types here are
596 * not necessarily a superset of the type returned by {@link #getType} --
597 * many content providers cannot return a raw stream for the structured
598 * data that they contain.
600 * @param url A Uri identifying content (either a list or specific type),
601 * using the content:// scheme.
602 * @param mimeTypeFilter The desired MIME type. This may be a pattern,
603 * such as */*, to query for all available MIME types that match the
605 * @return Returns an array of MIME type strings for all available
606 * data streams that match the given mimeTypeFilter. If there are none,
609 public @Nullable String[] getStreamTypes(@NonNull Uri url, @NonNull String mimeTypeFilter) {
610 Preconditions.checkNotNull(url, "url");
611 Preconditions.checkNotNull(mimeTypeFilter, "mimeTypeFilter");
613 IContentProvider provider = acquireProvider(url);
614 if (provider == null) {
619 return provider.getStreamTypes(url, mimeTypeFilter);
620 } catch (RemoteException e) {
621 // Arbitrary and not worth documenting, as Activity
622 // Manager will kill this process shortly anyway.
625 releaseProvider(provider);
630 * Query the given URI, returning a {@link Cursor} over the result set.
632 * For best performance, the caller should follow these guidelines:
634 * <li>Provide an explicit projection, to prevent
635 * reading data from storage that aren't going to be used.</li>
636 * <li>Use question mark parameter markers such as 'phone=?' instead of
637 * explicit values in the {@code selection} parameter, so that queries
638 * that differ only by those values will be recognized as the same
639 * for caching purposes.</li>
643 * @param uri The URI, using the content:// scheme, for the content to
645 * @param projection A list of which columns to return. Passing null will
646 * return all columns, which is inefficient.
647 * @param selection A filter declaring which rows to return, formatted as an
648 * SQL WHERE clause (excluding the WHERE itself). Passing null will
649 * return all rows for the given URI.
650 * @param selectionArgs You may include ?s in selection, which will be
651 * replaced by the values from selectionArgs, in the order that they
652 * appear in the selection. The values will be bound as Strings.
653 * @param sortOrder How to order the rows, formatted as an SQL ORDER BY
654 * clause (excluding the ORDER BY itself). Passing null will use the
655 * default sort order, which may be unordered.
656 * @return A Cursor object, which is positioned before the first entry, or null
659 public final @Nullable Cursor query(@RequiresPermission.Read @NonNull Uri uri,
660 @Nullable String[] projection, @Nullable String selection,
661 @Nullable String[] selectionArgs, @Nullable String sortOrder) {
662 return query(uri, projection, selection, selectionArgs, sortOrder, null);
666 * Query the given URI, returning a {@link Cursor} over the result set
667 * with optional support for cancellation.
669 * For best performance, the caller should follow these guidelines:
671 * <li>Provide an explicit projection, to prevent
672 * reading data from storage that aren't going to be used.</li>
673 * <li>Use question mark parameter markers such as 'phone=?' instead of
674 * explicit values in the {@code selection} parameter, so that queries
675 * that differ only by those values will be recognized as the same
676 * for caching purposes.</li>
680 * @param uri The URI, using the content:// scheme, for the content to
682 * @param projection A list of which columns to return. Passing null will
683 * return all columns, which is inefficient.
684 * @param selection A filter declaring which rows to return, formatted as an
685 * SQL WHERE clause (excluding the WHERE itself). Passing null will
686 * return all rows for the given URI.
687 * @param selectionArgs You may include ?s in selection, which will be
688 * replaced by the values from selectionArgs, in the order that they
689 * appear in the selection. The values will be bound as Strings.
690 * @param sortOrder How to order the rows, formatted as an SQL ORDER BY
691 * clause (excluding the ORDER BY itself). Passing null will use the
692 * default sort order, which may be unordered.
693 * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
694 * If the operation is canceled, then {@link OperationCanceledException} will be thrown
695 * when the query is executed.
696 * @return A Cursor object, which is positioned before the first entry, or null
699 public final @Nullable Cursor query(@RequiresPermission.Read @NonNull Uri uri,
700 @Nullable String[] projection, @Nullable String selection,
701 @Nullable String[] selectionArgs, @Nullable String sortOrder,
702 @Nullable CancellationSignal cancellationSignal) {
703 Bundle queryArgs = createSqlQueryBundle(selection, selectionArgs, sortOrder);
704 return query(uri, projection, queryArgs, cancellationSignal);
708 * Query the given URI, returning a {@link Cursor} over the result set
709 * with support for cancellation.
711 * <p>For best performance, the caller should follow these guidelines:
713 * <li>Provide an explicit projection, to prevent reading data from storage
714 * that aren't going to be used.
716 * Provider must identify which QUERY_ARG_SORT* arguments were honored during
717 * the preparation of the result set by including the respective argument keys
718 * in the {@link Cursor} extras {@link Bundle}. See {@link #EXTRA_HONORED_ARGS}
721 * @see #QUERY_ARG_SORT_COLUMNS, #QUERY_ARG_SORT_DIRECTION, #QUERY_ARG_SORT_COLLATION.
723 * @param uri The URI, using the content:// scheme, for the content to
725 * @param projection A list of which columns to return. Passing null will
726 * return all columns, which is inefficient.
727 * @param queryArgs A Bundle containing any arguments to the query.
728 * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
729 * If the operation is canceled, then {@link OperationCanceledException} will be thrown
730 * when the query is executed.
731 * @return A Cursor object, which is positioned before the first entry, or null
734 public final @Nullable Cursor query(final @RequiresPermission.Read @NonNull Uri uri,
735 @Nullable String[] projection, @Nullable Bundle queryArgs,
736 @Nullable CancellationSignal cancellationSignal) {
737 Preconditions.checkNotNull(uri, "uri");
738 IContentProvider unstableProvider = acquireUnstableProvider(uri);
739 if (unstableProvider == null) {
742 IContentProvider stableProvider = null;
743 Cursor qCursor = null;
745 long startTime = SystemClock.uptimeMillis();
747 ICancellationSignal remoteCancellationSignal = null;
748 if (cancellationSignal != null) {
749 cancellationSignal.throwIfCanceled();
750 remoteCancellationSignal = unstableProvider.createCancellationSignal();
751 cancellationSignal.setRemote(remoteCancellationSignal);
754 qCursor = unstableProvider.query(mPackageName, uri, projection,
755 queryArgs, remoteCancellationSignal);
756 } catch (DeadObjectException e) {
757 // The remote process has died... but we only hold an unstable
758 // reference though, so we might recover!!! Let's try!!!!
759 // This is exciting!!1!!1!!!!1
760 unstableProviderDied(unstableProvider);
761 stableProvider = acquireProvider(uri);
762 if (stableProvider == null) {
765 qCursor = stableProvider.query(
766 mPackageName, uri, projection, queryArgs, remoteCancellationSignal);
768 if (qCursor == null) {
772 // Force query execution. Might fail and throw a runtime exception here.
774 long durationMillis = SystemClock.uptimeMillis() - startTime;
775 maybeLogQueryToEventLog(durationMillis, uri, projection, queryArgs);
777 // Wrap the cursor object into CursorWrapperInner object.
778 final IContentProvider provider = (stableProvider != null) ? stableProvider
779 : acquireProvider(uri);
780 final CursorWrapperInner wrapper = new CursorWrapperInner(qCursor, provider);
781 stableProvider = null;
784 } catch (RemoteException e) {
785 // Arbitrary and not worth documenting, as Activity
786 // Manager will kill this process shortly anyway.
789 if (qCursor != null) {
792 if (cancellationSignal != null) {
793 cancellationSignal.setRemote(null);
795 if (unstableProvider != null) {
796 releaseUnstableProvider(unstableProvider);
798 if (stableProvider != null) {
799 releaseProvider(stableProvider);
805 * Transform the given <var>url</var> to a canonical representation of
806 * its referenced resource, which can be used across devices, persisted,
807 * backed up and restored, etc. The returned Uri is still a fully capable
808 * Uri for use with its content provider, allowing you to do all of the
809 * same content provider operations as with the original Uri --
810 * {@link #query}, {@link #openInputStream(android.net.Uri)}, etc. The
811 * only difference in behavior between the original and new Uris is that
812 * the content provider may need to do some additional work at each call
813 * using it to resolve it to the correct resource, especially if the
814 * canonical Uri has been moved to a different environment.
816 * <p>If you are moving a canonical Uri between environments, you should
817 * perform another call to {@link #canonicalize} with that original Uri to
818 * re-canonicalize it for the current environment. Alternatively, you may
819 * want to use {@link #uncanonicalize} to transform it to a non-canonical
820 * Uri that works only in the current environment but potentially more
821 * efficiently than the canonical representation.</p>
823 * @param url The {@link Uri} that is to be transformed to a canonical
824 * representation. Like all resolver calls, the input can be either
825 * a non-canonical or canonical Uri.
827 * @return Returns the official canonical representation of <var>url</var>,
828 * or null if the content provider does not support a canonical representation
829 * of the given Uri. Many providers may not support canonicalization of some
830 * or all of their Uris.
832 * @see #uncanonicalize
834 public final @Nullable Uri canonicalize(@NonNull Uri url) {
835 Preconditions.checkNotNull(url, "url");
836 IContentProvider provider = acquireProvider(url);
837 if (provider == null) {
842 return provider.canonicalize(mPackageName, url);
843 } catch (RemoteException e) {
844 // Arbitrary and not worth documenting, as Activity
845 // Manager will kill this process shortly anyway.
848 releaseProvider(provider);
853 * Given a canonical Uri previously generated by {@link #canonicalize}, convert
854 * it to its local non-canonical form. This can be useful in some cases where
855 * you know that you will only be using the Uri in the current environment and
856 * want to avoid any possible overhead when using it with the content
857 * provider or want to verify that the referenced data exists at all in the
860 * @param url The canonical {@link Uri} that is to be convered back to its
861 * non-canonical form.
863 * @return Returns the non-canonical representation of <var>url</var>. This will
864 * return null if data identified by the canonical Uri can not be found in
865 * the current environment; callers must always check for null and deal with
866 * that by appropriately falling back to an alternative.
870 public final @Nullable Uri uncanonicalize(@NonNull Uri url) {
871 Preconditions.checkNotNull(url, "url");
872 IContentProvider provider = acquireProvider(url);
873 if (provider == null) {
878 return provider.uncanonicalize(mPackageName, url);
879 } catch (RemoteException e) {
880 // Arbitrary and not worth documenting, as Activity
881 // Manager will kill this process shortly anyway.
884 releaseProvider(provider);
889 * This allows clients to request an explicit refresh of content identified by {@code uri}.
891 * Client code should only invoke this method when there is a strong indication (such as a user
892 * initiated pull to refresh gesture) that the content is stale.
895 * @param url The Uri identifying the data to refresh.
896 * @param args Additional options from the client. The definitions of these are specific to the
897 * content provider being called.
898 * @param cancellationSignal A signal to cancel the operation in progress, or {@code null} if
899 * none. For example, if you called refresh on a particular uri, you should call
900 * {@link CancellationSignal#throwIfCanceled()} to check whether the client has
901 * canceled the refresh request.
902 * @return true if the provider actually tried refreshing.
904 public final boolean refresh(@NonNull Uri url, @Nullable Bundle args,
905 @Nullable CancellationSignal cancellationSignal) {
906 Preconditions.checkNotNull(url, "url");
907 IContentProvider provider = acquireProvider(url);
908 if (provider == null) {
913 ICancellationSignal remoteCancellationSignal = null;
914 if (cancellationSignal != null) {
915 cancellationSignal.throwIfCanceled();
916 remoteCancellationSignal = provider.createCancellationSignal();
917 cancellationSignal.setRemote(remoteCancellationSignal);
919 return provider.refresh(mPackageName, url, args, remoteCancellationSignal);
920 } catch (RemoteException e) {
921 // Arbitrary and not worth documenting, as Activity
922 // Manager will kill this process shortly anyway.
925 releaseProvider(provider);
930 * Open a stream on to the content associated with a content URI. If there
931 * is no data associated with the URI, FileNotFoundException is thrown.
933 * <h5>Accepts the following URI schemes:</h5>
935 * <li>content ({@link #SCHEME_CONTENT})</li>
936 * <li>android.resource ({@link #SCHEME_ANDROID_RESOURCE})</li>
937 * <li>file ({@link #SCHEME_FILE})</li>
940 * <p>See {@link #openAssetFileDescriptor(Uri, String)} for more information
943 * @param uri The desired URI.
944 * @return InputStream
945 * @throws FileNotFoundException if the provided URI could not be opened.
946 * @see #openAssetFileDescriptor(Uri, String)
948 public final @Nullable InputStream openInputStream(@NonNull Uri uri)
949 throws FileNotFoundException {
950 Preconditions.checkNotNull(uri, "uri");
951 String scheme = uri.getScheme();
952 if (SCHEME_ANDROID_RESOURCE.equals(scheme)) {
953 // Note: left here to avoid breaking compatibility. May be removed
954 // with sufficient testing.
955 OpenResourceIdResult r = getResourceId(uri);
957 InputStream stream = r.r.openRawResource(r.id);
959 } catch (Resources.NotFoundException ex) {
960 throw new FileNotFoundException("Resource does not exist: " + uri);
962 } else if (SCHEME_FILE.equals(scheme)) {
963 // Note: left here to avoid breaking compatibility. May be removed
964 // with sufficient testing.
965 return new FileInputStream(uri.getPath());
967 AssetFileDescriptor fd = openAssetFileDescriptor(uri, "r", null);
969 return fd != null ? fd.createInputStream() : null;
970 } catch (IOException e) {
971 throw new FileNotFoundException("Unable to create stream");
977 * Synonym for {@link #openOutputStream(Uri, String)
978 * openOutputStream(uri, "w")}.
979 * @throws FileNotFoundException if the provided URI could not be opened.
981 public final @Nullable OutputStream openOutputStream(@NonNull Uri uri)
982 throws FileNotFoundException {
983 return openOutputStream(uri, "w");
987 * Open a stream on to the content associated with a content URI. If there
988 * is no data associated with the URI, FileNotFoundException is thrown.
990 * <h5>Accepts the following URI schemes:</h5>
992 * <li>content ({@link #SCHEME_CONTENT})</li>
993 * <li>file ({@link #SCHEME_FILE})</li>
996 * <p>See {@link #openAssetFileDescriptor(Uri, String)} for more information
999 * @param uri The desired URI.
1000 * @param mode May be "w", "wa", "rw", or "rwt".
1001 * @return OutputStream
1002 * @throws FileNotFoundException if the provided URI could not be opened.
1003 * @see #openAssetFileDescriptor(Uri, String)
1005 public final @Nullable OutputStream openOutputStream(@NonNull Uri uri, @NonNull String mode)
1006 throws FileNotFoundException {
1007 AssetFileDescriptor fd = openAssetFileDescriptor(uri, mode, null);
1009 return fd != null ? fd.createOutputStream() : null;
1010 } catch (IOException e) {
1011 throw new FileNotFoundException("Unable to create stream");
1016 * Open a raw file descriptor to access data under a URI. This
1017 * is like {@link #openAssetFileDescriptor(Uri, String)}, but uses the
1018 * underlying {@link ContentProvider#openFile}
1019 * ContentProvider.openFile()} method, so will <em>not</em> work with
1020 * providers that return sub-sections of files. If at all possible,
1021 * you should use {@link #openAssetFileDescriptor(Uri, String)}. You
1022 * will receive a FileNotFoundException exception if the provider returns a
1023 * sub-section of a file.
1025 * <h5>Accepts the following URI schemes:</h5>
1027 * <li>content ({@link #SCHEME_CONTENT})</li>
1028 * <li>file ({@link #SCHEME_FILE})</li>
1031 * <p>See {@link #openAssetFileDescriptor(Uri, String)} for more information
1034 * If opening with the exclusive "r" or "w" modes, the returned
1035 * ParcelFileDescriptor could be a pipe or socket pair to enable streaming
1036 * of data. Opening with the "rw" mode implies a file on disk that supports
1037 * seeking. If possible, always use an exclusive mode to give the underlying
1038 * {@link ContentProvider} the most flexibility.
1040 * If you are writing a file, and need to communicate an error to the
1041 * provider, use {@link ParcelFileDescriptor#closeWithError(String)}.
1043 * @param uri The desired URI to open.
1044 * @param mode The file mode to use, as per {@link ContentProvider#openFile
1045 * ContentProvider.openFile}.
1046 * @return Returns a new ParcelFileDescriptor pointing to the file. You
1047 * own this descriptor and are responsible for closing it when done.
1048 * @throws FileNotFoundException Throws FileNotFoundException if no
1049 * file exists under the URI or the mode is invalid.
1050 * @see #openAssetFileDescriptor(Uri, String)
1052 public final @Nullable ParcelFileDescriptor openFileDescriptor(@NonNull Uri uri,
1053 @NonNull String mode) throws FileNotFoundException {
1054 return openFileDescriptor(uri, mode, null);
1058 * Open a raw file descriptor to access data under a URI. This
1059 * is like {@link #openAssetFileDescriptor(Uri, String)}, but uses the
1060 * underlying {@link ContentProvider#openFile}
1061 * ContentProvider.openFile()} method, so will <em>not</em> work with
1062 * providers that return sub-sections of files. If at all possible,
1063 * you should use {@link #openAssetFileDescriptor(Uri, String)}. You
1064 * will receive a FileNotFoundException exception if the provider returns a
1065 * sub-section of a file.
1067 * <h5>Accepts the following URI schemes:</h5>
1069 * <li>content ({@link #SCHEME_CONTENT})</li>
1070 * <li>file ({@link #SCHEME_FILE})</li>
1073 * <p>See {@link #openAssetFileDescriptor(Uri, String)} for more information
1076 * If opening with the exclusive "r" or "w" modes, the returned
1077 * ParcelFileDescriptor could be a pipe or socket pair to enable streaming
1078 * of data. Opening with the "rw" mode implies a file on disk that supports
1079 * seeking. If possible, always use an exclusive mode to give the underlying
1080 * {@link ContentProvider} the most flexibility.
1082 * If you are writing a file, and need to communicate an error to the
1083 * provider, use {@link ParcelFileDescriptor#closeWithError(String)}.
1085 * @param uri The desired URI to open.
1086 * @param mode The file mode to use, as per {@link ContentProvider#openFile
1087 * ContentProvider.openFile}.
1088 * @param cancellationSignal A signal to cancel the operation in progress,
1089 * or null if none. If the operation is canceled, then
1090 * {@link OperationCanceledException} will be thrown.
1091 * @return Returns a new ParcelFileDescriptor pointing to the file. You
1092 * own this descriptor and are responsible for closing it when done.
1093 * @throws FileNotFoundException Throws FileNotFoundException if no
1094 * file exists under the URI or the mode is invalid.
1095 * @see #openAssetFileDescriptor(Uri, String)
1097 public final @Nullable ParcelFileDescriptor openFileDescriptor(@NonNull Uri uri,
1098 @NonNull String mode, @Nullable CancellationSignal cancellationSignal)
1099 throws FileNotFoundException {
1100 AssetFileDescriptor afd = openAssetFileDescriptor(uri, mode, cancellationSignal);
1105 if (afd.getDeclaredLength() < 0) {
1106 // This is a full file!
1107 return afd.getParcelFileDescriptor();
1110 // Client can't handle a sub-section of a file, so close what
1111 // we got and bail with an exception.
1114 } catch (IOException e) {
1117 throw new FileNotFoundException("Not a whole file");
1121 * Open a raw file descriptor to access data under a URI. This
1122 * interacts with the underlying {@link ContentProvider#openAssetFile}
1123 * method of the provider associated with the given URI, to retrieve any file stored there.
1125 * <h5>Accepts the following URI schemes:</h5>
1127 * <li>content ({@link #SCHEME_CONTENT})</li>
1128 * <li>android.resource ({@link #SCHEME_ANDROID_RESOURCE})</li>
1129 * <li>file ({@link #SCHEME_FILE})</li>
1131 * <h5>The android.resource ({@link #SCHEME_ANDROID_RESOURCE}) Scheme</h5>
1133 * A Uri object can be used to reference a resource in an APK file. The
1134 * Uri should be one of the following formats:
1136 * <li><code>android.resource://package_name/id_number</code><br/>
1137 * <code>package_name</code> is your package name as listed in your AndroidManifest.xml.
1138 * For example <code>com.example.myapp</code><br/>
1139 * <code>id_number</code> is the int form of the ID.<br/>
1140 * The easiest way to construct this form is
1141 * <pre>Uri uri = Uri.parse("android.resource://com.example.myapp/" + R.raw.my_resource");</pre>
1143 * <li><code>android.resource://package_name/type/name</code><br/>
1144 * <code>package_name</code> is your package name as listed in your AndroidManifest.xml.
1145 * For example <code>com.example.myapp</code><br/>
1146 * <code>type</code> is the string form of the resource type. For example, <code>raw</code>
1147 * or <code>drawable</code>.
1148 * <code>name</code> is the string form of the resource name. That is, whatever the file
1149 * name was in your res directory, without the type extension.
1150 * The easiest way to construct this form is
1151 * <pre>Uri uri = Uri.parse("android.resource://com.example.myapp/raw/my_resource");</pre>
1155 * <p>Note that if this function is called for read-only input (mode is "r")
1156 * on a content: URI, it will instead call {@link #openTypedAssetFileDescriptor}
1157 * for you with a MIME type of "*/*". This allows such callers to benefit
1158 * from any built-in data conversion that a provider implements.
1160 * @param uri The desired URI to open.
1161 * @param mode The file mode to use, as per {@link ContentProvider#openAssetFile
1162 * ContentProvider.openAssetFile}.
1163 * @return Returns a new ParcelFileDescriptor pointing to the file. You
1164 * own this descriptor and are responsible for closing it when done.
1165 * @throws FileNotFoundException Throws FileNotFoundException of no
1166 * file exists under the URI or the mode is invalid.
1168 public final @Nullable AssetFileDescriptor openAssetFileDescriptor(@NonNull Uri uri,
1169 @NonNull String mode) throws FileNotFoundException {
1170 return openAssetFileDescriptor(uri, mode, null);
1174 * Open a raw file descriptor to access data under a URI. This
1175 * interacts with the underlying {@link ContentProvider#openAssetFile}
1176 * method of the provider associated with the given URI, to retrieve any file stored there.
1178 * <h5>Accepts the following URI schemes:</h5>
1180 * <li>content ({@link #SCHEME_CONTENT})</li>
1181 * <li>android.resource ({@link #SCHEME_ANDROID_RESOURCE})</li>
1182 * <li>file ({@link #SCHEME_FILE})</li>
1184 * <h5>The android.resource ({@link #SCHEME_ANDROID_RESOURCE}) Scheme</h5>
1186 * A Uri object can be used to reference a resource in an APK file. The
1187 * Uri should be one of the following formats:
1189 * <li><code>android.resource://package_name/id_number</code><br/>
1190 * <code>package_name</code> is your package name as listed in your AndroidManifest.xml.
1191 * For example <code>com.example.myapp</code><br/>
1192 * <code>id_number</code> is the int form of the ID.<br/>
1193 * The easiest way to construct this form is
1194 * <pre>Uri uri = Uri.parse("android.resource://com.example.myapp/" + R.raw.my_resource");</pre>
1196 * <li><code>android.resource://package_name/type/name</code><br/>
1197 * <code>package_name</code> is your package name as listed in your AndroidManifest.xml.
1198 * For example <code>com.example.myapp</code><br/>
1199 * <code>type</code> is the string form of the resource type. For example, <code>raw</code>
1200 * or <code>drawable</code>.
1201 * <code>name</code> is the string form of the resource name. That is, whatever the file
1202 * name was in your res directory, without the type extension.
1203 * The easiest way to construct this form is
1204 * <pre>Uri uri = Uri.parse("android.resource://com.example.myapp/raw/my_resource");</pre>
1208 * <p>Note that if this function is called for read-only input (mode is "r")
1209 * on a content: URI, it will instead call {@link #openTypedAssetFileDescriptor}
1210 * for you with a MIME type of "*/*". This allows such callers to benefit
1211 * from any built-in data conversion that a provider implements.
1213 * @param uri The desired URI to open.
1214 * @param mode The file mode to use, as per {@link ContentProvider#openAssetFile
1215 * ContentProvider.openAssetFile}.
1216 * @param cancellationSignal A signal to cancel the operation in progress, or null if
1217 * none. If the operation is canceled, then
1218 * {@link OperationCanceledException} will be thrown.
1219 * @return Returns a new ParcelFileDescriptor pointing to the file. You
1220 * own this descriptor and are responsible for closing it when done.
1221 * @throws FileNotFoundException Throws FileNotFoundException of no
1222 * file exists under the URI or the mode is invalid.
1224 public final @Nullable AssetFileDescriptor openAssetFileDescriptor(@NonNull Uri uri,
1225 @NonNull String mode, @Nullable CancellationSignal cancellationSignal)
1226 throws FileNotFoundException {
1227 Preconditions.checkNotNull(uri, "uri");
1228 Preconditions.checkNotNull(mode, "mode");
1230 String scheme = uri.getScheme();
1231 if (SCHEME_ANDROID_RESOURCE.equals(scheme)) {
1232 if (!"r".equals(mode)) {
1233 throw new FileNotFoundException("Can't write resources: " + uri);
1235 OpenResourceIdResult r = getResourceId(uri);
1237 return r.r.openRawResourceFd(r.id);
1238 } catch (Resources.NotFoundException ex) {
1239 throw new FileNotFoundException("Resource does not exist: " + uri);
1241 } else if (SCHEME_FILE.equals(scheme)) {
1242 ParcelFileDescriptor pfd = ParcelFileDescriptor.open(
1243 new File(uri.getPath()), ParcelFileDescriptor.parseMode(mode));
1244 return new AssetFileDescriptor(pfd, 0, -1);
1246 if ("r".equals(mode)) {
1247 return openTypedAssetFileDescriptor(uri, "*/*", null, cancellationSignal);
1249 IContentProvider unstableProvider = acquireUnstableProvider(uri);
1250 if (unstableProvider == null) {
1251 throw new FileNotFoundException("No content provider: " + uri);
1253 IContentProvider stableProvider = null;
1254 AssetFileDescriptor fd = null;
1257 ICancellationSignal remoteCancellationSignal = null;
1258 if (cancellationSignal != null) {
1259 cancellationSignal.throwIfCanceled();
1260 remoteCancellationSignal = unstableProvider.createCancellationSignal();
1261 cancellationSignal.setRemote(remoteCancellationSignal);
1265 fd = unstableProvider.openAssetFile(
1266 mPackageName, uri, mode, remoteCancellationSignal);
1268 // The provider will be released by the finally{} clause
1271 } catch (DeadObjectException e) {
1272 // The remote process has died... but we only hold an unstable
1273 // reference though, so we might recover!!! Let's try!!!!
1274 // This is exciting!!1!!1!!!!1
1275 unstableProviderDied(unstableProvider);
1276 stableProvider = acquireProvider(uri);
1277 if (stableProvider == null) {
1278 throw new FileNotFoundException("No content provider: " + uri);
1280 fd = stableProvider.openAssetFile(
1281 mPackageName, uri, mode, remoteCancellationSignal);
1283 // The provider will be released by the finally{} clause
1288 if (stableProvider == null) {
1289 stableProvider = acquireProvider(uri);
1291 releaseUnstableProvider(unstableProvider);
1292 unstableProvider = null;
1293 ParcelFileDescriptor pfd = new ParcelFileDescriptorInner(
1294 fd.getParcelFileDescriptor(), stableProvider);
1296 // Success! Don't release the provider when exiting, let
1297 // ParcelFileDescriptorInner do that when it is closed.
1298 stableProvider = null;
1300 return new AssetFileDescriptor(pfd, fd.getStartOffset(),
1301 fd.getDeclaredLength());
1303 } catch (RemoteException e) {
1304 // Whatever, whatever, we'll go away.
1305 throw new FileNotFoundException(
1306 "Failed opening content provider: " + uri);
1307 } catch (FileNotFoundException e) {
1310 if (cancellationSignal != null) {
1311 cancellationSignal.setRemote(null);
1313 if (stableProvider != null) {
1314 releaseProvider(stableProvider);
1316 if (unstableProvider != null) {
1317 releaseUnstableProvider(unstableProvider);
1325 * Open a raw file descriptor to access (potentially type transformed)
1326 * data from a "content:" URI. This interacts with the underlying
1327 * {@link ContentProvider#openTypedAssetFile} method of the provider
1328 * associated with the given URI, to retrieve retrieve any appropriate
1329 * data stream for the data stored there.
1331 * <p>Unlike {@link #openAssetFileDescriptor}, this function only works
1332 * with "content:" URIs, because content providers are the only facility
1333 * with an associated MIME type to ensure that the returned data stream
1334 * is of the desired type.
1336 * <p>All text/* streams are encoded in UTF-8.
1338 * @param uri The desired URI to open.
1339 * @param mimeType The desired MIME type of the returned data. This can
1340 * be a pattern such as */*, which will allow the content provider to
1341 * select a type, though there is no way for you to determine what type
1343 * @param opts Additional provider-dependent options.
1344 * @return Returns a new ParcelFileDescriptor from which you can read the
1345 * data stream from the provider. Note that this may be a pipe, meaning
1346 * you can't seek in it. The only seek you should do is if the
1347 * AssetFileDescriptor contains an offset, to move to that offset before
1348 * reading. You own this descriptor and are responsible for closing it when done.
1349 * @throws FileNotFoundException Throws FileNotFoundException of no
1350 * data of the desired type exists under the URI.
1352 public final @Nullable AssetFileDescriptor openTypedAssetFileDescriptor(@NonNull Uri uri,
1353 @NonNull String mimeType, @Nullable Bundle opts) throws FileNotFoundException {
1354 return openTypedAssetFileDescriptor(uri, mimeType, opts, null);
1358 * Open a raw file descriptor to access (potentially type transformed)
1359 * data from a "content:" URI. This interacts with the underlying
1360 * {@link ContentProvider#openTypedAssetFile} method of the provider
1361 * associated with the given URI, to retrieve retrieve any appropriate
1362 * data stream for the data stored there.
1364 * <p>Unlike {@link #openAssetFileDescriptor}, this function only works
1365 * with "content:" URIs, because content providers are the only facility
1366 * with an associated MIME type to ensure that the returned data stream
1367 * is of the desired type.
1369 * <p>All text/* streams are encoded in UTF-8.
1371 * @param uri The desired URI to open.
1372 * @param mimeType The desired MIME type of the returned data. This can
1373 * be a pattern such as */*, which will allow the content provider to
1374 * select a type, though there is no way for you to determine what type
1376 * @param opts Additional provider-dependent options.
1377 * @param cancellationSignal A signal to cancel the operation in progress,
1378 * or null if none. If the operation is canceled, then
1379 * {@link OperationCanceledException} will be thrown.
1380 * @return Returns a new ParcelFileDescriptor from which you can read the
1381 * data stream from the provider. Note that this may be a pipe, meaning
1382 * you can't seek in it. The only seek you should do is if the
1383 * AssetFileDescriptor contains an offset, to move to that offset before
1384 * reading. You own this descriptor and are responsible for closing it when done.
1385 * @throws FileNotFoundException Throws FileNotFoundException of no
1386 * data of the desired type exists under the URI.
1388 public final @Nullable AssetFileDescriptor openTypedAssetFileDescriptor(@NonNull Uri uri,
1389 @NonNull String mimeType, @Nullable Bundle opts,
1390 @Nullable CancellationSignal cancellationSignal) throws FileNotFoundException {
1391 Preconditions.checkNotNull(uri, "uri");
1392 Preconditions.checkNotNull(mimeType, "mimeType");
1394 IContentProvider unstableProvider = acquireUnstableProvider(uri);
1395 if (unstableProvider == null) {
1396 throw new FileNotFoundException("No content provider: " + uri);
1398 IContentProvider stableProvider = null;
1399 AssetFileDescriptor fd = null;
1402 ICancellationSignal remoteCancellationSignal = null;
1403 if (cancellationSignal != null) {
1404 cancellationSignal.throwIfCanceled();
1405 remoteCancellationSignal = unstableProvider.createCancellationSignal();
1406 cancellationSignal.setRemote(remoteCancellationSignal);
1410 fd = unstableProvider.openTypedAssetFile(
1411 mPackageName, uri, mimeType, opts, remoteCancellationSignal);
1413 // The provider will be released by the finally{} clause
1416 } catch (DeadObjectException e) {
1417 // The remote process has died... but we only hold an unstable
1418 // reference though, so we might recover!!! Let's try!!!!
1419 // This is exciting!!1!!1!!!!1
1420 unstableProviderDied(unstableProvider);
1421 stableProvider = acquireProvider(uri);
1422 if (stableProvider == null) {
1423 throw new FileNotFoundException("No content provider: " + uri);
1425 fd = stableProvider.openTypedAssetFile(
1426 mPackageName, uri, mimeType, opts, remoteCancellationSignal);
1428 // The provider will be released by the finally{} clause
1433 if (stableProvider == null) {
1434 stableProvider = acquireProvider(uri);
1436 releaseUnstableProvider(unstableProvider);
1437 unstableProvider = null;
1438 ParcelFileDescriptor pfd = new ParcelFileDescriptorInner(
1439 fd.getParcelFileDescriptor(), stableProvider);
1441 // Success! Don't release the provider when exiting, let
1442 // ParcelFileDescriptorInner do that when it is closed.
1443 stableProvider = null;
1445 return new AssetFileDescriptor(pfd, fd.getStartOffset(),
1446 fd.getDeclaredLength());
1448 } catch (RemoteException e) {
1449 // Whatever, whatever, we'll go away.
1450 throw new FileNotFoundException(
1451 "Failed opening content provider: " + uri);
1452 } catch (FileNotFoundException e) {
1455 if (cancellationSignal != null) {
1456 cancellationSignal.setRemote(null);
1458 if (stableProvider != null) {
1459 releaseProvider(stableProvider);
1461 if (unstableProvider != null) {
1462 releaseUnstableProvider(unstableProvider);
1468 * A resource identified by the {@link Resources} that contains it, and a resource id.
1472 public class OpenResourceIdResult {
1478 * Resolves an android.resource URI to a {@link Resources} and a resource id.
1482 public OpenResourceIdResult getResourceId(Uri uri) throws FileNotFoundException {
1483 String authority = uri.getAuthority();
1485 if (TextUtils.isEmpty(authority)) {
1486 throw new FileNotFoundException("No authority: " + uri);
1489 r = mContext.getPackageManager().getResourcesForApplication(authority);
1490 } catch (NameNotFoundException ex) {
1491 throw new FileNotFoundException("No package found for authority: " + uri);
1494 List<String> path = uri.getPathSegments();
1496 throw new FileNotFoundException("No path: " + uri);
1498 int len = path.size();
1502 id = Integer.parseInt(path.get(0));
1503 } catch (NumberFormatException e) {
1504 throw new FileNotFoundException("Single path segment is not a resource ID: " + uri);
1506 } else if (len == 2) {
1507 id = r.getIdentifier(path.get(1), path.get(0), authority);
1509 throw new FileNotFoundException("More than two path segments: " + uri);
1512 throw new FileNotFoundException("No resource found for: " + uri);
1514 OpenResourceIdResult res = new OpenResourceIdResult();
1521 * Inserts a row into a table at the given URL.
1523 * If the content provider supports transactions the insertion will be atomic.
1525 * @param url The URL of the table to insert into.
1526 * @param values The initial values for the newly inserted row. The key is the column name for
1527 * the field. Passing an empty ContentValues will create an empty row.
1528 * @return the URL of the newly created row.
1530 public final @Nullable Uri insert(@RequiresPermission.Write @NonNull Uri url,
1531 @Nullable ContentValues values) {
1532 Preconditions.checkNotNull(url, "url");
1533 IContentProvider provider = acquireProvider(url);
1534 if (provider == null) {
1535 throw new IllegalArgumentException("Unknown URL " + url);
1538 long startTime = SystemClock.uptimeMillis();
1539 Uri createdRow = provider.insert(mPackageName, url, values);
1540 long durationMillis = SystemClock.uptimeMillis() - startTime;
1541 maybeLogUpdateToEventLog(durationMillis, url, "insert", null /* where */);
1543 } catch (RemoteException e) {
1544 // Arbitrary and not worth documenting, as Activity
1545 // Manager will kill this process shortly anyway.
1548 releaseProvider(provider);
1553 * Applies each of the {@link ContentProviderOperation} objects and returns an array
1554 * of their results. Passes through OperationApplicationException, which may be thrown
1555 * by the call to {@link ContentProviderOperation#apply}.
1556 * If all the applications succeed then a {@link ContentProviderResult} array with the
1557 * same number of elements as the operations will be returned. It is implementation-specific
1558 * how many, if any, operations will have been successfully applied if a call to
1559 * apply results in a {@link OperationApplicationException}.
1560 * @param authority the authority of the ContentProvider to which this batch should be applied
1561 * @param operations the operations to apply
1562 * @return the results of the applications
1563 * @throws OperationApplicationException thrown if an application fails.
1564 * See {@link ContentProviderOperation#apply} for more information.
1565 * @throws RemoteException thrown if a RemoteException is encountered while attempting
1566 * to communicate with a remote provider.
1568 public @NonNull ContentProviderResult[] applyBatch(@NonNull String authority,
1569 @NonNull ArrayList<ContentProviderOperation> operations)
1570 throws RemoteException, OperationApplicationException {
1571 Preconditions.checkNotNull(authority, "authority");
1572 Preconditions.checkNotNull(operations, "operations");
1573 ContentProviderClient provider = acquireContentProviderClient(authority);
1574 if (provider == null) {
1575 throw new IllegalArgumentException("Unknown authority " + authority);
1578 return provider.applyBatch(operations);
1585 * Inserts multiple rows into a table at the given URL.
1587 * This function make no guarantees about the atomicity of the insertions.
1589 * @param url The URL of the table to insert into.
1590 * @param values The initial values for the newly inserted rows. The key is the column name for
1591 * the field. Passing null will create an empty row.
1592 * @return the number of newly created rows.
1594 public final int bulkInsert(@RequiresPermission.Write @NonNull Uri url,
1595 @NonNull ContentValues[] values) {
1596 Preconditions.checkNotNull(url, "url");
1597 Preconditions.checkNotNull(values, "values");
1598 IContentProvider provider = acquireProvider(url);
1599 if (provider == null) {
1600 throw new IllegalArgumentException("Unknown URL " + url);
1603 long startTime = SystemClock.uptimeMillis();
1604 int rowsCreated = provider.bulkInsert(mPackageName, url, values);
1605 long durationMillis = SystemClock.uptimeMillis() - startTime;
1606 maybeLogUpdateToEventLog(durationMillis, url, "bulkinsert", null /* where */);
1608 } catch (RemoteException e) {
1609 // Arbitrary and not worth documenting, as Activity
1610 // Manager will kill this process shortly anyway.
1613 releaseProvider(provider);
1618 * Deletes row(s) specified by a content URI.
1620 * If the content provider supports transactions, the deletion will be atomic.
1622 * @param url The URL of the row to delete.
1623 * @param where A filter to apply to rows before deleting, formatted as an SQL WHERE clause
1624 (excluding the WHERE itself).
1625 * @return The number of rows deleted.
1627 public final int delete(@RequiresPermission.Write @NonNull Uri url, @Nullable String where,
1628 @Nullable String[] selectionArgs) {
1629 Preconditions.checkNotNull(url, "url");
1630 IContentProvider provider = acquireProvider(url);
1631 if (provider == null) {
1632 throw new IllegalArgumentException("Unknown URL " + url);
1635 long startTime = SystemClock.uptimeMillis();
1636 int rowsDeleted = provider.delete(mPackageName, url, where, selectionArgs);
1637 long durationMillis = SystemClock.uptimeMillis() - startTime;
1638 maybeLogUpdateToEventLog(durationMillis, url, "delete", where);
1640 } catch (RemoteException e) {
1641 // Arbitrary and not worth documenting, as Activity
1642 // Manager will kill this process shortly anyway.
1645 releaseProvider(provider);
1650 * Update row(s) in a content URI.
1652 * If the content provider supports transactions the update will be atomic.
1654 * @param uri The URI to modify.
1655 * @param values The new field values. The key is the column name for the field.
1656 A null value will remove an existing field value.
1657 * @param where A filter to apply to rows before updating, formatted as an SQL WHERE clause
1658 (excluding the WHERE itself).
1659 * @return the number of rows updated.
1660 * @throws NullPointerException if uri or values are null
1662 public final int update(@RequiresPermission.Write @NonNull Uri uri,
1663 @Nullable ContentValues values, @Nullable String where,
1664 @Nullable String[] selectionArgs) {
1665 Preconditions.checkNotNull(uri, "uri");
1666 IContentProvider provider = acquireProvider(uri);
1667 if (provider == null) {
1668 throw new IllegalArgumentException("Unknown URI " + uri);
1671 long startTime = SystemClock.uptimeMillis();
1672 int rowsUpdated = provider.update(mPackageName, uri, values, where, selectionArgs);
1673 long durationMillis = SystemClock.uptimeMillis() - startTime;
1674 maybeLogUpdateToEventLog(durationMillis, uri, "update", where);
1676 } catch (RemoteException e) {
1677 // Arbitrary and not worth documenting, as Activity
1678 // Manager will kill this process shortly anyway.
1681 releaseProvider(provider);
1686 * Call a provider-defined method. This can be used to implement
1687 * read or write interfaces which are cheaper than using a Cursor and/or
1688 * do not fit into the traditional table model.
1690 * @param method provider-defined method name to call. Opaque to
1691 * framework, but must be non-null.
1692 * @param arg provider-defined String argument. May be null.
1693 * @param extras provider-defined Bundle argument. May be null.
1694 * @return a result Bundle, possibly null. Will be null if the ContentProvider
1695 * does not implement call.
1696 * @throws NullPointerException if uri or method is null
1697 * @throws IllegalArgumentException if uri is not known
1699 public final @Nullable Bundle call(@NonNull Uri uri, @NonNull String method,
1700 @Nullable String arg, @Nullable Bundle extras) {
1701 Preconditions.checkNotNull(uri, "uri");
1702 Preconditions.checkNotNull(method, "method");
1703 IContentProvider provider = acquireProvider(uri);
1704 if (provider == null) {
1705 throw new IllegalArgumentException("Unknown URI " + uri);
1708 final Bundle res = provider.call(mPackageName, method, arg, extras);
1709 Bundle.setDefusable(res, true);
1711 } catch (RemoteException e) {
1712 // Arbitrary and not worth documenting, as Activity
1713 // Manager will kill this process shortly anyway.
1716 releaseProvider(provider);
1721 * Returns the content provider for the given content URI.
1723 * @param uri The URI to a content provider
1724 * @return The ContentProvider for the given URI, or null if no content provider is found.
1727 public final IContentProvider acquireProvider(Uri uri) {
1728 if (!SCHEME_CONTENT.equals(uri.getScheme())) {
1731 final String auth = uri.getAuthority();
1733 return acquireProvider(mContext, auth);
1739 * Returns the content provider for the given content URI if the process
1740 * already has a reference on it.
1742 * @param uri The URI to a content provider
1743 * @return The ContentProvider for the given URI, or null if no content provider is found.
1746 public final IContentProvider acquireExistingProvider(Uri uri) {
1747 if (!SCHEME_CONTENT.equals(uri.getScheme())) {
1750 final String auth = uri.getAuthority();
1752 return acquireExistingProvider(mContext, auth);
1760 public final IContentProvider acquireProvider(String name) {
1764 return acquireProvider(mContext, name);
1768 * Returns the content provider for the given content URI.
1770 * @param uri The URI to a content provider
1771 * @return The ContentProvider for the given URI, or null if no content provider is found.
1774 public final IContentProvider acquireUnstableProvider(Uri uri) {
1775 if (!SCHEME_CONTENT.equals(uri.getScheme())) {
1778 String auth = uri.getAuthority();
1780 return acquireUnstableProvider(mContext, uri.getAuthority());
1788 public final IContentProvider acquireUnstableProvider(String name) {
1792 return acquireUnstableProvider(mContext, name);
1796 * Returns a {@link ContentProviderClient} that is associated with the {@link ContentProvider}
1797 * that services the content at uri, starting the provider if necessary. Returns
1798 * null if there is no provider associated wih the uri. The caller must indicate that they are
1799 * done with the provider by calling {@link ContentProviderClient#release} which will allow
1800 * the system to release the provider it it determines that there is no other reason for
1801 * keeping it active.
1802 * @param uri specifies which provider should be acquired
1803 * @return a {@link ContentProviderClient} that is associated with the {@link ContentProvider}
1804 * that services the content at uri or null if there isn't one.
1806 public final @Nullable ContentProviderClient acquireContentProviderClient(@NonNull Uri uri) {
1807 Preconditions.checkNotNull(uri, "uri");
1808 IContentProvider provider = acquireProvider(uri);
1809 if (provider != null) {
1810 return new ContentProviderClient(this, provider, true);
1816 * Returns a {@link ContentProviderClient} that is associated with the {@link ContentProvider}
1817 * with the authority of name, starting the provider if necessary. Returns
1818 * null if there is no provider associated wih the uri. The caller must indicate that they are
1819 * done with the provider by calling {@link ContentProviderClient#release} which will allow
1820 * the system to release the provider it it determines that there is no other reason for
1821 * keeping it active.
1822 * @param name specifies which provider should be acquired
1823 * @return a {@link ContentProviderClient} that is associated with the {@link ContentProvider}
1824 * with the authority of name or null if there isn't one.
1826 public final @Nullable ContentProviderClient acquireContentProviderClient(
1827 @NonNull String name) {
1828 Preconditions.checkNotNull(name, "name");
1829 IContentProvider provider = acquireProvider(name);
1830 if (provider != null) {
1831 return new ContentProviderClient(this, provider, true);
1838 * Like {@link #acquireContentProviderClient(Uri)}, but for use when you do
1839 * not trust the stability of the target content provider. This turns off
1840 * the mechanism in the platform clean up processes that are dependent on
1841 * a content provider if that content provider's process goes away. Normally
1842 * you can safely assume that once you have acquired a provider, you can freely
1843 * use it as needed and it won't disappear, even if your process is in the
1844 * background. If using this method, you need to take care to deal with any
1845 * failures when communicating with the provider, and be sure to close it
1846 * so that it can be re-opened later. In particular, catching a
1847 * {@link android.os.DeadObjectException} from the calls there will let you
1848 * know that the content provider has gone away; at that point the current
1849 * ContentProviderClient object is invalid, and you should release it. You
1850 * can acquire a new one if you would like to try to restart the provider
1851 * and perform new operations on it.
1853 public final @Nullable ContentProviderClient acquireUnstableContentProviderClient(
1855 Preconditions.checkNotNull(uri, "uri");
1856 IContentProvider provider = acquireUnstableProvider(uri);
1857 if (provider != null) {
1858 return new ContentProviderClient(this, provider, false);
1865 * Like {@link #acquireContentProviderClient(String)}, but for use when you do
1866 * not trust the stability of the target content provider. This turns off
1867 * the mechanism in the platform clean up processes that are dependent on
1868 * a content provider if that content provider's process goes away. Normally
1869 * you can safely assume that once you have acquired a provider, you can freely
1870 * use it as needed and it won't disappear, even if your process is in the
1871 * background. If using this method, you need to take care to deal with any
1872 * failures when communicating with the provider, and be sure to close it
1873 * so that it can be re-opened later. In particular, catching a
1874 * {@link android.os.DeadObjectException} from the calls there will let you
1875 * know that the content provider has gone away; at that point the current
1876 * ContentProviderClient object is invalid, and you should release it. You
1877 * can acquire a new one if you would like to try to restart the provider
1878 * and perform new operations on it.
1880 public final @Nullable ContentProviderClient acquireUnstableContentProviderClient(
1881 @NonNull String name) {
1882 Preconditions.checkNotNull(name, "name");
1883 IContentProvider provider = acquireUnstableProvider(name);
1884 if (provider != null) {
1885 return new ContentProviderClient(this, provider, false);
1892 * Register an observer class that gets callbacks when data identified by a
1893 * given content URI changes.
1895 * Starting in {@link android.os.Build.VERSION_CODES#O}, all content
1896 * notifications must be backed by a valid {@link ContentProvider}.
1898 * @param uri The URI to watch for changes. This can be a specific row URI,
1899 * or a base URI for a whole class of content.
1900 * @param notifyForDescendants When false, the observer will be notified
1901 * whenever a change occurs to the exact URI specified by
1902 * <code>uri</code> or to one of the URI's ancestors in the path
1903 * hierarchy. When true, the observer will also be notified
1904 * whenever a change occurs to the URI's descendants in the path
1906 * @param observer The object that receives callbacks when changes occur.
1907 * @see #unregisterContentObserver
1909 public final void registerContentObserver(@NonNull Uri uri, boolean notifyForDescendants,
1910 @NonNull ContentObserver observer) {
1911 Preconditions.checkNotNull(uri, "uri");
1912 Preconditions.checkNotNull(observer, "observer");
1913 registerContentObserver(
1914 ContentProvider.getUriWithoutUserId(uri),
1915 notifyForDescendants,
1917 ContentProvider.getUserIdFromUri(uri, mContext.getUserId()));
1920 /** @hide - designated user version */
1921 public final void registerContentObserver(Uri uri, boolean notifyForDescendents,
1922 ContentObserver observer, @UserIdInt int userHandle) {
1924 getContentService().registerContentObserver(uri, notifyForDescendents,
1925 observer.getContentObserver(), userHandle, mTargetSdkVersion);
1926 } catch (RemoteException e) {
1931 * Unregisters a change observer.
1933 * @param observer The previously registered observer that is no longer needed.
1934 * @see #registerContentObserver
1936 public final void unregisterContentObserver(@NonNull ContentObserver observer) {
1937 Preconditions.checkNotNull(observer, "observer");
1939 IContentObserver contentObserver = observer.releaseContentObserver();
1940 if (contentObserver != null) {
1941 getContentService().unregisterContentObserver(
1944 } catch (RemoteException e) {
1949 * Notify registered observers that a row was updated and attempt to sync
1950 * changes to the network.
1952 * To observe events sent through this call, use
1953 * {@link #registerContentObserver(Uri, boolean, ContentObserver)}.
1955 * Starting in {@link android.os.Build.VERSION_CODES#O}, all content
1956 * notifications must be backed by a valid {@link ContentProvider}.
1958 * @param uri The uri of the content that was changed.
1959 * @param observer The observer that originated the change, may be
1960 * <code>null</null>. The observer that originated the change
1961 * will only receive the notification if it has requested to
1962 * receive self-change notifications by implementing
1963 * {@link ContentObserver#deliverSelfNotifications()} to return
1966 public void notifyChange(@NonNull Uri uri, @Nullable ContentObserver observer) {
1967 notifyChange(uri, observer, true /* sync to network */);
1971 * Notify registered observers that a row was updated.
1973 * To observe events sent through this call, use
1974 * {@link #registerContentObserver(Uri, boolean, ContentObserver)}.
1976 * If syncToNetwork is true, this will attempt to schedule a local sync
1977 * using the sync adapter that's registered for the authority of the
1978 * provided uri. No account will be passed to the sync adapter, so all
1979 * matching accounts will be synchronized.
1981 * Starting in {@link android.os.Build.VERSION_CODES#O}, all content
1982 * notifications must be backed by a valid {@link ContentProvider}.
1984 * @param uri The uri of the content that was changed.
1985 * @param observer The observer that originated the change, may be
1986 * <code>null</null>. The observer that originated the change
1987 * will only receive the notification if it has requested to
1988 * receive self-change notifications by implementing
1989 * {@link ContentObserver#deliverSelfNotifications()} to return
1991 * @param syncToNetwork If true, same as {@link #NOTIFY_SYNC_TO_NETWORK}.
1992 * @see #requestSync(android.accounts.Account, String, android.os.Bundle)
1994 public void notifyChange(@NonNull Uri uri, @Nullable ContentObserver observer,
1995 boolean syncToNetwork) {
1996 Preconditions.checkNotNull(uri, "uri");
1998 ContentProvider.getUriWithoutUserId(uri),
2001 ContentProvider.getUserIdFromUri(uri, mContext.getUserId()));
2005 * Notify registered observers that a row was updated.
2007 * To observe events sent through this call, use
2008 * {@link #registerContentObserver(Uri, boolean, ContentObserver)}.
2010 * If syncToNetwork is true, this will attempt to schedule a local sync
2011 * using the sync adapter that's registered for the authority of the
2012 * provided uri. No account will be passed to the sync adapter, so all
2013 * matching accounts will be synchronized.
2015 * Starting in {@link android.os.Build.VERSION_CODES#O}, all content
2016 * notifications must be backed by a valid {@link ContentProvider}.
2018 * @param uri The uri of the content that was changed.
2019 * @param observer The observer that originated the change, may be
2020 * <code>null</null>. The observer that originated the change
2021 * will only receive the notification if it has requested to
2022 * receive self-change notifications by implementing
2023 * {@link ContentObserver#deliverSelfNotifications()} to return
2025 * @param flags Additional flags: {@link #NOTIFY_SYNC_TO_NETWORK}.
2026 * @see #requestSync(android.accounts.Account, String, android.os.Bundle)
2028 public void notifyChange(@NonNull Uri uri, @Nullable ContentObserver observer,
2029 @NotifyFlags int flags) {
2030 Preconditions.checkNotNull(uri, "uri");
2032 ContentProvider.getUriWithoutUserId(uri),
2035 ContentProvider.getUserIdFromUri(uri, mContext.getUserId()));
2039 * Notify registered observers within the designated user(s) that a row was updated.
2043 public void notifyChange(@NonNull Uri uri, ContentObserver observer, boolean syncToNetwork,
2044 @UserIdInt int userHandle) {
2046 getContentService().notifyChange(
2047 uri, observer == null ? null : observer.getContentObserver(),
2048 observer != null && observer.deliverSelfNotifications(),
2049 syncToNetwork ? NOTIFY_SYNC_TO_NETWORK : 0,
2050 userHandle, mTargetSdkVersion);
2051 } catch (RemoteException e) {
2056 * Notify registered observers within the designated user(s) that a row was updated.
2060 public void notifyChange(@NonNull Uri uri, ContentObserver observer, @NotifyFlags int flags,
2061 @UserIdInt int userHandle) {
2063 getContentService().notifyChange(
2064 uri, observer == null ? null : observer.getContentObserver(),
2065 observer != null && observer.deliverSelfNotifications(), flags,
2066 userHandle, mTargetSdkVersion);
2067 } catch (RemoteException e) {
2072 * Take a persistable URI permission grant that has been offered. Once
2073 * taken, the permission grant will be remembered across device reboots.
2074 * Only URI permissions granted with
2075 * {@link Intent#FLAG_GRANT_PERSISTABLE_URI_PERMISSION} can be persisted. If
2076 * the grant has already been persisted, taking it again will touch
2077 * {@link UriPermission#getPersistedTime()}.
2079 * @see #getPersistedUriPermissions()
2081 public void takePersistableUriPermission(@NonNull Uri uri,
2082 @Intent.AccessUriMode int modeFlags) {
2083 Preconditions.checkNotNull(uri, "uri");
2085 ActivityManager.getService().takePersistableUriPermission(
2086 ContentProvider.getUriWithoutUserId(uri), modeFlags, resolveUserId(uri));
2087 } catch (RemoteException e) {
2092 * Relinquish a persisted URI permission grant. The URI must have been
2093 * previously made persistent with
2094 * {@link #takePersistableUriPermission(Uri, int)}. Any non-persistent
2095 * grants to the calling package will remain intact.
2097 * @see #getPersistedUriPermissions()
2099 public void releasePersistableUriPermission(@NonNull Uri uri,
2100 @Intent.AccessUriMode int modeFlags) {
2101 Preconditions.checkNotNull(uri, "uri");
2103 ActivityManager.getService().releasePersistableUriPermission(
2104 ContentProvider.getUriWithoutUserId(uri), modeFlags, resolveUserId(uri));
2105 } catch (RemoteException e) {
2110 * Return list of all URI permission grants that have been persisted by the
2111 * calling app. That is, the returned permissions have been granted
2112 * <em>to</em> the calling app. Only persistable grants taken with
2113 * {@link #takePersistableUriPermission(Uri, int)} are returned.
2114 * <p>Note: Some of the returned URIs may not be usable until after the user is unlocked.
2116 * @see #takePersistableUriPermission(Uri, int)
2117 * @see #releasePersistableUriPermission(Uri, int)
2119 public @NonNull List<UriPermission> getPersistedUriPermissions() {
2121 return ActivityManager.getService()
2122 .getPersistedUriPermissions(mPackageName, true).getList();
2123 } catch (RemoteException e) {
2124 throw new RuntimeException("Activity manager has died", e);
2129 * Return list of all persisted URI permission grants that are hosted by the
2130 * calling app. That is, the returned permissions have been granted
2131 * <em>from</em> the calling app. Only grants taken with
2132 * {@link #takePersistableUriPermission(Uri, int)} are returned.
2133 * <p>Note: Some of the returned URIs may not be usable until after the user is unlocked.
2135 public @NonNull List<UriPermission> getOutgoingPersistedUriPermissions() {
2137 return ActivityManager.getService()
2138 .getPersistedUriPermissions(mPackageName, false).getList();
2139 } catch (RemoteException e) {
2140 throw new RuntimeException("Activity manager has died", e);
2145 * Start an asynchronous sync operation. If you want to monitor the progress
2146 * of the sync you may register a SyncObserver. Only values of the following
2147 * types may be used in the extras bundle:
2159 * @param uri the uri of the provider to sync or null to sync all providers.
2160 * @param extras any extras to pass to the SyncAdapter.
2161 * @deprecated instead use
2162 * {@link #requestSync(android.accounts.Account, String, android.os.Bundle)}
2165 public void startSync(Uri uri, Bundle extras) {
2166 Account account = null;
2167 if (extras != null) {
2168 String accountName = extras.getString(SYNC_EXTRAS_ACCOUNT);
2169 if (!TextUtils.isEmpty(accountName)) {
2170 // TODO: No references to Google in AOSP
2171 account = new Account(accountName, "com.google");
2173 extras.remove(SYNC_EXTRAS_ACCOUNT);
2175 requestSync(account, uri != null ? uri.getAuthority() : null, extras);
2179 * Start an asynchronous sync operation. If you want to monitor the progress
2180 * of the sync you may register a SyncObserver. Only values of the following
2181 * types may be used in the extras bundle:
2193 * @param account which account should be synced
2194 * @param authority which authority should be synced
2195 * @param extras any extras to pass to the SyncAdapter.
2197 public static void requestSync(Account account, String authority, Bundle extras) {
2198 requestSyncAsUser(account, authority, UserHandle.myUserId(), extras);
2202 * @see #requestSync(Account, String, Bundle)
2205 public static void requestSyncAsUser(Account account, String authority, @UserIdInt int userId,
2207 if (extras == null) {
2208 throw new IllegalArgumentException("Must specify extras.");
2210 SyncRequest request =
2211 new SyncRequest.Builder()
2212 .setSyncAdapter(account, authority)
2214 .syncOnce() // Immediate sync.
2217 getContentService().syncAsUser(request, userId);
2218 } catch(RemoteException e) {
2219 // Shouldn't happen.
2224 * Register a sync with the SyncManager. These requests are built using the
2225 * {@link SyncRequest.Builder}.
2227 public static void requestSync(SyncRequest request) {
2229 getContentService().sync(request);
2230 } catch(RemoteException e) {
2231 // Shouldn't happen.
2236 * Check that only values of the following types are in the Bundle:
2247 * @param extras the Bundle to check
2249 public static void validateSyncExtrasBundle(Bundle extras) {
2251 for (String key : extras.keySet()) {
2252 Object value = extras.get(key);
2253 if (value == null) continue;
2254 if (value instanceof Long) continue;
2255 if (value instanceof Integer) continue;
2256 if (value instanceof Boolean) continue;
2257 if (value instanceof Float) continue;
2258 if (value instanceof Double) continue;
2259 if (value instanceof String) continue;
2260 if (value instanceof Account) continue;
2261 throw new IllegalArgumentException("unexpected value type: "
2262 + value.getClass().getName());
2264 } catch (IllegalArgumentException e) {
2266 } catch (RuntimeException exc) {
2267 throw new IllegalArgumentException("error unparceling Bundle", exc);
2272 * Cancel any active or pending syncs that match the Uri. If the uri is null then
2273 * all syncs will be canceled.
2275 * @param uri the uri of the provider to sync or null to sync all providers.
2276 * @deprecated instead use {@link #cancelSync(android.accounts.Account, String)}
2279 public void cancelSync(Uri uri) {
2280 cancelSync(null /* all accounts */, uri != null ? uri.getAuthority() : null);
2284 * Cancel any active or pending syncs that match account and authority. The account and
2285 * authority can each independently be set to null, which means that syncs with any account
2286 * or authority, respectively, will match.
2288 * @param account filters the syncs that match by this account
2289 * @param authority filters the syncs that match by this authority
2291 public static void cancelSync(Account account, String authority) {
2293 getContentService().cancelSync(account, authority, null);
2294 } catch (RemoteException e) {
2299 * @see #cancelSync(Account, String)
2302 public static void cancelSyncAsUser(Account account, String authority, @UserIdInt int userId) {
2304 getContentService().cancelSyncAsUser(account, authority, null, userId);
2305 } catch (RemoteException e) {
2310 * Get information about the SyncAdapters that are known to the system.
2311 * @return an array of SyncAdapters that have registered with the system
2313 public static SyncAdapterType[] getSyncAdapterTypes() {
2315 return getContentService().getSyncAdapterTypes();
2316 } catch (RemoteException e) {
2317 throw new RuntimeException("the ContentService should always be reachable", e);
2322 * @see #getSyncAdapterTypes()
2325 public static SyncAdapterType[] getSyncAdapterTypesAsUser(@UserIdInt int userId) {
2327 return getContentService().getSyncAdapterTypesAsUser(userId);
2328 } catch (RemoteException e) {
2329 throw new RuntimeException("the ContentService should always be reachable", e);
2335 * Returns the package names of syncadapters that match a given user and authority.
2338 public static String[] getSyncAdapterPackagesForAuthorityAsUser(String authority,
2339 @UserIdInt int userId) {
2341 return getContentService().getSyncAdapterPackagesForAuthorityAsUser(authority, userId);
2342 } catch (RemoteException e) {
2344 return ArrayUtils.emptyArray(String.class);
2348 * Check if the provider should be synced when a network tickle is received
2349 * <p>This method requires the caller to hold the permission
2350 * {@link android.Manifest.permission#READ_SYNC_SETTINGS}.
2352 * @param account the account whose setting we are querying
2353 * @param authority the provider whose setting we are querying
2354 * @return true if the provider should be synced when a network tickle is received
2356 public static boolean getSyncAutomatically(Account account, String authority) {
2358 return getContentService().getSyncAutomatically(account, authority);
2359 } catch (RemoteException e) {
2360 throw new RuntimeException("the ContentService should always be reachable", e);
2365 * @see #getSyncAutomatically(Account, String)
2368 public static boolean getSyncAutomaticallyAsUser(Account account, String authority,
2369 @UserIdInt int userId) {
2371 return getContentService().getSyncAutomaticallyAsUser(account, authority, userId);
2372 } catch (RemoteException e) {
2373 throw new RuntimeException("the ContentService should always be reachable", e);
2378 * Set whether or not the provider is synced when it receives a network tickle.
2379 * <p>This method requires the caller to hold the permission
2380 * {@link android.Manifest.permission#WRITE_SYNC_SETTINGS}.
2382 * @param account the account whose setting we are querying
2383 * @param authority the provider whose behavior is being controlled
2384 * @param sync true if the provider should be synced when tickles are received for it
2386 public static void setSyncAutomatically(Account account, String authority, boolean sync) {
2387 setSyncAutomaticallyAsUser(account, authority, sync, UserHandle.myUserId());
2391 * @see #setSyncAutomatically(Account, String, boolean)
2394 public static void setSyncAutomaticallyAsUser(Account account, String authority, boolean sync,
2395 @UserIdInt int userId) {
2397 getContentService().setSyncAutomaticallyAsUser(account, authority, sync, userId);
2398 } catch (RemoteException e) {
2399 // exception ignored; if this is thrown then it means the runtime is in the midst of
2405 * Specifies that a sync should be requested with the specified the account, authority,
2406 * and extras at the given frequency. If there is already another periodic sync scheduled
2407 * with the account, authority and extras then a new periodic sync won't be added, instead
2408 * the frequency of the previous one will be updated.
2410 * These periodic syncs honor the "syncAutomatically" and "masterSyncAutomatically" settings.
2411 * Although these sync are scheduled at the specified frequency, it may take longer for it to
2412 * actually be started if other syncs are ahead of it in the sync operation queue. This means
2413 * that the actual start time may drift.
2415 * Periodic syncs are not allowed to have any of {@link #SYNC_EXTRAS_DO_NOT_RETRY},
2416 * {@link #SYNC_EXTRAS_IGNORE_BACKOFF}, {@link #SYNC_EXTRAS_IGNORE_SETTINGS},
2417 * {@link #SYNC_EXTRAS_INITIALIZE}, {@link #SYNC_EXTRAS_FORCE},
2418 * {@link #SYNC_EXTRAS_EXPEDITED}, {@link #SYNC_EXTRAS_MANUAL} set to true.
2419 * If any are supplied then an {@link IllegalArgumentException} will be thrown.
2421 * <p>This method requires the caller to hold the permission
2422 * {@link android.Manifest.permission#WRITE_SYNC_SETTINGS}.
2423 * <p>The bundle for a periodic sync can be queried by applications with the correct
2425 * {@link ContentResolver#getPeriodicSyncs(Account account, String provider)}, so no
2426 * sensitive data should be transferred here.
2428 * @param account the account to specify in the sync
2429 * @param authority the provider to specify in the sync request
2430 * @param extras extra parameters to go along with the sync request
2431 * @param pollFrequency how frequently the sync should be performed, in seconds. A minimum value
2432 * of 1 hour is enforced.
2433 * @throws IllegalArgumentException if an illegal extra was set or if any of the parameters
2436 public static void addPeriodicSync(Account account, String authority, Bundle extras,
2437 long pollFrequency) {
2438 validateSyncExtrasBundle(extras);
2439 if (extras.getBoolean(SYNC_EXTRAS_MANUAL, false)
2440 || extras.getBoolean(SYNC_EXTRAS_DO_NOT_RETRY, false)
2441 || extras.getBoolean(SYNC_EXTRAS_IGNORE_BACKOFF, false)
2442 || extras.getBoolean(SYNC_EXTRAS_IGNORE_SETTINGS, false)
2443 || extras.getBoolean(SYNC_EXTRAS_INITIALIZE, false)
2444 || extras.getBoolean(SYNC_EXTRAS_FORCE, false)
2445 || extras.getBoolean(SYNC_EXTRAS_EXPEDITED, false)) {
2446 throw new IllegalArgumentException("illegal extras were set");
2449 getContentService().addPeriodicSync(account, authority, extras, pollFrequency);
2450 } catch (RemoteException e) {
2451 // exception ignored; if this is thrown then it means the runtime is in the midst of
2458 * Helper function to throw an <code>IllegalArgumentException</code> if any illegal
2459 * extras were set for a periodic sync.
2461 * @param extras bundle to validate.
2463 public static boolean invalidPeriodicExtras(Bundle extras) {
2464 if (extras.getBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, false)
2465 || extras.getBoolean(ContentResolver.SYNC_EXTRAS_DO_NOT_RETRY, false)
2466 || extras.getBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_BACKOFF, false)
2467 || extras.getBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_SETTINGS, false)
2468 || extras.getBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE, false)
2469 || extras.getBoolean(ContentResolver.SYNC_EXTRAS_FORCE, false)
2470 || extras.getBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, false)) {
2477 * Remove a periodic sync. Has no affect if account, authority and extras don't match
2478 * an existing periodic sync.
2479 * <p>This method requires the caller to hold the permission
2480 * {@link android.Manifest.permission#WRITE_SYNC_SETTINGS}.
2482 * @param account the account of the periodic sync to remove
2483 * @param authority the provider of the periodic sync to remove
2484 * @param extras the extras of the periodic sync to remove
2486 public static void removePeriodicSync(Account account, String authority, Bundle extras) {
2487 validateSyncExtrasBundle(extras);
2489 getContentService().removePeriodicSync(account, authority, extras);
2490 } catch (RemoteException e) {
2491 throw new RuntimeException("the ContentService should always be reachable", e);
2496 * Remove the specified sync. This will cancel any pending or active syncs. If the request is
2497 * for a periodic sync, this call will remove any future occurrences.
2499 * If a periodic sync is specified, the caller must hold the permission
2500 * {@link android.Manifest.permission#WRITE_SYNC_SETTINGS}.
2502 * It is possible to cancel a sync using a SyncRequest object that is not the same object
2503 * with which you requested the sync. Do so by building a SyncRequest with the same
2504 * adapter, frequency, <b>and</b> extras bundle.
2506 * @param request SyncRequest object containing information about sync to cancel.
2508 public static void cancelSync(SyncRequest request) {
2509 if (request == null) {
2510 throw new IllegalArgumentException("request cannot be null");
2513 getContentService().cancelRequest(request);
2514 } catch (RemoteException e) {
2515 // exception ignored; if this is thrown then it means the runtime is in the midst of
2521 * Get the list of information about the periodic syncs for the given account and authority.
2522 * <p>This method requires the caller to hold the permission
2523 * {@link android.Manifest.permission#READ_SYNC_SETTINGS}.
2525 * @param account the account whose periodic syncs we are querying
2526 * @param authority the provider whose periodic syncs we are querying
2527 * @return a list of PeriodicSync objects. This list may be empty but will never be null.
2529 public static List<PeriodicSync> getPeriodicSyncs(Account account, String authority) {
2531 return getContentService().getPeriodicSyncs(account, authority, null);
2532 } catch (RemoteException e) {
2533 throw new RuntimeException("the ContentService should always be reachable", e);
2538 * Check if this account/provider is syncable.
2539 * <p>This method requires the caller to hold the permission
2540 * {@link android.Manifest.permission#READ_SYNC_SETTINGS}.
2541 * @return >0 if it is syncable, 0 if not, and <0 if the state isn't known yet.
2543 public static int getIsSyncable(Account account, String authority) {
2545 return getContentService().getIsSyncable(account, authority);
2546 } catch (RemoteException e) {
2547 throw new RuntimeException("the ContentService should always be reachable", e);
2552 * @see #getIsSyncable(Account, String)
2555 public static int getIsSyncableAsUser(Account account, String authority,
2556 @UserIdInt int userId) {
2558 return getContentService().getIsSyncableAsUser(account, authority, userId);
2559 } catch (RemoteException e) {
2560 throw new RuntimeException("the ContentService should always be reachable", e);
2565 * Set whether this account/provider is syncable.
2566 * <p>This method requires the caller to hold the permission
2567 * {@link android.Manifest.permission#WRITE_SYNC_SETTINGS}.
2568 * @param syncable >0 denotes syncable, 0 means not syncable, <0 means unknown
2570 public static void setIsSyncable(Account account, String authority, int syncable) {
2572 getContentService().setIsSyncable(account, authority, syncable);
2573 } catch (RemoteException e) {
2574 // exception ignored; if this is thrown then it means the runtime is in the midst of
2580 * Gets the master auto-sync setting that applies to all the providers and accounts.
2581 * If this is false then the per-provider auto-sync setting is ignored.
2582 * <p>This method requires the caller to hold the permission
2583 * {@link android.Manifest.permission#READ_SYNC_SETTINGS}.
2585 * @return the master auto-sync setting that applies to all the providers and accounts
2587 public static boolean getMasterSyncAutomatically() {
2589 return getContentService().getMasterSyncAutomatically();
2590 } catch (RemoteException e) {
2591 throw new RuntimeException("the ContentService should always be reachable", e);
2596 * @see #getMasterSyncAutomatically()
2599 public static boolean getMasterSyncAutomaticallyAsUser(@UserIdInt int userId) {
2601 return getContentService().getMasterSyncAutomaticallyAsUser(userId);
2602 } catch (RemoteException e) {
2603 throw new RuntimeException("the ContentService should always be reachable", e);
2608 * Sets the master auto-sync setting that applies to all the providers and accounts.
2609 * If this is false then the per-provider auto-sync setting is ignored.
2610 * <p>This method requires the caller to hold the permission
2611 * {@link android.Manifest.permission#WRITE_SYNC_SETTINGS}.
2613 * @param sync the master auto-sync setting that applies to all the providers and accounts
2615 public static void setMasterSyncAutomatically(boolean sync) {
2616 setMasterSyncAutomaticallyAsUser(sync, UserHandle.myUserId());
2620 * @see #setMasterSyncAutomatically(boolean)
2623 public static void setMasterSyncAutomaticallyAsUser(boolean sync, @UserIdInt int userId) {
2625 getContentService().setMasterSyncAutomaticallyAsUser(sync, userId);
2626 } catch (RemoteException e) {
2627 // exception ignored; if this is thrown then it means the runtime is in the midst of
2633 * Returns true if there is currently a sync operation for the given account or authority
2634 * actively being processed.
2635 * <p>This method requires the caller to hold the permission
2636 * {@link android.Manifest.permission#READ_SYNC_STATS}.
2637 * @param account the account whose setting we are querying
2638 * @param authority the provider whose behavior is being queried
2639 * @return true if a sync is active for the given account or authority.
2641 public static boolean isSyncActive(Account account, String authority) {
2642 if (account == null) {
2643 throw new IllegalArgumentException("account must not be null");
2645 if (authority == null) {
2646 throw new IllegalArgumentException("authority must not be null");
2650 return getContentService().isSyncActive(account, authority, null);
2651 } catch (RemoteException e) {
2652 throw new RuntimeException("the ContentService should always be reachable", e);
2657 * If a sync is active returns the information about it, otherwise returns null.
2659 * This method requires the caller to hold the permission
2660 * {@link android.Manifest.permission#READ_SYNC_STATS}.
2662 * @return the SyncInfo for the currently active sync or null if one is not active.
2664 * Since multiple concurrent syncs are now supported you should use
2665 * {@link #getCurrentSyncs()} to get the accurate list of current syncs.
2666 * This method returns the first item from the list of current syncs
2667 * or null if there are none.
2670 public static SyncInfo getCurrentSync() {
2672 final List<SyncInfo> syncs = getContentService().getCurrentSyncs();
2673 if (syncs.isEmpty()) {
2676 return syncs.get(0);
2677 } catch (RemoteException e) {
2678 throw new RuntimeException("the ContentService should always be reachable", e);
2683 * Returns a list with information about all the active syncs. This list will be empty
2684 * if there are no active syncs.
2686 * This method requires the caller to hold the permission
2687 * {@link android.Manifest.permission#READ_SYNC_STATS}.
2689 * @return a List of SyncInfo objects for the currently active syncs.
2691 public static List<SyncInfo> getCurrentSyncs() {
2693 return getContentService().getCurrentSyncs();
2694 } catch (RemoteException e) {
2695 throw new RuntimeException("the ContentService should always be reachable", e);
2700 * @see #getCurrentSyncs()
2703 public static List<SyncInfo> getCurrentSyncsAsUser(@UserIdInt int userId) {
2705 return getContentService().getCurrentSyncsAsUser(userId);
2706 } catch (RemoteException e) {
2707 throw new RuntimeException("the ContentService should always be reachable", e);
2712 * Returns the status that matches the authority.
2713 * @param account the account whose setting we are querying
2714 * @param authority the provider whose behavior is being queried
2715 * @return the SyncStatusInfo for the authority, or null if none exists
2718 public static SyncStatusInfo getSyncStatus(Account account, String authority) {
2720 return getContentService().getSyncStatus(account, authority, null);
2721 } catch (RemoteException e) {
2722 throw new RuntimeException("the ContentService should always be reachable", e);
2727 * @see #getSyncStatus(Account, String)
2730 public static SyncStatusInfo getSyncStatusAsUser(Account account, String authority,
2731 @UserIdInt int userId) {
2733 return getContentService().getSyncStatusAsUser(account, authority, null, userId);
2734 } catch (RemoteException e) {
2735 throw new RuntimeException("the ContentService should always be reachable", e);
2740 * Return true if the pending status is true of any matching authorities.
2741 * <p>This method requires the caller to hold the permission
2742 * {@link android.Manifest.permission#READ_SYNC_STATS}.
2743 * @param account the account whose setting we are querying
2744 * @param authority the provider whose behavior is being queried
2745 * @return true if there is a pending sync with the matching account and authority
2747 public static boolean isSyncPending(Account account, String authority) {
2748 return isSyncPendingAsUser(account, authority, UserHandle.myUserId());
2752 * @see #requestSync(Account, String, Bundle)
2755 public static boolean isSyncPendingAsUser(Account account, String authority,
2756 @UserIdInt int userId) {
2758 return getContentService().isSyncPendingAsUser(account, authority, null, userId);
2759 } catch (RemoteException e) {
2760 throw new RuntimeException("the ContentService should always be reachable", e);
2765 * Request notifications when the different aspects of the SyncManager change. The
2766 * different items that can be requested are:
2768 * <li> {@link #SYNC_OBSERVER_TYPE_PENDING}
2769 * <li> {@link #SYNC_OBSERVER_TYPE_ACTIVE}
2770 * <li> {@link #SYNC_OBSERVER_TYPE_SETTINGS}
2772 * The caller can set one or more of the status types in the mask for any
2773 * given listener registration.
2774 * @param mask the status change types that will cause the callback to be invoked
2775 * @param callback observer to be invoked when the status changes
2776 * @return a handle that can be used to remove the listener at a later time
2778 public static Object addStatusChangeListener(int mask, final SyncStatusObserver callback) {
2779 if (callback == null) {
2780 throw new IllegalArgumentException("you passed in a null callback");
2783 ISyncStatusObserver.Stub observer = new ISyncStatusObserver.Stub() {
2785 public void onStatusChanged(int which) throws RemoteException {
2786 callback.onStatusChanged(which);
2789 getContentService().addStatusChangeListener(mask, observer);
2791 } catch (RemoteException e) {
2792 throw new RuntimeException("the ContentService should always be reachable", e);
2797 * Remove a previously registered status change listener.
2798 * @param handle the handle that was returned by {@link #addStatusChangeListener}
2800 public static void removeStatusChangeListener(Object handle) {
2801 if (handle == null) {
2802 throw new IllegalArgumentException("you passed in a null handle");
2805 getContentService().removeStatusChangeListener((ISyncStatusObserver.Stub) handle);
2806 } catch (RemoteException e) {
2807 // exception ignored; if this is thrown then it means the runtime is in the midst of
2813 public void putCache(Uri key, Bundle value) {
2815 getContentService().putCache(mContext.getPackageName(), key, value,
2816 mContext.getUserId());
2817 } catch (RemoteException e) {
2818 throw e.rethrowFromSystemServer();
2823 public Bundle getCache(Uri key) {
2825 final Bundle bundle = getContentService().getCache(mContext.getPackageName(), key,
2826 mContext.getUserId());
2827 if (bundle != null) bundle.setClassLoader(mContext.getClassLoader());
2829 } catch (RemoteException e) {
2830 throw e.rethrowFromSystemServer();
2835 public int getTargetSdkVersion() {
2836 return mTargetSdkVersion;
2840 * Returns sampling percentage for a given duration.
2842 * Always returns at least 1%.
2844 private int samplePercentForDuration(long durationMillis) {
2845 if (durationMillis >= SLOW_THRESHOLD_MILLIS) {
2848 return (int) (100 * durationMillis / SLOW_THRESHOLD_MILLIS) + 1;
2851 private void maybeLogQueryToEventLog(
2852 long durationMillis, Uri uri, String[] projection, @Nullable Bundle queryArgs) {
2853 if (!ENABLE_CONTENT_SAMPLE) return;
2854 int samplePercent = samplePercentForDuration(durationMillis);
2855 if (samplePercent < 100) {
2856 synchronized (mRandom) {
2857 if (mRandom.nextInt(100) >= samplePercent) {
2863 // Ensure a non-null bundle.
2864 queryArgs = (queryArgs != null) ? queryArgs : Bundle.EMPTY;
2866 StringBuilder projectionBuffer = new StringBuilder(100);
2867 if (projection != null) {
2868 for (int i = 0; i < projection.length; ++i) {
2869 // Note: not using a comma delimiter here, as the
2870 // multiple arguments to EventLog.writeEvent later
2871 // stringify with a comma delimiter, which would make
2872 // parsing uglier later.
2873 if (i != 0) projectionBuffer.append('/');
2874 projectionBuffer.append(projection[i]);
2878 // ActivityThread.currentPackageName() only returns non-null if the
2879 // current thread is an application main thread. This parameter tells
2880 // us whether an event loop is blocked, and if so, which app it is.
2881 String blockingPackage = AppGlobals.getInitialPackage();
2883 EventLog.writeEvent(
2884 EventLogTags.CONTENT_QUERY_SAMPLE,
2886 projectionBuffer.toString(),
2887 queryArgs.getString(QUERY_ARG_SQL_SELECTION, ""),
2888 queryArgs.getString(QUERY_ARG_SQL_SORT_ORDER, ""),
2890 blockingPackage != null ? blockingPackage : "",
2894 private void maybeLogUpdateToEventLog(
2895 long durationMillis, Uri uri, String operation, String selection) {
2896 if (!ENABLE_CONTENT_SAMPLE) return;
2897 int samplePercent = samplePercentForDuration(durationMillis);
2898 if (samplePercent < 100) {
2899 synchronized (mRandom) {
2900 if (mRandom.nextInt(100) >= samplePercent) {
2905 String blockingPackage = AppGlobals.getInitialPackage();
2906 EventLog.writeEvent(
2907 EventLogTags.CONTENT_UPDATE_SAMPLE,
2910 selection != null ? selection : "",
2912 blockingPackage != null ? blockingPackage : "",
2916 private final class CursorWrapperInner extends CrossProcessCursorWrapper {
2917 private final IContentProvider mContentProvider;
2918 private final AtomicBoolean mProviderReleased = new AtomicBoolean();
2920 private final CloseGuard mCloseGuard = CloseGuard.get();
2922 CursorWrapperInner(Cursor cursor, IContentProvider contentProvider) {
2924 mContentProvider = contentProvider;
2925 mCloseGuard.open("close");
2929 public void close() {
2930 mCloseGuard.close();
2933 if (mProviderReleased.compareAndSet(false, true)) {
2934 ContentResolver.this.releaseProvider(mContentProvider);
2939 protected void finalize() throws Throwable {
2941 mCloseGuard.warnIfOpen();
2949 private final class ParcelFileDescriptorInner extends ParcelFileDescriptor {
2950 private final IContentProvider mContentProvider;
2951 private final AtomicBoolean mProviderReleased = new AtomicBoolean();
2953 ParcelFileDescriptorInner(ParcelFileDescriptor pfd, IContentProvider icp) {
2955 mContentProvider = icp;
2959 public void releaseResources() {
2960 if (mProviderReleased.compareAndSet(false, true)) {
2961 ContentResolver.this.releaseProvider(mContentProvider);
2967 public static final String CONTENT_SERVICE_NAME = "content";
2970 public static IContentService getContentService() {
2971 if (sContentService != null) {
2972 return sContentService;
2974 IBinder b = ServiceManager.getService(CONTENT_SERVICE_NAME);
2975 if (false) Log.v("ContentService", "default service binder = " + b);
2976 sContentService = IContentService.Stub.asInterface(b);
2977 if (false) Log.v("ContentService", "default service = " + sContentService);
2978 return sContentService;
2982 public String getPackageName() {
2983 return mPackageName;
2986 private static IContentService sContentService;
2987 private final Context mContext;
2989 final String mPackageName;
2990 final int mTargetSdkVersion;
2992 private static final String TAG = "ContentResolver";
2995 public int resolveUserId(Uri uri) {
2996 return ContentProvider.getUserIdFromUri(uri, mContext.getUserId());
3000 public Drawable getTypeDrawable(String mimeType) {
3001 return MimeIconUtils.loadMimeIcon(mContext, mimeType);
3007 public static @Nullable Bundle createSqlQueryBundle(
3008 @Nullable String selection,
3009 @Nullable String[] selectionArgs,
3010 @Nullable String sortOrder) {
3012 if (selection == null && selectionArgs == null && sortOrder == null) {
3016 Bundle queryArgs = new Bundle();
3017 if (selection != null) {
3018 queryArgs.putString(QUERY_ARG_SQL_SELECTION, selection);
3020 if (selectionArgs != null) {
3021 queryArgs.putStringArray(QUERY_ARG_SQL_SELECTION_ARGS, selectionArgs);
3023 if (sortOrder != null) {
3024 queryArgs.putString(QUERY_ARG_SQL_SORT_ORDER, sortOrder);
3030 * Returns structured sort args formatted as an SQL sort clause.
3032 * NOTE: Collator clauses are suitable for use with non text fields. We might
3033 * choose to omit any collation clause since we don't know the underlying
3034 * type of data to be collated. Imperical testing shows that sqlite3 doesn't
3035 * appear to care much about the presence of collate clauses in queries
3036 * when ordering by numeric fields. For this reason we include collate
3037 * clause unilaterally when {@link #QUERY_ARG_SORT_COLLATION} is present
3038 * in query args bundle.
3040 * TODO: Would be nice to explicitly validate that colums referenced in
3041 * {@link #QUERY_ARG_SORT_COLUMNS} are present in the associated projection.
3045 public static String createSqlSortClause(Bundle queryArgs) {
3046 String[] columns = queryArgs.getStringArray(QUERY_ARG_SORT_COLUMNS);
3047 if (columns == null || columns.length == 0) {
3048 throw new IllegalArgumentException("Can't create sort clause without columns.");
3051 String query = TextUtils.join(", ", columns);
3053 // Interpret PRIMARY and SECONDARY collation strength as no-case collation based
3054 // on their javadoc descriptions.
3055 int collation = queryArgs.getInt(
3056 ContentResolver.QUERY_ARG_SORT_COLLATION, java.text.Collator.IDENTICAL);
3057 if (collation == java.text.Collator.PRIMARY || collation == java.text.Collator.SECONDARY) {
3058 query += " COLLATE NOCASE";
3061 int sortDir = queryArgs.getInt(QUERY_ARG_SORT_DIRECTION, Integer.MIN_VALUE);
3062 if (sortDir != Integer.MIN_VALUE) {
3064 case QUERY_SORT_DIRECTION_ASCENDING:
3067 case QUERY_SORT_DIRECTION_DESCENDING:
3071 throw new IllegalArgumentException("Unsupported sort direction value."
3072 + " See ContentResolver documentation for details.");