Home | History | Annotate | Download | only in content
      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 
     17 package android.content;
     18 
     19 import static android.provider.DocumentsContract.EXTRA_ORIENTATION;
     20 
     21 import android.accounts.Account;
     22 import android.annotation.IntDef;
     23 import android.annotation.NonNull;
     24 import android.annotation.Nullable;
     25 import android.annotation.RequiresPermission;
     26 import android.annotation.SystemApi;
     27 import android.annotation.TestApi;
     28 import android.annotation.UnsupportedAppUsage;
     29 import android.annotation.UserIdInt;
     30 import android.app.ActivityManager;
     31 import android.app.ActivityThread;
     32 import android.app.AppGlobals;
     33 import android.app.UriGrantsManager;
     34 import android.content.pm.PackageManager.NameNotFoundException;
     35 import android.content.res.AssetFileDescriptor;
     36 import android.content.res.Resources;
     37 import android.database.ContentObserver;
     38 import android.database.CrossProcessCursorWrapper;
     39 import android.database.Cursor;
     40 import android.database.IContentObserver;
     41 import android.graphics.Bitmap;
     42 import android.graphics.ImageDecoder;
     43 import android.graphics.ImageDecoder.ImageInfo;
     44 import android.graphics.ImageDecoder.Source;
     45 import android.graphics.Matrix;
     46 import android.graphics.Point;
     47 import android.graphics.drawable.Drawable;
     48 import android.graphics.drawable.Icon;
     49 import android.net.Uri;
     50 import android.os.Bundle;
     51 import android.os.CancellationSignal;
     52 import android.os.DeadObjectException;
     53 import android.os.IBinder;
     54 import android.os.ICancellationSignal;
     55 import android.os.OperationCanceledException;
     56 import android.os.ParcelFileDescriptor;
     57 import android.os.RemoteException;
     58 import android.os.ServiceManager;
     59 import android.os.SystemClock;
     60 import android.os.UserHandle;
     61 import android.os.storage.StorageManager;
     62 import android.system.Int32Ref;
     63 import android.text.TextUtils;
     64 import android.util.EventLog;
     65 import android.util.Log;
     66 import android.util.Size;
     67 
     68 import com.android.internal.util.MimeIconUtils;
     69 import com.android.internal.util.Preconditions;
     70 
     71 import dalvik.system.CloseGuard;
     72 
     73 import java.io.File;
     74 import java.io.FileInputStream;
     75 import java.io.FileNotFoundException;
     76 import java.io.IOException;
     77 import java.io.InputStream;
     78 import java.io.OutputStream;
     79 import java.lang.annotation.Retention;
     80 import java.lang.annotation.RetentionPolicy;
     81 import java.util.ArrayList;
     82 import java.util.List;
     83 import java.util.Objects;
     84 import java.util.Random;
     85 import java.util.concurrent.atomic.AtomicBoolean;
     86 
     87 /**
     88  * This class provides applications access to the content model.
     89  *
     90  * <div class="special reference">
     91  * <h3>Developer Guides</h3>
     92  * <p>For more information about using a ContentResolver with content providers, read the
     93  * <a href="{@docRoot}guide/topics/providers/content-providers.html">Content Providers</a>
     94  * developer guide.</p>
     95  * </div>
     96  */
     97 public abstract class ContentResolver implements ContentInterface {
     98     /**
     99      * Enables logic that supports deprecation of {@code _data} columns,
    100      * typically by replacing values with fake paths that the OS then offers to
    101      * redirect to {@link #openFileDescriptor(Uri, String)}, which developers
    102      * should be using directly.
    103      *
    104      * @hide
    105      */
    106     public static final boolean DEPRECATE_DATA_COLUMNS = StorageManager.hasIsolatedStorage();
    107 
    108     /**
    109      * Special filesystem path prefix which indicates that a path should be
    110      * treated as a {@code content://} {@link Uri} when
    111      * {@link #DEPRECATE_DATA_COLUMNS} is enabled.
    112      * <p>
    113      * The remainder of the path after this prefix is a
    114      * {@link Uri#getSchemeSpecificPart()} value, which includes authority, path
    115      * segments, and query parameters.
    116      *
    117      * @hide
    118      */
    119     public static final String DEPRECATE_DATA_PREFIX = "/mnt/content/";
    120 
    121     /**
    122      * @deprecated instead use
    123      * {@link #requestSync(android.accounts.Account, String, android.os.Bundle)}
    124      */
    125     @Deprecated
    126     public static final String SYNC_EXTRAS_ACCOUNT = "account";
    127 
    128     /**
    129      * If this extra is set to true, the sync request will be scheduled
    130      * at the front of the sync request queue and without any delay
    131      */
    132     public static final String SYNC_EXTRAS_EXPEDITED = "expedited";
    133 
    134     /**
    135      * If this extra is set to true, the sync request will be scheduled
    136      * only when the device is plugged in. This is equivalent to calling
    137      * setRequiresCharging(true) on {@link SyncRequest}.
    138      */
    139     public static final String SYNC_EXTRAS_REQUIRE_CHARGING = "require_charging";
    140 
    141     /**
    142      * @deprecated instead use
    143      * {@link #SYNC_EXTRAS_MANUAL}
    144      */
    145     @Deprecated
    146     public static final String SYNC_EXTRAS_FORCE = "force";
    147 
    148     /**
    149      * If this extra is set to true then the sync settings (like getSyncAutomatically())
    150      * are ignored by the sync scheduler.
    151      */
    152     public static final String SYNC_EXTRAS_IGNORE_SETTINGS = "ignore_settings";
    153 
    154     /**
    155      * If this extra is set to true then any backoffs for the initial attempt (e.g. due to retries)
    156      * are ignored by the sync scheduler. If this request fails and gets rescheduled then the
    157      * retries will still honor the backoff.
    158      */
    159     public static final String SYNC_EXTRAS_IGNORE_BACKOFF = "ignore_backoff";
    160 
    161     /**
    162      * If this extra is set to true then the request will not be retried if it fails.
    163      */
    164     public static final String SYNC_EXTRAS_DO_NOT_RETRY = "do_not_retry";
    165 
    166     /**
    167      * Setting this extra is the equivalent of setting both {@link #SYNC_EXTRAS_IGNORE_SETTINGS}
    168      * and {@link #SYNC_EXTRAS_IGNORE_BACKOFF}
    169      */
    170     public static final String SYNC_EXTRAS_MANUAL = "force";
    171 
    172     /**
    173      * Indicates that this sync is intended to only upload local changes to the server.
    174      * For example, this will be set to true if the sync is initiated by a call to
    175      * {@link ContentResolver#notifyChange(android.net.Uri, android.database.ContentObserver, boolean)}
    176      */
    177     public static final String SYNC_EXTRAS_UPLOAD = "upload";
    178 
    179     /**
    180      * Indicates that the sync adapter should proceed with the delete operations,
    181      * even if it determines that there are too many.
    182      * See {@link SyncResult#tooManyDeletions}
    183      */
    184     public static final String SYNC_EXTRAS_OVERRIDE_TOO_MANY_DELETIONS = "deletions_override";
    185 
    186     /**
    187      * Indicates that the sync adapter should not proceed with the delete operations,
    188      * if it determines that there are too many.
    189      * See {@link SyncResult#tooManyDeletions}
    190      */
    191     public static final String SYNC_EXTRAS_DISCARD_LOCAL_DELETIONS = "discard_deletions";
    192 
    193     /* Extensions to API. TODO: Not clear if we will keep these as public flags. */
    194     /** {@hide} User-specified flag for expected upload size. */
    195     public static final String SYNC_EXTRAS_EXPECTED_UPLOAD = "expected_upload";
    196 
    197     /** {@hide} User-specified flag for expected download size. */
    198     public static final String SYNC_EXTRAS_EXPECTED_DOWNLOAD = "expected_download";
    199 
    200     /** {@hide} Priority of this sync with respect to other syncs scheduled for this application. */
    201     public static final String SYNC_EXTRAS_PRIORITY = "sync_priority";
    202 
    203     /** {@hide} Flag to allow sync to occur on metered network. */
    204     public static final String SYNC_EXTRAS_DISALLOW_METERED = "allow_metered";
    205 
    206     /**
    207      * {@hide} Integer extra containing a SyncExemption flag.
    208      *
    209      * Only the system and the shell user can set it.
    210      *
    211      * This extra is "virtual". Once passed to the system server, it'll be removed from the bundle.
    212      */
    213     public static final String SYNC_VIRTUAL_EXTRAS_EXEMPTION_FLAG = "v_exemption";
    214 
    215     /**
    216      * Set by the SyncManager to request that the SyncAdapter initialize itself for
    217      * the given account/authority pair. One required initialization step is to
    218      * ensure that {@link #setIsSyncable(android.accounts.Account, String, int)} has been
    219      * called with a >= 0 value. When this flag is set the SyncAdapter does not need to
    220      * do a full sync, though it is allowed to do so.
    221      */
    222     public static final String SYNC_EXTRAS_INITIALIZE = "initialize";
    223 
    224     /** @hide */
    225     public static final Intent ACTION_SYNC_CONN_STATUS_CHANGED =
    226             new Intent("com.android.sync.SYNC_CONN_STATUS_CHANGED");
    227 
    228     public static final String SCHEME_CONTENT = "content";
    229     public static final String SCHEME_ANDROID_RESOURCE = "android.resource";
    230     public static final String SCHEME_FILE = "file";
    231 
    232     /**
    233      * An extra {@link Point} describing the optimal size for a requested image
    234      * resource, in pixels. If a provider has multiple sizes of the image, it
    235      * should return the image closest to this size.
    236      *
    237      * @see #openTypedAssetFileDescriptor(Uri, String, Bundle)
    238      * @see #openTypedAssetFileDescriptor(Uri, String, Bundle,
    239      *      CancellationSignal)
    240      */
    241     public static final String EXTRA_SIZE = "android.content.extra.SIZE";
    242 
    243     /**
    244      * An extra boolean describing whether a particular provider supports refresh
    245      * or not. If a provider supports refresh, it should include this key in its
    246      * returned Cursor as part of its query call.
    247      *
    248      */
    249     public static final String EXTRA_REFRESH_SUPPORTED = "android.content.extra.REFRESH_SUPPORTED";
    250 
    251     /**
    252      * Key for an SQL style selection string that may be present in the query Bundle argument
    253      * passed to {@link ContentProvider#query(Uri, String[], Bundle, CancellationSignal)}
    254      * when called by a legacy client.
    255      *
    256      * <p>Clients should never include user supplied values directly in the selection string,
    257      * as this presents an avenue for SQL injection attacks. In lieu of this, a client
    258      * should use standard placeholder notation to represent values in a selection string,
    259      * then supply a corresponding value in {@value #QUERY_ARG_SQL_SELECTION_ARGS}.
    260      *
    261      * <p><b>Apps targeting {@link android.os.Build.VERSION_CODES#O} or higher are strongly
    262      * encourage to use structured query arguments in lieu of opaque SQL query clauses.</b>
    263      *
    264      * @see #QUERY_ARG_SORT_COLUMNS
    265      * @see #QUERY_ARG_SORT_DIRECTION
    266      * @see #QUERY_ARG_SORT_COLLATION
    267      */
    268     public static final String QUERY_ARG_SQL_SELECTION = "android:query-arg-sql-selection";
    269 
    270     /**
    271      * Key for SQL selection string arguments list.
    272      *
    273      * <p>Clients should never include user supplied values directly in the selection string,
    274      * as this presents an avenue for SQL injection attacks. In lieu of this, a client
    275      * should use standard placeholder notation to represent values in a selection string,
    276      * then supply a corresponding value in {@value #QUERY_ARG_SQL_SELECTION_ARGS}.
    277      *
    278      * <p><b>Apps targeting {@link android.os.Build.VERSION_CODES#O} or higher are strongly
    279      * encourage to use structured query arguments in lieu of opaque SQL query clauses.</b>
    280      *
    281      * @see #QUERY_ARG_SORT_COLUMNS
    282      * @see #QUERY_ARG_SORT_DIRECTION
    283      * @see #QUERY_ARG_SORT_COLLATION
    284      */
    285     public static final String QUERY_ARG_SQL_SELECTION_ARGS =
    286             "android:query-arg-sql-selection-args";
    287 
    288     /**
    289      * Key for an SQL style sort string that may be present in the query Bundle argument
    290      * passed to {@link ContentProvider#query(Uri, String[], Bundle, CancellationSignal)}
    291      * when called by a legacy client.
    292      *
    293      * <p><b>Apps targeting {@link android.os.Build.VERSION_CODES#O} or higher are strongly
    294      * encourage to use structured query arguments in lieu of opaque SQL query clauses.</b>
    295      *
    296      * @see #QUERY_ARG_SORT_COLUMNS
    297      * @see #QUERY_ARG_SORT_DIRECTION
    298      * @see #QUERY_ARG_SORT_COLLATION
    299      */
    300     public static final String QUERY_ARG_SQL_SORT_ORDER = "android:query-arg-sql-sort-order";
    301 
    302     /** {@hide} */
    303     public static final String QUERY_ARG_SQL_GROUP_BY = "android:query-arg-sql-group-by";
    304     /** {@hide} */
    305     public static final String QUERY_ARG_SQL_HAVING = "android:query-arg-sql-having";
    306     /** {@hide} */
    307     public static final String QUERY_ARG_SQL_LIMIT = "android:query-arg-sql-limit";
    308 
    309     /**
    310      * Specifies the list of columns against which to sort results. When first column values
    311      * are identical, records are then sorted based on second column values, and so on.
    312      *
    313      * <p>Columns present in this list must also be included in the projection
    314      * supplied to {@link ContentResolver#query(Uri, String[], Bundle, CancellationSignal)}.
    315      *
    316      * <p>Apps targeting {@link android.os.Build.VERSION_CODES#O} or higher:
    317      *
    318      * <li>{@link ContentProvider} implementations: When preparing data in
    319      * {@link ContentProvider#query(Uri, String[], Bundle, CancellationSignal)}, if sort columns
    320      * is reflected in the returned Cursor, it is  strongly recommended that
    321      * {@link #QUERY_ARG_SORT_COLUMNS} then be included in the array of honored arguments
    322      * reflected in {@link Cursor} extras {@link Bundle} under {@link #EXTRA_HONORED_ARGS}.
    323      *
    324      * <li>When querying a provider, where no QUERY_ARG_SQL* otherwise exists in the
    325      * arguments {@link Bundle}, the Content framework will attempt to synthesize
    326      * an QUERY_ARG_SQL* argument using the corresponding QUERY_ARG_SORT* values.
    327      */
    328     public static final String QUERY_ARG_SORT_COLUMNS = "android:query-arg-sort-columns";
    329 
    330     /**
    331      * Specifies desired sort order. When unspecified a provider may provide a default
    332      * sort direction, or choose to return unsorted results.
    333      *
    334      * <p>Apps targeting {@link android.os.Build.VERSION_CODES#O} or higher:
    335      *
    336      * <li>{@link ContentProvider} implementations: When preparing data in
    337      * {@link ContentProvider#query(Uri, String[], Bundle, CancellationSignal)}, if sort direction
    338      * is reflected in the returned Cursor, it is  strongly recommended that
    339      * {@link #QUERY_ARG_SORT_DIRECTION} then be included in the array of honored arguments
    340      * reflected in {@link Cursor} extras {@link Bundle} under {@link #EXTRA_HONORED_ARGS}.
    341      *
    342      * <li>When querying a provider, where no QUERY_ARG_SQL* otherwise exists in the
    343      * arguments {@link Bundle}, the Content framework will attempt to synthesize
    344      * a QUERY_ARG_SQL* argument using the corresponding QUERY_ARG_SORT* values.
    345      *
    346      * @see #QUERY_SORT_DIRECTION_ASCENDING
    347      * @see #QUERY_SORT_DIRECTION_DESCENDING
    348      */
    349     public static final String QUERY_ARG_SORT_DIRECTION = "android:query-arg-sort-direction";
    350 
    351     /**
    352      * Allows client to specify a hint to the provider declaring which collation
    353      * to use when sorting text values.
    354      *
    355      * <p>Providers may support custom collators. When specifying a custom collator
    356      * the value is determined by the Provider.
    357      *
    358      * <li>{@link ContentProvider} implementations: When preparing data in
    359      * {@link ContentProvider#query(Uri, String[], Bundle, CancellationSignal)}, if sort collation
    360      * is reflected in the returned Cursor, it is  strongly recommended that
    361      * {@link #QUERY_ARG_SORT_COLLATION} then be included in the array of honored arguments
    362      * reflected in {@link Cursor} extras {@link Bundle} under {@link #EXTRA_HONORED_ARGS}.
    363      *
    364      * <li>When querying a provider, where no QUERY_ARG_SQL* otherwise exists in the
    365      * arguments {@link Bundle}, the Content framework will attempt to synthesize
    366      * a QUERY_ARG_SQL* argument using the corresponding QUERY_ARG_SORT* values.
    367      *
    368      * @see java.text.Collator#PRIMARY
    369      * @see java.text.Collator#SECONDARY
    370      * @see java.text.Collator#TERTIARY
    371      * @see java.text.Collator#IDENTICAL
    372      */
    373     public static final String QUERY_ARG_SORT_COLLATION = "android:query-arg-sort-collation";
    374 
    375     /**
    376      * Allows provider to report back to client which query keys are honored in a Cursor.
    377      *
    378      * <p>Key identifying a {@code String[]} containing all QUERY_ARG_SORT* arguments
    379      * honored by the provider. Include this in {@link Cursor} extras {@link Bundle}
    380      * when any QUERY_ARG_SORT* value was honored during the preparation of the
    381      * results {@link Cursor}.
    382      *
    383      * <p>If present, ALL honored arguments are enumerated in this extras payload.
    384      *
    385      * @see #QUERY_ARG_SORT_COLUMNS
    386      * @see #QUERY_ARG_SORT_DIRECTION
    387      * @see #QUERY_ARG_SORT_COLLATION
    388      */
    389     public static final String EXTRA_HONORED_ARGS = "android.content.extra.HONORED_ARGS";
    390 
    391     /** @hide */
    392     @IntDef(flag = false, prefix = { "QUERY_SORT_DIRECTION_" }, value = {
    393             QUERY_SORT_DIRECTION_ASCENDING,
    394             QUERY_SORT_DIRECTION_DESCENDING
    395     })
    396     @Retention(RetentionPolicy.SOURCE)
    397     public @interface SortDirection {}
    398     public static final int QUERY_SORT_DIRECTION_ASCENDING = 0;
    399     public static final int QUERY_SORT_DIRECTION_DESCENDING = 1;
    400 
    401     /**
    402      * @see {@link java.text.Collector} for details on respective collation strength.
    403      * @hide
    404      */
    405     @IntDef(flag = false, value = {
    406             java.text.Collator.PRIMARY,
    407             java.text.Collator.SECONDARY,
    408             java.text.Collator.TERTIARY,
    409             java.text.Collator.IDENTICAL
    410     })
    411     @Retention(RetentionPolicy.SOURCE)
    412     public @interface QueryCollator {}
    413 
    414     /**
    415      * Specifies the offset row index within a Cursor.
    416      */
    417     public static final String QUERY_ARG_OFFSET = "android:query-arg-offset";
    418 
    419     /**
    420      * Specifies the max number of rows to include in a Cursor.
    421      */
    422     public static final String QUERY_ARG_LIMIT = "android:query-arg-limit";
    423 
    424     /**
    425      * Added to {@link Cursor} extras {@link Bundle} to indicate total row count of
    426      * recordset when paging is supported. Providers must include this when
    427      * implementing paging support.
    428      *
    429      * <p>A provider may return -1 that row count of the recordset is unknown.
    430      *
    431      * <p>Providers having returned -1 in a previous query are recommended to
    432      * send content change notification once (if) full recordset size becomes
    433      * known.
    434      */
    435     public static final String EXTRA_TOTAL_COUNT = "android.content.extra.TOTAL_COUNT";
    436 
    437     /**
    438      * This is the Android platform's base MIME type for a content: URI
    439      * containing a Cursor of a single item.  Applications should use this
    440      * as the base type along with their own sub-type of their content: URIs
    441      * that represent a particular item.  For example, hypothetical IMAP email
    442      * client may have a URI
    443      * <code>content://com.company.provider.imap/inbox/1</code> for a particular
    444      * message in the inbox, whose MIME type would be reported as
    445      * <code>CURSOR_ITEM_BASE_TYPE + "/vnd.company.imap-msg"</code>
    446      *
    447      * <p>Compare with {@link #CURSOR_DIR_BASE_TYPE}.
    448      */
    449     public static final String CURSOR_ITEM_BASE_TYPE = "vnd.android.cursor.item";
    450 
    451     /**
    452      * This is the Android platform's base MIME type for a content: URI
    453      * containing a Cursor of zero or more items.  Applications should use this
    454      * as the base type along with their own sub-type of their content: URIs
    455      * that represent a directory of items.  For example, hypothetical IMAP email
    456      * client may have a URI
    457      * <code>content://com.company.provider.imap/inbox</code> for all of the
    458      * messages in its inbox, whose MIME type would be reported as
    459      * <code>CURSOR_DIR_BASE_TYPE + "/vnd.company.imap-msg"</code>
    460      *
    461      * <p>Note how the base MIME type varies between this and
    462      * {@link #CURSOR_ITEM_BASE_TYPE} depending on whether there is
    463      * one single item or multiple items in the data set, while the sub-type
    464      * remains the same because in either case the data structure contained
    465      * in the cursor is the same.
    466      */
    467     public static final String CURSOR_DIR_BASE_TYPE = "vnd.android.cursor.dir";
    468 
    469     /**
    470      * This is the Android platform's generic MIME type to match any MIME
    471      * type of the form "{@link #CURSOR_ITEM_BASE_TYPE}/{@code SUB_TYPE}".
    472      * {@code SUB_TYPE} is the sub-type of the application-dependent
    473      * content, e.g., "audio", "video", "playlist".
    474      */
    475     public static final String ANY_CURSOR_ITEM_TYPE = "vnd.android.cursor.item/*";
    476 
    477     /**
    478      * Default MIME type for files whose type is otherwise unknown.
    479      * @hide
    480      */
    481     public static final String MIME_TYPE_DEFAULT = "application/octet-stream";
    482 
    483     /** @hide */
    484     @UnsupportedAppUsage
    485     public static final int SYNC_ERROR_SYNC_ALREADY_IN_PROGRESS = 1;
    486     /** @hide */
    487     public static final int SYNC_ERROR_AUTHENTICATION = 2;
    488     /** @hide */
    489     public static final int SYNC_ERROR_IO = 3;
    490     /** @hide */
    491     public static final int SYNC_ERROR_PARSE = 4;
    492     /** @hide */
    493     public static final int SYNC_ERROR_CONFLICT = 5;
    494     /** @hide */
    495     public static final int SYNC_ERROR_TOO_MANY_DELETIONS = 6;
    496     /** @hide */
    497     public static final int SYNC_ERROR_TOO_MANY_RETRIES = 7;
    498     /** @hide */
    499     public static final int SYNC_ERROR_INTERNAL = 8;
    500 
    501     private static final String[] SYNC_ERROR_NAMES = new String[] {
    502           "already-in-progress",
    503           "authentication-error",
    504           "io-error",
    505           "parse-error",
    506           "conflict",
    507           "too-many-deletions",
    508           "too-many-retries",
    509           "internal-error",
    510     };
    511 
    512     /** @hide */
    513     public static String syncErrorToString(int error) {
    514         if (error < 1 || error > SYNC_ERROR_NAMES.length) {
    515             return String.valueOf(error);
    516         }
    517         return SYNC_ERROR_NAMES[error - 1];
    518     }
    519 
    520     /** @hide */
    521     public static int syncErrorStringToInt(String error) {
    522         for (int i = 0, n = SYNC_ERROR_NAMES.length; i < n; i++) {
    523             if (SYNC_ERROR_NAMES[i].equals(error)) {
    524                 return i + 1;
    525             }
    526         }
    527         if (error != null) {
    528             try {
    529                 return Integer.parseInt(error);
    530             } catch (NumberFormatException e) {
    531                 Log.d(TAG, "error parsing sync error: " + error);
    532             }
    533         }
    534         return 0;
    535     }
    536 
    537     public static final int SYNC_OBSERVER_TYPE_SETTINGS = 1<<0;
    538     public static final int SYNC_OBSERVER_TYPE_PENDING = 1<<1;
    539     public static final int SYNC_OBSERVER_TYPE_ACTIVE = 1<<2;
    540     /** @hide */
    541     @UnsupportedAppUsage
    542     public static final int SYNC_OBSERVER_TYPE_STATUS = 1<<3;
    543     /** @hide */
    544     public static final int SYNC_OBSERVER_TYPE_ALL = 0x7fffffff;
    545 
    546     /** @hide */
    547     @IntDef(flag = true, prefix = { "NOTIFY_" }, value = {
    548             NOTIFY_SYNC_TO_NETWORK,
    549             NOTIFY_SKIP_NOTIFY_FOR_DESCENDANTS
    550     })
    551     @Retention(RetentionPolicy.SOURCE)
    552     public @interface NotifyFlags {}
    553 
    554     /**
    555      * Flag for {@link #notifyChange(Uri, ContentObserver, int)}: attempt to sync the change
    556      * to the network.
    557      */
    558     public static final int NOTIFY_SYNC_TO_NETWORK = 1<<0;
    559 
    560     /**
    561      * Flag for {@link #notifyChange(Uri, ContentObserver, int)}: if set, this notification
    562      * will be skipped if it is being delivered to the root URI of a ContentObserver that is
    563      * using "notify for descendants."  The purpose of this is to allow the provide to send
    564      * a general notification of "something under X" changed that observers of that specific
    565      * URI can receive, while also sending a specific URI under X.  It would use this flag
    566      * when sending the former, so that observers of "X and descendants" only see the latter.
    567      */
    568     public static final int NOTIFY_SKIP_NOTIFY_FOR_DESCENDANTS = 1<<1;
    569 
    570     /**
    571      * No exception, throttled by app standby normally.
    572      * @hide
    573      */
    574     public static final int SYNC_EXEMPTION_NONE = 0;
    575 
    576     /**
    577      * Exemption given to a sync request made by a foreground app (including
    578      * PROCESS_STATE_IMPORTANT_FOREGROUND).
    579      *
    580      * At the schedule time, we promote the sync adapter app for a higher bucket:
    581      * - If the device is not dozing (so the sync will start right away)
    582      *   promote to ACTIVE for 1 hour.
    583      * - If the device is dozing (so the sync *won't* start right away),
    584      * promote to WORKING_SET for 4 hours, so it'll get a higher chance to be started once the
    585      * device comes out of doze.
    586      * - When the sync actually starts, we promote the sync adapter app to ACTIVE for 10 minutes,
    587      * so it can schedule and start more syncs without getting throttled, even when the first
    588      * operation was canceled and now we're retrying.
    589      *
    590      *
    591      * @hide
    592      */
    593     public static final int SYNC_EXEMPTION_PROMOTE_BUCKET = 1;
    594 
    595     /**
    596      * In addition to {@link #SYNC_EXEMPTION_PROMOTE_BUCKET}, we put the sync adapter app in the
    597      * temp whitelist for 10 minutes, so that even RARE apps can run syncs right away.
    598      * @hide
    599      */
    600     public static final int SYNC_EXEMPTION_PROMOTE_BUCKET_WITH_TEMP = 2;
    601 
    602     /** @hide */
    603     @IntDef(flag = false, prefix = { "SYNC_EXEMPTION_" }, value = {
    604             SYNC_EXEMPTION_NONE,
    605             SYNC_EXEMPTION_PROMOTE_BUCKET,
    606             SYNC_EXEMPTION_PROMOTE_BUCKET_WITH_TEMP,
    607     })
    608     @Retention(RetentionPolicy.SOURCE)
    609     public @interface SyncExemption {}
    610 
    611     // Always log queries which take 500ms+; shorter queries are
    612     // sampled accordingly.
    613     private static final boolean ENABLE_CONTENT_SAMPLE = false;
    614     private static final int SLOW_THRESHOLD_MILLIS = 500;
    615     private final Random mRandom = new Random();  // guarded by itself
    616 
    617     public ContentResolver(@Nullable Context context) {
    618         this(context, null);
    619     }
    620 
    621     /** {@hide} */
    622     public ContentResolver(@Nullable Context context, @Nullable ContentInterface wrapped) {
    623         mContext = context != null ? context : ActivityThread.currentApplication();
    624         mPackageName = mContext.getOpPackageName();
    625         mTargetSdkVersion = mContext.getApplicationInfo().targetSdkVersion;
    626         mWrapped = wrapped;
    627     }
    628 
    629     /** {@hide} */
    630     public static @NonNull ContentResolver wrap(@NonNull ContentInterface wrapped) {
    631         Preconditions.checkNotNull(wrapped);
    632 
    633         return new ContentResolver(null, wrapped) {
    634             @Override
    635             public void unstableProviderDied(IContentProvider icp) {
    636                 throw new UnsupportedOperationException();
    637             }
    638             @Override
    639             public boolean releaseUnstableProvider(IContentProvider icp) {
    640                 throw new UnsupportedOperationException();
    641             }
    642             @Override
    643             public boolean releaseProvider(IContentProvider icp) {
    644                 throw new UnsupportedOperationException();
    645             }
    646             @Override
    647             protected IContentProvider acquireUnstableProvider(Context c, String name) {
    648                 throw new UnsupportedOperationException();
    649             }
    650             @Override
    651             protected IContentProvider acquireProvider(Context c, String name) {
    652                 throw new UnsupportedOperationException();
    653             }
    654         };
    655     }
    656 
    657     /**
    658      * Create a {@link ContentResolver} instance that redirects all its methods
    659      * to the given {@link ContentProvider}.
    660      */
    661     public static @NonNull ContentResolver wrap(@NonNull ContentProvider wrapped) {
    662         return wrap((ContentInterface) wrapped);
    663     }
    664 
    665     /**
    666      * Create a {@link ContentResolver} instance that redirects all its methods
    667      * to the given {@link ContentProviderClient}.
    668      */
    669     public static @NonNull ContentResolver wrap(@NonNull ContentProviderClient wrapped) {
    670         return wrap((ContentInterface) wrapped);
    671     }
    672 
    673     /** @hide */
    674     @UnsupportedAppUsage
    675     protected abstract IContentProvider acquireProvider(Context c, String name);
    676 
    677     /**
    678      * Providing a default implementation of this, to avoid having to change a
    679      * lot of other things, but implementations of ContentResolver should
    680      * implement it.
    681      *
    682      * @hide
    683      */
    684     @UnsupportedAppUsage
    685     protected IContentProvider acquireExistingProvider(Context c, String name) {
    686         return acquireProvider(c, name);
    687     }
    688 
    689     /** @hide */
    690     @UnsupportedAppUsage
    691     public abstract boolean releaseProvider(IContentProvider icp);
    692     /** @hide */
    693     @UnsupportedAppUsage
    694     protected abstract IContentProvider acquireUnstableProvider(Context c, String name);
    695     /** @hide */
    696     @UnsupportedAppUsage
    697     public abstract boolean releaseUnstableProvider(IContentProvider icp);
    698     /** @hide */
    699     @UnsupportedAppUsage
    700     public abstract void unstableProviderDied(IContentProvider icp);
    701 
    702     /** @hide */
    703     public void appNotRespondingViaProvider(IContentProvider icp) {
    704         throw new UnsupportedOperationException("appNotRespondingViaProvider");
    705     }
    706 
    707     /**
    708      * Return the MIME type of the given content URL.
    709      *
    710      * @param url A Uri identifying content (either a list or specific type),
    711      * using the content:// scheme.
    712      * @return A MIME type for the content, or null if the URL is invalid or the type is unknown
    713      */
    714     @Override
    715     public final @Nullable String getType(@NonNull Uri url) {
    716         Preconditions.checkNotNull(url, "url");
    717 
    718         try {
    719             if (mWrapped != null) return mWrapped.getType(url);
    720         } catch (RemoteException e) {
    721             return null;
    722         }
    723 
    724         // XXX would like to have an acquireExistingUnstableProvider for this.
    725         IContentProvider provider = acquireExistingProvider(url);
    726         if (provider != null) {
    727             try {
    728                 return provider.getType(url);
    729             } catch (RemoteException e) {
    730                 // Arbitrary and not worth documenting, as Activity
    731                 // Manager will kill this process shortly anyway.
    732                 return null;
    733             } catch (java.lang.Exception e) {
    734                 Log.w(TAG, "Failed to get type for: " + url + " (" + e.getMessage() + ")");
    735                 return null;
    736             } finally {
    737                 releaseProvider(provider);
    738             }
    739         }
    740 
    741         if (!SCHEME_CONTENT.equals(url.getScheme())) {
    742             return null;
    743         }
    744 
    745         try {
    746             String type = ActivityManager.getService().getProviderMimeType(
    747                     ContentProvider.getUriWithoutUserId(url), resolveUserId(url));
    748             return type;
    749         } catch (RemoteException e) {
    750             throw e.rethrowFromSystemServer();
    751         } catch (java.lang.Exception e) {
    752             Log.w(TAG, "Failed to get type for: " + url + " (" + e.getMessage() + ")");
    753             return null;
    754         }
    755     }
    756 
    757     /**
    758      * Query for the possible MIME types for the representations the given
    759      * content URL can be returned when opened as as stream with
    760      * {@link #openTypedAssetFileDescriptor}.  Note that the types here are
    761      * not necessarily a superset of the type returned by {@link #getType} --
    762      * many content providers cannot return a raw stream for the structured
    763      * data that they contain.
    764      *
    765      * @param url A Uri identifying content (either a list or specific type),
    766      * using the content:// scheme.
    767      * @param mimeTypeFilter The desired MIME type.  This may be a pattern,
    768      * such as *&#47;*, to query for all available MIME types that match the
    769      * pattern.
    770      * @return Returns an array of MIME type strings for all available
    771      * data streams that match the given mimeTypeFilter.  If there are none,
    772      * null is returned.
    773      */
    774     @Override
    775     public @Nullable String[] getStreamTypes(@NonNull Uri url, @NonNull String mimeTypeFilter) {
    776         Preconditions.checkNotNull(url, "url");
    777         Preconditions.checkNotNull(mimeTypeFilter, "mimeTypeFilter");
    778 
    779         try {
    780             if (mWrapped != null) return mWrapped.getStreamTypes(url, mimeTypeFilter);
    781         } catch (RemoteException e) {
    782             return null;
    783         }
    784 
    785         IContentProvider provider = acquireProvider(url);
    786         if (provider == null) {
    787             return null;
    788         }
    789 
    790         try {
    791             return provider.getStreamTypes(url, mimeTypeFilter);
    792         } catch (RemoteException e) {
    793             // Arbitrary and not worth documenting, as Activity
    794             // Manager will kill this process shortly anyway.
    795             return null;
    796         } finally {
    797             releaseProvider(provider);
    798         }
    799     }
    800 
    801     /**
    802      * Query the given URI, returning a {@link Cursor} over the result set.
    803      * <p>
    804      * For best performance, the caller should follow these guidelines:
    805      * <ul>
    806      * <li>Provide an explicit projection, to prevent
    807      * reading data from storage that aren't going to be used.</li>
    808      * <li>Use question mark parameter markers such as 'phone=?' instead of
    809      * explicit values in the {@code selection} parameter, so that queries
    810      * that differ only by those values will be recognized as the same
    811      * for caching purposes.</li>
    812      * </ul>
    813      * </p>
    814      *
    815      * @param uri The URI, using the content:// scheme, for the content to
    816      *         retrieve.
    817      * @param projection A list of which columns to return. Passing null will
    818      *         return all columns, which is inefficient.
    819      * @param selection A filter declaring which rows to return, formatted as an
    820      *         SQL WHERE clause (excluding the WHERE itself). Passing null will
    821      *         return all rows for the given URI.
    822      * @param selectionArgs You may include ?s in selection, which will be
    823      *         replaced by the values from selectionArgs, in the order that they
    824      *         appear in the selection. The values will be bound as Strings.
    825      * @param sortOrder How to order the rows, formatted as an SQL ORDER BY
    826      *         clause (excluding the ORDER BY itself). Passing null will use the
    827      *         default sort order, which may be unordered.
    828      * @return A Cursor object, which is positioned before the first entry. May return
    829      *         <code>null</code> if the underlying content provider returns <code>null</code>,
    830      *         or if it crashes.
    831      * @see Cursor
    832      */
    833     public final @Nullable Cursor query(@RequiresPermission.Read @NonNull Uri uri,
    834             @Nullable String[] projection, @Nullable String selection,
    835             @Nullable String[] selectionArgs, @Nullable String sortOrder) {
    836         return query(uri, projection, selection, selectionArgs, sortOrder, null);
    837     }
    838 
    839     /**
    840      * Query the given URI, returning a {@link Cursor} over the result set
    841      * with optional support for cancellation.
    842      * <p>
    843      * For best performance, the caller should follow these guidelines:
    844      * <ul>
    845      * <li>Provide an explicit projection, to prevent
    846      * reading data from storage that aren't going to be used.</li>
    847      * <li>Use question mark parameter markers such as 'phone=?' instead of
    848      * explicit values in the {@code selection} parameter, so that queries
    849      * that differ only by those values will be recognized as the same
    850      * for caching purposes.</li>
    851      * </ul>
    852      * </p>
    853      *
    854      * @param uri The URI, using the content:// scheme, for the content to
    855      *         retrieve.
    856      * @param projection A list of which columns to return. Passing null will
    857      *         return all columns, which is inefficient.
    858      * @param selection A filter declaring which rows to return, formatted as an
    859      *         SQL WHERE clause (excluding the WHERE itself). Passing null will
    860      *         return all rows for the given URI.
    861      * @param selectionArgs You may include ?s in selection, which will be
    862      *         replaced by the values from selectionArgs, in the order that they
    863      *         appear in the selection. The values will be bound as Strings.
    864      * @param sortOrder How to order the rows, formatted as an SQL ORDER BY
    865      *         clause (excluding the ORDER BY itself). Passing null will use the
    866      *         default sort order, which may be unordered.
    867      * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
    868      * If the operation is canceled, then {@link OperationCanceledException} will be thrown
    869      * when the query is executed.
    870      * @return A Cursor object, which is positioned before the first entry. May return
    871      *         <code>null</code> if the underlying content provider returns <code>null</code>,
    872      *         or if it crashes.
    873      * @see Cursor
    874      */
    875     public final @Nullable Cursor query(@RequiresPermission.Read @NonNull Uri uri,
    876             @Nullable String[] projection, @Nullable String selection,
    877             @Nullable String[] selectionArgs, @Nullable String sortOrder,
    878             @Nullable CancellationSignal cancellationSignal) {
    879         Bundle queryArgs = createSqlQueryBundle(selection, selectionArgs, sortOrder);
    880         return query(uri, projection, queryArgs, cancellationSignal);
    881     }
    882 
    883     /**
    884      * Query the given URI, returning a {@link Cursor} over the result set
    885      * with support for cancellation.
    886      *
    887      * <p>For best performance, the caller should follow these guidelines:
    888      *
    889      * <li>Provide an explicit projection, to prevent reading data from storage
    890      * that aren't going to be used.
    891      *
    892      * Provider must identify which QUERY_ARG_SORT* arguments were honored during
    893      * the preparation of the result set by including the respective argument keys
    894      * in the {@link Cursor} extras {@link Bundle}. See {@link #EXTRA_HONORED_ARGS}
    895      * for details.
    896      *
    897      * @see #QUERY_ARG_SORT_COLUMNS
    898      * @see #QUERY_ARG_SORT_DIRECTION
    899      * @see #QUERY_ARG_SORT_COLLATION
    900      *
    901      * @param uri The URI, using the content:// scheme, for the content to
    902      *         retrieve.
    903      * @param projection A list of which columns to return. Passing null will
    904      *         return all columns, which is inefficient.
    905      * @param queryArgs A Bundle containing any arguments to the query.
    906      * @param cancellationSignal A signal to cancel the operation in progress, or null if none.
    907      * If the operation is canceled, then {@link OperationCanceledException} will be thrown
    908      * when the query is executed.
    909      * @return A Cursor object, which is positioned before the first entry. May return
    910      *         <code>null</code> if the underlying content provider returns <code>null</code>,
    911      *         or if it crashes.
    912      * @see Cursor
    913      */
    914     @Override
    915     public final @Nullable Cursor query(final @RequiresPermission.Read @NonNull Uri uri,
    916             @Nullable String[] projection, @Nullable Bundle queryArgs,
    917             @Nullable CancellationSignal cancellationSignal) {
    918         Preconditions.checkNotNull(uri, "uri");
    919 
    920         try {
    921             if (mWrapped != null) {
    922                 return mWrapped.query(uri, projection, queryArgs, cancellationSignal);
    923             }
    924         } catch (RemoteException e) {
    925             return null;
    926         }
    927 
    928         IContentProvider unstableProvider = acquireUnstableProvider(uri);
    929         if (unstableProvider == null) {
    930             return null;
    931         }
    932         IContentProvider stableProvider = null;
    933         Cursor qCursor = null;
    934         try {
    935             long startTime = SystemClock.uptimeMillis();
    936 
    937             ICancellationSignal remoteCancellationSignal = null;
    938             if (cancellationSignal != null) {
    939                 cancellationSignal.throwIfCanceled();
    940                 remoteCancellationSignal = unstableProvider.createCancellationSignal();
    941                 cancellationSignal.setRemote(remoteCancellationSignal);
    942             }
    943             try {
    944                 qCursor = unstableProvider.query(mPackageName, uri, projection,
    945                         queryArgs, remoteCancellationSignal);
    946             } catch (DeadObjectException e) {
    947                 // The remote process has died...  but we only hold an unstable
    948                 // reference though, so we might recover!!!  Let's try!!!!
    949                 // This is exciting!!1!!1!!!!1
    950                 unstableProviderDied(unstableProvider);
    951                 stableProvider = acquireProvider(uri);
    952                 if (stableProvider == null) {
    953                     return null;
    954                 }
    955                 qCursor = stableProvider.query(
    956                         mPackageName, uri, projection, queryArgs, remoteCancellationSignal);
    957             }
    958             if (qCursor == null) {
    959                 return null;
    960             }
    961 
    962             // Force query execution.  Might fail and throw a runtime exception here.
    963             qCursor.getCount();
    964             long durationMillis = SystemClock.uptimeMillis() - startTime;
    965             maybeLogQueryToEventLog(durationMillis, uri, projection, queryArgs);
    966 
    967             // Wrap the cursor object into CursorWrapperInner object.
    968             final IContentProvider provider = (stableProvider != null) ? stableProvider
    969                     : acquireProvider(uri);
    970             final CursorWrapperInner wrapper = new CursorWrapperInner(qCursor, provider);
    971             stableProvider = null;
    972             qCursor = null;
    973             return wrapper;
    974         } catch (RemoteException e) {
    975             // Arbitrary and not worth documenting, as Activity
    976             // Manager will kill this process shortly anyway.
    977             return null;
    978         } finally {
    979             if (qCursor != null) {
    980                 qCursor.close();
    981             }
    982             if (cancellationSignal != null) {
    983                 cancellationSignal.setRemote(null);
    984             }
    985             if (unstableProvider != null) {
    986                 releaseUnstableProvider(unstableProvider);
    987             }
    988             if (stableProvider != null) {
    989                 releaseProvider(stableProvider);
    990             }
    991         }
    992     }
    993 
    994     /** {@hide} */
    995     public final @NonNull Uri canonicalizeOrElse(@NonNull Uri uri) {
    996         final Uri res = canonicalize(uri);
    997         return (res != null) ? res : uri;
    998     }
    999 
   1000     /**
   1001      * Transform the given <var>url</var> to a canonical representation of
   1002      * its referenced resource, which can be used across devices, persisted,
   1003      * backed up and restored, etc.  The returned Uri is still a fully capable
   1004      * Uri for use with its content provider, allowing you to do all of the
   1005      * same content provider operations as with the original Uri --
   1006      * {@link #query}, {@link #openInputStream(android.net.Uri)}, etc.  The
   1007      * only difference in behavior between the original and new Uris is that
   1008      * the content provider may need to do some additional work at each call
   1009      * using it to resolve it to the correct resource, especially if the
   1010      * canonical Uri has been moved to a different environment.
   1011      *
   1012      * <p>If you are moving a canonical Uri between environments, you should
   1013      * perform another call to {@link #canonicalize} with that original Uri to
   1014      * re-canonicalize it for the current environment.  Alternatively, you may
   1015      * want to use {@link #uncanonicalize} to transform it to a non-canonical
   1016      * Uri that works only in the current environment but potentially more
   1017      * efficiently than the canonical representation.</p>
   1018      *
   1019      * @param url The {@link Uri} that is to be transformed to a canonical
   1020      * representation.  Like all resolver calls, the input can be either
   1021      * a non-canonical or canonical Uri.
   1022      *
   1023      * @return Returns the official canonical representation of <var>url</var>,
   1024      * or null if the content provider does not support a canonical representation
   1025      * of the given Uri.  Many providers may not support canonicalization of some
   1026      * or all of their Uris.
   1027      *
   1028      * @see #uncanonicalize
   1029      */
   1030     @Override
   1031     public final @Nullable Uri canonicalize(@NonNull Uri url) {
   1032         Preconditions.checkNotNull(url, "url");
   1033 
   1034         try {
   1035             if (mWrapped != null) return mWrapped.canonicalize(url);
   1036         } catch (RemoteException e) {
   1037             return null;
   1038         }
   1039 
   1040         IContentProvider provider = acquireProvider(url);
   1041         if (provider == null) {
   1042             return null;
   1043         }
   1044 
   1045         try {
   1046             return provider.canonicalize(mPackageName, url);
   1047         } catch (RemoteException e) {
   1048             // Arbitrary and not worth documenting, as Activity
   1049             // Manager will kill this process shortly anyway.
   1050             return null;
   1051         } finally {
   1052             releaseProvider(provider);
   1053         }
   1054     }
   1055 
   1056     /**
   1057      * Given a canonical Uri previously generated by {@link #canonicalize}, convert
   1058      * it to its local non-canonical form.  This can be useful in some cases where
   1059      * you know that you will only be using the Uri in the current environment and
   1060      * want to avoid any possible overhead when using it with the content
   1061      * provider or want to verify that the referenced data exists at all in the
   1062      * new environment.
   1063      *
   1064      * @param url The canonical {@link Uri} that is to be convered back to its
   1065      * non-canonical form.
   1066      *
   1067      * @return Returns the non-canonical representation of <var>url</var>.  This will
   1068      * return null if data identified by the canonical Uri can not be found in
   1069      * the current environment; callers must always check for null and deal with
   1070      * that by appropriately falling back to an alternative.
   1071      *
   1072      * @see #canonicalize
   1073      */
   1074     @Override
   1075     public final @Nullable Uri uncanonicalize(@NonNull Uri url) {
   1076         Preconditions.checkNotNull(url, "url");
   1077 
   1078         try {
   1079             if (mWrapped != null) return mWrapped.uncanonicalize(url);
   1080         } catch (RemoteException e) {
   1081             return null;
   1082         }
   1083 
   1084         IContentProvider provider = acquireProvider(url);
   1085         if (provider == null) {
   1086             return null;
   1087         }
   1088 
   1089         try {
   1090             return provider.uncanonicalize(mPackageName, url);
   1091         } catch (RemoteException e) {
   1092             // Arbitrary and not worth documenting, as Activity
   1093             // Manager will kill this process shortly anyway.
   1094             return null;
   1095         } finally {
   1096             releaseProvider(provider);
   1097         }
   1098     }
   1099 
   1100     /**
   1101      * This allows clients to request an explicit refresh of content identified by {@code uri}.
   1102      * <p>
   1103      * Client code should only invoke this method when there is a strong indication (such as a user
   1104      * initiated pull to refresh gesture) that the content is stale.
   1105      * <p>
   1106      *
   1107      * @param url The Uri identifying the data to refresh.
   1108      * @param args Additional options from the client. The definitions of these are specific to the
   1109      *            content provider being called.
   1110      * @param cancellationSignal A signal to cancel the operation in progress, or {@code null} if
   1111      *            none. For example, if you called refresh on a particular uri, you should call
   1112      *            {@link CancellationSignal#throwIfCanceled()} to check whether the client has
   1113      *            canceled the refresh request.
   1114      * @return true if the provider actually tried refreshing.
   1115      */
   1116     @Override
   1117     public final boolean refresh(@NonNull Uri url, @Nullable Bundle args,
   1118             @Nullable CancellationSignal cancellationSignal) {
   1119         Preconditions.checkNotNull(url, "url");
   1120 
   1121         try {
   1122             if (mWrapped != null) return mWrapped.refresh(url, args, cancellationSignal);
   1123         } catch (RemoteException e) {
   1124             return false;
   1125         }
   1126 
   1127         IContentProvider provider = acquireProvider(url);
   1128         if (provider == null) {
   1129             return false;
   1130         }
   1131 
   1132         try {
   1133             ICancellationSignal remoteCancellationSignal = null;
   1134             if (cancellationSignal != null) {
   1135                 cancellationSignal.throwIfCanceled();
   1136                 remoteCancellationSignal = provider.createCancellationSignal();
   1137                 cancellationSignal.setRemote(remoteCancellationSignal);
   1138             }
   1139             return provider.refresh(mPackageName, url, args, remoteCancellationSignal);
   1140         } catch (RemoteException e) {
   1141             // Arbitrary and not worth documenting, as Activity
   1142             // Manager will kill this process shortly anyway.
   1143             return false;
   1144         } finally {
   1145             releaseProvider(provider);
   1146         }
   1147     }
   1148 
   1149     /**
   1150      * Open a stream on to the content associated with a content URI.  If there
   1151      * is no data associated with the URI, FileNotFoundException is thrown.
   1152      *
   1153      * <h5>Accepts the following URI schemes:</h5>
   1154      * <ul>
   1155      * <li>content ({@link #SCHEME_CONTENT})</li>
   1156      * <li>android.resource ({@link #SCHEME_ANDROID_RESOURCE})</li>
   1157      * <li>file ({@link #SCHEME_FILE})</li>
   1158      * </ul>
   1159      *
   1160      * <p>See {@link #openAssetFileDescriptor(Uri, String)} for more information
   1161      * on these schemes.
   1162      *
   1163      * @param uri The desired URI.
   1164      * @return InputStream
   1165      * @throws FileNotFoundException if the provided URI could not be opened.
   1166      * @see #openAssetFileDescriptor(Uri, String)
   1167      */
   1168     public final @Nullable InputStream openInputStream(@NonNull Uri uri)
   1169             throws FileNotFoundException {
   1170         Preconditions.checkNotNull(uri, "uri");
   1171         String scheme = uri.getScheme();
   1172         if (SCHEME_ANDROID_RESOURCE.equals(scheme)) {
   1173             // Note: left here to avoid breaking compatibility.  May be removed
   1174             // with sufficient testing.
   1175             OpenResourceIdResult r = getResourceId(uri);
   1176             try {
   1177                 InputStream stream = r.r.openRawResource(r.id);
   1178                 return stream;
   1179             } catch (Resources.NotFoundException ex) {
   1180                 throw new FileNotFoundException("Resource does not exist: " + uri);
   1181             }
   1182         } else if (SCHEME_FILE.equals(scheme)) {
   1183             // Note: left here to avoid breaking compatibility.  May be removed
   1184             // with sufficient testing.
   1185             return new FileInputStream(uri.getPath());
   1186         } else {
   1187             AssetFileDescriptor fd = openAssetFileDescriptor(uri, "r", null);
   1188             try {
   1189                 return fd != null ? fd.createInputStream() : null;
   1190             } catch (IOException e) {
   1191                 throw new FileNotFoundException("Unable to create stream");
   1192             }
   1193         }
   1194     }
   1195 
   1196     /**
   1197      * Synonym for {@link #openOutputStream(Uri, String)
   1198      * openOutputStream(uri, "w")}.
   1199      * @throws FileNotFoundException if the provided URI could not be opened.
   1200      */
   1201     public final @Nullable OutputStream openOutputStream(@NonNull Uri uri)
   1202             throws FileNotFoundException {
   1203         return openOutputStream(uri, "w");
   1204     }
   1205 
   1206     /**
   1207      * Open a stream on to the content associated with a content URI.  If there
   1208      * is no data associated with the URI, FileNotFoundException is thrown.
   1209      *
   1210      * <h5>Accepts the following URI schemes:</h5>
   1211      * <ul>
   1212      * <li>content ({@link #SCHEME_CONTENT})</li>
   1213      * <li>file ({@link #SCHEME_FILE})</li>
   1214      * </ul>
   1215      *
   1216      * <p>See {@link #openAssetFileDescriptor(Uri, String)} for more information
   1217      * on these schemes.
   1218      *
   1219      * @param uri The desired URI.
   1220      * @param mode May be "w", "wa", "rw", or "rwt".
   1221      * @return OutputStream
   1222      * @throws FileNotFoundException if the provided URI could not be opened.
   1223      * @see #openAssetFileDescriptor(Uri, String)
   1224      */
   1225     public final @Nullable OutputStream openOutputStream(@NonNull Uri uri, @NonNull String mode)
   1226             throws FileNotFoundException {
   1227         AssetFileDescriptor fd = openAssetFileDescriptor(uri, mode, null);
   1228         try {
   1229             return fd != null ? fd.createOutputStream() : null;
   1230         } catch (IOException e) {
   1231             throw new FileNotFoundException("Unable to create stream");
   1232         }
   1233     }
   1234 
   1235     @Override
   1236     public final @Nullable ParcelFileDescriptor openFile(@NonNull Uri uri, @NonNull String mode,
   1237             @Nullable CancellationSignal signal) throws FileNotFoundException {
   1238         try {
   1239             if (mWrapped != null) return mWrapped.openFile(uri, mode, signal);
   1240         } catch (RemoteException e) {
   1241             return null;
   1242         }
   1243 
   1244         return openFileDescriptor(uri, mode, signal);
   1245     }
   1246 
   1247     /**
   1248      * Open a raw file descriptor to access data under a URI.  This
   1249      * is like {@link #openAssetFileDescriptor(Uri, String)}, but uses the
   1250      * underlying {@link ContentProvider#openFile}
   1251      * ContentProvider.openFile()} method, so will <em>not</em> work with
   1252      * providers that return sub-sections of files.  If at all possible,
   1253      * you should use {@link #openAssetFileDescriptor(Uri, String)}.  You
   1254      * will receive a FileNotFoundException exception if the provider returns a
   1255      * sub-section of a file.
   1256      *
   1257      * <h5>Accepts the following URI schemes:</h5>
   1258      * <ul>
   1259      * <li>content ({@link #SCHEME_CONTENT})</li>
   1260      * <li>file ({@link #SCHEME_FILE})</li>
   1261      * </ul>
   1262      *
   1263      * <p>See {@link #openAssetFileDescriptor(Uri, String)} for more information
   1264      * on these schemes.
   1265      * <p>
   1266      * If opening with the exclusive "r" or "w" modes, the returned
   1267      * ParcelFileDescriptor could be a pipe or socket pair to enable streaming
   1268      * of data. Opening with the "rw" mode implies a file on disk that supports
   1269      * seeking. If possible, always use an exclusive mode to give the underlying
   1270      * {@link ContentProvider} the most flexibility.
   1271      * <p>
   1272      * If you are writing a file, and need to communicate an error to the
   1273      * provider, use {@link ParcelFileDescriptor#closeWithError(String)}.
   1274      *
   1275      * @param uri The desired URI to open.
   1276      * @param mode The file mode to use, as per {@link ContentProvider#openFile
   1277      * ContentProvider.openFile}.
   1278      * @return Returns a new ParcelFileDescriptor pointing to the file.  You
   1279      * own this descriptor and are responsible for closing it when done.
   1280      * @throws FileNotFoundException Throws FileNotFoundException if no
   1281      * file exists under the URI or the mode is invalid.
   1282      * @see #openAssetFileDescriptor(Uri, String)
   1283      */
   1284     public final @Nullable ParcelFileDescriptor openFileDescriptor(@NonNull Uri uri,
   1285             @NonNull String mode) throws FileNotFoundException {
   1286         return openFileDescriptor(uri, mode, null);
   1287     }
   1288 
   1289     /**
   1290      * Open a raw file descriptor to access data under a URI.  This
   1291      * is like {@link #openAssetFileDescriptor(Uri, String)}, but uses the
   1292      * underlying {@link ContentProvider#openFile}
   1293      * ContentProvider.openFile()} method, so will <em>not</em> work with
   1294      * providers that return sub-sections of files.  If at all possible,
   1295      * you should use {@link #openAssetFileDescriptor(Uri, String)}.  You
   1296      * will receive a FileNotFoundException exception if the provider returns a
   1297      * sub-section of a file.
   1298      *
   1299      * <h5>Accepts the following URI schemes:</h5>
   1300      * <ul>
   1301      * <li>content ({@link #SCHEME_CONTENT})</li>
   1302      * <li>file ({@link #SCHEME_FILE})</li>
   1303      * </ul>
   1304      *
   1305      * <p>See {@link #openAssetFileDescriptor(Uri, String)} for more information
   1306      * on these schemes.
   1307      * <p>
   1308      * If opening with the exclusive "r" or "w" modes, the returned
   1309      * ParcelFileDescriptor could be a pipe or socket pair to enable streaming
   1310      * of data. Opening with the "rw" mode implies a file on disk that supports
   1311      * seeking. If possible, always use an exclusive mode to give the underlying
   1312      * {@link ContentProvider} the most flexibility.
   1313      * <p>
   1314      * If you are writing a file, and need to communicate an error to the
   1315      * provider, use {@link ParcelFileDescriptor#closeWithError(String)}.
   1316      *
   1317      * @param uri The desired URI to open.
   1318      * @param mode The file mode to use, as per {@link ContentProvider#openFile
   1319      * ContentProvider.openFile}.
   1320      * @param cancellationSignal A signal to cancel the operation in progress,
   1321      *         or null if none. If the operation is canceled, then
   1322      *         {@link OperationCanceledException} will be thrown.
   1323      * @return Returns a new ParcelFileDescriptor pointing to the file.  You
   1324      * own this descriptor and are responsible for closing it when done.
   1325      * @throws FileNotFoundException Throws FileNotFoundException if no
   1326      * file exists under the URI or the mode is invalid.
   1327      * @see #openAssetFileDescriptor(Uri, String)
   1328      */
   1329     public final @Nullable ParcelFileDescriptor openFileDescriptor(@NonNull Uri uri,
   1330             @NonNull String mode, @Nullable CancellationSignal cancellationSignal)
   1331                     throws FileNotFoundException {
   1332         try {
   1333             if (mWrapped != null) return mWrapped.openFile(uri, mode, cancellationSignal);
   1334         } catch (RemoteException e) {
   1335             return null;
   1336         }
   1337 
   1338         AssetFileDescriptor afd = openAssetFileDescriptor(uri, mode, cancellationSignal);
   1339         if (afd == null) {
   1340             return null;
   1341         }
   1342 
   1343         if (afd.getDeclaredLength() < 0) {
   1344             // This is a full file!
   1345             return afd.getParcelFileDescriptor();
   1346         }
   1347 
   1348         // Client can't handle a sub-section of a file, so close what
   1349         // we got and bail with an exception.
   1350         try {
   1351             afd.close();
   1352         } catch (IOException e) {
   1353         }
   1354 
   1355         throw new FileNotFoundException("Not a whole file");
   1356     }
   1357 
   1358     @Override
   1359     public final @Nullable AssetFileDescriptor openAssetFile(@NonNull Uri uri, @NonNull String mode,
   1360             @Nullable CancellationSignal signal) throws FileNotFoundException {
   1361         try {
   1362             if (mWrapped != null) return mWrapped.openAssetFile(uri, mode, signal);
   1363         } catch (RemoteException e) {
   1364             return null;
   1365         }
   1366 
   1367         return openAssetFileDescriptor(uri, mode, signal);
   1368     }
   1369 
   1370     /**
   1371      * Open a raw file descriptor to access data under a URI.  This
   1372      * interacts with the underlying {@link ContentProvider#openAssetFile}
   1373      * method of the provider associated with the given URI, to retrieve any file stored there.
   1374      *
   1375      * <h5>Accepts the following URI schemes:</h5>
   1376      * <ul>
   1377      * <li>content ({@link #SCHEME_CONTENT})</li>
   1378      * <li>android.resource ({@link #SCHEME_ANDROID_RESOURCE})</li>
   1379      * <li>file ({@link #SCHEME_FILE})</li>
   1380      * </ul>
   1381      * <h5>The android.resource ({@link #SCHEME_ANDROID_RESOURCE}) Scheme</h5>
   1382      * <p>
   1383      * A Uri object can be used to reference a resource in an APK file.  The
   1384      * Uri should be one of the following formats:
   1385      * <ul>
   1386      * <li><code>android.resource://package_name/id_number</code><br/>
   1387      * <code>package_name</code> is your package name as listed in your AndroidManifest.xml.
   1388      * For example <code>com.example.myapp</code><br/>
   1389      * <code>id_number</code> is the int form of the ID.<br/>
   1390      * The easiest way to construct this form is
   1391      * <pre>Uri uri = Uri.parse("android.resource://com.example.myapp/" + R.raw.my_resource");</pre>
   1392      * </li>
   1393      * <li><code>android.resource://package_name/type/name</code><br/>
   1394      * <code>package_name</code> is your package name as listed in your AndroidManifest.xml.
   1395      * For example <code>com.example.myapp</code><br/>
   1396      * <code>type</code> is the string form of the resource type.  For example, <code>raw</code>
   1397      * or <code>drawable</code>.
   1398      * <code>name</code> is the string form of the resource name.  That is, whatever the file
   1399      * name was in your res directory, without the type extension.
   1400      * The easiest way to construct this form is
   1401      * <pre>Uri uri = Uri.parse("android.resource://com.example.myapp/raw/my_resource");</pre>
   1402      * </li>
   1403      * </ul>
   1404      *
   1405      * <p>Note that if this function is called for read-only input (mode is "r")
   1406      * on a content: URI, it will instead call {@link #openTypedAssetFileDescriptor}
   1407      * for you with a MIME type of "*&#47;*".  This allows such callers to benefit
   1408      * from any built-in data conversion that a provider implements.
   1409      *
   1410      * @param uri The desired URI to open.
   1411      * @param mode The file mode to use, as per {@link ContentProvider#openAssetFile
   1412      * ContentProvider.openAssetFile}.
   1413      * @return Returns a new ParcelFileDescriptor pointing to the file.  You
   1414      * own this descriptor and are responsible for closing it when done.
   1415      * @throws FileNotFoundException Throws FileNotFoundException of no
   1416      * file exists under the URI or the mode is invalid.
   1417      */
   1418     public final @Nullable AssetFileDescriptor openAssetFileDescriptor(@NonNull Uri uri,
   1419             @NonNull String mode) throws FileNotFoundException {
   1420         return openAssetFileDescriptor(uri, mode, null);
   1421     }
   1422 
   1423     /**
   1424      * Open a raw file descriptor to access data under a URI.  This
   1425      * interacts with the underlying {@link ContentProvider#openAssetFile}
   1426      * method of the provider associated with the given URI, to retrieve any file stored there.
   1427      *
   1428      * <h5>Accepts the following URI schemes:</h5>
   1429      * <ul>
   1430      * <li>content ({@link #SCHEME_CONTENT})</li>
   1431      * <li>android.resource ({@link #SCHEME_ANDROID_RESOURCE})</li>
   1432      * <li>file ({@link #SCHEME_FILE})</li>
   1433      * </ul>
   1434      * <h5>The android.resource ({@link #SCHEME_ANDROID_RESOURCE}) Scheme</h5>
   1435      * <p>
   1436      * A Uri object can be used to reference a resource in an APK file.  The
   1437      * Uri should be one of the following formats:
   1438      * <ul>
   1439      * <li><code>android.resource://package_name/id_number</code><br/>
   1440      * <code>package_name</code> is your package name as listed in your AndroidManifest.xml.
   1441      * For example <code>com.example.myapp</code><br/>
   1442      * <code>id_number</code> is the int form of the ID.<br/>
   1443      * The easiest way to construct this form is
   1444      * <pre>Uri uri = Uri.parse("android.resource://com.example.myapp/" + R.raw.my_resource");</pre>
   1445      * </li>
   1446      * <li><code>android.resource://package_name/type/name</code><br/>
   1447      * <code>package_name</code> is your package name as listed in your AndroidManifest.xml.
   1448      * For example <code>com.example.myapp</code><br/>
   1449      * <code>type</code> is the string form of the resource type.  For example, <code>raw</code>
   1450      * or <code>drawable</code>.
   1451      * <code>name</code> is the string form of the resource name.  That is, whatever the file
   1452      * name was in your res directory, without the type extension.
   1453      * The easiest way to construct this form is
   1454      * <pre>Uri uri = Uri.parse("android.resource://com.example.myapp/raw/my_resource");</pre>
   1455      * </li>
   1456      * </ul>
   1457      *
   1458      * <p>Note that if this function is called for read-only input (mode is "r")
   1459      * on a content: URI, it will instead call {@link #openTypedAssetFileDescriptor}
   1460      * for you with a MIME type of "*&#47;*".  This allows such callers to benefit
   1461      * from any built-in data conversion that a provider implements.
   1462      *
   1463      * @param uri The desired URI to open.
   1464      * @param mode The file mode to use, as per {@link ContentProvider#openAssetFile
   1465      * ContentProvider.openAssetFile}.
   1466      * @param cancellationSignal A signal to cancel the operation in progress, or null if
   1467      *            none. If the operation is canceled, then
   1468      *            {@link OperationCanceledException} will be thrown.
   1469      * @return Returns a new ParcelFileDescriptor pointing to the file.  You
   1470      * own this descriptor and are responsible for closing it when done.
   1471      * @throws FileNotFoundException Throws FileNotFoundException of no
   1472      * file exists under the URI or the mode is invalid.
   1473      */
   1474     public final @Nullable AssetFileDescriptor openAssetFileDescriptor(@NonNull Uri uri,
   1475             @NonNull String mode, @Nullable CancellationSignal cancellationSignal)
   1476                     throws FileNotFoundException {
   1477         Preconditions.checkNotNull(uri, "uri");
   1478         Preconditions.checkNotNull(mode, "mode");
   1479 
   1480         try {
   1481             if (mWrapped != null) return mWrapped.openAssetFile(uri, mode, cancellationSignal);
   1482         } catch (RemoteException e) {
   1483             return null;
   1484         }
   1485 
   1486         String scheme = uri.getScheme();
   1487         if (SCHEME_ANDROID_RESOURCE.equals(scheme)) {
   1488             if (!"r".equals(mode)) {
   1489                 throw new FileNotFoundException("Can't write resources: " + uri);
   1490             }
   1491             OpenResourceIdResult r = getResourceId(uri);
   1492             try {
   1493                 return r.r.openRawResourceFd(r.id);
   1494             } catch (Resources.NotFoundException ex) {
   1495                 throw new FileNotFoundException("Resource does not exist: " + uri);
   1496             }
   1497         } else if (SCHEME_FILE.equals(scheme)) {
   1498             ParcelFileDescriptor pfd = ParcelFileDescriptor.open(
   1499                     new File(uri.getPath()), ParcelFileDescriptor.parseMode(mode));
   1500             return new AssetFileDescriptor(pfd, 0, -1);
   1501         } else {
   1502             if ("r".equals(mode)) {
   1503                 return openTypedAssetFileDescriptor(uri, "*/*", null, cancellationSignal);
   1504             } else {
   1505                 IContentProvider unstableProvider = acquireUnstableProvider(uri);
   1506                 if (unstableProvider == null) {
   1507                     throw new FileNotFoundException("No content provider: " + uri);
   1508                 }
   1509                 IContentProvider stableProvider = null;
   1510                 AssetFileDescriptor fd = null;
   1511 
   1512                 try {
   1513                     ICancellationSignal remoteCancellationSignal = null;
   1514                     if (cancellationSignal != null) {
   1515                         cancellationSignal.throwIfCanceled();
   1516                         remoteCancellationSignal = unstableProvider.createCancellationSignal();
   1517                         cancellationSignal.setRemote(remoteCancellationSignal);
   1518                     }
   1519 
   1520                     try {
   1521                         fd = unstableProvider.openAssetFile(
   1522                                 mPackageName, uri, mode, remoteCancellationSignal);
   1523                         if (fd == null) {
   1524                             // The provider will be released by the finally{} clause
   1525                             return null;
   1526                         }
   1527                     } catch (DeadObjectException e) {
   1528                         // The remote process has died...  but we only hold an unstable
   1529                         // reference though, so we might recover!!!  Let's try!!!!
   1530                         // This is exciting!!1!!1!!!!1
   1531                         unstableProviderDied(unstableProvider);
   1532                         stableProvider = acquireProvider(uri);
   1533                         if (stableProvider == null) {
   1534                             throw new FileNotFoundException("No content provider: " + uri);
   1535                         }
   1536                         fd = stableProvider.openAssetFile(
   1537                                 mPackageName, uri, mode, remoteCancellationSignal);
   1538                         if (fd == null) {
   1539                             // The provider will be released by the finally{} clause
   1540                             return null;
   1541                         }
   1542                     }
   1543 
   1544                     if (stableProvider == null) {
   1545                         stableProvider = acquireProvider(uri);
   1546                     }
   1547                     releaseUnstableProvider(unstableProvider);
   1548                     unstableProvider = null;
   1549                     ParcelFileDescriptor pfd = new ParcelFileDescriptorInner(
   1550                             fd.getParcelFileDescriptor(), stableProvider);
   1551 
   1552                     // Success!  Don't release the provider when exiting, let
   1553                     // ParcelFileDescriptorInner do that when it is closed.
   1554                     stableProvider = null;
   1555 
   1556                     return new AssetFileDescriptor(pfd, fd.getStartOffset(),
   1557                             fd.getDeclaredLength());
   1558 
   1559                 } catch (RemoteException e) {
   1560                     // Whatever, whatever, we'll go away.
   1561                     throw new FileNotFoundException(
   1562                             "Failed opening content provider: " + uri);
   1563                 } catch (FileNotFoundException e) {
   1564                     throw e;
   1565                 } finally {
   1566                     if (cancellationSignal != null) {
   1567                         cancellationSignal.setRemote(null);
   1568                     }
   1569                     if (stableProvider != null) {
   1570                         releaseProvider(stableProvider);
   1571                     }
   1572                     if (unstableProvider != null) {
   1573                         releaseUnstableProvider(unstableProvider);
   1574                     }
   1575                 }
   1576             }
   1577         }
   1578     }
   1579 
   1580     @Override
   1581     public final @Nullable AssetFileDescriptor openTypedAssetFile(@NonNull Uri uri,
   1582             @NonNull String mimeTypeFilter, @Nullable Bundle opts,
   1583             @Nullable CancellationSignal signal) throws FileNotFoundException {
   1584         try {
   1585             if (mWrapped != null) {
   1586                 return mWrapped.openTypedAssetFile(uri, mimeTypeFilter, opts, signal);
   1587             }
   1588         } catch (RemoteException e) {
   1589             return null;
   1590         }
   1591 
   1592         return openTypedAssetFileDescriptor(uri, mimeTypeFilter, opts, signal);
   1593     }
   1594 
   1595     /**
   1596      * Open a raw file descriptor to access (potentially type transformed)
   1597      * data from a "content:" URI.  This interacts with the underlying
   1598      * {@link ContentProvider#openTypedAssetFile} method of the provider
   1599      * associated with the given URI, to retrieve retrieve any appropriate
   1600      * data stream for the data stored there.
   1601      *
   1602      * <p>Unlike {@link #openAssetFileDescriptor}, this function only works
   1603      * with "content:" URIs, because content providers are the only facility
   1604      * with an associated MIME type to ensure that the returned data stream
   1605      * is of the desired type.
   1606      *
   1607      * <p>All text/* streams are encoded in UTF-8.
   1608      *
   1609      * @param uri The desired URI to open.
   1610      * @param mimeType The desired MIME type of the returned data.  This can
   1611      * be a pattern such as *&#47;*, which will allow the content provider to
   1612      * select a type, though there is no way for you to determine what type
   1613      * it is returning.
   1614      * @param opts Additional provider-dependent options.
   1615      * @return Returns a new ParcelFileDescriptor from which you can read the
   1616      * data stream from the provider.  Note that this may be a pipe, meaning
   1617      * you can't seek in it.  The only seek you should do is if the
   1618      * AssetFileDescriptor contains an offset, to move to that offset before
   1619      * reading.  You own this descriptor and are responsible for closing it when done.
   1620      * @throws FileNotFoundException Throws FileNotFoundException of no
   1621      * data of the desired type exists under the URI.
   1622      */
   1623     public final @Nullable AssetFileDescriptor openTypedAssetFileDescriptor(@NonNull Uri uri,
   1624             @NonNull String mimeType, @Nullable Bundle opts) throws FileNotFoundException {
   1625         return openTypedAssetFileDescriptor(uri, mimeType, opts, null);
   1626     }
   1627 
   1628     /**
   1629      * Open a raw file descriptor to access (potentially type transformed)
   1630      * data from a "content:" URI.  This interacts with the underlying
   1631      * {@link ContentProvider#openTypedAssetFile} method of the provider
   1632      * associated with the given URI, to retrieve retrieve any appropriate
   1633      * data stream for the data stored there.
   1634      *
   1635      * <p>Unlike {@link #openAssetFileDescriptor}, this function only works
   1636      * with "content:" URIs, because content providers are the only facility
   1637      * with an associated MIME type to ensure that the returned data stream
   1638      * is of the desired type.
   1639      *
   1640      * <p>All text/* streams are encoded in UTF-8.
   1641      *
   1642      * @param uri The desired URI to open.
   1643      * @param mimeType The desired MIME type of the returned data.  This can
   1644      * be a pattern such as *&#47;*, which will allow the content provider to
   1645      * select a type, though there is no way for you to determine what type
   1646      * it is returning.
   1647      * @param opts Additional provider-dependent options.
   1648      * @param cancellationSignal A signal to cancel the operation in progress,
   1649      *         or null if none. If the operation is canceled, then
   1650      *         {@link OperationCanceledException} will be thrown.
   1651      * @return Returns a new ParcelFileDescriptor from which you can read the
   1652      * data stream from the provider.  Note that this may be a pipe, meaning
   1653      * you can't seek in it.  The only seek you should do is if the
   1654      * AssetFileDescriptor contains an offset, to move to that offset before
   1655      * reading.  You own this descriptor and are responsible for closing it when done.
   1656      * @throws FileNotFoundException Throws FileNotFoundException of no
   1657      * data of the desired type exists under the URI.
   1658      */
   1659     public final @Nullable AssetFileDescriptor openTypedAssetFileDescriptor(@NonNull Uri uri,
   1660             @NonNull String mimeType, @Nullable Bundle opts,
   1661             @Nullable CancellationSignal cancellationSignal) throws FileNotFoundException {
   1662         Preconditions.checkNotNull(uri, "uri");
   1663         Preconditions.checkNotNull(mimeType, "mimeType");
   1664 
   1665         try {
   1666             if (mWrapped != null) return mWrapped.openTypedAssetFile(uri, mimeType, opts, cancellationSignal);
   1667         } catch (RemoteException e) {
   1668             return null;
   1669         }
   1670 
   1671         IContentProvider unstableProvider = acquireUnstableProvider(uri);
   1672         if (unstableProvider == null) {
   1673             throw new FileNotFoundException("No content provider: " + uri);
   1674         }
   1675         IContentProvider stableProvider = null;
   1676         AssetFileDescriptor fd = null;
   1677 
   1678         try {
   1679             ICancellationSignal remoteCancellationSignal = null;
   1680             if (cancellationSignal != null) {
   1681                 cancellationSignal.throwIfCanceled();
   1682                 remoteCancellationSignal = unstableProvider.createCancellationSignal();
   1683                 cancellationSignal.setRemote(remoteCancellationSignal);
   1684             }
   1685 
   1686             try {
   1687                 fd = unstableProvider.openTypedAssetFile(
   1688                         mPackageName, uri, mimeType, opts, remoteCancellationSignal);
   1689                 if (fd == null) {
   1690                     // The provider will be released by the finally{} clause
   1691                     return null;
   1692                 }
   1693             } catch (DeadObjectException e) {
   1694                 // The remote process has died...  but we only hold an unstable
   1695                 // reference though, so we might recover!!!  Let's try!!!!
   1696                 // This is exciting!!1!!1!!!!1
   1697                 unstableProviderDied(unstableProvider);
   1698                 stableProvider = acquireProvider(uri);
   1699                 if (stableProvider == null) {
   1700                     throw new FileNotFoundException("No content provider: " + uri);
   1701                 }
   1702                 fd = stableProvider.openTypedAssetFile(
   1703                         mPackageName, uri, mimeType, opts, remoteCancellationSignal);
   1704                 if (fd == null) {
   1705                     // The provider will be released by the finally{} clause
   1706                     return null;
   1707                 }
   1708             }
   1709 
   1710             if (stableProvider == null) {
   1711                 stableProvider = acquireProvider(uri);
   1712             }
   1713             releaseUnstableProvider(unstableProvider);
   1714             unstableProvider = null;
   1715             ParcelFileDescriptor pfd = new ParcelFileDescriptorInner(
   1716                     fd.getParcelFileDescriptor(), stableProvider);
   1717 
   1718             // Success!  Don't release the provider when exiting, let
   1719             // ParcelFileDescriptorInner do that when it is closed.
   1720             stableProvider = null;
   1721 
   1722             return new AssetFileDescriptor(pfd, fd.getStartOffset(),
   1723                     fd.getDeclaredLength());
   1724 
   1725         } catch (RemoteException e) {
   1726             // Whatever, whatever, we'll go away.
   1727             throw new FileNotFoundException(
   1728                     "Failed opening content provider: " + uri);
   1729         } catch (FileNotFoundException e) {
   1730             throw e;
   1731         } finally {
   1732             if (cancellationSignal != null) {
   1733                 cancellationSignal.setRemote(null);
   1734             }
   1735             if (stableProvider != null) {
   1736                 releaseProvider(stableProvider);
   1737             }
   1738             if (unstableProvider != null) {
   1739                 releaseUnstableProvider(unstableProvider);
   1740             }
   1741         }
   1742     }
   1743 
   1744     /**
   1745      * A resource identified by the {@link Resources} that contains it, and a resource id.
   1746      *
   1747      * @hide
   1748      */
   1749     public class OpenResourceIdResult {
   1750         @UnsupportedAppUsage
   1751         public Resources r;
   1752         @UnsupportedAppUsage
   1753         public int id;
   1754     }
   1755 
   1756     /**
   1757      * Resolves an android.resource URI to a {@link Resources} and a resource id.
   1758      *
   1759      * @hide
   1760      */
   1761     @UnsupportedAppUsage
   1762     public OpenResourceIdResult getResourceId(Uri uri) throws FileNotFoundException {
   1763         String authority = uri.getAuthority();
   1764         Resources r;
   1765         if (TextUtils.isEmpty(authority)) {
   1766             throw new FileNotFoundException("No authority: " + uri);
   1767         } else {
   1768             try {
   1769                 r = mContext.getPackageManager().getResourcesForApplication(authority);
   1770             } catch (NameNotFoundException ex) {
   1771                 throw new FileNotFoundException("No package found for authority: " + uri);
   1772             }
   1773         }
   1774         List<String> path = uri.getPathSegments();
   1775         if (path == null) {
   1776             throw new FileNotFoundException("No path: " + uri);
   1777         }
   1778         int len = path.size();
   1779         int id;
   1780         if (len == 1) {
   1781             try {
   1782                 id = Integer.parseInt(path.get(0));
   1783             } catch (NumberFormatException e) {
   1784                 throw new FileNotFoundException("Single path segment is not a resource ID: " + uri);
   1785             }
   1786         } else if (len == 2) {
   1787             id = r.getIdentifier(path.get(1), path.get(0), authority);
   1788         } else {
   1789             throw new FileNotFoundException("More than two path segments: " + uri);
   1790         }
   1791         if (id == 0) {
   1792             throw new FileNotFoundException("No resource found for: " + uri);
   1793         }
   1794         OpenResourceIdResult res = new OpenResourceIdResult();
   1795         res.r = r;
   1796         res.id = id;
   1797         return res;
   1798     }
   1799 
   1800     /**
   1801      * Inserts a row into a table at the given URL.
   1802      *
   1803      * If the content provider supports transactions the insertion will be atomic.
   1804      *
   1805      * @param url The URL of the table to insert into.
   1806      * @param values The initial values for the newly inserted row. The key is the column name for
   1807      *               the field. Passing an empty ContentValues will create an empty row.
   1808      * @return the URL of the newly created row. May return <code>null</code> if the underlying
   1809      *         content provider returns <code>null</code>, or if it crashes.
   1810      */
   1811     @Override
   1812     public final @Nullable Uri insert(@RequiresPermission.Write @NonNull Uri url,
   1813                 @Nullable ContentValues values) {
   1814         Preconditions.checkNotNull(url, "url");
   1815 
   1816         try {
   1817             if (mWrapped != null) return mWrapped.insert(url, values);
   1818         } catch (RemoteException e) {
   1819             return null;
   1820         }
   1821 
   1822         IContentProvider provider = acquireProvider(url);
   1823         if (provider == null) {
   1824             throw new IllegalArgumentException("Unknown URL " + url);
   1825         }
   1826         try {
   1827             long startTime = SystemClock.uptimeMillis();
   1828             Uri createdRow = provider.insert(mPackageName, url, values);
   1829             long durationMillis = SystemClock.uptimeMillis() - startTime;
   1830             maybeLogUpdateToEventLog(durationMillis, url, "insert", null /* where */);
   1831             return createdRow;
   1832         } catch (RemoteException e) {
   1833             // Arbitrary and not worth documenting, as Activity
   1834             // Manager will kill this process shortly anyway.
   1835             return null;
   1836         } finally {
   1837             releaseProvider(provider);
   1838         }
   1839     }
   1840 
   1841     /**
   1842      * Applies each of the {@link ContentProviderOperation} objects and returns an array
   1843      * of their results. Passes through OperationApplicationException, which may be thrown
   1844      * by the call to {@link ContentProviderOperation#apply}.
   1845      * If all the applications succeed then a {@link ContentProviderResult} array with the
   1846      * same number of elements as the operations will be returned. It is implementation-specific
   1847      * how many, if any, operations will have been successfully applied if a call to
   1848      * apply results in a {@link OperationApplicationException}.
   1849      * @param authority the authority of the ContentProvider to which this batch should be applied
   1850      * @param operations the operations to apply
   1851      * @return the results of the applications
   1852      * @throws OperationApplicationException thrown if an application fails.
   1853      * See {@link ContentProviderOperation#apply} for more information.
   1854      * @throws RemoteException thrown if a RemoteException is encountered while attempting
   1855      *   to communicate with a remote provider.
   1856      */
   1857     @Override
   1858     public @NonNull ContentProviderResult[] applyBatch(@NonNull String authority,
   1859             @NonNull ArrayList<ContentProviderOperation> operations)
   1860                     throws RemoteException, OperationApplicationException {
   1861         Preconditions.checkNotNull(authority, "authority");
   1862         Preconditions.checkNotNull(operations, "operations");
   1863 
   1864         try {
   1865             if (mWrapped != null) return mWrapped.applyBatch(authority, operations);
   1866         } catch (RemoteException e) {
   1867             return null;
   1868         }
   1869 
   1870         ContentProviderClient provider = acquireContentProviderClient(authority);
   1871         if (provider == null) {
   1872             throw new IllegalArgumentException("Unknown authority " + authority);
   1873         }
   1874         try {
   1875             return provider.applyBatch(operations);
   1876         } finally {
   1877             provider.release();
   1878         }
   1879     }
   1880 
   1881     /**
   1882      * Inserts multiple rows into a table at the given URL.
   1883      *
   1884      * This function make no guarantees about the atomicity of the insertions.
   1885      *
   1886      * @param url The URL of the table to insert into.
   1887      * @param values The initial values for the newly inserted rows. The key is the column name for
   1888      *               the field. Passing null will create an empty row.
   1889      * @return the number of newly created rows.
   1890      */
   1891     @Override
   1892     public final int bulkInsert(@RequiresPermission.Write @NonNull Uri url,
   1893                 @NonNull ContentValues[] values) {
   1894         Preconditions.checkNotNull(url, "url");
   1895         Preconditions.checkNotNull(values, "values");
   1896 
   1897         try {
   1898             if (mWrapped != null) return mWrapped.bulkInsert(url, values);
   1899         } catch (RemoteException e) {
   1900             return 0;
   1901         }
   1902 
   1903         IContentProvider provider = acquireProvider(url);
   1904         if (provider == null) {
   1905             throw new IllegalArgumentException("Unknown URL " + url);
   1906         }
   1907         try {
   1908             long startTime = SystemClock.uptimeMillis();
   1909             int rowsCreated = provider.bulkInsert(mPackageName, url, values);
   1910             long durationMillis = SystemClock.uptimeMillis() - startTime;
   1911             maybeLogUpdateToEventLog(durationMillis, url, "bulkinsert", null /* where */);
   1912             return rowsCreated;
   1913         } catch (RemoteException e) {
   1914             // Arbitrary and not worth documenting, as Activity
   1915             // Manager will kill this process shortly anyway.
   1916             return 0;
   1917         } finally {
   1918             releaseProvider(provider);
   1919         }
   1920     }
   1921 
   1922     /**
   1923      * Deletes row(s) specified by a content URI.
   1924      *
   1925      * If the content provider supports transactions, the deletion will be atomic.
   1926      *
   1927      * @param url The URL of the row to delete.
   1928      * @param where A filter to apply to rows before deleting, formatted as an SQL WHERE clause
   1929                     (excluding the WHERE itself).
   1930      * @return The number of rows deleted.
   1931      */
   1932     @Override
   1933     public final int delete(@RequiresPermission.Write @NonNull Uri url, @Nullable String where,
   1934             @Nullable String[] selectionArgs) {
   1935         Preconditions.checkNotNull(url, "url");
   1936 
   1937         try {
   1938             if (mWrapped != null) return mWrapped.delete(url, where, selectionArgs);
   1939         } catch (RemoteException e) {
   1940             return 0;
   1941         }
   1942 
   1943         IContentProvider provider = acquireProvider(url);
   1944         if (provider == null) {
   1945             throw new IllegalArgumentException("Unknown URL " + url);
   1946         }
   1947         try {
   1948             long startTime = SystemClock.uptimeMillis();
   1949             int rowsDeleted = provider.delete(mPackageName, url, where, selectionArgs);
   1950             long durationMillis = SystemClock.uptimeMillis() - startTime;
   1951             maybeLogUpdateToEventLog(durationMillis, url, "delete", where);
   1952             return rowsDeleted;
   1953         } catch (RemoteException e) {
   1954             // Arbitrary and not worth documenting, as Activity
   1955             // Manager will kill this process shortly anyway.
   1956             return -1;
   1957         } finally {
   1958             releaseProvider(provider);
   1959         }
   1960     }
   1961 
   1962     /**
   1963      * Update row(s) in a content URI.
   1964      *
   1965      * If the content provider supports transactions the update will be atomic.
   1966      *
   1967      * @param uri The URI to modify.
   1968      * @param values The new field values. The key is the column name for the field.
   1969                      A null value will remove an existing field value.
   1970      * @param where A filter to apply to rows before updating, formatted as an SQL WHERE clause
   1971                     (excluding the WHERE itself).
   1972      * @return the number of rows updated.
   1973      * @throws NullPointerException if uri or values are null
   1974      */
   1975     @Override
   1976     public final int update(@RequiresPermission.Write @NonNull Uri uri,
   1977             @Nullable ContentValues values, @Nullable String where,
   1978             @Nullable String[] selectionArgs) {
   1979         Preconditions.checkNotNull(uri, "uri");
   1980 
   1981         try {
   1982             if (mWrapped != null) return mWrapped.update(uri, values, where, selectionArgs);
   1983         } catch (RemoteException e) {
   1984             return 0;
   1985         }
   1986 
   1987         IContentProvider provider = acquireProvider(uri);
   1988         if (provider == null) {
   1989             throw new IllegalArgumentException("Unknown URI " + uri);
   1990         }
   1991         try {
   1992             long startTime = SystemClock.uptimeMillis();
   1993             int rowsUpdated = provider.update(mPackageName, uri, values, where, selectionArgs);
   1994             long durationMillis = SystemClock.uptimeMillis() - startTime;
   1995             maybeLogUpdateToEventLog(durationMillis, uri, "update", where);
   1996             return rowsUpdated;
   1997         } catch (RemoteException e) {
   1998             // Arbitrary and not worth documenting, as Activity
   1999             // Manager will kill this process shortly anyway.
   2000             return -1;
   2001         } finally {
   2002             releaseProvider(provider);
   2003         }
   2004     }
   2005 
   2006     /**
   2007      * Call a provider-defined method.  This can be used to implement
   2008      * read or write interfaces which are cheaper than using a Cursor and/or
   2009      * do not fit into the traditional table model.
   2010      *
   2011      * @param method provider-defined method name to call.  Opaque to
   2012      *   framework, but must be non-null.
   2013      * @param arg provider-defined String argument.  May be null.
   2014      * @param extras provider-defined Bundle argument.  May be null.
   2015      * @return a result Bundle, possibly null.  Will be null if the ContentProvider
   2016      *   does not implement call.
   2017      * @throws NullPointerException if uri or method is null
   2018      * @throws IllegalArgumentException if uri is not known
   2019      */
   2020     public final @Nullable Bundle call(@NonNull Uri uri, @NonNull String method,
   2021             @Nullable String arg, @Nullable Bundle extras) {
   2022         return call(uri.getAuthority(), method, arg, extras);
   2023     }
   2024 
   2025     @Override
   2026     public final @Nullable Bundle call(@NonNull String authority, @NonNull String method,
   2027             @Nullable String arg, @Nullable Bundle extras) {
   2028         Preconditions.checkNotNull(authority, "authority");
   2029         Preconditions.checkNotNull(method, "method");
   2030 
   2031         try {
   2032             if (mWrapped != null) return mWrapped.call(authority, method, arg, extras);
   2033         } catch (RemoteException e) {
   2034             return null;
   2035         }
   2036 
   2037         IContentProvider provider = acquireProvider(authority);
   2038         if (provider == null) {
   2039             throw new IllegalArgumentException("Unknown authority " + authority);
   2040         }
   2041         try {
   2042             final Bundle res = provider.call(mPackageName, authority, method, arg, extras);
   2043             Bundle.setDefusable(res, true);
   2044             return res;
   2045         } catch (RemoteException e) {
   2046             // Arbitrary and not worth documenting, as Activity
   2047             // Manager will kill this process shortly anyway.
   2048             return null;
   2049         } finally {
   2050             releaseProvider(provider);
   2051         }
   2052     }
   2053 
   2054     /**
   2055      * Returns the content provider for the given content URI.
   2056      *
   2057      * @param uri The URI to a content provider
   2058      * @return The ContentProvider for the given URI, or null if no content provider is found.
   2059      * @hide
   2060      */
   2061     @UnsupportedAppUsage
   2062     public final IContentProvider acquireProvider(Uri uri) {
   2063         if (!SCHEME_CONTENT.equals(uri.getScheme())) {
   2064             return null;
   2065         }
   2066         final String auth = uri.getAuthority();
   2067         if (auth != null) {
   2068             return acquireProvider(mContext, auth);
   2069         }
   2070         return null;
   2071     }
   2072 
   2073     /**
   2074      * Returns the content provider for the given content URI if the process
   2075      * already has a reference on it.
   2076      *
   2077      * @param uri The URI to a content provider
   2078      * @return The ContentProvider for the given URI, or null if no content provider is found.
   2079      * @hide
   2080      */
   2081     @UnsupportedAppUsage
   2082     public final IContentProvider acquireExistingProvider(Uri uri) {
   2083         if (!SCHEME_CONTENT.equals(uri.getScheme())) {
   2084             return null;
   2085         }
   2086         final String auth = uri.getAuthority();
   2087         if (auth != null) {
   2088             return acquireExistingProvider(mContext, auth);
   2089         }
   2090         return null;
   2091     }
   2092 
   2093     /**
   2094      * @hide
   2095      */
   2096     @UnsupportedAppUsage
   2097     public final IContentProvider acquireProvider(String name) {
   2098         if (name == null) {
   2099             return null;
   2100         }
   2101         return acquireProvider(mContext, name);
   2102     }
   2103 
   2104     /**
   2105      * Returns the content provider for the given content URI.
   2106      *
   2107      * @param uri The URI to a content provider
   2108      * @return The ContentProvider for the given URI, or null if no content provider is found.
   2109      * @hide
   2110      */
   2111     public final IContentProvider acquireUnstableProvider(Uri uri) {
   2112         if (!SCHEME_CONTENT.equals(uri.getScheme())) {
   2113             return null;
   2114         }
   2115         String auth = uri.getAuthority();
   2116         if (auth != null) {
   2117             return acquireUnstableProvider(mContext, uri.getAuthority());
   2118         }
   2119         return null;
   2120     }
   2121 
   2122     /**
   2123      * @hide
   2124      */
   2125     @UnsupportedAppUsage
   2126     public final IContentProvider acquireUnstableProvider(String name) {
   2127         if (name == null) {
   2128             return null;
   2129         }
   2130         return acquireUnstableProvider(mContext, name);
   2131     }
   2132 
   2133     /**
   2134      * Returns a {@link ContentProviderClient} that is associated with the {@link ContentProvider}
   2135      * that services the content at uri, starting the provider if necessary. Returns
   2136      * null if there is no provider associated wih the uri. The caller must indicate that they are
   2137      * done with the provider by calling {@link ContentProviderClient#release} which will allow
   2138      * the system to release the provider if it determines that there is no other reason for
   2139      * keeping it active.
   2140      * @param uri specifies which provider should be acquired
   2141      * @return a {@link ContentProviderClient} that is associated with the {@link ContentProvider}
   2142      * that services the content at uri or null if there isn't one.
   2143      */
   2144     public final @Nullable ContentProviderClient acquireContentProviderClient(@NonNull Uri uri) {
   2145         Preconditions.checkNotNull(uri, "uri");
   2146         IContentProvider provider = acquireProvider(uri);
   2147         if (provider != null) {
   2148             return new ContentProviderClient(this, provider, uri.getAuthority(), true);
   2149         }
   2150         return null;
   2151     }
   2152 
   2153     /**
   2154      * Returns a {@link ContentProviderClient} that is associated with the {@link ContentProvider}
   2155      * with the authority of name, starting the provider if necessary. Returns
   2156      * null if there is no provider associated wih the uri. The caller must indicate that they are
   2157      * done with the provider by calling {@link ContentProviderClient#release} which will allow
   2158      * the system to release the provider if it determines that there is no other reason for
   2159      * keeping it active.
   2160      * @param name specifies which provider should be acquired
   2161      * @return a {@link ContentProviderClient} that is associated with the {@link ContentProvider}
   2162      * with the authority of name or null if there isn't one.
   2163      */
   2164     public final @Nullable ContentProviderClient acquireContentProviderClient(
   2165             @NonNull String name) {
   2166         Preconditions.checkNotNull(name, "name");
   2167         IContentProvider provider = acquireProvider(name);
   2168         if (provider != null) {
   2169             return new ContentProviderClient(this, provider, name, true);
   2170         }
   2171 
   2172         return null;
   2173     }
   2174 
   2175     /**
   2176      * Like {@link #acquireContentProviderClient(Uri)}, but for use when you do
   2177      * not trust the stability of the target content provider.  This turns off
   2178      * the mechanism in the platform clean up processes that are dependent on
   2179      * a content provider if that content provider's process goes away.  Normally
   2180      * you can safely assume that once you have acquired a provider, you can freely
   2181      * use it as needed and it won't disappear, even if your process is in the
   2182      * background.  If using this method, you need to take care to deal with any
   2183      * failures when communicating with the provider, and be sure to close it
   2184      * so that it can be re-opened later.  In particular, catching a
   2185      * {@link android.os.DeadObjectException} from the calls there will let you
   2186      * know that the content provider has gone away; at that point the current
   2187      * ContentProviderClient object is invalid, and you should release it.  You
   2188      * can acquire a new one if you would like to try to restart the provider
   2189      * and perform new operations on it.
   2190      */
   2191     public final @Nullable ContentProviderClient acquireUnstableContentProviderClient(
   2192             @NonNull Uri uri) {
   2193         Preconditions.checkNotNull(uri, "uri");
   2194         IContentProvider provider = acquireUnstableProvider(uri);
   2195         if (provider != null) {
   2196             return new ContentProviderClient(this, provider, uri.getAuthority(), false);
   2197         }
   2198 
   2199         return null;
   2200     }
   2201 
   2202     /**
   2203      * Like {@link #acquireContentProviderClient(String)}, but for use when you do
   2204      * not trust the stability of the target content provider.  This turns off
   2205      * the mechanism in the platform clean up processes that are dependent on
   2206      * a content provider if that content provider's process goes away.  Normally
   2207      * you can safely assume that once you have acquired a provider, you can freely
   2208      * use it as needed and it won't disappear, even if your process is in the
   2209      * background.  If using this method, you need to take care to deal with any
   2210      * failures when communicating with the provider, and be sure to close it
   2211      * so that it can be re-opened later.  In particular, catching a
   2212      * {@link android.os.DeadObjectException} from the calls there will let you
   2213      * know that the content provider has gone away; at that point the current
   2214      * ContentProviderClient object is invalid, and you should release it.  You
   2215      * can acquire a new one if you would like to try to restart the provider
   2216      * and perform new operations on it.
   2217      */
   2218     public final @Nullable ContentProviderClient acquireUnstableContentProviderClient(
   2219             @NonNull String name) {
   2220         Preconditions.checkNotNull(name, "name");
   2221         IContentProvider provider = acquireUnstableProvider(name);
   2222         if (provider != null) {
   2223             return new ContentProviderClient(this, provider, name, false);
   2224         }
   2225 
   2226         return null;
   2227     }
   2228 
   2229     /**
   2230      * Register an observer class that gets callbacks when data identified by a
   2231      * given content URI changes.
   2232      * <p>
   2233      * Starting in {@link android.os.Build.VERSION_CODES#O}, all content
   2234      * notifications must be backed by a valid {@link ContentProvider}.
   2235      *
   2236      * @param uri The URI to watch for changes. This can be a specific row URI,
   2237      *            or a base URI for a whole class of content.
   2238      * @param notifyForDescendants When false, the observer will be notified
   2239      *            whenever a change occurs to the exact URI specified by
   2240      *            <code>uri</code> or to one of the URI's ancestors in the path
   2241      *            hierarchy. When true, the observer will also be notified
   2242      *            whenever a change occurs to the URI's descendants in the path
   2243      *            hierarchy.
   2244      * @param observer The object that receives callbacks when changes occur.
   2245      * @see #unregisterContentObserver
   2246      */
   2247     public final void registerContentObserver(@NonNull Uri uri, boolean notifyForDescendants,
   2248             @NonNull ContentObserver observer) {
   2249         Preconditions.checkNotNull(uri, "uri");
   2250         Preconditions.checkNotNull(observer, "observer");
   2251         registerContentObserver(
   2252                 ContentProvider.getUriWithoutUserId(uri),
   2253                 notifyForDescendants,
   2254                 observer,
   2255                 ContentProvider.getUserIdFromUri(uri, mContext.getUserId()));
   2256     }
   2257 
   2258     /** @hide - designated user version */
   2259     @UnsupportedAppUsage
   2260     public final void registerContentObserver(Uri uri, boolean notifyForDescendents,
   2261             ContentObserver observer, @UserIdInt int userHandle) {
   2262         try {
   2263             getContentService().registerContentObserver(uri, notifyForDescendents,
   2264                     observer.getContentObserver(), userHandle, mTargetSdkVersion);
   2265         } catch (RemoteException e) {
   2266             throw e.rethrowFromSystemServer();
   2267         }
   2268     }
   2269 
   2270     /**
   2271      * Unregisters a change observer.
   2272      *
   2273      * @param observer The previously registered observer that is no longer needed.
   2274      * @see #registerContentObserver
   2275      */
   2276     public final void unregisterContentObserver(@NonNull ContentObserver observer) {
   2277         Preconditions.checkNotNull(observer, "observer");
   2278         try {
   2279             IContentObserver contentObserver = observer.releaseContentObserver();
   2280             if (contentObserver != null) {
   2281                 getContentService().unregisterContentObserver(
   2282                         contentObserver);
   2283             }
   2284         } catch (RemoteException e) {
   2285             throw e.rethrowFromSystemServer();
   2286         }
   2287     }
   2288 
   2289     /**
   2290      * Notify registered observers that a row was updated and attempt to sync
   2291      * changes to the network.
   2292      * <p>
   2293      * To observe events sent through this call, use
   2294      * {@link #registerContentObserver(Uri, boolean, ContentObserver)}.
   2295      * <p>
   2296      * Starting in {@link android.os.Build.VERSION_CODES#O}, all content
   2297      * notifications must be backed by a valid {@link ContentProvider}.
   2298      *
   2299      * @param uri The uri of the content that was changed.
   2300      * @param observer The observer that originated the change, may be
   2301      *            <code>null</null>. The observer that originated the change
   2302      *            will only receive the notification if it has requested to
   2303      *            receive self-change notifications by implementing
   2304      *            {@link ContentObserver#deliverSelfNotifications()} to return
   2305      *            true.
   2306      */
   2307     public void notifyChange(@NonNull Uri uri, @Nullable ContentObserver observer) {
   2308         notifyChange(uri, observer, true /* sync to network */);
   2309     }
   2310 
   2311     /**
   2312      * Notify registered observers that a row was updated.
   2313      * <p>
   2314      * To observe events sent through this call, use
   2315      * {@link #registerContentObserver(Uri, boolean, ContentObserver)}.
   2316      * <p>
   2317      * If syncToNetwork is true, this will attempt to schedule a local sync
   2318      * using the sync adapter that's registered for the authority of the
   2319      * provided uri. No account will be passed to the sync adapter, so all
   2320      * matching accounts will be synchronized.
   2321      * <p>
   2322      * Starting in {@link android.os.Build.VERSION_CODES#O}, all content
   2323      * notifications must be backed by a valid {@link ContentProvider}.
   2324      *
   2325      * @param uri The uri of the content that was changed.
   2326      * @param observer The observer that originated the change, may be
   2327      *            <code>null</null>. The observer that originated the change
   2328      *            will only receive the notification if it has requested to
   2329      *            receive self-change notifications by implementing
   2330      *            {@link ContentObserver#deliverSelfNotifications()} to return
   2331      *            true.
   2332      * @param syncToNetwork If true, same as {@link #NOTIFY_SYNC_TO_NETWORK}.
   2333      * @see #requestSync(android.accounts.Account, String, android.os.Bundle)
   2334      */
   2335     public void notifyChange(@NonNull Uri uri, @Nullable ContentObserver observer,
   2336             boolean syncToNetwork) {
   2337         Preconditions.checkNotNull(uri, "uri");
   2338         notifyChange(
   2339                 ContentProvider.getUriWithoutUserId(uri),
   2340                 observer,
   2341                 syncToNetwork,
   2342                 ContentProvider.getUserIdFromUri(uri, mContext.getUserId()));
   2343     }
   2344 
   2345     /**
   2346      * Notify registered observers that a row was updated.
   2347      * <p>
   2348      * To observe events sent through this call, use
   2349      * {@link #registerContentObserver(Uri, boolean, ContentObserver)}.
   2350      * <p>
   2351      * If syncToNetwork is true, this will attempt to schedule a local sync
   2352      * using the sync adapter that's registered for the authority of the
   2353      * provided uri. No account will be passed to the sync adapter, so all
   2354      * matching accounts will be synchronized.
   2355      * <p>
   2356      * Starting in {@link android.os.Build.VERSION_CODES#O}, all content
   2357      * notifications must be backed by a valid {@link ContentProvider}.
   2358      *
   2359      * @param uri The uri of the content that was changed.
   2360      * @param observer The observer that originated the change, may be
   2361      *            <code>null</null>. The observer that originated the change
   2362      *            will only receive the notification if it has requested to
   2363      *            receive self-change notifications by implementing
   2364      *            {@link ContentObserver#deliverSelfNotifications()} to return
   2365      *            true.
   2366      * @param flags Additional flags: {@link #NOTIFY_SYNC_TO_NETWORK}.
   2367      * @see #requestSync(android.accounts.Account, String, android.os.Bundle)
   2368      */
   2369     public void notifyChange(@NonNull Uri uri, @Nullable ContentObserver observer,
   2370             @NotifyFlags int flags) {
   2371         Preconditions.checkNotNull(uri, "uri");
   2372         notifyChange(
   2373                 ContentProvider.getUriWithoutUserId(uri),
   2374                 observer,
   2375                 flags,
   2376                 ContentProvider.getUserIdFromUri(uri, mContext.getUserId()));
   2377     }
   2378 
   2379     /**
   2380      * Notify registered observers within the designated user(s) that a row was updated.
   2381      *
   2382      * @hide
   2383      */
   2384     public void notifyChange(@NonNull Uri uri, ContentObserver observer, boolean syncToNetwork,
   2385             @UserIdInt int userHandle) {
   2386         try {
   2387             getContentService().notifyChange(
   2388                     uri, observer == null ? null : observer.getContentObserver(),
   2389                     observer != null && observer.deliverSelfNotifications(),
   2390                     syncToNetwork ? NOTIFY_SYNC_TO_NETWORK : 0,
   2391                     userHandle, mTargetSdkVersion, mContext.getPackageName());
   2392         } catch (RemoteException e) {
   2393             throw e.rethrowFromSystemServer();
   2394         }
   2395     }
   2396 
   2397     /**
   2398      * Notify registered observers within the designated user(s) that a row was updated.
   2399      *
   2400      * @hide
   2401      */
   2402     public void notifyChange(@NonNull Uri uri, ContentObserver observer, @NotifyFlags int flags,
   2403             @UserIdInt int userHandle) {
   2404         try {
   2405             getContentService().notifyChange(
   2406                     uri, observer == null ? null : observer.getContentObserver(),
   2407                     observer != null && observer.deliverSelfNotifications(), flags,
   2408                     userHandle, mTargetSdkVersion, mContext.getPackageName());
   2409         } catch (RemoteException e) {
   2410             throw e.rethrowFromSystemServer();
   2411         }
   2412     }
   2413 
   2414     /**
   2415      * Take a persistable URI permission grant that has been offered. Once
   2416      * taken, the permission grant will be remembered across device reboots.
   2417      * Only URI permissions granted with
   2418      * {@link Intent#FLAG_GRANT_PERSISTABLE_URI_PERMISSION} can be persisted. If
   2419      * the grant has already been persisted, taking it again will touch
   2420      * {@link UriPermission#getPersistedTime()}.
   2421      *
   2422      * @see #getPersistedUriPermissions()
   2423      */
   2424     public void takePersistableUriPermission(@NonNull Uri uri,
   2425             @Intent.AccessUriMode int modeFlags) {
   2426         Preconditions.checkNotNull(uri, "uri");
   2427         try {
   2428             UriGrantsManager.getService().takePersistableUriPermission(
   2429                     ContentProvider.getUriWithoutUserId(uri), modeFlags, /* toPackage= */ null,
   2430                     resolveUserId(uri));
   2431         } catch (RemoteException e) {
   2432             throw e.rethrowFromSystemServer();
   2433         }
   2434     }
   2435 
   2436     /**
   2437      * @hide
   2438      */
   2439     @UnsupportedAppUsage
   2440     public void takePersistableUriPermission(@NonNull String toPackage, @NonNull Uri uri,
   2441             @Intent.AccessUriMode int modeFlags) {
   2442         Preconditions.checkNotNull(toPackage, "toPackage");
   2443         Preconditions.checkNotNull(uri, "uri");
   2444         try {
   2445             UriGrantsManager.getService().takePersistableUriPermission(
   2446                     ContentProvider.getUriWithoutUserId(uri), modeFlags, toPackage,
   2447                     resolveUserId(uri));
   2448         } catch (RemoteException e) {
   2449             throw e.rethrowFromSystemServer();
   2450         }
   2451     }
   2452 
   2453     /**
   2454      * Relinquish a persisted URI permission grant. The URI must have been
   2455      * previously made persistent with
   2456      * {@link #takePersistableUriPermission(Uri, int)}. Any non-persistent
   2457      * grants to the calling package will remain intact.
   2458      *
   2459      * @see #getPersistedUriPermissions()
   2460      */
   2461     public void releasePersistableUriPermission(@NonNull Uri uri,
   2462             @Intent.AccessUriMode int modeFlags) {
   2463         Preconditions.checkNotNull(uri, "uri");
   2464         try {
   2465             UriGrantsManager.getService().releasePersistableUriPermission(
   2466                     ContentProvider.getUriWithoutUserId(uri), modeFlags, /* toPackage= */ null,
   2467                     resolveUserId(uri));
   2468         } catch (RemoteException e) {
   2469             throw e.rethrowFromSystemServer();
   2470         }
   2471     }
   2472 
   2473     /**
   2474      * Return list of all URI permission grants that have been persisted by the
   2475      * calling app. That is, the returned permissions have been granted
   2476      * <em>to</em> the calling app. Only persistable grants taken with
   2477      * {@link #takePersistableUriPermission(Uri, int)} are returned.
   2478      * <p>Note: Some of the returned URIs may not be usable until after the user is unlocked.
   2479      *
   2480      * @see #takePersistableUriPermission(Uri, int)
   2481      * @see #releasePersistableUriPermission(Uri, int)
   2482      */
   2483     public @NonNull List<UriPermission> getPersistedUriPermissions() {
   2484         try {
   2485             return UriGrantsManager.getService().getUriPermissions(
   2486                     mPackageName, true /* incoming */, true /* persistedOnly */).getList();
   2487         } catch (RemoteException e) {
   2488             throw e.rethrowFromSystemServer();
   2489         }
   2490     }
   2491 
   2492     /**
   2493      * Return list of all persisted URI permission grants that are hosted by the
   2494      * calling app. That is, the returned permissions have been granted
   2495      * <em>from</em> the calling app. Only grants taken with
   2496      * {@link #takePersistableUriPermission(Uri, int)} are returned.
   2497      * <p>Note: Some of the returned URIs may not be usable until after the user is unlocked.
   2498      */
   2499     public @NonNull List<UriPermission> getOutgoingPersistedUriPermissions() {
   2500         try {
   2501             return UriGrantsManager.getService().getUriPermissions(
   2502                     mPackageName, false /* incoming */, true /* persistedOnly */).getList();
   2503         } catch (RemoteException e) {
   2504             throw e.rethrowFromSystemServer();
   2505         }
   2506     }
   2507 
   2508     /** @hide */
   2509     public @NonNull List<UriPermission> getOutgoingUriPermissions() {
   2510         try {
   2511             return UriGrantsManager.getService().getUriPermissions(
   2512                     mPackageName, false /* incoming */, false /* persistedOnly */).getList();
   2513         } catch (RemoteException e) {
   2514             throw e.rethrowFromSystemServer();
   2515         }
   2516     }
   2517 
   2518     /**
   2519      * Start an asynchronous sync operation. If you want to monitor the progress
   2520      * of the sync you may register a SyncObserver. Only values of the following
   2521      * types may be used in the extras bundle:
   2522      * <ul>
   2523      * <li>Integer</li>
   2524      * <li>Long</li>
   2525      * <li>Boolean</li>
   2526      * <li>Float</li>
   2527      * <li>Double</li>
   2528      * <li>String</li>
   2529      * <li>Account</li>
   2530      * <li>null</li>
   2531      * </ul>
   2532      *
   2533      * @param uri the uri of the provider to sync or null to sync all providers.
   2534      * @param extras any extras to pass to the SyncAdapter.
   2535      * @deprecated instead use
   2536      * {@link #requestSync(android.accounts.Account, String, android.os.Bundle)}
   2537      */
   2538     @Deprecated
   2539     public void startSync(Uri uri, Bundle extras) {
   2540         Account account = null;
   2541         if (extras != null) {
   2542             String accountName = extras.getString(SYNC_EXTRAS_ACCOUNT);
   2543             if (!TextUtils.isEmpty(accountName)) {
   2544                 // TODO: No references to Google in AOSP
   2545                 account = new Account(accountName, "com.google");
   2546             }
   2547             extras.remove(SYNC_EXTRAS_ACCOUNT);
   2548         }
   2549         requestSync(account, uri != null ? uri.getAuthority() : null, extras);
   2550     }
   2551 
   2552     /**
   2553      * Start an asynchronous sync operation. If you want to monitor the progress
   2554      * of the sync you may register a SyncObserver. Only values of the following
   2555      * types may be used in the extras bundle:
   2556      * <ul>
   2557      * <li>Integer</li>
   2558      * <li>Long</li>
   2559      * <li>Boolean</li>
   2560      * <li>Float</li>
   2561      * <li>Double</li>
   2562      * <li>String</li>
   2563      * <li>Account</li>
   2564      * <li>null</li>
   2565      * </ul>
   2566      *
   2567      * @param account which account should be synced
   2568      * @param authority which authority should be synced
   2569      * @param extras any extras to pass to the SyncAdapter.
   2570      */
   2571     public static void requestSync(Account account, String authority, Bundle extras) {
   2572         requestSyncAsUser(account, authority, UserHandle.myUserId(), extras);
   2573     }
   2574 
   2575     /**
   2576      * @see #requestSync(Account, String, Bundle)
   2577      * @hide
   2578      */
   2579     public static void requestSyncAsUser(Account account, String authority, @UserIdInt int userId,
   2580             Bundle extras) {
   2581         if (extras == null) {
   2582             throw new IllegalArgumentException("Must specify extras.");
   2583         }
   2584         SyncRequest request =
   2585             new SyncRequest.Builder()
   2586                 .setSyncAdapter(account, authority)
   2587                 .setExtras(extras)
   2588                 .syncOnce()     // Immediate sync.
   2589                 .build();
   2590         try {
   2591             // Note ActivityThread.currentPackageName() may not be accurate in a shared process
   2592             // case, but it's only for debugging.
   2593             getContentService().syncAsUser(request, userId, ActivityThread.currentPackageName());
   2594         } catch(RemoteException e) {
   2595             throw e.rethrowFromSystemServer();
   2596         }
   2597     }
   2598 
   2599     /**
   2600      * Register a sync with the SyncManager. These requests are built using the
   2601      * {@link SyncRequest.Builder}.
   2602      */
   2603     public static void requestSync(SyncRequest request) {
   2604         try {
   2605             // Note ActivityThread.currentPackageName() may not be accurate in a shared process
   2606             // case, but it's only for debugging.
   2607             getContentService().sync(request, ActivityThread.currentPackageName());
   2608         } catch(RemoteException e) {
   2609             throw e.rethrowFromSystemServer();
   2610         }
   2611     }
   2612 
   2613     /**
   2614      * Check that only values of the following types are in the Bundle:
   2615      * <ul>
   2616      * <li>Integer</li>
   2617      * <li>Long</li>
   2618      * <li>Boolean</li>
   2619      * <li>Float</li>
   2620      * <li>Double</li>
   2621      * <li>String</li>
   2622      * <li>Account</li>
   2623      * <li>null</li>
   2624      * </ul>
   2625      * @param extras the Bundle to check
   2626      */
   2627     public static void validateSyncExtrasBundle(Bundle extras) {
   2628         try {
   2629             for (String key : extras.keySet()) {
   2630                 Object value = extras.get(key);
   2631                 if (value == null) continue;
   2632                 if (value instanceof Long) continue;
   2633                 if (value instanceof Integer) continue;
   2634                 if (value instanceof Boolean) continue;
   2635                 if (value instanceof Float) continue;
   2636                 if (value instanceof Double) continue;
   2637                 if (value instanceof String) continue;
   2638                 if (value instanceof Account) continue;
   2639                 throw new IllegalArgumentException("unexpected value type: "
   2640                         + value.getClass().getName());
   2641             }
   2642         } catch (IllegalArgumentException e) {
   2643             throw e;
   2644         } catch (RuntimeException exc) {
   2645             throw new IllegalArgumentException("error unparceling Bundle", exc);
   2646         }
   2647     }
   2648 
   2649     /**
   2650      * Cancel any active or pending syncs that match the Uri. If the uri is null then
   2651      * all syncs will be canceled.
   2652      *
   2653      * @param uri the uri of the provider to sync or null to sync all providers.
   2654      * @deprecated instead use {@link #cancelSync(android.accounts.Account, String)}
   2655      */
   2656     @Deprecated
   2657     public void cancelSync(Uri uri) {
   2658         cancelSync(null /* all accounts */, uri != null ? uri.getAuthority() : null);
   2659     }
   2660 
   2661     /**
   2662      * Cancel any active or pending syncs that match account and authority. The account and
   2663      * authority can each independently be set to null, which means that syncs with any account
   2664      * or authority, respectively, will match.
   2665      *
   2666      * @param account filters the syncs that match by this account
   2667      * @param authority filters the syncs that match by this authority
   2668      */
   2669     public static void cancelSync(Account account, String authority) {
   2670         try {
   2671             getContentService().cancelSync(account, authority, null);
   2672         } catch (RemoteException e) {
   2673             throw e.rethrowFromSystemServer();
   2674         }
   2675     }
   2676 
   2677     /**
   2678      * @see #cancelSync(Account, String)
   2679      * @hide
   2680      */
   2681     public static void cancelSyncAsUser(Account account, String authority, @UserIdInt int userId) {
   2682         try {
   2683             getContentService().cancelSyncAsUser(account, authority, null, userId);
   2684         } catch (RemoteException e) {
   2685             throw e.rethrowFromSystemServer();
   2686         }
   2687     }
   2688 
   2689     /**
   2690      * Get information about the SyncAdapters that are known to the system.
   2691      * @return an array of SyncAdapters that have registered with the system
   2692      */
   2693     public static SyncAdapterType[] getSyncAdapterTypes() {
   2694         try {
   2695             return getContentService().getSyncAdapterTypes();
   2696         } catch (RemoteException e) {
   2697             throw e.rethrowFromSystemServer();
   2698         }
   2699     }
   2700 
   2701     /**
   2702      * @see #getSyncAdapterTypes()
   2703      * @hide
   2704      */
   2705     public static SyncAdapterType[] getSyncAdapterTypesAsUser(@UserIdInt int userId) {
   2706         try {
   2707             return getContentService().getSyncAdapterTypesAsUser(userId);
   2708         } catch (RemoteException e) {
   2709             throw e.rethrowFromSystemServer();
   2710         }
   2711     }
   2712 
   2713     /**
   2714      * @hide
   2715      * Returns the package names of syncadapters that match a given user and authority.
   2716      */
   2717     @TestApi
   2718     public static String[] getSyncAdapterPackagesForAuthorityAsUser(String authority,
   2719             @UserIdInt int userId) {
   2720         try {
   2721             return getContentService().getSyncAdapterPackagesForAuthorityAsUser(authority, userId);
   2722         } catch (RemoteException e) {
   2723             throw e.rethrowFromSystemServer();
   2724         }
   2725     }
   2726 
   2727     /**
   2728      * Check if the provider should be synced when a network tickle is received
   2729      * <p>This method requires the caller to hold the permission
   2730      * {@link android.Manifest.permission#READ_SYNC_SETTINGS}.
   2731      *
   2732      * @param account the account whose setting we are querying
   2733      * @param authority the provider whose setting we are querying
   2734      * @return true if the provider should be synced when a network tickle is received
   2735      */
   2736     public static boolean getSyncAutomatically(Account account, String authority) {
   2737         try {
   2738             return getContentService().getSyncAutomatically(account, authority);
   2739         } catch (RemoteException e) {
   2740             throw e.rethrowFromSystemServer();
   2741         }
   2742     }
   2743 
   2744     /**
   2745      * @see #getSyncAutomatically(Account, String)
   2746      * @hide
   2747      */
   2748     public static boolean getSyncAutomaticallyAsUser(Account account, String authority,
   2749             @UserIdInt int userId) {
   2750         try {
   2751             return getContentService().getSyncAutomaticallyAsUser(account, authority, userId);
   2752         } catch (RemoteException e) {
   2753             throw e.rethrowFromSystemServer();
   2754         }
   2755     }
   2756 
   2757     /**
   2758      * Set whether or not the provider is synced when it receives a network tickle.
   2759      * <p>This method requires the caller to hold the permission
   2760      * {@link android.Manifest.permission#WRITE_SYNC_SETTINGS}.
   2761      *
   2762      * @param account the account whose setting we are querying
   2763      * @param authority the provider whose behavior is being controlled
   2764      * @param sync true if the provider should be synced when tickles are received for it
   2765      */
   2766     public static void setSyncAutomatically(Account account, String authority, boolean sync) {
   2767         setSyncAutomaticallyAsUser(account, authority, sync, UserHandle.myUserId());
   2768     }
   2769 
   2770     /**
   2771      * @see #setSyncAutomatically(Account, String, boolean)
   2772      * @hide
   2773      */
   2774     public static void setSyncAutomaticallyAsUser(Account account, String authority, boolean sync,
   2775             @UserIdInt int userId) {
   2776         try {
   2777             getContentService().setSyncAutomaticallyAsUser(account, authority, sync, userId);
   2778         } catch (RemoteException e) {
   2779             throw e.rethrowFromSystemServer();
   2780         }
   2781     }
   2782 
   2783     /**
   2784      * Specifies that a sync should be requested with the specified the account, authority,
   2785      * and extras at the given frequency. If there is already another periodic sync scheduled
   2786      * with the account, authority and extras then a new periodic sync won't be added, instead
   2787      * the frequency of the previous one will be updated.
   2788      * <p>
   2789      * These periodic syncs honor the "syncAutomatically" and "masterSyncAutomatically" settings.
   2790      * Although these sync are scheduled at the specified frequency, it may take longer for it to
   2791      * actually be started if other syncs are ahead of it in the sync operation queue. This means
   2792      * that the actual start time may drift.
   2793      * <p>
   2794      * Periodic syncs are not allowed to have any of {@link #SYNC_EXTRAS_DO_NOT_RETRY},
   2795      * {@link #SYNC_EXTRAS_IGNORE_BACKOFF}, {@link #SYNC_EXTRAS_IGNORE_SETTINGS},
   2796      * {@link #SYNC_EXTRAS_INITIALIZE}, {@link #SYNC_EXTRAS_FORCE},
   2797      * {@link #SYNC_EXTRAS_EXPEDITED}, {@link #SYNC_EXTRAS_MANUAL} set to true.
   2798      * If any are supplied then an {@link IllegalArgumentException} will be thrown.
   2799      *
   2800      * <p>This method requires the caller to hold the permission
   2801      * {@link android.Manifest.permission#WRITE_SYNC_SETTINGS}.
   2802      * <p>The bundle for a periodic sync can be queried by applications with the correct
   2803      * permissions using
   2804      * {@link ContentResolver#getPeriodicSyncs(Account account, String provider)}, so no
   2805      * sensitive data should be transferred here.
   2806      *
   2807      * @param account the account to specify in the sync
   2808      * @param authority the provider to specify in the sync request
   2809      * @param extras extra parameters to go along with the sync request
   2810      * @param pollFrequency how frequently the sync should be performed, in seconds.
   2811      * On Android API level 24 and above, a minmam interval of 15 minutes is enforced.
   2812      * On previous versions, the minimum interval is 1 hour.
   2813      * @throws IllegalArgumentException if an illegal extra was set or if any of the parameters
   2814      * are null.
   2815      */
   2816     public static void addPeriodicSync(Account account, String authority, Bundle extras,
   2817             long pollFrequency) {
   2818         validateSyncExtrasBundle(extras);
   2819         if (invalidPeriodicExtras(extras)) {
   2820             throw new IllegalArgumentException("illegal extras were set");
   2821         }
   2822         try {
   2823              getContentService().addPeriodicSync(account, authority, extras, pollFrequency);
   2824         } catch (RemoteException e) {
   2825             throw e.rethrowFromSystemServer();
   2826         }
   2827     }
   2828 
   2829     /**
   2830      * {@hide}
   2831      * Helper function to throw an <code>IllegalArgumentException</code> if any illegal
   2832      * extras were set for a periodic sync.
   2833      *
   2834      * @param extras bundle to validate.
   2835      */
   2836     public static boolean invalidPeriodicExtras(Bundle extras) {
   2837         if (extras.getBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, false)
   2838                 || extras.getBoolean(ContentResolver.SYNC_EXTRAS_DO_NOT_RETRY, false)
   2839                 || extras.getBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_BACKOFF, false)
   2840                 || extras.getBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_SETTINGS, false)
   2841                 || extras.getBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE, false)
   2842                 || extras.getBoolean(ContentResolver.SYNC_EXTRAS_FORCE, false)
   2843                 || extras.getBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, false)) {
   2844             return true;
   2845         }
   2846         return false;
   2847     }
   2848 
   2849     /**
   2850      * Remove a periodic sync. Has no affect if account, authority and extras don't match
   2851      * an existing periodic sync.
   2852      * <p>This method requires the caller to hold the permission
   2853      * {@link android.Manifest.permission#WRITE_SYNC_SETTINGS}.
   2854      *
   2855      * @param account the account of the periodic sync to remove
   2856      * @param authority the provider of the periodic sync to remove
   2857      * @param extras the extras of the periodic sync to remove
   2858      */
   2859     public static void removePeriodicSync(Account account, String authority, Bundle extras) {
   2860         validateSyncExtrasBundle(extras);
   2861         try {
   2862             getContentService().removePeriodicSync(account, authority, extras);
   2863         } catch (RemoteException e) {
   2864             throw e.rethrowFromSystemServer();
   2865         }
   2866     }
   2867 
   2868     /**
   2869      * Remove the specified sync. This will cancel any pending or active syncs. If the request is
   2870      * for a periodic sync, this call will remove any future occurrences.
   2871      * <p>
   2872      *     If a periodic sync is specified, the caller must hold the permission
   2873      *     {@link android.Manifest.permission#WRITE_SYNC_SETTINGS}.
   2874      *</p>
   2875      * It is possible to cancel a sync using a SyncRequest object that is not the same object
   2876      * with which you requested the sync. Do so by building a SyncRequest with the same
   2877      * adapter, frequency, <b>and</b> extras bundle.
   2878      *
   2879      * @param request SyncRequest object containing information about sync to cancel.
   2880      */
   2881     public static void cancelSync(SyncRequest request) {
   2882         if (request == null) {
   2883             throw new IllegalArgumentException("request cannot be null");
   2884         }
   2885         try {
   2886             getContentService().cancelRequest(request);
   2887         } catch (RemoteException e) {
   2888             throw e.rethrowFromSystemServer();
   2889         }
   2890     }
   2891 
   2892     /**
   2893      * Get the list of information about the periodic syncs for the given account and authority.
   2894      * <p>This method requires the caller to hold the permission
   2895      * {@link android.Manifest.permission#READ_SYNC_SETTINGS}.
   2896      *
   2897      * @param account the account whose periodic syncs we are querying
   2898      * @param authority the provider whose periodic syncs we are querying
   2899      * @return a list of PeriodicSync objects. This list may be empty but will never be null.
   2900      */
   2901     public static List<PeriodicSync> getPeriodicSyncs(Account account, String authority) {
   2902         try {
   2903             return getContentService().getPeriodicSyncs(account, authority, null);
   2904         } catch (RemoteException e) {
   2905             throw e.rethrowFromSystemServer();
   2906         }
   2907     }
   2908 
   2909     /**
   2910      * Check if this account/provider is syncable.
   2911      * <p>This method requires the caller to hold the permission
   2912      * {@link android.Manifest.permission#READ_SYNC_SETTINGS}.
   2913      * @return >0 if it is syncable, 0 if not, and <0 if the state isn't known yet.
   2914      */
   2915     public static int getIsSyncable(Account account, String authority) {
   2916         try {
   2917             return getContentService().getIsSyncable(account, authority);
   2918         } catch (RemoteException e) {
   2919             throw e.rethrowFromSystemServer();
   2920         }
   2921     }
   2922 
   2923     /**
   2924      * @see #getIsSyncable(Account, String)
   2925      * @hide
   2926      */
   2927     public static int getIsSyncableAsUser(Account account, String authority,
   2928             @UserIdInt int userId) {
   2929         try {
   2930             return getContentService().getIsSyncableAsUser(account, authority, userId);
   2931         } catch (RemoteException e) {
   2932             throw e.rethrowFromSystemServer();
   2933         }
   2934     }
   2935 
   2936     /**
   2937      * Set whether this account/provider is syncable.
   2938      * <p>This method requires the caller to hold the permission
   2939      * {@link android.Manifest.permission#WRITE_SYNC_SETTINGS}.
   2940      * @param syncable >0 denotes syncable, 0 means not syncable, <0 means unknown
   2941      */
   2942     public static void setIsSyncable(Account account, String authority, int syncable) {
   2943         try {
   2944             getContentService().setIsSyncable(account, authority, syncable);
   2945         } catch (RemoteException e) {
   2946             throw e.rethrowFromSystemServer();
   2947         }
   2948     }
   2949 
   2950     /**
   2951      * @see #setIsSyncable(Account, String, int)
   2952      * @hide
   2953      */
   2954     public static void setIsSyncableAsUser(Account account, String authority, int syncable,
   2955             int userId) {
   2956         try {
   2957             getContentService().setIsSyncableAsUser(account, authority, syncable, userId);
   2958         } catch (RemoteException e) {
   2959             throw e.rethrowFromSystemServer();
   2960         }
   2961     }
   2962 
   2963     /**
   2964      * Gets the master auto-sync setting that applies to all the providers and accounts.
   2965      * If this is false then the per-provider auto-sync setting is ignored.
   2966      * <p>This method requires the caller to hold the permission
   2967      * {@link android.Manifest.permission#READ_SYNC_SETTINGS}.
   2968      *
   2969      * @return the master auto-sync setting that applies to all the providers and accounts
   2970      */
   2971     public static boolean getMasterSyncAutomatically() {
   2972         try {
   2973             return getContentService().getMasterSyncAutomatically();
   2974         } catch (RemoteException e) {
   2975             throw e.rethrowFromSystemServer();
   2976         }
   2977     }
   2978 
   2979     /**
   2980      * @see #getMasterSyncAutomatically()
   2981      * @hide
   2982      */
   2983     public static boolean getMasterSyncAutomaticallyAsUser(@UserIdInt int userId) {
   2984         try {
   2985             return getContentService().getMasterSyncAutomaticallyAsUser(userId);
   2986         } catch (RemoteException e) {
   2987             throw e.rethrowFromSystemServer();
   2988         }
   2989     }
   2990 
   2991     /**
   2992      * Sets the master auto-sync setting that applies to all the providers and accounts.
   2993      * If this is false then the per-provider auto-sync setting is ignored.
   2994      * <p>This method requires the caller to hold the permission
   2995      * {@link android.Manifest.permission#WRITE_SYNC_SETTINGS}.
   2996      *
   2997      * @param sync the master auto-sync setting that applies to all the providers and accounts
   2998      */
   2999     public static void setMasterSyncAutomatically(boolean sync) {
   3000         setMasterSyncAutomaticallyAsUser(sync, UserHandle.myUserId());
   3001     }
   3002 
   3003     /**
   3004      * @see #setMasterSyncAutomatically(boolean)
   3005      * @hide
   3006      */
   3007     public static void setMasterSyncAutomaticallyAsUser(boolean sync, @UserIdInt int userId) {
   3008         try {
   3009             getContentService().setMasterSyncAutomaticallyAsUser(sync, userId);
   3010         } catch (RemoteException e) {
   3011             throw e.rethrowFromSystemServer();
   3012         }
   3013     }
   3014 
   3015     /**
   3016      * Returns true if there is currently a sync operation for the given account or authority
   3017      * actively being processed.
   3018      * <p>This method requires the caller to hold the permission
   3019      * {@link android.Manifest.permission#READ_SYNC_STATS}.
   3020      * @param account the account whose setting we are querying
   3021      * @param authority the provider whose behavior is being queried
   3022      * @return true if a sync is active for the given account or authority.
   3023      */
   3024     public static boolean isSyncActive(Account account, String authority) {
   3025         if (account == null) {
   3026             throw new IllegalArgumentException("account must not be null");
   3027         }
   3028         if (authority == null) {
   3029             throw new IllegalArgumentException("authority must not be null");
   3030         }
   3031 
   3032         try {
   3033             return getContentService().isSyncActive(account, authority, null);
   3034         } catch (RemoteException e) {
   3035             throw e.rethrowFromSystemServer();
   3036         }
   3037     }
   3038 
   3039     /**
   3040      * If a sync is active returns the information about it, otherwise returns null.
   3041      * <p>
   3042      * This method requires the caller to hold the permission
   3043      * {@link android.Manifest.permission#READ_SYNC_STATS}.
   3044      * <p>
   3045      * @return the SyncInfo for the currently active sync or null if one is not active.
   3046      * @deprecated
   3047      * Since multiple concurrent syncs are now supported you should use
   3048      * {@link #getCurrentSyncs()} to get the accurate list of current syncs.
   3049      * This method returns the first item from the list of current syncs
   3050      * or null if there are none.
   3051      */
   3052     @Deprecated
   3053     public static SyncInfo getCurrentSync() {
   3054         try {
   3055             final List<SyncInfo> syncs = getContentService().getCurrentSyncs();
   3056             if (syncs.isEmpty()) {
   3057                 return null;
   3058             }
   3059             return syncs.get(0);
   3060         } catch (RemoteException e) {
   3061             throw e.rethrowFromSystemServer();
   3062         }
   3063     }
   3064 
   3065     /**
   3066      * Returns a list with information about all the active syncs. This list will be empty
   3067      * if there are no active syncs.
   3068      * <p>
   3069      * This method requires the caller to hold the permission
   3070      * {@link android.Manifest.permission#READ_SYNC_STATS}.
   3071      * <p>
   3072      * @return a List of SyncInfo objects for the currently active syncs.
   3073      */
   3074     public static List<SyncInfo> getCurrentSyncs() {
   3075         try {
   3076             return getContentService().getCurrentSyncs();
   3077         } catch (RemoteException e) {
   3078             throw e.rethrowFromSystemServer();
   3079         }
   3080     }
   3081 
   3082     /**
   3083      * @see #getCurrentSyncs()
   3084      * @hide
   3085      */
   3086     public static List<SyncInfo> getCurrentSyncsAsUser(@UserIdInt int userId) {
   3087         try {
   3088             return getContentService().getCurrentSyncsAsUser(userId);
   3089         } catch (RemoteException e) {
   3090             throw e.rethrowFromSystemServer();
   3091         }
   3092     }
   3093 
   3094     /**
   3095      * Returns the status that matches the authority.
   3096      * @param account the account whose setting we are querying
   3097      * @param authority the provider whose behavior is being queried
   3098      * @return the SyncStatusInfo for the authority, or null if none exists
   3099      * @hide
   3100      */
   3101     @UnsupportedAppUsage
   3102     public static SyncStatusInfo getSyncStatus(Account account, String authority) {
   3103         try {
   3104             return getContentService().getSyncStatus(account, authority, null);
   3105         } catch (RemoteException e) {
   3106             throw e.rethrowFromSystemServer();
   3107         }
   3108     }
   3109 
   3110     /**
   3111      * @see #getSyncStatus(Account, String)
   3112      * @hide
   3113      */
   3114     @UnsupportedAppUsage
   3115     public static SyncStatusInfo getSyncStatusAsUser(Account account, String authority,
   3116             @UserIdInt int userId) {
   3117         try {
   3118             return getContentService().getSyncStatusAsUser(account, authority, null, userId);
   3119         } catch (RemoteException e) {
   3120             throw e.rethrowFromSystemServer();
   3121         }
   3122     }
   3123 
   3124     /**
   3125      * Return true if the pending status is true of any matching authorities.
   3126      * <p>This method requires the caller to hold the permission
   3127      * {@link android.Manifest.permission#READ_SYNC_STATS}.
   3128      * @param account the account whose setting we are querying
   3129      * @param authority the provider whose behavior is being queried
   3130      * @return true if there is a pending sync with the matching account and authority
   3131      */
   3132     public static boolean isSyncPending(Account account, String authority) {
   3133         return isSyncPendingAsUser(account, authority, UserHandle.myUserId());
   3134     }
   3135 
   3136     /**
   3137      * @see #requestSync(Account, String, Bundle)
   3138      * @hide
   3139      */
   3140     public static boolean isSyncPendingAsUser(Account account, String authority,
   3141             @UserIdInt int userId) {
   3142         try {
   3143             return getContentService().isSyncPendingAsUser(account, authority, null, userId);
   3144         } catch (RemoteException e) {
   3145             throw e.rethrowFromSystemServer();
   3146         }
   3147     }
   3148 
   3149     /**
   3150      * Request notifications when the different aspects of the SyncManager change. The
   3151      * different items that can be requested are:
   3152      * <ul>
   3153      * <li> {@link #SYNC_OBSERVER_TYPE_PENDING}
   3154      * <li> {@link #SYNC_OBSERVER_TYPE_ACTIVE}
   3155      * <li> {@link #SYNC_OBSERVER_TYPE_SETTINGS}
   3156      * </ul>
   3157      * The caller can set one or more of the status types in the mask for any
   3158      * given listener registration.
   3159      * @param mask the status change types that will cause the callback to be invoked
   3160      * @param callback observer to be invoked when the status changes
   3161      * @return a handle that can be used to remove the listener at a later time
   3162      */
   3163     public static Object addStatusChangeListener(int mask, final SyncStatusObserver callback) {
   3164         if (callback == null) {
   3165             throw new IllegalArgumentException("you passed in a null callback");
   3166         }
   3167         try {
   3168             ISyncStatusObserver.Stub observer = new ISyncStatusObserver.Stub() {
   3169                 @Override
   3170                 public void onStatusChanged(int which) throws RemoteException {
   3171                     callback.onStatusChanged(which);
   3172                 }
   3173             };
   3174             getContentService().addStatusChangeListener(mask, observer);
   3175             return observer;
   3176         } catch (RemoteException e) {
   3177             throw e.rethrowFromSystemServer();
   3178         }
   3179     }
   3180 
   3181     /**
   3182      * Remove a previously registered status change listener.
   3183      * @param handle the handle that was returned by {@link #addStatusChangeListener}
   3184      */
   3185     public static void removeStatusChangeListener(Object handle) {
   3186         if (handle == null) {
   3187             throw new IllegalArgumentException("you passed in a null handle");
   3188         }
   3189         try {
   3190             getContentService().removeStatusChangeListener((ISyncStatusObserver.Stub) handle);
   3191         } catch (RemoteException e) {
   3192             throw e.rethrowFromSystemServer();
   3193         }
   3194     }
   3195 
   3196     /**
   3197      * Store the given {@link Bundle} as a long-lived cached object within the
   3198      * system. This can be useful to avoid expensive re-parsing when apps are
   3199      * restarted multiple times on low-RAM devices.
   3200      * <p>
   3201      * The {@link Bundle} is automatically invalidated when a
   3202      * {@link #notifyChange(Uri, ContentObserver)} event applies to the key.
   3203      *
   3204      * @hide
   3205      */
   3206     @SystemApi
   3207     @RequiresPermission(android.Manifest.permission.CACHE_CONTENT)
   3208     public void putCache(@NonNull Uri key, @Nullable Bundle value) {
   3209         try {
   3210             getContentService().putCache(mContext.getPackageName(), key, value,
   3211                     mContext.getUserId());
   3212         } catch (RemoteException e) {
   3213             throw e.rethrowFromSystemServer();
   3214         }
   3215     }
   3216 
   3217     /**
   3218      * Retrieve the last {@link Bundle} stored as a long-lived cached object
   3219      * within the system.
   3220      *
   3221      * @return {@code null} if no cached object has been stored, or if the
   3222      *         stored object has been invalidated due to a
   3223      *         {@link #notifyChange(Uri, ContentObserver)} event.
   3224      * @hide
   3225      */
   3226     @SystemApi
   3227     @RequiresPermission(android.Manifest.permission.CACHE_CONTENT)
   3228     public @Nullable Bundle getCache(@NonNull Uri key) {
   3229         try {
   3230             final Bundle bundle = getContentService().getCache(mContext.getPackageName(), key,
   3231                     mContext.getUserId());
   3232             if (bundle != null) bundle.setClassLoader(mContext.getClassLoader());
   3233             return bundle;
   3234         } catch (RemoteException e) {
   3235             throw e.rethrowFromSystemServer();
   3236         }
   3237     }
   3238 
   3239     /** {@hide} */
   3240     public int getTargetSdkVersion() {
   3241         return mTargetSdkVersion;
   3242     }
   3243 
   3244     /**
   3245      * Returns sampling percentage for a given duration.
   3246      *
   3247      * Always returns at least 1%.
   3248      */
   3249     private int samplePercentForDuration(long durationMillis) {
   3250         if (durationMillis >= SLOW_THRESHOLD_MILLIS) {
   3251             return 100;
   3252         }
   3253         return (int) (100 * durationMillis / SLOW_THRESHOLD_MILLIS) + 1;
   3254     }
   3255 
   3256     private void maybeLogQueryToEventLog(
   3257             long durationMillis, Uri uri, String[] projection, @Nullable Bundle queryArgs) {
   3258         if (!ENABLE_CONTENT_SAMPLE) return;
   3259         int samplePercent = samplePercentForDuration(durationMillis);
   3260         if (samplePercent < 100) {
   3261             synchronized (mRandom) {
   3262                 if (mRandom.nextInt(100) >= samplePercent) {
   3263                     return;
   3264                 }
   3265             }
   3266         }
   3267 
   3268         // Ensure a non-null bundle.
   3269         queryArgs = (queryArgs != null) ? queryArgs : Bundle.EMPTY;
   3270 
   3271         StringBuilder projectionBuffer = new StringBuilder(100);
   3272         if (projection != null) {
   3273             for (int i = 0; i < projection.length; ++i) {
   3274                 // Note: not using a comma delimiter here, as the
   3275                 // multiple arguments to EventLog.writeEvent later
   3276                 // stringify with a comma delimiter, which would make
   3277                 // parsing uglier later.
   3278                 if (i != 0) projectionBuffer.append('/');
   3279                 projectionBuffer.append(projection[i]);
   3280             }
   3281         }
   3282 
   3283         // ActivityThread.currentPackageName() only returns non-null if the
   3284         // current thread is an application main thread.  This parameter tells
   3285         // us whether an event loop is blocked, and if so, which app it is.
   3286         String blockingPackage = AppGlobals.getInitialPackage();
   3287 
   3288         EventLog.writeEvent(
   3289             EventLogTags.CONTENT_QUERY_SAMPLE,
   3290             uri.toString(),
   3291             projectionBuffer.toString(),
   3292             queryArgs.getString(QUERY_ARG_SQL_SELECTION, ""),
   3293             queryArgs.getString(QUERY_ARG_SQL_SORT_ORDER, ""),
   3294             durationMillis,
   3295             blockingPackage != null ? blockingPackage : "",
   3296             samplePercent);
   3297     }
   3298 
   3299     private void maybeLogUpdateToEventLog(
   3300         long durationMillis, Uri uri, String operation, String selection) {
   3301         if (!ENABLE_CONTENT_SAMPLE) return;
   3302         int samplePercent = samplePercentForDuration(durationMillis);
   3303         if (samplePercent < 100) {
   3304             synchronized (mRandom) {
   3305                 if (mRandom.nextInt(100) >= samplePercent) {
   3306                     return;
   3307                 }
   3308             }
   3309         }
   3310         String blockingPackage = AppGlobals.getInitialPackage();
   3311         EventLog.writeEvent(
   3312             EventLogTags.CONTENT_UPDATE_SAMPLE,
   3313             uri.toString(),
   3314             operation,
   3315             selection != null ? selection : "",
   3316             durationMillis,
   3317             blockingPackage != null ? blockingPackage : "",
   3318             samplePercent);
   3319     }
   3320 
   3321     private final class CursorWrapperInner extends CrossProcessCursorWrapper {
   3322         private final IContentProvider mContentProvider;
   3323         private final AtomicBoolean mProviderReleased = new AtomicBoolean();
   3324 
   3325         private final CloseGuard mCloseGuard = CloseGuard.get();
   3326 
   3327         CursorWrapperInner(Cursor cursor, IContentProvider contentProvider) {
   3328             super(cursor);
   3329             mContentProvider = contentProvider;
   3330             mCloseGuard.open("close");
   3331         }
   3332 
   3333         @Override
   3334         public void close() {
   3335             mCloseGuard.close();
   3336             super.close();
   3337 
   3338             if (mProviderReleased.compareAndSet(false, true)) {
   3339                 ContentResolver.this.releaseProvider(mContentProvider);
   3340             }
   3341         }
   3342 
   3343         @Override
   3344         protected void finalize() throws Throwable {
   3345             try {
   3346                 if (mCloseGuard != null) {
   3347                     mCloseGuard.warnIfOpen();
   3348                 }
   3349 
   3350                 close();
   3351             } finally {
   3352                 super.finalize();
   3353             }
   3354         }
   3355     }
   3356 
   3357     private final class ParcelFileDescriptorInner extends ParcelFileDescriptor {
   3358         private final IContentProvider mContentProvider;
   3359         private final AtomicBoolean mProviderReleased = new AtomicBoolean();
   3360 
   3361         ParcelFileDescriptorInner(ParcelFileDescriptor pfd, IContentProvider icp) {
   3362             super(pfd);
   3363             mContentProvider = icp;
   3364         }
   3365 
   3366         @Override
   3367         public void releaseResources() {
   3368             if (mProviderReleased.compareAndSet(false, true)) {
   3369                 ContentResolver.this.releaseProvider(mContentProvider);
   3370             }
   3371         }
   3372     }
   3373 
   3374     /** @hide */
   3375     public static final String CONTENT_SERVICE_NAME = "content";
   3376 
   3377     /** @hide */
   3378     @UnsupportedAppUsage
   3379     public static IContentService getContentService() {
   3380         if (sContentService != null) {
   3381             return sContentService;
   3382         }
   3383         IBinder b = ServiceManager.getService(CONTENT_SERVICE_NAME);
   3384         sContentService = IContentService.Stub.asInterface(b);
   3385         return sContentService;
   3386     }
   3387 
   3388     /** @hide */
   3389     @UnsupportedAppUsage
   3390     public String getPackageName() {
   3391         return mPackageName;
   3392     }
   3393 
   3394     @UnsupportedAppUsage
   3395     private static volatile IContentService sContentService;
   3396     @UnsupportedAppUsage
   3397     private final Context mContext;
   3398 
   3399     @UnsupportedAppUsage
   3400     final String mPackageName;
   3401     final int mTargetSdkVersion;
   3402     final ContentInterface mWrapped;
   3403 
   3404     private static final String TAG = "ContentResolver";
   3405 
   3406     /** @hide */
   3407     public int resolveUserId(Uri uri) {
   3408         return ContentProvider.getUserIdFromUri(uri, mContext.getUserId());
   3409     }
   3410 
   3411     /** @hide */
   3412     public int getUserId() {
   3413         return mContext.getUserId();
   3414     }
   3415 
   3416     /** {@hide} */
   3417     @Deprecated
   3418     public Drawable getTypeDrawable(String mimeType) {
   3419         return getTypeInfo(mimeType).getIcon().loadDrawable(mContext);
   3420     }
   3421 
   3422     /**
   3423      * Return a detailed description of the given MIME type, including an icon
   3424      * and label that describe the type.
   3425      *
   3426      * @param mimeType Valid, concrete MIME type.
   3427      */
   3428     public final @NonNull MimeTypeInfo getTypeInfo(@NonNull String mimeType) {
   3429         Objects.requireNonNull(mimeType);
   3430         return MimeIconUtils.getTypeInfo(mimeType);
   3431     }
   3432 
   3433     /**
   3434      * Detailed description of a specific MIME type, including an icon and label
   3435      * that describe the type.
   3436      */
   3437     public static final class MimeTypeInfo {
   3438         private final Icon mIcon;
   3439         private final CharSequence mLabel;
   3440         private final CharSequence mContentDescription;
   3441 
   3442         /** {@hide} */
   3443         public MimeTypeInfo(@NonNull Icon icon, @NonNull CharSequence label,
   3444                 @NonNull CharSequence contentDescription) {
   3445             mIcon = Objects.requireNonNull(icon);
   3446             mLabel = Objects.requireNonNull(label);
   3447             mContentDescription = Objects.requireNonNull(contentDescription);
   3448         }
   3449 
   3450         /**
   3451          * Return a visual representation of this MIME type. This can be styled
   3452          * using {@link Icon#setTint(int)} to match surrounding UI.
   3453          *
   3454          * @see Icon#loadDrawable(Context)
   3455          * @see android.widget.ImageView#setImageDrawable(Drawable)
   3456          */
   3457         public @NonNull Icon getIcon() {
   3458             return mIcon;
   3459         }
   3460 
   3461         /**
   3462          * Return a textual representation of this MIME type.
   3463          *
   3464          * @see android.widget.TextView#setText(CharSequence)
   3465          */
   3466         public @NonNull CharSequence getLabel() {
   3467             return mLabel;
   3468         }
   3469 
   3470         /**
   3471          * Return a content description for this MIME type.
   3472          *
   3473          * @see android.view.View#setContentDescription(CharSequence)
   3474          */
   3475         public @NonNull CharSequence getContentDescription() {
   3476             return mContentDescription;
   3477         }
   3478     }
   3479 
   3480     /**
   3481      * @hide
   3482      */
   3483     public static @Nullable Bundle createSqlQueryBundle(
   3484             @Nullable String selection,
   3485             @Nullable String[] selectionArgs,
   3486             @Nullable String sortOrder) {
   3487 
   3488         if (selection == null && selectionArgs == null && sortOrder == null) {
   3489             return null;
   3490         }
   3491 
   3492         Bundle queryArgs = new Bundle();
   3493         if (selection != null) {
   3494             queryArgs.putString(QUERY_ARG_SQL_SELECTION, selection);
   3495         }
   3496         if (selectionArgs != null) {
   3497             queryArgs.putStringArray(QUERY_ARG_SQL_SELECTION_ARGS, selectionArgs);
   3498         }
   3499         if (sortOrder != null) {
   3500             queryArgs.putString(QUERY_ARG_SQL_SORT_ORDER, sortOrder);
   3501         }
   3502         return queryArgs;
   3503     }
   3504 
   3505     /**
   3506      * Returns structured sort args formatted as an SQL sort clause.
   3507      *
   3508      * NOTE: Collator clauses are suitable for use with non text fields. We might
   3509      * choose to omit any collation clause since we don't know the underlying
   3510      * type of data to be collated. Imperical testing shows that sqlite3 doesn't
   3511      * appear to care much about the presence of collate clauses in queries
   3512      * when ordering by numeric fields. For this reason we include collate
   3513      * clause unilaterally when {@link #QUERY_ARG_SORT_COLLATION} is present
   3514      * in query args bundle.
   3515      *
   3516      * TODO: Would be nice to explicitly validate that colums referenced in
   3517      * {@link #QUERY_ARG_SORT_COLUMNS} are present in the associated projection.
   3518      *
   3519      * @hide
   3520      */
   3521     public static String createSqlSortClause(Bundle queryArgs) {
   3522         String[] columns = queryArgs.getStringArray(QUERY_ARG_SORT_COLUMNS);
   3523         if (columns == null || columns.length == 0) {
   3524             throw new IllegalArgumentException("Can't create sort clause without columns.");
   3525         }
   3526 
   3527         String query = TextUtils.join(", ", columns);
   3528 
   3529         // Interpret PRIMARY and SECONDARY collation strength as no-case collation based
   3530         // on their javadoc descriptions.
   3531         int collation = queryArgs.getInt(
   3532                 ContentResolver.QUERY_ARG_SORT_COLLATION, java.text.Collator.IDENTICAL);
   3533         if (collation == java.text.Collator.PRIMARY || collation == java.text.Collator.SECONDARY) {
   3534             query += " COLLATE NOCASE";
   3535         }
   3536 
   3537         int sortDir = queryArgs.getInt(QUERY_ARG_SORT_DIRECTION, Integer.MIN_VALUE);
   3538         if (sortDir != Integer.MIN_VALUE) {
   3539             switch (sortDir) {
   3540                 case QUERY_SORT_DIRECTION_ASCENDING:
   3541                     query += " ASC";
   3542                     break;
   3543                 case QUERY_SORT_DIRECTION_DESCENDING:
   3544                     query += " DESC";
   3545                     break;
   3546                 default:
   3547                     throw new IllegalArgumentException("Unsupported sort direction value."
   3548                             + " See ContentResolver documentation for details.");
   3549             }
   3550         }
   3551         return query;
   3552     }
   3553 
   3554     /**
   3555      * Convenience method that efficiently loads a visual thumbnail for the
   3556      * given {@link Uri}. Internally calls
   3557      * {@link ContentProvider#openTypedAssetFile} on the remote provider, but
   3558      * also defensively resizes any returned content to match the requested
   3559      * target size.
   3560      *
   3561      * @param uri The item that should be visualized as a thumbnail.
   3562      * @param size The target area on the screen where this thumbnail will be
   3563      *            shown. This is passed to the provider as {@link #EXTRA_SIZE}
   3564      *            to help it avoid downloading or generating heavy resources.
   3565      * @param signal A signal to cancel the operation in progress.
   3566      * @return Valid {@link Bitmap} which is a visual thumbnail.
   3567      * @throws IOException If any trouble was encountered while generating or
   3568      *             loading the thumbnail, or if
   3569      *             {@link CancellationSignal#cancel()} was invoked.
   3570      */
   3571     public @NonNull Bitmap loadThumbnail(@NonNull Uri uri, @NonNull Size size,
   3572             @Nullable CancellationSignal signal) throws IOException {
   3573         return loadThumbnail(this, uri, size, signal, ImageDecoder.ALLOCATOR_SOFTWARE);
   3574     }
   3575 
   3576     /** {@hide} */
   3577     public static Bitmap loadThumbnail(@NonNull ContentInterface content, @NonNull Uri uri,
   3578             @NonNull Size size, @Nullable CancellationSignal signal, int allocator)
   3579             throws IOException {
   3580         Objects.requireNonNull(content);
   3581         Objects.requireNonNull(uri);
   3582         Objects.requireNonNull(size);
   3583 
   3584         // Convert to Point, since that's what the API is defined as
   3585         final Bundle opts = new Bundle();
   3586         opts.putParcelable(EXTRA_SIZE, Point.convert(size));
   3587         final Int32Ref orientation = new Int32Ref(0);
   3588 
   3589         Bitmap bitmap = ImageDecoder.decodeBitmap(ImageDecoder.createSource(() -> {
   3590             final AssetFileDescriptor afd = content.openTypedAssetFile(uri, "image/*", opts,
   3591                     signal);
   3592             final Bundle extras = afd.getExtras();
   3593             orientation.value = (extras != null) ? extras.getInt(EXTRA_ORIENTATION, 0) : 0;
   3594             return afd;
   3595         }), (ImageDecoder decoder, ImageInfo info, Source source) -> {
   3596             decoder.setAllocator(allocator);
   3597 
   3598             // One last-ditch check to see if we've been canceled.
   3599             if (signal != null) signal.throwIfCanceled();
   3600 
   3601             // We requested a rough thumbnail size, but the remote size may have
   3602             // returned something giant, so defensively scale down as needed.
   3603             final int widthSample = info.getSize().getWidth() / size.getWidth();
   3604             final int heightSample = info.getSize().getHeight() / size.getHeight();
   3605             final int sample = Math.min(widthSample, heightSample);
   3606             if (sample > 1) {
   3607                 decoder.setTargetSampleSize(sample);
   3608             }
   3609         });
   3610 
   3611         // Transform the bitmap if requested. We use a side-channel to
   3612         // communicate the orientation, since EXIF thumbnails don't contain
   3613         // the rotation flags of the original image.
   3614         if (orientation.value != 0) {
   3615             final int width = bitmap.getWidth();
   3616             final int height = bitmap.getHeight();
   3617 
   3618             final Matrix m = new Matrix();
   3619             m.setRotate(orientation.value, width / 2, height / 2);
   3620             bitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height, m, false);
   3621         }
   3622 
   3623         return bitmap;
   3624     }
   3625 
   3626     /** {@hide} */
   3627     public static void onDbCorruption(String tag, String message, Throwable stacktrace) {
   3628         try {
   3629             getContentService().onDbCorruption(tag, message, Log.getStackTraceString(stacktrace));
   3630         } catch (RemoteException e) {
   3631             e.rethrowFromSystemServer();
   3632         }
   3633     }
   3634 
   3635     /** {@hide} */
   3636     public static Uri translateDeprecatedDataPath(String path) {
   3637         final String ssp = "//" + path.substring(DEPRECATE_DATA_PREFIX.length());
   3638         return Uri.parse(new Uri.Builder().scheme(SCHEME_CONTENT)
   3639                 .encodedOpaquePart(ssp).build().toString());
   3640     }
   3641 
   3642     /** {@hide} */
   3643     public static String translateDeprecatedDataPath(Uri uri) {
   3644         return DEPRECATE_DATA_PREFIX + uri.getEncodedSchemeSpecificPart().substring(2);
   3645     }
   3646 }
   3647