PageRenderTime 27ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/core/java/android/content/ContentProvider.java

https://github.com/PapaDocta/android_frameworks_base
Java | 834 lines | 309 code | 63 blank | 462 comment | 63 complexity | 37e70b49739803562c7c927c717c7368 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 android.content.pm.PackageManager;
  18. import android.content.pm.PathPermission;
  19. import android.content.pm.ProviderInfo;
  20. import android.content.res.AssetFileDescriptor;
  21. import android.content.res.Configuration;
  22. import android.database.Cursor;
  23. import android.database.CursorToBulkCursorAdaptor;
  24. import android.database.CursorWindow;
  25. import android.database.IBulkCursor;
  26. import android.database.IContentObserver;
  27. import android.database.SQLException;
  28. import android.net.Uri;
  29. import android.os.Binder;
  30. import android.os.Bundle;
  31. import android.os.ParcelFileDescriptor;
  32. import android.os.Process;
  33. import java.io.File;
  34. import java.io.FileNotFoundException;
  35. import java.util.ArrayList;
  36. /**
  37. * Content providers are one of the primary building blocks of Android applications, providing
  38. * content to applications. They encapsulate data and provide it to applications through the single
  39. * {@link ContentResolver} interface. A content provider is only required if you need to share
  40. * data between multiple applications. For example, the contacts data is used by multiple
  41. * applications and must be stored in a content provider. If you don't need to share data amongst
  42. * multiple applications you can use a database directly via
  43. * {@link android.database.sqlite.SQLiteDatabase}.
  44. *
  45. * <p>For more information, read <a href="{@docRoot}guide/topics/providers/content-providers.html">Content
  46. * Providers</a>.</p>
  47. *
  48. * <p>When a request is made via
  49. * a {@link ContentResolver} the system inspects the authority of the given URI and passes the
  50. * request to the content provider registered with the authority. The content provider can interpret
  51. * the rest of the URI however it wants. The {@link UriMatcher} class is helpful for parsing
  52. * URIs.</p>
  53. *
  54. * <p>The primary methods that need to be implemented are:
  55. * <ul>
  56. * <li>{@link #onCreate} which is called to initialize the provider</li>
  57. * <li>{@link #query} which returns data to the caller</li>
  58. * <li>{@link #insert} which inserts new data into the content provider</li>
  59. * <li>{@link #update} which updates existing data in the content provider</li>
  60. * <li>{@link #delete} which deletes data from the content provider</li>
  61. * <li>{@link #getType} which returns the MIME type of data in the content provider</li>
  62. * </ul></p>
  63. *
  64. * <p class="caution">Data access methods (such as {@link #insert} and
  65. * {@link #update}) may be called from many threads at once, and must be thread-safe.
  66. * Other methods (such as {@link #onCreate}) are only called from the application
  67. * main thread, and must avoid performing lengthy operations. See the method
  68. * descriptions for their expected thread behavior.</p>
  69. *
  70. * <p>Requests to {@link ContentResolver} are automatically forwarded to the appropriate
  71. * ContentProvider instance, so subclasses don't have to worry about the details of
  72. * cross-process calls.</p>
  73. */
  74. public abstract class ContentProvider implements ComponentCallbacks {
  75. /*
  76. * Note: if you add methods to ContentProvider, you must add similar methods to
  77. * MockContentProvider.
  78. */
  79. private Context mContext = null;
  80. private int mMyUid;
  81. private String mReadPermission;
  82. private String mWritePermission;
  83. private PathPermission[] mPathPermissions;
  84. private Transport mTransport = new Transport();
  85. /**
  86. * Construct a ContentProvider instance. Content providers must be
  87. * <a href="{@docRoot}guide/topics/manifest/provider-element.html">declared
  88. * in the manifest</a>, accessed with {@link ContentResolver}, and created
  89. * automatically by the system, so applications usually do not create
  90. * ContentProvider instances directly.
  91. *
  92. * <p>At construction time, the object is uninitialized, and most fields and
  93. * methods are unavailable. Subclasses should initialize themselves in
  94. * {@link #onCreate}, not the constructor.
  95. *
  96. * <p>Content providers are created on the application main thread at
  97. * application launch time. The constructor must not perform lengthy
  98. * operations, or application startup will be delayed.
  99. */
  100. public ContentProvider() {
  101. }
  102. /**
  103. * Constructor just for mocking.
  104. *
  105. * @param context A Context object which should be some mock instance (like the
  106. * instance of {@link android.test.mock.MockContext}).
  107. * @param readPermission The read permision you want this instance should have in the
  108. * test, which is available via {@link #getReadPermission()}.
  109. * @param writePermission The write permission you want this instance should have
  110. * in the test, which is available via {@link #getWritePermission()}.
  111. * @param pathPermissions The PathPermissions you want this instance should have
  112. * in the test, which is available via {@link #getPathPermissions()}.
  113. * @hide
  114. */
  115. public ContentProvider(
  116. Context context,
  117. String readPermission,
  118. String writePermission,
  119. PathPermission[] pathPermissions) {
  120. mContext = context;
  121. mReadPermission = readPermission;
  122. mWritePermission = writePermission;
  123. mPathPermissions = pathPermissions;
  124. }
  125. /**
  126. * Given an IContentProvider, try to coerce it back to the real
  127. * ContentProvider object if it is running in the local process. This can
  128. * be used if you know you are running in the same process as a provider,
  129. * and want to get direct access to its implementation details. Most
  130. * clients should not nor have a reason to use it.
  131. *
  132. * @param abstractInterface The ContentProvider interface that is to be
  133. * coerced.
  134. * @return If the IContentProvider is non-null and local, returns its actual
  135. * ContentProvider instance. Otherwise returns null.
  136. * @hide
  137. */
  138. public static ContentProvider coerceToLocalContentProvider(
  139. IContentProvider abstractInterface) {
  140. if (abstractInterface instanceof Transport) {
  141. return ((Transport)abstractInterface).getContentProvider();
  142. }
  143. return null;
  144. }
  145. /**
  146. * Binder object that deals with remoting.
  147. *
  148. * @hide
  149. */
  150. class Transport extends ContentProviderNative {
  151. ContentProvider getContentProvider() {
  152. return ContentProvider.this;
  153. }
  154. /**
  155. * Remote version of a query, which returns an IBulkCursor. The bulk
  156. * cursor should be wrapped with BulkCursorToCursorAdaptor before use.
  157. */
  158. public IBulkCursor bulkQuery(Uri uri, String[] projection,
  159. String selection, String[] selectionArgs, String sortOrder,
  160. IContentObserver observer, CursorWindow window) {
  161. enforceReadPermission(uri);
  162. Cursor cursor = ContentProvider.this.query(uri, projection,
  163. selection, selectionArgs, sortOrder);
  164. if (cursor == null) {
  165. return null;
  166. }
  167. return new CursorToBulkCursorAdaptor(cursor, observer,
  168. ContentProvider.this.getClass().getName(),
  169. hasWritePermission(uri), window);
  170. }
  171. public Cursor query(Uri uri, String[] projection,
  172. String selection, String[] selectionArgs, String sortOrder) {
  173. enforceReadPermission(uri);
  174. return ContentProvider.this.query(uri, projection, selection,
  175. selectionArgs, sortOrder);
  176. }
  177. public String getType(Uri uri) {
  178. return ContentProvider.this.getType(uri);
  179. }
  180. public Uri insert(Uri uri, ContentValues initialValues) {
  181. enforceWritePermission(uri);
  182. return ContentProvider.this.insert(uri, initialValues);
  183. }
  184. public int bulkInsert(Uri uri, ContentValues[] initialValues) {
  185. enforceWritePermission(uri);
  186. return ContentProvider.this.bulkInsert(uri, initialValues);
  187. }
  188. public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations)
  189. throws OperationApplicationException {
  190. for (ContentProviderOperation operation : operations) {
  191. if (operation.isReadOperation()) {
  192. enforceReadPermission(operation.getUri());
  193. }
  194. if (operation.isWriteOperation()) {
  195. enforceWritePermission(operation.getUri());
  196. }
  197. }
  198. return ContentProvider.this.applyBatch(operations);
  199. }
  200. public int delete(Uri uri, String selection, String[] selectionArgs) {
  201. enforceWritePermission(uri);
  202. return ContentProvider.this.delete(uri, selection, selectionArgs);
  203. }
  204. public int update(Uri uri, ContentValues values, String selection,
  205. String[] selectionArgs) {
  206. enforceWritePermission(uri);
  207. return ContentProvider.this.update(uri, values, selection, selectionArgs);
  208. }
  209. public ParcelFileDescriptor openFile(Uri uri, String mode)
  210. throws FileNotFoundException {
  211. if (mode != null && mode.startsWith("rw")) enforceWritePermission(uri);
  212. else enforceReadPermission(uri);
  213. return ContentProvider.this.openFile(uri, mode);
  214. }
  215. public AssetFileDescriptor openAssetFile(Uri uri, String mode)
  216. throws FileNotFoundException {
  217. if (mode != null && mode.startsWith("rw")) enforceWritePermission(uri);
  218. else enforceReadPermission(uri);
  219. return ContentProvider.this.openAssetFile(uri, mode);
  220. }
  221. /**
  222. * @hide
  223. */
  224. public Bundle call(String method, String request, Bundle args) {
  225. return ContentProvider.this.call(method, request, args);
  226. }
  227. private void enforceReadPermission(Uri uri) {
  228. final int uid = Binder.getCallingUid();
  229. if (uid == mMyUid) {
  230. return;
  231. }
  232. final Context context = getContext();
  233. final String rperm = getReadPermission();
  234. final int pid = Binder.getCallingPid();
  235. if (rperm == null
  236. || context.checkPermission(rperm, pid, uid)
  237. == PackageManager.PERMISSION_GRANTED) {
  238. return;
  239. }
  240. PathPermission[] pps = getPathPermissions();
  241. if (pps != null) {
  242. final String path = uri.getPath();
  243. int i = pps.length;
  244. while (i > 0) {
  245. i--;
  246. final PathPermission pp = pps[i];
  247. final String pprperm = pp.getReadPermission();
  248. if (pprperm != null && pp.match(path)) {
  249. if (context.checkPermission(pprperm, pid, uid)
  250. == PackageManager.PERMISSION_GRANTED) {
  251. return;
  252. }
  253. }
  254. }
  255. }
  256. if (context.checkUriPermission(uri, pid, uid,
  257. Intent.FLAG_GRANT_READ_URI_PERMISSION)
  258. == PackageManager.PERMISSION_GRANTED) {
  259. return;
  260. }
  261. String msg = "Permission Denial: reading "
  262. + ContentProvider.this.getClass().getName()
  263. + " uri " + uri + " from pid=" + Binder.getCallingPid()
  264. + ", uid=" + Binder.getCallingUid()
  265. + " requires " + rperm;
  266. throw new SecurityException(msg);
  267. }
  268. private boolean hasWritePermission(Uri uri) {
  269. final int uid = Binder.getCallingUid();
  270. if (uid == mMyUid) {
  271. return true;
  272. }
  273. final Context context = getContext();
  274. final String wperm = getWritePermission();
  275. final int pid = Binder.getCallingPid();
  276. if (wperm == null
  277. || context.checkPermission(wperm, pid, uid)
  278. == PackageManager.PERMISSION_GRANTED) {
  279. return true;
  280. }
  281. PathPermission[] pps = getPathPermissions();
  282. if (pps != null) {
  283. final String path = uri.getPath();
  284. int i = pps.length;
  285. while (i > 0) {
  286. i--;
  287. final PathPermission pp = pps[i];
  288. final String ppwperm = pp.getWritePermission();
  289. if (ppwperm != null && pp.match(path)) {
  290. if (context.checkPermission(ppwperm, pid, uid)
  291. == PackageManager.PERMISSION_GRANTED) {
  292. return true;
  293. }
  294. }
  295. }
  296. }
  297. if (context.checkUriPermission(uri, pid, uid,
  298. Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
  299. == PackageManager.PERMISSION_GRANTED) {
  300. return true;
  301. }
  302. return false;
  303. }
  304. private void enforceWritePermission(Uri uri) {
  305. if (hasWritePermission(uri)) {
  306. return;
  307. }
  308. String msg = "Permission Denial: writing "
  309. + ContentProvider.this.getClass().getName()
  310. + " uri " + uri + " from pid=" + Binder.getCallingPid()
  311. + ", uid=" + Binder.getCallingUid()
  312. + " requires " + getWritePermission();
  313. throw new SecurityException(msg);
  314. }
  315. }
  316. /**
  317. * Retrieves the Context this provider is running in. Only available once
  318. * {@link #onCreate} has been called -- this will return null in the
  319. * constructor.
  320. */
  321. public final Context getContext() {
  322. return mContext;
  323. }
  324. /**
  325. * Change the permission required to read data from the content
  326. * provider. This is normally set for you from its manifest information
  327. * when the provider is first created.
  328. *
  329. * @param permission Name of the permission required for read-only access.
  330. */
  331. protected final void setReadPermission(String permission) {
  332. mReadPermission = permission;
  333. }
  334. /**
  335. * Return the name of the permission required for read-only access to
  336. * this content provider. This method can be called from multiple
  337. * threads, as described in
  338. * <a href="{@docRoot}guide/topics/fundamentals.html#procthread">Application Fundamentals:
  339. * Processes and Threads</a>.
  340. */
  341. public final String getReadPermission() {
  342. return mReadPermission;
  343. }
  344. /**
  345. * Change the permission required to read and write data in the content
  346. * provider. This is normally set for you from its manifest information
  347. * when the provider is first created.
  348. *
  349. * @param permission Name of the permission required for read/write access.
  350. */
  351. protected final void setWritePermission(String permission) {
  352. mWritePermission = permission;
  353. }
  354. /**
  355. * Return the name of the permission required for read/write access to
  356. * this content provider. This method can be called from multiple
  357. * threads, as described in
  358. * <a href="{@docRoot}guide/topics/fundamentals.html#procthread">Application Fundamentals:
  359. * Processes and Threads</a>.
  360. */
  361. public final String getWritePermission() {
  362. return mWritePermission;
  363. }
  364. /**
  365. * Change the path-based permission required to read and/or write data in
  366. * the content provider. This is normally set for you from its manifest
  367. * information when the provider is first created.
  368. *
  369. * @param permissions Array of path permission descriptions.
  370. */
  371. protected final void setPathPermissions(PathPermission[] permissions) {
  372. mPathPermissions = permissions;
  373. }
  374. /**
  375. * Return the path-based permissions required for read and/or write access to
  376. * this content provider. This method can be called from multiple
  377. * threads, as described in
  378. * <a href="{@docRoot}guide/topics/fundamentals.html#procthread">Application Fundamentals:
  379. * Processes and Threads</a>.
  380. */
  381. public final PathPermission[] getPathPermissions() {
  382. return mPathPermissions;
  383. }
  384. /**
  385. * Implement this to initialize your content provider on startup.
  386. * This method is called for all registered content providers on the
  387. * application main thread at application launch time. It must not perform
  388. * lengthy operations, or application startup will be delayed.
  389. *
  390. * <p>You should defer nontrivial initialization (such as opening,
  391. * upgrading, and scanning databases) until the content provider is used
  392. * (via {@link #query}, {@link #insert}, etc). Deferred initialization
  393. * keeps application startup fast, avoids unnecessary work if the provider
  394. * turns out not to be needed, and stops database errors (such as a full
  395. * disk) from halting application launch.
  396. *
  397. * <p>If you use SQLite, {@link android.database.sqlite.SQLiteOpenHelper}
  398. * is a helpful utility class that makes it easy to manage databases,
  399. * and will automatically defer opening until first use. If you do use
  400. * SQLiteOpenHelper, make sure to avoid calling
  401. * {@link android.database.sqlite.SQLiteOpenHelper#getReadableDatabase} or
  402. * {@link android.database.sqlite.SQLiteOpenHelper#getWritableDatabase}
  403. * from this method. (Instead, override
  404. * {@link android.database.sqlite.SQLiteOpenHelper#onOpen} to initialize the
  405. * database when it is first opened.)
  406. *
  407. * @return true if the provider was successfully loaded, false otherwise
  408. */
  409. public abstract boolean onCreate();
  410. /**
  411. * {@inheritDoc}
  412. * This method is always called on the application main thread, and must
  413. * not perform lengthy operations.
  414. *
  415. * <p>The default content provider implementation does nothing.
  416. * Override this method to take appropriate action.
  417. * (Content providers do not usually care about things like screen
  418. * orientation, but may want to know about locale changes.)
  419. */
  420. public void onConfigurationChanged(Configuration newConfig) {
  421. }
  422. /**
  423. * {@inheritDoc}
  424. * This method is always called on the application main thread, and must
  425. * not perform lengthy operations.
  426. *
  427. * <p>The default content provider implementation does nothing.
  428. * Subclasses may override this method to take appropriate action.
  429. */
  430. public void onLowMemory() {
  431. }
  432. /**
  433. * Implement this to handle query requests from clients.
  434. * This method can be called from multiple threads, as described in
  435. * <a href="{@docRoot}guide/topics/fundamentals.html#procthread">Application Fundamentals:
  436. * Processes and Threads</a>.
  437. * <p>
  438. * Example client call:<p>
  439. * <pre>// Request a specific record.
  440. * Cursor managedCursor = managedQuery(
  441. ContentUris.withAppendedId(Contacts.People.CONTENT_URI, 2),
  442. projection, // Which columns to return.
  443. null, // WHERE clause.
  444. null, // WHERE clause value substitution
  445. People.NAME + " ASC"); // Sort order.</pre>
  446. * Example implementation:<p>
  447. * <pre>// SQLiteQueryBuilder is a helper class that creates the
  448. // proper SQL syntax for us.
  449. SQLiteQueryBuilder qBuilder = new SQLiteQueryBuilder();
  450. // Set the table we're querying.
  451. qBuilder.setTables(DATABASE_TABLE_NAME);
  452. // If the query ends in a specific record number, we're
  453. // being asked for a specific record, so set the
  454. // WHERE clause in our query.
  455. if((URI_MATCHER.match(uri)) == SPECIFIC_MESSAGE){
  456. qBuilder.appendWhere("_id=" + uri.getPathLeafId());
  457. }
  458. // Make the query.
  459. Cursor c = qBuilder.query(mDb,
  460. projection,
  461. selection,
  462. selectionArgs,
  463. groupBy,
  464. having,
  465. sortOrder);
  466. c.setNotificationUri(getContext().getContentResolver(), uri);
  467. return c;</pre>
  468. *
  469. * @param uri The URI to query. This will be the full URI sent by the client;
  470. * if the client is requesting a specific record, the URI will end in a record number
  471. * that the implementation should parse and add to a WHERE or HAVING clause, specifying
  472. * that _id value.
  473. * @param projection The list of columns to put into the cursor. If
  474. * null all columns are included.
  475. * @param selection A selection criteria to apply when filtering rows.
  476. * If null then all rows are included.
  477. * @param selectionArgs You may include ?s in selection, which will be replaced by
  478. * the values from selectionArgs, in order that they appear in the selection.
  479. * The values will be bound as Strings.
  480. * @param sortOrder How the rows in the cursor should be sorted.
  481. * If null then the provider is free to define the sort order.
  482. * @return a Cursor or null.
  483. */
  484. public abstract Cursor query(Uri uri, String[] projection,
  485. String selection, String[] selectionArgs, String sortOrder);
  486. /**
  487. * Implement this to handle requests for the MIME type of the data at the
  488. * given URI. The returned MIME type should start with
  489. * <code>vnd.android.cursor.item</code> for a single record,
  490. * or <code>vnd.android.cursor.dir/</code> for multiple items.
  491. * This method can be called from multiple threads, as described in
  492. * <a href="{@docRoot}guide/topics/fundamentals.html#procthread">Application Fundamentals:
  493. * Processes and Threads</a>.
  494. *
  495. * @param uri the URI to query.
  496. * @return a MIME type string, or null if there is no type.
  497. */
  498. public abstract String getType(Uri uri);
  499. /**
  500. * Implement this to handle requests to insert a new row.
  501. * As a courtesy, call {@link ContentResolver#notifyChange(android.net.Uri ,android.database.ContentObserver) notifyChange()}
  502. * after inserting.
  503. * This method can be called from multiple threads, as described in
  504. * <a href="{@docRoot}guide/topics/fundamentals.html#procthread">Application Fundamentals:
  505. * Processes and Threads</a>.
  506. * @param uri The content:// URI of the insertion request.
  507. * @param values A set of column_name/value pairs to add to the database.
  508. * @return The URI for the newly inserted item.
  509. */
  510. public abstract Uri insert(Uri uri, ContentValues values);
  511. /**
  512. * Override this to handle requests to insert a set of new rows, or the
  513. * default implementation will iterate over the values and call
  514. * {@link #insert} on each of them.
  515. * As a courtesy, call {@link ContentResolver#notifyChange(android.net.Uri ,android.database.ContentObserver) notifyChange()}
  516. * after inserting.
  517. * This method can be called from multiple threads, as described in
  518. * <a href="{@docRoot}guide/topics/fundamentals.html#procthread">Application Fundamentals:
  519. * Processes and Threads</a>.
  520. *
  521. * @param uri The content:// URI of the insertion request.
  522. * @param values An array of sets of column_name/value pairs to add to the database.
  523. * @return The number of values that were inserted.
  524. */
  525. public int bulkInsert(Uri uri, ContentValues[] values) {
  526. int numValues = values.length;
  527. for (int i = 0; i < numValues; i++) {
  528. insert(uri, values[i]);
  529. }
  530. return numValues;
  531. }
  532. /**
  533. * Implement this to handle requests to delete one or more rows.
  534. * The implementation should apply the selection clause when performing
  535. * deletion, allowing the operation to affect multiple rows in a directory.
  536. * As a courtesy, call {@link ContentResolver#notifyChange(android.net.Uri ,android.database.ContentObserver) notifyDelete()}
  537. * after deleting.
  538. * This method can be called from multiple threads, as described in
  539. * <a href="{@docRoot}guide/topics/fundamentals.html#procthread">Application Fundamentals:
  540. * Processes and Threads</a>.
  541. *
  542. * <p>The implementation is responsible for parsing out a row ID at the end
  543. * of the URI, if a specific row is being deleted. That is, the client would
  544. * pass in <code>content://contacts/people/22</code> and the implementation is
  545. * responsible for parsing the record number (22) when creating a SQL statement.
  546. *
  547. * @param uri The full URI to query, including a row ID (if a specific record is requested).
  548. * @param selection An optional restriction to apply to rows when deleting.
  549. * @return The number of rows affected.
  550. * @throws SQLException
  551. */
  552. public abstract int delete(Uri uri, String selection, String[] selectionArgs);
  553. /**
  554. * Implement this to handle requests to update one or more rows.
  555. * The implementation should update all rows matching the selection
  556. * to set the columns according to the provided values map.
  557. * As a courtesy, call {@link ContentResolver#notifyChange(android.net.Uri ,android.database.ContentObserver) notifyChange()}
  558. * after updating.
  559. * This method can be called from multiple threads, as described in
  560. * <a href="{@docRoot}guide/topics/fundamentals.html#procthread">Application Fundamentals:
  561. * Processes and Threads</a>.
  562. *
  563. * @param uri The URI to query. This can potentially have a record ID if this
  564. * is an update request for a specific record.
  565. * @param values A Bundle mapping from column names to new column values (NULL is a
  566. * valid value).
  567. * @param selection An optional filter to match rows to update.
  568. * @return the number of rows affected.
  569. */
  570. public abstract int update(Uri uri, ContentValues values, String selection,
  571. String[] selectionArgs);
  572. /**
  573. * Override this to handle requests to open a file blob.
  574. * The default implementation always throws {@link FileNotFoundException}.
  575. * This method can be called from multiple threads, as described in
  576. * <a href="{@docRoot}guide/topics/fundamentals.html#procthread">Application Fundamentals:
  577. * Processes and Threads</a>.
  578. *
  579. * <p>This method returns a ParcelFileDescriptor, which is returned directly
  580. * to the caller. This way large data (such as images and documents) can be
  581. * returned without copying the content.
  582. *
  583. * <p>The returned ParcelFileDescriptor is owned by the caller, so it is
  584. * their responsibility to close it when done. That is, the implementation
  585. * of this method should create a new ParcelFileDescriptor for each call.
  586. *
  587. * @param uri The URI whose file is to be opened.
  588. * @param mode Access mode for the file. May be "r" for read-only access,
  589. * "rw" for read and write access, or "rwt" for read and write access
  590. * that truncates any existing file.
  591. *
  592. * @return Returns a new ParcelFileDescriptor which you can use to access
  593. * the file.
  594. *
  595. * @throws FileNotFoundException Throws FileNotFoundException if there is
  596. * no file associated with the given URI or the mode is invalid.
  597. * @throws SecurityException Throws SecurityException if the caller does
  598. * not have permission to access the file.
  599. *
  600. * @see #openAssetFile(Uri, String)
  601. * @see #openFileHelper(Uri, String)
  602. */
  603. public ParcelFileDescriptor openFile(Uri uri, String mode)
  604. throws FileNotFoundException {
  605. throw new FileNotFoundException("No files supported by provider at "
  606. + uri);
  607. }
  608. /**
  609. * This is like {@link #openFile}, but can be implemented by providers
  610. * that need to be able to return sub-sections of files, often assets
  611. * inside of their .apk.
  612. * This method can be called from multiple threads, as described in
  613. * <a href="{@docRoot}guide/topics/fundamentals.html#procthread">Application Fundamentals:
  614. * Processes and Threads</a>.
  615. *
  616. * <p>If you implement this, your clients must be able to deal with such
  617. * file slices, either directly with
  618. * {@link ContentResolver#openAssetFileDescriptor}, or by using the higher-level
  619. * {@link ContentResolver#openInputStream ContentResolver.openInputStream}
  620. * or {@link ContentResolver#openOutputStream ContentResolver.openOutputStream}
  621. * methods.
  622. *
  623. * <p class="note">If you are implementing this to return a full file, you
  624. * should create the AssetFileDescriptor with
  625. * {@link AssetFileDescriptor#UNKNOWN_LENGTH} to be compatible with
  626. * applications that can not handle sub-sections of files.</p>
  627. *
  628. * @param uri The URI whose file is to be opened.
  629. * @param mode Access mode for the file. May be "r" for read-only access,
  630. * "w" for write-only access (erasing whatever data is currently in
  631. * the file), "wa" for write-only access to append to any existing data,
  632. * "rw" for read and write access on any existing data, and "rwt" for read
  633. * and write access that truncates any existing file.
  634. *
  635. * @return Returns a new AssetFileDescriptor which you can use to access
  636. * the file.
  637. *
  638. * @throws FileNotFoundException Throws FileNotFoundException if there is
  639. * no file associated with the given URI or the mode is invalid.
  640. * @throws SecurityException Throws SecurityException if the caller does
  641. * not have permission to access the file.
  642. *
  643. * @see #openFile(Uri, String)
  644. * @see #openFileHelper(Uri, String)
  645. */
  646. public AssetFileDescriptor openAssetFile(Uri uri, String mode)
  647. throws FileNotFoundException {
  648. ParcelFileDescriptor fd = openFile(uri, mode);
  649. return fd != null ? new AssetFileDescriptor(fd, 0, -1) : null;
  650. }
  651. /**
  652. * Convenience for subclasses that wish to implement {@link #openFile}
  653. * by looking up a column named "_data" at the given URI.
  654. *
  655. * @param uri The URI to be opened.
  656. * @param mode The file mode. May be "r" for read-only access,
  657. * "w" for write-only access (erasing whatever data is currently in
  658. * the file), "wa" for write-only access to append to any existing data,
  659. * "rw" for read and write access on any existing data, and "rwt" for read
  660. * and write access that truncates any existing file.
  661. *
  662. * @return Returns a new ParcelFileDescriptor that can be used by the
  663. * client to access the file.
  664. */
  665. protected final ParcelFileDescriptor openFileHelper(Uri uri,
  666. String mode) throws FileNotFoundException {
  667. Cursor c = query(uri, new String[]{"_data"}, null, null, null);
  668. int count = (c != null) ? c.getCount() : 0;
  669. if (count != 1) {
  670. // If there is not exactly one result, throw an appropriate
  671. // exception.
  672. if (c != null) {
  673. c.close();
  674. }
  675. if (count == 0) {
  676. throw new FileNotFoundException("No entry for " + uri);
  677. }
  678. throw new FileNotFoundException("Multiple items at " + uri);
  679. }
  680. c.moveToFirst();
  681. int i = c.getColumnIndex("_data");
  682. String path = (i >= 0 ? c.getString(i) : null);
  683. c.close();
  684. if (path == null) {
  685. throw new FileNotFoundException("Column _data not found.");
  686. }
  687. int modeBits = ContentResolver.modeToMode(uri, mode);
  688. return ParcelFileDescriptor.open(new File(path), modeBits);
  689. }
  690. /**
  691. * Returns true if this instance is a temporary content provider.
  692. * @return true if this instance is a temporary content provider
  693. */
  694. protected boolean isTemporary() {
  695. return false;
  696. }
  697. /**
  698. * Returns the Binder object for this provider.
  699. *
  700. * @return the Binder object for this provider
  701. * @hide
  702. */
  703. public IContentProvider getIContentProvider() {
  704. return mTransport;
  705. }
  706. /**
  707. * After being instantiated, this is called to tell the content provider
  708. * about itself.
  709. *
  710. * @param context The context this provider is running in
  711. * @param info Registered information about this content provider
  712. */
  713. public void attachInfo(Context context, ProviderInfo info) {
  714. /*
  715. * Only allow it to be set once, so after the content service gives
  716. * this to us clients can't change it.
  717. */
  718. if (mContext == null) {
  719. mContext = context;
  720. mMyUid = Process.myUid();
  721. if (info != null) {
  722. setReadPermission(info.readPermission);
  723. setWritePermission(info.writePermission);
  724. setPathPermissions(info.pathPermissions);
  725. }
  726. ContentProvider.this.onCreate();
  727. }
  728. }
  729. /**
  730. * Override this to handle requests to perform a batch of operations, or the
  731. * default implementation will iterate over the operations and call
  732. * {@link ContentProviderOperation#apply} on each of them.
  733. * If all calls to {@link ContentProviderOperation#apply} succeed
  734. * then a {@link ContentProviderResult} array with as many
  735. * elements as there were operations will be returned. If any of the calls
  736. * fail, it is up to the implementation how many of the others take effect.
  737. * This method can be called from multiple threads, as described in
  738. * <a href="{@docRoot}guide/topics/fundamentals.html#procthread">Application Fundamentals:
  739. * Processes and Threads</a>.
  740. *
  741. * @param operations the operations to apply
  742. * @return the results of the applications
  743. * @throws OperationApplicationException thrown if any operation fails.
  744. * @see ContentProviderOperation#apply
  745. */
  746. public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations)
  747. throws OperationApplicationException {
  748. final int numOperations = operations.size();
  749. final ContentProviderResult[] results = new ContentProviderResult[numOperations];
  750. for (int i = 0; i < numOperations; i++) {
  751. results[i] = operations.get(i).apply(this, results, i);
  752. }
  753. return results;
  754. }
  755. /**
  756. * @hide -- until interface has proven itself
  757. *
  758. * Call an provider-defined method. This can be used to implement
  759. * interfaces that are cheaper than using a Cursor.
  760. *
  761. * @param method Method name to call. Opaque to framework.
  762. * @param request Nullable String argument passed to method.
  763. * @param args Nullable Bundle argument passed to method.
  764. */
  765. public Bundle call(String method, String request, Bundle args) {
  766. return null;
  767. }
  768. }