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