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 a 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 IContentProvider provider = null; 924 try { 925 provider = acquireProvider(url); 926 } catch (Exception e) { 927 // if unable to acquire the provider, then it should try to get the type 928 // using getTypeAnonymous via ActivityManagerService 929 } 930 if (provider != null) { 931 try { 932 final StringResultListener resultListener = new StringResultListener(); 933 provider.getTypeAsync(mContext.getAttributionSource(), 934 url, new RemoteCallback(resultListener)); 935 resultListener.waitForResult(CONTENT_PROVIDER_TIMEOUT_MILLIS); 936 if (resultListener.exception != null) { 937 throw resultListener.exception; 938 } 939 return resultListener.result; 940 } catch (RemoteException e) { 941 // Arbitrary and not worth documenting, as Activity 942 // Manager will kill this process shortly anyway. 943 return null; 944 } catch (java.lang.Exception e) { 945 Log.w(TAG, "Failed to get type for: " + url + " (" + e.getMessage() + ")"); 946 return null; 947 } finally { 948 try { 949 releaseProvider(provider); 950 } catch (java.lang.NullPointerException e) { 951 // does nothing, Binder connection already null 952 } 953 } 954 } 955 956 if (!SCHEME_CONTENT.equals(url.getScheme())) { 957 return null; 958 } 959 960 try { 961 final StringResultListener resultListener = new StringResultListener(); 962 ActivityManager.getService().getMimeTypeFilterAsync( 963 ContentProvider.getUriWithoutUserId(url), 964 resolveUserId(url), 965 new RemoteCallback(resultListener)); 966 resultListener.waitForResult(REMOTE_CONTENT_PROVIDER_TIMEOUT_MILLIS); 967 if (resultListener.exception != null) { 968 throw resultListener.exception; 969 } 970 return resultListener.result; 971 } catch (RemoteException e) { 972 // We just failed to send a oneway request to the System Server. Nothing to do. 973 return null; 974 } catch (java.lang.Exception e) { 975 Log.w(TAG, "Failed to get type for: " + url + " (" + e.getMessage() + ")"); 976 return null; 977 } 978 } 979 980 private abstract static class ResultListener<T> implements RemoteCallback.OnResultListener { 981 @GuardedBy("this") 982 public boolean done; 983 984 @GuardedBy("this") 985 public T result; 986 987 @GuardedBy("this") 988 public RuntimeException exception; 989 990 @Override 991 public void onResult(Bundle result) { 992 synchronized (this) { 993 ParcelableException e = result.getParcelable(REMOTE_CALLBACK_ERROR, android.os.ParcelableException.class); 994 if (e != null) { 995 Throwable t = e.getCause(); 996 if (t instanceof RuntimeException) { 997 this.exception = (RuntimeException) t; 998 } else { 999 this.exception = new RuntimeException(t); 1000 } 1001 } else { 1002 this.result = getResultFromBundle(result); 1003 } 1004 done = true; 1005 notifyAll(); 1006 } 1007 } 1008 1009 protected abstract T getResultFromBundle(Bundle result); 1010 1011 public void waitForResult(long timeout) { 1012 synchronized (this) { 1013 if (!done) { 1014 try { 1015 wait(timeout); 1016 } catch (InterruptedException e) { 1017 // Ignore 1018 } 1019 } 1020 } 1021 } 1022 } 1023 1024 private static class StringResultListener extends ResultListener<String> { 1025 @Override 1026 protected String getResultFromBundle(Bundle result) { 1027 return result.getString(REMOTE_CALLBACK_RESULT); 1028 } 1029 } 1030 1031 private static class UriResultListener extends ResultListener<Uri> { 1032 @Override 1033 protected Uri getResultFromBundle(Bundle result) { 1034 return result.getParcelable(REMOTE_CALLBACK_RESULT, android.net.Uri.class); 1035 } 1036 } 1037 1038 /** 1039 * Query for the possible MIME types for the representations the given 1040 * content URL can be returned when opened as as stream with 1041 * {@link #openTypedAssetFileDescriptor}. Note that the types here are 1042 * not necessarily a superset of the type returned by {@link #getType} -- 1043 * many content providers cannot return a raw stream for the structured 1044 * data that they contain. 1045 * 1046 * @param url A Uri identifying content (either a list or specific type), 1047 * using the content:// scheme. 1048 * @param mimeTypeFilter The desired MIME type. This may be a pattern, 1049 * such as */*, to query for all available MIME types that match the 1050 * pattern. 1051 * @return Returns an array of MIME type strings for all available 1052 * data streams that match the given mimeTypeFilter. If there are none, 1053 * null is returned. 1054 */ 1055 @Override 1056 public @Nullable String[] getStreamTypes(@NonNull Uri url, @NonNull String mimeTypeFilter) { 1057 Objects.requireNonNull(url, "url"); 1058 Objects.requireNonNull(mimeTypeFilter, "mimeTypeFilter"); 1059 1060 try { 1061 if (mWrapped != null) return mWrapped.getStreamTypes(url, mimeTypeFilter); 1062 } catch (RemoteException e) { 1063 return null; 1064 } 1065 1066 IContentProvider provider = acquireProvider(url); 1067 if (provider == null) { 1068 return null; 1069 } 1070 1071 try { 1072 return provider.getStreamTypes(mContext.getAttributionSource(), url, mimeTypeFilter); 1073 } catch (RemoteException e) { 1074 // Arbitrary and not worth documenting, as Activity 1075 // Manager will kill this process shortly anyway. 1076 return null; 1077 } finally { 1078 releaseProvider(provider); 1079 } 1080 } 1081 1082 /** 1083 * Query the given URI, returning a {@link Cursor} over the result set. 1084 * <p> 1085 * For best performance, the caller should follow these guidelines: 1086 * <ul> 1087 * <li>Provide an explicit projection, to prevent 1088 * reading data from storage that aren't going to be used.</li> 1089 * <li>Use question mark parameter markers such as 'phone=?' instead of 1090 * explicit values in the {@code selection} parameter, so that queries 1091 * that differ only by those values will be recognized as the same 1092 * for caching purposes.</li> 1093 * </ul> 1094 * </p> 1095 * 1096 * @param uri The URI, using the content:// scheme, for the content to 1097 * retrieve. 1098 * @param projection A list of which columns to return. Passing null will 1099 * return all columns, which is inefficient. 1100 * @param selection A filter declaring which rows to return, formatted as an 1101 * SQL WHERE clause (excluding the WHERE itself). Passing null will 1102 * return all rows for the given URI. 1103 * @param selectionArgs You may include ?s in selection, which will be 1104 * replaced by the values from selectionArgs, in the order that they 1105 * appear in the selection. The values will be bound as Strings. 1106 * @param sortOrder How to order the rows, formatted as an SQL ORDER BY 1107 * clause (excluding the ORDER BY itself). Passing null will use the 1108 * default sort order, which may be unordered. 1109 * @return A Cursor object, which is positioned before the first entry. May return 1110 * <code>null</code> if the underlying content provider returns <code>null</code>, 1111 * or if it crashes. 1112 * @see Cursor 1113 */ 1114 public final @Nullable Cursor query(@RequiresPermission.Read @NonNull Uri uri, 1115 @Nullable String[] projection, @Nullable String selection, 1116 @Nullable String[] selectionArgs, @Nullable String sortOrder) { 1117 return query(uri, projection, selection, selectionArgs, sortOrder, null); 1118 } 1119 1120 /** 1121 * Query the given URI, returning a {@link Cursor} over the result set 1122 * with optional support for cancellation. 1123 * <p> 1124 * For best performance, the caller should follow these guidelines: 1125 * <ul> 1126 * <li>Provide an explicit projection, to prevent 1127 * reading data from storage that aren't going to be used.</li> 1128 * <li>Use question mark parameter markers such as 'phone=?' instead of 1129 * explicit values in the {@code selection} parameter, so that queries 1130 * that differ only by those values will be recognized as the same 1131 * for caching purposes.</li> 1132 * </ul> 1133 * </p> 1134 * 1135 * @param uri The URI, using the content:// scheme, for the content to 1136 * retrieve. 1137 * @param projection A list of which columns to return. Passing null will 1138 * return all columns, which is inefficient. 1139 * @param selection A filter declaring which rows to return, formatted as an 1140 * SQL WHERE clause (excluding the WHERE itself). Passing null will 1141 * return all rows for the given URI. 1142 * @param selectionArgs You may include ?s in selection, which will be 1143 * replaced by the values from selectionArgs, in the order that they 1144 * appear in the selection. The values will be bound as Strings. 1145 * @param sortOrder How to order the rows, formatted as an SQL ORDER BY 1146 * clause (excluding the ORDER BY itself). Passing null will use the 1147 * default sort order, which may be unordered. 1148 * @param cancellationSignal A signal to cancel the operation in progress, or null if none. 1149 * If the operation is canceled, then {@link OperationCanceledException} will be thrown 1150 * when the query is executed. 1151 * @return A Cursor object, which is positioned before the first entry. May return 1152 * <code>null</code> if the underlying content provider returns <code>null</code>, 1153 * or if it crashes. 1154 * @see Cursor 1155 */ 1156 public final @Nullable Cursor query(@RequiresPermission.Read @NonNull Uri uri, 1157 @Nullable String[] projection, @Nullable String selection, 1158 @Nullable String[] selectionArgs, @Nullable String sortOrder, 1159 @Nullable CancellationSignal cancellationSignal) { 1160 Bundle queryArgs = createSqlQueryBundle(selection, selectionArgs, sortOrder); 1161 return query(uri, projection, queryArgs, cancellationSignal); 1162 } 1163 1164 /** 1165 * Query the given URI, returning a {@link Cursor} over the result set 1166 * with support for cancellation. 1167 * 1168 * <p>For best performance, the caller should follow these guidelines: 1169 * 1170 * <li>Provide an explicit projection, to prevent reading data from storage 1171 * that aren't going to be used. 1172 * 1173 * Provider must identify which QUERY_ARG_SORT* arguments were honored during 1174 * the preparation of the result set by including the respective argument keys 1175 * in the {@link Cursor} extras {@link Bundle}. See {@link #EXTRA_HONORED_ARGS} 1176 * for details. 1177 * 1178 * @see #QUERY_ARG_SORT_COLUMNS 1179 * @see #QUERY_ARG_SORT_DIRECTION 1180 * @see #QUERY_ARG_SORT_COLLATION 1181 * 1182 * @param uri The URI, using the content:// scheme, for the content to 1183 * retrieve. 1184 * @param projection A list of which columns to return. Passing null will 1185 * return all columns, which is inefficient. 1186 * @param queryArgs A Bundle containing additional information necessary for 1187 * the operation. Arguments may include SQL style arguments, such 1188 * as {@link ContentResolver#QUERY_ARG_SQL_LIMIT}, but note that 1189 * the documentation for each individual provider will indicate 1190 * which arguments they support. 1191 * @param cancellationSignal A signal to cancel the operation in progress, or null if none. 1192 * If the operation is canceled, then {@link OperationCanceledException} will be thrown 1193 * when the query is executed. 1194 * @return A Cursor object, which is positioned before the first entry. May return 1195 * <code>null</code> if the underlying content provider returns <code>null</code>, 1196 * or if it crashes. 1197 * @see Cursor 1198 */ 1199 @Override 1200 public final @Nullable Cursor query(final @RequiresPermission.Read @NonNull Uri uri, 1201 @Nullable String[] projection, @Nullable Bundle queryArgs, 1202 @Nullable CancellationSignal cancellationSignal) { 1203 Objects.requireNonNull(uri, "uri"); 1204 1205 try { 1206 if (mWrapped != null) { 1207 return mWrapped.query(uri, projection, queryArgs, cancellationSignal); 1208 } 1209 } catch (RemoteException e) { 1210 return null; 1211 } 1212 1213 IContentProvider unstableProvider = acquireUnstableProvider(uri); 1214 if (unstableProvider == null) { 1215 return null; 1216 } 1217 IContentProvider stableProvider = null; 1218 Cursor qCursor = null; 1219 try { 1220 long startTime = SystemClock.uptimeMillis(); 1221 1222 ICancellationSignal remoteCancellationSignal = null; 1223 if (cancellationSignal != null) { 1224 cancellationSignal.throwIfCanceled(); 1225 remoteCancellationSignal = unstableProvider.createCancellationSignal(); 1226 cancellationSignal.setRemote(remoteCancellationSignal); 1227 } 1228 try { 1229 qCursor = unstableProvider.query(mContext.getAttributionSource(), uri, projection, 1230 queryArgs, remoteCancellationSignal); 1231 } catch (DeadObjectException e) { 1232 // The remote process has died... but we only hold an unstable 1233 // reference though, so we might recover!!! Let's try!!!! 1234 // This is exciting!!1!!1!!!!1 1235 unstableProviderDied(unstableProvider); 1236 stableProvider = acquireProvider(uri); 1237 if (stableProvider == null) { 1238 return null; 1239 } 1240 qCursor = stableProvider.query(mContext.getAttributionSource(), uri, projection, 1241 queryArgs, remoteCancellationSignal); 1242 } 1243 if (qCursor == null) { 1244 return null; 1245 } 1246 1247 // Force query execution. Might fail and throw a runtime exception here. 1248 qCursor.getCount(); 1249 long durationMillis = SystemClock.uptimeMillis() - startTime; 1250 maybeLogQueryToEventLog(durationMillis, uri, projection, queryArgs); 1251 1252 // Wrap the cursor object into CursorWrapperInner object. 1253 final IContentProvider provider = (stableProvider != null) ? stableProvider 1254 : acquireProvider(uri); 1255 final CursorWrapperInner wrapper = new CursorWrapperInner(qCursor, provider); 1256 stableProvider = null; 1257 qCursor = null; 1258 return wrapper; 1259 } catch (RemoteException e) { 1260 // Arbitrary and not worth documenting, as Activity 1261 // Manager will kill this process shortly anyway. 1262 return null; 1263 } finally { 1264 if (qCursor != null) { 1265 qCursor.close(); 1266 } 1267 if (cancellationSignal != null) { 1268 cancellationSignal.setRemote(null); 1269 } 1270 if (unstableProvider != null) { 1271 releaseUnstableProvider(unstableProvider); 1272 } 1273 if (stableProvider != null) { 1274 releaseProvider(stableProvider); 1275 } 1276 } 1277 } 1278 1279 /** {@hide} */ 1280 public final @NonNull Uri canonicalizeOrElse(@NonNull Uri uri) { 1281 final Uri res = canonicalize(uri); 1282 return (res != null) ? res : uri; 1283 } 1284 1285 /** 1286 * Transform the given <var>url</var> to a canonical representation of 1287 * its referenced resource, which can be used across devices, persisted, 1288 * backed up and restored, etc. The returned Uri is still a fully capable 1289 * Uri for use with its content provider, allowing you to do all of the 1290 * same content provider operations as with the original Uri -- 1291 * {@link #query}, {@link #openInputStream(android.net.Uri)}, etc. The 1292 * only difference in behavior between the original and new Uris is that 1293 * the content provider may need to do some additional work at each call 1294 * using it to resolve it to the correct resource, especially if the 1295 * canonical Uri has been moved to a different environment. 1296 * 1297 * <p>If you are moving a canonical Uri between environments, you should 1298 * perform another call to {@link #canonicalize} with that original Uri to 1299 * re-canonicalize it for the current environment. Alternatively, you may 1300 * want to use {@link #uncanonicalize} to transform it to a non-canonical 1301 * Uri that works only in the current environment but potentially more 1302 * efficiently than the canonical representation.</p> 1303 * 1304 * @param url The {@link Uri} that is to be transformed to a canonical 1305 * representation. Like all resolver calls, the input can be either 1306 * a non-canonical or canonical Uri. 1307 * 1308 * @return Returns the official canonical representation of <var>url</var>, 1309 * or null if the content provider does not support a canonical representation 1310 * of the given Uri. Many providers may not support canonicalization of some 1311 * or all of their Uris. 1312 * 1313 * @see #uncanonicalize 1314 */ 1315 @Override 1316 public final @Nullable Uri canonicalize(@NonNull Uri url) { 1317 Objects.requireNonNull(url, "url"); 1318 1319 try { 1320 if (mWrapped != null) return mWrapped.canonicalize(url); 1321 } catch (RemoteException e) { 1322 return null; 1323 } 1324 1325 IContentProvider provider = acquireProvider(url); 1326 if (provider == null) { 1327 return null; 1328 } 1329 1330 try { 1331 final UriResultListener resultListener = new UriResultListener(); 1332 provider.canonicalizeAsync(mContext.getAttributionSource(), url, 1333 new RemoteCallback(resultListener)); 1334 resultListener.waitForResult(CONTENT_PROVIDER_TIMEOUT_MILLIS); 1335 if (resultListener.exception != null) { 1336 throw resultListener.exception; 1337 } 1338 return resultListener.result; 1339 } catch (RemoteException e) { 1340 // Arbitrary and not worth documenting, as Activity 1341 // Manager will kill this process shortly anyway. 1342 return null; 1343 } finally { 1344 releaseProvider(provider); 1345 } 1346 } 1347 1348 /** 1349 * Given a canonical Uri previously generated by {@link #canonicalize}, convert 1350 * it to its local non-canonical form. This can be useful in some cases where 1351 * you know that you will only be using the Uri in the current environment and 1352 * want to avoid any possible overhead when using it with the content 1353 * provider or want to verify that the referenced data exists at all in the 1354 * new environment. 1355 * 1356 * @param url The canonical {@link Uri} that is to be convered back to its 1357 * non-canonical form. 1358 * 1359 * @return Returns the non-canonical representation of <var>url</var>. This will 1360 * return null if data identified by the canonical Uri can not be found in 1361 * the current environment; callers must always check for null and deal with 1362 * that by appropriately falling back to an alternative. 1363 * 1364 * @see #canonicalize 1365 */ 1366 @Override 1367 public final @Nullable Uri uncanonicalize(@NonNull Uri url) { 1368 Objects.requireNonNull(url, "url"); 1369 1370 try { 1371 if (mWrapped != null) return mWrapped.uncanonicalize(url); 1372 } catch (RemoteException e) { 1373 return null; 1374 } 1375 1376 IContentProvider provider = acquireProvider(url); 1377 if (provider == null) { 1378 return null; 1379 } 1380 1381 try { 1382 final UriResultListener resultListener = new UriResultListener(); 1383 provider.uncanonicalizeAsync(mContext.getAttributionSource(), url, 1384 new RemoteCallback(resultListener)); 1385 resultListener.waitForResult(CONTENT_PROVIDER_TIMEOUT_MILLIS); 1386 if (resultListener.exception != null) { 1387 throw resultListener.exception; 1388 } 1389 return resultListener.result; 1390 } catch (RemoteException e) { 1391 // Arbitrary and not worth documenting, as Activity 1392 // Manager will kill this process shortly anyway. 1393 return null; 1394 } finally { 1395 releaseProvider(provider); 1396 } 1397 } 1398 1399 /** 1400 * This allows clients to request an explicit refresh of content identified 1401 * by {@code uri}. 1402 * <p> 1403 * Client code should only invoke this method when there is a strong 1404 * indication (such as a user initiated pull to refresh gesture) that the 1405 * content is stale. 1406 * <p> 1407 * 1408 * @param url The Uri identifying the data to refresh. 1409 * @param extras Additional options from the client. The definitions of 1410 * these are specific to the content provider being called. 1411 * @param cancellationSignal A signal to cancel the operation in progress, 1412 * or {@code null} if none. For example, if you called refresh on 1413 * a particular uri, you should call 1414 * {@link CancellationSignal#throwIfCanceled()} to check whether 1415 * the client has canceled the refresh request. 1416 * @return true if the provider actually tried refreshing. 1417 */ 1418 @Override 1419 public final boolean refresh(@NonNull Uri url, @Nullable Bundle extras, 1420 @Nullable CancellationSignal cancellationSignal) { 1421 Objects.requireNonNull(url, "url"); 1422 1423 try { 1424 if (mWrapped != null) return mWrapped.refresh(url, extras, cancellationSignal); 1425 } catch (RemoteException e) { 1426 return false; 1427 } 1428 1429 IContentProvider provider = acquireProvider(url); 1430 if (provider == null) { 1431 return false; 1432 } 1433 1434 try { 1435 ICancellationSignal remoteCancellationSignal = null; 1436 if (cancellationSignal != null) { 1437 cancellationSignal.throwIfCanceled(); 1438 remoteCancellationSignal = provider.createCancellationSignal(); 1439 cancellationSignal.setRemote(remoteCancellationSignal); 1440 } 1441 return provider.refresh(mContext.getAttributionSource(), url, extras, 1442 remoteCancellationSignal); 1443 } catch (RemoteException e) { 1444 // Arbitrary and not worth documenting, as Activity 1445 // Manager will kill this process shortly anyway. 1446 return false; 1447 } finally { 1448 releaseProvider(provider); 1449 } 1450 } 1451 1452 /** 1453 * Perform a detailed internal check on a {@link Uri} to determine if a UID 1454 * is able to access it with specific mode flags. 1455 * <p> 1456 * This method is typically used when the provider implements more dynamic 1457 * access controls that cannot be expressed with {@code <path-permission>} 1458 * style static rules. 1459 * <p> 1460 * Because validation of these dynamic access controls has significant 1461 * system health impact, this feature is only available to providers that 1462 * are built into the system. 1463 * 1464 * @param uri the {@link Uri} to perform an access check on. 1465 * @param uid the UID to check the permission for. 1466 * @param modeFlags the access flags to use for the access check, such as 1467 * {@link Intent#FLAG_GRANT_READ_URI_PERMISSION}. 1468 * @return {@link PackageManager#PERMISSION_GRANTED} if access is allowed, 1469 * otherwise {@link PackageManager#PERMISSION_DENIED}. 1470 * @hide 1471 */ 1472 @Override 1473 @SystemApi 1474 public int checkUriPermission(@NonNull Uri uri, int uid, @Intent.AccessUriMode int modeFlags) { 1475 Objects.requireNonNull(uri, "uri"); 1476 1477 try { 1478 if (mWrapped != null) return mWrapped.checkUriPermission(uri, uid, modeFlags); 1479 } catch (RemoteException e) { 1480 return PackageManager.PERMISSION_DENIED; 1481 } 1482 1483 try (ContentProviderClient client = acquireUnstableContentProviderClient(uri)) { 1484 return client.checkUriPermission(uri, uid, modeFlags); 1485 } catch (RemoteException e) { 1486 return PackageManager.PERMISSION_DENIED; 1487 } 1488 } 1489 1490 /** 1491 * Open a stream on to the content associated with a content URI. If there 1492 * is no data associated with the URI, FileNotFoundException is thrown. 1493 * 1494 * <h5>Accepts the following URI schemes:</h5> 1495 * <ul> 1496 * <li>content ({@link #SCHEME_CONTENT})</li> 1497 * <li>android.resource ({@link #SCHEME_ANDROID_RESOURCE})</li> 1498 * <li>file ({@link #SCHEME_FILE})</li> 1499 * </ul> 1500 * 1501 * <p>See {@link #openAssetFileDescriptor(Uri, String)} for more information 1502 * on these schemes. 1503 * 1504 * @param uri The desired URI. 1505 * @return InputStream or {@code null} if the provider recently crashed. 1506 * @throws FileNotFoundException if the provided URI could not be opened. 1507 * @see #openAssetFileDescriptor(Uri, String) 1508 */ 1509 public final @Nullable InputStream openInputStream(@NonNull Uri uri) 1510 throws FileNotFoundException { 1511 Objects.requireNonNull(uri, "uri"); 1512 String scheme = uri.getScheme(); 1513 if (SCHEME_ANDROID_RESOURCE.equals(scheme)) { 1514 // Note: left here to avoid breaking compatibility. May be removed 1515 // with sufficient testing. 1516 OpenResourceIdResult r = getResourceId(uri); 1517 try { 1518 InputStream stream = r.r.openRawResource(r.id); 1519 return stream; 1520 } catch (Resources.NotFoundException ex) { 1521 throw new FileNotFoundException("Resource does not exist: " + uri); 1522 } 1523 } else if (SCHEME_FILE.equals(scheme)) { 1524 // Note: left here to avoid breaking compatibility. May be removed 1525 // with sufficient testing. 1526 return new FileInputStream(uri.getPath()); 1527 } else { 1528 AssetFileDescriptor fd = openAssetFileDescriptor(uri, "r", null); 1529 try { 1530 return fd != null ? fd.createInputStream() : null; 1531 } catch (IOException e) { 1532 throw new FileNotFoundException("Unable to create stream"); 1533 } 1534 } 1535 } 1536 1537 /** 1538 * Synonym for {@link #openOutputStream(Uri, String) 1539 * openOutputStream(uri, "w")}. Please note the implementation of "w" is up to each 1540 * Provider implementation and it may or may not truncate. 1541 * 1542 * @param uri The desired URI. 1543 * @return an OutputStream or {@code null} if the provider recently crashed. 1544 * @throws FileNotFoundException if the provided URI could not be opened. 1545 */ 1546 public final @Nullable OutputStream openOutputStream(@NonNull Uri uri) 1547 throws FileNotFoundException { 1548 return openOutputStream(uri, "w"); 1549 } 1550 1551 /** 1552 * Open a stream on to the content associated with a content URI. If there 1553 * is no data associated with the URI, FileNotFoundException is thrown. 1554 * 1555 * <h5>Accepts the following URI schemes:</h5> 1556 * <ul> 1557 * <li>content ({@link #SCHEME_CONTENT})</li> 1558 * <li>file ({@link #SCHEME_FILE})</li> 1559 * </ul> 1560 * 1561 * <p>See {@link #openAssetFileDescriptor(Uri, String)} for more information 1562 * on these schemes. 1563 * 1564 * @param uri The desired URI. 1565 * @param mode The string representation of the file mode. Can be "r", "w", "wt", "wa", "rw" 1566 * or "rwt". Please note the exact implementation of these may differ for each 1567 * Provider implementation - for example, "w" may or may not truncate. 1568 * @return an OutputStream or {@code null} if the provider recently crashed. 1569 * @throws FileNotFoundException if the provided URI could not be opened. 1570 * @see #openAssetFileDescriptor(Uri, String) 1571 */ 1572 public final @Nullable OutputStream openOutputStream(@NonNull Uri uri, @NonNull String mode) 1573 throws FileNotFoundException { 1574 AssetFileDescriptor fd = openAssetFileDescriptor(uri, mode, null); 1575 try { 1576 return fd != null ? fd.createOutputStream() : null; 1577 } catch (IOException e) { 1578 throw new FileNotFoundException("Unable to create stream"); 1579 } 1580 } 1581 1582 @Override 1583 public final @Nullable ParcelFileDescriptor openFile(@NonNull Uri uri, @NonNull String mode, 1584 @Nullable CancellationSignal signal) throws FileNotFoundException { 1585 try { 1586 if (mWrapped != null) return mWrapped.openFile(uri, mode, signal); 1587 } catch (RemoteException e) { 1588 return null; 1589 } 1590 1591 return openFileDescriptor(uri, mode, signal); 1592 } 1593 1594 /** 1595 * Open a raw file descriptor to access data under a URI. This 1596 * is like {@link #openAssetFileDescriptor(Uri, String)}, but uses the 1597 * underlying {@link ContentProvider#openFile} 1598 * ContentProvider.openFile()} method, so will <em>not</em> work with 1599 * providers that return sub-sections of files. If at all possible, 1600 * you should use {@link #openAssetFileDescriptor(Uri, String)}. You 1601 * will receive a FileNotFoundException exception if the provider returns a 1602 * sub-section of a file. 1603 * 1604 * <h5>Accepts the following URI schemes:</h5> 1605 * <ul> 1606 * <li>content ({@link #SCHEME_CONTENT})</li> 1607 * <li>file ({@link #SCHEME_FILE})</li> 1608 * </ul> 1609 * 1610 * <p>See {@link #openAssetFileDescriptor(Uri, String)} for more information 1611 * on these schemes. 1612 * <p> 1613 * If opening with the exclusive "r" or "w" modes, the returned 1614 * ParcelFileDescriptor could be a pipe or socket pair to enable streaming 1615 * of data. Opening with the "rw" mode implies a file on disk that supports 1616 * seeking. If possible, always use an exclusive mode to give the underlying 1617 * {@link ContentProvider} the most flexibility. 1618 * <p> 1619 * If you are writing a file, and need to communicate an error to the 1620 * provider, use {@link ParcelFileDescriptor#closeWithError(String)}. 1621 * 1622 * @param uri The desired URI to open. 1623 * @param mode The string representation of the file mode. Can be "r", "w", "wt", "wa", "rw" 1624 * or "rwt". Please note the exact implementation of these may differ for each 1625 * Provider implementation - for example, "w" may or may not truncate. 1626 * @return Returns a new ParcelFileDescriptor pointing to the file or {@code null} if the 1627 * provider recently crashed. You own this descriptor and are responsible for closing it 1628 * when done. 1629 * @throws FileNotFoundException Throws FileNotFoundException if no 1630 * file exists under the URI or the mode is invalid. 1631 * @see #openAssetFileDescriptor(Uri, String) 1632 */ 1633 public final @Nullable ParcelFileDescriptor openFileDescriptor(@NonNull Uri uri, 1634 @NonNull String mode) throws FileNotFoundException { 1635 return openFileDescriptor(uri, mode, null); 1636 } 1637 1638 /** 1639 * Open a raw file descriptor to access data under a URI. This 1640 * is like {@link #openAssetFileDescriptor(Uri, String)}, but uses the 1641 * underlying {@link ContentProvider#openFile} 1642 * ContentProvider.openFile()} method, so will <em>not</em> work with 1643 * providers that return sub-sections of files. If at all possible, 1644 * you should use {@link #openAssetFileDescriptor(Uri, String)}. You 1645 * will receive a FileNotFoundException exception if the provider returns a 1646 * sub-section of a file. 1647 * 1648 * <h5>Accepts the following URI schemes:</h5> 1649 * <ul> 1650 * <li>content ({@link #SCHEME_CONTENT})</li> 1651 * <li>file ({@link #SCHEME_FILE})</li> 1652 * </ul> 1653 * 1654 * <p>See {@link #openAssetFileDescriptor(Uri, String)} for more information 1655 * on these schemes. 1656 * <p> 1657 * If opening with the exclusive "r" or "w" modes, the returned 1658 * ParcelFileDescriptor could be a pipe or socket pair to enable streaming 1659 * of data. Opening with the "rw" mode implies a file on disk that supports 1660 * seeking. If possible, always use an exclusive mode to give the underlying 1661 * {@link ContentProvider} the most flexibility. 1662 * <p> 1663 * If you are writing a file, and need to communicate an error to the 1664 * provider, use {@link ParcelFileDescriptor#closeWithError(String)}. 1665 * 1666 * @param uri The desired URI to open. 1667 * @param mode The string representation of the file mode. Can be "r", "w", "wt", "wa", "rw" 1668 * or "rwt". Please note the exact implementation of these may differ for each 1669 * Provider implementation - for example, "w" may or may not truncate. 1670 * @param cancellationSignal A signal to cancel the operation in progress, 1671 * or null if none. If the operation is canceled, then 1672 * {@link OperationCanceledException} will be thrown. 1673 * @return Returns a new ParcelFileDescriptor pointing to the file or {@code null} if the 1674 * provider recently crashed. You own this descriptor and are responsible for closing it 1675 * when done. 1676 * @throws FileNotFoundException Throws FileNotFoundException if no 1677 * file exists under the URI or the mode is invalid. 1678 * @see #openAssetFileDescriptor(Uri, String) 1679 */ 1680 public final @Nullable ParcelFileDescriptor openFileDescriptor(@NonNull Uri uri, 1681 @NonNull String mode, @Nullable CancellationSignal cancellationSignal) 1682 throws FileNotFoundException { 1683 try { 1684 if (mWrapped != null) return mWrapped.openFile(uri, mode, cancellationSignal); 1685 } catch (RemoteException e) { 1686 return null; 1687 } 1688 1689 AssetFileDescriptor afd = openAssetFileDescriptor(uri, mode, cancellationSignal); 1690 if (afd == null) { 1691 return null; 1692 } 1693 1694 if (afd.getDeclaredLength() < 0) { 1695 // This is a full file! 1696 return afd.getParcelFileDescriptor(); 1697 } 1698 1699 // Client can't handle a sub-section of a file, so close what 1700 // we got and bail with an exception. 1701 try { 1702 afd.close(); 1703 } catch (IOException e) { 1704 } 1705 1706 throw new FileNotFoundException("Not a whole file"); 1707 } 1708 1709 @Override 1710 public final @Nullable AssetFileDescriptor openAssetFile(@NonNull Uri uri, @NonNull String mode, 1711 @Nullable CancellationSignal signal) throws FileNotFoundException { 1712 try { 1713 if (mWrapped != null) return mWrapped.openAssetFile(uri, mode, signal); 1714 } catch (RemoteException e) { 1715 return null; 1716 } 1717 1718 return openAssetFileDescriptor(uri, mode, signal); 1719 } 1720 1721 /** 1722 * Open a raw file descriptor to access data under a URI. This 1723 * interacts with the underlying {@link ContentProvider#openAssetFile} 1724 * method of the provider associated with the given URI, to retrieve any file stored there. 1725 * 1726 * <h5>Accepts the following URI schemes:</h5> 1727 * <ul> 1728 * <li>content ({@link #SCHEME_CONTENT})</li> 1729 * <li>android.resource ({@link #SCHEME_ANDROID_RESOURCE})</li> 1730 * <li>file ({@link #SCHEME_FILE})</li> 1731 * </ul> 1732 * <h5>The android.resource ({@link #SCHEME_ANDROID_RESOURCE}) Scheme</h5> 1733 * <p> 1734 * A Uri object can be used to reference a resource in an APK file. The 1735 * Uri should be one of the following formats: 1736 * <ul> 1737 * <li><code>android.resource://package_name/id_number</code><br/> 1738 * <code>package_name</code> is your package name as listed in your AndroidManifest.xml. 1739 * For example <code>com.example.myapp</code><br/> 1740 * <code>id_number</code> is the int form of the ID.<br/> 1741 * The easiest way to construct this form is 1742 * <pre>Uri uri = Uri.parse("android.resource://com.example.myapp/" + R.raw.my_resource");</pre> 1743 * </li> 1744 * <li><code>android.resource://package_name/type/name</code><br/> 1745 * <code>package_name</code> is your package name as listed in your AndroidManifest.xml. 1746 * For example <code>com.example.myapp</code><br/> 1747 * <code>type</code> is the string form of the resource type. For example, <code>raw</code> 1748 * or <code>drawable</code>. 1749 * <code>name</code> is the string form of the resource name. That is, whatever the file 1750 * name was in your res directory, without the type extension. 1751 * The easiest way to construct this form is 1752 * <pre>Uri uri = Uri.parse("android.resource://com.example.myapp/raw/my_resource");</pre> 1753 * </li> 1754 * </ul> 1755 * 1756 * <p>Note that if this function is called for read-only input (mode is "r") 1757 * on a content: URI, it will instead call {@link #openTypedAssetFileDescriptor} 1758 * for you with a MIME type of "*/*". This allows such callers to benefit 1759 * from any built-in data conversion that a provider implements. 1760 * 1761 * @param uri The desired URI to open. 1762 * @param mode The string representation of the file mode. Can be "r", "w", "wt", "wa", "rw" 1763 * or "rwt". Please note the exact implementation of these may differ for each 1764 * Provider implementation - for example, "w" may or may not truncate. 1765 * @return Returns a new ParcelFileDescriptor pointing to the file or {@code null} if the 1766 * provider recently crashed. You own this descriptor and are responsible for closing it 1767 * when done. 1768 * @throws FileNotFoundException Throws FileNotFoundException of no 1769 * file exists under the URI or the mode is invalid. 1770 */ 1771 public final @Nullable AssetFileDescriptor openAssetFileDescriptor(@NonNull Uri uri, 1772 @NonNull String mode) throws FileNotFoundException { 1773 return openAssetFileDescriptor(uri, mode, null); 1774 } 1775 1776 /** 1777 * Open a raw file descriptor to access data under a URI. This 1778 * interacts with the underlying {@link ContentProvider#openAssetFile} 1779 * method of the provider associated with the given URI, to retrieve any file stored there. 1780 * 1781 * <h5>Accepts the following URI schemes:</h5> 1782 * <ul> 1783 * <li>content ({@link #SCHEME_CONTENT})</li> 1784 * <li>android.resource ({@link #SCHEME_ANDROID_RESOURCE})</li> 1785 * <li>file ({@link #SCHEME_FILE})</li> 1786 * </ul> 1787 * <h5>The android.resource ({@link #SCHEME_ANDROID_RESOURCE}) Scheme</h5> 1788 * <p> 1789 * A Uri object can be used to reference a resource in an APK file. The 1790 * Uri should be one of the following formats: 1791 * <ul> 1792 * <li><code>android.resource://package_name/id_number</code><br/> 1793 * <code>package_name</code> is your package name as listed in your AndroidManifest.xml. 1794 * For example <code>com.example.myapp</code><br/> 1795 * <code>id_number</code> is the int form of the ID.<br/> 1796 * The easiest way to construct this form is 1797 * <pre>Uri uri = Uri.parse("android.resource://com.example.myapp/" + R.raw.my_resource");</pre> 1798 * </li> 1799 * <li><code>android.resource://package_name/type/name</code><br/> 1800 * <code>package_name</code> is your package name as listed in your AndroidManifest.xml. 1801 * For example <code>com.example.myapp</code><br/> 1802 * <code>type</code> is the string form of the resource type. For example, <code>raw</code> 1803 * or <code>drawable</code>. 1804 * <code>name</code> is the string form of the resource name. That is, whatever the file 1805 * name was in your res directory, without the type extension. 1806 * The easiest way to construct this form is 1807 * <pre>Uri uri = Uri.parse("android.resource://com.example.myapp/raw/my_resource");</pre> 1808 * </li> 1809 * </ul> 1810 * 1811 * <p>Note that if this function is called for read-only input (mode is "r") 1812 * on a content: URI, it will instead call {@link #openTypedAssetFileDescriptor} 1813 * for you with a MIME type of "*/*". This allows such callers to benefit 1814 * from any built-in data conversion that a provider implements. 1815 * 1816 * @param uri The desired URI to open. 1817 * @param mode The string representation of the file mode. Can be "r", "w", "wt", "wa", "rw" 1818 * or "rwt". Please note "w" is write only and "wt" is write and truncate. 1819 * See{@link ParcelFileDescriptor#parseMode} for more details. 1820 * @param cancellationSignal A signal to cancel the operation in progress, or null if 1821 * none. If the operation is canceled, then 1822 * {@link OperationCanceledException} will be thrown. 1823 * @return Returns a new ParcelFileDescriptor pointing to the file or {@code null} if the 1824 * provider recently crashed. You own this descriptor and are responsible for closing it 1825 * when done. 1826 * @throws FileNotFoundException Throws FileNotFoundException of no 1827 * file exists under the URI or the mode is invalid. 1828 */ 1829 public final @Nullable AssetFileDescriptor openAssetFileDescriptor(@NonNull Uri uri, 1830 @NonNull String mode, @Nullable CancellationSignal cancellationSignal) 1831 throws FileNotFoundException { 1832 Objects.requireNonNull(uri, "uri"); 1833 Objects.requireNonNull(mode, "mode"); 1834 1835 try { 1836 if (mWrapped != null) return mWrapped.openAssetFile(uri, mode, cancellationSignal); 1837 } catch (RemoteException e) { 1838 return null; 1839 } 1840 1841 String scheme = uri.getScheme(); 1842 if (SCHEME_ANDROID_RESOURCE.equals(scheme)) { 1843 if (!"r".equals(mode)) { 1844 throw new FileNotFoundException("Can't write resources: " + uri); 1845 } 1846 OpenResourceIdResult r = getResourceId(uri); 1847 try { 1848 return r.r.openRawResourceFd(r.id); 1849 } catch (Resources.NotFoundException ex) { 1850 throw new FileNotFoundException("Resource does not exist: " + uri); 1851 } 1852 } else if (SCHEME_FILE.equals(scheme)) { 1853 ParcelFileDescriptor pfd = ParcelFileDescriptor.open( 1854 new File(uri.getPath()), ParcelFileDescriptor.parseMode(mode)); 1855 return new AssetFileDescriptor(pfd, 0, -1); 1856 } else { 1857 if ("r".equals(mode)) { 1858 return openTypedAssetFileDescriptor(uri, "*/*", null, cancellationSignal); 1859 } else { 1860 IContentProvider unstableProvider = acquireUnstableProvider(uri); 1861 if (unstableProvider == null) { 1862 throw new FileNotFoundException("No content provider: " + uri); 1863 } 1864 IContentProvider stableProvider = null; 1865 AssetFileDescriptor fd = null; 1866 1867 try { 1868 ICancellationSignal remoteCancellationSignal = null; 1869 if (cancellationSignal != null) { 1870 cancellationSignal.throwIfCanceled(); 1871 remoteCancellationSignal = unstableProvider.createCancellationSignal(); 1872 cancellationSignal.setRemote(remoteCancellationSignal); 1873 } 1874 1875 try { 1876 fd = unstableProvider.openAssetFile( 1877 mContext.getAttributionSource(), uri, mode, 1878 remoteCancellationSignal); 1879 if (fd == null) { 1880 // The provider will be released by the finally{} clause 1881 return null; 1882 } 1883 } catch (DeadObjectException e) { 1884 // The remote process has died... but we only hold an unstable 1885 // reference though, so we might recover!!! Let's try!!!! 1886 // This is exciting!!1!!1!!!!1 1887 unstableProviderDied(unstableProvider); 1888 stableProvider = acquireProvider(uri); 1889 if (stableProvider == null) { 1890 throw new FileNotFoundException("No content provider: " + uri); 1891 } 1892 fd = stableProvider.openAssetFile(mContext.getAttributionSource(), 1893 uri, mode, remoteCancellationSignal); 1894 if (fd == null) { 1895 // The provider will be released by the finally{} clause 1896 return null; 1897 } 1898 } 1899 1900 if (stableProvider == null) { 1901 stableProvider = acquireProvider(uri); 1902 } 1903 releaseUnstableProvider(unstableProvider); 1904 unstableProvider = null; 1905 ParcelFileDescriptor pfd = new ParcelFileDescriptorInner( 1906 fd.getParcelFileDescriptor(), stableProvider); 1907 1908 // Success! Don't release the provider when exiting, let 1909 // ParcelFileDescriptorInner do that when it is closed. 1910 stableProvider = null; 1911 1912 return new AssetFileDescriptor(pfd, fd.getStartOffset(), 1913 fd.getDeclaredLength()); 1914 1915 } catch (RemoteException e) { 1916 // Whatever, whatever, we'll go away. 1917 throw new FileNotFoundException( 1918 "Failed opening content provider: " + uri); 1919 } catch (FileNotFoundException e) { 1920 throw e; 1921 } finally { 1922 if (cancellationSignal != null) { 1923 cancellationSignal.setRemote(null); 1924 } 1925 if (stableProvider != null) { 1926 releaseProvider(stableProvider); 1927 } 1928 if (unstableProvider != null) { 1929 releaseUnstableProvider(unstableProvider); 1930 } 1931 } 1932 } 1933 } 1934 } 1935 1936 @Override 1937 public final @Nullable AssetFileDescriptor openTypedAssetFile(@NonNull Uri uri, 1938 @NonNull String mimeTypeFilter, @Nullable Bundle opts, 1939 @Nullable CancellationSignal signal) throws FileNotFoundException { 1940 try { 1941 if (mWrapped != null) { 1942 return mWrapped.openTypedAssetFile(uri, mimeTypeFilter, opts, signal); 1943 } 1944 } catch (RemoteException e) { 1945 return null; 1946 } 1947 1948 return openTypedAssetFileDescriptor(uri, mimeTypeFilter, opts, signal); 1949 } 1950 1951 /** 1952 * Open a raw file descriptor to access (potentially type transformed) 1953 * data from a "content:" URI. This interacts with the underlying 1954 * {@link ContentProvider#openTypedAssetFile} method of the provider 1955 * associated with the given URI, to retrieve retrieve any appropriate 1956 * data stream for the data stored there. 1957 * 1958 * <p>Unlike {@link #openAssetFileDescriptor}, this function only works 1959 * with "content:" URIs, because content providers are the only facility 1960 * with an associated MIME type to ensure that the returned data stream 1961 * is of the desired type. 1962 * 1963 * <p>All text/* streams are encoded in UTF-8. 1964 * 1965 * @param uri The desired URI to open. 1966 * @param mimeType The desired MIME type of the returned data. This can 1967 * be a pattern such as */*, which will allow the content provider to 1968 * select a type, though there is no way for you to determine what type 1969 * it is returning. 1970 * @param opts Additional provider-dependent options. 1971 * @return Returns a new ParcelFileDescriptor from which you can read the 1972 * data stream from the provider or {@code null} if the provider recently crashed. 1973 * Note that this may be a pipe, meaning you can't seek in it. The only seek you 1974 * should do is if the AssetFileDescriptor contains an offset, to move to that offset before 1975 * reading. You own this descriptor and are responsible for closing it when done. 1976 * @throws FileNotFoundException Throws FileNotFoundException of no 1977 * data of the desired type exists under the URI. 1978 */ 1979 public final @Nullable AssetFileDescriptor openTypedAssetFileDescriptor(@NonNull Uri uri, 1980 @NonNull String mimeType, @Nullable Bundle opts) throws FileNotFoundException { 1981 return openTypedAssetFileDescriptor(uri, mimeType, opts, null); 1982 } 1983 1984 /** 1985 * Open a raw file descriptor to access (potentially type transformed) 1986 * data from a "content:" URI. This interacts with the underlying 1987 * {@link ContentProvider#openTypedAssetFile} method of the provider 1988 * associated with the given URI, to retrieve any appropriate 1989 * data stream for the data stored there. 1990 * 1991 * <p>Unlike {@link #openAssetFileDescriptor}, this function only works 1992 * with "content:" URIs, because content providers are the only facility 1993 * with an associated MIME type to ensure that the returned data stream 1994 * is of the desired type. 1995 * 1996 * <p>All text/* streams are encoded in UTF-8. 1997 * 1998 * @param uri The desired URI to open. 1999 * @param mimeType The desired MIME type of the returned data. This can 2000 * be a pattern such as */*, which will allow the content provider to 2001 * select a type, though there is no way for you to determine what type 2002 * it is returning. 2003 * @param opts Additional provider-dependent options. 2004 * @param cancellationSignal A signal to cancel the operation in progress, 2005 * or null if none. If the operation is canceled, then 2006 * {@link OperationCanceledException} will be thrown. 2007 * @return Returns a new ParcelFileDescriptor from which you can read the 2008 * data stream from the provider or {@code null} if the provider recently crashed. 2009 * Note that this may be a pipe, meaning you can't seek in it. The only seek you 2010 * should do is if the AssetFileDescriptor contains an offset, to move to that offset before 2011 * reading. You own this descriptor and are responsible for closing it when done. 2012 * @throws FileNotFoundException Throws FileNotFoundException of no 2013 * data of the desired type exists under the URI. 2014 */ 2015 public final @Nullable AssetFileDescriptor openTypedAssetFileDescriptor(@NonNull Uri uri, 2016 @NonNull String mimeType, @Nullable Bundle opts, 2017 @Nullable CancellationSignal cancellationSignal) throws FileNotFoundException { 2018 Objects.requireNonNull(uri, "uri"); 2019 Objects.requireNonNull(mimeType, "mimeType"); 2020 2021 try { 2022 if (mWrapped != null) return mWrapped.openTypedAssetFile(uri, mimeType, opts, cancellationSignal); 2023 } catch (RemoteException e) { 2024 return null; 2025 } 2026 2027 IContentProvider unstableProvider = acquireUnstableProvider(uri); 2028 if (unstableProvider == null) { 2029 throw new FileNotFoundException("No content provider: " + uri); 2030 } 2031 IContentProvider stableProvider = null; 2032 AssetFileDescriptor fd = null; 2033 2034 try { 2035 ICancellationSignal remoteCancellationSignal = null; 2036 if (cancellationSignal != null) { 2037 cancellationSignal.throwIfCanceled(); 2038 remoteCancellationSignal = unstableProvider.createCancellationSignal(); 2039 cancellationSignal.setRemote(remoteCancellationSignal); 2040 } 2041 2042 try { 2043 fd = unstableProvider.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 } catch (DeadObjectException e) { 2051 // The remote process has died... but we only hold an unstable 2052 // reference though, so we might recover!!! Let's try!!!! 2053 // This is exciting!!1!!1!!!!1 2054 unstableProviderDied(unstableProvider); 2055 stableProvider = acquireProvider(uri); 2056 if (stableProvider == null) { 2057 throw new FileNotFoundException("No content provider: " + uri); 2058 } 2059 fd = stableProvider.openTypedAssetFile( 2060 mContext.getAttributionSource(), uri, mimeType, opts, 2061 remoteCancellationSignal); 2062 if (fd == null) { 2063 // The provider will be released by the finally{} clause 2064 return null; 2065 } 2066 } 2067 2068 if (stableProvider == null) { 2069 stableProvider = acquireProvider(uri); 2070 } 2071 releaseUnstableProvider(unstableProvider); 2072 unstableProvider = null; 2073 ParcelFileDescriptor pfd = new ParcelFileDescriptorInner( 2074 fd.getParcelFileDescriptor(), stableProvider); 2075 2076 // Success! Don't release the provider when exiting, let 2077 // ParcelFileDescriptorInner do that when it is closed. 2078 stableProvider = null; 2079 2080 return new AssetFileDescriptor(pfd, fd.getStartOffset(), 2081 fd.getDeclaredLength(), fd.getExtras()); 2082 2083 } catch (RemoteException e) { 2084 // Whatever, whatever, we'll go away. 2085 throw new FileNotFoundException( 2086 "Failed opening content provider: " + uri); 2087 } catch (FileNotFoundException e) { 2088 throw e; 2089 } finally { 2090 if (cancellationSignal != null) { 2091 cancellationSignal.setRemote(null); 2092 } 2093 if (stableProvider != null) { 2094 releaseProvider(stableProvider); 2095 } 2096 if (unstableProvider != null) { 2097 releaseUnstableProvider(unstableProvider); 2098 } 2099 } 2100 } 2101 2102 /** 2103 * A resource identified by the {@link Resources} that contains it, and a resource id. 2104 * 2105 * @hide 2106 */ 2107 public class OpenResourceIdResult { 2108 @UnsupportedAppUsage 2109 public Resources r; 2110 @UnsupportedAppUsage 2111 public int id; 2112 } 2113 2114 /** 2115 * Resolves an android.resource URI to a {@link Resources} and a resource id. 2116 * 2117 * @hide 2118 */ 2119 @UnsupportedAppUsage 2120 public OpenResourceIdResult getResourceId(Uri uri) throws FileNotFoundException { 2121 String authority = uri.getAuthority(); 2122 Resources r; 2123 if (TextUtils.isEmpty(authority)) { 2124 throw new FileNotFoundException("No authority: " + uri); 2125 } else { 2126 try { 2127 r = mContext.getPackageManager().getResourcesForApplication(authority); 2128 } catch (NameNotFoundException ex) { 2129 throw new FileNotFoundException("No package found for authority: " + uri); 2130 } 2131 } 2132 List<String> path = uri.getPathSegments(); 2133 if (path == null) { 2134 throw new FileNotFoundException("No path: " + uri); 2135 } 2136 int len = path.size(); 2137 int id; 2138 if (len == 1) { 2139 try { 2140 id = Integer.parseInt(path.get(0)); 2141 } catch (NumberFormatException e) { 2142 throw new FileNotFoundException("Single path segment is not a resource ID: " + uri); 2143 } 2144 } else if (len == 2) { 2145 id = r.getIdentifier(path.get(1), path.get(0), authority); 2146 } else { 2147 throw new FileNotFoundException("More than two path segments: " + uri); 2148 } 2149 if (id == 0) { 2150 throw new FileNotFoundException("No resource found for: " + uri); 2151 } 2152 OpenResourceIdResult res = new OpenResourceIdResult(); 2153 res.r = r; 2154 res.id = id; 2155 return res; 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 * @return the URL of the newly created row. May return <code>null</code> if the underlying 2167 * content provider returns <code>null</code>, or if it crashes. 2168 */ 2169 public final @Nullable Uri insert(@RequiresPermission.Write @NonNull Uri url, 2170 @Nullable ContentValues values) { 2171 return insert(url, values, null); 2172 } 2173 2174 /** 2175 * Inserts a row into a table at the given URL. 2176 * 2177 * If the content provider supports transactions the insertion will be atomic. 2178 * 2179 * @param url The URL of the table to insert into. 2180 * @param values The initial values for the newly inserted row. The key is the column name for 2181 * the field. Passing an empty ContentValues will create an empty row. 2182 * @param extras A Bundle containing additional information necessary for 2183 * the operation. Arguments may include SQL style arguments, such 2184 * as {@link ContentResolver#QUERY_ARG_SQL_LIMIT}, but note that 2185 * the documentation for each individual provider will indicate 2186 * which arguments they support. 2187 * @return the URL of the newly created row. May return <code>null</code> if the underlying 2188 * content provider returns <code>null</code>, or if it crashes. 2189 * @throws IllegalArgumentException if the provider doesn't support one of 2190 * the requested Bundle arguments. 2191 */ 2192 @Override 2193 public final @Nullable Uri insert(@RequiresPermission.Write @NonNull Uri url, 2194 @Nullable ContentValues values, @Nullable Bundle extras) { 2195 Objects.requireNonNull(url, "url"); 2196 2197 try { 2198 if (mWrapped != null) return mWrapped.insert(url, values, extras); 2199 } catch (RemoteException e) { 2200 return null; 2201 } 2202 2203 IContentProvider provider = acquireProvider(url); 2204 if (provider == null) { 2205 throw new IllegalArgumentException("Unknown URL " + url); 2206 } 2207 try { 2208 long startTime = SystemClock.uptimeMillis(); 2209 Uri createdRow = provider.insert(mContext.getAttributionSource(), url, values, extras); 2210 long durationMillis = SystemClock.uptimeMillis() - startTime; 2211 maybeLogUpdateToEventLog(durationMillis, url, "insert", null /* where */); 2212 return createdRow; 2213 } catch (RemoteException e) { 2214 // Arbitrary and not worth documenting, as Activity 2215 // Manager will kill this process shortly anyway. 2216 return null; 2217 } finally { 2218 releaseProvider(provider); 2219 } 2220 } 2221 2222 /** 2223 * Applies each of the {@link ContentProviderOperation} objects and returns an array 2224 * of their results. Passes through OperationApplicationException, which may be thrown 2225 * by the call to {@link ContentProviderOperation#apply}. 2226 * If all the applications succeed then a {@link ContentProviderResult} array with the 2227 * same number of elements as the operations will be returned. It is implementation-specific 2228 * how many, if any, operations will have been successfully applied if a call to 2229 * apply results in a {@link OperationApplicationException}. 2230 * @param authority the authority of the ContentProvider to which this batch should be applied 2231 * @param operations the operations to apply 2232 * @return the results of the applications 2233 * @throws OperationApplicationException thrown if an application fails. 2234 * See {@link ContentProviderOperation#apply} for more information. 2235 * @throws RemoteException thrown if a RemoteException is encountered while attempting 2236 * to communicate with a remote provider. 2237 */ 2238 @Override 2239 public @NonNull ContentProviderResult[] applyBatch(@NonNull String authority, 2240 @NonNull ArrayList<ContentProviderOperation> operations) 2241 throws RemoteException, OperationApplicationException { 2242 Objects.requireNonNull(authority, "authority"); 2243 Objects.requireNonNull(operations, "operations"); 2244 2245 try { 2246 if (mWrapped != null) return mWrapped.applyBatch(authority, operations); 2247 } catch (RemoteException e) { 2248 return null; 2249 } 2250 2251 ContentProviderClient provider = acquireContentProviderClient(authority); 2252 if (provider == null) { 2253 throw new IllegalArgumentException("Unknown authority " + authority); 2254 } 2255 try { 2256 return provider.applyBatch(operations); 2257 } finally { 2258 provider.release(); 2259 } 2260 } 2261 2262 /** 2263 * Inserts multiple rows into a table at the given URL. 2264 * 2265 * This function make no guarantees about the atomicity of the insertions. 2266 * 2267 * @param url The URL of the table to insert into. 2268 * @param values The initial values for the newly inserted rows. The key is the column name for 2269 * the field. Passing null will create an empty row. 2270 * @return the number of newly created rows. 2271 */ 2272 @Override 2273 public final int bulkInsert(@RequiresPermission.Write @NonNull Uri url, 2274 @NonNull ContentValues[] values) { 2275 Objects.requireNonNull(url, "url"); 2276 Objects.requireNonNull(values, "values"); 2277 2278 try { 2279 if (mWrapped != null) return mWrapped.bulkInsert(url, values); 2280 } catch (RemoteException e) { 2281 return 0; 2282 } 2283 2284 IContentProvider provider = acquireProvider(url); 2285 if (provider == null) { 2286 throw new IllegalArgumentException("Unknown URL " + url); 2287 } 2288 try { 2289 long startTime = SystemClock.uptimeMillis(); 2290 int rowsCreated = provider.bulkInsert(mContext.getAttributionSource(), url, values); 2291 long durationMillis = SystemClock.uptimeMillis() - startTime; 2292 maybeLogUpdateToEventLog(durationMillis, url, "bulkinsert", null /* where */); 2293 return rowsCreated; 2294 } catch (RemoteException e) { 2295 // Arbitrary and not worth documenting, as Activity 2296 // Manager will kill this process shortly anyway. 2297 return 0; 2298 } finally { 2299 releaseProvider(provider); 2300 } 2301 } 2302 2303 /** 2304 * Deletes row(s) specified by a content URI. 2305 * 2306 * If the content provider supports transactions, the deletion will be atomic. 2307 * 2308 * @param url The URL of the row to delete. 2309 * @param where A filter to apply to rows before deleting, formatted as an SQL WHERE clause 2310 (excluding the WHERE itself). 2311 * @return The number of rows deleted. 2312 */ 2313 public final int delete(@RequiresPermission.Write @NonNull Uri url, @Nullable String where, 2314 @Nullable String[] selectionArgs) { 2315 return delete(url, createSqlQueryBundle(where, selectionArgs)); 2316 } 2317 2318 /** 2319 * Deletes row(s) specified by a content URI. 2320 * 2321 * If the content provider supports transactions, the deletion will be atomic. 2322 * 2323 * @param url The URL of the row to delete. 2324 * @param extras A Bundle containing additional information necessary for 2325 * the operation. Arguments may include SQL style arguments, such 2326 * as {@link ContentResolver#QUERY_ARG_SQL_LIMIT}, but note that 2327 * the documentation for each individual provider will indicate 2328 * which arguments they support. 2329 * @return The number of rows deleted. 2330 * @throws IllegalArgumentException if the provider doesn't support one of 2331 * the requested Bundle arguments. 2332 */ 2333 @Override 2334 public final int delete(@RequiresPermission.Write @NonNull Uri url, @Nullable Bundle extras) { 2335 Objects.requireNonNull(url, "url"); 2336 2337 try { 2338 if (mWrapped != null) return mWrapped.delete(url, extras); 2339 } catch (RemoteException e) { 2340 return 0; 2341 } 2342 2343 IContentProvider provider = acquireProvider(url); 2344 if (provider == null) { 2345 throw new IllegalArgumentException("Unknown URL " + url); 2346 } 2347 try { 2348 long startTime = SystemClock.uptimeMillis(); 2349 int rowsDeleted = provider.delete(mContext.getAttributionSource(), url, extras); 2350 long durationMillis = SystemClock.uptimeMillis() - startTime; 2351 maybeLogUpdateToEventLog(durationMillis, url, "delete", null); 2352 return rowsDeleted; 2353 } catch (RemoteException e) { 2354 // Arbitrary and not worth documenting, as Activity 2355 // Manager will kill this process shortly anyway. 2356 return -1; 2357 } finally { 2358 releaseProvider(provider); 2359 } 2360 } 2361 2362 /** 2363 * Update row(s) in a content URI. 2364 * 2365 * If the content provider supports transactions the update will be atomic. 2366 * 2367 * @param uri The URI to modify. 2368 * @param values The new field values. The key is the column name for the field. 2369 A null value will remove an existing field value. 2370 * @param where A filter to apply to rows before updating, formatted as an SQL WHERE clause 2371 (excluding the WHERE itself). 2372 * @return the number of rows updated. 2373 * @throws NullPointerException if uri or values are null 2374 */ 2375 public final int update(@RequiresPermission.Write @NonNull Uri uri, 2376 @Nullable ContentValues values, @Nullable String where, 2377 @Nullable String[] selectionArgs) { 2378 return update(uri, values, createSqlQueryBundle(where, selectionArgs)); 2379 } 2380 2381 /** 2382 * Update row(s) in a content URI. 2383 * 2384 * If the content provider supports transactions the update will be atomic. 2385 * 2386 * @param uri The URI to modify. 2387 * @param values The new field values. The key is the column name for the field. 2388 A null value will remove an existing field value. 2389 * @param extras A Bundle containing additional information necessary for 2390 * the operation. Arguments may include SQL style arguments, such 2391 * as {@link ContentResolver#QUERY_ARG_SQL_LIMIT}, but note that 2392 * the documentation for each individual provider will indicate 2393 * which arguments they support. 2394 * @return the number of rows updated. 2395 * @throws NullPointerException if uri or values are null 2396 * @throws IllegalArgumentException if the provider doesn't support one of 2397 * the requested Bundle arguments. 2398 */ 2399 @Override 2400 public final int update(@RequiresPermission.Write @NonNull Uri uri, 2401 @Nullable ContentValues values, @Nullable Bundle extras) { 2402 Objects.requireNonNull(uri, "uri"); 2403 2404 try { 2405 if (mWrapped != null) return mWrapped.update(uri, values, extras); 2406 } catch (RemoteException e) { 2407 return 0; 2408 } 2409 2410 IContentProvider provider = acquireProvider(uri); 2411 if (provider == null) { 2412 throw new IllegalArgumentException("Unknown URI " + uri); 2413 } 2414 try { 2415 long startTime = SystemClock.uptimeMillis(); 2416 int rowsUpdated = provider.update(mContext.getAttributionSource(), 2417 uri, values, extras); 2418 long durationMillis = SystemClock.uptimeMillis() - startTime; 2419 maybeLogUpdateToEventLog(durationMillis, uri, "update", null); 2420 return rowsUpdated; 2421 } catch (RemoteException e) { 2422 // Arbitrary and not worth documenting, as Activity 2423 // Manager will kill this process shortly anyway. 2424 return -1; 2425 } finally { 2426 releaseProvider(provider); 2427 } 2428 } 2429 2430 /** 2431 * Call a provider-defined method. This can be used to implement 2432 * read or write interfaces which are cheaper than using a Cursor and/or 2433 * do not fit into the traditional table model. 2434 * 2435 * @param method provider-defined method name to call. Opaque to 2436 * framework, but must be non-null. 2437 * @param arg provider-defined String argument. May be null. 2438 * @param extras provider-defined Bundle argument. May be null. 2439 * @return a result Bundle, possibly null. Will be null if the ContentProvider 2440 * does not implement call. 2441 * @throws NullPointerException if uri or method is null 2442 * @throws IllegalArgumentException if uri is not known 2443 */ 2444 public final @Nullable Bundle call(@NonNull Uri uri, @NonNull String method, 2445 @Nullable String arg, @Nullable Bundle extras) { 2446 return call(uri.getAuthority(), method, arg, extras); 2447 } 2448 2449 @Override 2450 public final @Nullable Bundle call(@NonNull String authority, @NonNull String method, 2451 @Nullable String arg, @Nullable Bundle extras) { 2452 Objects.requireNonNull(authority, "authority"); 2453 Objects.requireNonNull(method, "method"); 2454 2455 try { 2456 if (mWrapped != null) return mWrapped.call(authority, method, arg, extras); 2457 } catch (RemoteException e) { 2458 return null; 2459 } 2460 2461 IContentProvider provider = acquireProvider(authority); 2462 if (provider == null) { 2463 throw new IllegalArgumentException("Unknown authority " + authority); 2464 } 2465 try { 2466 final Bundle res = provider.call(mContext.getAttributionSource(), 2467 authority, method, arg, extras); 2468 Bundle.setDefusable(res, true); 2469 return res; 2470 } catch (RemoteException e) { 2471 // Arbitrary and not worth documenting, as Activity 2472 // Manager will kill this process shortly anyway. 2473 return null; 2474 } finally { 2475 releaseProvider(provider); 2476 } 2477 } 2478 2479 /** 2480 * Returns the content provider for the given content URI. 2481 * 2482 * @param uri The URI to a content provider 2483 * @return The ContentProvider for the given URI, or null if no content provider is found. 2484 * @hide 2485 */ 2486 @UnsupportedAppUsage 2487 public final IContentProvider acquireProvider(Uri uri) { 2488 if (!SCHEME_CONTENT.equals(uri.getScheme())) { 2489 return null; 2490 } 2491 final String auth = uri.getAuthority(); 2492 if (auth != null) { 2493 return acquireProvider(mContext, auth); 2494 } 2495 return null; 2496 } 2497 2498 /** 2499 * Returns the content provider for the given content URI if the process 2500 * already has a reference on it. 2501 * 2502 * @param uri The URI to a content provider 2503 * @return The ContentProvider for the given URI, or null if no content provider is found. 2504 * @hide 2505 */ 2506 @UnsupportedAppUsage 2507 public final IContentProvider acquireExistingProvider(Uri uri) { 2508 if (!SCHEME_CONTENT.equals(uri.getScheme())) { 2509 return null; 2510 } 2511 final String auth = uri.getAuthority(); 2512 if (auth != null) { 2513 return acquireExistingProvider(mContext, auth); 2514 } 2515 return null; 2516 } 2517 2518 /** 2519 * @hide 2520 */ 2521 @UnsupportedAppUsage 2522 public final IContentProvider acquireProvider(String name) { 2523 if (name == null) { 2524 return null; 2525 } 2526 return acquireProvider(mContext, name); 2527 } 2528 2529 /** 2530 * Returns the content provider for the given content URI. 2531 * 2532 * @param uri The URI to a content provider 2533 * @return The ContentProvider for the given URI, or null if no content provider is found. 2534 * @hide 2535 */ 2536 public final IContentProvider acquireUnstableProvider(Uri uri) { 2537 if (!SCHEME_CONTENT.equals(uri.getScheme())) { 2538 return null; 2539 } 2540 String auth = uri.getAuthority(); 2541 if (auth != null) { 2542 return acquireUnstableProvider(mContext, uri.getAuthority()); 2543 } 2544 return null; 2545 } 2546 2547 /** 2548 * @hide 2549 */ 2550 @UnsupportedAppUsage 2551 public final IContentProvider acquireUnstableProvider(String name) { 2552 if (name == null) { 2553 return null; 2554 } 2555 return acquireUnstableProvider(mContext, name); 2556 } 2557 2558 /** 2559 * Returns a {@link ContentProviderClient} that is associated with the {@link ContentProvider} 2560 * that services the content at uri, starting the provider if necessary. Returns 2561 * null if there is no provider associated wih the uri. The caller must indicate that they are 2562 * done with the provider by calling {@link ContentProviderClient#release} which will allow 2563 * the system to release the provider if it determines that there is no other reason for 2564 * keeping it active. 2565 * @param uri specifies which provider should be acquired 2566 * @return a {@link ContentProviderClient} that is associated with the {@link ContentProvider} 2567 * that services the content at uri or null if there isn't one. 2568 */ 2569 public final @Nullable ContentProviderClient acquireContentProviderClient(@NonNull Uri uri) { 2570 Objects.requireNonNull(uri, "uri"); 2571 IContentProvider provider = acquireProvider(uri); 2572 if (provider != null) { 2573 return new ContentProviderClient(this, provider, uri.getAuthority(), true); 2574 } 2575 return null; 2576 } 2577 2578 /** 2579 * Returns a {@link ContentProviderClient} that is associated with the {@link ContentProvider} 2580 * with the authority of name, starting the provider if necessary. Returns 2581 * null if there is no provider associated wih the uri. The caller must indicate that they are 2582 * done with the provider by calling {@link ContentProviderClient#release} which will allow 2583 * the system to release the provider if it determines that there is no other reason for 2584 * keeping it active. 2585 * @param name specifies which provider should be acquired 2586 * @return a {@link ContentProviderClient} that is associated with the {@link ContentProvider} 2587 * with the authority of name or null if there isn't one. 2588 */ 2589 public final @Nullable ContentProviderClient acquireContentProviderClient( 2590 @NonNull String name) { 2591 Objects.requireNonNull(name, "name"); 2592 IContentProvider provider = acquireProvider(name); 2593 if (provider != null) { 2594 return new ContentProviderClient(this, provider, name, true); 2595 } 2596 2597 return null; 2598 } 2599 2600 /** 2601 * Like {@link #acquireContentProviderClient(Uri)}, but for use when you do 2602 * not trust the stability of the target content provider. This turns off 2603 * the mechanism in the platform clean up processes that are dependent on 2604 * a content provider if that content provider's process goes away. Normally 2605 * you can safely assume that once you have acquired a provider, you can freely 2606 * use it as needed and it won't disappear, even if your process is in the 2607 * background. If using this method, you need to take care to deal with any 2608 * failures when communicating with the provider, and be sure to close it 2609 * so that it can be re-opened later. In particular, catching a 2610 * {@link android.os.DeadObjectException} from the calls there will let you 2611 * know that the content provider has gone away; at that point the current 2612 * ContentProviderClient object is invalid, and you should release it. You 2613 * can acquire a new one if you would like to try to restart the provider 2614 * and perform new operations on it. 2615 */ 2616 public final @Nullable ContentProviderClient acquireUnstableContentProviderClient( 2617 @NonNull Uri uri) { 2618 Objects.requireNonNull(uri, "uri"); 2619 IContentProvider provider = acquireUnstableProvider(uri); 2620 if (provider != null) { 2621 return new ContentProviderClient(this, provider, uri.getAuthority(), false); 2622 } 2623 2624 return null; 2625 } 2626 2627 /** 2628 * Like {@link #acquireContentProviderClient(String)}, but for use when you do 2629 * not trust the stability of the target content provider. This turns off 2630 * the mechanism in the platform clean up processes that are dependent on 2631 * a content provider if that content provider's process goes away. Normally 2632 * you can safely assume that once you have acquired a provider, you can freely 2633 * use it as needed and it won't disappear, even if your process is in the 2634 * background. If using this method, you need to take care to deal with any 2635 * failures when communicating with the provider, and be sure to close it 2636 * so that it can be re-opened later. In particular, catching a 2637 * {@link android.os.DeadObjectException} from the calls there will let you 2638 * know that the content provider has gone away; at that point the current 2639 * ContentProviderClient object is invalid, and you should release it. You 2640 * can acquire a new one if you would like to try to restart the provider 2641 * and perform new operations on it. 2642 */ 2643 public final @Nullable ContentProviderClient acquireUnstableContentProviderClient( 2644 @NonNull String name) { 2645 Objects.requireNonNull(name, "name"); 2646 IContentProvider provider = acquireUnstableProvider(name); 2647 if (provider != null) { 2648 return new ContentProviderClient(this, provider, name, false); 2649 } 2650 2651 return null; 2652 } 2653 2654 /** 2655 * Register an observer class that gets callbacks when data identified by a 2656 * given content URI changes. 2657 * <p> 2658 * Starting in {@link android.os.Build.VERSION_CODES#O}, all content 2659 * notifications must be backed by a valid {@link ContentProvider}. 2660 * 2661 * @param uri The URI to watch for changes. This can be a specific row URI, 2662 * or a base URI for a whole class of content. 2663 * @param notifyForDescendants When false, the observer will be notified 2664 * whenever a change occurs to the exact URI specified by 2665 * <code>uri</code> or to one of the URI's ancestors in the path 2666 * hierarchy. When true, the observer will also be notified 2667 * whenever a change occurs to the URI's descendants in the path 2668 * hierarchy. 2669 * @param observer The object that receives callbacks when changes occur. 2670 * @see #unregisterContentObserver 2671 */ 2672 public final void registerContentObserver(@NonNull Uri uri, boolean notifyForDescendants, 2673 @NonNull ContentObserver observer) { 2674 Objects.requireNonNull(uri, "uri"); 2675 Objects.requireNonNull(observer, "observer"); 2676 registerContentObserver( 2677 ContentProvider.getUriWithoutUserId(uri), 2678 notifyForDescendants, 2679 observer, 2680 ContentProvider.getUserIdFromUri(uri, mContext.getUserId())); 2681 } 2682 2683 /** 2684 * Same as {@link #registerContentObserver(Uri, boolean, ContentObserver)}, but the observer 2685 * registered will get content change notifications for the specified user. 2686 * {@link ContentObserver#onChange(boolean, Collection, int, UserHandle)} should be 2687 * overwritten to get the corresponding {@link UserHandle} for that notification. 2688 * 2689 * <p> If you don't hold the {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} 2690 * permission, you can register the {@link ContentObserver} only for current user. 2691 * 2692 * @param uri The URI to watch for changes. This can be a specific row URI, 2693 * or a base URI for a whole class of content. 2694 * @param notifyForDescendants When false, the observer will be notified 2695 * whenever a change occurs to the exact URI specified by 2696 * <code>uri</code> or to one of the URI's ancestors in the path 2697 * hierarchy. When true, the observer will also be notified 2698 * whenever a change occurs to the URI's descendants in the path 2699 * hierarchy. 2700 * @param observer The object that receives callbacks when changes occur. 2701 * @param userHandle The UserHandle of the user the content change notifications are 2702 * for. 2703 * @hide 2704 * @see #unregisterContentObserver 2705 */ 2706 @RequiresPermission(value = android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, 2707 conditional = true) 2708 @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) 2709 public final void registerContentObserverAsUser(@NonNull Uri uri, 2710 boolean notifyForDescendants, 2711 @NonNull ContentObserver observer, 2712 @NonNull UserHandle userHandle) { 2713 Objects.requireNonNull(uri, "uri"); 2714 Objects.requireNonNull(observer, "observer"); 2715 Objects.requireNonNull(userHandle, "userHandle"); 2716 registerContentObserver( 2717 ContentProvider.getUriWithoutUserId(uri), 2718 notifyForDescendants, 2719 observer, 2720 userHandle.getIdentifier()); 2721 } 2722 2723 /** @hide - designated user version */ 2724 @UnsupportedAppUsage 2725 public final void registerContentObserver(Uri uri, boolean notifyForDescendents, 2726 ContentObserver observer, @UserIdInt int userHandle) { 2727 try { 2728 getContentService().registerContentObserver(uri, notifyForDescendents, 2729 observer.getContentObserver(), userHandle, mTargetSdkVersion); 2730 } catch (RemoteException e) { 2731 throw e.rethrowFromSystemServer(); 2732 } 2733 } 2734 2735 /** 2736 * Unregisters a change observer. 2737 * 2738 * @param observer The previously registered observer that is no longer needed. 2739 * @see #registerContentObserver 2740 */ 2741 public final void unregisterContentObserver(@NonNull ContentObserver observer) { 2742 Objects.requireNonNull(observer, "observer"); 2743 try { 2744 IContentObserver contentObserver = observer.releaseContentObserver(); 2745 if (contentObserver != null) { 2746 getContentService().unregisterContentObserver( 2747 contentObserver); 2748 } 2749 } catch (RemoteException e) { 2750 throw e.rethrowFromSystemServer(); 2751 } 2752 } 2753 2754 /** 2755 * Notify registered observers that a row was updated and attempt to sync 2756 * changes to the network. 2757 * <p> 2758 * To observe events sent through this call, use 2759 * {@link #registerContentObserver(Uri, boolean, ContentObserver)}. 2760 * <p> 2761 * Starting in {@link android.os.Build.VERSION_CODES#O}, all content 2762 * notifications must be backed by a valid {@link ContentProvider}. 2763 * 2764 * @param uri The uri of the content that was changed. 2765 * @param observer The observer that originated the change, may be 2766 * <code>null</null>. The observer that originated the change 2767 * will only receive the notification if it has requested to 2768 * receive self-change notifications by implementing 2769 * {@link ContentObserver#deliverSelfNotifications()} to return 2770 * true. 2771 */ 2772 public void notifyChange(@NonNull Uri uri, @Nullable ContentObserver observer) { 2773 notifyChange(uri, observer, true /* sync to network */); 2774 } 2775 2776 /** 2777 * Notify registered observers that a row was updated. 2778 * <p> 2779 * To observe events sent through this call, use 2780 * {@link #registerContentObserver(Uri, boolean, ContentObserver)}. 2781 * <p> 2782 * If syncToNetwork is true, this will attempt to schedule a local sync 2783 * using the sync adapter that's registered for the authority of the 2784 * provided uri. No account will be passed to the sync adapter, so all 2785 * matching accounts will be synchronized. 2786 * <p> 2787 * Starting in {@link android.os.Build.VERSION_CODES#O}, all content 2788 * notifications must be backed by a valid {@link ContentProvider}. 2789 * 2790 * @param uri The uri of the content that was changed. 2791 * @param observer The observer that originated the change, may be 2792 * <code>null</null>. The observer that originated the change 2793 * will only receive the notification if it has requested to 2794 * receive self-change notifications by implementing 2795 * {@link ContentObserver#deliverSelfNotifications()} to return 2796 * true. 2797 * @param syncToNetwork If true, same as {@link #NOTIFY_SYNC_TO_NETWORK}. 2798 * @see #requestSync(android.accounts.Account, String, android.os.Bundle) 2799 * @deprecated callers should consider migrating to 2800 * {@link #notifyChange(Uri, ContentObserver, int)}, as it 2801 * offers support for many more options than just 2802 * {@link #NOTIFY_SYNC_TO_NETWORK}. 2803 */ 2804 @Deprecated 2805 public void notifyChange(@NonNull Uri uri, @Nullable ContentObserver observer, 2806 boolean syncToNetwork) { 2807 notifyChange(uri, observer, syncToNetwork ? NOTIFY_SYNC_TO_NETWORK : 0); 2808 } 2809 2810 /** 2811 * Notify registered observers that a row was updated. 2812 * <p> 2813 * To observe events sent through this call, use 2814 * {@link #registerContentObserver(Uri, boolean, ContentObserver)}. 2815 * <p> 2816 * If {@link #NOTIFY_SYNC_TO_NETWORK} is set, this will attempt to schedule 2817 * a local sync using the sync adapter that's registered for the authority 2818 * of the provided uri. No account will be passed to the sync adapter, so 2819 * all matching accounts will be synchronized. 2820 * <p> 2821 * Starting in {@link android.os.Build.VERSION_CODES#O}, all content 2822 * notifications must be backed by a valid {@link ContentProvider}. 2823 * 2824 * @param uri The uri of the content that was changed. 2825 * @param observer The observer that originated the change, may be 2826 * <code>null</null>. The observer that originated the change 2827 * will only receive the notification if it has requested to 2828 * receive self-change notifications by implementing 2829 * {@link ContentObserver#deliverSelfNotifications()} to return 2830 * true. 2831 * @param flags Additional flags: {@link #NOTIFY_SYNC_TO_NETWORK}. 2832 * @see #requestSync(android.accounts.Account, String, android.os.Bundle) 2833 */ 2834 public void notifyChange(@NonNull Uri uri, @Nullable ContentObserver observer, 2835 @NotifyFlags int flags) { 2836 Objects.requireNonNull(uri, "uri"); 2837 notifyChange( 2838 ContentProvider.getUriWithoutUserId(uri), 2839 observer, 2840 flags, 2841 ContentProvider.getUserIdFromUri(uri, mContext.getUserId())); 2842 } 2843 2844 /** @removed */ 2845 @Deprecated 2846 public void notifyChange(@NonNull Iterable<Uri> uris, @Nullable ContentObserver observer, 2847 @NotifyFlags int flags) { 2848 final Collection<Uri> asCollection = new ArrayList<>(); 2849 uris.forEach(asCollection::add); 2850 notifyChange(asCollection, observer, flags); 2851 } 2852 2853 /** 2854 * Notify registered observers that several rows have been updated. 2855 * <p> 2856 * To observe events sent through this call, use 2857 * {@link #registerContentObserver(Uri, boolean, ContentObserver)}. 2858 * <p> 2859 * If {@link #NOTIFY_SYNC_TO_NETWORK} is set, this will attempt to schedule 2860 * a local sync using the sync adapter that's registered for the authority 2861 * of the provided uri. No account will be passed to the sync adapter, so 2862 * all matching accounts will be synchronized. 2863 * <p> 2864 * Starting in {@link android.os.Build.VERSION_CODES#O}, all content 2865 * notifications must be backed by a valid {@link ContentProvider}. 2866 * 2867 * @param uris The uris of the content that was changed. 2868 * @param observer The observer that originated the change, may be 2869 * <code>null</null>. The observer that originated the change 2870 * will only receive the notification if it has requested to 2871 * receive self-change notifications by implementing 2872 * {@link ContentObserver#deliverSelfNotifications()} to return 2873 * true. 2874 * @param flags Flags such as {@link #NOTIFY_SYNC_TO_NETWORK} or 2875 * {@link #NOTIFY_SKIP_NOTIFY_FOR_DESCENDANTS}. 2876 */ 2877 public void notifyChange(@NonNull Collection<Uri> uris, @Nullable ContentObserver observer, 2878 @NotifyFlags int flags) { 2879 Objects.requireNonNull(uris, "uris"); 2880 2881 // Cluster based on user ID 2882 final SparseArray<ArrayList<Uri>> clusteredByUser = new SparseArray<>(); 2883 for (Uri uri : uris) { 2884 final int userId = ContentProvider.getUserIdFromUri(uri, mContext.getUserId()); 2885 ArrayList<Uri> list = clusteredByUser.get(userId); 2886 if (list == null) { 2887 list = new ArrayList<>(); 2888 clusteredByUser.put(userId, list); 2889 } 2890 list.add(ContentProvider.getUriWithoutUserId(uri)); 2891 } 2892 2893 for (int i = 0; i < clusteredByUser.size(); i++) { 2894 final int userId = clusteredByUser.keyAt(i); 2895 final ArrayList<Uri> list = clusteredByUser.valueAt(i); 2896 notifyChange(list.toArray(new Uri[list.size()]), observer, flags, userId); 2897 } 2898 } 2899 2900 /** 2901 * Notify registered observers within the designated user(s) that a row was updated. 2902 * 2903 * @deprecated callers should consider migrating to 2904 * {@link #notifyChange(Uri, ContentObserver, int)}, as it 2905 * offers support for many more options than just 2906 * {@link #NOTIFY_SYNC_TO_NETWORK}. 2907 * @hide 2908 */ 2909 @Deprecated 2910 public void notifyChange(@NonNull Uri uri, ContentObserver observer, boolean syncToNetwork, 2911 @UserIdInt int userHandle) { 2912 notifyChange(uri, observer, syncToNetwork ? NOTIFY_SYNC_TO_NETWORK : 0, userHandle); 2913 } 2914 2915 /** {@hide} */ 2916 public void notifyChange(@NonNull Uri uri, ContentObserver observer, @NotifyFlags int flags, 2917 @UserIdInt int userHandle) { 2918 notifyChange(new Uri[] { uri }, observer, flags, userHandle); 2919 } 2920 2921 /** 2922 * Notify registered observers within the designated user(s) that a row was updated. 2923 * 2924 * @hide 2925 */ 2926 public void notifyChange(@NonNull Uri[] uris, ContentObserver observer, @NotifyFlags int flags, 2927 @UserIdInt int userHandle) { 2928 try { 2929 getContentService().notifyChange( 2930 uris, observer == null ? null : observer.getContentObserver(), 2931 observer != null && observer.deliverSelfNotifications(), flags, 2932 userHandle, mTargetSdkVersion, mContext.getPackageName()); 2933 } catch (RemoteException e) { 2934 throw e.rethrowFromSystemServer(); 2935 } 2936 } 2937 2938 /** 2939 * Take a persistable URI permission grant that has been offered. Once 2940 * taken, the permission grant will be remembered across device reboots. 2941 * Only URI permissions granted with 2942 * {@link Intent#FLAG_GRANT_PERSISTABLE_URI_PERMISSION} can be persisted. If 2943 * the grant has already been persisted, taking it again will touch 2944 * {@link UriPermission#getPersistedTime()}. 2945 * 2946 * @see #getPersistedUriPermissions() 2947 */ 2948 public void takePersistableUriPermission(@NonNull Uri uri, 2949 @Intent.AccessUriMode int modeFlags) { 2950 Objects.requireNonNull(uri, "uri"); 2951 try { 2952 UriGrantsManager.getService().takePersistableUriPermission( 2953 ContentProvider.getUriWithoutUserId(uri), modeFlags, /* toPackage= */ null, 2954 resolveUserId(uri)); 2955 } catch (RemoteException e) { 2956 throw e.rethrowFromSystemServer(); 2957 } 2958 } 2959 2960 /** 2961 * @hide 2962 */ 2963 @UnsupportedAppUsage 2964 public void takePersistableUriPermission(@NonNull String toPackage, @NonNull Uri uri, 2965 @Intent.AccessUriMode int modeFlags) { 2966 Objects.requireNonNull(toPackage, "toPackage"); 2967 Objects.requireNonNull(uri, "uri"); 2968 try { 2969 UriGrantsManager.getService().takePersistableUriPermission( 2970 ContentProvider.getUriWithoutUserId(uri), modeFlags, toPackage, 2971 resolveUserId(uri)); 2972 } catch (RemoteException e) { 2973 throw e.rethrowFromSystemServer(); 2974 } 2975 } 2976 2977 /** 2978 * Relinquish a persisted URI permission grant. The URI must have been 2979 * previously made persistent with 2980 * {@link #takePersistableUriPermission(Uri, int)}. Any non-persistent 2981 * grants to the calling package will remain intact. 2982 * 2983 * @see #getPersistedUriPermissions() 2984 */ 2985 public void releasePersistableUriPermission(@NonNull Uri uri, 2986 @Intent.AccessUriMode int modeFlags) { 2987 Objects.requireNonNull(uri, "uri"); 2988 try { 2989 UriGrantsManager.getService().releasePersistableUriPermission( 2990 ContentProvider.getUriWithoutUserId(uri), modeFlags, /* toPackage= */ null, 2991 resolveUserId(uri)); 2992 } catch (RemoteException e) { 2993 throw e.rethrowFromSystemServer(); 2994 } 2995 } 2996 2997 /** 2998 * Return list of all URI permission grants that have been persisted by the 2999 * calling app. That is, the returned permissions have been granted 3000 * <em>to</em> the calling app. Only persistable grants taken with 3001 * {@link #takePersistableUriPermission(Uri, int)} are returned. 3002 * <p>Note: Some of the returned URIs may not be usable until after the user is unlocked. 3003 * 3004 * @see #takePersistableUriPermission(Uri, int) 3005 * @see #releasePersistableUriPermission(Uri, int) 3006 */ 3007 public @NonNull List<UriPermission> getPersistedUriPermissions() { 3008 try { 3009 return UriGrantsManager.getService().getUriPermissions( 3010 mPackageName, true /* incoming */, true /* persistedOnly */).getList(); 3011 } catch (RemoteException e) { 3012 throw e.rethrowFromSystemServer(); 3013 } 3014 } 3015 3016 /** 3017 * Return list of all persisted URI permission grants that are hosted by the 3018 * calling app. That is, the returned permissions have been granted 3019 * <em>from</em> the calling app. Only grants taken with 3020 * {@link #takePersistableUriPermission(Uri, int)} are returned. 3021 * <p>Note: Some of the returned URIs may not be usable until after the user is unlocked. 3022 */ 3023 public @NonNull List<UriPermission> getOutgoingPersistedUriPermissions() { 3024 try { 3025 return UriGrantsManager.getService().getUriPermissions( 3026 mPackageName, false /* incoming */, true /* persistedOnly */).getList(); 3027 } catch (RemoteException e) { 3028 throw e.rethrowFromSystemServer(); 3029 } 3030 } 3031 3032 /** @hide */ 3033 public @NonNull List<UriPermission> getOutgoingUriPermissions() { 3034 try { 3035 return UriGrantsManager.getService().getUriPermissions( 3036 mPackageName, false /* incoming */, false /* persistedOnly */).getList(); 3037 } catch (RemoteException e) { 3038 throw e.rethrowFromSystemServer(); 3039 } 3040 } 3041 3042 /** 3043 * Start an asynchronous sync operation. If you want to monitor the progress 3044 * of the sync you may register a SyncObserver. Only values of the following 3045 * types may be used in the extras bundle: 3046 * <ul> 3047 * <li>Integer</li> 3048 * <li>Long</li> 3049 * <li>Boolean</li> 3050 * <li>Float</li> 3051 * <li>Double</li> 3052 * <li>String</li> 3053 * <li>Account</li> 3054 * <li>null</li> 3055 * </ul> 3056 * 3057 * @param uri the uri of the provider to sync or null to sync all providers. 3058 * @param extras any extras to pass to the SyncAdapter. 3059 * @deprecated instead use 3060 * {@link #requestSync(android.accounts.Account, String, android.os.Bundle)} 3061 */ 3062 @Deprecated 3063 public void startSync(Uri uri, Bundle extras) { 3064 Account account = null; 3065 if (extras != null) { 3066 String accountName = extras.getString(SYNC_EXTRAS_ACCOUNT); 3067 if (!TextUtils.isEmpty(accountName)) { 3068 // TODO: No references to Google in AOSP 3069 account = new Account(accountName, "com.google"); 3070 } 3071 extras.remove(SYNC_EXTRAS_ACCOUNT); 3072 } 3073 requestSync(account, uri != null ? uri.getAuthority() : null, extras); 3074 } 3075 3076 /** 3077 * Start an asynchronous sync operation. If you want to monitor the progress 3078 * of the sync you may register a SyncObserver. Only values of the following 3079 * types may be used in the extras bundle: 3080 * <ul> 3081 * <li>Integer</li> 3082 * <li>Long</li> 3083 * <li>Boolean</li> 3084 * <li>Float</li> 3085 * <li>Double</li> 3086 * <li>String</li> 3087 * <li>Account</li> 3088 * <li>null</li> 3089 * </ul> 3090 * 3091 * @param account which account should be synced 3092 * @param authority which authority should be synced 3093 * @param extras any extras to pass to the SyncAdapter. 3094 */ 3095 public static void requestSync(Account account, String authority, Bundle extras) { 3096 requestSyncAsUser(account, authority, UserHandle.myUserId(), extras); 3097 } 3098 3099 /** 3100 * @see #requestSync(Account, String, Bundle) 3101 * @hide 3102 */ 3103 public static void requestSyncAsUser(Account account, String authority, @UserIdInt int userId, 3104 Bundle extras) { 3105 if (extras == null) { 3106 throw new IllegalArgumentException("Must specify extras."); 3107 } 3108 SyncRequest request = 3109 new SyncRequest.Builder() 3110 .setSyncAdapter(account, authority) 3111 .setExtras(extras) 3112 .syncOnce() // Immediate sync. 3113 .build(); 3114 try { 3115 // Note ActivityThread.currentPackageName() may not be accurate in a shared process 3116 // case, but it's only for debugging. 3117 getContentService().syncAsUser(request, userId, ActivityThread.currentPackageName()); 3118 } catch(RemoteException e) { 3119 throw e.rethrowFromSystemServer(); 3120 } 3121 } 3122 3123 /** 3124 * Register a sync with the SyncManager. These requests are built using the 3125 * {@link SyncRequest.Builder}. 3126 */ 3127 public static void requestSync(SyncRequest request) { 3128 try { 3129 // Note ActivityThread.currentPackageName() may not be accurate in a shared process 3130 // case, but it's only for debugging. 3131 getContentService().sync(request, ActivityThread.currentPackageName()); 3132 } catch(RemoteException e) { 3133 throw e.rethrowFromSystemServer(); 3134 } 3135 } 3136 3137 /** 3138 * Check that only values of the following types are in the Bundle: 3139 * <ul> 3140 * <li>Integer</li> 3141 * <li>Long</li> 3142 * <li>Boolean</li> 3143 * <li>Float</li> 3144 * <li>Double</li> 3145 * <li>String</li> 3146 * <li>Account</li> 3147 * <li>null</li> 3148 * </ul> 3149 * @param extras the Bundle to check 3150 */ 3151 public static void validateSyncExtrasBundle(Bundle extras) { 3152 try { 3153 for (String key : extras.keySet()) { 3154 Object value = extras.get(key); 3155 if (value == null) continue; 3156 if (value instanceof Long) continue; 3157 if (value instanceof Integer) continue; 3158 if (value instanceof Boolean) continue; 3159 if (value instanceof Float) continue; 3160 if (value instanceof Double) continue; 3161 if (value instanceof String) continue; 3162 if (value instanceof Account) continue; 3163 throw new IllegalArgumentException("unexpected value type: " 3164 + value.getClass().getName()); 3165 } 3166 } catch (IllegalArgumentException e) { 3167 throw e; 3168 } catch (RuntimeException exc) { 3169 throw new IllegalArgumentException("error unparceling Bundle", exc); 3170 } 3171 } 3172 3173 /** 3174 * Cancel any active or pending syncs that match the Uri. If the uri is null then 3175 * all syncs will be canceled. 3176 * 3177 * @param uri the uri of the provider to sync or null to sync all providers. 3178 * @deprecated instead use {@link #cancelSync(android.accounts.Account, String)} 3179 */ 3180 @Deprecated 3181 public void cancelSync(Uri uri) { 3182 cancelSync(null /* all accounts */, uri != null ? uri.getAuthority() : null); 3183 } 3184 3185 /** 3186 * Cancel any active or pending syncs that match account and authority. The account and 3187 * authority can each independently be set to null, which means that syncs with any account 3188 * or authority, respectively, will match. 3189 * 3190 * @param account filters the syncs that match by this account 3191 * @param authority filters the syncs that match by this authority 3192 */ 3193 public static void cancelSync(Account account, String authority) { 3194 try { 3195 getContentService().cancelSync(account, authority, null); 3196 } catch (RemoteException e) { 3197 throw e.rethrowFromSystemServer(); 3198 } 3199 } 3200 3201 /** 3202 * @see #cancelSync(Account, String) 3203 * @hide 3204 */ 3205 public static void cancelSyncAsUser(Account account, String authority, @UserIdInt int userId) { 3206 try { 3207 getContentService().cancelSyncAsUser(account, authority, null, userId); 3208 } catch (RemoteException e) { 3209 throw e.rethrowFromSystemServer(); 3210 } 3211 } 3212 3213 /** 3214 * Get information about the SyncAdapters that are known to the system. 3215 * @return an array of SyncAdapters that have registered with the system 3216 */ 3217 public static SyncAdapterType[] getSyncAdapterTypes() { 3218 try { 3219 return getContentService().getSyncAdapterTypes(); 3220 } catch (RemoteException e) { 3221 throw e.rethrowFromSystemServer(); 3222 } 3223 } 3224 3225 /** 3226 * @see #getSyncAdapterTypes() 3227 * @hide 3228 */ 3229 public static SyncAdapterType[] getSyncAdapterTypesAsUser(@UserIdInt int userId) { 3230 try { 3231 return getContentService().getSyncAdapterTypesAsUser(userId); 3232 } catch (RemoteException e) { 3233 throw e.rethrowFromSystemServer(); 3234 } 3235 } 3236 3237 /** 3238 * @hide 3239 * Returns the package names of syncadapters that match a given user and authority. 3240 */ 3241 @TestApi 3242 public static String[] getSyncAdapterPackagesForAuthorityAsUser(String authority, 3243 @UserIdInt int userId) { 3244 try { 3245 return getContentService().getSyncAdapterPackagesForAuthorityAsUser(authority, userId); 3246 } catch (RemoteException e) { 3247 throw e.rethrowFromSystemServer(); 3248 } 3249 } 3250 3251 /** 3252 * Returns the package name of the syncadapter that matches a given account type, authority 3253 * and user. 3254 * @hide 3255 */ 3256 @Nullable 3257 public static String getSyncAdapterPackageAsUser(@NonNull String accountType, 3258 @NonNull String authority, @UserIdInt int userId) { 3259 try { 3260 return getContentService().getSyncAdapterPackageAsUser(accountType, authority, userId); 3261 } catch (RemoteException e) { 3262 throw e.rethrowFromSystemServer(); 3263 } 3264 } 3265 3266 /** 3267 * Check if the provider should be synced when a network tickle is received 3268 * <p>This method requires the caller to hold the permission 3269 * {@link android.Manifest.permission#READ_SYNC_SETTINGS}. 3270 * 3271 * @param account the account whose setting we are querying 3272 * @param authority the provider whose setting we are querying 3273 * @return true if the provider should be synced when a network tickle is received 3274 */ 3275 public static boolean getSyncAutomatically(Account account, String authority) { 3276 try { 3277 return getContentService().getSyncAutomatically(account, authority); 3278 } catch (RemoteException e) { 3279 throw e.rethrowFromSystemServer(); 3280 } 3281 } 3282 3283 /** 3284 * @see #getSyncAutomatically(Account, String) 3285 * @hide 3286 */ 3287 public static boolean getSyncAutomaticallyAsUser(Account account, String authority, 3288 @UserIdInt int userId) { 3289 try { 3290 return getContentService().getSyncAutomaticallyAsUser(account, authority, userId); 3291 } catch (RemoteException e) { 3292 throw e.rethrowFromSystemServer(); 3293 } 3294 } 3295 3296 /** 3297 * Set whether or not the provider is synced when it receives a network tickle. 3298 * <p>This method requires the caller to hold the permission 3299 * {@link android.Manifest.permission#WRITE_SYNC_SETTINGS}. 3300 * 3301 * @param account the account whose setting we are querying 3302 * @param authority the provider whose behavior is being controlled 3303 * @param sync true if the provider should be synced when tickles are received for it 3304 */ 3305 public static void setSyncAutomatically(Account account, String authority, boolean sync) { 3306 setSyncAutomaticallyAsUser(account, authority, sync, UserHandle.myUserId()); 3307 } 3308 3309 /** 3310 * @see #setSyncAutomatically(Account, String, boolean) 3311 * @hide 3312 */ 3313 public static void setSyncAutomaticallyAsUser(Account account, String authority, boolean sync, 3314 @UserIdInt int userId) { 3315 try { 3316 getContentService().setSyncAutomaticallyAsUser(account, authority, sync, userId); 3317 } catch (RemoteException e) { 3318 throw e.rethrowFromSystemServer(); 3319 } 3320 } 3321 3322 /** 3323 * {@hide} 3324 * Helper function to throw an <code>IllegalArgumentException</code> if any illegal 3325 * extras were set for a sync scheduled as an expedited job. 3326 * 3327 * @param extras bundle to validate. 3328 */ 3329 public static boolean hasInvalidScheduleAsEjExtras(Bundle extras) { 3330 return extras.getBoolean(ContentResolver.SYNC_EXTRAS_REQUIRE_CHARGING) 3331 || extras.getBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED); 3332 } 3333 3334 /** 3335 * Specifies that a sync should be requested with the specified the account, authority, 3336 * and extras at the given frequency. If there is already another periodic sync scheduled 3337 * with the account, authority and extras then a new periodic sync won't be added, instead 3338 * the frequency of the previous one will be updated. 3339 * <p> 3340 * These periodic syncs honor the "syncAutomatically" and "masterSyncAutomatically" settings. 3341 * Although these sync are scheduled at the specified frequency, it may take longer for it to 3342 * actually be started if other syncs are ahead of it in the sync operation queue. This means 3343 * that the actual start time may drift. 3344 * <p> 3345 * Periodic syncs are not allowed to have any of {@link #SYNC_EXTRAS_DO_NOT_RETRY}, 3346 * {@link #SYNC_EXTRAS_IGNORE_BACKOFF}, {@link #SYNC_EXTRAS_IGNORE_SETTINGS}, 3347 * {@link #SYNC_EXTRAS_INITIALIZE}, {@link #SYNC_EXTRAS_FORCE}, 3348 * {@link #SYNC_EXTRAS_EXPEDITED}, {@link #SYNC_EXTRAS_MANUAL}, 3349 * {@link #SYNC_EXTRAS_SCHEDULE_AS_EXPEDITED_JOB} set to true. 3350 * If any are supplied then an {@link IllegalArgumentException} will be thrown. 3351 * 3352 * <p>This method requires the caller to hold the permission 3353 * {@link android.Manifest.permission#WRITE_SYNC_SETTINGS}. 3354 * <p>The bundle for a periodic sync can be queried by applications with the correct 3355 * permissions using 3356 * {@link ContentResolver#getPeriodicSyncs(Account account, String provider)}, so no 3357 * sensitive data should be transferred here. 3358 * 3359 * @param account the account to specify in the sync 3360 * @param authority the provider to specify in the sync request 3361 * @param extras extra parameters to go along with the sync request 3362 * @param pollFrequency how frequently the sync should be performed, in seconds. 3363 * On Android API level 24 and above, a minimum interval of 15 minutes is enforced. 3364 * On previous versions, the minimum interval is 1 hour. 3365 * @throws IllegalArgumentException if an illegal extra was set or if any of the parameters 3366 * are null. 3367 */ 3368 public static void addPeriodicSync(Account account, String authority, Bundle extras, 3369 long pollFrequency) { 3370 validateSyncExtrasBundle(extras); 3371 if (invalidPeriodicExtras(extras)) { 3372 throw new IllegalArgumentException("illegal extras were set"); 3373 } 3374 try { 3375 getContentService().addPeriodicSync(account, authority, extras, pollFrequency); 3376 } catch (RemoteException e) { 3377 throw e.rethrowFromSystemServer(); 3378 } 3379 } 3380 3381 /** 3382 * {@hide} 3383 * Helper function to throw an <code>IllegalArgumentException</code> if any illegal 3384 * extras were set for a periodic sync. 3385 * 3386 * @param extras bundle to validate. 3387 */ 3388 public static boolean invalidPeriodicExtras(Bundle extras) { 3389 return extras.getBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, false) 3390 || extras.getBoolean(ContentResolver.SYNC_EXTRAS_DO_NOT_RETRY, false) 3391 || extras.getBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_BACKOFF, false) 3392 || extras.getBoolean(ContentResolver.SYNC_EXTRAS_IGNORE_SETTINGS, false) 3393 || extras.getBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE, false) 3394 || extras.getBoolean(ContentResolver.SYNC_EXTRAS_FORCE, false) 3395 || extras.getBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, false) 3396 || extras.getBoolean(ContentResolver.SYNC_EXTRAS_SCHEDULE_AS_EXPEDITED_JOB, false); 3397 } 3398 3399 /** 3400 * Remove a periodic sync. Has no affect if account, authority and extras don't match 3401 * an existing periodic sync. 3402 * <p>This method requires the caller to hold the permission 3403 * {@link android.Manifest.permission#WRITE_SYNC_SETTINGS}. 3404 * 3405 * @param account the account of the periodic sync to remove 3406 * @param authority the provider of the periodic sync to remove 3407 * @param extras the extras of the periodic sync to remove 3408 */ 3409 public static void removePeriodicSync(Account account, String authority, Bundle extras) { 3410 validateSyncExtrasBundle(extras); 3411 try { 3412 getContentService().removePeriodicSync(account, authority, extras); 3413 } catch (RemoteException e) { 3414 throw e.rethrowFromSystemServer(); 3415 } 3416 } 3417 3418 /** 3419 * Remove the specified sync. This will cancel any pending or active syncs. If the request is 3420 * for a periodic sync, this call will remove any future occurrences. 3421 * <p> 3422 * If a periodic sync is specified, the caller must hold the permission 3423 * {@link android.Manifest.permission#WRITE_SYNC_SETTINGS}. 3424 *</p> 3425 * It is possible to cancel a sync using a SyncRequest object that is not the same object 3426 * with which you requested the sync. Do so by building a SyncRequest with the same 3427 * adapter, frequency, <b>and</b> extras bundle. 3428 * 3429 * @param request SyncRequest object containing information about sync to cancel. 3430 */ 3431 public static void cancelSync(SyncRequest request) { 3432 if (request == null) { 3433 throw new IllegalArgumentException("request cannot be null"); 3434 } 3435 try { 3436 getContentService().cancelRequest(request); 3437 } catch (RemoteException e) { 3438 throw e.rethrowFromSystemServer(); 3439 } 3440 } 3441 3442 /** 3443 * Get the list of information about the periodic syncs for the given account and authority. 3444 * <p>This method requires the caller to hold the permission 3445 * {@link android.Manifest.permission#READ_SYNC_SETTINGS}. 3446 * 3447 * @param account the account whose periodic syncs we are querying 3448 * @param authority the provider whose periodic syncs we are querying 3449 * @return a list of PeriodicSync objects. This list may be empty but will never be null. 3450 */ 3451 public static List<PeriodicSync> getPeriodicSyncs(Account account, String authority) { 3452 try { 3453 return getContentService().getPeriodicSyncs(account, authority, null); 3454 } catch (RemoteException e) { 3455 throw e.rethrowFromSystemServer(); 3456 } 3457 } 3458 3459 /** 3460 * Check if this account/provider is syncable. 3461 * <p>This method requires the caller to hold the permission 3462 * {@link android.Manifest.permission#READ_SYNC_SETTINGS}. 3463 * @return >0 if it is syncable, 0 if not, and <0 if the state isn't known yet. 3464 */ 3465 public static int getIsSyncable(Account account, String authority) { 3466 try { 3467 return getContentService().getIsSyncable(account, authority); 3468 } catch (RemoteException e) { 3469 throw e.rethrowFromSystemServer(); 3470 } 3471 } 3472 3473 /** 3474 * @see #getIsSyncable(Account, String) 3475 * @hide 3476 */ 3477 public static int getIsSyncableAsUser(Account account, String authority, 3478 @UserIdInt int userId) { 3479 try { 3480 return getContentService().getIsSyncableAsUser(account, authority, userId); 3481 } catch (RemoteException e) { 3482 throw e.rethrowFromSystemServer(); 3483 } 3484 } 3485 3486 /** 3487 * Set whether this account/provider is syncable. 3488 * <p>This method requires the caller to hold the permission 3489 * {@link android.Manifest.permission#WRITE_SYNC_SETTINGS}. 3490 * @param syncable >0 denotes syncable, 0 means not syncable, <0 means unknown 3491 */ 3492 public static void setIsSyncable(Account account, String authority, int syncable) { 3493 try { 3494 getContentService().setIsSyncable(account, authority, syncable); 3495 } catch (RemoteException e) { 3496 throw e.rethrowFromSystemServer(); 3497 } 3498 } 3499 3500 /** 3501 * @see #setIsSyncable(Account, String, int) 3502 * @hide 3503 */ 3504 public static void setIsSyncableAsUser(Account account, String authority, int syncable, 3505 int userId) { 3506 try { 3507 getContentService().setIsSyncableAsUser(account, authority, syncable, userId); 3508 } catch (RemoteException e) { 3509 throw e.rethrowFromSystemServer(); 3510 } 3511 } 3512 3513 /** 3514 * Gets the global auto-sync setting that applies to all the providers and accounts. 3515 * If this is false then the per-provider auto-sync setting is ignored. 3516 * <p>This method requires the caller to hold the permission 3517 * {@link android.Manifest.permission#READ_SYNC_SETTINGS}. 3518 * 3519 * @return the global auto-sync setting that applies to all the providers and accounts 3520 */ 3521 public static boolean getMasterSyncAutomatically() { 3522 try { 3523 return getContentService().getMasterSyncAutomatically(); 3524 } catch (RemoteException e) { 3525 throw e.rethrowFromSystemServer(); 3526 } 3527 } 3528 3529 /** 3530 * @see #getMasterSyncAutomatically() 3531 * @hide 3532 */ 3533 public static boolean getMasterSyncAutomaticallyAsUser(@UserIdInt int userId) { 3534 try { 3535 return getContentService().getMasterSyncAutomaticallyAsUser(userId); 3536 } catch (RemoteException e) { 3537 throw e.rethrowFromSystemServer(); 3538 } 3539 } 3540 3541 /** 3542 * Sets the global auto-sync setting that applies to all the providers and accounts. 3543 * If this is false then the per-provider auto-sync setting is ignored. 3544 * <p>This method requires the caller to hold the permission 3545 * {@link android.Manifest.permission#WRITE_SYNC_SETTINGS}. 3546 * 3547 * @param sync the global auto-sync setting that applies to all the providers and accounts 3548 */ 3549 public static void setMasterSyncAutomatically(boolean sync) { 3550 setMasterSyncAutomaticallyAsUser(sync, UserHandle.myUserId()); 3551 } 3552 3553 /** 3554 * @see #setMasterSyncAutomatically(boolean) 3555 * @hide 3556 */ 3557 public static void setMasterSyncAutomaticallyAsUser(boolean sync, @UserIdInt int userId) { 3558 try { 3559 getContentService().setMasterSyncAutomaticallyAsUser(sync, userId); 3560 } catch (RemoteException e) { 3561 throw e.rethrowFromSystemServer(); 3562 } 3563 } 3564 3565 /** 3566 * Returns true if there is currently a sync operation for the given account or authority 3567 * actively being processed. 3568 * <p>This method requires the caller to hold the permission 3569 * {@link android.Manifest.permission#READ_SYNC_STATS}. 3570 * @param account the account whose setting we are querying 3571 * @param authority the provider whose behavior is being queried 3572 * @return true if a sync is active for the given account or authority. 3573 */ 3574 public static boolean isSyncActive(Account account, String authority) { 3575 if (account == null) { 3576 throw new IllegalArgumentException("account must not be null"); 3577 } 3578 if (authority == null) { 3579 throw new IllegalArgumentException("authority must not be null"); 3580 } 3581 3582 try { 3583 return getContentService().isSyncActive(account, authority, null); 3584 } catch (RemoteException e) { 3585 throw e.rethrowFromSystemServer(); 3586 } 3587 } 3588 3589 /** 3590 * If a sync is active returns the information about it, otherwise returns null. 3591 * <p> 3592 * This method requires the caller to hold the permission 3593 * {@link android.Manifest.permission#READ_SYNC_STATS}. 3594 * <p> 3595 * @return the SyncInfo for the currently active sync or null if one is not active. 3596 * @deprecated 3597 * Since multiple concurrent syncs are now supported you should use 3598 * {@link #getCurrentSyncs()} to get the accurate list of current syncs. 3599 * This method returns the first item from the list of current syncs 3600 * or null if there are none. 3601 */ 3602 @Deprecated 3603 public static SyncInfo getCurrentSync() { 3604 try { 3605 final List<SyncInfo> syncs = getContentService().getCurrentSyncs(); 3606 if (syncs.isEmpty()) { 3607 return null; 3608 } 3609 return syncs.get(0); 3610 } catch (RemoteException e) { 3611 throw e.rethrowFromSystemServer(); 3612 } 3613 } 3614 3615 /** 3616 * Returns a list with information about all the active syncs. This list will be empty 3617 * if there are no active syncs. 3618 * <p> 3619 * This method requires the caller to hold the permission 3620 * {@link android.Manifest.permission#READ_SYNC_STATS}. 3621 * <p> 3622 * @return a List of SyncInfo objects for the currently active syncs. 3623 */ 3624 public static List<SyncInfo> getCurrentSyncs() { 3625 try { 3626 return getContentService().getCurrentSyncs(); 3627 } catch (RemoteException e) { 3628 throw e.rethrowFromSystemServer(); 3629 } 3630 } 3631 3632 /** 3633 * @see #getCurrentSyncs() 3634 * @hide 3635 */ 3636 public static List<SyncInfo> getCurrentSyncsAsUser(@UserIdInt int userId) { 3637 try { 3638 return getContentService().getCurrentSyncsAsUser(userId); 3639 } catch (RemoteException e) { 3640 throw e.rethrowFromSystemServer(); 3641 } 3642 } 3643 3644 /** 3645 * Returns the status that matches the authority. 3646 * @param account the account whose setting we are querying 3647 * @param authority the provider whose behavior is being queried 3648 * @return the SyncStatusInfo for the authority, or null if none exists 3649 * @hide 3650 */ 3651 @UnsupportedAppUsage 3652 public static SyncStatusInfo getSyncStatus(Account account, String authority) { 3653 try { 3654 return getContentService().getSyncStatus(account, authority, null); 3655 } catch (RemoteException e) { 3656 throw e.rethrowFromSystemServer(); 3657 } 3658 } 3659 3660 /** 3661 * @see #getSyncStatus(Account, String) 3662 * @hide 3663 */ 3664 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 3665 public static SyncStatusInfo getSyncStatusAsUser(Account account, String authority, 3666 @UserIdInt int userId) { 3667 try { 3668 return getContentService().getSyncStatusAsUser(account, authority, null, userId); 3669 } catch (RemoteException e) { 3670 throw e.rethrowFromSystemServer(); 3671 } 3672 } 3673 3674 /** 3675 * Return true if the pending status is true of any matching authorities. 3676 * <p>This method requires the caller to hold the permission 3677 * {@link android.Manifest.permission#READ_SYNC_STATS}. 3678 * @param account the account whose setting we are querying 3679 * @param authority the provider whose behavior is being queried 3680 * @return true if there is a pending sync with the matching account and authority 3681 */ 3682 public static boolean isSyncPending(Account account, String authority) { 3683 return isSyncPendingAsUser(account, authority, UserHandle.myUserId()); 3684 } 3685 3686 /** 3687 * @see #requestSync(Account, String, Bundle) 3688 * @hide 3689 */ 3690 public static boolean isSyncPendingAsUser(Account account, String authority, 3691 @UserIdInt int userId) { 3692 try { 3693 return getContentService().isSyncPendingAsUser(account, authority, null, userId); 3694 } catch (RemoteException e) { 3695 throw e.rethrowFromSystemServer(); 3696 } 3697 } 3698 3699 /** 3700 * Request notifications when the different aspects of the SyncManager change. The 3701 * different items that can be requested are: 3702 * <ul> 3703 * <li> {@link #SYNC_OBSERVER_TYPE_PENDING} 3704 * <li> {@link #SYNC_OBSERVER_TYPE_ACTIVE} 3705 * <li> {@link #SYNC_OBSERVER_TYPE_SETTINGS} 3706 * </ul> 3707 * The caller can set one or more of the status types in the mask for any 3708 * given listener registration. 3709 * @param mask the status change types that will cause the callback to be invoked 3710 * @param callback observer to be invoked when the status changes 3711 * @return a handle that can be used to remove the listener at a later time 3712 */ 3713 public static Object addStatusChangeListener(int mask, final SyncStatusObserver callback) { 3714 if (callback == null) { 3715 throw new IllegalArgumentException("you passed in a null callback"); 3716 } 3717 try { 3718 ISyncStatusObserver.Stub observer = new ISyncStatusObserver.Stub() { 3719 @Override 3720 public void onStatusChanged(int which) throws RemoteException { 3721 callback.onStatusChanged(which); 3722 } 3723 }; 3724 getContentService().addStatusChangeListener(mask, observer); 3725 return observer; 3726 } catch (RemoteException e) { 3727 throw e.rethrowFromSystemServer(); 3728 } 3729 } 3730 3731 /** 3732 * Remove a previously registered status change listener. 3733 * @param handle the handle that was returned by {@link #addStatusChangeListener} 3734 */ 3735 public static void removeStatusChangeListener(Object handle) { 3736 if (handle == null) { 3737 throw new IllegalArgumentException("you passed in a null handle"); 3738 } 3739 try { 3740 getContentService().removeStatusChangeListener((ISyncStatusObserver.Stub) handle); 3741 } catch (RemoteException e) { 3742 throw e.rethrowFromSystemServer(); 3743 } 3744 } 3745 3746 /** 3747 * Store the given {@link Bundle} as a long-lived cached object within the 3748 * system. This can be useful to avoid expensive re-parsing when apps are 3749 * restarted multiple times on low-RAM devices. 3750 * <p> 3751 * The {@link Bundle} is automatically invalidated when a 3752 * {@link #notifyChange(Uri, ContentObserver)} event applies to the key. 3753 * 3754 * @hide 3755 */ 3756 @SystemApi 3757 @RequiresPermission(android.Manifest.permission.CACHE_CONTENT) 3758 public void putCache(@NonNull Uri key, @Nullable Bundle value) { 3759 try { 3760 getContentService().putCache(mContext.getPackageName(), key, value, 3761 mContext.getUserId()); 3762 } catch (RemoteException e) { 3763 throw e.rethrowFromSystemServer(); 3764 } 3765 } 3766 3767 /** 3768 * Retrieve the last {@link Bundle} stored as a long-lived cached object 3769 * within the system. 3770 * 3771 * @return {@code null} if no cached object has been stored, or if the 3772 * stored object has been invalidated due to a 3773 * {@link #notifyChange(Uri, ContentObserver)} event. 3774 * @hide 3775 */ 3776 @SystemApi 3777 @RequiresPermission(android.Manifest.permission.CACHE_CONTENT) 3778 public @Nullable Bundle getCache(@NonNull Uri key) { 3779 try { 3780 final Bundle bundle = getContentService().getCache(mContext.getPackageName(), key, 3781 mContext.getUserId()); 3782 if (bundle != null) bundle.setClassLoader(mContext.getClassLoader()); 3783 return bundle; 3784 } catch (RemoteException e) { 3785 throw e.rethrowFromSystemServer(); 3786 } 3787 } 3788 3789 /** {@hide} */ 3790 public int getTargetSdkVersion() { 3791 return mTargetSdkVersion; 3792 } 3793 3794 /** 3795 * Returns sampling percentage for a given duration. 3796 * 3797 * Always returns at least 1%. 3798 */ 3799 private int samplePercentForDuration(long durationMillis) { 3800 if (durationMillis >= SLOW_THRESHOLD_MILLIS) { 3801 return 100; 3802 } 3803 return (int) (100 * durationMillis / SLOW_THRESHOLD_MILLIS) + 1; 3804 } 3805 3806 private void maybeLogQueryToEventLog( 3807 long durationMillis, Uri uri, String[] projection, @Nullable Bundle queryArgs) { 3808 if (!ENABLE_CONTENT_SAMPLE) return; 3809 int samplePercent = samplePercentForDuration(durationMillis); 3810 if (samplePercent < 100) { 3811 synchronized (mRandom) { 3812 if (mRandom.nextInt(100) >= samplePercent) { 3813 return; 3814 } 3815 } 3816 } 3817 3818 // Ensure a non-null bundle. 3819 queryArgs = (queryArgs != null) ? queryArgs : Bundle.EMPTY; 3820 3821 StringBuilder projectionBuffer = new StringBuilder(100); 3822 if (projection != null) { 3823 for (int i = 0; i < projection.length; ++i) { 3824 // Note: not using a comma delimiter here, as the 3825 // multiple arguments to EventLog.writeEvent later 3826 // stringify with a comma delimiter, which would make 3827 // parsing uglier later. 3828 if (i != 0) projectionBuffer.append('/'); 3829 projectionBuffer.append(projection[i]); 3830 } 3831 } 3832 3833 // ActivityThread.currentPackageName() only returns non-null if the 3834 // current thread is an application main thread. This parameter tells 3835 // us whether an event loop is blocked, and if so, which app it is. 3836 String blockingPackage = AppGlobals.getInitialPackage(); 3837 3838 EventLog.writeEvent( 3839 EventLogTags.CONTENT_QUERY_SAMPLE, 3840 uri.toString(), 3841 projectionBuffer.toString(), 3842 queryArgs.getString(QUERY_ARG_SQL_SELECTION, ""), 3843 queryArgs.getString(QUERY_ARG_SQL_SORT_ORDER, ""), 3844 durationMillis, 3845 blockingPackage != null ? blockingPackage : "", 3846 samplePercent); 3847 } 3848 3849 private void maybeLogUpdateToEventLog( 3850 long durationMillis, Uri uri, String operation, String selection) { 3851 if (!ENABLE_CONTENT_SAMPLE) return; 3852 int samplePercent = samplePercentForDuration(durationMillis); 3853 if (samplePercent < 100) { 3854 synchronized (mRandom) { 3855 if (mRandom.nextInt(100) >= samplePercent) { 3856 return; 3857 } 3858 } 3859 } 3860 String blockingPackage = AppGlobals.getInitialPackage(); 3861 EventLog.writeEvent( 3862 EventLogTags.CONTENT_UPDATE_SAMPLE, 3863 uri.toString(), 3864 operation, 3865 selection != null ? selection : "", 3866 durationMillis, 3867 blockingPackage != null ? blockingPackage : "", 3868 samplePercent); 3869 } 3870 3871 private final class CursorWrapperInner extends CrossProcessCursorWrapper { 3872 private final IContentProvider mContentProvider; 3873 private final AtomicBoolean mProviderReleased = new AtomicBoolean(); 3874 3875 private final CloseGuard mCloseGuard = CloseGuard.get(); 3876 3877 CursorWrapperInner(Cursor cursor, IContentProvider contentProvider) { 3878 super(cursor); 3879 mContentProvider = contentProvider; 3880 mCloseGuard.open("CursorWrapperInner.close"); 3881 } 3882 3883 @Override 3884 public void close() { 3885 mCloseGuard.close(); 3886 super.close(); 3887 3888 if (mProviderReleased.compareAndSet(false, true)) { 3889 ContentResolver.this.releaseProvider(mContentProvider); 3890 } 3891 } 3892 3893 @Override 3894 protected void finalize() throws Throwable { 3895 try { 3896 if (mCloseGuard != null) { 3897 mCloseGuard.warnIfOpen(); 3898 } 3899 3900 close(); 3901 } finally { 3902 super.finalize(); 3903 } 3904 } 3905 } 3906 3907 private final class ParcelFileDescriptorInner extends ParcelFileDescriptor { 3908 private final IContentProvider mContentProvider; 3909 private final AtomicBoolean mProviderReleased = new AtomicBoolean(); 3910 3911 ParcelFileDescriptorInner(ParcelFileDescriptor pfd, IContentProvider icp) { 3912 super(pfd); 3913 mContentProvider = icp; 3914 } 3915 3916 @Override 3917 public void releaseResources() { 3918 if (mProviderReleased.compareAndSet(false, true)) { 3919 ContentResolver.this.releaseProvider(mContentProvider); 3920 } 3921 } 3922 } 3923 3924 /** @hide */ 3925 public static final String CONTENT_SERVICE_NAME = "content"; 3926 3927 /** @hide */ 3928 @UnsupportedAppUsage 3929 public static IContentService getContentService() { 3930 if (sContentService != null) { 3931 return sContentService; 3932 } 3933 IBinder b = ServiceManager.getService(CONTENT_SERVICE_NAME); 3934 sContentService = IContentService.Stub.asInterface(b); 3935 return sContentService; 3936 } 3937 3938 /** @hide */ 3939 @UnsupportedAppUsage 3940 public String getPackageName() { 3941 return mContext.getOpPackageName(); 3942 } 3943 3944 /** @hide */ 3945 public @Nullable String getAttributionTag() { 3946 return mContext.getAttributionTag(); 3947 } 3948 3949 /** @hide */ 3950 public @NonNull AttributionSource getAttributionSource() { 3951 return mContext.getAttributionSource(); 3952 } 3953 3954 @UnsupportedAppUsage 3955 private static volatile IContentService sContentService; 3956 @UnsupportedAppUsage 3957 private final Context mContext; 3958 3959 @Deprecated 3960 @UnsupportedAppUsage 3961 final String mPackageName; 3962 final int mTargetSdkVersion; 3963 final ContentInterface mWrapped; 3964 3965 private static final String TAG = "ContentResolver"; 3966 3967 /** @hide */ 3968 public int resolveUserId(Uri uri) { 3969 return ContentProvider.getUserIdFromUri(uri, mContext.getUserId()); 3970 } 3971 3972 /** @hide */ 3973 public int getUserId() { 3974 return mContext.getUserId(); 3975 } 3976 3977 /** {@hide} */ 3978 @Deprecated 3979 public Drawable getTypeDrawable(String mimeType) { 3980 return getTypeInfo(mimeType).getIcon().loadDrawable(mContext); 3981 } 3982 3983 /** 3984 * Return a detailed description of the given MIME type, including an icon 3985 * and label that describe the type. 3986 * 3987 * @param mimeType Valid, concrete MIME type. 3988 */ 3989 public final @NonNull MimeTypeInfo getTypeInfo(@NonNull String mimeType) { 3990 Objects.requireNonNull(mimeType); 3991 return MimeIconUtils.getTypeInfo(mimeType); 3992 } 3993 3994 /** 3995 * Detailed description of a specific MIME type, including an icon and label 3996 * that describe the type. 3997 */ 3998 public static final class MimeTypeInfo { 3999 private final Icon mIcon; 4000 private final CharSequence mLabel; 4001 private final CharSequence mContentDescription; 4002 4003 /** {@hide} */ 4004 public MimeTypeInfo(@NonNull Icon icon, @NonNull CharSequence label, 4005 @NonNull CharSequence contentDescription) { 4006 mIcon = Objects.requireNonNull(icon); 4007 mLabel = Objects.requireNonNull(label); 4008 mContentDescription = Objects.requireNonNull(contentDescription); 4009 } 4010 4011 /** 4012 * Return a visual representation of this MIME type. This can be styled 4013 * using {@link Icon#setTint(int)} to match surrounding UI. 4014 * 4015 * @see Icon#loadDrawable(Context) 4016 * @see android.widget.ImageView#setImageDrawable(Drawable) 4017 */ 4018 public @NonNull Icon getIcon() { 4019 return mIcon; 4020 } 4021 4022 /** 4023 * Return a textual representation of this MIME type. 4024 * 4025 * @see android.widget.TextView#setText(CharSequence) 4026 */ 4027 public @NonNull CharSequence getLabel() { 4028 return mLabel; 4029 } 4030 4031 /** 4032 * Return a content description for this MIME type. 4033 * 4034 * @see android.view.View#setContentDescription(CharSequence) 4035 */ 4036 public @NonNull CharSequence getContentDescription() { 4037 return mContentDescription; 4038 } 4039 } 4040 4041 /** 4042 * @hide 4043 */ 4044 public static @Nullable Bundle createSqlQueryBundle( 4045 @Nullable String selection, 4046 @Nullable String[] selectionArgs) { 4047 return createSqlQueryBundle(selection, selectionArgs, null); 4048 } 4049 4050 /** 4051 * @hide 4052 */ 4053 public static @Nullable Bundle createSqlQueryBundle( 4054 @Nullable String selection, 4055 @Nullable String[] selectionArgs, 4056 @Nullable String sortOrder) { 4057 4058 if (selection == null && selectionArgs == null && sortOrder == null) { 4059 return null; 4060 } 4061 4062 Bundle queryArgs = new Bundle(); 4063 if (selection != null) { 4064 queryArgs.putString(QUERY_ARG_SQL_SELECTION, selection); 4065 } 4066 if (selectionArgs != null) { 4067 queryArgs.putStringArray(QUERY_ARG_SQL_SELECTION_ARGS, selectionArgs); 4068 } 4069 if (sortOrder != null) { 4070 queryArgs.putString(QUERY_ARG_SQL_SORT_ORDER, sortOrder); 4071 } 4072 return queryArgs; 4073 } 4074 4075 /** @hide */ 4076 public static @NonNull Bundle includeSqlSelectionArgs(@NonNull Bundle queryArgs, 4077 @Nullable String selection, @Nullable String[] selectionArgs) { 4078 if (selection != null) { 4079 queryArgs.putString(QUERY_ARG_SQL_SELECTION, selection); 4080 } 4081 if (selectionArgs != null) { 4082 queryArgs.putStringArray(QUERY_ARG_SQL_SELECTION_ARGS, selectionArgs); 4083 } 4084 return queryArgs; 4085 } 4086 4087 /** 4088 * Returns structured sort args formatted as an SQL sort clause. 4089 * 4090 * NOTE: Collator clauses are suitable for use with non text fields. We might 4091 * choose to omit any collation clause since we don't know the underlying 4092 * type of data to be collated. Imperical testing shows that sqlite3 doesn't 4093 * appear to care much about the presence of collate clauses in queries 4094 * when ordering by numeric fields. For this reason we include collate 4095 * clause unilaterally when {@link #QUERY_ARG_SORT_COLLATION} is present 4096 * in query args bundle. 4097 * 4098 * TODO: Would be nice to explicitly validate that colums referenced in 4099 * {@link #QUERY_ARG_SORT_COLUMNS} are present in the associated projection. 4100 * 4101 * @hide 4102 */ 4103 public static String createSqlSortClause(Bundle queryArgs) { 4104 String[] columns = queryArgs.getStringArray(QUERY_ARG_SORT_COLUMNS); 4105 if (columns == null || columns.length == 0) { 4106 throw new IllegalArgumentException("Can't create sort clause without columns."); 4107 } 4108 4109 String query = TextUtils.join(", ", columns); 4110 4111 // Interpret PRIMARY and SECONDARY collation strength as no-case collation based 4112 // on their javadoc descriptions. 4113 int collation = queryArgs.getInt( 4114 ContentResolver.QUERY_ARG_SORT_COLLATION, java.text.Collator.IDENTICAL); 4115 if (collation == java.text.Collator.PRIMARY || collation == java.text.Collator.SECONDARY) { 4116 query += " COLLATE NOCASE"; 4117 } 4118 4119 int sortDir = queryArgs.getInt(QUERY_ARG_SORT_DIRECTION, Integer.MIN_VALUE); 4120 if (sortDir != Integer.MIN_VALUE) { 4121 switch (sortDir) { 4122 case QUERY_SORT_DIRECTION_ASCENDING: 4123 query += " ASC"; 4124 break; 4125 case QUERY_SORT_DIRECTION_DESCENDING: 4126 query += " DESC"; 4127 break; 4128 default: 4129 throw new IllegalArgumentException("Unsupported sort direction value." 4130 + " See ContentResolver documentation for details."); 4131 } 4132 } 4133 return query; 4134 } 4135 4136 /** 4137 * Convenience method that efficiently loads a visual thumbnail for the 4138 * given {@link Uri}. Internally calls 4139 * {@link ContentProvider#openTypedAssetFile} on the remote provider, but 4140 * also defensively resizes any returned content to match the requested 4141 * target size. 4142 * 4143 * @param uri The item that should be visualized as a thumbnail. 4144 * @param size The target area on the screen where this thumbnail will be 4145 * shown. This is passed to the provider as {@link #EXTRA_SIZE} 4146 * to help it avoid downloading or generating heavy resources. 4147 * @param signal A signal to cancel the operation in progress. 4148 * @return Valid {@link Bitmap} which is a visual thumbnail. 4149 * @throws IOException If any trouble was encountered while generating or 4150 * loading the thumbnail, or if 4151 * {@link CancellationSignal#cancel()} was invoked. 4152 */ 4153 public @NonNull Bitmap loadThumbnail(@NonNull Uri uri, @NonNull Size size, 4154 @Nullable CancellationSignal signal) throws IOException { 4155 return loadThumbnail(this, uri, size, signal, ImageDecoder.ALLOCATOR_SOFTWARE); 4156 } 4157 4158 /** {@hide} */ 4159 public static Bitmap loadThumbnail(@NonNull ContentInterface content, @NonNull Uri uri, 4160 @NonNull Size size, @Nullable CancellationSignal signal, int allocator) 4161 throws IOException { 4162 Objects.requireNonNull(content); 4163 Objects.requireNonNull(uri); 4164 Objects.requireNonNull(size); 4165 4166 // Convert to Point, since that's what the API is defined as 4167 final Bundle opts = new Bundle(); 4168 opts.putParcelable(EXTRA_SIZE, new Point(size.getWidth(), size.getHeight())); 4169 final Int64Ref orientation = new Int64Ref(0); 4170 4171 Bitmap bitmap = ImageDecoder.decodeBitmap(ImageDecoder.createSource(() -> { 4172 final AssetFileDescriptor afd = content.openTypedAssetFile(uri, "image/*", opts, 4173 signal); 4174 final Bundle extras = afd.getExtras(); 4175 orientation.value = (extras != null) ? extras.getInt(EXTRA_ORIENTATION, 0) : 0; 4176 return afd; 4177 }), (ImageDecoder decoder, ImageInfo info, Source source) -> { 4178 decoder.setAllocator(allocator); 4179 4180 // One last-ditch check to see if we've been canceled. 4181 if (signal != null) signal.throwIfCanceled(); 4182 4183 // We requested a rough thumbnail size, but the remote size may have 4184 // returned something giant, so defensively scale down as needed. 4185 final int widthSample = info.getSize().getWidth() / size.getWidth(); 4186 final int heightSample = info.getSize().getHeight() / size.getHeight(); 4187 final int sample = Math.max(widthSample, heightSample); 4188 if (sample > 1) { 4189 decoder.setTargetSampleSize(sample); 4190 } 4191 }); 4192 4193 // Transform the bitmap if requested. We use a side-channel to 4194 // communicate the orientation, since EXIF thumbnails don't contain 4195 // the rotation flags of the original image. 4196 if (orientation.value != 0) { 4197 final int width = bitmap.getWidth(); 4198 final int height = bitmap.getHeight(); 4199 4200 final Matrix m = new Matrix(); 4201 m.setRotate(orientation.value, width / 2, height / 2); 4202 bitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height, m, false); 4203 } 4204 4205 return bitmap; 4206 } 4207 4208 /** {@hide} */ 4209 public static void onDbCorruption(String tag, String message, Throwable stacktrace) { 4210 try { 4211 getContentService().onDbCorruption(tag, message, Log.getStackTraceString(stacktrace)); 4212 } catch (RemoteException e) { 4213 e.rethrowFromSystemServer(); 4214 } 4215 } 4216 4217 /** 4218 * Decode a path generated by {@link #encodeToFile(Uri)} back into 4219 * the original {@link Uri}. 4220 * <p> 4221 * This is used to offer a way to intercept filesystem calls in 4222 * {@link ContentProvider} unaware code and redirect them to a 4223 * {@link ContentProvider} when they attempt to use {@code _DATA} columns 4224 * that are otherwise deprecated. 4225 * 4226 * @hide 4227 */ 4228 @SystemApi 4229 // We can't accept an already-opened FD here, since these methods are 4230 // rewriting actual filesystem paths 4231 @SuppressLint("StreamFiles") 4232 public static @NonNull Uri decodeFromFile(@NonNull File file) { 4233 return translateDeprecatedDataPath(file.getAbsolutePath()); 4234 } 4235 4236 /** 4237 * Encode a {@link Uri} into an opaque filesystem path which can then be 4238 * resurrected by {@link #decodeFromFile(File)}. 4239 * <p> 4240 * This is used to offer a way to intercept filesystem calls in 4241 * {@link ContentProvider} unaware code and redirect them to a 4242 * {@link ContentProvider} when they attempt to use {@code _DATA} columns 4243 * that are otherwise deprecated. 4244 * 4245 * @hide 4246 */ 4247 @SystemApi 4248 // We can't accept an already-opened FD here, since these methods are 4249 // rewriting actual filesystem paths 4250 @SuppressLint("StreamFiles") 4251 public static @NonNull File encodeToFile(@NonNull Uri uri) { 4252 return new File(translateDeprecatedDataPath(uri)); 4253 } 4254 4255 /** {@hide} */ 4256 public static @NonNull Uri translateDeprecatedDataPath(@NonNull String path) { 4257 final String ssp = "//" + path.substring(DEPRECATE_DATA_PREFIX.length()); 4258 return Uri.parse(new Uri.Builder().scheme(SCHEME_CONTENT) 4259 .encodedOpaquePart(ssp).build().toString()); 4260 } 4261 4262 /** {@hide} */ 4263 public static @NonNull String translateDeprecatedDataPath(@NonNull Uri uri) { 4264 return DEPRECATE_DATA_PREFIX + uri.getEncodedSchemeSpecificPart().substring(2); 4265 } 4266 } 4267