1/*
2 * Copyright (C) 2006 The Android Open Source Project
3 *
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
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
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.
15 */
16
17package android.content;
18
19import android.accounts.Account;
20import android.annotation.IntDef;
21import android.annotation.NonNull;
22import android.annotation.Nullable;
23import android.annotation.RequiresPermission;
24import android.annotation.TestApi;
25import android.annotation.UserIdInt;
26import android.app.ActivityManager;
27import android.app.ActivityThread;
28import android.app.AppGlobals;
29import android.content.pm.PackageManager.NameNotFoundException;
30import android.content.res.AssetFileDescriptor;
31import android.content.res.Resources;
32import android.database.ContentObserver;
33import android.database.CrossProcessCursorWrapper;
34import android.database.Cursor;
35import android.database.IContentObserver;
36import android.graphics.Point;
37import android.graphics.drawable.Drawable;
38import android.net.Uri;
39import android.os.Bundle;
40import android.os.CancellationSignal;
41import android.os.DeadObjectException;
42import android.os.IBinder;
43import android.os.ICancellationSignal;
44import android.os.OperationCanceledException;
45import android.os.ParcelFileDescriptor;
46import android.os.RemoteException;
47import android.os.ServiceManager;
48import android.os.SystemClock;
49import android.os.UserHandle;
50import android.text.TextUtils;
51import android.util.EventLog;
52import android.util.Log;
53
54import com.android.internal.util.ArrayUtils;
55import com.android.internal.util.MimeIconUtils;
56import com.android.internal.util.Preconditions;
57
58import dalvik.system.CloseGuard;
59
60import java.io.File;
61import java.io.FileInputStream;
62import java.io.FileNotFoundException;
63import java.io.IOException;
64import java.io.InputStream;
65import java.io.OutputStream;
66import java.lang.annotation.Retention;
67import java.lang.annotation.RetentionPolicy;
68import java.util.ArrayList;
69import java.util.List;
70import java.util.Random;
71import java.util.concurrent.atomic.AtomicBoolean;
72
73/**
74 * This class provides applications access to the content model.
75 *
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>
81 */
82public abstract class ContentResolver {
83    /**
84     * @deprecated instead use
85     * {@link #requestSync(android.accounts.Account, String, android.os.Bundle)}
86     */
87    @Deprecated
88    public static final String SYNC_EXTRAS_ACCOUNT = "account";
89
90    /**
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
93     */
94    public static final String SYNC_EXTRAS_EXPEDITED = "expedited";
95
96    /**
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}.
100     */
101    public static final String SYNC_EXTRAS_REQUIRE_CHARGING = "require_charging";
102
103    /**
104     * @deprecated instead use
105     * {@link #SYNC_EXTRAS_MANUAL}
106     */
107    @Deprecated
108    public static final String SYNC_EXTRAS_FORCE = "force";
109
110    /**
111     * If this extra is set to true then the sync settings (like getSyncAutomatically())
112     * are ignored by the sync scheduler.
113     */
114    public static final String SYNC_EXTRAS_IGNORE_SETTINGS = "ignore_settings";
115
116    /**
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.
120     */
121    public static final String SYNC_EXTRAS_IGNORE_BACKOFF = "ignore_backoff";
122
123    /**
124     * If this extra is set to true then the request will not be retried if it fails.
125     */
126    public static final String SYNC_EXTRAS_DO_NOT_RETRY = "do_not_retry";
127
128    /**
129     * Setting this extra is the equivalent of setting both {@link #SYNC_EXTRAS_IGNORE_SETTINGS}
130     * and {@link #SYNC_EXTRAS_IGNORE_BACKOFF}
131     */
132    public static final String SYNC_EXTRAS_MANUAL = "force";
133
134    /**
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)}
138     */
139    public static final String SYNC_EXTRAS_UPLOAD = "upload";
140
141    /**
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}
145     */
146    public static final String SYNC_EXTRAS_OVERRIDE_TOO_MANY_DELETIONS = "deletions_override";
147
148    /**
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}
152     */
153    public static final String SYNC_EXTRAS_DISCARD_LOCAL_DELETIONS = "discard_deletions";
154
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";
158
159    /** {@hide} User-specified flag for expected download size. */
160    public static final String SYNC_EXTRAS_EXPECTED_DOWNLOAD = "expected_download";
161
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";
164
165    /** {@hide} Flag to allow sync to occur on metered network. */
166    public static final String SYNC_EXTRAS_DISALLOW_METERED = "allow_metered";
167
168    /**
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.
174     */
175    public static final String SYNC_EXTRAS_INITIALIZE = "initialize";
176
177    /** @hide */
178    public static final Intent ACTION_SYNC_CONN_STATUS_CHANGED =
179            new Intent("com.android.sync.SYNC_CONN_STATUS_CHANGED");
180
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";
184
185    /**
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.
189     *
190     * @see #openTypedAssetFileDescriptor(Uri, String, Bundle)
191     * @see #openTypedAssetFileDescriptor(Uri, String, Bundle,
192     *      CancellationSignal)
193     */
194    public static final String EXTRA_SIZE = "android.content.extra.SIZE";
195
196    /**
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.
200     *
201     */
202    public static final String EXTRA_REFRESH_SUPPORTED = "android.content.extra.REFRESH_SUPPORTED";
203
204    /**
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.
208     *
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}.
213     *
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>
216     *
217     * @see #QUERY_ARG_SORT_COLUMNS
218     * @see #QUERY_ARG_SORT_DIRECTION
219     * @see #QUERY_ARG_SORT_COLLATION
220     */
221    public static final String QUERY_ARG_SQL_SELECTION = "android:query-arg-sql-selection";
222
223    /**
224     * Key for SQL selection string arguments list.
225     *
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}.
230     *
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>
233     *
234     * @see #QUERY_ARG_SORT_COLUMNS
235     * @see #QUERY_ARG_SORT_DIRECTION
236     * @see #QUERY_ARG_SORT_COLLATION
237     */
238    public static final String QUERY_ARG_SQL_SELECTION_ARGS =
239            "android:query-arg-sql-selection-args";
240
241    /**
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.
245     *
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>
248     *
249     * @see #QUERY_ARG_SORT_COLUMNS
250     * @see #QUERY_ARG_SORT_DIRECTION
251     * @see #QUERY_ARG_SORT_COLLATION
252     */
253    public static final String QUERY_ARG_SQL_SORT_ORDER = "android:query-arg-sql-sort-order";
254
255    /**
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.
258     *
259     * <p>Columns present in this list must also be included in the projection
260     * supplied to {@link ContentResolver#query(Uri, String[], Bundle, CancellationSignal)}.
261     *
262     * <p>Apps targeting {@link android.os.Build.VERSION_CODES#O} or higher:
263     *
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}.
269     *
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.
273     */
274    public static final String QUERY_ARG_SORT_COLUMNS = "android:query-arg-sort-columns";
275
276    /**
277     * Specifies desired sort order. When unspecified a provider may provide a default
278     * sort direction, or choose to return unsorted results.
279     *
280     * <p>Apps targeting {@link android.os.Build.VERSION_CODES#O} or higher:
281     *
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}.
287     *
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.
291     *
292     * @see #QUERY_SORT_DIRECTION_ASCENDING
293     * @see #QUERY_SORT_DIRECTION_DESCENDING
294     */
295    public static final String QUERY_ARG_SORT_DIRECTION = "android:query-arg-sort-direction";
296
297    /**
298     * Allows client to specify a hint to the provider declaring which collation
299     * to use when sorting text values.
300     *
301     * <p>Providers may support custom collators. When specifying a custom collator
302     * the value is determined by the Provider.
303     *
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}.
309     *
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.
313     *
314     * @see java.text.Collator#PRIMARY
315     * @see java.text.Collator#SECONDARY
316     * @see java.text.Collator#TERTIARY
317     * @see java.text.Collator#IDENTICAL
318     */
319    public static final String QUERY_ARG_SORT_COLLATION = "android:query-arg-sort-collation";
320
321    /**
322     * Allows provider to report back to client which query keys are honored in a Cursor.
323     *
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}.
328     *
329     * <p>If present, ALL honored arguments are enumerated in this extra’s payload.
330     *
331     * @see #QUERY_ARG_SORT_COLUMNS
332     * @see #QUERY_ARG_SORT_DIRECTION
333     * @see #QUERY_ARG_SORT_COLLATION
334     */
335    public static final String EXTRA_HONORED_ARGS = "android.content.extra.HONORED_ARGS";
336
337    /** @hide */
338    @IntDef(flag = false, value = {
339            QUERY_SORT_DIRECTION_ASCENDING,
340            QUERY_SORT_DIRECTION_DESCENDING
341    })
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;
346
347    /**
348     * @see {@link java.text.Collector} for details on respective collation strength.
349     * @hide
350     */
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
356    })
357    @Retention(RetentionPolicy.SOURCE)
358    public @interface QueryCollator {}
359
360    /**
361     * Specifies the offset row index within a Cursor.
362     */
363    public static final String QUERY_ARG_OFFSET = "android:query-arg-offset";
364
365    /**
366     * Specifies the max number of rows to include in a Cursor.
367     */
368    public static final String QUERY_ARG_LIMIT = "android:query-arg-limit";
369
370    /**
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.
374     *
375     * <p>A provider may return -1 that row count of the recordset is unknown.
376     *
377     * <p>Providers having returned -1 in a previous query are recommended to
378     * send content change notification once (if) full recordset size becomes
379     * known.
380     */
381    public static final String EXTRA_TOTAL_COUNT = "android.content.extra.TOTAL_COUNT";
382
383    /**
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>
392     *
393     * <p>Compare with {@link #CURSOR_DIR_BASE_TYPE}.
394     */
395    public static final String CURSOR_ITEM_BASE_TYPE = "vnd.android.cursor.item";
396
397    /**
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>
406     *
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.
412     */
413    public static final String CURSOR_DIR_BASE_TYPE = "vnd.android.cursor.dir";
414
415    /**
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".
420     */
421    public static final String ANY_CURSOR_ITEM_TYPE = "vnd.android.cursor.item/*";
422
423    /** @hide */
424    public static final int SYNC_ERROR_SYNC_ALREADY_IN_PROGRESS = 1;
425    /** @hide */
426    public static final int SYNC_ERROR_AUTHENTICATION = 2;
427    /** @hide */
428    public static final int SYNC_ERROR_IO = 3;
429    /** @hide */
430    public static final int SYNC_ERROR_PARSE = 4;
431    /** @hide */
432    public static final int SYNC_ERROR_CONFLICT = 5;
433    /** @hide */
434    public static final int SYNC_ERROR_TOO_MANY_DELETIONS = 6;
435    /** @hide */
436    public static final int SYNC_ERROR_TOO_MANY_RETRIES = 7;
437    /** @hide */
438    public static final int SYNC_ERROR_INTERNAL = 8;
439
440    private static final String[] SYNC_ERROR_NAMES = new String[] {
441          "already-in-progress",
442          "authentication-error",
443          "io-error",
444          "parse-error",
445          "conflict",
446          "too-many-deletions",
447          "too-many-retries",
448          "internal-error",
449    };
450
451    /** @hide */
452    public static String syncErrorToString(int error) {
453        if (error < 1 || error > SYNC_ERROR_NAMES.length) {
454            return String.valueOf(error);
455        }
456        return SYNC_ERROR_NAMES[error - 1];
457    }
458
459    /** @hide */
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)) {
463                return i + 1;
464            }
465        }
466        if (error != null) {
467            try {
468                return Integer.parseInt(error);
469            } catch (NumberFormatException e) {
470                Log.d(TAG, "error parsing sync error: " + error);
471            }
472        }
473        return 0;
474    }
475
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;
479    /** @hide */
480    public static final int SYNC_OBSERVER_TYPE_STATUS = 1<<3;
481    /** @hide */
482    public static final int SYNC_OBSERVER_TYPE_ALL = 0x7fffffff;
483
484    /** @hide */
485    @IntDef(flag = true,
486            value = {
487                NOTIFY_SYNC_TO_NETWORK,
488                NOTIFY_SKIP_NOTIFY_FOR_DESCENDANTS
489            })
490    @Retention(RetentionPolicy.SOURCE)
491    public @interface NotifyFlags {}
492
493    /**
494     * Flag for {@link #notifyChange(Uri, ContentObserver, int)}: attempt to sync the change
495     * to the network.
496     */
497    public static final int NOTIFY_SYNC_TO_NETWORK = 1<<0;
498
499    /**
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.
506     */
507    public static final int NOTIFY_SKIP_NOTIFY_FOR_DESCENDANTS = 1<<1;
508
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
514
515    public ContentResolver(Context context) {
516        mContext = context != null ? context : ActivityThread.currentApplication();
517        mPackageName = mContext.getOpPackageName();
518        mTargetSdkVersion = mContext.getApplicationInfo().targetSdkVersion;
519    }
520
521    /** @hide */
522    protected abstract IContentProvider acquireProvider(Context c, String name);
523
524    /**
525     * Providing a default implementation of this, to avoid having to change a
526     * lot of other things, but implementations of ContentResolver should
527     * implement it.
528     *
529     * @hide
530     */
531    protected IContentProvider acquireExistingProvider(Context c, String name) {
532        return acquireProvider(c, name);
533    }
534
535    /** @hide */
536    public abstract boolean releaseProvider(IContentProvider icp);
537    /** @hide */
538    protected abstract IContentProvider acquireUnstableProvider(Context c, String name);
539    /** @hide */
540    public abstract boolean releaseUnstableProvider(IContentProvider icp);
541    /** @hide */
542    public abstract void unstableProviderDied(IContentProvider icp);
543
544    /** @hide */
545    public void appNotRespondingViaProvider(IContentProvider icp) {
546        throw new UnsupportedOperationException("appNotRespondingViaProvider");
547    }
548
549    /**
550     * Return the MIME type of the given content URL.
551     *
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
555     */
556    public final @Nullable String getType(@NonNull Uri url) {
557        Preconditions.checkNotNull(url, "url");
558
559        // XXX would like to have an acquireExistingUnstableProvider for this.
560        IContentProvider provider = acquireExistingProvider(url);
561        if (provider != null) {
562            try {
563                return provider.getType(url);
564            } catch (RemoteException e) {
565                return null;
566            } catch (java.lang.Exception e) {
567                Log.w(TAG, "Failed to get type for: " + url + " (" + e.getMessage() + ")");
568                return null;
569            } finally {
570                releaseProvider(provider);
571            }
572        }
573
574        if (!SCHEME_CONTENT.equals(url.getScheme())) {
575            return null;
576        }
577
578        try {
579            String type = ActivityManager.getService().getProviderMimeType(
580                    ContentProvider.getUriWithoutUserId(url), resolveUserId(url));
581            return type;
582        } catch (RemoteException e) {
583            // Arbitrary and not worth documenting, as Activity
584            // Manager will kill this process shortly anyway.
585            return null;
586        } catch (java.lang.Exception e) {
587            Log.w(TAG, "Failed to get type for: " + url + " (" + e.getMessage() + ")");
588            return null;
589        }
590    }
591
592    /**
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.
599     *
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 *&#47;*, to query for all available MIME types that match the
604     * pattern.
605     * @return Returns an array of MIME type strings for all available
606     * data streams that match the given mimeTypeFilter.  If there are none,
607     * null is returned.
608     */
609    public @Nullable String[] getStreamTypes(@NonNull Uri url, @NonNull String mimeTypeFilter) {
610        Preconditions.checkNotNull(url, "url");
611        Preconditions.checkNotNull(mimeTypeFilter, "mimeTypeFilter");
612
613        IContentProvider provider = acquireProvider(url);
614        if (provider == null) {
615            return null;
616        }
617
618        try {
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.
623            return null;
624        } finally {
625            releaseProvider(provider);
626        }
627    }
628
629    /**
630     * Query the given URI, returning a {@link Cursor} over the result set.
631     * <p>
632     * For best performance, the caller should follow these guidelines:
633     * <ul>
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>
640     * </ul>
641     * </p>
642     *
643     * @param uri The URI, using the content:// scheme, for the content to
644     *         retrieve.
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
657     * @see Cursor
658     */
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);
663    }
664
665    /**
666     * Query the given URI, returning a {@link Cursor} over the result set
667     * with optional support for cancellation.
668     * <p>
669     * For best performance, the caller should follow these guidelines:
670     * <ul>
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>
677     * </ul>
678     * </p>
679     *
680     * @param uri The URI, using the content:// scheme, for the content to
681     *         retrieve.
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
697     * @see Cursor
698     */
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);
705    }
706
707    /**
708     * Query the given URI, returning a {@link Cursor} over the result set
709     * with support for cancellation.
710     *
711     * <p>For best performance, the caller should follow these guidelines:
712     *
713     * <li>Provide an explicit projection, to prevent reading data from storage
714     * that aren't going to be used.
715     *
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}
719     * for details.
720     *
721     * @see #QUERY_ARG_SORT_COLUMNS, #QUERY_ARG_SORT_DIRECTION, #QUERY_ARG_SORT_COLLATION.
722     *
723     * @param uri The URI, using the content:// scheme, for the content to
724     *         retrieve.
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
732     * @see Cursor
733     */
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) {
740            return null;
741        }
742        IContentProvider stableProvider = null;
743        Cursor qCursor = null;
744        try {
745            long startTime = SystemClock.uptimeMillis();
746
747            ICancellationSignal remoteCancellationSignal = null;
748            if (cancellationSignal != null) {
749                cancellationSignal.throwIfCanceled();
750                remoteCancellationSignal = unstableProvider.createCancellationSignal();
751                cancellationSignal.setRemote(remoteCancellationSignal);
752            }
753            try {
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) {
763                    return null;
764                }
765                qCursor = stableProvider.query(
766                        mPackageName, uri, projection, queryArgs, remoteCancellationSignal);
767            }
768            if (qCursor == null) {
769                return null;
770            }
771
772            // Force query execution.  Might fail and throw a runtime exception here.
773            qCursor.getCount();
774            long durationMillis = SystemClock.uptimeMillis() - startTime;
775            maybeLogQueryToEventLog(durationMillis, uri, projection, queryArgs);
776
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;
782            qCursor = null;
783            return wrapper;
784        } catch (RemoteException e) {
785            // Arbitrary and not worth documenting, as Activity
786            // Manager will kill this process shortly anyway.
787            return null;
788        } finally {
789            if (qCursor != null) {
790                qCursor.close();
791            }
792            if (cancellationSignal != null) {
793                cancellationSignal.setRemote(null);
794            }
795            if (unstableProvider != null) {
796                releaseUnstableProvider(unstableProvider);
797            }
798            if (stableProvider != null) {
799                releaseProvider(stableProvider);
800            }
801        }
802    }
803
804    /**
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.
815     *
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>
822     *
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.
826     *
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.
831     *
832     * @see #uncanonicalize
833     */
834    public final @Nullable Uri canonicalize(@NonNull Uri url) {
835        Preconditions.checkNotNull(url, "url");
836        IContentProvider provider = acquireProvider(url);
837        if (provider == null) {
838            return null;
839        }
840
841        try {
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.
846            return null;
847        } finally {
848            releaseProvider(provider);
849        }
850    }
851
852    /**
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
858     * new environment.
859     *
860     * @param url The canonical {@link Uri} that is to be convered back to its
861     * non-canonical form.
862     *
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.
867     *
868     * @see #canonicalize
869     */
870    public final @Nullable Uri uncanonicalize(@NonNull Uri url) {
871        Preconditions.checkNotNull(url, "url");
872        IContentProvider provider = acquireProvider(url);
873        if (provider == null) {
874            return null;
875        }
876
877        try {
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.
882            return null;
883        } finally {
884            releaseProvider(provider);
885        }
886    }
887
888    /**
889     * This allows clients to request an explicit refresh of content identified by {@code uri}.
890     * <p>
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.
893     * <p>
894     *
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.
903     */
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) {
909            return false;
910        }
911
912        try {
913            ICancellationSignal remoteCancellationSignal = null;
914            if (cancellationSignal != null) {
915                cancellationSignal.throwIfCanceled();
916                remoteCancellationSignal = provider.createCancellationSignal();
917                cancellationSignal.setRemote(remoteCancellationSignal);
918            }
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.
923            return false;
924        } finally {
925            releaseProvider(provider);
926        }
927    }
928
929    /**
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.
932     *
933     * <h5>Accepts the following URI schemes:</h5>
934     * <ul>
935     * <li>content ({@link #SCHEME_CONTENT})</li>
936     * <li>android.resource ({@link #SCHEME_ANDROID_RESOURCE})</li>
937     * <li>file ({@link #SCHEME_FILE})</li>
938     * </ul>
939     *
940     * <p>See {@link #openAssetFileDescriptor(Uri, String)} for more information
941     * on these schemes.
942     *
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)
947     */
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);
956            try {
957                InputStream stream = r.r.openRawResource(r.id);
958                return stream;
959            } catch (Resources.NotFoundException ex) {
960                throw new FileNotFoundException("Resource does not exist: " + uri);
961            }
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());
966        } else {
967            AssetFileDescriptor fd = openAssetFileDescriptor(uri, "r", null);
968            try {
969                return fd != null ? fd.createInputStream() : null;
970            } catch (IOException e) {
971                throw new FileNotFoundException("Unable to create stream");
972            }
973        }
974    }
975
976    /**
977     * Synonym for {@link #openOutputStream(Uri, String)
978     * openOutputStream(uri, "w")}.
979     * @throws FileNotFoundException if the provided URI could not be opened.
980     */
981    public final @Nullable OutputStream openOutputStream(@NonNull Uri uri)
982            throws FileNotFoundException {
983        return openOutputStream(uri, "w");
984    }
985
986    /**
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.
989     *
990     * <h5>Accepts the following URI schemes:</h5>
991     * <ul>
992     * <li>content ({@link #SCHEME_CONTENT})</li>
993     * <li>file ({@link #SCHEME_FILE})</li>
994     * </ul>
995     *
996     * <p>See {@link #openAssetFileDescriptor(Uri, String)} for more information
997     * on these schemes.
998     *
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)
1004     */
1005    public final @Nullable OutputStream openOutputStream(@NonNull Uri uri, @NonNull String mode)
1006            throws FileNotFoundException {
1007        AssetFileDescriptor fd = openAssetFileDescriptor(uri, mode, null);
1008        try {
1009            return fd != null ? fd.createOutputStream() : null;
1010        } catch (IOException e) {
1011            throw new FileNotFoundException("Unable to create stream");
1012        }
1013    }
1014
1015    /**
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.
1024     *
1025     * <h5>Accepts the following URI schemes:</h5>
1026     * <ul>
1027     * <li>content ({@link #SCHEME_CONTENT})</li>
1028     * <li>file ({@link #SCHEME_FILE})</li>
1029     * </ul>
1030     *
1031     * <p>See {@link #openAssetFileDescriptor(Uri, String)} for more information
1032     * on these schemes.
1033     * <p>
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.
1039     * <p>
1040     * If you are writing a file, and need to communicate an error to the
1041     * provider, use {@link ParcelFileDescriptor#closeWithError(String)}.
1042     *
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)
1051     */
1052    public final @Nullable ParcelFileDescriptor openFileDescriptor(@NonNull Uri uri,
1053            @NonNull String mode) throws FileNotFoundException {
1054        return openFileDescriptor(uri, mode, null);
1055    }
1056
1057    /**
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.
1066     *
1067     * <h5>Accepts the following URI schemes:</h5>
1068     * <ul>
1069     * <li>content ({@link #SCHEME_CONTENT})</li>
1070     * <li>file ({@link #SCHEME_FILE})</li>
1071     * </ul>
1072     *
1073     * <p>See {@link #openAssetFileDescriptor(Uri, String)} for more information
1074     * on these schemes.
1075     * <p>
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.
1081     * <p>
1082     * If you are writing a file, and need to communicate an error to the
1083     * provider, use {@link ParcelFileDescriptor#closeWithError(String)}.
1084     *
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)
1096     */
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);
1101        if (afd == null) {
1102            return null;
1103        }
1104
1105        if (afd.getDeclaredLength() < 0) {
1106            // This is a full file!
1107            return afd.getParcelFileDescriptor();
1108        }
1109
1110        // Client can't handle a sub-section of a file, so close what
1111        // we got and bail with an exception.
1112        try {
1113            afd.close();
1114        } catch (IOException e) {
1115        }
1116
1117        throw new FileNotFoundException("Not a whole file");
1118    }
1119
1120    /**
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.
1124     *
1125     * <h5>Accepts the following URI schemes:</h5>
1126     * <ul>
1127     * <li>content ({@link #SCHEME_CONTENT})</li>
1128     * <li>android.resource ({@link #SCHEME_ANDROID_RESOURCE})</li>
1129     * <li>file ({@link #SCHEME_FILE})</li>
1130     * </ul>
1131     * <h5>The android.resource ({@link #SCHEME_ANDROID_RESOURCE}) Scheme</h5>
1132     * <p>
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:
1135     * <ul>
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>
1142     * </li>
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>
1152     * </li>
1153     * </ul>
1154     *
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 "*&#47;*".  This allows such callers to benefit
1158     * from any built-in data conversion that a provider implements.
1159     *
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.
1167     */
1168    public final @Nullable AssetFileDescriptor openAssetFileDescriptor(@NonNull Uri uri,
1169            @NonNull String mode) throws FileNotFoundException {
1170        return openAssetFileDescriptor(uri, mode, null);
1171    }
1172
1173    /**
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.
1177     *
1178     * <h5>Accepts the following URI schemes:</h5>
1179     * <ul>
1180     * <li>content ({@link #SCHEME_CONTENT})</li>
1181     * <li>android.resource ({@link #SCHEME_ANDROID_RESOURCE})</li>
1182     * <li>file ({@link #SCHEME_FILE})</li>
1183     * </ul>
1184     * <h5>The android.resource ({@link #SCHEME_ANDROID_RESOURCE}) Scheme</h5>
1185     * <p>
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:
1188     * <ul>
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>
1195     * </li>
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>
1205     * </li>
1206     * </ul>
1207     *
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 "*&#47;*".  This allows such callers to benefit
1211     * from any built-in data conversion that a provider implements.
1212     *
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.
1223     */
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");
1229
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);
1234            }
1235            OpenResourceIdResult r = getResourceId(uri);
1236            try {
1237                return r.r.openRawResourceFd(r.id);
1238            } catch (Resources.NotFoundException ex) {
1239                throw new FileNotFoundException("Resource does not exist: " + uri);
1240            }
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);
1245        } else {
1246            if ("r".equals(mode)) {
1247                return openTypedAssetFileDescriptor(uri, "*/*", null, cancellationSignal);
1248            } else {
1249                IContentProvider unstableProvider = acquireUnstableProvider(uri);
1250                if (unstableProvider == null) {
1251                    throw new FileNotFoundException("No content provider: " + uri);
1252                }
1253                IContentProvider stableProvider = null;
1254                AssetFileDescriptor fd = null;
1255
1256                try {
1257                    ICancellationSignal remoteCancellationSignal = null;
1258                    if (cancellationSignal != null) {
1259                        cancellationSignal.throwIfCanceled();
1260                        remoteCancellationSignal = unstableProvider.createCancellationSignal();
1261                        cancellationSignal.setRemote(remoteCancellationSignal);
1262                    }
1263
1264                    try {
1265                        fd = unstableProvider.openAssetFile(
1266                                mPackageName, uri, mode, remoteCancellationSignal);
1267                        if (fd == null) {
1268                            // The provider will be released by the finally{} clause
1269                            return null;
1270                        }
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);
1279                        }
1280                        fd = stableProvider.openAssetFile(
1281                                mPackageName, uri, mode, remoteCancellationSignal);
1282                        if (fd == null) {
1283                            // The provider will be released by the finally{} clause
1284                            return null;
1285                        }
1286                    }
1287
1288                    if (stableProvider == null) {
1289                        stableProvider = acquireProvider(uri);
1290                    }
1291                    releaseUnstableProvider(unstableProvider);
1292                    unstableProvider = null;
1293                    ParcelFileDescriptor pfd = new ParcelFileDescriptorInner(
1294                            fd.getParcelFileDescriptor(), stableProvider);
1295
1296                    // Success!  Don't release the provider when exiting, let
1297                    // ParcelFileDescriptorInner do that when it is closed.
1298                    stableProvider = null;
1299
1300                    return new AssetFileDescriptor(pfd, fd.getStartOffset(),
1301                            fd.getDeclaredLength());
1302
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) {
1308                    throw e;
1309                } finally {
1310                    if (cancellationSignal != null) {
1311                        cancellationSignal.setRemote(null);
1312                    }
1313                    if (stableProvider != null) {
1314                        releaseProvider(stableProvider);
1315                    }
1316                    if (unstableProvider != null) {
1317                        releaseUnstableProvider(unstableProvider);
1318                    }
1319                }
1320            }
1321        }
1322    }
1323
1324    /**
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.
1330     *
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.
1335     *
1336     * <p>All text/* streams are encoded in UTF-8.
1337     *
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 *&#47;*, which will allow the content provider to
1341     * select a type, though there is no way for you to determine what type
1342     * it is returning.
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.
1351     */
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);
1355    }
1356
1357    /**
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.
1363     *
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.
1368     *
1369     * <p>All text/* streams are encoded in UTF-8.
1370     *
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 *&#47;*, which will allow the content provider to
1374     * select a type, though there is no way for you to determine what type
1375     * it is returning.
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.
1387     */
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");
1393
1394        IContentProvider unstableProvider = acquireUnstableProvider(uri);
1395        if (unstableProvider == null) {
1396            throw new FileNotFoundException("No content provider: " + uri);
1397        }
1398        IContentProvider stableProvider = null;
1399        AssetFileDescriptor fd = null;
1400
1401        try {
1402            ICancellationSignal remoteCancellationSignal = null;
1403            if (cancellationSignal != null) {
1404                cancellationSignal.throwIfCanceled();
1405                remoteCancellationSignal = unstableProvider.createCancellationSignal();
1406                cancellationSignal.setRemote(remoteCancellationSignal);
1407            }
1408
1409            try {
1410                fd = unstableProvider.openTypedAssetFile(
1411                        mPackageName, uri, mimeType, opts, remoteCancellationSignal);
1412                if (fd == null) {
1413                    // The provider will be released by the finally{} clause
1414                    return null;
1415                }
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);
1424                }
1425                fd = stableProvider.openTypedAssetFile(
1426                        mPackageName, uri, mimeType, opts, remoteCancellationSignal);
1427                if (fd == null) {
1428                    // The provider will be released by the finally{} clause
1429                    return null;
1430                }
1431            }
1432
1433            if (stableProvider == null) {
1434                stableProvider = acquireProvider(uri);
1435            }
1436            releaseUnstableProvider(unstableProvider);
1437            unstableProvider = null;
1438            ParcelFileDescriptor pfd = new ParcelFileDescriptorInner(
1439                    fd.getParcelFileDescriptor(), stableProvider);
1440
1441            // Success!  Don't release the provider when exiting, let
1442            // ParcelFileDescriptorInner do that when it is closed.
1443            stableProvider = null;
1444
1445            return new AssetFileDescriptor(pfd, fd.getStartOffset(),
1446                    fd.getDeclaredLength());
1447
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) {
1453            throw e;
1454        } finally {
1455            if (cancellationSignal != null) {
1456                cancellationSignal.setRemote(null);
1457            }
1458            if (stableProvider != null) {
1459                releaseProvider(stableProvider);
1460            }
1461            if (unstableProvider != null) {
1462                releaseUnstableProvider(unstableProvider);
1463            }
1464        }
1465    }
1466
1467    /**
1468     * A resource identified by the {@link Resources} that contains it, and a resource id.
1469     *
1470     * @hide
1471     */
1472    public class OpenResourceIdResult {
1473        public Resources r;
1474        public int id;
1475    }
1476
1477    /**
1478     * Resolves an android.resource URI to a {@link Resources} and a resource id.
1479     *
1480     * @hide
1481     */
1482    public OpenResourceIdResult getResourceId(Uri uri) throws FileNotFoundException {
1483        String authority = uri.getAuthority();
1484        Resources r;
1485        if (TextUtils.isEmpty(authority)) {
1486            throw new FileNotFoundException("No authority: " + uri);
1487        } else {
1488            try {
1489                r = mContext.getPackageManager().getResourcesForApplication(authority);
1490            } catch (NameNotFoundException ex) {
1491                throw new FileNotFoundException("No package found for authority: " + uri);
1492            }
1493        }
1494        List<String> path = uri.getPathSegments();
1495        if (path == null) {
1496            throw new FileNotFoundException("No path: " + uri);
1497        }
1498        int len = path.size();
1499        int id;
1500        if (len == 1) {
1501            try {
1502                id = Integer.parseInt(path.get(0));
1503            } catch (NumberFormatException e) {
1504                throw new FileNotFoundException("Single path segment is not a resource ID: " + uri);
1505            }
1506        } else if (len == 2) {
1507            id = r.getIdentifier(path.get(1), path.get(0), authority);
1508        } else {
1509            throw new FileNotFoundException("More than two path segments: " + uri);
1510        }
1511        if (id == 0) {
1512            throw new FileNotFoundException("No resource found for: " + uri);
1513        }
1514        OpenResourceIdResult res = new OpenResourceIdResult();
1515        res.r = r;
1516        res.id = id;
1517        return res;
1518    }
1519
1520    /**
1521     * Inserts a row into a table at the given URL.
1522     *
1523     * If the content provider supports transactions the insertion will be atomic.
1524     *
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.
1529     */
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);
1536        }
1537        try {
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 */);
1542            return createdRow;
1543        } catch (RemoteException e) {
1544            // Arbitrary and not worth documenting, as Activity
1545            // Manager will kill this process shortly anyway.
1546            return null;
1547        } finally {
1548            releaseProvider(provider);
1549        }
1550    }
1551
1552    /**
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.
1567     */
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);
1576        }
1577        try {
1578            return provider.applyBatch(operations);
1579        } finally {
1580            provider.release();
1581        }
1582    }
1583
1584    /**
1585     * Inserts multiple rows into a table at the given URL.
1586     *
1587     * This function make no guarantees about the atomicity of the insertions.
1588     *
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.
1593     */
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);
1601        }
1602        try {
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 */);
1607            return rowsCreated;
1608        } catch (RemoteException e) {
1609            // Arbitrary and not worth documenting, as Activity
1610            // Manager will kill this process shortly anyway.
1611            return 0;
1612        } finally {
1613            releaseProvider(provider);
1614        }
1615    }
1616
1617    /**
1618     * Deletes row(s) specified by a content URI.
1619     *
1620     * If the content provider supports transactions, the deletion will be atomic.
1621     *
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.
1626     */
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);
1633        }
1634        try {
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);
1639            return rowsDeleted;
1640        } catch (RemoteException e) {
1641            // Arbitrary and not worth documenting, as Activity
1642            // Manager will kill this process shortly anyway.
1643            return -1;
1644        } finally {
1645            releaseProvider(provider);
1646        }
1647    }
1648
1649    /**
1650     * Update row(s) in a content URI.
1651     *
1652     * If the content provider supports transactions the update will be atomic.
1653     *
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
1661     */
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);
1669        }
1670        try {
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);
1675            return rowsUpdated;
1676        } catch (RemoteException e) {
1677            // Arbitrary and not worth documenting, as Activity
1678            // Manager will kill this process shortly anyway.
1679            return -1;
1680        } finally {
1681            releaseProvider(provider);
1682        }
1683    }
1684
1685    /**
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.
1689     *
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
1698     */
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);
1706        }
1707        try {
1708            final Bundle res = provider.call(mPackageName, method, arg, extras);
1709            Bundle.setDefusable(res, true);
1710            return res;
1711        } catch (RemoteException e) {
1712            // Arbitrary and not worth documenting, as Activity
1713            // Manager will kill this process shortly anyway.
1714            return null;
1715        } finally {
1716            releaseProvider(provider);
1717        }
1718    }
1719
1720    /**
1721     * Returns the content provider for the given content URI.
1722     *
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.
1725     * @hide
1726     */
1727    public final IContentProvider acquireProvider(Uri uri) {
1728        if (!SCHEME_CONTENT.equals(uri.getScheme())) {
1729            return null;
1730        }
1731        final String auth = uri.getAuthority();
1732        if (auth != null) {
1733            return acquireProvider(mContext, auth);
1734        }
1735        return null;
1736    }
1737
1738    /**
1739     * Returns the content provider for the given content URI if the process
1740     * already has a reference on it.
1741     *
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.
1744     * @hide
1745     */
1746    public final IContentProvider acquireExistingProvider(Uri uri) {
1747        if (!SCHEME_CONTENT.equals(uri.getScheme())) {
1748            return null;
1749        }
1750        final String auth = uri.getAuthority();
1751        if (auth != null) {
1752            return acquireExistingProvider(mContext, auth);
1753        }
1754        return null;
1755    }
1756
1757    /**
1758     * @hide
1759     */
1760    public final IContentProvider acquireProvider(String name) {
1761        if (name == null) {
1762            return null;
1763        }
1764        return acquireProvider(mContext, name);
1765    }
1766
1767    /**
1768     * Returns the content provider for the given content URI.
1769     *
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.
1772     * @hide
1773     */
1774    public final IContentProvider acquireUnstableProvider(Uri uri) {
1775        if (!SCHEME_CONTENT.equals(uri.getScheme())) {
1776            return null;
1777        }
1778        String auth = uri.getAuthority();
1779        if (auth != null) {
1780            return acquireUnstableProvider(mContext, uri.getAuthority());
1781        }
1782        return null;
1783    }
1784
1785    /**
1786     * @hide
1787     */
1788    public final IContentProvider acquireUnstableProvider(String name) {
1789        if (name == null) {
1790            return null;
1791        }
1792        return acquireUnstableProvider(mContext, name);
1793    }
1794
1795    /**
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.
1805     */
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);
1811        }
1812        return null;
1813    }
1814
1815    /**
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.
1825     */
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);
1832        }
1833
1834        return null;
1835    }
1836
1837    /**
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.
1852     */
1853    public final @Nullable ContentProviderClient acquireUnstableContentProviderClient(
1854            @NonNull Uri uri) {
1855        Preconditions.checkNotNull(uri, "uri");
1856        IContentProvider provider = acquireUnstableProvider(uri);
1857        if (provider != null) {
1858            return new ContentProviderClient(this, provider, false);
1859        }
1860
1861        return null;
1862    }
1863
1864    /**
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.
1879     */
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);
1886        }
1887
1888        return null;
1889    }
1890
1891    /**
1892     * Register an observer class that gets callbacks when data identified by a
1893     * given content URI changes.
1894     * <p>
1895     * Starting in {@link android.os.Build.VERSION_CODES#O}, all content
1896     * notifications must be backed by a valid {@link ContentProvider}.
1897     *
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
1905     *            hierarchy.
1906     * @param observer The object that receives callbacks when changes occur.
1907     * @see #unregisterContentObserver
1908     */
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,
1916                observer,
1917                ContentProvider.getUserIdFromUri(uri, mContext.getUserId()));
1918    }
1919
1920    /** @hide - designated user version */
1921    public final void registerContentObserver(Uri uri, boolean notifyForDescendents,
1922            ContentObserver observer, @UserIdInt int userHandle) {
1923        try {
1924            getContentService().registerContentObserver(uri, notifyForDescendents,
1925                    observer.getContentObserver(), userHandle, mTargetSdkVersion);
1926        } catch (RemoteException e) {
1927        }
1928    }
1929
1930    /**
1931     * Unregisters a change observer.
1932     *
1933     * @param observer The previously registered observer that is no longer needed.
1934     * @see #registerContentObserver
1935     */
1936    public final void unregisterContentObserver(@NonNull ContentObserver observer) {
1937        Preconditions.checkNotNull(observer, "observer");
1938        try {
1939            IContentObserver contentObserver = observer.releaseContentObserver();
1940            if (contentObserver != null) {
1941                getContentService().unregisterContentObserver(
1942                        contentObserver);
1943            }
1944        } catch (RemoteException e) {
1945        }
1946    }
1947
1948    /**
1949     * Notify registered observers that a row was updated and attempt to sync
1950     * changes to the network.
1951     * <p>
1952     * To observe events sent through this call, use
1953     * {@link #registerContentObserver(Uri, boolean, ContentObserver)}.
1954     * <p>
1955     * Starting in {@link android.os.Build.VERSION_CODES#O}, all content
1956     * notifications must be backed by a valid {@link ContentProvider}.
1957     *
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
1964     *            true.
1965     */
1966    public void notifyChange(@NonNull Uri uri, @Nullable ContentObserver observer) {
1967        notifyChange(uri, observer, true /* sync to network */);
1968    }
1969
1970    /**
1971     * Notify registered observers that a row was updated.
1972     * <p>
1973     * To observe events sent through this call, use
1974     * {@link #registerContentObserver(Uri, boolean, ContentObserver)}.
1975     * <p>
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.
1980     * <p>
1981     * Starting in {@link android.os.Build.VERSION_CODES#O}, all content
1982     * notifications must be backed by a valid {@link ContentProvider}.
1983     *
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
1990     *            true.
1991     * @param syncToNetwork If true, same as {@link #NOTIFY_SYNC_TO_NETWORK}.
1992     * @see #requestSync(android.accounts.Account, String, android.os.Bundle)
1993     */
1994    public void notifyChange(@NonNull Uri uri, @Nullable ContentObserver observer,
1995            boolean syncToNetwork) {
1996        Preconditions.checkNotNull(uri, "uri");
1997        notifyChange(
1998                ContentProvider.getUriWithoutUserId(uri),
1999                observer,
2000                syncToNetwork,
2001                ContentProvider.getUserIdFromUri(uri, mContext.getUserId()));
2002    }
2003
2004    /**
2005     * Notify registered observers that a row was updated.
2006     * <p>
2007     * To observe events sent through this call, use
2008     * {@link #registerContentObserver(Uri, boolean, ContentObserver)}.
2009     * <p>
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.
2014     * <p>
2015     * Starting in {@link android.os.Build.VERSION_CODES#O}, all content
2016     * notifications must be backed by a valid {@link ContentProvider}.
2017     *
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
2024     *            true.
2025     * @param flags Additional flags: {@link #NOTIFY_SYNC_TO_NETWORK}.
2026     * @see #requestSync(android.accounts.Account, String, android.os.Bundle)
2027     */
2028    public void notifyChange(@NonNull Uri uri, @Nullable ContentObserver observer,
2029            @NotifyFlags int flags) {
2030        Preconditions.checkNotNull(uri, "uri");
2031        notifyChange(
2032                ContentProvider.getUriWithoutUserId(uri),
2033                observer,
2034                flags,
2035                ContentProvider.getUserIdFromUri(uri, mContext.getUserId()));
2036    }
2037
2038    /**
2039     * Notify registered observers within the designated user(s) that a row was updated.
2040     *
2041     * @hide
2042     */
2043    public void notifyChange(@NonNull Uri uri, ContentObserver observer, boolean syncToNetwork,
2044            @UserIdInt int userHandle) {
2045        try {
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) {
2052        }
2053    }
2054
2055    /**
2056     * Notify registered observers within the designated user(s) that a row was updated.
2057     *
2058     * @hide
2059     */
2060    public void notifyChange(@NonNull Uri uri, ContentObserver observer, @NotifyFlags int flags,
2061            @UserIdInt int userHandle) {
2062        try {
2063            getContentService().notifyChange(
2064                    uri, observer == null ? null : observer.getContentObserver(),
2065                    observer != null && observer.deliverSelfNotifications(), flags,
2066                    userHandle, mTargetSdkVersion);
2067        } catch (RemoteException e) {
2068        }
2069    }
2070
2071    /**
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()}.
2078     *
2079     * @see #getPersistedUriPermissions()
2080     */
2081    public void takePersistableUriPermission(@NonNull Uri uri,
2082            @Intent.AccessUriMode int modeFlags) {
2083        Preconditions.checkNotNull(uri, "uri");
2084        try {
2085            ActivityManager.getService().takePersistableUriPermission(
2086                    ContentProvider.getUriWithoutUserId(uri), modeFlags, resolveUserId(uri));
2087        } catch (RemoteException e) {
2088        }
2089    }
2090
2091    /**
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.
2096     *
2097     * @see #getPersistedUriPermissions()
2098     */
2099    public void releasePersistableUriPermission(@NonNull Uri uri,
2100            @Intent.AccessUriMode int modeFlags) {
2101        Preconditions.checkNotNull(uri, "uri");
2102        try {
2103            ActivityManager.getService().releasePersistableUriPermission(
2104                    ContentProvider.getUriWithoutUserId(uri), modeFlags, resolveUserId(uri));
2105        } catch (RemoteException e) {
2106        }
2107    }
2108
2109    /**
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.
2115     *
2116     * @see #takePersistableUriPermission(Uri, int)
2117     * @see #releasePersistableUriPermission(Uri, int)
2118     */
2119    public @NonNull List<UriPermission> getPersistedUriPermissions() {
2120        try {
2121            return ActivityManager.getService()
2122                    .getPersistedUriPermissions(mPackageName, true).getList();
2123        } catch (RemoteException e) {
2124            throw new RuntimeException("Activity manager has died", e);
2125        }
2126    }
2127
2128    /**
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.
2134     */
2135    public @NonNull List<UriPermission> getOutgoingPersistedUriPermissions() {
2136        try {
2137            return ActivityManager.getService()
2138                    .getPersistedUriPermissions(mPackageName, false).getList();
2139        } catch (RemoteException e) {
2140            throw new RuntimeException("Activity manager has died", e);
2141        }
2142    }
2143
2144    /**
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:
2148     * <ul>
2149     * <li>Integer</li>
2150     * <li>Long</li>
2151     * <li>Boolean</li>
2152     * <li>Float</li>
2153     * <li>Double</li>
2154     * <li>String</li>
2155     * <li>Account</li>
2156     * <li>null</li>
2157     * </ul>
2158     *
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)}
2163     */
2164    @Deprecated
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");
2172            }
2173            extras.remove(SYNC_EXTRAS_ACCOUNT);
2174        }
2175        requestSync(account, uri != null ? uri.getAuthority() : null, extras);
2176    }
2177
2178    /**
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:
2182     * <ul>
2183     * <li>Integer</li>
2184     * <li>Long</li>
2185     * <li>Boolean</li>
2186     * <li>Float</li>
2187     * <li>Double</li>
2188     * <li>String</li>
2189     * <li>Account</li>
2190     * <li>null</li>
2191     * </ul>
2192     *
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.
2196     */
2197    public static void requestSync(Account account, String authority, Bundle extras) {
2198        requestSyncAsUser(account, authority, UserHandle.myUserId(), extras);
2199    }
2200
2201    /**
2202     * @see #requestSync(Account, String, Bundle)
2203     * @hide
2204     */
2205    public static void requestSyncAsUser(Account account, String authority, @UserIdInt int userId,
2206            Bundle extras) {
2207        if (extras == null) {
2208            throw new IllegalArgumentException("Must specify extras.");
2209        }
2210        SyncRequest request =
2211            new SyncRequest.Builder()
2212                .setSyncAdapter(account, authority)
2213                .setExtras(extras)
2214                .syncOnce()     // Immediate sync.
2215                .build();
2216        try {
2217            getContentService().syncAsUser(request, userId);
2218        } catch(RemoteException e) {
2219            // Shouldn't happen.
2220        }
2221    }
2222
2223    /**
2224     * Register a sync with the SyncManager. These requests are built using the
2225     * {@link SyncRequest.Builder}.
2226     */
2227    public static void requestSync(SyncRequest request) {
2228        try {
2229            getContentService().sync(request);
2230        } catch(RemoteException e) {
2231            // Shouldn't happen.
2232        }
2233    }
2234
2235    /**
2236     * Check that only values of the following types are in the Bundle:
2237     * <ul>
2238     * <li>Integer</li>
2239     * <li>Long</li>
2240     * <li>Boolean</li>
2241     * <li>Float</li>
2242     * <li>Double</li>
2243     * <li>String</li>
2244     * <li>Account</li>
2245     * <li>null</li>
2246     * </ul>
2247     * @param extras the Bundle to check
2248     */
2249    public static void validateSyncExtrasBundle(Bundle extras) {
2250        try {
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());
2263            }
2264        } catch (IllegalArgumentException e) {
2265            throw e;
2266        } catch (RuntimeException exc) {
2267            throw new IllegalArgumentException("error unparceling Bundle", exc);
2268        }
2269    }
2270
2271    /**
2272     * Cancel any active or pending syncs that match the Uri. If the uri is null then
2273     * all syncs will be canceled.
2274     *
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)}
2277     */
2278    @Deprecated
2279    public void cancelSync(Uri uri) {
2280        cancelSync(null /* all accounts */, uri != null ? uri.getAuthority() : null);
2281    }
2282
2283    /**
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.
2287     *
2288     * @param account filters the syncs that match by this account
2289     * @param authority filters the syncs that match by this authority
2290     */
2291    public static void cancelSync(Account account, String authority) {
2292        try {
2293            getContentService().cancelSync(account, authority, null);
2294        } catch (RemoteException e) {
2295        }
2296    }
2297
2298    /**
2299     * @see #cancelSync(Account, String)
2300     * @hide
2301     */
2302    public static void cancelSyncAsUser(Account account, String authority, @UserIdInt int userId) {
2303        try {
2304            getContentService().cancelSyncAsUser(account, authority, null, userId);
2305        } catch (RemoteException e) {
2306        }
2307    }
2308
2309    /**
2310     * Get information about the SyncAdapters that are known to the system.
2311     * @return an array of SyncAdapters that have registered with the system
2312     */
2313    public static SyncAdapterType[] getSyncAdapterTypes() {
2314        try {
2315            return getContentService().getSyncAdapterTypes();
2316        } catch (RemoteException e) {
2317            throw new RuntimeException("the ContentService should always be reachable", e);
2318        }
2319    }
2320
2321    /**
2322     * @see #getSyncAdapterTypes()
2323     * @hide
2324     */
2325    public static SyncAdapterType[] getSyncAdapterTypesAsUser(@UserIdInt int userId) {
2326        try {
2327            return getContentService().getSyncAdapterTypesAsUser(userId);
2328        } catch (RemoteException e) {
2329            throw new RuntimeException("the ContentService should always be reachable", e);
2330        }
2331    }
2332
2333    /**
2334     * @hide
2335     * Returns the package names of syncadapters that match a given user and authority.
2336     */
2337    @TestApi
2338    public static String[] getSyncAdapterPackagesForAuthorityAsUser(String authority,
2339            @UserIdInt int userId) {
2340        try {
2341            return getContentService().getSyncAdapterPackagesForAuthorityAsUser(authority, userId);
2342        } catch (RemoteException e) {
2343        }
2344        return ArrayUtils.emptyArray(String.class);
2345    }
2346
2347    /**
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}.
2351     *
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
2355     */
2356    public static boolean getSyncAutomatically(Account account, String authority) {
2357        try {
2358            return getContentService().getSyncAutomatically(account, authority);
2359        } catch (RemoteException e) {
2360            throw new RuntimeException("the ContentService should always be reachable", e);
2361        }
2362    }
2363
2364    /**
2365     * @see #getSyncAutomatically(Account, String)
2366     * @hide
2367     */
2368    public static boolean getSyncAutomaticallyAsUser(Account account, String authority,
2369            @UserIdInt int userId) {
2370        try {
2371            return getContentService().getSyncAutomaticallyAsUser(account, authority, userId);
2372        } catch (RemoteException e) {
2373            throw new RuntimeException("the ContentService should always be reachable", e);
2374        }
2375    }
2376
2377    /**
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}.
2381     *
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
2385     */
2386    public static void setSyncAutomatically(Account account, String authority, boolean sync) {
2387        setSyncAutomaticallyAsUser(account, authority, sync, UserHandle.myUserId());
2388    }
2389
2390    /**
2391     * @see #setSyncAutomatically(Account, String, boolean)
2392     * @hide
2393     */
2394    public static void setSyncAutomaticallyAsUser(Account account, String authority, boolean sync,
2395            @UserIdInt int userId) {
2396        try {
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
2400            // being restarted
2401        }
2402    }
2403
2404    /**
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.
2409     * <p>
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.
2414     * <p>
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.
2420     *
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
2424     * permissions using
2425     * {@link ContentResolver#getPeriodicSyncs(Account account, String provider)}, so no
2426     * sensitive data should be transferred here.
2427     *
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
2434     * are null.
2435     */
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");
2447        }
2448        try {
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
2452            // being restarted
2453        }
2454    }
2455
2456    /**
2457     * {@hide}
2458     * Helper function to throw an <code>IllegalArgumentException</code> if any illegal
2459     * extras were set for a periodic sync.
2460     *
2461     * @param extras bundle to validate.
2462     */
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)) {
2471            return true;
2472        }
2473        return false;
2474    }
2475
2476    /**
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}.
2481     *
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
2485     */
2486    public static void removePeriodicSync(Account account, String authority, Bundle extras) {
2487        validateSyncExtrasBundle(extras);
2488        try {
2489            getContentService().removePeriodicSync(account, authority, extras);
2490        } catch (RemoteException e) {
2491            throw new RuntimeException("the ContentService should always be reachable", e);
2492        }
2493    }
2494
2495    /**
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.
2498     * <p>
2499     *     If a periodic sync is specified, the caller must hold the permission
2500     *     {@link android.Manifest.permission#WRITE_SYNC_SETTINGS}.
2501     *</p>
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.
2505     *
2506     * @param request SyncRequest object containing information about sync to cancel.
2507     */
2508    public static void cancelSync(SyncRequest request) {
2509        if (request == null) {
2510            throw new IllegalArgumentException("request cannot be null");
2511        }
2512        try {
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
2516            // being restarted
2517        }
2518    }
2519
2520    /**
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}.
2524     *
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.
2528     */
2529    public static List<PeriodicSync> getPeriodicSyncs(Account account, String authority) {
2530        try {
2531            return getContentService().getPeriodicSyncs(account, authority, null);
2532        } catch (RemoteException e) {
2533            throw new RuntimeException("the ContentService should always be reachable", e);
2534        }
2535    }
2536
2537    /**
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.
2542     */
2543    public static int getIsSyncable(Account account, String authority) {
2544        try {
2545            return getContentService().getIsSyncable(account, authority);
2546        } catch (RemoteException e) {
2547            throw new RuntimeException("the ContentService should always be reachable", e);
2548        }
2549    }
2550
2551    /**
2552     * @see #getIsSyncable(Account, String)
2553     * @hide
2554     */
2555    public static int getIsSyncableAsUser(Account account, String authority,
2556            @UserIdInt int userId) {
2557        try {
2558            return getContentService().getIsSyncableAsUser(account, authority, userId);
2559        } catch (RemoteException e) {
2560            throw new RuntimeException("the ContentService should always be reachable", e);
2561        }
2562    }
2563
2564    /**
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
2569     */
2570    public static void setIsSyncable(Account account, String authority, int syncable) {
2571        try {
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
2575            // being restarted
2576        }
2577    }
2578
2579    /**
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}.
2584     *
2585     * @return the master auto-sync setting that applies to all the providers and accounts
2586     */
2587    public static boolean getMasterSyncAutomatically() {
2588        try {
2589            return getContentService().getMasterSyncAutomatically();
2590        } catch (RemoteException e) {
2591            throw new RuntimeException("the ContentService should always be reachable", e);
2592        }
2593    }
2594
2595    /**
2596     * @see #getMasterSyncAutomatically()
2597     * @hide
2598     */
2599    public static boolean getMasterSyncAutomaticallyAsUser(@UserIdInt int userId) {
2600        try {
2601            return getContentService().getMasterSyncAutomaticallyAsUser(userId);
2602        } catch (RemoteException e) {
2603            throw new RuntimeException("the ContentService should always be reachable", e);
2604        }
2605    }
2606
2607    /**
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}.
2612     *
2613     * @param sync the master auto-sync setting that applies to all the providers and accounts
2614     */
2615    public static void setMasterSyncAutomatically(boolean sync) {
2616        setMasterSyncAutomaticallyAsUser(sync, UserHandle.myUserId());
2617    }
2618
2619    /**
2620     * @see #setMasterSyncAutomatically(boolean)
2621     * @hide
2622     */
2623    public static void setMasterSyncAutomaticallyAsUser(boolean sync, @UserIdInt int userId) {
2624        try {
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
2628            // being restarted
2629        }
2630    }
2631
2632    /**
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.
2640     */
2641    public static boolean isSyncActive(Account account, String authority) {
2642        if (account == null) {
2643            throw new IllegalArgumentException("account must not be null");
2644        }
2645        if (authority == null) {
2646            throw new IllegalArgumentException("authority must not be null");
2647        }
2648
2649        try {
2650            return getContentService().isSyncActive(account, authority, null);
2651        } catch (RemoteException e) {
2652            throw new RuntimeException("the ContentService should always be reachable", e);
2653        }
2654    }
2655
2656    /**
2657     * If a sync is active returns the information about it, otherwise returns null.
2658     * <p>
2659     * This method requires the caller to hold the permission
2660     * {@link android.Manifest.permission#READ_SYNC_STATS}.
2661     * <p>
2662     * @return the SyncInfo for the currently active sync or null if one is not active.
2663     * @deprecated
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.
2668     */
2669    @Deprecated
2670    public static SyncInfo getCurrentSync() {
2671        try {
2672            final List<SyncInfo> syncs = getContentService().getCurrentSyncs();
2673            if (syncs.isEmpty()) {
2674                return null;
2675            }
2676            return syncs.get(0);
2677        } catch (RemoteException e) {
2678            throw new RuntimeException("the ContentService should always be reachable", e);
2679        }
2680    }
2681
2682    /**
2683     * Returns a list with information about all the active syncs. This list will be empty
2684     * if there are no active syncs.
2685     * <p>
2686     * This method requires the caller to hold the permission
2687     * {@link android.Manifest.permission#READ_SYNC_STATS}.
2688     * <p>
2689     * @return a List of SyncInfo objects for the currently active syncs.
2690     */
2691    public static List<SyncInfo> getCurrentSyncs() {
2692        try {
2693            return getContentService().getCurrentSyncs();
2694        } catch (RemoteException e) {
2695            throw new RuntimeException("the ContentService should always be reachable", e);
2696        }
2697    }
2698
2699    /**
2700     * @see #getCurrentSyncs()
2701     * @hide
2702     */
2703    public static List<SyncInfo> getCurrentSyncsAsUser(@UserIdInt int userId) {
2704        try {
2705            return getContentService().getCurrentSyncsAsUser(userId);
2706        } catch (RemoteException e) {
2707            throw new RuntimeException("the ContentService should always be reachable", e);
2708        }
2709    }
2710
2711    /**
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
2716     * @hide
2717     */
2718    public static SyncStatusInfo getSyncStatus(Account account, String authority) {
2719        try {
2720            return getContentService().getSyncStatus(account, authority, null);
2721        } catch (RemoteException e) {
2722            throw new RuntimeException("the ContentService should always be reachable", e);
2723        }
2724    }
2725
2726    /**
2727     * @see #getSyncStatus(Account, String)
2728     * @hide
2729     */
2730    public static SyncStatusInfo getSyncStatusAsUser(Account account, String authority,
2731            @UserIdInt int userId) {
2732        try {
2733            return getContentService().getSyncStatusAsUser(account, authority, null, userId);
2734        } catch (RemoteException e) {
2735            throw new RuntimeException("the ContentService should always be reachable", e);
2736        }
2737    }
2738
2739    /**
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
2746     */
2747    public static boolean isSyncPending(Account account, String authority) {
2748        return isSyncPendingAsUser(account, authority, UserHandle.myUserId());
2749    }
2750
2751    /**
2752     * @see #requestSync(Account, String, Bundle)
2753     * @hide
2754     */
2755    public static boolean isSyncPendingAsUser(Account account, String authority,
2756            @UserIdInt int userId) {
2757        try {
2758            return getContentService().isSyncPendingAsUser(account, authority, null, userId);
2759        } catch (RemoteException e) {
2760            throw new RuntimeException("the ContentService should always be reachable", e);
2761        }
2762    }
2763
2764    /**
2765     * Request notifications when the different aspects of the SyncManager change. The
2766     * different items that can be requested are:
2767     * <ul>
2768     * <li> {@link #SYNC_OBSERVER_TYPE_PENDING}
2769     * <li> {@link #SYNC_OBSERVER_TYPE_ACTIVE}
2770     * <li> {@link #SYNC_OBSERVER_TYPE_SETTINGS}
2771     * </ul>
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
2777     */
2778    public static Object addStatusChangeListener(int mask, final SyncStatusObserver callback) {
2779        if (callback == null) {
2780            throw new IllegalArgumentException("you passed in a null callback");
2781        }
2782        try {
2783            ISyncStatusObserver.Stub observer = new ISyncStatusObserver.Stub() {
2784                @Override
2785                public void onStatusChanged(int which) throws RemoteException {
2786                    callback.onStatusChanged(which);
2787                }
2788            };
2789            getContentService().addStatusChangeListener(mask, observer);
2790            return observer;
2791        } catch (RemoteException e) {
2792            throw new RuntimeException("the ContentService should always be reachable", e);
2793        }
2794    }
2795
2796    /**
2797     * Remove a previously registered status change listener.
2798     * @param handle the handle that was returned by {@link #addStatusChangeListener}
2799     */
2800    public static void removeStatusChangeListener(Object handle) {
2801        if (handle == null) {
2802            throw new IllegalArgumentException("you passed in a null handle");
2803        }
2804        try {
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
2808            // being restarted
2809        }
2810    }
2811
2812    /** {@hide} */
2813    public void putCache(Uri key, Bundle value) {
2814        try {
2815            getContentService().putCache(mContext.getPackageName(), key, value,
2816                    mContext.getUserId());
2817        } catch (RemoteException e) {
2818            throw e.rethrowFromSystemServer();
2819        }
2820    }
2821
2822    /** {@hide} */
2823    public Bundle getCache(Uri key) {
2824        try {
2825            final Bundle bundle = getContentService().getCache(mContext.getPackageName(), key,
2826                    mContext.getUserId());
2827            if (bundle != null) bundle.setClassLoader(mContext.getClassLoader());
2828            return bundle;
2829        } catch (RemoteException e) {
2830            throw e.rethrowFromSystemServer();
2831        }
2832    }
2833
2834    /** {@hide} */
2835    public int getTargetSdkVersion() {
2836        return mTargetSdkVersion;
2837    }
2838
2839    /**
2840     * Returns sampling percentage for a given duration.
2841     *
2842     * Always returns at least 1%.
2843     */
2844    private int samplePercentForDuration(long durationMillis) {
2845        if (durationMillis >= SLOW_THRESHOLD_MILLIS) {
2846            return 100;
2847        }
2848        return (int) (100 * durationMillis / SLOW_THRESHOLD_MILLIS) + 1;
2849    }
2850
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) {
2858                    return;
2859                }
2860            }
2861        }
2862
2863        // Ensure a non-null bundle.
2864        queryArgs = (queryArgs != null) ? queryArgs : Bundle.EMPTY;
2865
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]);
2875            }
2876        }
2877
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();
2882
2883        EventLog.writeEvent(
2884            EventLogTags.CONTENT_QUERY_SAMPLE,
2885            uri.toString(),
2886            projectionBuffer.toString(),
2887            queryArgs.getString(QUERY_ARG_SQL_SELECTION, ""),
2888            queryArgs.getString(QUERY_ARG_SQL_SORT_ORDER, ""),
2889            durationMillis,
2890            blockingPackage != null ? blockingPackage : "",
2891            samplePercent);
2892    }
2893
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) {
2901                    return;
2902                }
2903            }
2904        }
2905        String blockingPackage = AppGlobals.getInitialPackage();
2906        EventLog.writeEvent(
2907            EventLogTags.CONTENT_UPDATE_SAMPLE,
2908            uri.toString(),
2909            operation,
2910            selection != null ? selection : "",
2911            durationMillis,
2912            blockingPackage != null ? blockingPackage : "",
2913            samplePercent);
2914    }
2915
2916    private final class CursorWrapperInner extends CrossProcessCursorWrapper {
2917        private final IContentProvider mContentProvider;
2918        private final AtomicBoolean mProviderReleased = new AtomicBoolean();
2919
2920        private final CloseGuard mCloseGuard = CloseGuard.get();
2921
2922        CursorWrapperInner(Cursor cursor, IContentProvider contentProvider) {
2923            super(cursor);
2924            mContentProvider = contentProvider;
2925            mCloseGuard.open("close");
2926        }
2927
2928        @Override
2929        public void close() {
2930            mCloseGuard.close();
2931            super.close();
2932
2933            if (mProviderReleased.compareAndSet(false, true)) {
2934                ContentResolver.this.releaseProvider(mContentProvider);
2935            }
2936        }
2937
2938        @Override
2939        protected void finalize() throws Throwable {
2940            try {
2941                if (mCloseGuard != null) {
2942                    mCloseGuard.warnIfOpen();
2943                }
2944
2945                close();
2946            } finally {
2947                super.finalize();
2948            }
2949        }
2950    }
2951
2952    private final class ParcelFileDescriptorInner extends ParcelFileDescriptor {
2953        private final IContentProvider mContentProvider;
2954        private final AtomicBoolean mProviderReleased = new AtomicBoolean();
2955
2956        ParcelFileDescriptorInner(ParcelFileDescriptor pfd, IContentProvider icp) {
2957            super(pfd);
2958            mContentProvider = icp;
2959        }
2960
2961        @Override
2962        public void releaseResources() {
2963            if (mProviderReleased.compareAndSet(false, true)) {
2964                ContentResolver.this.releaseProvider(mContentProvider);
2965            }
2966        }
2967    }
2968
2969    /** @hide */
2970    public static final String CONTENT_SERVICE_NAME = "content";
2971
2972    /** @hide */
2973    public static IContentService getContentService() {
2974        if (sContentService != null) {
2975            return sContentService;
2976        }
2977        IBinder b = ServiceManager.getService(CONTENT_SERVICE_NAME);
2978        if (false) Log.v("ContentService", "default service binder = " + b);
2979        sContentService = IContentService.Stub.asInterface(b);
2980        if (false) Log.v("ContentService", "default service = " + sContentService);
2981        return sContentService;
2982    }
2983
2984    /** @hide */
2985    public String getPackageName() {
2986        return mPackageName;
2987    }
2988
2989    private static IContentService sContentService;
2990    private final Context mContext;
2991
2992    final String mPackageName;
2993    final int mTargetSdkVersion;
2994
2995    private static final String TAG = "ContentResolver";
2996
2997    /** @hide */
2998    public int resolveUserId(Uri uri) {
2999        return ContentProvider.getUserIdFromUri(uri, mContext.getUserId());
3000    }
3001
3002    /** @hide */
3003    public Drawable getTypeDrawable(String mimeType) {
3004        return MimeIconUtils.loadMimeIcon(mContext, mimeType);
3005    }
3006
3007    /**
3008     * @hide
3009     */
3010    public static @Nullable Bundle createSqlQueryBundle(
3011            @Nullable String selection,
3012            @Nullable String[] selectionArgs,
3013            @Nullable String sortOrder) {
3014
3015        if (selection == null && selectionArgs == null && sortOrder == null) {
3016            return null;
3017        }
3018
3019        Bundle queryArgs = new Bundle();
3020        if (selection != null) {
3021            queryArgs.putString(QUERY_ARG_SQL_SELECTION, selection);
3022        }
3023        if (selectionArgs != null) {
3024            queryArgs.putStringArray(QUERY_ARG_SQL_SELECTION_ARGS, selectionArgs);
3025        }
3026        if (sortOrder != null) {
3027            queryArgs.putString(QUERY_ARG_SQL_SORT_ORDER, sortOrder);
3028        }
3029        return queryArgs;
3030    }
3031
3032    /**
3033     * Returns structured sort args formatted as an SQL sort clause.
3034     *
3035     * NOTE: Collator clauses are suitable for use with non text fields. We might
3036     * choose to omit any collation clause since we don't know the underlying
3037     * type of data to be collated. Imperical testing shows that sqlite3 doesn't
3038     * appear to care much about the presence of collate clauses in queries
3039     * when ordering by numeric fields. For this reason we include collate
3040     * clause unilaterally when {@link #QUERY_ARG_SORT_COLLATION} is present
3041     * in query args bundle.
3042     *
3043     * TODO: Would be nice to explicitly validate that colums referenced in
3044     * {@link #QUERY_ARG_SORT_COLUMNS} are present in the associated projection.
3045     *
3046     * @hide
3047     */
3048    public static String createSqlSortClause(Bundle queryArgs) {
3049        String[] columns = queryArgs.getStringArray(QUERY_ARG_SORT_COLUMNS);
3050        if (columns == null || columns.length == 0) {
3051            throw new IllegalArgumentException("Can't create sort clause without columns.");
3052        }
3053
3054        String query = TextUtils.join(", ", columns);
3055
3056        // Interpret PRIMARY and SECONDARY collation strength as no-case collation based
3057        // on their javadoc descriptions.
3058        int collation = queryArgs.getInt(
3059                ContentResolver.QUERY_ARG_SORT_COLLATION, java.text.Collator.IDENTICAL);
3060        if (collation == java.text.Collator.PRIMARY || collation == java.text.Collator.SECONDARY) {
3061            query += " COLLATE NOCASE";
3062        }
3063
3064        int sortDir = queryArgs.getInt(QUERY_ARG_SORT_DIRECTION, Integer.MIN_VALUE);
3065        if (sortDir != Integer.MIN_VALUE) {
3066            switch (sortDir) {
3067                case QUERY_SORT_DIRECTION_ASCENDING:
3068                    query += " ASC";
3069                    break;
3070                case QUERY_SORT_DIRECTION_DESCENDING:
3071                    query += " DESC";
3072                    break;
3073                default:
3074                    throw new IllegalArgumentException("Unsupported sort direction value."
3075                            + " See ContentResolver documentation for details.");
3076            }
3077        }
3078        return query;
3079    }
3080}
3081