DocumentsProvider.java revision 3b945405cf96eae8b882f87934222a453718a559
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; 49aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey 50aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey/** 51e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * Base class for a document provider. A document provider offers read and write 52e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * access to durable files, such as files stored on a local disk, or files in a 53e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * cloud storage service. To create a document provider, extend this class, 54e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * implement the abstract methods, and add it to your manifest like this: 55e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * 56e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * <pre class="prettyprint"><manifest> 57e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * ... 58e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * <application> 59e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * ... 60e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * <provider 61e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * android:name="com.example.MyCloudProvider" 62e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * android:authorities="com.example.mycloudprovider" 63e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * android:exported="true" 64e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * android:grantUriPermissions="true" 653b945405cf96eae8b882f87934222a453718a559Jeff Sharkey * android:permission="android.permission.MANAGE_DOCUMENTS" 663b945405cf96eae8b882f87934222a453718a559Jeff Sharkey * android:enabled="@bool/isAtLeastKitKat"> 67e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * <intent-filter> 68e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * <action android:name="android.content.action.DOCUMENTS_PROVIDER" /> 69e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * </intent-filter> 70e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * </provider> 71e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * ... 72e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * </application> 73e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey *</manifest></pre> 74aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey * <p> 75e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * When defining your provider, you must protect it with 76e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * {@link android.Manifest.permission#MANAGE_DOCUMENTS}, which is a permission 77e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * only the system can obtain. Applications cannot use a documents provider 78e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * directly; they must go through {@link Intent#ACTION_OPEN_DOCUMENT} or 79e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * {@link Intent#ACTION_CREATE_DOCUMENT} which requires a user to actively 809352c383e95c3e1facd8a7a2d49ff488fb7bbcafJeff Sharkey * navigate and select documents. When a user selects documents through that UI, 819352c383e95c3e1facd8a7a2d49ff488fb7bbcafJeff Sharkey * the system issues narrow URI permission grants to the requesting application. 82e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * </p> 83e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * <h3>Documents</h3> 84aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey * <p> 85e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * A document can be either an openable stream (with a specific MIME type), or a 86aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey * directory containing additional documents (with the 87e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * {@link Document#MIME_TYPE_DIR} MIME type). Each directory represents the top 88e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * of a subtree containing zero or more documents, which can recursively contain 89e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * even more documents and directories. 90e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * </p> 91e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * <p> 92e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * Each document can have different capabilities, as described by 93e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * {@link Document#COLUMN_FLAGS}. For example, if a document can be represented 949352c383e95c3e1facd8a7a2d49ff488fb7bbcafJeff Sharkey * as a thumbnail, your provider can set 959352c383e95c3e1facd8a7a2d49ff488fb7bbcafJeff Sharkey * {@link Document#FLAG_SUPPORTS_THUMBNAIL} and implement 96e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * {@link #openDocumentThumbnail(String, Point, CancellationSignal)} to return 97e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * that thumbnail. 98e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * </p> 99e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * <p> 100e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * Each document under a provider is uniquely referenced by its 101e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * {@link Document#COLUMN_DOCUMENT_ID}, which must not change once returned. A 102e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * single document can be included in multiple directories when responding to 103e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * {@link #queryChildDocuments(String, String[], String)}. For example, a 104e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * provider might surface a single photo in multiple locations: once in a 1059352c383e95c3e1facd8a7a2d49ff488fb7bbcafJeff Sharkey * directory of geographic locations, and again in a directory of dates. 106e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * </p> 107e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * <h3>Roots</h3> 108aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey * <p> 109e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * All documents are surfaced through one or more "roots." Each root represents 110e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * the top of a document tree that a user can navigate. For example, a root 111e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * could represent an account or a physical storage device. Similar to 112e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * documents, each root can have capabilities expressed through 113e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * {@link Root#COLUMN_FLAGS}. 114e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * </p> 115aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey * 116aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey * @see Intent#ACTION_OPEN_DOCUMENT 117aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey * @see Intent#ACTION_CREATE_DOCUMENT 118aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey */ 119aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkeypublic abstract class DocumentsProvider extends ContentProvider { 120aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey private static final String TAG = "DocumentsProvider"; 121aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey 122a61dc8e03e6e863005b3a4629ca8f3801d33d3c4Jeff Sharkey private static final int MATCH_ROOTS = 1; 123a61dc8e03e6e863005b3a4629ca8f3801d33d3c4Jeff Sharkey private static final int MATCH_ROOT = 2; 124a61dc8e03e6e863005b3a4629ca8f3801d33d3c4Jeff Sharkey private static final int MATCH_RECENT = 3; 1253e1189b3590aefb65a2af720ae2ba959bbd4188dJeff Sharkey private static final int MATCH_SEARCH = 4; 1263e1189b3590aefb65a2af720ae2ba959bbd4188dJeff Sharkey private static final int MATCH_DOCUMENT = 5; 1273e1189b3590aefb65a2af720ae2ba959bbd4188dJeff Sharkey private static final int MATCH_CHILDREN = 6; 128aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey 129aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey private String mAuthority; 130aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey 131aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey private UriMatcher mMatcher; 132aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey 133ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey /** 134ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey * Implementation is provided by the parent class. 135ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey */ 136aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey @Override 137aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey public void attachInfo(Context context, ProviderInfo info) { 138aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey mAuthority = info.authority; 139aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey 140aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey mMatcher = new UriMatcher(UriMatcher.NO_MATCH); 141a61dc8e03e6e863005b3a4629ca8f3801d33d3c4Jeff Sharkey mMatcher.addURI(mAuthority, "root", MATCH_ROOTS); 142a61dc8e03e6e863005b3a4629ca8f3801d33d3c4Jeff Sharkey mMatcher.addURI(mAuthority, "root/*", MATCH_ROOT); 143ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey mMatcher.addURI(mAuthority, "root/*/recent", MATCH_RECENT); 1443e1189b3590aefb65a2af720ae2ba959bbd4188dJeff Sharkey mMatcher.addURI(mAuthority, "root/*/search", MATCH_SEARCH); 145ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey mMatcher.addURI(mAuthority, "document/*", MATCH_DOCUMENT); 146ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey mMatcher.addURI(mAuthority, "document/*/children", MATCH_CHILDREN); 147aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey 148aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey // Sanity check our setup 149aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey if (!info.exported) { 150aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey throw new SecurityException("Provider must be exported"); 151aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey } 152aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey if (!info.grantUriPermissions) { 153aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey throw new SecurityException("Provider must grantUriPermissions"); 154aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey } 155aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey if (!android.Manifest.permission.MANAGE_DOCUMENTS.equals(info.readPermission) 156aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey || !android.Manifest.permission.MANAGE_DOCUMENTS.equals(info.writePermission)) { 157aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey throw new SecurityException("Provider must be protected by MANAGE_DOCUMENTS"); 158aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey } 159aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey 160aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey super.attachInfo(context, info); 161aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey } 162aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey 163aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey /** 164e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * Create a new document and return its newly generated 1659352c383e95c3e1facd8a7a2d49ff488fb7bbcafJeff Sharkey * {@link Document#COLUMN_DOCUMENT_ID}. You must allocate a new 166e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * {@link Document#COLUMN_DOCUMENT_ID} to represent the document, which must 167e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * not change once returned. 168aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey * 169e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * @param parentDocumentId the parent directory to create the new document 170e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * under. 171e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * @param mimeType the concrete MIME type associated with the new document. 172e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * If the MIME type is not supported, the provider must throw. 173e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * @param displayName the display name of the new document. The provider may 174e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * alter this name to meet any internal constraints, such as 175e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * conflicting names. 176aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey */ 177aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey @SuppressWarnings("unused") 178e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey public String createDocument(String parentDocumentId, String mimeType, String displayName) 179aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey throws FileNotFoundException { 180aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey throw new UnsupportedOperationException("Create not supported"); 181aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey } 182aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey 183aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey /** 184e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * Delete the requested document. Upon returning, any URI permission grants 185e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * for the requested document will be revoked. If additional documents were 186e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * deleted as a side effect of this call, such as documents inside a 187e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * directory, the implementor is responsible for revoking those permissions. 188aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey * 189ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey * @param documentId the document to delete. 190aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey */ 191aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey @SuppressWarnings("unused") 192ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey public void deleteDocument(String documentId) throws FileNotFoundException { 193ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey throw new UnsupportedOperationException("Delete not supported"); 194aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey } 195aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey 196e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey /** 1979352c383e95c3e1facd8a7a2d49ff488fb7bbcafJeff Sharkey * Return all roots currently provided. To display to users, you must define 1989352c383e95c3e1facd8a7a2d49ff488fb7bbcafJeff Sharkey * at least one root. You should avoid making network requests to keep this 1999352c383e95c3e1facd8a7a2d49ff488fb7bbcafJeff Sharkey * request fast. 200e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * <p> 201e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * Each root is defined by the metadata columns described in {@link Root}, 202e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * including {@link Root#COLUMN_DOCUMENT_ID} which points to a directory 203e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * representing a tree of documents to display under that root. 204e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * <p> 205e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * If this set of roots changes, you must call {@link ContentResolver#notifyChange(Uri, 2069352c383e95c3e1facd8a7a2d49ff488fb7bbcafJeff Sharkey * android.database.ContentObserver, boolean)} with 2079352c383e95c3e1facd8a7a2d49ff488fb7bbcafJeff Sharkey * {@link DocumentsContract#buildRootsUri(String)} to notify the system. 208e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * 209e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * @param projection list of {@link Root} columns to put into the cursor. If 210e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * {@code null} all supported columns should be included. 211e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey */ 212ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey public abstract Cursor queryRoots(String[] projection) throws FileNotFoundException; 213ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey 214e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey /** 215e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * Return recently modified documents under the requested root. This will 216e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * only be called for roots that advertise 217e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * {@link Root#FLAG_SUPPORTS_RECENTS}. The returned documents should be 218e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * sorted by {@link Document#COLUMN_LAST_MODIFIED} in descending order, and 219e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * limited to only return the 64 most recently modified documents. 22037ed78e504ef3666dd5fce15ff4994f151c44fcdJeff Sharkey * <p> 22137ed78e504ef3666dd5fce15ff4994f151c44fcdJeff Sharkey * Recent documents do not support change notifications. 222e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * 223e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * @param projection list of {@link Document} columns to put into the 224e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * cursor. If {@code null} all supported columns should be 225e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * included. 226e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * @see DocumentsContract#EXTRA_LOADING 227e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey */ 228aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey @SuppressWarnings("unused") 229ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey public Cursor queryRecentDocuments(String rootId, String[] projection) 230ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey throws FileNotFoundException { 231ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey throw new UnsupportedOperationException("Recent not supported"); 232aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey } 233aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey 234aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey /** 2359352c383e95c3e1facd8a7a2d49ff488fb7bbcafJeff Sharkey * Return metadata for the single requested document. You should avoid 2369352c383e95c3e1facd8a7a2d49ff488fb7bbcafJeff Sharkey * making network requests to keep this request fast. 237aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey * 238ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey * @param documentId the document to return. 239e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * @param projection list of {@link Document} columns to put into the 240e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * cursor. If {@code null} all supported columns should be 241e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * included. 242aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey */ 243ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey public abstract Cursor queryDocument(String documentId, String[] projection) 244ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey throws FileNotFoundException; 245aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey 246aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey /** 247e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * Return the children documents contained in the requested directory. This 248e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * must only return immediate descendants, as additional queries will be 249e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * issued to recursively explore the tree. 250e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * <p> 251e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * If your provider is cloud-based, and you have some data cached or pinned 252e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * locally, you may return the local data immediately, setting 253e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * {@link DocumentsContract#EXTRA_LOADING} on the Cursor to indicate that 2549352c383e95c3e1facd8a7a2d49ff488fb7bbcafJeff Sharkey * you are still fetching additional data. Then, when the network data is 2559352c383e95c3e1facd8a7a2d49ff488fb7bbcafJeff Sharkey * available, you can send a change notification to trigger a requery and 2563b945405cf96eae8b882f87934222a453718a559Jeff Sharkey * return the complete contents. To return a Cursor with extras, you need to 2573b945405cf96eae8b882f87934222a453718a559Jeff Sharkey * extend and override {@link Cursor#getExtras()}. 2589352c383e95c3e1facd8a7a2d49ff488fb7bbcafJeff Sharkey * <p> 2599352c383e95c3e1facd8a7a2d49ff488fb7bbcafJeff Sharkey * To support change notifications, you must 2609352c383e95c3e1facd8a7a2d49ff488fb7bbcafJeff Sharkey * {@link Cursor#setNotificationUri(ContentResolver, Uri)} with a relevant 2619352c383e95c3e1facd8a7a2d49ff488fb7bbcafJeff Sharkey * Uri, such as 2629352c383e95c3e1facd8a7a2d49ff488fb7bbcafJeff Sharkey * {@link DocumentsContract#buildChildDocumentsUri(String, String)}. Then 2639352c383e95c3e1facd8a7a2d49ff488fb7bbcafJeff Sharkey * you can call {@link ContentResolver#notifyChange(Uri, 2649352c383e95c3e1facd8a7a2d49ff488fb7bbcafJeff Sharkey * android.database.ContentObserver, boolean)} with that Uri to send change 2659352c383e95c3e1facd8a7a2d49ff488fb7bbcafJeff Sharkey * notifications. 266aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey * 267ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey * @param parentDocumentId the directory to return children for. 268e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * @param projection list of {@link Document} columns to put into the 269e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * cursor. If {@code null} all supported columns should be 270e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * included. 271e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * @param sortOrder how to order the rows, formatted as an SQL 272e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * {@code ORDER BY} clause (excluding the ORDER BY itself). 273e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * Passing {@code null} will use the default sort order, which 274e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * may be unordered. This ordering is a hint that can be used to 275e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * prioritize how data is fetched from the network, but UI may 276e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * always enforce a specific ordering. 277e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * @see DocumentsContract#EXTRA_LOADING 278e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * @see DocumentsContract#EXTRA_INFO 279e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * @see DocumentsContract#EXTRA_ERROR 280aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey */ 281ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey public abstract Cursor queryChildDocuments( 282ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey String parentDocumentId, String[] projection, String sortOrder) 283ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey throws FileNotFoundException; 284aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey 2854ec973925fc2cd18f9ec0d0ca5af588564fded27Jeff Sharkey /** {@hide} */ 2864ec973925fc2cd18f9ec0d0ca5af588564fded27Jeff Sharkey @SuppressWarnings("unused") 2874ec973925fc2cd18f9ec0d0ca5af588564fded27Jeff Sharkey public Cursor queryChildDocumentsForManage( 2884ec973925fc2cd18f9ec0d0ca5af588564fded27Jeff Sharkey String parentDocumentId, String[] projection, String sortOrder) 2894ec973925fc2cd18f9ec0d0ca5af588564fded27Jeff Sharkey throws FileNotFoundException { 2904ec973925fc2cd18f9ec0d0ca5af588564fded27Jeff Sharkey throw new UnsupportedOperationException("Manage not supported"); 2914ec973925fc2cd18f9ec0d0ca5af588564fded27Jeff Sharkey } 2924ec973925fc2cd18f9ec0d0ca5af588564fded27Jeff Sharkey 293aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey /** 294e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * Return documents that that match the given query under the requested 295e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * root. The returned documents should be sorted by relevance in descending 296e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * order. How documents are matched against the query string is an 297e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * implementation detail left to each provider, but it's suggested that at 298e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * least {@link Document#COLUMN_DISPLAY_NAME} be matched in a 299e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * case-insensitive fashion. 300e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * <p> 301e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * Only documents may be returned; directories are not supported in search 302e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * results. 3039352c383e95c3e1facd8a7a2d49ff488fb7bbcafJeff Sharkey * <p> 3049352c383e95c3e1facd8a7a2d49ff488fb7bbcafJeff Sharkey * If your provider is cloud-based, and you have some data cached or pinned 3059352c383e95c3e1facd8a7a2d49ff488fb7bbcafJeff Sharkey * locally, you may return the local data immediately, setting 3069352c383e95c3e1facd8a7a2d49ff488fb7bbcafJeff Sharkey * {@link DocumentsContract#EXTRA_LOADING} on the Cursor to indicate that 3079352c383e95c3e1facd8a7a2d49ff488fb7bbcafJeff Sharkey * you are still fetching additional data. Then, when the network data is 3089352c383e95c3e1facd8a7a2d49ff488fb7bbcafJeff Sharkey * available, you can send a change notification to trigger a requery and 3099352c383e95c3e1facd8a7a2d49ff488fb7bbcafJeff Sharkey * return the complete contents. 3109352c383e95c3e1facd8a7a2d49ff488fb7bbcafJeff Sharkey * <p> 3119352c383e95c3e1facd8a7a2d49ff488fb7bbcafJeff Sharkey * To support change notifications, you must 3129352c383e95c3e1facd8a7a2d49ff488fb7bbcafJeff Sharkey * {@link Cursor#setNotificationUri(ContentResolver, Uri)} with a relevant 3139352c383e95c3e1facd8a7a2d49ff488fb7bbcafJeff Sharkey * Uri, such as {@link DocumentsContract#buildSearchDocumentsUri(String, 3149352c383e95c3e1facd8a7a2d49ff488fb7bbcafJeff Sharkey * String, String)}. Then you can call {@link ContentResolver#notifyChange(Uri, 3159352c383e95c3e1facd8a7a2d49ff488fb7bbcafJeff Sharkey * android.database.ContentObserver, boolean)} with that Uri to send change 3169352c383e95c3e1facd8a7a2d49ff488fb7bbcafJeff Sharkey * notifications. 317aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey * 3183e1189b3590aefb65a2af720ae2ba959bbd4188dJeff Sharkey * @param rootId the root to search under. 319e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * @param query string to match documents against. 320e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * @param projection list of {@link Document} columns to put into the 321e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * cursor. If {@code null} all supported columns should be 322e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * included. 323e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * @see DocumentsContract#EXTRA_LOADING 324e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * @see DocumentsContract#EXTRA_INFO 325e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * @see DocumentsContract#EXTRA_ERROR 326aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey */ 327aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey @SuppressWarnings("unused") 3283e1189b3590aefb65a2af720ae2ba959bbd4188dJeff Sharkey public Cursor querySearchDocuments(String rootId, String query, String[] projection) 329ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey throws FileNotFoundException { 330aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey throw new UnsupportedOperationException("Search not supported"); 331aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey } 332aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey 333aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey /** 334e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * Return concrete MIME type of the requested document. Must match the value 335e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * of {@link Document#COLUMN_MIME_TYPE} for this document. The default 336e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * implementation queries {@link #queryDocument(String, String[])}, so 337e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * providers may choose to override this as an optimization. 338aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey */ 339ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey public String getDocumentType(String documentId) throws FileNotFoundException { 340ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey final Cursor cursor = queryDocument(documentId, null); 341aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey try { 342aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey if (cursor.moveToFirst()) { 343ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey return cursor.getString(cursor.getColumnIndexOrThrow(Document.COLUMN_MIME_TYPE)); 344aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey } else { 345aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey return null; 346aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey } 347aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey } finally { 348aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey IoUtils.closeQuietly(cursor); 349aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey } 350aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey } 351aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey 352aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey /** 353e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * Open and return the requested document. 354e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * <p> 3559352c383e95c3e1facd8a7a2d49ff488fb7bbcafJeff Sharkey * Your provider should return a reliable {@link ParcelFileDescriptor} to 356e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * detect when the remote caller has finished reading or writing the 3579352c383e95c3e1facd8a7a2d49ff488fb7bbcafJeff Sharkey * document. You may return a pipe or socket pair if the mode is exclusively 3589352c383e95c3e1facd8a7a2d49ff488fb7bbcafJeff Sharkey * "r" or "w", but complex modes like "rw" imply a normal file on disk that 3599352c383e95c3e1facd8a7a2d49ff488fb7bbcafJeff Sharkey * supports seeking. 360e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * <p> 3619352c383e95c3e1facd8a7a2d49ff488fb7bbcafJeff Sharkey * If you block while downloading content, you should periodically check 3629352c383e95c3e1facd8a7a2d49ff488fb7bbcafJeff Sharkey * {@link CancellationSignal#isCanceled()} to abort abandoned open requests. 363aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey * 364e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * @param documentId the document to return. 365aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey * @param mode the mode to open with, such as 'r', 'w', or 'rw'. 366aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey * @param signal used by the caller to signal if the request should be 3673b945405cf96eae8b882f87934222a453718a559Jeff Sharkey * cancelled. May be null. 368aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey * @see ParcelFileDescriptor#open(java.io.File, int, android.os.Handler, 369aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey * OnCloseListener) 370aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey * @see ParcelFileDescriptor#createReliablePipe() 371aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey * @see ParcelFileDescriptor#createReliableSocketPair() 372e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * @see ParcelFileDescriptor#parseMode(String) 373aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey */ 374aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey public abstract ParcelFileDescriptor openDocument( 375e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey String documentId, String mode, CancellationSignal signal) throws FileNotFoundException; 376aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey 377aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey /** 378e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * Open and return a thumbnail of the requested document. 379e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * <p> 380e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * A provider should return a thumbnail closely matching the hinted size, 381e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * attempting to serve from a local cache if possible. A provider should 382e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * never return images more than double the hinted size. 383e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * <p> 3849352c383e95c3e1facd8a7a2d49ff488fb7bbcafJeff Sharkey * If you perform expensive operations to download or generate a thumbnail, 3859352c383e95c3e1facd8a7a2d49ff488fb7bbcafJeff Sharkey * you should periodically check {@link CancellationSignal#isCanceled()} to 3869352c383e95c3e1facd8a7a2d49ff488fb7bbcafJeff Sharkey * abort abandoned thumbnail requests. 387aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey * 388e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * @param documentId the document to return. 389aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey * @param sizeHint hint of the optimal thumbnail dimensions. 390aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey * @param signal used by the caller to signal if the request should be 3913b945405cf96eae8b882f87934222a453718a559Jeff Sharkey * cancelled. May be null. 392ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey * @see Document#FLAG_SUPPORTS_THUMBNAIL 393aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey */ 394aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey @SuppressWarnings("unused") 395aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey public AssetFileDescriptor openDocumentThumbnail( 396e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey String documentId, Point sizeHint, CancellationSignal signal) 397e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey throws FileNotFoundException { 398aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey throw new UnsupportedOperationException("Thumbnails not supported"); 399aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey } 400aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey 401ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey /** 402ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey * Implementation is provided by the parent class. Cannot be overriden. 403ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey * 404ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey * @see #queryRoots(String[]) 405ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey * @see #queryRecentDocuments(String, String[]) 406ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey * @see #queryDocument(String, String[]) 407ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey * @see #queryChildDocuments(String, String[], String) 408ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey * @see #querySearchDocuments(String, String, String[]) 409ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey */ 410aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey @Override 411ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey public final Cursor query(Uri uri, String[] projection, String selection, 412ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey String[] selectionArgs, String sortOrder) { 413aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey try { 414aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey switch (mMatcher.match(uri)) { 415a61dc8e03e6e863005b3a4629ca8f3801d33d3c4Jeff Sharkey case MATCH_ROOTS: 416ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey return queryRoots(projection); 417ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey case MATCH_RECENT: 418ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey return queryRecentDocuments(getRootId(uri), projection); 4193e1189b3590aefb65a2af720ae2ba959bbd4188dJeff Sharkey case MATCH_SEARCH: 4203e1189b3590aefb65a2af720ae2ba959bbd4188dJeff Sharkey return querySearchDocuments( 4213e1189b3590aefb65a2af720ae2ba959bbd4188dJeff Sharkey getRootId(uri), getSearchDocumentsQuery(uri), projection); 422aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey case MATCH_DOCUMENT: 423ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey return queryDocument(getDocumentId(uri), projection); 424aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey case MATCH_CHILDREN: 4254ec973925fc2cd18f9ec0d0ca5af588564fded27Jeff Sharkey if (DocumentsContract.isManageMode(uri)) { 4264ec973925fc2cd18f9ec0d0ca5af588564fded27Jeff Sharkey return queryChildDocumentsForManage( 4274ec973925fc2cd18f9ec0d0ca5af588564fded27Jeff Sharkey getDocumentId(uri), projection, sortOrder); 4284ec973925fc2cd18f9ec0d0ca5af588564fded27Jeff Sharkey } else { 4294ec973925fc2cd18f9ec0d0ca5af588564fded27Jeff Sharkey return queryChildDocuments(getDocumentId(uri), projection, sortOrder); 4304ec973925fc2cd18f9ec0d0ca5af588564fded27Jeff Sharkey } 431aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey default: 432aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey throw new UnsupportedOperationException("Unsupported Uri " + uri); 433aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey } 434aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey } catch (FileNotFoundException e) { 435aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey Log.w(TAG, "Failed during query", e); 436aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey return null; 437aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey } 438aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey } 439aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey 440ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey /** 441ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey * Implementation is provided by the parent class. Cannot be overriden. 442ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey * 443ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey * @see #getDocumentType(String) 444ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey */ 445aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey @Override 446aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey public final String getType(Uri uri) { 447aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey try { 448aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey switch (mMatcher.match(uri)) { 449a61dc8e03e6e863005b3a4629ca8f3801d33d3c4Jeff Sharkey case MATCH_ROOT: 450a61dc8e03e6e863005b3a4629ca8f3801d33d3c4Jeff Sharkey return DocumentsContract.Root.MIME_TYPE_ITEM; 451aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey case MATCH_DOCUMENT: 452ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey return getDocumentType(getDocumentId(uri)); 453aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey default: 454aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey return null; 455aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey } 456aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey } catch (FileNotFoundException e) { 457aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey Log.w(TAG, "Failed during getType", e); 458aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey return null; 459aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey } 460aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey } 461aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey 462ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey /** 463ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey * Implementation is provided by the parent class. Throws by default, and 464ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey * cannot be overriden. 465ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey * 466ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey * @see #createDocument(String, String, String) 467ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey */ 468aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey @Override 469aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey public final Uri insert(Uri uri, ContentValues values) { 470aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey throw new UnsupportedOperationException("Insert not supported"); 471aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey } 472aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey 473ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey /** 474ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey * Implementation is provided by the parent class. Throws by default, and 475ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey * cannot be overriden. 476ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey * 477ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey * @see #deleteDocument(String) 478ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey */ 479aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey @Override 480aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey public final int delete(Uri uri, String selection, String[] selectionArgs) { 481aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey throw new UnsupportedOperationException("Delete not supported"); 482aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey } 483aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey 484ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey /** 485ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey * Implementation is provided by the parent class. Throws by default, and 486ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey * cannot be overriden. 487ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey */ 488aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey @Override 489aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey public final int update( 490aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey Uri uri, ContentValues values, String selection, String[] selectionArgs) { 491aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey throw new UnsupportedOperationException("Update not supported"); 492aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey } 493aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey 494911d7f411f36f2279aae44c89ff1d33a29140046Jeff Sharkey /** 495911d7f411f36f2279aae44c89ff1d33a29140046Jeff Sharkey * Implementation is provided by the parent class. Can be overridden to 496911d7f411f36f2279aae44c89ff1d33a29140046Jeff Sharkey * provide additional functionality, but subclasses <em>must</em> always 497911d7f411f36f2279aae44c89ff1d33a29140046Jeff Sharkey * call the superclass. If the superclass returns {@code null}, the subclass 498911d7f411f36f2279aae44c89ff1d33a29140046Jeff Sharkey * may implement custom behavior. 499911d7f411f36f2279aae44c89ff1d33a29140046Jeff Sharkey * 500911d7f411f36f2279aae44c89ff1d33a29140046Jeff Sharkey * @see #openDocument(String, String, CancellationSignal) 501911d7f411f36f2279aae44c89ff1d33a29140046Jeff Sharkey * @see #deleteDocument(String) 502911d7f411f36f2279aae44c89ff1d33a29140046Jeff Sharkey */ 503aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey @Override 504911d7f411f36f2279aae44c89ff1d33a29140046Jeff Sharkey public Bundle call(String method, String arg, Bundle extras) { 505e37ea6123d1aa3cd3e8804988886b1f6046d79d6Jeff Sharkey final Context context = getContext(); 506e37ea6123d1aa3cd3e8804988886b1f6046d79d6Jeff Sharkey 507aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey if (!method.startsWith("android:")) { 508aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey // Let non-platform methods pass through 509911d7f411f36f2279aae44c89ff1d33a29140046Jeff Sharkey return super.call(method, arg, extras); 510aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey } 511aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey 512ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey final String documentId = extras.getString(Document.COLUMN_DOCUMENT_ID); 513ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey final Uri documentUri = DocumentsContract.buildDocumentUri(mAuthority, documentId); 514e37ea6123d1aa3cd3e8804988886b1f6046d79d6Jeff Sharkey 515e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey // Require that caller can manage requested document 516e37ea6123d1aa3cd3e8804988886b1f6046d79d6Jeff Sharkey final boolean callerHasManage = 517e37ea6123d1aa3cd3e8804988886b1f6046d79d6Jeff Sharkey context.checkCallingOrSelfPermission(android.Manifest.permission.MANAGE_DOCUMENTS) 518e37ea6123d1aa3cd3e8804988886b1f6046d79d6Jeff Sharkey == PackageManager.PERMISSION_GRANTED; 5198a2998eade93032a78d681c66ebadbfa6f802f76Jeff Sharkey enforceWritePermissionInner(documentUri); 520aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey 521aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey final Bundle out = new Bundle(); 522aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey try { 523ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey if (METHOD_CREATE_DOCUMENT.equals(method)) { 524ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey final String mimeType = extras.getString(Document.COLUMN_MIME_TYPE); 525ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey final String displayName = extras.getString(Document.COLUMN_DISPLAY_NAME); 526aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey 527ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey final String newDocumentId = createDocument(documentId, mimeType, displayName); 528ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey out.putString(Document.COLUMN_DOCUMENT_ID, newDocumentId); 529aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey 530e37ea6123d1aa3cd3e8804988886b1f6046d79d6Jeff Sharkey // Extend permission grant towards caller if needed 531e37ea6123d1aa3cd3e8804988886b1f6046d79d6Jeff Sharkey if (!callerHasManage) { 532e37ea6123d1aa3cd3e8804988886b1f6046d79d6Jeff Sharkey final Uri newDocumentUri = DocumentsContract.buildDocumentUri( 533e37ea6123d1aa3cd3e8804988886b1f6046d79d6Jeff Sharkey mAuthority, newDocumentId); 534911d7f411f36f2279aae44c89ff1d33a29140046Jeff Sharkey context.grantUriPermission(getCallingPackage(), newDocumentUri, 535e37ea6123d1aa3cd3e8804988886b1f6046d79d6Jeff Sharkey Intent.FLAG_GRANT_READ_URI_PERMISSION 536e37ea6123d1aa3cd3e8804988886b1f6046d79d6Jeff Sharkey | Intent.FLAG_GRANT_WRITE_URI_PERMISSION 537e66c1778f80f4b18e29e018eca3a338f125f23b9Jeff Sharkey | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION); 538e37ea6123d1aa3cd3e8804988886b1f6046d79d6Jeff Sharkey } 539e37ea6123d1aa3cd3e8804988886b1f6046d79d6Jeff Sharkey 540aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey } else if (METHOD_DELETE_DOCUMENT.equals(method)) { 541e37ea6123d1aa3cd3e8804988886b1f6046d79d6Jeff Sharkey deleteDocument(documentId); 542e37ea6123d1aa3cd3e8804988886b1f6046d79d6Jeff Sharkey 543e37ea6123d1aa3cd3e8804988886b1f6046d79d6Jeff Sharkey // Document no longer exists, clean up any grants 544e37ea6123d1aa3cd3e8804988886b1f6046d79d6Jeff Sharkey context.revokeUriPermission(documentUri, Intent.FLAG_GRANT_READ_URI_PERMISSION 545e37ea6123d1aa3cd3e8804988886b1f6046d79d6Jeff Sharkey | Intent.FLAG_GRANT_WRITE_URI_PERMISSION 546e66c1778f80f4b18e29e018eca3a338f125f23b9Jeff Sharkey | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION); 547aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey 548aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey } else { 549aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey throw new UnsupportedOperationException("Method not supported " + method); 550aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey } 551aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey } catch (FileNotFoundException e) { 552aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey throw new IllegalStateException("Failed call " + method, e); 553aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey } 554aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey return out; 555aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey } 556aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey 557ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey /** 558e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * Implementation is provided by the parent class. Cannot be overriden. 559ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey * 560ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey * @see #openDocument(String, String, CancellationSignal) 561ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey */ 562aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey @Override 563aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey public final ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException { 564ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey return openDocument(getDocumentId(uri), mode, null); 565aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey } 566aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey 567ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey /** 568e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * Implementation is provided by the parent class. Cannot be overriden. 569ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey * 570ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey * @see #openDocument(String, String, CancellationSignal) 571ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey */ 572aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey @Override 573aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey public final ParcelFileDescriptor openFile(Uri uri, String mode, CancellationSignal signal) 574aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey throws FileNotFoundException { 575ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey return openDocument(getDocumentId(uri), mode, signal); 576aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey } 577aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey 578ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey /** 579e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * Implementation is provided by the parent class. Cannot be overriden. 580ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey * 581ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey * @see #openDocumentThumbnail(String, Point, CancellationSignal) 582ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey */ 583aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey @Override 584aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey public final AssetFileDescriptor openTypedAssetFile(Uri uri, String mimeTypeFilter, Bundle opts) 585aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey throws FileNotFoundException { 586aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey if (opts != null && opts.containsKey(EXTRA_THUMBNAIL_SIZE)) { 587aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey final Point sizeHint = opts.getParcelable(EXTRA_THUMBNAIL_SIZE); 588ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey return openDocumentThumbnail(getDocumentId(uri), sizeHint, null); 589aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey } else { 590aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey return super.openTypedAssetFile(uri, mimeTypeFilter, opts); 591aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey } 592aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey } 593aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey 594ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey /** 595e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * Implementation is provided by the parent class. Cannot be overriden. 596ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey * 597ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey * @see #openDocumentThumbnail(String, Point, CancellationSignal) 598ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey */ 599aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey @Override 600aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey public final AssetFileDescriptor openTypedAssetFile( 601aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey Uri uri, String mimeTypeFilter, Bundle opts, CancellationSignal signal) 602aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey throws FileNotFoundException { 603aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey if (opts != null && opts.containsKey(EXTRA_THUMBNAIL_SIZE)) { 604aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey final Point sizeHint = opts.getParcelable(EXTRA_THUMBNAIL_SIZE); 605ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey return openDocumentThumbnail(getDocumentId(uri), sizeHint, signal); 606aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey } else { 607aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey return super.openTypedAssetFile(uri, mimeTypeFilter, opts, signal); 608aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey } 609aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey } 610aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey} 611