PageRenderTime 102ms CodeModel.GetById 6ms RepoModel.GetById 0ms app.codeStats 0ms

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

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