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