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