PageRenderTime 120ms CodeModel.GetById 38ms RepoModel.GetById 1ms app.codeStats 1ms

/android/upstream/android/content/ContentResolver.java

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