DocumentsProvider.java revision e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372
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">&lt;manifest&gt;
57e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey *    ...
58e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey *    &lt;application&gt;
59e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey *        ...
60e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey *        &lt;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"
65e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey *            android:permission="android.permission.MANAGE_DOCUMENTS"&gt;
66e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey *            &lt;intent-filter&gt;
67e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey *                &lt;action android:name="android.content.action.DOCUMENTS_PROVIDER" /&gt;
68e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey *            &lt;/intent-filter&gt;
69e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey *        &lt;/provider&gt;
70e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey *        ...
71e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey *    &lt;/application&gt;
72e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey *&lt;/manifest&gt;</pre>
73aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey * <p>
74e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * When defining your provider, you must protect it with
75e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * {@link android.Manifest.permission#MANAGE_DOCUMENTS}, which is a permission
76e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * only the system can obtain. Applications cannot use a documents provider
77e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * directly; they must go through {@link Intent#ACTION_OPEN_DOCUMENT} or
78e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * {@link Intent#ACTION_CREATE_DOCUMENT} which requires a user to actively
79e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * navigate and select documents. When a user selects documents through that
80e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * UI, the system issues narrow URI permission grants to the requesting
81e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * 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
94e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * as a thumbnail, a provider can set {@link Document#FLAG_SUPPORTS_THUMBNAIL}
95e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * 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
105e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey * directory of 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
165e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     * {@link Document#COLUMN_DOCUMENT_ID}. A provider 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    /**
197e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     * Return all roots currently provided. A provider must define at least one
198e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     * root to display to users, and it should avoid making network requests to
199e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     * keep this 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,
206e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     * android.database.ContentObserver)} to notify the system.
207e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     *
208e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     * @param projection list of {@link Root} columns to put into the cursor. If
209e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     *            {@code null} all supported columns should be included.
210e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     */
211ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey    public abstract Cursor queryRoots(String[] projection) throws FileNotFoundException;
212ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey
213e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey    /**
214e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     * Return recently modified documents under the requested root. This will
215e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     * only be called for roots that advertise
216e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     * {@link Root#FLAG_SUPPORTS_RECENTS}. The returned documents should be
217e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     * sorted by {@link Document#COLUMN_LAST_MODIFIED} in descending order, and
218e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     * limited to only return the 64 most recently modified documents.
219e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     *
220e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     * @param projection list of {@link Document} columns to put into the
221e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     *            cursor. If {@code null} all supported columns should be
222e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     *            included.
223e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     * @see DocumentsContract#EXTRA_LOADING
224e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     */
225aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    @SuppressWarnings("unused")
226ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey    public Cursor queryRecentDocuments(String rootId, String[] projection)
227ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey            throws FileNotFoundException {
228ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey        throw new UnsupportedOperationException("Recent not supported");
229aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    }
230aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey
231aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    /**
232e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     * Return metadata for the single requested document. A provider should
233e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     * avoid making network requests to keep this request fast.
234aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey     *
235ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     * @param documentId the document to return.
236e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     * @param projection list of {@link Document} columns to put into the
237e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     *            cursor. If {@code null} all supported columns should be
238e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     *            included.
239aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey     */
240ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey    public abstract Cursor queryDocument(String documentId, String[] projection)
241ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey            throws FileNotFoundException;
242aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey
243aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    /**
244e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     * Return the children documents contained in the requested directory. This
245e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     * must only return immediate descendants, as additional queries will be
246e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     * issued to recursively explore the tree.
247e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     * <p>
248e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     * If your provider is cloud-based, and you have some data cached or pinned
249e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     * locally, you may return the local data immediately, setting
250e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     * {@link DocumentsContract#EXTRA_LOADING} on the Cursor to indicate that
251e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     * your provider is still fetching additional data. Then, when the network
252e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     * data is available, you can call {@link ContentResolver#notifyChange(Uri,
253e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     * android.database.ContentObserver)} to trigger a requery and return the
254e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     * complete contents.
255aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey     *
256ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     * @param parentDocumentId the directory to return children for.
257e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     * @param projection list of {@link Document} columns to put into the
258e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     *            cursor. If {@code null} all supported columns should be
259e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     *            included.
260e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     * @param sortOrder how to order the rows, formatted as an SQL
261e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     *            {@code ORDER BY} clause (excluding the ORDER BY itself).
262e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     *            Passing {@code null} will use the default sort order, which
263e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     *            may be unordered. This ordering is a hint that can be used to
264e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     *            prioritize how data is fetched from the network, but UI may
265e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     *            always enforce a specific ordering.
266e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     * @see DocumentsContract#EXTRA_LOADING
267e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     * @see DocumentsContract#EXTRA_INFO
268e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     * @see DocumentsContract#EXTRA_ERROR
269aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey     */
270ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey    public abstract Cursor queryChildDocuments(
271ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey            String parentDocumentId, String[] projection, String sortOrder)
272ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey            throws FileNotFoundException;
273aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey
2744ec973925fc2cd18f9ec0d0ca5af588564fded27Jeff Sharkey    /** {@hide} */
2754ec973925fc2cd18f9ec0d0ca5af588564fded27Jeff Sharkey    @SuppressWarnings("unused")
2764ec973925fc2cd18f9ec0d0ca5af588564fded27Jeff Sharkey    public Cursor queryChildDocumentsForManage(
2774ec973925fc2cd18f9ec0d0ca5af588564fded27Jeff Sharkey            String parentDocumentId, String[] projection, String sortOrder)
2784ec973925fc2cd18f9ec0d0ca5af588564fded27Jeff Sharkey            throws FileNotFoundException {
2794ec973925fc2cd18f9ec0d0ca5af588564fded27Jeff Sharkey        throw new UnsupportedOperationException("Manage not supported");
2804ec973925fc2cd18f9ec0d0ca5af588564fded27Jeff Sharkey    }
2814ec973925fc2cd18f9ec0d0ca5af588564fded27Jeff Sharkey
282aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    /**
283e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     * Return documents that that match the given query under the requested
284e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     * root. The returned documents should be sorted by relevance in descending
285e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     * order. How documents are matched against the query string is an
286e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     * implementation detail left to each provider, but it's suggested that at
287e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     * least {@link Document#COLUMN_DISPLAY_NAME} be matched in a
288e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     * case-insensitive fashion.
289e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     * <p>
290e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     * Only documents may be returned; directories are not supported in search
291e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     * results.
292aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey     *
2933e1189b3590aefb65a2af720ae2ba959bbd4188dJeff Sharkey     * @param rootId the root to search under.
294e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     * @param query string to match documents against.
295e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     * @param projection list of {@link Document} columns to put into the
296e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     *            cursor. If {@code null} all supported columns should be
297e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     *            included.
298e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     * @see DocumentsContract#EXTRA_LOADING
299e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     * @see DocumentsContract#EXTRA_INFO
300e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     * @see DocumentsContract#EXTRA_ERROR
301aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey     */
302aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    @SuppressWarnings("unused")
3033e1189b3590aefb65a2af720ae2ba959bbd4188dJeff Sharkey    public Cursor querySearchDocuments(String rootId, String query, String[] projection)
304ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey            throws FileNotFoundException {
305aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey        throw new UnsupportedOperationException("Search not supported");
306aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    }
307aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey
308aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    /**
309e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     * Return concrete MIME type of the requested document. Must match the value
310e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     * of {@link Document#COLUMN_MIME_TYPE} for this document. The default
311e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     * implementation queries {@link #queryDocument(String, String[])}, so
312e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     * providers may choose to override this as an optimization.
313aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey     */
314ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey    public String getDocumentType(String documentId) throws FileNotFoundException {
315ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey        final Cursor cursor = queryDocument(documentId, null);
316aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey        try {
317aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey            if (cursor.moveToFirst()) {
318ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey                return cursor.getString(cursor.getColumnIndexOrThrow(Document.COLUMN_MIME_TYPE));
319aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey            } else {
320aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey                return null;
321aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey            }
322aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey        } finally {
323aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey            IoUtils.closeQuietly(cursor);
324aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey        }
325aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    }
326aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey
327aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    /**
328e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     * Open and return the requested document.
329e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     * <p>
330e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     * A provider should return a reliable {@link ParcelFileDescriptor} to
331e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     * detect when the remote caller has finished reading or writing the
332e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     * document. A provider may return a pipe or socket pair if the mode is
333e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     * exclusively {@link ParcelFileDescriptor#MODE_READ_ONLY} or
334aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey     * {@link ParcelFileDescriptor#MODE_WRITE_ONLY}, but complex modes like
335aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey     * {@link ParcelFileDescriptor#MODE_READ_WRITE} require a normal file on
336e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     * disk.
337e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     * <p>
338e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     * If a provider blocks while downloading content, it should periodically
339e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     * check {@link CancellationSignal#isCanceled()} to abort abandoned open
340e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     * requests.
341aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey     *
342e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     * @param documentId the document to return.
343aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey     * @param mode the mode to open with, such as 'r', 'w', or 'rw'.
344aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey     * @param signal used by the caller to signal if the request should be
345aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey     *            cancelled.
346aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey     * @see ParcelFileDescriptor#open(java.io.File, int, android.os.Handler,
347aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey     *      OnCloseListener)
348aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey     * @see ParcelFileDescriptor#createReliablePipe()
349aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey     * @see ParcelFileDescriptor#createReliableSocketPair()
350e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     * @see ParcelFileDescriptor#parseMode(String)
351aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey     */
352aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    public abstract ParcelFileDescriptor openDocument(
353e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey            String documentId, String mode, CancellationSignal signal) throws FileNotFoundException;
354aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey
355aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    /**
356e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     * Open and return a thumbnail of the requested document.
357e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     * <p>
358e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     * A provider should return a thumbnail closely matching the hinted size,
359e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     * attempting to serve from a local cache if possible. A provider should
360e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     * never return images more than double the hinted size.
361e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     * <p>
362e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     * If a provider performs expensive operations to download or generate a
363e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     * thumbnail, it should periodically check
364e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     * {@link CancellationSignal#isCanceled()} to abort abandoned thumbnail
365e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     * requests.
366aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey     *
367e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     * @param documentId the document to return.
368aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey     * @param sizeHint hint of the optimal thumbnail dimensions.
369aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey     * @param signal used by the caller to signal if the request should be
370aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey     *            cancelled.
371ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     * @see Document#FLAG_SUPPORTS_THUMBNAIL
372aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey     */
373aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    @SuppressWarnings("unused")
374aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    public AssetFileDescriptor openDocumentThumbnail(
375e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey            String documentId, Point sizeHint, CancellationSignal signal)
376e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey            throws FileNotFoundException {
377aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey        throw new UnsupportedOperationException("Thumbnails not supported");
378aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    }
379aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey
380ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey    /**
381ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     * Implementation is provided by the parent class. Cannot be overriden.
382ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     *
383ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     * @see #queryRoots(String[])
384ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     * @see #queryRecentDocuments(String, String[])
385ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     * @see #queryDocument(String, String[])
386ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     * @see #queryChildDocuments(String, String[], String)
387ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     * @see #querySearchDocuments(String, String, String[])
388ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     */
389aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    @Override
390ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey    public final Cursor query(Uri uri, String[] projection, String selection,
391ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey            String[] selectionArgs, String sortOrder) {
392aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey        try {
393aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey            switch (mMatcher.match(uri)) {
394a61dc8e03e6e863005b3a4629ca8f3801d33d3c4Jeff Sharkey                case MATCH_ROOTS:
395ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey                    return queryRoots(projection);
396ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey                case MATCH_RECENT:
397ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey                    return queryRecentDocuments(getRootId(uri), projection);
3983e1189b3590aefb65a2af720ae2ba959bbd4188dJeff Sharkey                case MATCH_SEARCH:
3993e1189b3590aefb65a2af720ae2ba959bbd4188dJeff Sharkey                    return querySearchDocuments(
4003e1189b3590aefb65a2af720ae2ba959bbd4188dJeff Sharkey                            getRootId(uri), getSearchDocumentsQuery(uri), projection);
401aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey                case MATCH_DOCUMENT:
402ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey                    return queryDocument(getDocumentId(uri), projection);
403aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey                case MATCH_CHILDREN:
4044ec973925fc2cd18f9ec0d0ca5af588564fded27Jeff Sharkey                    if (DocumentsContract.isManageMode(uri)) {
4054ec973925fc2cd18f9ec0d0ca5af588564fded27Jeff Sharkey                        return queryChildDocumentsForManage(
4064ec973925fc2cd18f9ec0d0ca5af588564fded27Jeff Sharkey                                getDocumentId(uri), projection, sortOrder);
4074ec973925fc2cd18f9ec0d0ca5af588564fded27Jeff Sharkey                    } else {
4084ec973925fc2cd18f9ec0d0ca5af588564fded27Jeff Sharkey                        return queryChildDocuments(getDocumentId(uri), projection, sortOrder);
4094ec973925fc2cd18f9ec0d0ca5af588564fded27Jeff Sharkey                    }
410aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey                default:
411aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey                    throw new UnsupportedOperationException("Unsupported Uri " + uri);
412aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey            }
413aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey        } catch (FileNotFoundException e) {
414aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey            Log.w(TAG, "Failed during query", e);
415aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey            return null;
416aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey        }
417aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    }
418aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey
419ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey    /**
420ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     * Implementation is provided by the parent class. Cannot be overriden.
421ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     *
422ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     * @see #getDocumentType(String)
423ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     */
424aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    @Override
425aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    public final String getType(Uri uri) {
426aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey        try {
427aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey            switch (mMatcher.match(uri)) {
428a61dc8e03e6e863005b3a4629ca8f3801d33d3c4Jeff Sharkey                case MATCH_ROOT:
429a61dc8e03e6e863005b3a4629ca8f3801d33d3c4Jeff Sharkey                    return DocumentsContract.Root.MIME_TYPE_ITEM;
430aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey                case MATCH_DOCUMENT:
431ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey                    return getDocumentType(getDocumentId(uri));
432aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey                default:
433aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey                    return null;
434aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey            }
435aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey        } catch (FileNotFoundException e) {
436aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey            Log.w(TAG, "Failed during getType", e);
437aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey            return null;
438aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey        }
439aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    }
440aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey
441ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey    /**
442ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     * Implementation is provided by the parent class. Throws by default, and
443ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     * cannot be overriden.
444ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     *
445ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     * @see #createDocument(String, String, String)
446ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     */
447aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    @Override
448aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    public final Uri insert(Uri uri, ContentValues values) {
449aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey        throw new UnsupportedOperationException("Insert not supported");
450aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    }
451aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey
452ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey    /**
453ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     * Implementation is provided by the parent class. Throws by default, and
454ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     * cannot be overriden.
455ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     *
456ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     * @see #deleteDocument(String)
457ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     */
458aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    @Override
459aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    public final int delete(Uri uri, String selection, String[] selectionArgs) {
460aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey        throw new UnsupportedOperationException("Delete not supported");
461aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    }
462aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey
463ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey    /**
464ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     * Implementation is provided by the parent class. Throws by default, and
465ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     * cannot be overriden.
466ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     */
467aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    @Override
468aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    public final int update(
469aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey            Uri uri, ContentValues values, String selection, String[] selectionArgs) {
470aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey        throw new UnsupportedOperationException("Update not supported");
471aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    }
472aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey
473911d7f411f36f2279aae44c89ff1d33a29140046Jeff Sharkey    /**
474911d7f411f36f2279aae44c89ff1d33a29140046Jeff Sharkey     * Implementation is provided by the parent class. Can be overridden to
475911d7f411f36f2279aae44c89ff1d33a29140046Jeff Sharkey     * provide additional functionality, but subclasses <em>must</em> always
476911d7f411f36f2279aae44c89ff1d33a29140046Jeff Sharkey     * call the superclass. If the superclass returns {@code null}, the subclass
477911d7f411f36f2279aae44c89ff1d33a29140046Jeff Sharkey     * may implement custom behavior.
478911d7f411f36f2279aae44c89ff1d33a29140046Jeff Sharkey     *
479911d7f411f36f2279aae44c89ff1d33a29140046Jeff Sharkey     * @see #openDocument(String, String, CancellationSignal)
480911d7f411f36f2279aae44c89ff1d33a29140046Jeff Sharkey     * @see #deleteDocument(String)
481911d7f411f36f2279aae44c89ff1d33a29140046Jeff Sharkey     */
482aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    @Override
483911d7f411f36f2279aae44c89ff1d33a29140046Jeff Sharkey    public Bundle call(String method, String arg, Bundle extras) {
484e37ea6123d1aa3cd3e8804988886b1f6046d79d6Jeff Sharkey        final Context context = getContext();
485e37ea6123d1aa3cd3e8804988886b1f6046d79d6Jeff Sharkey
486aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey        if (!method.startsWith("android:")) {
487aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey            // Let non-platform methods pass through
488911d7f411f36f2279aae44c89ff1d33a29140046Jeff Sharkey            return super.call(method, arg, extras);
489aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey        }
490aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey
491ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey        final String documentId = extras.getString(Document.COLUMN_DOCUMENT_ID);
492ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey        final Uri documentUri = DocumentsContract.buildDocumentUri(mAuthority, documentId);
493e37ea6123d1aa3cd3e8804988886b1f6046d79d6Jeff Sharkey
494e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey        // Require that caller can manage requested document
495e37ea6123d1aa3cd3e8804988886b1f6046d79d6Jeff Sharkey        final boolean callerHasManage =
496e37ea6123d1aa3cd3e8804988886b1f6046d79d6Jeff Sharkey                context.checkCallingOrSelfPermission(android.Manifest.permission.MANAGE_DOCUMENTS)
497e37ea6123d1aa3cd3e8804988886b1f6046d79d6Jeff Sharkey                == PackageManager.PERMISSION_GRANTED;
498e37ea6123d1aa3cd3e8804988886b1f6046d79d6Jeff Sharkey        if (!callerHasManage) {
499e37ea6123d1aa3cd3e8804988886b1f6046d79d6Jeff Sharkey            getContext().enforceCallingOrSelfUriPermission(
500e37ea6123d1aa3cd3e8804988886b1f6046d79d6Jeff Sharkey                    documentUri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION, method);
501e37ea6123d1aa3cd3e8804988886b1f6046d79d6Jeff Sharkey        }
502aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey
503aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey        final Bundle out = new Bundle();
504aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey        try {
505ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey            if (METHOD_CREATE_DOCUMENT.equals(method)) {
506ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey                final String mimeType = extras.getString(Document.COLUMN_MIME_TYPE);
507ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey                final String displayName = extras.getString(Document.COLUMN_DISPLAY_NAME);
508aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey
509ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey                final String newDocumentId = createDocument(documentId, mimeType, displayName);
510ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey                out.putString(Document.COLUMN_DOCUMENT_ID, newDocumentId);
511aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey
512e37ea6123d1aa3cd3e8804988886b1f6046d79d6Jeff Sharkey                // Extend permission grant towards caller if needed
513e37ea6123d1aa3cd3e8804988886b1f6046d79d6Jeff Sharkey                if (!callerHasManage) {
514e37ea6123d1aa3cd3e8804988886b1f6046d79d6Jeff Sharkey                    final Uri newDocumentUri = DocumentsContract.buildDocumentUri(
515e37ea6123d1aa3cd3e8804988886b1f6046d79d6Jeff Sharkey                            mAuthority, newDocumentId);
516911d7f411f36f2279aae44c89ff1d33a29140046Jeff Sharkey                    context.grantUriPermission(getCallingPackage(), newDocumentUri,
517e37ea6123d1aa3cd3e8804988886b1f6046d79d6Jeff Sharkey                            Intent.FLAG_GRANT_READ_URI_PERMISSION
518e37ea6123d1aa3cd3e8804988886b1f6046d79d6Jeff Sharkey                            | Intent.FLAG_GRANT_WRITE_URI_PERMISSION
519e66c1778f80f4b18e29e018eca3a338f125f23b9Jeff Sharkey                            | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
520e37ea6123d1aa3cd3e8804988886b1f6046d79d6Jeff Sharkey                }
521e37ea6123d1aa3cd3e8804988886b1f6046d79d6Jeff Sharkey
522aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey            } else if (METHOD_DELETE_DOCUMENT.equals(method)) {
523e37ea6123d1aa3cd3e8804988886b1f6046d79d6Jeff Sharkey                deleteDocument(documentId);
524e37ea6123d1aa3cd3e8804988886b1f6046d79d6Jeff Sharkey
525e37ea6123d1aa3cd3e8804988886b1f6046d79d6Jeff Sharkey                // Document no longer exists, clean up any grants
526e37ea6123d1aa3cd3e8804988886b1f6046d79d6Jeff Sharkey                context.revokeUriPermission(documentUri, Intent.FLAG_GRANT_READ_URI_PERMISSION
527e37ea6123d1aa3cd3e8804988886b1f6046d79d6Jeff Sharkey                        | Intent.FLAG_GRANT_WRITE_URI_PERMISSION
528e66c1778f80f4b18e29e018eca3a338f125f23b9Jeff Sharkey                        | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
529aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey
530aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey            } else {
531aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey                throw new UnsupportedOperationException("Method not supported " + method);
532aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey            }
533aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey        } catch (FileNotFoundException e) {
534aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey            throw new IllegalStateException("Failed call " + method, e);
535aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey        }
536aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey        return out;
537aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    }
538aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey
539ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey    /**
540e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     * Implementation is provided by the parent class. Cannot be overriden.
541ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     *
542ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     * @see #openDocument(String, String, CancellationSignal)
543ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     */
544aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    @Override
545aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    public final ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
546ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey        return openDocument(getDocumentId(uri), mode, null);
547aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    }
548aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey
549ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey    /**
550e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     * Implementation is provided by the parent class. Cannot be overriden.
551ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     *
552ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     * @see #openDocument(String, String, CancellationSignal)
553ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     */
554aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    @Override
555aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    public final ParcelFileDescriptor openFile(Uri uri, String mode, CancellationSignal signal)
556aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey            throws FileNotFoundException {
557ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey        return openDocument(getDocumentId(uri), mode, signal);
558aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    }
559aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey
560ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey    /**
561e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     * Implementation is provided by the parent class. Cannot be overriden.
562ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     *
563ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     * @see #openDocumentThumbnail(String, Point, CancellationSignal)
564ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     */
565aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    @Override
566aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    public final AssetFileDescriptor openTypedAssetFile(Uri uri, String mimeTypeFilter, Bundle opts)
567aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey            throws FileNotFoundException {
568aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey        if (opts != null && opts.containsKey(EXTRA_THUMBNAIL_SIZE)) {
569aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey            final Point sizeHint = opts.getParcelable(EXTRA_THUMBNAIL_SIZE);
570ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey            return openDocumentThumbnail(getDocumentId(uri), sizeHint, null);
571aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey        } else {
572aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey            return super.openTypedAssetFile(uri, mimeTypeFilter, opts);
573aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey        }
574aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    }
575aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey
576ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey    /**
577e8c00d8ed477e199b7f8d1b1e2f37e9cf8593372Jeff Sharkey     * Implementation is provided by the parent class. Cannot be overriden.
578ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     *
579ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     * @see #openDocumentThumbnail(String, Point, CancellationSignal)
580ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     */
581aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    @Override
582aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    public final AssetFileDescriptor openTypedAssetFile(
583aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey            Uri uri, String mimeTypeFilter, Bundle opts, CancellationSignal signal)
584aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey            throws FileNotFoundException {
585aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey        if (opts != null && opts.containsKey(EXTRA_THUMBNAIL_SIZE)) {
586aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey            final Point sizeHint = opts.getParcelable(EXTRA_THUMBNAIL_SIZE);
587ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey            return openDocumentThumbnail(getDocumentId(uri), sizeHint, signal);
588aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey        } else {
589aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey            return super.openTypedAssetFile(uri, mimeTypeFilter, opts, signal);
590aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey        }
591aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    }
592aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey}
593