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