PageRenderTime 65ms CodeModel.GetById 28ms RepoModel.GetById 1ms app.codeStats 0ms

/core/java/android/content/ContentResolver.java

https://github.com/Kali-/android_frameworks_base
Java | 1205 lines | 565 code | 68 blank | 572 comment | 108 complexity | 4dfe19883bbc812f92d9da0a02a20807 MD5 | raw file
  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. package android.content;
  17. import dalvik.system.CloseGuard;
  18. import android.accounts.Account;
  19. import android.app.ActivityManagerNative;
  20. import android.app.ActivityThread;
  21. import android.app.AppGlobals;
  22. import android.content.pm.PackageManager.NameNotFoundException;
  23. import android.content.res.AssetFileDescriptor;
  24. import android.content.res.Resources;
  25. import android.database.ContentObserver;
  26. import android.database.CrossProcessCursorWrapper;
  27. import android.database.Cursor;
  28. import android.database.CursorWrapper;
  29. import android.database.IContentObserver;
  30. import android.net.Uri;
  31. import android.os.Bundle;
  32. import android.os.IBinder;
  33. import android.os.ParcelFileDescriptor;
  34. import android.os.RemoteException;
  35. import android.os.ServiceManager;
  36. import android.os.StrictMode;
  37. import android.os.SystemClock;
  38. import android.text.TextUtils;
  39. import android.util.EventLog;
  40. import android.util.Log;
  41. import java.io.File;
  42. import java.io.FileInputStream;
  43. import java.io.FileNotFoundException;
  44. import java.io.IOException;
  45. import java.io.InputStream;
  46. import java.io.OutputStream;
  47. import java.util.ArrayList;
  48. import java.util.List;
  49. import java.util.Random;
  50. /**
  51. * This class provides applications access to the content model.
  52. *
  53. * <div class="special reference">
  54. * <h3>Developer Guides</h3>
  55. * <p>For more information about using a ContentResolver with content providers, read the
  56. * <a href="{@docRoot}guide/topics/providers/content-providers.html">Content Providers</a>
  57. * developer guide.</p>
  58. */
  59. public abstract class ContentResolver {
  60. /**
  61. * @deprecated instead use
  62. * {@link #requestSync(android.accounts.Account, String, android.os.Bundle)}
  63. */
  64. @Deprecated
  65. public static final String SYNC_EXTRAS_ACCOUNT = "account";
  66. public static final String SYNC_EXTRAS_EXPEDITED = "expedited";
  67. /**
  68. * @deprecated instead use
  69. * {@link #SYNC_EXTRAS_MANUAL}
  70. */
  71. @Deprecated
  72. public static final String SYNC_EXTRAS_FORCE = "force";
  73. /**
  74. * If this extra is set to true then the sync settings (like getSyncAutomatically())
  75. * are ignored by the sync scheduler.
  76. */
  77. public static final String SYNC_EXTRAS_IGNORE_SETTINGS = "ignore_settings";
  78. /**
  79. * If this extra is set to true then any backoffs for the initial attempt (e.g. due to retries)
  80. * are ignored by the sync scheduler. If this request fails and gets rescheduled then the
  81. * retries will still honor the backoff.
  82. */
  83. public static final String SYNC_EXTRAS_IGNORE_BACKOFF = "ignore_backoff";
  84. /**
  85. * If this extra is set to true then the request will not be retried if it fails.
  86. */
  87. public static final String SYNC_EXTRAS_DO_NOT_RETRY = "do_not_retry";
  88. /**
  89. * Setting this extra is the equivalent of setting both {@link #SYNC_EXTRAS_IGNORE_SETTINGS}
  90. * and {@link #SYNC_EXTRAS_IGNORE_BACKOFF}
  91. */
  92. public static final String SYNC_EXTRAS_MANUAL = "force";
  93. public static final String SYNC_EXTRAS_UPLOAD = "upload";
  94. public static final String SYNC_EXTRAS_OVERRIDE_TOO_MANY_DELETIONS = "deletions_override";
  95. public static final String SYNC_EXTRAS_DISCARD_LOCAL_DELETIONS = "discard_deletions";
  96. /**
  97. * Set by the SyncManager to request that the SyncAdapter initialize itself for
  98. * the given account/authority pair. One required initialization step is to
  99. * ensure that {@link #setIsSyncable(android.accounts.Account, String, int)} has been
  100. * called with a >= 0 value. When this flag is set the SyncAdapter does not need to
  101. * do a full sync, though it is allowed to do so.
  102. */
  103. public static final String SYNC_EXTRAS_INITIALIZE = "initialize";
  104. public static final String SCHEME_CONTENT = "content";
  105. public static final String SCHEME_ANDROID_RESOURCE = "android.resource";
  106. public static final String SCHEME_FILE = "file";
  107. /**
  108. * This is the Android platform's base MIME type for a content: URI
  109. * containing a Cursor of a single item. Applications should use this
  110. * as the base type along with their own sub-type of their content: URIs
  111. * that represent a particular item. For example, hypothetical IMAP email
  112. * client may have a URI
  113. * <code>content://com.company.provider.imap/inbox/1</code> for a particular
  114. * message in the inbox, whose MIME type would be reported as
  115. * <code>CURSOR_ITEM_BASE_TYPE + "/vnd.company.imap-msg"</code>
  116. *
  117. * <p>Compare with {@link #CURSOR_DIR_BASE_TYPE}.
  118. */
  119. public static final String CURSOR_ITEM_BASE_TYPE = "vnd.android.cursor.item";
  120. /**
  121. * This is the Android platform's base MIME type for a content: URI
  122. * containing a Cursor of zero or more items. Applications should use this
  123. * as the base type along with their own sub-type of their content: URIs
  124. * that represent a directory of items. For example, hypothetical IMAP email
  125. * client may have a URI
  126. * <code>content://com.company.provider.imap/inbox</code> for all of the
  127. * messages in its inbox, whose MIME type would be reported as
  128. * <code>CURSOR_DIR_BASE_TYPE + "/vnd.company.imap-msg"</code>
  129. *
  130. * <p>Note how the base MIME type varies between this and
  131. * {@link #CURSOR_ITEM_BASE_TYPE} depending on whether there is
  132. * one single item or multiple items in the data set, while the sub-type
  133. * remains the same because in either case the data structure contained
  134. * in the cursor is the same.
  135. */
  136. public static final String CURSOR_DIR_BASE_TYPE = "vnd.android.cursor.dir";
  137. /** @hide */
  138. public static final int SYNC_ERROR_SYNC_ALREADY_IN_PROGRESS = 1;
  139. /** @hide */
  140. public static final int SYNC_ERROR_AUTHENTICATION = 2;
  141. /** @hide */
  142. public static final int SYNC_ERROR_IO = 3;
  143. /** @hide */
  144. public static final int SYNC_ERROR_PARSE = 4;
  145. /** @hide */
  146. public static final int SYNC_ERROR_CONFLICT = 5;
  147. /** @hide */
  148. public static final int SYNC_ERROR_TOO_MANY_DELETIONS = 6;
  149. /** @hide */
  150. public static final int SYNC_ERROR_TOO_MANY_RETRIES = 7;
  151. /** @hide */
  152. public static final int SYNC_ERROR_INTERNAL = 8;
  153. public static final int SYNC_OBSERVER_TYPE_SETTINGS = 1<<0;
  154. public static final int SYNC_OBSERVER_TYPE_PENDING = 1<<1;
  155. public static final int SYNC_OBSERVER_TYPE_ACTIVE = 1<<2;
  156. /** @hide */
  157. public static final int SYNC_OBSERVER_TYPE_STATUS = 1<<3;
  158. /** @hide */
  159. public static final int SYNC_OBSERVER_TYPE_ALL = 0x7fffffff;
  160. // Always log queries which take 500ms+; shorter queries are
  161. // sampled accordingly.
  162. private static final int SLOW_THRESHOLD_MILLIS = 500;
  163. private final Random mRandom = new Random(); // guarded by itself
  164. public ContentResolver(Context context) {
  165. mContext = context;
  166. }
  167. /** @hide */
  168. public final Context getContext() {
  169. return mContext;
  170. }
  171. /** @hide */
  172. protected abstract IContentProvider acquireProvider(Context c, String name);
  173. /** Providing a default implementation of this, to avoid having to change
  174. * a lot of other things, but implementations of ContentResolver should
  175. * implement it. @hide */
  176. protected IContentProvider acquireExistingProvider(Context c, String name) {
  177. return acquireProvider(c, name);
  178. }
  179. /** @hide */
  180. public abstract boolean releaseProvider(IContentProvider icp);
  181. /**
  182. * Return the MIME type of the given content URL.
  183. *
  184. * @param url A Uri identifying content (either a list or specific type),
  185. * using the content:// scheme.
  186. * @return A MIME type for the content, or null if the URL is invalid or the type is unknown
  187. */
  188. public final String getType(Uri url) {
  189. IContentProvider provider = acquireExistingProvider(url);
  190. if (provider != null) {
  191. try {
  192. return provider.getType(url);
  193. } catch (RemoteException e) {
  194. return null;
  195. } catch (java.lang.Exception e) {
  196. Log.w(TAG, "Failed to get type for: " + url + " (" + e.getMessage() + ")");
  197. return null;
  198. } finally {
  199. releaseProvider(provider);
  200. }
  201. }
  202. if (!SCHEME_CONTENT.equals(url.getScheme())) {
  203. return null;
  204. }
  205. try {
  206. String type = ActivityManagerNative.getDefault().getProviderMimeType(url);
  207. return type;
  208. } catch (RemoteException e) {
  209. // Arbitrary and not worth documenting, as Activity
  210. // Manager will kill this process shortly anyway.
  211. return null;
  212. } catch (java.lang.Exception e) {
  213. Log.w(TAG, "Failed to get type for: " + url + " (" + e.getMessage() + ")");
  214. return null;
  215. }
  216. }
  217. /**
  218. * Query for the possible MIME types for the representations the given
  219. * content URL can be returned when opened as as stream with
  220. * {@link #openTypedAssetFileDescriptor}. Note that the types here are
  221. * not necessarily a superset of the type returned by {@link #getType} --
  222. * many content providers can not return a raw stream for the structured
  223. * data that they contain.
  224. *
  225. * @param url A Uri identifying content (either a list or specific type),
  226. * using the content:// scheme.
  227. * @param mimeTypeFilter The desired MIME type. This may be a pattern,
  228. * such as *\/*, to query for all available MIME types that match the
  229. * pattern.
  230. * @return Returns an array of MIME type strings for all availablle
  231. * data streams that match the given mimeTypeFilter. If there are none,
  232. * null is returned.
  233. */
  234. public String[] getStreamTypes(Uri url, String mimeTypeFilter) {
  235. IContentProvider provider = acquireProvider(url);
  236. if (provider == null) {
  237. return null;
  238. }
  239. try {
  240. return provider.getStreamTypes(url, mimeTypeFilter);
  241. } catch (RemoteException e) {
  242. // Arbitrary and not worth documenting, as Activity
  243. // Manager will kill this process shortly anyway.
  244. return null;
  245. } finally {
  246. releaseProvider(provider);
  247. }
  248. }
  249. /**
  250. * <p>
  251. * Query the given URI, returning a {@link Cursor} over the result set.
  252. * </p>
  253. * <p>
  254. * For best performance, the caller should follow these guidelines:
  255. * <ul>
  256. * <li>Provide an explicit projection, to prevent
  257. * reading data from storage that aren't going to be used.</li>
  258. * <li>Use question mark parameter markers such as 'phone=?' instead of
  259. * explicit values in the {@code selection} parameter, so that queries
  260. * that differ only by those values will be recognized as the same
  261. * for caching purposes.</li>
  262. * </ul>
  263. * </p>
  264. *
  265. * @param uri The URI, using the content:// scheme, for the content to
  266. * retrieve.
  267. * @param projection A list of which columns to return. Passing null will
  268. * return all columns, which is inefficient.
  269. * @param selection A filter declaring which rows to return, formatted as an
  270. * SQL WHERE clause (excluding the WHERE itself). Passing null will
  271. * return all rows for the given URI.
  272. * @param selectionArgs You may include ?s in selection, which will be
  273. * replaced by the values from selectionArgs, in the order that they
  274. * appear in the selection. The values will be bound as Strings.
  275. * @param sortOrder How to order the rows, formatted as an SQL ORDER BY
  276. * clause (excluding the ORDER BY itself). Passing null will use the
  277. * default sort order, which may be unordered.
  278. * @return A Cursor object, which is positioned before the first entry, or null
  279. * @see Cursor
  280. */
  281. public final Cursor query(Uri uri, String[] projection,
  282. String selection, String[] selectionArgs, String sortOrder) {
  283. IContentProvider provider = acquireProvider(uri);
  284. if (provider == null) {
  285. return null;
  286. }
  287. try {
  288. long startTime = SystemClock.uptimeMillis();
  289. Cursor qCursor = provider.query(uri, projection, selection, selectionArgs, sortOrder);
  290. if (qCursor == null) {
  291. releaseProvider(provider);
  292. return null;
  293. }
  294. // force query execution
  295. qCursor.getCount();
  296. long durationMillis = SystemClock.uptimeMillis() - startTime;
  297. maybeLogQueryToEventLog(durationMillis, uri, projection, selection, sortOrder);
  298. // Wrap the cursor object into CursorWrapperInner object
  299. return new CursorWrapperInner(qCursor, provider);
  300. } catch (RemoteException e) {
  301. releaseProvider(provider);
  302. // Arbitrary and not worth documenting, as Activity
  303. // Manager will kill this process shortly anyway.
  304. return null;
  305. } catch (RuntimeException e) {
  306. releaseProvider(provider);
  307. throw e;
  308. }
  309. }
  310. /**
  311. * Open a stream on to the content associated with a content URI. If there
  312. * is no data associated with the URI, FileNotFoundException is thrown.
  313. *
  314. * <h5>Accepts the following URI schemes:</h5>
  315. * <ul>
  316. * <li>content ({@link #SCHEME_CONTENT})</li>
  317. * <li>android.resource ({@link #SCHEME_ANDROID_RESOURCE})</li>
  318. * <li>file ({@link #SCHEME_FILE})</li>
  319. * </ul>
  320. *
  321. * <p>See {@link #openAssetFileDescriptor(Uri, String)} for more information
  322. * on these schemes.
  323. *
  324. * @param uri The desired URI.
  325. * @return InputStream
  326. * @throws FileNotFoundException if the provided URI could not be opened.
  327. * @see #openAssetFileDescriptor(Uri, String)
  328. */
  329. public final InputStream openInputStream(Uri uri)
  330. throws FileNotFoundException {
  331. String scheme = uri.getScheme();
  332. if (SCHEME_ANDROID_RESOURCE.equals(scheme)) {
  333. // Note: left here to avoid breaking compatibility. May be removed
  334. // with sufficient testing.
  335. OpenResourceIdResult r = getResourceId(uri);
  336. try {
  337. InputStream stream = r.r.openRawResource(r.id);
  338. return stream;
  339. } catch (Resources.NotFoundException ex) {
  340. throw new FileNotFoundException("Resource does not exist: " + uri);
  341. }
  342. } else if (SCHEME_FILE.equals(scheme)) {
  343. // Note: left here to avoid breaking compatibility. May be removed
  344. // with sufficient testing.
  345. return new FileInputStream(uri.getPath());
  346. } else {
  347. AssetFileDescriptor fd = openAssetFileDescriptor(uri, "r");
  348. try {
  349. return fd != null ? fd.createInputStream() : null;
  350. } catch (IOException e) {
  351. throw new FileNotFoundException("Unable to create stream");
  352. }
  353. }
  354. }
  355. /**
  356. * Synonym for {@link #openOutputStream(Uri, String)
  357. * openOutputStream(uri, "w")}.
  358. * @throws FileNotFoundException if the provided URI could not be opened.
  359. */
  360. public final OutputStream openOutputStream(Uri uri)
  361. throws FileNotFoundException {
  362. return openOutputStream(uri, "w");
  363. }
  364. /**
  365. * Open a stream on to the content associated with a content URI. If there
  366. * is no data associated with the URI, FileNotFoundException is thrown.
  367. *
  368. * <h5>Accepts the following URI schemes:</h5>
  369. * <ul>
  370. * <li>content ({@link #SCHEME_CONTENT})</li>
  371. * <li>file ({@link #SCHEME_FILE})</li>
  372. * </ul>
  373. *
  374. * <p>See {@link #openAssetFileDescriptor(Uri, String)} for more information
  375. * on these schemes.
  376. *
  377. * @param uri The desired URI.
  378. * @param mode May be "w", "wa", "rw", or "rwt".
  379. * @return OutputStream
  380. * @throws FileNotFoundException if the provided URI could not be opened.
  381. * @see #openAssetFileDescriptor(Uri, String)
  382. */
  383. public final OutputStream openOutputStream(Uri uri, String mode)
  384. throws FileNotFoundException {
  385. AssetFileDescriptor fd = openAssetFileDescriptor(uri, mode);
  386. try {
  387. return fd != null ? fd.createOutputStream() : null;
  388. } catch (IOException e) {
  389. throw new FileNotFoundException("Unable to create stream");
  390. }
  391. }
  392. /**
  393. * Open a raw file descriptor to access data under a URI. This
  394. * is like {@link #openAssetFileDescriptor(Uri, String)}, but uses the
  395. * underlying {@link ContentProvider#openFile}
  396. * ContentProvider.openFile()} method, so will <em>not</em> work with
  397. * providers that return sub-sections of files. If at all possible,
  398. * you should use {@link #openAssetFileDescriptor(Uri, String)}. You
  399. * will receive a FileNotFoundException exception if the provider returns a
  400. * sub-section of a file.
  401. *
  402. * <h5>Accepts the following URI schemes:</h5>
  403. * <ul>
  404. * <li>content ({@link #SCHEME_CONTENT})</li>
  405. * <li>file ({@link #SCHEME_FILE})</li>
  406. * </ul>
  407. *
  408. * <p>See {@link #openAssetFileDescriptor(Uri, String)} for more information
  409. * on these schemes.
  410. *
  411. * @param uri The desired URI to open.
  412. * @param mode The file mode to use, as per {@link ContentProvider#openFile
  413. * ContentProvider.openFile}.
  414. * @return Returns a new ParcelFileDescriptor pointing to the file. You
  415. * own this descriptor and are responsible for closing it when done.
  416. * @throws FileNotFoundException Throws FileNotFoundException of no
  417. * file exists under the URI or the mode is invalid.
  418. * @see #openAssetFileDescriptor(Uri, String)
  419. */
  420. public final ParcelFileDescriptor openFileDescriptor(Uri uri,
  421. String mode) throws FileNotFoundException {
  422. AssetFileDescriptor afd = openAssetFileDescriptor(uri, mode);
  423. if (afd == null) {
  424. return null;
  425. }
  426. if (afd.getDeclaredLength() < 0) {
  427. // This is a full file!
  428. return afd.getParcelFileDescriptor();
  429. }
  430. // Client can't handle a sub-section of a file, so close what
  431. // we got and bail with an exception.
  432. try {
  433. afd.close();
  434. } catch (IOException e) {
  435. }
  436. throw new FileNotFoundException("Not a whole file");
  437. }
  438. /**
  439. * Open a raw file descriptor to access data under a URI. This
  440. * interacts with the underlying {@link ContentProvider#openAssetFile}
  441. * method of the provider associated with the given URI, to retrieve any file stored there.
  442. *
  443. * <h5>Accepts the following URI schemes:</h5>
  444. * <ul>
  445. * <li>content ({@link #SCHEME_CONTENT})</li>
  446. * <li>android.resource ({@link #SCHEME_ANDROID_RESOURCE})</li>
  447. * <li>file ({@link #SCHEME_FILE})</li>
  448. * </ul>
  449. * <h5>The android.resource ({@link #SCHEME_ANDROID_RESOURCE}) Scheme</h5>
  450. * <p>
  451. * A Uri object can be used to reference a resource in an APK file. The
  452. * Uri should be one of the following formats:
  453. * <ul>
  454. * <li><code>android.resource://package_name/id_number</code><br/>
  455. * <code>package_name</code> is your package name as listed in your AndroidManifest.xml.
  456. * For example <code>com.example.myapp</code><br/>
  457. * <code>id_number</code> is the int form of the ID.<br/>
  458. * The easiest way to construct this form is
  459. * <pre>Uri uri = Uri.parse("android.resource://com.example.myapp/" + R.raw.my_resource");</pre>
  460. * </li>
  461. * <li><code>android.resource://package_name/type/name</code><br/>
  462. * <code>package_name</code> is your package name as listed in your AndroidManifest.xml.
  463. * For example <code>com.example.myapp</code><br/>
  464. * <code>type</code> is the string form of the resource type. For example, <code>raw</code>
  465. * or <code>drawable</code>.
  466. * <code>name</code> is the string form of the resource name. That is, whatever the file
  467. * name was in your res directory, without the type extension.
  468. * The easiest way to construct this form is
  469. * <pre>Uri uri = Uri.parse("android.resource://com.example.myapp/raw/my_resource");</pre>
  470. * </li>
  471. * </ul>
  472. *
  473. * <p>Note that if this function is called for read-only input (mode is "r")
  474. * on a content: URI, it will instead call {@link #openTypedAssetFileDescriptor}
  475. * for you with a MIME type of "*\/*". This allows such callers to benefit
  476. * from any built-in data conversion that a provider implements.
  477. *
  478. * @param uri The desired URI to open.
  479. * @param mode The file mode to use, as per {@link ContentProvider#openAssetFile
  480. * ContentProvider.openAssetFile}.
  481. * @return Returns a new ParcelFileDescriptor pointing to the file. You
  482. * own this descriptor and are responsible for closing it when done.
  483. * @throws FileNotFoundException Throws FileNotFoundException of no
  484. * file exists under the URI or the mode is invalid.
  485. */
  486. public final AssetFileDescriptor openAssetFileDescriptor(Uri uri,
  487. String mode) throws FileNotFoundException {
  488. String scheme = uri.getScheme();
  489. if (SCHEME_ANDROID_RESOURCE.equals(scheme)) {
  490. if (!"r".equals(mode)) {
  491. throw new FileNotFoundException("Can't write resources: " + uri);
  492. }
  493. OpenResourceIdResult r = getResourceId(uri);
  494. try {
  495. return r.r.openRawResourceFd(r.id);
  496. } catch (Resources.NotFoundException ex) {
  497. throw new FileNotFoundException("Resource does not exist: " + uri);
  498. }
  499. } else if (SCHEME_FILE.equals(scheme)) {
  500. ParcelFileDescriptor pfd = ParcelFileDescriptor.open(
  501. new File(uri.getPath()), modeToMode(uri, mode));
  502. return new AssetFileDescriptor(pfd, 0, -1);
  503. } else {
  504. if ("r".equals(mode)) {
  505. return openTypedAssetFileDescriptor(uri, "*/*", null);
  506. } else {
  507. IContentProvider provider = acquireProvider(uri);
  508. if (provider == null) {
  509. throw new FileNotFoundException("No content provider: " + uri);
  510. }
  511. try {
  512. AssetFileDescriptor fd = provider.openAssetFile(uri, mode);
  513. if(fd == null) {
  514. // The provider will be released by the finally{} clause
  515. return null;
  516. }
  517. ParcelFileDescriptor pfd = new ParcelFileDescriptorInner(
  518. fd.getParcelFileDescriptor(), provider);
  519. // Success! Don't release the provider when exiting, let
  520. // ParcelFileDescriptorInner do that when it is closed.
  521. provider = null;
  522. return new AssetFileDescriptor(pfd, fd.getStartOffset(),
  523. fd.getDeclaredLength());
  524. } catch (RemoteException e) {
  525. // Somewhat pointless, as Activity Manager will kill this
  526. // process shortly anyway if the depdendent ContentProvider dies.
  527. throw new FileNotFoundException("Dead content provider: " + uri);
  528. } catch (FileNotFoundException e) {
  529. throw e;
  530. } finally {
  531. if (provider != null) {
  532. releaseProvider(provider);
  533. }
  534. }
  535. }
  536. }
  537. }
  538. /**
  539. * Open a raw file descriptor to access (potentially type transformed)
  540. * data from a "content:" URI. This interacts with the underlying
  541. * {@link ContentProvider#openTypedAssetFile} method of the provider
  542. * associated with the given URI, to retrieve retrieve any appropriate
  543. * data stream for the data stored there.
  544. *
  545. * <p>Unlike {@link #openAssetFileDescriptor}, this function only works
  546. * with "content:" URIs, because content providers are the only facility
  547. * with an associated MIME type to ensure that the returned data stream
  548. * is of the desired type.
  549. *
  550. * <p>All text/* streams are encoded in UTF-8.
  551. *
  552. * @param uri The desired URI to open.
  553. * @param mimeType The desired MIME type of the returned data. This can
  554. * be a pattern such as *\/*, which will allow the content provider to
  555. * select a type, though there is no way for you to determine what type
  556. * it is returning.
  557. * @param opts Additional provider-dependent options.
  558. * @return Returns a new ParcelFileDescriptor from which you can read the
  559. * data stream from the provider. Note that this may be a pipe, meaning
  560. * you can't seek in it. The only seek you should do is if the
  561. * AssetFileDescriptor contains an offset, to move to that offset before
  562. * reading. You own this descriptor and are responsible for closing it when done.
  563. * @throws FileNotFoundException Throws FileNotFoundException of no
  564. * data of the desired type exists under the URI.
  565. */
  566. public final AssetFileDescriptor openTypedAssetFileDescriptor(Uri uri,
  567. String mimeType, Bundle opts) throws FileNotFoundException {
  568. IContentProvider provider = acquireProvider(uri);
  569. if (provider == null) {
  570. throw new FileNotFoundException("No content provider: " + uri);
  571. }
  572. try {
  573. AssetFileDescriptor fd = provider.openTypedAssetFile(uri, mimeType, opts);
  574. if (fd == null) {
  575. // The provider will be released by the finally{} clause
  576. return null;
  577. }
  578. ParcelFileDescriptor pfd = new ParcelFileDescriptorInner(
  579. fd.getParcelFileDescriptor(), provider);
  580. // Success! Don't release the provider when exiting, let
  581. // ParcelFileDescriptorInner do that when it is closed.
  582. provider = null;
  583. return new AssetFileDescriptor(pfd, fd.getStartOffset(),
  584. fd.getDeclaredLength());
  585. } catch (RemoteException e) {
  586. throw new FileNotFoundException("Dead content provider: " + uri);
  587. } catch (FileNotFoundException e) {
  588. throw e;
  589. } finally {
  590. if (provider != null) {
  591. releaseProvider(provider);
  592. }
  593. }
  594. }
  595. /**
  596. * A resource identified by the {@link Resources} that contains it, and a resource id.
  597. *
  598. * @hide
  599. */
  600. public class OpenResourceIdResult {
  601. public Resources r;
  602. public int id;
  603. }
  604. /**
  605. * Resolves an android.resource URI to a {@link Resources} and a resource id.
  606. *
  607. * @hide
  608. */
  609. public OpenResourceIdResult getResourceId(Uri uri) throws FileNotFoundException {
  610. String authority = uri.getAuthority();
  611. Resources r;
  612. if (TextUtils.isEmpty(authority)) {
  613. throw new FileNotFoundException("No authority: " + uri);
  614. } else {
  615. try {
  616. r = mContext.getPackageManager().getResourcesForApplication(authority);
  617. } catch (NameNotFoundException ex) {
  618. throw new FileNotFoundException("No package found for authority: " + uri);
  619. }
  620. }
  621. List<String> path = uri.getPathSegments();
  622. if (path == null) {
  623. throw new FileNotFoundException("No path: " + uri);
  624. }
  625. int len = path.size();
  626. int id;
  627. if (len == 1) {
  628. try {
  629. id = Integer.parseInt(path.get(0));
  630. } catch (NumberFormatException e) {
  631. throw new FileNotFoundException("Single path segment is not a resource ID: " + uri);
  632. }
  633. } else if (len == 2) {
  634. id = r.getIdentifier(path.get(1), path.get(0), authority);
  635. } else {
  636. throw new FileNotFoundException("More than two path segments: " + uri);
  637. }
  638. if (id == 0) {
  639. throw new FileNotFoundException("No resource found for: " + uri);
  640. }
  641. OpenResourceIdResult res = new OpenResourceIdResult();
  642. res.r = r;
  643. res.id = id;
  644. return res;
  645. }
  646. /** @hide */
  647. static public int modeToMode(Uri uri, String mode) throws FileNotFoundException {
  648. int modeBits;
  649. if ("r".equals(mode)) {
  650. modeBits = ParcelFileDescriptor.MODE_READ_ONLY;
  651. } else if ("w".equals(mode) || "wt".equals(mode)) {
  652. modeBits = ParcelFileDescriptor.MODE_WRITE_ONLY
  653. | ParcelFileDescriptor.MODE_CREATE
  654. | ParcelFileDescriptor.MODE_TRUNCATE;
  655. } else if ("wa".equals(mode)) {
  656. modeBits = ParcelFileDescriptor.MODE_WRITE_ONLY
  657. | ParcelFileDescriptor.MODE_CREATE
  658. | ParcelFileDescriptor.MODE_APPEND;
  659. } else if ("rw".equals(mode)) {
  660. modeBits = ParcelFileDescriptor.MODE_READ_WRITE
  661. | ParcelFileDescriptor.MODE_CREATE;
  662. } else if ("rwt".equals(mode)) {
  663. modeBits = ParcelFileDescriptor.MODE_READ_WRITE
  664. | ParcelFileDescriptor.MODE_CREATE
  665. | ParcelFileDescriptor.MODE_TRUNCATE;
  666. } else {
  667. throw new FileNotFoundException("Bad mode for " + uri + ": "
  668. + mode);
  669. }
  670. return modeBits;
  671. }
  672. /**
  673. * Inserts a row into a table at the given URL.
  674. *
  675. * If the content provider supports transactions the insertion will be atomic.
  676. *
  677. * @param url The URL of the table to insert into.
  678. * @param values The initial values for the newly inserted row. The key is the column name for
  679. * the field. Passing an empty ContentValues will create an empty row.
  680. * @return the URL of the newly created row.
  681. */
  682. public final Uri insert(Uri url, ContentValues values)
  683. {
  684. IContentProvider provider = acquireProvider(url);
  685. if (provider == null) {
  686. throw new IllegalArgumentException("Unknown URL " + url);
  687. }
  688. try {
  689. long startTime = SystemClock.uptimeMillis();
  690. Uri createdRow = provider.insert(url, values);
  691. long durationMillis = SystemClock.uptimeMillis() - startTime;
  692. maybeLogUpdateToEventLog(durationMillis, url, "insert", null /* where */);
  693. return createdRow;
  694. } catch (RemoteException e) {
  695. // Arbitrary and not worth documenting, as Activity
  696. // Manager will kill this process shortly anyway.
  697. return null;
  698. } finally {
  699. releaseProvider(provider);
  700. }
  701. }
  702. /**
  703. * Applies each of the {@link ContentProviderOperation} objects and returns an array
  704. * of their results. Passes through OperationApplicationException, which may be thrown
  705. * by the call to {@link ContentProviderOperation#apply}.
  706. * If all the applications succeed then a {@link ContentProviderResult} array with the
  707. * same number of elements as the operations will be returned. It is implementation-specific
  708. * how many, if any, operations will have been successfully applied if a call to
  709. * apply results in a {@link OperationApplicationException}.
  710. * @param authority the authority of the ContentProvider to which this batch should be applied
  711. * @param operations the operations to apply
  712. * @return the results of the applications
  713. * @throws OperationApplicationException thrown if an application fails.
  714. * See {@link ContentProviderOperation#apply} for more information.
  715. * @throws RemoteException thrown if a RemoteException is encountered while attempting
  716. * to communicate with a remote provider.
  717. */
  718. public ContentProviderResult[] applyBatch(String authority,
  719. ArrayList<ContentProviderOperation> operations)
  720. throws RemoteException, OperationApplicationException {
  721. ContentProviderClient provider = acquireContentProviderClient(authority);
  722. if (provider == null) {
  723. throw new IllegalArgumentException("Unknown authority " + authority);
  724. }
  725. try {
  726. return provider.applyBatch(operations);
  727. } finally {
  728. provider.release();
  729. }
  730. }
  731. /**
  732. * Inserts multiple rows into a table at the given URL.
  733. *
  734. * This function make no guarantees about the atomicity of the insertions.
  735. *
  736. * @param url The URL of the table to insert into.
  737. * @param values The initial values for the newly inserted rows. The key is the column name for
  738. * the field. Passing null will create an empty row.
  739. * @return the number of newly created rows.
  740. */
  741. public final int bulkInsert(Uri url, ContentValues[] values)
  742. {
  743. IContentProvider provider = acquireProvider(url);
  744. if (provider == null) {
  745. throw new IllegalArgumentException("Unknown URL " + url);
  746. }
  747. try {
  748. long startTime = SystemClock.uptimeMillis();
  749. int rowsCreated = provider.bulkInsert(url, values);
  750. long durationMillis = SystemClock.uptimeMillis() - startTime;
  751. maybeLogUpdateToEventLog(durationMillis, url, "bulkinsert", null /* where */);
  752. return rowsCreated;
  753. } catch (RemoteException e) {
  754. // Arbitrary and not worth documenting, as Activity
  755. // Manager will kill this process shortly anyway.
  756. return 0;
  757. } finally {
  758. releaseProvider(provider);
  759. }
  760. }
  761. /**
  762. * Deletes row(s) specified by a content URI.
  763. *
  764. * If the content provider supports transactions, the deletion will be atomic.
  765. *
  766. * @param url The URL of the row to delete.
  767. * @param where A filter to apply to rows before deleting, formatted as an SQL WHERE clause
  768. (excluding the WHERE itself).
  769. * @return The number of rows deleted.
  770. */
  771. public final int delete(Uri url, String where, String[] selectionArgs)
  772. {
  773. IContentProvider provider = acquireProvider(url);
  774. if (provider == null) {
  775. throw new IllegalArgumentException("Unknown URL " + url);
  776. }
  777. try {
  778. long startTime = SystemClock.uptimeMillis();
  779. int rowsDeleted = provider.delete(url, where, selectionArgs);
  780. long durationMillis = SystemClock.uptimeMillis() - startTime;
  781. maybeLogUpdateToEventLog(durationMillis, url, "delete", where);
  782. return rowsDeleted;
  783. } catch (RemoteException e) {
  784. // Arbitrary and not worth documenting, as Activity
  785. // Manager will kill this process shortly anyway.
  786. return -1;
  787. } finally {
  788. releaseProvider(provider);
  789. }
  790. }
  791. /**
  792. * Update row(s) in a content URI.
  793. *
  794. * If the content provider supports transactions the update will be atomic.
  795. *
  796. * @param uri The URI to modify.
  797. * @param values The new field values. The key is the column name for the field.
  798. A null value will remove an existing field value.
  799. * @param where A filter to apply to rows before updating, formatted as an SQL WHERE clause
  800. (excluding the WHERE itself).
  801. * @return the number of rows updated.
  802. * @throws NullPointerException if uri or values are null
  803. */
  804. public final int update(Uri uri, ContentValues values, String where,
  805. String[] selectionArgs) {
  806. IContentProvider provider = acquireProvider(uri);
  807. if (provider == null) {
  808. throw new IllegalArgumentException("Unknown URI " + uri);
  809. }
  810. try {
  811. long startTime = SystemClock.uptimeMillis();
  812. int rowsUpdated = provider.update(uri, values, where, selectionArgs);
  813. long durationMillis = SystemClock.uptimeMillis() - startTime;
  814. maybeLogUpdateToEventLog(durationMillis, uri, "update", where);
  815. return rowsUpdated;
  816. } catch (RemoteException e) {
  817. // Arbitrary and not worth documenting, as Activity
  818. // Manager will kill this process shortly anyway.
  819. return -1;
  820. } finally {
  821. releaseProvider(provider);
  822. }
  823. }
  824. /**
  825. * Call an provider-defined method. This can be used to implement
  826. * read or write interfaces which are cheaper than using a Cursor and/or
  827. * do not fit into the traditional table model.
  828. *
  829. * @param method provider-defined method name to call. Opaque to
  830. * framework, but must be non-null.
  831. * @param arg provider-defined String argument. May be null.
  832. * @param extras provider-defined Bundle argument. May be null.
  833. * @return a result Bundle, possibly null. Will be null if the ContentProvider
  834. * does not implement call.
  835. * @throws NullPointerException if uri or method is null
  836. * @throws IllegalArgumentException if uri is not known
  837. */
  838. public final Bundle call(Uri uri, String method, String arg, Bundle extras) {
  839. if (uri == null) {
  840. throw new NullPointerException("uri == null");
  841. }
  842. if (method == null) {
  843. throw new NullPointerException("method == null");
  844. }
  845. IContentProvider provider = acquireProvider(uri);
  846. if (provider == null) {
  847. throw new IllegalArgumentException("Unknown URI " + uri);
  848. }
  849. try {
  850. return provider.call(method, arg, extras);
  851. } catch (RemoteException e) {
  852. // Arbitrary and not worth documenting, as Activity
  853. // Manager will kill this process shortly anyway.
  854. return null;
  855. } finally {
  856. releaseProvider(provider);
  857. }
  858. }
  859. /**
  860. * Returns the content provider for the given content URI.
  861. *
  862. * @param uri The URI to a content provider
  863. * @return The ContentProvider for the given URI, or null if no content provider is found.
  864. * @hide
  865. */
  866. public final IContentProvider acquireProvider(Uri uri) {
  867. if (!SCHEME_CONTENT.equals(uri.getScheme())) {
  868. return null;
  869. }
  870. String auth = uri.getAuthority();
  871. if (auth != null) {
  872. return acquireProvider(mContext, uri.getAuthority());
  873. }
  874. return null;
  875. }
  876. /**
  877. * Returns the content provider for the given content URI if the process
  878. * already has a reference on it.
  879. *
  880. * @param uri The URI to a content provider
  881. * @return The ContentProvider for the given URI, or null if no content provider is found.
  882. * @hide
  883. */
  884. public final IContentProvider acquireExistingProvider(Uri uri) {
  885. if (!SCHEME_CONTENT.equals(uri.getScheme())) {
  886. return null;
  887. }
  888. String auth = uri.getAuthority();
  889. if (auth != null) {
  890. return acquireExistingProvider(mContext, uri.getAuthority());
  891. }
  892. return null;
  893. }
  894. /**
  895. * @hide
  896. */
  897. public final IContentProvider acquireProvider(String name) {
  898. if (name == null) {
  899. return null;
  900. }
  901. return acquireProvider(mContext, name);
  902. }
  903. /**
  904. * Returns a {@link ContentProviderClient} that is associated with the {@link ContentProvider}
  905. * that services the content at uri, starting the provider if necessary. Returns
  906. * null if there is no provider associated wih the uri. The caller must indicate that they are
  907. * done with the provider by calling {@link ContentProviderClient#release} which will allow
  908. * the system to release the provider it it determines that there is no other reason for
  909. * keeping it active.
  910. * @param uri specifies which provider should be acquired
  911. * @return a {@link ContentProviderClient} that is associated with the {@link ContentProvider}
  912. * that services the content at uri or null if there isn't one.
  913. */
  914. public final ContentProviderClient acquireContentProviderClient(Uri uri) {
  915. IContentProvider provider = acquireProvider(uri);
  916. if (provider != null) {
  917. return new ContentProviderClient(this, provider);
  918. }
  919. return null;
  920. }
  921. /**
  922. * Returns a {@link ContentProviderClient} that is associated with the {@link ContentProvider}
  923. * with the authority of name, starting the provider if necessary. Returns
  924. * null if there is no provider associated wih the uri. The caller must indicate that they are
  925. * done with the provider by calling {@link ContentProviderClient#release} which will allow
  926. * the system to release the provider it it determines that there is no other reason for
  927. * keeping it active.
  928. * @param name specifies which provider should be acquired
  929. * @return a {@link ContentProviderClient} that is associated with the {@link ContentProvider}
  930. * with the authority of name or null if there isn't one.
  931. */
  932. public final ContentProviderClient acquireContentProviderClient(String name) {
  933. IContentProvider provider = acquireProvider(name);
  934. if (provider != null) {
  935. return new ContentProviderClient(this, provider);
  936. }
  937. return null;
  938. }
  939. /**
  940. * Register an observer class that gets callbacks when data identified by a
  941. * given content URI changes.
  942. *
  943. * @param uri The URI to watch for changes. This can be a specific row URI, or a base URI
  944. * for a whole class of content.
  945. * @param notifyForDescendents If <code>true</code> changes to URIs beginning with <code>uri</code>
  946. * will also cause notifications to be sent. If <code>false</code> only changes to the exact URI
  947. * specified by <em>uri</em> will cause notifications to be sent. If true, than any URI values
  948. * at or below the specified URI will also trigger a match.
  949. * @param observer The object that receives callbacks when changes occur.
  950. * @see #unregisterContentObserver
  951. */
  952. public final void registerContentObserver(Uri uri, boolean notifyForDescendents,
  953. ContentObserver observer)
  954. {
  955. try {
  956. getContentService().registerContentObserver(uri, notifyForDescendents,
  957. observer.getContentObserver());
  958. } catch (RemoteException e) {
  959. }
  960. }
  961. /**
  962. * Unregisters a change observer.
  963. *
  964. * @param observer The previously registered observer that is no longer needed.
  965. * @see #registerContentObserver
  966. */
  967. public final void unregisterContentObserver(ContentObserver observer) {
  968. try {
  969. IContentObserver contentObserver = observer.releaseContentObserver();
  970. if (contentObserver != null) {
  971. getContentService().unregisterContentObserver(
  972. contentObserver);
  973. }
  974. } catch (RemoteException e) {
  975. }
  976. }
  977. /**
  978. * Notify registered observers that a row was updated.
  979. * To register, call {@link #registerContentObserver(android.net.Uri , boolean, android.database.ContentObserver) registerContentObserver()}.
  980. * By default, CursorAdapter objects will get this notification.
  981. *
  982. * @param uri
  983. * @param observer The observer that originated the change, may be <code>null</null>
  984. */
  985. public void notifyChange(Uri uri, ContentObserver observer) {
  986. notifyChange(uri, observer, true /* sync to network */);
  987. }
  988. /**
  989. * Notify registered observers that a row was updated.
  990. * To register, call {@link #registerContentObserver(android.net.Uri , boolean, android.database.ContentObserver) registerContentObserver()}.
  991. * By default, CursorAdapter objects will get this notification.
  992. *
  993. * @param uri
  994. * @param observer The observer that originated the change, may be <code>null</null>
  995. * @param syncToNetwork If true, attempt to sync the change to the network.
  996. */
  997. public void notifyChange(Uri uri, ContentObserver observer, boolean syncToNetwork) {
  998. try {
  999. getContentService().notifyChange(
  1000. uri, observer == null ? null : observer.getContentObserver(),
  1001. observer != null && observer.deliverSelfNotifications(), syncToNetwork);
  1002. } catch (RemoteException e) {
  1003. }
  1004. }
  1005. /**
  1006. * Start an asynchronous sync operation. If you want to monitor the progress
  1007. * of the sync you may register a SyncObserver. Only values of the following
  1008. * types may be used in the extras bundle:
  1009. * <ul>
  1010. * <li>Integer</li>
  1011. * <li>Long</li>
  1012. * <li>Boolean</li>
  1013. * <li>Float</li>
  1014. * <li>Double</li>
  1015. * <li>String</li>
  1016. * </ul>
  1017. *
  1018. * @param uri the uri of the provider to sync or null to sync all providers.
  1019. * @param extras any extras to pass to the SyncAdapter.
  1020. * @deprecated instead use
  1021. * {@link #requestSync(android.accounts.Account, String, android.os.Bundle)}
  1022. */
  1023. @Deprecated
  1024. public void startSync(Uri uri, Bundle extras) {
  1025. Account account = null;
  1026. if (extras != null) {
  1027. String accountName = extras.getString(SYNC_EXTRAS_ACCOUNT);
  1028. if (!TextUtils.isEmpty(accountName)) {
  1029. account = new Account(accountName, "com.google");
  1030. }
  1031. extras.remove(SYNC_EXTRAS_ACCOUNT);
  1032. }
  1033. requestSync(account, uri != null ? uri.getAuthority() : null, extras);
  1034. }
  1035. /**
  1036. * Start an asynchronous sync operation. If you want to monitor the progress
  1037. * of the sync you may register a SyncObserver. Only values of the following
  1038. * types may be used in the extras bundle:
  1039. * <ul>
  1040. * <li>Integer</li>
  1041. * <li>Long</li>
  1042. * <li>Boolean</li>
  1043. * <li>Float</li>
  1044. * <li>Double</li>
  1045. * <li>String</li>
  1046. * </ul>
  1047. *
  1048. * @param account which account should be synced
  1049. * @param authority which authority should be synced
  1050. * @param extras any extras to pass to the SyncAdapter.
  1051. */
  1052. public static void requestSync(Account account, String authority, Bundle extras) {
  1053. validateSyncExtrasBundle(extras);
  1054. try {
  1055. getContentService().requestSync(account, authority, extras);
  1056. } catch (RemoteException e) {
  1057. }
  1058. }
  1059. /**
  1060. * Check that only values of the following types are in the Bundle:
  1061. * <ul>
  1062. * <li>Integer</li>
  1063. * <li>Long</li>
  1064. * <li>Boolean</li>
  1065. * <li>Float</li>
  1066. * <li>Double</li>
  1067. * <li>String</li>
  1068. * <li>Account</li>
  1069. * <li>null</li>
  1070. * </ul>
  1071. * @param extras the Bundle to check
  1072. */
  1073. public static void validateSyncExtrasBundle(Bundle extras) {
  1074. try {
  1075. for (String key : extras.keySet()) {
  1076. Object value = extras.get(key);
  1077. if (value == null) continue;
  1078. if (value instanceof Long) continue;
  1079. if (value instanceof Integer) continue;
  1080. if (value instanceof Boolean) continue;
  1081. if (value instanceof Float) continue;
  1082. if (value instanceof Double) continue;
  1083. if (value instanceof String) continue;
  1084. if (value instanceof Account) continue;
  1085. throw new IllegalArgumentException("unexpected value type: "
  1086. + value.getClass().getName());
  1087. }
  1088. } catch (IllegalArgumentException e) {
  1089. throw e;
  1090. } catch (RuntimeException exc) {
  1091. throw new IllegalArgumentException("error unparceling Bundle", exc);
  1092. }
  1093. }
  1094. /**
  1095. * Cancel any active or pending syncs that match the Uri. If the uri is null then
  1096. * all syncs will be canceled.
  1097. *
  1098. * @param uri the uri of the provider to sync or null to sync all providers.
  1099. * @deprecated instead use {@link #cancelSync(android.accounts.Account, String)}
  1100. */
  1101. @Deprecated
  1102. public void cancelSync(Uri uri) {
  1103. cancelSync(null /* all accounts */, uri != null ? uri.getAuthority() : null);
  1104. }
  1105. /**
  1106. * Cancel any active or pending syncs that match account and authority. The account and
  1107. * authority can each independently be set to null, which means that syncs with any account
  1108. * or authority, respectively, will match.
  1109. *
  1110. * @param account filters the syncs that match by this account
  1111. * @param authority filters the syncs that match by this authority
  1112. */
  1113. public static void cancelSync(Account account, String authority) {
  1114. try {
  1115. getContentService().cancelSync(account, authority);
  1116. } catch (RemoteException e) {
  1117. }
  1118. }
  1119. /**
  1120. * Get information about the SyncAdapters that are known to the system.
  1121. * @return an array of SyncAdapters that have registered with the system
  1122. */
  1123. public static SyncAdapterType[] getSyncAdapterTypes() {
  1124. try {
  1125. return getContentService().getSyncAdapterTypes();
  1126. } catch (RemoteException e) {
  1127. throw new RuntimeException("the ContentService should always be reachable", e);
  1128. }
  1129. }
  1130. /**
  1131. * Check if the provider should be synced when a network tickle is received
  1132. *
  1133. * @param account the account whose setting we are querying
  1134. * @param authority the provider whose setting we are querying
  1135. * @return true if the provider should be synced when a network tickle is received
  1136. */
  1137. public static b