DocumentsProvider.java revision 21de56a94668e0fda1b8bb4ee4f99a09b40d28fd
1aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey/* 2aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey * Copyright (C) 2013 The Android Open Source Project 3aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey * 4aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey * Licensed under the Apache License, Version 2.0 (the "License"); 5aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey * you may not use this file except in compliance with the License. 6aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey * You may obtain a copy of the License at 7aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey * 8aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey * http://www.apache.org/licenses/LICENSE-2.0 9aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey * 10aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey * Unless required by applicable law or agreed to in writing, software 11aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey * distributed under the License is distributed on an "AS IS" BASIS, 12aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey * See the License for the specific language governing permissions and 14aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey * limitations under the License. 15aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey */ 16aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey 17aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkeypackage android.provider; 18aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey 19aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkeyimport static android.provider.DocumentsContract.EXTRA_THUMBNAIL_SIZE; 20aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkeyimport static android.provider.DocumentsContract.METHOD_CREATE_DOCUMENT; 21aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkeyimport static android.provider.DocumentsContract.METHOD_DELETE_DOCUMENT; 22ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkeyimport static android.provider.DocumentsContract.getDocumentId; 23ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkeyimport static android.provider.DocumentsContract.getRootId; 24ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkeyimport static android.provider.DocumentsContract.getSearchDocumentsQuery; 25aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey 26aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkeyimport android.content.ContentProvider; 27e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkeyimport android.content.ContentResolver; 28aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkeyimport android.content.ContentValues; 29aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkeyimport android.content.Context; 30aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkeyimport android.content.Intent; 31aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkeyimport android.content.UriMatcher; 32e37ea6123d1aa3cd3e8804988886b1f6046d79d6Jeff Sharkeyimport android.content.pm.PackageManager; 33aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkeyimport android.content.pm.ProviderInfo; 34aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkeyimport android.content.res.AssetFileDescriptor; 35aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkeyimport android.database.Cursor; 36aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkeyimport android.graphics.Point; 37aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkeyimport android.net.Uri; 38aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkeyimport android.os.Bundle; 39aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkeyimport android.os.CancellationSignal; 40aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkeyimport android.os.ParcelFileDescriptor; 41aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkeyimport android.os.ParcelFileDescriptor.OnCloseListener; 42ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkeyimport android.provider.DocumentsContract.Document; 43e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkeyimport android.provider.DocumentsContract.Root; 44aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkeyimport android.util.Log; 45aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey 46aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkeyimport libcore.io.IoUtils; 47aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey 48aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkeyimport java.io.FileNotFoundException; 4921de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkeyimport java.util.Objects; 50aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey 51aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey/** 52e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * Base class for a document provider. A document provider offers read and write 53e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * access to durable files, such as files stored on a local disk, or files in a 54e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * cloud storage service. To create a document provider, extend this class, 55e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * implement the abstract methods, and add it to your manifest like this: 56e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * 57e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * <pre class="prettyprint"><manifest> 58e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * ... 59e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * <application> 60e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * ... 61e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * <provider 62e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * android:name="com.example.MyCloudProvider" 63e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * android:authorities="com.example.mycloudprovider" 64e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * android:exported="true" 65e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * android:grantUriPermissions="true" 663b945405cf96eae8b882f87934222a453718a559Jeff Sharkey * android:permission="android.permission.MANAGE_DOCUMENTS" 673b945405cf96eae8b882f87934222a453718a559Jeff Sharkey * android:enabled="@bool/isAtLeastKitKat"> 68e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * <intent-filter> 69e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * <action android:name="android.content.action.DOCUMENTS_PROVIDER" /> 70e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * </intent-filter> 71e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * </provider> 72e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * ... 73e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * </application> 74e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey *</manifest></pre> 75aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey * <p> 76e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * When defining your provider, you must protect it with 77e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * {@link android.Manifest.permission#MANAGE_DOCUMENTS}, which is a permission 78e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * only the system can obtain. Applications cannot use a documents provider 79e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * directly; they must go through {@link Intent#ACTION_OPEN_DOCUMENT} or 80e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * {@link Intent#ACTION_CREATE_DOCUMENT} which requires a user to actively 819352c383e95c3e1facd8a7a2d49ff488fb7bbcafJeff Sharkey * navigate and select documents. When a user selects documents through that UI, 829352c383e95c3e1facd8a7a2d49ff488fb7bbcafJeff Sharkey * the system issues narrow URI permission grants to the requesting application. 83e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * </p> 84e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * <h3>Documents</h3> 85aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey * <p> 86e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * A document can be either an openable stream (with a specific MIME type), or a 87aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey * directory containing additional documents (with the 88e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * {@link Document#MIME_TYPE_DIR} MIME type). Each directory represents the top 89e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * of a subtree containing zero or more documents, which can recursively contain 90e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * even more documents and directories. 91e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * </p> 92e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * <p> 93e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * Each document can have different capabilities, as described by 94e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * {@link Document#COLUMN_FLAGS}. For example, if a document can be represented 959352c383e95c3e1facd8a7a2d49ff488fb7bbcafJeff Sharkey * as a thumbnail, your provider can set 969352c383e95c3e1facd8a7a2d49ff488fb7bbcafJeff Sharkey * {@link Document#FLAG_SUPPORTS_THUMBNAIL} and implement 97e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * {@link #openDocumentThumbnail(String, Point, CancellationSignal)} to return 98e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * that thumbnail. 99e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * </p> 100e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * <p> 101e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * Each document under a provider is uniquely referenced by its 102e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * {@link Document#COLUMN_DOCUMENT_ID}, which must not change once returned. A 103e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * single document can be included in multiple directories when responding to 104e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * {@link #queryChildDocuments(String, String[], String)}. For example, a 105e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * provider might surface a single photo in multiple locations: once in a 1069352c383e95c3e1facd8a7a2d49ff488fb7bbcafJeff Sharkey * directory of geographic locations, and again in a directory of dates. 107e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * </p> 108e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * <h3>Roots</h3> 109aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey * <p> 110e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * All documents are surfaced through one or more "roots." Each root represents 111e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * the top of a document tree that a user can navigate. For example, a root 112e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * could represent an account or a physical storage device. Similar to 113e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * documents, each root can have capabilities expressed through 114e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * {@link Root#COLUMN_FLAGS}. 115e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * </p> 116aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey * 117aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey * @see Intent#ACTION_OPEN_DOCUMENT 118aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey * @see Intent#ACTION_CREATE_DOCUMENT 119aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey */ 120aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkeypublic abstract class DocumentsProvider extends ContentProvider { 121aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey private static final String TAG = "DocumentsProvider"; 122aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey 123a61dc8e03e6e863005b3a4629ca8f3801d33d3c4Jeff Sharkey private static final int MATCH_ROOTS = 1; 124a61dc8e03e6e863005b3a4629ca8f3801d33d3c4Jeff Sharkey private static final int MATCH_ROOT = 2; 125a61dc8e03e6e863005b3a4629ca8f3801d33d3c4Jeff Sharkey private static final int MATCH_RECENT = 3; 1263e1189b3590aefb65a2af720ae2ba959bbd4188dJeff Sharkey private static final int MATCH_SEARCH = 4; 1273e1189b3590aefb65a2af720ae2ba959bbd4188dJeff Sharkey private static final int MATCH_DOCUMENT = 5; 1283e1189b3590aefb65a2af720ae2ba959bbd4188dJeff Sharkey private static final int MATCH_CHILDREN = 6; 12921de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey private static final int MATCH_DOCUMENT_VIA = 7; 13021de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey private static final int MATCH_CHILDREN_VIA = 8; 131aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey 132aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey private String mAuthority; 133aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey 134aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey private UriMatcher mMatcher; 135aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey 136ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey /** 137ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey * Implementation is provided by the parent class. 138ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey */ 139aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey @Override 140aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey public void attachInfo(Context context, ProviderInfo info) { 141aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey mAuthority = info.authority; 142aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey 143aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey mMatcher = new UriMatcher(UriMatcher.NO_MATCH); 144a61dc8e03e6e863005b3a4629ca8f3801d33d3c4Jeff Sharkey mMatcher.addURI(mAuthority, "root", MATCH_ROOTS); 145a61dc8e03e6e863005b3a4629ca8f3801d33d3c4Jeff Sharkey mMatcher.addURI(mAuthority, "root/*", MATCH_ROOT); 146ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey mMatcher.addURI(mAuthority, "root/*/recent", MATCH_RECENT); 1473e1189b3590aefb65a2af720ae2ba959bbd4188dJeff Sharkey mMatcher.addURI(mAuthority, "root/*/search", MATCH_SEARCH); 148ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey mMatcher.addURI(mAuthority, "document/*", MATCH_DOCUMENT); 149ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey mMatcher.addURI(mAuthority, "document/*/children", MATCH_CHILDREN); 15021de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey mMatcher.addURI(mAuthority, "via/*/document/*", MATCH_DOCUMENT_VIA); 15121de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey mMatcher.addURI(mAuthority, "via/*/document/*/children", MATCH_CHILDREN_VIA); 152aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey 153aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey // Sanity check our setup 154aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey if (!info.exported) { 155aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey throw new SecurityException("Provider must be exported"); 156aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey } 157aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey if (!info.grantUriPermissions) { 158aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey throw new SecurityException("Provider must grantUriPermissions"); 159aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey } 160aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey if (!android.Manifest.permission.MANAGE_DOCUMENTS.equals(info.readPermission) 161aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey || !android.Manifest.permission.MANAGE_DOCUMENTS.equals(info.writePermission)) { 162aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey throw new SecurityException("Provider must be protected by MANAGE_DOCUMENTS"); 163aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey } 164aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey 165aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey super.attachInfo(context, info); 166aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey } 167aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey 168aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey /** 16921de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey * Test if a document is descendant (child, grandchild, etc) from the given 17021de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey * parent. Providers must override this to support directory selection. You 17121de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey * should avoid making network requests to keep this request fast. 17221de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey * 17321de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey * @param parentDocumentId parent to verify against. 17421de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey * @param documentId child to verify. 17521de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey * @return if given document is a descendant of the given parent. 17621de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey * @see DocumentsContract.Root#FLAG_SUPPORTS_DIR_SELECTION 17721de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey */ 17821de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey public boolean isChildDocument(String parentDocumentId, String documentId) { 17921de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey return false; 18021de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey } 18121de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey 18221de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey /** {@hide} */ 18321de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey private void enforceVia(Uri documentUri) { 18421de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey if (DocumentsContract.isViaUri(documentUri)) { 18521de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey final String parent = DocumentsContract.getViaDocumentId(documentUri); 18621de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey final String child = DocumentsContract.getDocumentId(documentUri); 18721de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey if (Objects.equals(parent, child)) { 18821de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey return; 18921de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey } 19021de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey if (!isChildDocument(parent, child)) { 19121de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey throw new SecurityException( 19221de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey "Document " + child + " is not a descendant of " + parent); 19321de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey } 19421de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey } 19521de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey } 19621de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey 19721de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey /** 198e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * Create a new document and return its newly generated 1999352c383e95c3e1facd8a7a2d49ff488fb7bbcafJeff Sharkey * {@link Document#COLUMN_DOCUMENT_ID}. You must allocate a new 200e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * {@link Document#COLUMN_DOCUMENT_ID} to represent the document, which must 201e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * not change once returned. 202aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey * 203e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * @param parentDocumentId the parent directory to create the new document 204e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * under. 205e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * @param mimeType the concrete MIME type associated with the new document. 206e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * If the MIME type is not supported, the provider must throw. 207e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * @param displayName the display name of the new document. The provider may 208e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * alter this name to meet any internal constraints, such as 209e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * conflicting names. 210aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey */ 211aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey @SuppressWarnings("unused") 212e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey public String createDocument(String parentDocumentId, String mimeType, String displayName) 213aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey throws FileNotFoundException { 214aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey throw new UnsupportedOperationException("Create not supported"); 215aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey } 216aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey 217aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey /** 218e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * Delete the requested document. Upon returning, any URI permission grants 21921de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey * for the given document will be revoked. If additional documents were 22021de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey * deleted as a side effect of this call (such as documents inside a 22121de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey * directory) the implementor is responsible for revoking those permissions 22221de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey * using {@link #revokeDocumentPermission(String)}. 223aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey * 224ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey * @param documentId the document to delete. 225aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey */ 226aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey @SuppressWarnings("unused") 227ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey public void deleteDocument(String documentId) throws FileNotFoundException { 228ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey throw new UnsupportedOperationException("Delete not supported"); 229aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey } 230aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey 231e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey /** 2329352c383e95c3e1facd8a7a2d49ff488fb7bbcafJeff Sharkey * Return all roots currently provided. To display to users, you must define 2339352c383e95c3e1facd8a7a2d49ff488fb7bbcafJeff Sharkey * at least one root. You should avoid making network requests to keep this 2349352c383e95c3e1facd8a7a2d49ff488fb7bbcafJeff Sharkey * request fast. 235e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * <p> 236e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * Each root is defined by the metadata columns described in {@link Root}, 237e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * including {@link Root#COLUMN_DOCUMENT_ID} which points to a directory 238e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * representing a tree of documents to display under that root. 239e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * <p> 240e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * If this set of roots changes, you must call {@link ContentResolver#notifyChange(Uri, 2419352c383e95c3e1facd8a7a2d49ff488fb7bbcafJeff Sharkey * android.database.ContentObserver, boolean)} with 2429352c383e95c3e1facd8a7a2d49ff488fb7bbcafJeff Sharkey * {@link DocumentsContract#buildRootsUri(String)} to notify the system. 243e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * 244e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * @param projection list of {@link Root} columns to put into the cursor. If 245e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * {@code null} all supported columns should be included. 246e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey */ 247ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey public abstract Cursor queryRoots(String[] projection) throws FileNotFoundException; 248ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey 249e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey /** 250e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * Return recently modified documents under the requested root. This will 251e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * only be called for roots that advertise 252e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * {@link Root#FLAG_SUPPORTS_RECENTS}. The returned documents should be 253e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * sorted by {@link Document#COLUMN_LAST_MODIFIED} in descending order, and 254e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * limited to only return the 64 most recently modified documents. 25537ed78e504ef3666dd5fce15ff4994f151c44fcdJeff Sharkey * <p> 25637ed78e504ef3666dd5fce15ff4994f151c44fcdJeff Sharkey * Recent documents do not support change notifications. 257e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * 258e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * @param projection list of {@link Document} columns to put into the 259e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * cursor. If {@code null} all supported columns should be 260e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * included. 261e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * @see DocumentsContract#EXTRA_LOADING 262e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey */ 263aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey @SuppressWarnings("unused") 264ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey public Cursor queryRecentDocuments(String rootId, String[] projection) 265ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey throws FileNotFoundException { 266ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey throw new UnsupportedOperationException("Recent not supported"); 267aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey } 268aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey 269aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey /** 2709352c383e95c3e1facd8a7a2d49ff488fb7bbcafJeff Sharkey * Return metadata for the single requested document. You should avoid 2719352c383e95c3e1facd8a7a2d49ff488fb7bbcafJeff Sharkey * making network requests to keep this request fast. 272aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey * 273ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey * @param documentId the document to return. 274e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * @param projection list of {@link Document} columns to put into the 275e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * cursor. If {@code null} all supported columns should be 276e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * included. 277aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey */ 278ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey public abstract Cursor queryDocument(String documentId, String[] projection) 279ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey throws FileNotFoundException; 280aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey 281aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey /** 282e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * Return the children documents contained in the requested directory. This 283e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * must only return immediate descendants, as additional queries will be 284e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * issued to recursively explore the tree. 285e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * <p> 286e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * If your provider is cloud-based, and you have some data cached or pinned 287e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * locally, you may return the local data immediately, setting 288e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * {@link DocumentsContract#EXTRA_LOADING} on the Cursor to indicate that 2899352c383e95c3e1facd8a7a2d49ff488fb7bbcafJeff Sharkey * you are still fetching additional data. Then, when the network data is 2909352c383e95c3e1facd8a7a2d49ff488fb7bbcafJeff Sharkey * available, you can send a change notification to trigger a requery and 2913b945405cf96eae8b882f87934222a453718a559Jeff Sharkey * return the complete contents. To return a Cursor with extras, you need to 2923b945405cf96eae8b882f87934222a453718a559Jeff Sharkey * extend and override {@link Cursor#getExtras()}. 2939352c383e95c3e1facd8a7a2d49ff488fb7bbcafJeff Sharkey * <p> 2949352c383e95c3e1facd8a7a2d49ff488fb7bbcafJeff Sharkey * To support change notifications, you must 2959352c383e95c3e1facd8a7a2d49ff488fb7bbcafJeff Sharkey * {@link Cursor#setNotificationUri(ContentResolver, Uri)} with a relevant 2969352c383e95c3e1facd8a7a2d49ff488fb7bbcafJeff Sharkey * Uri, such as 2979352c383e95c3e1facd8a7a2d49ff488fb7bbcafJeff Sharkey * {@link DocumentsContract#buildChildDocumentsUri(String, String)}. Then 2989352c383e95c3e1facd8a7a2d49ff488fb7bbcafJeff Sharkey * you can call {@link ContentResolver#notifyChange(Uri, 2999352c383e95c3e1facd8a7a2d49ff488fb7bbcafJeff Sharkey * android.database.ContentObserver, boolean)} with that Uri to send change 3009352c383e95c3e1facd8a7a2d49ff488fb7bbcafJeff Sharkey * notifications. 301aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey * 302ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey * @param parentDocumentId the directory to return children for. 303e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * @param projection list of {@link Document} columns to put into the 304e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * cursor. If {@code null} all supported columns should be 305e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * included. 306e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * @param sortOrder how to order the rows, formatted as an SQL 307e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * {@code ORDER BY} clause (excluding the ORDER BY itself). 308e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * Passing {@code null} will use the default sort order, which 309e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * may be unordered. This ordering is a hint that can be used to 310e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * prioritize how data is fetched from the network, but UI may 311e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * always enforce a specific ordering. 312e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * @see DocumentsContract#EXTRA_LOADING 313e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * @see DocumentsContract#EXTRA_INFO 314e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * @see DocumentsContract#EXTRA_ERROR 315aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey */ 316ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey public abstract Cursor queryChildDocuments( 317ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey String parentDocumentId, String[] projection, String sortOrder) 318ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey throws FileNotFoundException; 319aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey 3204ec973925fc2cd18f9ec0d0ca5af588564fded27Jeff Sharkey /** {@hide} */ 3214ec973925fc2cd18f9ec0d0ca5af588564fded27Jeff Sharkey @SuppressWarnings("unused") 3224ec973925fc2cd18f9ec0d0ca5af588564fded27Jeff Sharkey public Cursor queryChildDocumentsForManage( 3234ec973925fc2cd18f9ec0d0ca5af588564fded27Jeff Sharkey String parentDocumentId, String[] projection, String sortOrder) 3244ec973925fc2cd18f9ec0d0ca5af588564fded27Jeff Sharkey throws FileNotFoundException { 3254ec973925fc2cd18f9ec0d0ca5af588564fded27Jeff Sharkey throw new UnsupportedOperationException("Manage not supported"); 3264ec973925fc2cd18f9ec0d0ca5af588564fded27Jeff Sharkey } 3274ec973925fc2cd18f9ec0d0ca5af588564fded27Jeff Sharkey 328aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey /** 329e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * Return documents that that match the given query under the requested 330e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * root. The returned documents should be sorted by relevance in descending 331e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * order. How documents are matched against the query string is an 332e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * implementation detail left to each provider, but it's suggested that at 333e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * least {@link Document#COLUMN_DISPLAY_NAME} be matched in a 334e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * case-insensitive fashion. 335e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * <p> 336e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * Only documents may be returned; directories are not supported in search 337e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * results. 3389352c383e95c3e1facd8a7a2d49ff488fb7bbcafJeff Sharkey * <p> 3399352c383e95c3e1facd8a7a2d49ff488fb7bbcafJeff Sharkey * If your provider is cloud-based, and you have some data cached or pinned 3409352c383e95c3e1facd8a7a2d49ff488fb7bbcafJeff Sharkey * locally, you may return the local data immediately, setting 3419352c383e95c3e1facd8a7a2d49ff488fb7bbcafJeff Sharkey * {@link DocumentsContract#EXTRA_LOADING} on the Cursor to indicate that 3429352c383e95c3e1facd8a7a2d49ff488fb7bbcafJeff Sharkey * you are still fetching additional data. Then, when the network data is 3439352c383e95c3e1facd8a7a2d49ff488fb7bbcafJeff Sharkey * available, you can send a change notification to trigger a requery and 3449352c383e95c3e1facd8a7a2d49ff488fb7bbcafJeff Sharkey * return the complete contents. 3459352c383e95c3e1facd8a7a2d49ff488fb7bbcafJeff Sharkey * <p> 3469352c383e95c3e1facd8a7a2d49ff488fb7bbcafJeff Sharkey * To support change notifications, you must 3479352c383e95c3e1facd8a7a2d49ff488fb7bbcafJeff Sharkey * {@link Cursor#setNotificationUri(ContentResolver, Uri)} with a relevant 3489352c383e95c3e1facd8a7a2d49ff488fb7bbcafJeff Sharkey * Uri, such as {@link DocumentsContract#buildSearchDocumentsUri(String, 3499352c383e95c3e1facd8a7a2d49ff488fb7bbcafJeff Sharkey * String, String)}. Then you can call {@link ContentResolver#notifyChange(Uri, 3509352c383e95c3e1facd8a7a2d49ff488fb7bbcafJeff Sharkey * android.database.ContentObserver, boolean)} with that Uri to send change 3519352c383e95c3e1facd8a7a2d49ff488fb7bbcafJeff Sharkey * notifications. 352aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey * 3533e1189b3590aefb65a2af720ae2ba959bbd4188dJeff Sharkey * @param rootId the root to search under. 354e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * @param query string to match documents against. 355e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * @param projection list of {@link Document} columns to put into the 356e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * cursor. If {@code null} all supported columns should be 357e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * included. 358e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * @see DocumentsContract#EXTRA_LOADING 359e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * @see DocumentsContract#EXTRA_INFO 360e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * @see DocumentsContract#EXTRA_ERROR 361aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey */ 362aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey @SuppressWarnings("unused") 3633e1189b3590aefb65a2af720ae2ba959bbd4188dJeff Sharkey public Cursor querySearchDocuments(String rootId, String query, String[] projection) 364ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey throws FileNotFoundException { 365aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey throw new UnsupportedOperationException("Search not supported"); 366aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey } 367aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey 368aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey /** 369e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * Return concrete MIME type of the requested document. Must match the value 370e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * of {@link Document#COLUMN_MIME_TYPE} for this document. The default 371e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * implementation queries {@link #queryDocument(String, String[])}, so 372e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * providers may choose to override this as an optimization. 373aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey */ 374ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey public String getDocumentType(String documentId) throws FileNotFoundException { 375ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey final Cursor cursor = queryDocument(documentId, null); 376aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey try { 377aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey if (cursor.moveToFirst()) { 378ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey return cursor.getString(cursor.getColumnIndexOrThrow(Document.COLUMN_MIME_TYPE)); 379aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey } else { 380aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey return null; 381aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey } 382aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey } finally { 383aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey IoUtils.closeQuietly(cursor); 384aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey } 385aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey } 386aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey 387aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey /** 388e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * Open and return the requested document. 389e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * <p> 3909352c383e95c3e1facd8a7a2d49ff488fb7bbcafJeff Sharkey * Your provider should return a reliable {@link ParcelFileDescriptor} to 391e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * detect when the remote caller has finished reading or writing the 3929352c383e95c3e1facd8a7a2d49ff488fb7bbcafJeff Sharkey * document. You may return a pipe or socket pair if the mode is exclusively 3939352c383e95c3e1facd8a7a2d49ff488fb7bbcafJeff Sharkey * "r" or "w", but complex modes like "rw" imply a normal file on disk that 3949352c383e95c3e1facd8a7a2d49ff488fb7bbcafJeff Sharkey * supports seeking. 395e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * <p> 3969352c383e95c3e1facd8a7a2d49ff488fb7bbcafJeff Sharkey * If you block while downloading content, you should periodically check 3979352c383e95c3e1facd8a7a2d49ff488fb7bbcafJeff Sharkey * {@link CancellationSignal#isCanceled()} to abort abandoned open requests. 398aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey * 399e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * @param documentId the document to return. 400aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey * @param mode the mode to open with, such as 'r', 'w', or 'rw'. 401aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey * @param signal used by the caller to signal if the request should be 4023b945405cf96eae8b882f87934222a453718a559Jeff Sharkey * cancelled. May be null. 403aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey * @see ParcelFileDescriptor#open(java.io.File, int, android.os.Handler, 404aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey * OnCloseListener) 405aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey * @see ParcelFileDescriptor#createReliablePipe() 406aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey * @see ParcelFileDescriptor#createReliableSocketPair() 407e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * @see ParcelFileDescriptor#parseMode(String) 408aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey */ 409aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey public abstract ParcelFileDescriptor openDocument( 410e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey String documentId, String mode, CancellationSignal signal) throws FileNotFoundException; 411aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey 412aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey /** 413e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * Open and return a thumbnail of the requested document. 414e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * <p> 415e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * A provider should return a thumbnail closely matching the hinted size, 416e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * attempting to serve from a local cache if possible. A provider should 417e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * never return images more than double the hinted size. 418e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * <p> 4199352c383e95c3e1facd8a7a2d49ff488fb7bbcafJeff Sharkey * If you perform expensive operations to download or generate a thumbnail, 4209352c383e95c3e1facd8a7a2d49ff488fb7bbcafJeff Sharkey * you should periodically check {@link CancellationSignal#isCanceled()} to 4219352c383e95c3e1facd8a7a2d49ff488fb7bbcafJeff Sharkey * abort abandoned thumbnail requests. 422aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey * 423e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * @param documentId the document to return. 424aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey * @param sizeHint hint of the optimal thumbnail dimensions. 425aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey * @param signal used by the caller to signal if the request should be 4263b945405cf96eae8b882f87934222a453718a559Jeff Sharkey * cancelled. May be null. 427ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey * @see Document#FLAG_SUPPORTS_THUMBNAIL 428aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey */ 429aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey @SuppressWarnings("unused") 430aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey public AssetFileDescriptor openDocumentThumbnail( 431e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey String documentId, Point sizeHint, CancellationSignal signal) 432e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey throws FileNotFoundException { 433aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey throw new UnsupportedOperationException("Thumbnails not supported"); 434aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey } 435aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey 436ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey /** 437ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey * Implementation is provided by the parent class. Cannot be overriden. 438ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey * 439ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey * @see #queryRoots(String[]) 440ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey * @see #queryRecentDocuments(String, String[]) 441ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey * @see #queryDocument(String, String[]) 442ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey * @see #queryChildDocuments(String, String[], String) 443ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey * @see #querySearchDocuments(String, String, String[]) 444ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey */ 445aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey @Override 446ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey public final Cursor query(Uri uri, String[] projection, String selection, 447ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey String[] selectionArgs, String sortOrder) { 448aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey try { 449aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey switch (mMatcher.match(uri)) { 450a61dc8e03e6e863005b3a4629ca8f3801d33d3c4Jeff Sharkey case MATCH_ROOTS: 451ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey return queryRoots(projection); 452ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey case MATCH_RECENT: 453ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey return queryRecentDocuments(getRootId(uri), projection); 4543e1189b3590aefb65a2af720ae2ba959bbd4188dJeff Sharkey case MATCH_SEARCH: 4553e1189b3590aefb65a2af720ae2ba959bbd4188dJeff Sharkey return querySearchDocuments( 4563e1189b3590aefb65a2af720ae2ba959bbd4188dJeff Sharkey getRootId(uri), getSearchDocumentsQuery(uri), projection); 457aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey case MATCH_DOCUMENT: 45821de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey case MATCH_DOCUMENT_VIA: 45921de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey enforceVia(uri); 460ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey return queryDocument(getDocumentId(uri), projection); 461aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey case MATCH_CHILDREN: 46221de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey case MATCH_CHILDREN_VIA: 46321de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey enforceVia(uri); 4644ec973925fc2cd18f9ec0d0ca5af588564fded27Jeff Sharkey if (DocumentsContract.isManageMode(uri)) { 4654ec973925fc2cd18f9ec0d0ca5af588564fded27Jeff Sharkey return queryChildDocumentsForManage( 4664ec973925fc2cd18f9ec0d0ca5af588564fded27Jeff Sharkey getDocumentId(uri), projection, sortOrder); 4674ec973925fc2cd18f9ec0d0ca5af588564fded27Jeff Sharkey } else { 4684ec973925fc2cd18f9ec0d0ca5af588564fded27Jeff Sharkey return queryChildDocuments(getDocumentId(uri), projection, sortOrder); 4694ec973925fc2cd18f9ec0d0ca5af588564fded27Jeff Sharkey } 470aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey default: 471aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey throw new UnsupportedOperationException("Unsupported Uri " + uri); 472aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey } 473aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey } catch (FileNotFoundException e) { 474aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey Log.w(TAG, "Failed during query", e); 475aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey return null; 476aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey } 477aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey } 478aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey 479ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey /** 480ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey * Implementation is provided by the parent class. Cannot be overriden. 481ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey * 482ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey * @see #getDocumentType(String) 483ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey */ 484aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey @Override 485aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey public final String getType(Uri uri) { 486aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey try { 487aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey switch (mMatcher.match(uri)) { 488a61dc8e03e6e863005b3a4629ca8f3801d33d3c4Jeff Sharkey case MATCH_ROOT: 489a61dc8e03e6e863005b3a4629ca8f3801d33d3c4Jeff Sharkey return DocumentsContract.Root.MIME_TYPE_ITEM; 490aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey case MATCH_DOCUMENT: 49121de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey case MATCH_DOCUMENT_VIA: 49221de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey enforceVia(uri); 493ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey return getDocumentType(getDocumentId(uri)); 494aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey default: 495aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey return null; 496aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey } 497aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey } catch (FileNotFoundException e) { 498aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey Log.w(TAG, "Failed during getType", e); 499aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey return null; 500aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey } 501aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey } 502aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey 503ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey /** 50421de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey * Implementation is provided by the parent class. Can be overridden to 50521de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey * provide additional functionality, but subclasses <em>must</em> always 50621de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey * call the superclass. If the superclass returns {@code null}, the subclass 50721de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey * may implement custom behavior. 50821de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey * <p> 50921de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey * This is typically used to resolve a "via" URI into a concrete document 51021de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey * reference, issuing a narrower single-document URI permission grant along 51121de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey * the way. 51221de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey * 51321de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey * @see DocumentsContract#buildDocumentViaUri(Uri, String) 51421de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey */ 51521de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey @Override 51621de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey public Uri canonicalize(Uri uri) { 51721de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey final Context context = getContext(); 51821de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey switch (mMatcher.match(uri)) { 51921de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey case MATCH_DOCUMENT_VIA: 52021de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey enforceVia(uri); 52121de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey 52221de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey final Uri narrowUri = DocumentsContract.buildDocumentUri(uri.getAuthority(), 52321de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey DocumentsContract.getDocumentId(uri)); 52421de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey 52521de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey // Caller may only have prefix grant, so extend them a grant to 52621de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey // the narrow Uri. Caller already holds read grant to get here, 52721de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey // so check for any other modes we should extend. 52821de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey int modeFlags = Intent.FLAG_GRANT_READ_URI_PERMISSION; 52921de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey if (context.checkCallingOrSelfUriPermission(uri, 53021de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey Intent.FLAG_GRANT_WRITE_URI_PERMISSION) 53121de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey == PackageManager.PERMISSION_GRANTED) { 53221de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey modeFlags |= Intent.FLAG_GRANT_WRITE_URI_PERMISSION; 53321de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey } 53421de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey if (context.checkCallingOrSelfUriPermission(uri, 53521de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey Intent.FLAG_GRANT_READ_URI_PERMISSION 53621de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION) 53721de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey == PackageManager.PERMISSION_GRANTED) { 53821de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey modeFlags |= Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION; 53921de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey } 54021de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey context.grantUriPermission(getCallingPackage(), narrowUri, modeFlags); 54121de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey return narrowUri; 54221de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey } 54321de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey return null; 54421de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey } 54521de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey 54621de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey /** 547ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey * Implementation is provided by the parent class. Throws by default, and 548ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey * cannot be overriden. 549ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey * 550ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey * @see #createDocument(String, String, String) 551ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey */ 552aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey @Override 553aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey public final Uri insert(Uri uri, ContentValues values) { 554aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey throw new UnsupportedOperationException("Insert not supported"); 555aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey } 556aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey 557ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey /** 558ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey * Implementation is provided by the parent class. Throws by default, and 559ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey * cannot be overriden. 560ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey * 561ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey * @see #deleteDocument(String) 562ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey */ 563aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey @Override 564aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey public final int delete(Uri uri, String selection, String[] selectionArgs) { 565aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey throw new UnsupportedOperationException("Delete not supported"); 566aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey } 567aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey 568ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey /** 569ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey * Implementation is provided by the parent class. Throws by default, and 570ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey * cannot be overriden. 571ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey */ 572aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey @Override 573aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey public final int update( 574aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey Uri uri, ContentValues values, String selection, String[] selectionArgs) { 575aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey throw new UnsupportedOperationException("Update not supported"); 576aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey } 577aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey 578911d7f411f36f2279aae44c89ff1d33a29140046Jeff Sharkey /** 579911d7f411f36f2279aae44c89ff1d33a29140046Jeff Sharkey * Implementation is provided by the parent class. Can be overridden to 580911d7f411f36f2279aae44c89ff1d33a29140046Jeff Sharkey * provide additional functionality, but subclasses <em>must</em> always 581911d7f411f36f2279aae44c89ff1d33a29140046Jeff Sharkey * call the superclass. If the superclass returns {@code null}, the subclass 582911d7f411f36f2279aae44c89ff1d33a29140046Jeff Sharkey * may implement custom behavior. 583911d7f411f36f2279aae44c89ff1d33a29140046Jeff Sharkey */ 584aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey @Override 585911d7f411f36f2279aae44c89ff1d33a29140046Jeff Sharkey public Bundle call(String method, String arg, Bundle extras) { 586aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey if (!method.startsWith("android:")) { 58721de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey // Ignore non-platform methods 588911d7f411f36f2279aae44c89ff1d33a29140046Jeff Sharkey return super.call(method, arg, extras); 589aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey } 590aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey 59121de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey final Uri documentUri = extras.getParcelable(DocumentsContract.EXTRA_URI); 59221de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey final String authority = documentUri.getAuthority(); 59321de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey final String documentId = DocumentsContract.getDocumentId(documentUri); 594e37ea6123d1aa3cd3e8804988886b1f6046d79d6Jeff Sharkey 59521de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey if (!mAuthority.equals(authority)) { 59621de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey throw new SecurityException( 59721de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey "Requested authority " + authority + " doesn't match provider " + mAuthority); 59821de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey } 59921de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey enforceVia(documentUri); 600aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey 601aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey final Bundle out = new Bundle(); 602aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey try { 603ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey if (METHOD_CREATE_DOCUMENT.equals(method)) { 60421de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey enforceWritePermissionInner(documentUri); 60521de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey 606ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey final String mimeType = extras.getString(Document.COLUMN_MIME_TYPE); 607ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey final String displayName = extras.getString(Document.COLUMN_DISPLAY_NAME); 608aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey 609ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey final String newDocumentId = createDocument(documentId, mimeType, displayName); 61021de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey 61121de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey // No need to issue new grants here, since caller either has 61221de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey // manage permission or a prefix grant. We might generate a 61321de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey // "via" style URI if that's how they called us. 61421de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey final Uri newDocumentUri = DocumentsContract.buildDocumentMaybeViaUri(documentUri, 61521de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey newDocumentId); 61621de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey out.putParcelable(DocumentsContract.EXTRA_URI, newDocumentUri); 617e37ea6123d1aa3cd3e8804988886b1f6046d79d6Jeff Sharkey 618aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey } else if (METHOD_DELETE_DOCUMENT.equals(method)) { 61921de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey enforceWritePermissionInner(documentUri); 620e37ea6123d1aa3cd3e8804988886b1f6046d79d6Jeff Sharkey deleteDocument(documentId); 621e37ea6123d1aa3cd3e8804988886b1f6046d79d6Jeff Sharkey 622e37ea6123d1aa3cd3e8804988886b1f6046d79d6Jeff Sharkey // Document no longer exists, clean up any grants 62321de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey revokeDocumentPermission(documentId); 624aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey 625aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey } else { 626aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey throw new UnsupportedOperationException("Method not supported " + method); 627aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey } 628aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey } catch (FileNotFoundException e) { 629aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey throw new IllegalStateException("Failed call " + method, e); 630aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey } 631aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey return out; 632aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey } 633aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey 634ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey /** 63521de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey * Revoke any active permission grants for the given 63621de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey * {@link Document#COLUMN_DOCUMENT_ID}, usually called when a document 63721de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey * becomes invalid. Follows the same semantics as 63821de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey * {@link Context#revokeUriPermission(Uri, int)}. 63921de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey */ 64021de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey public final void revokeDocumentPermission(String documentId) { 64121de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey final Context context = getContext(); 64221de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey context.revokeUriPermission(DocumentsContract.buildDocumentUri(mAuthority, documentId), ~0); 64321de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey context.revokeUriPermission(DocumentsContract.buildViaUri(mAuthority, documentId), ~0); 64421de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey } 64521de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey 64621de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey /** 647e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * Implementation is provided by the parent class. Cannot be overriden. 648ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey * 649ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey * @see #openDocument(String, String, CancellationSignal) 650ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey */ 651aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey @Override 652aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey public final ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException { 65321de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey enforceVia(uri); 654ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey return openDocument(getDocumentId(uri), mode, null); 655aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey } 656aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey 657ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey /** 658e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * Implementation is provided by the parent class. Cannot be overriden. 659ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey * 660ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey * @see #openDocument(String, String, CancellationSignal) 661ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey */ 662aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey @Override 663aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey public final ParcelFileDescriptor openFile(Uri uri, String mode, CancellationSignal signal) 664aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey throws FileNotFoundException { 66521de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey enforceVia(uri); 666ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey return openDocument(getDocumentId(uri), mode, signal); 667aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey } 668aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey 669ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey /** 670e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * Implementation is provided by the parent class. Cannot be overriden. 671ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey * 67221de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey * @see #openDocument(String, String, CancellationSignal) 67321de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey */ 67421de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey @Override 67521de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey @SuppressWarnings("resource") 67621de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey public final AssetFileDescriptor openAssetFile(Uri uri, String mode) 67721de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey throws FileNotFoundException { 67821de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey enforceVia(uri); 67921de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey final ParcelFileDescriptor fd = openDocument(getDocumentId(uri), mode, null); 68021de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey return fd != null ? new AssetFileDescriptor(fd, 0, -1) : null; 68121de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey } 68221de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey 68321de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey /** 68421de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey * Implementation is provided by the parent class. Cannot be overriden. 68521de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey * 68621de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey * @see #openDocument(String, String, CancellationSignal) 68721de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey */ 68821de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey @Override 68921de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey @SuppressWarnings("resource") 69021de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey public final AssetFileDescriptor openAssetFile(Uri uri, String mode, CancellationSignal signal) 69121de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey throws FileNotFoundException { 69221de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey enforceVia(uri); 69321de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey final ParcelFileDescriptor fd = openDocument(getDocumentId(uri), mode, signal); 69421de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey return fd != null ? new AssetFileDescriptor(fd, 0, -1) : null; 69521de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey } 69621de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey 69721de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey /** 69821de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey * Implementation is provided by the parent class. Cannot be overriden. 69921de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey * 700ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey * @see #openDocumentThumbnail(String, Point, CancellationSignal) 701ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey */ 702aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey @Override 703aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey public final AssetFileDescriptor openTypedAssetFile(Uri uri, String mimeTypeFilter, Bundle opts) 704aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey throws FileNotFoundException { 70521de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey enforceVia(uri); 706aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey if (opts != null && opts.containsKey(EXTRA_THUMBNAIL_SIZE)) { 707aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey final Point sizeHint = opts.getParcelable(EXTRA_THUMBNAIL_SIZE); 708ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey return openDocumentThumbnail(getDocumentId(uri), sizeHint, null); 709aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey } else { 710aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey return super.openTypedAssetFile(uri, mimeTypeFilter, opts); 711aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey } 712aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey } 713aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey 714ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey /** 715e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * Implementation is provided by the parent class. Cannot be overriden. 716ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey * 717ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey * @see #openDocumentThumbnail(String, Point, CancellationSignal) 718ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey */ 719aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey @Override 720aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey public final AssetFileDescriptor openTypedAssetFile( 721aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey Uri uri, String mimeTypeFilter, Bundle opts, CancellationSignal signal) 722aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey throws FileNotFoundException { 72321de56a94668e0fda1b8bb4ee4f99a09b40d28fdJeff Sharkey enforceVia(uri); 724aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey if (opts != null && opts.containsKey(EXTRA_THUMBNAIL_SIZE)) { 725aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey final Point sizeHint = opts.getParcelable(EXTRA_THUMBNAIL_SIZE); 726ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey return openDocumentThumbnail(getDocumentId(uri), sizeHint, signal); 727aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey } else { 728aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey return super.openTypedAssetFile(uri, mimeTypeFilter, opts, signal); 729aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey } 730aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey } 731aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey} 732