DocumentsProvider.java revision e37ea6123d1aa3cd3e8804988886b1f6046d79d6
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;
27aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkeyimport android.content.ContentValues;
28aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkeyimport android.content.Context;
29aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkeyimport android.content.Intent;
30aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkeyimport android.content.UriMatcher;
31e37ea6123d1aa3cd3e8804988886b1f6046d79d6Jeff Sharkeyimport android.content.pm.PackageManager;
32aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkeyimport android.content.pm.ProviderInfo;
33aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkeyimport android.content.res.AssetFileDescriptor;
34aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkeyimport android.database.Cursor;
35aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkeyimport android.graphics.Point;
36aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkeyimport android.net.Uri;
37e37ea6123d1aa3cd3e8804988886b1f6046d79d6Jeff Sharkeyimport android.os.Binder;
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;
43aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkeyimport android.util.Log;
44aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey
45e37ea6123d1aa3cd3e8804988886b1f6046d79d6Jeff Sharkeyimport com.android.internal.util.ArrayUtils;
46e37ea6123d1aa3cd3e8804988886b1f6046d79d6Jeff Sharkey
47aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkeyimport libcore.io.IoUtils;
48aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey
49aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkeyimport java.io.FileNotFoundException;
50aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey
51aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey/**
52aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey * Base class for a document provider. A document provider should extend this
53aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey * class and implement the abstract methods.
54aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey * <p>
55aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey * Each document provider expresses one or more "roots" which each serve as the
56aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey * top-level of a tree. For example, a root could represent an account, or a
57aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey * physical storage device. Under each root, documents are referenced by
58ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey * {@link Document#COLUMN_DOCUMENT_ID}, which must not change once returned.
59aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey * <p>
60aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey * Documents can be either an openable file (with a specific MIME type), or a
61aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey * directory containing additional documents (with the
62ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey * {@link Document#MIME_TYPE_DIR} MIME type). Each document can have different
63ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey * capabilities, as described by {@link Document#COLUMN_FLAGS}. The same
64ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey * {@link Document#COLUMN_DOCUMENT_ID} can be included in multiple directories.
65aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey * <p>
66aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey * Document providers must be protected with the
67aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey * {@link android.Manifest.permission#MANAGE_DOCUMENTS} permission, which can
68aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey * only be requested by the system. The system-provided UI then issues narrow
69aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey * Uri permission grants for individual documents when the user explicitly picks
70aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey * documents.
71aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey *
72aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey * @see Intent#ACTION_OPEN_DOCUMENT
73aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey * @see Intent#ACTION_CREATE_DOCUMENT
74aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey */
75aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkeypublic abstract class DocumentsProvider extends ContentProvider {
76aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    private static final String TAG = "DocumentsProvider";
77aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey
78ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey    private static final int MATCH_ROOT = 1;
79ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey    private static final int MATCH_RECENT = 2;
80ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey    private static final int MATCH_DOCUMENT = 3;
81ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey    private static final int MATCH_CHILDREN = 4;
82ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey    private static final int MATCH_SEARCH = 5;
83aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey
84aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    private String mAuthority;
85aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey
86aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    private UriMatcher mMatcher;
87aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey
88ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey    /**
89ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     * Implementation is provided by the parent class.
90ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     */
91aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    @Override
92aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    public void attachInfo(Context context, ProviderInfo info) {
93aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey        mAuthority = info.authority;
94aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey
95aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey        mMatcher = new UriMatcher(UriMatcher.NO_MATCH);
96ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey        mMatcher.addURI(mAuthority, "root", MATCH_ROOT);
97ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey        mMatcher.addURI(mAuthority, "root/*/recent", MATCH_RECENT);
98ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey        mMatcher.addURI(mAuthority, "document/*", MATCH_DOCUMENT);
99ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey        mMatcher.addURI(mAuthority, "document/*/children", MATCH_CHILDREN);
100ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey        mMatcher.addURI(mAuthority, "document/*/search", MATCH_SEARCH);
101aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey
102aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey        // Sanity check our setup
103aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey        if (!info.exported) {
104aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey            throw new SecurityException("Provider must be exported");
105aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey        }
106aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey        if (!info.grantUriPermissions) {
107aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey            throw new SecurityException("Provider must grantUriPermissions");
108aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey        }
109aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey        if (!android.Manifest.permission.MANAGE_DOCUMENTS.equals(info.readPermission)
110aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey                || !android.Manifest.permission.MANAGE_DOCUMENTS.equals(info.writePermission)) {
111aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey            throw new SecurityException("Provider must be protected by MANAGE_DOCUMENTS");
112aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey        }
113aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey
114aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey        super.attachInfo(context, info);
115aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    }
116aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey
117aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    /**
118ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     * Create a new document and return its {@link Document#COLUMN_DOCUMENT_ID}.
119ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     * A provider must allocate a new {@link Document#COLUMN_DOCUMENT_ID} to
120ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     * represent the document, which must not change once returned.
121aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey     *
122ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     * @param documentId the parent directory to create the new document under.
123aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey     * @param mimeType the MIME type associated with the new document.
124aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey     * @param displayName the display name of the new document.
125aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey     */
126aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    @SuppressWarnings("unused")
127ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey    public String createDocument(String documentId, String mimeType, String displayName)
128aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey            throws FileNotFoundException {
129aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey        throw new UnsupportedOperationException("Create not supported");
130aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    }
131aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey
132aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    /**
133ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     * Delete the given document. Upon returning, any Uri permission grants for
134ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     * the given document will be revoked. If additional documents were deleted
135ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     * as a side effect of this call, such as documents inside a directory, the
136ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     * implementor is responsible for revoking those permissions.
137aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey     *
138ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     * @param documentId the document to delete.
139aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey     */
140aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    @SuppressWarnings("unused")
141ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey    public void deleteDocument(String documentId) throws FileNotFoundException {
142ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey        throw new UnsupportedOperationException("Delete not supported");
143aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    }
144aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey
145ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey    public abstract Cursor queryRoots(String[] projection) throws FileNotFoundException;
146ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey
147aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    @SuppressWarnings("unused")
148ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey    public Cursor queryRecentDocuments(String rootId, String[] projection)
149ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey            throws FileNotFoundException {
150ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey        throw new UnsupportedOperationException("Recent not supported");
151aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    }
152aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey
153aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    /**
154aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey     * Return metadata for the given document. A provider should avoid making
155aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey     * network requests to keep this request fast.
156aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey     *
157ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     * @param documentId the document to return.
158aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey     */
159ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey    public abstract Cursor queryDocument(String documentId, String[] projection)
160ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey            throws FileNotFoundException;
161aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey
162aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    /**
163aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey     * Return the children of the given document which is a directory.
164aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey     *
165ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     * @param parentDocumentId the directory to return children for.
166aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey     */
167ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey    public abstract Cursor queryChildDocuments(
168ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey            String parentDocumentId, String[] projection, String sortOrder)
169ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey            throws FileNotFoundException;
170aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey
171aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    /**
172aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey     * Return documents that that match the given query, starting the search at
173aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey     * the given directory.
174aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey     *
175ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     * @param parentDocumentId the directory to start search at.
176aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey     */
177aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    @SuppressWarnings("unused")
178ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey    public Cursor querySearchDocuments(String parentDocumentId, String query, String[] projection)
179ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey            throws FileNotFoundException {
180aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey        throw new UnsupportedOperationException("Search not supported");
181aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    }
182aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey
183aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    /**
184aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey     * Return MIME type for the given document. Must match the value of
185ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     * {@link Document#COLUMN_MIME_TYPE} for this document.
186aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey     */
187ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey    public String getDocumentType(String documentId) throws FileNotFoundException {
188ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey        final Cursor cursor = queryDocument(documentId, null);
189aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey        try {
190aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey            if (cursor.moveToFirst()) {
191ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey                return cursor.getString(cursor.getColumnIndexOrThrow(Document.COLUMN_MIME_TYPE));
192aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey            } else {
193aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey                return null;
194aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey            }
195aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey        } finally {
196aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey            IoUtils.closeQuietly(cursor);
197aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey        }
198aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    }
199aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey
200aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    /**
201aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey     * Open and return the requested document. A provider should return a
202aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey     * reliable {@link ParcelFileDescriptor} to detect when the remote caller
203aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey     * has finished reading or writing the document. A provider may return a
204aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey     * pipe or socket pair if the mode is exclusively
205aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey     * {@link ParcelFileDescriptor#MODE_READ_ONLY} or
206aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey     * {@link ParcelFileDescriptor#MODE_WRITE_ONLY}, but complex modes like
207aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey     * {@link ParcelFileDescriptor#MODE_READ_WRITE} require a normal file on
208aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey     * disk. If a provider blocks while downloading content, it should
209aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey     * periodically check {@link CancellationSignal#isCanceled()} to abort
210aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey     * abandoned open requests.
211aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey     *
212aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey     * @param docId the document to return.
213aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey     * @param mode the mode to open with, such as 'r', 'w', or 'rw'.
214aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey     * @param signal used by the caller to signal if the request should be
215aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey     *            cancelled.
216aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey     * @see ParcelFileDescriptor#open(java.io.File, int, android.os.Handler,
217aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey     *      OnCloseListener)
218aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey     * @see ParcelFileDescriptor#createReliablePipe()
219aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey     * @see ParcelFileDescriptor#createReliableSocketPair()
220aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey     */
221aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    public abstract ParcelFileDescriptor openDocument(
222aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey            String docId, String mode, CancellationSignal signal) throws FileNotFoundException;
223aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey
224aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    /**
225aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey     * Open and return a thumbnail of the requested document. A provider should
226aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey     * return a thumbnail closely matching the hinted size, attempting to serve
227aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey     * from a local cache if possible. A provider should never return images
228aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey     * more than double the hinted size. If a provider performs expensive
229aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey     * operations to download or generate a thumbnail, it should periodically
230aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey     * check {@link CancellationSignal#isCanceled()} to abort abandoned
231aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey     * thumbnail requests.
232aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey     *
233aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey     * @param docId the document to return.
234aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey     * @param sizeHint hint of the optimal thumbnail dimensions.
235aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey     * @param signal used by the caller to signal if the request should be
236aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey     *            cancelled.
237ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     * @see Document#FLAG_SUPPORTS_THUMBNAIL
238aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey     */
239aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    @SuppressWarnings("unused")
240aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    public AssetFileDescriptor openDocumentThumbnail(
241aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey            String docId, Point sizeHint, CancellationSignal signal) throws FileNotFoundException {
242aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey        throw new UnsupportedOperationException("Thumbnails not supported");
243aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    }
244aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey
245ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey    /**
246ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     * Implementation is provided by the parent class. Cannot be overriden.
247ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     *
248ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     * @see #queryRoots(String[])
249ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     * @see #queryRecentDocuments(String, String[])
250ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     * @see #queryDocument(String, String[])
251ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     * @see #queryChildDocuments(String, String[], String)
252ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     * @see #querySearchDocuments(String, String, String[])
253ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     */
254aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    @Override
255ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey    public final Cursor query(Uri uri, String[] projection, String selection,
256ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey            String[] selectionArgs, String sortOrder) {
257aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey        try {
258aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey            switch (mMatcher.match(uri)) {
259ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey                case MATCH_ROOT:
260ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey                    return queryRoots(projection);
261ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey                case MATCH_RECENT:
262ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey                    return queryRecentDocuments(getRootId(uri), projection);
263aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey                case MATCH_DOCUMENT:
264ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey                    return queryDocument(getDocumentId(uri), projection);
265aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey                case MATCH_CHILDREN:
266ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey                    return queryChildDocuments(getDocumentId(uri), projection, sortOrder);
267aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey                case MATCH_SEARCH:
268ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey                    return querySearchDocuments(
269ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey                            getDocumentId(uri), getSearchDocumentsQuery(uri), projection);
270aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey                default:
271aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey                    throw new UnsupportedOperationException("Unsupported Uri " + uri);
272aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey            }
273aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey        } catch (FileNotFoundException e) {
274aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey            Log.w(TAG, "Failed during query", e);
275aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey            return null;
276aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey        }
277aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    }
278aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey
279ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey    /**
280ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     * Implementation is provided by the parent class. Cannot be overriden.
281ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     *
282ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     * @see #getDocumentType(String)
283ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     */
284aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    @Override
285aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    public final String getType(Uri uri) {
286aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey        try {
287aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey            switch (mMatcher.match(uri)) {
288aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey                case MATCH_DOCUMENT:
289ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey                    return getDocumentType(getDocumentId(uri));
290aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey                default:
291aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey                    return null;
292aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey            }
293aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey        } catch (FileNotFoundException e) {
294aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey            Log.w(TAG, "Failed during getType", e);
295aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey            return null;
296aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey        }
297aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    }
298aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey
299ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey    /**
300ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     * Implementation is provided by the parent class. Throws by default, and
301ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     * cannot be overriden.
302ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     *
303ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     * @see #createDocument(String, String, String)
304ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     */
305aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    @Override
306aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    public final Uri insert(Uri uri, ContentValues values) {
307aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey        throw new UnsupportedOperationException("Insert not supported");
308aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    }
309aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey
310ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey    /**
311ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     * Implementation is provided by the parent class. Throws by default, and
312ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     * cannot be overriden.
313ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     *
314ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     * @see #deleteDocument(String)
315ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     */
316aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    @Override
317aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    public final int delete(Uri uri, String selection, String[] selectionArgs) {
318aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey        throw new UnsupportedOperationException("Delete not supported");
319aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    }
320aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey
321ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey    /**
322ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     * Implementation is provided by the parent class. Throws by default, and
323ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     * cannot be overriden.
324ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     */
325aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    @Override
326aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    public final int update(
327aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey            Uri uri, ContentValues values, String selection, String[] selectionArgs) {
328aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey        throw new UnsupportedOperationException("Update not supported");
329aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    }
330aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey
331ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey    /** {@hide} */
332aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    @Override
333aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    public final Bundle callFromPackage(
334aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey            String callingPackage, String method, String arg, Bundle extras) {
335e37ea6123d1aa3cd3e8804988886b1f6046d79d6Jeff Sharkey        final Context context = getContext();
336e37ea6123d1aa3cd3e8804988886b1f6046d79d6Jeff Sharkey
337aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey        if (!method.startsWith("android:")) {
338aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey            // Let non-platform methods pass through
339aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey            return super.callFromPackage(callingPackage, method, arg, extras);
340aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey        }
341aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey
342ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey        final String documentId = extras.getString(Document.COLUMN_DOCUMENT_ID);
343ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey        final Uri documentUri = DocumentsContract.buildDocumentUri(mAuthority, documentId);
344e37ea6123d1aa3cd3e8804988886b1f6046d79d6Jeff Sharkey
345e37ea6123d1aa3cd3e8804988886b1f6046d79d6Jeff Sharkey        // Require that caller can manage given document
346e37ea6123d1aa3cd3e8804988886b1f6046d79d6Jeff Sharkey        final boolean callerHasManage =
347e37ea6123d1aa3cd3e8804988886b1f6046d79d6Jeff Sharkey                context.checkCallingOrSelfPermission(android.Manifest.permission.MANAGE_DOCUMENTS)
348e37ea6123d1aa3cd3e8804988886b1f6046d79d6Jeff Sharkey                == PackageManager.PERMISSION_GRANTED;
349e37ea6123d1aa3cd3e8804988886b1f6046d79d6Jeff Sharkey        if (!callerHasManage) {
350e37ea6123d1aa3cd3e8804988886b1f6046d79d6Jeff Sharkey            getContext().enforceCallingOrSelfUriPermission(
351e37ea6123d1aa3cd3e8804988886b1f6046d79d6Jeff Sharkey                    documentUri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION, method);
352e37ea6123d1aa3cd3e8804988886b1f6046d79d6Jeff Sharkey        }
353aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey
354aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey        final Bundle out = new Bundle();
355aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey        try {
356ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey            if (METHOD_CREATE_DOCUMENT.equals(method)) {
357ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey                final String mimeType = extras.getString(Document.COLUMN_MIME_TYPE);
358ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey                final String displayName = extras.getString(Document.COLUMN_DISPLAY_NAME);
359aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey
360ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey                final String newDocumentId = createDocument(documentId, mimeType, displayName);
361ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey                out.putString(Document.COLUMN_DOCUMENT_ID, newDocumentId);
362aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey
363e37ea6123d1aa3cd3e8804988886b1f6046d79d6Jeff Sharkey                // Extend permission grant towards caller if needed
364e37ea6123d1aa3cd3e8804988886b1f6046d79d6Jeff Sharkey                if (!callerHasManage) {
365e37ea6123d1aa3cd3e8804988886b1f6046d79d6Jeff Sharkey                    final Uri newDocumentUri = DocumentsContract.buildDocumentUri(
366e37ea6123d1aa3cd3e8804988886b1f6046d79d6Jeff Sharkey                            mAuthority, newDocumentId);
367e37ea6123d1aa3cd3e8804988886b1f6046d79d6Jeff Sharkey                    context.grantUriPermission(callingPackage, newDocumentUri,
368e37ea6123d1aa3cd3e8804988886b1f6046d79d6Jeff Sharkey                            Intent.FLAG_GRANT_READ_URI_PERMISSION
369e37ea6123d1aa3cd3e8804988886b1f6046d79d6Jeff Sharkey                            | Intent.FLAG_GRANT_WRITE_URI_PERMISSION
370e37ea6123d1aa3cd3e8804988886b1f6046d79d6Jeff Sharkey                            | Intent.FLAG_PERSIST_GRANT_URI_PERMISSION);
371e37ea6123d1aa3cd3e8804988886b1f6046d79d6Jeff Sharkey                }
372e37ea6123d1aa3cd3e8804988886b1f6046d79d6Jeff Sharkey
373aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey            } else if (METHOD_DELETE_DOCUMENT.equals(method)) {
374e37ea6123d1aa3cd3e8804988886b1f6046d79d6Jeff Sharkey                deleteDocument(documentId);
375e37ea6123d1aa3cd3e8804988886b1f6046d79d6Jeff Sharkey
376e37ea6123d1aa3cd3e8804988886b1f6046d79d6Jeff Sharkey                // Document no longer exists, clean up any grants
377e37ea6123d1aa3cd3e8804988886b1f6046d79d6Jeff Sharkey                context.revokeUriPermission(documentUri, Intent.FLAG_GRANT_READ_URI_PERMISSION
378e37ea6123d1aa3cd3e8804988886b1f6046d79d6Jeff Sharkey                        | Intent.FLAG_GRANT_WRITE_URI_PERMISSION
379e37ea6123d1aa3cd3e8804988886b1f6046d79d6Jeff Sharkey                        | Intent.FLAG_PERSIST_GRANT_URI_PERMISSION);
380aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey
381aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey            } else {
382aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey                throw new UnsupportedOperationException("Method not supported " + method);
383aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey            }
384aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey        } catch (FileNotFoundException e) {
385aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey            throw new IllegalStateException("Failed call " + method, e);
386aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey        }
387aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey        return out;
388aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    }
389aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey
390ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey    /**
391ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     * Implementation is provided by the parent class.
392ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     *
393ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     * @see #openDocument(String, String, CancellationSignal)
394ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     */
395aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    @Override
396aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    public final ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
397ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey        return openDocument(getDocumentId(uri), mode, null);
398aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    }
399aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey
400ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey    /**
401ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     * Implementation is provided by the parent class.
402ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     *
403ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     * @see #openDocument(String, String, CancellationSignal)
404ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     */
405aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    @Override
406aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    public final ParcelFileDescriptor openFile(Uri uri, String mode, CancellationSignal signal)
407aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey            throws FileNotFoundException {
408ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey        return openDocument(getDocumentId(uri), mode, signal);
409aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    }
410aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey
411ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey    /**
412ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     * Implementation is provided by the parent class.
413ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     *
414ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     * @see #openDocumentThumbnail(String, Point, CancellationSignal)
415ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     */
416aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    @Override
417aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    public final AssetFileDescriptor openTypedAssetFile(Uri uri, String mimeTypeFilter, Bundle opts)
418aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey            throws FileNotFoundException {
419aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey        if (opts != null && opts.containsKey(EXTRA_THUMBNAIL_SIZE)) {
420aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey            final Point sizeHint = opts.getParcelable(EXTRA_THUMBNAIL_SIZE);
421ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey            return openDocumentThumbnail(getDocumentId(uri), sizeHint, null);
422aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey        } else {
423aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey            return super.openTypedAssetFile(uri, mimeTypeFilter, opts);
424aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey        }
425aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    }
426aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey
427ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey    /**
428ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     * Implementation is provided by the parent class.
429ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     *
430ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     * @see #openDocumentThumbnail(String, Point, CancellationSignal)
431ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey     */
432aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    @Override
433aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    public final AssetFileDescriptor openTypedAssetFile(
434aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey            Uri uri, String mimeTypeFilter, Bundle opts, CancellationSignal signal)
435aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey            throws FileNotFoundException {
436aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey        if (opts != null && opts.containsKey(EXTRA_THUMBNAIL_SIZE)) {
437aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey            final Point sizeHint = opts.getParcelable(EXTRA_THUMBNAIL_SIZE);
438ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkey            return openDocumentThumbnail(getDocumentId(uri), sizeHint, signal);
439aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey        } else {
440aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey            return super.openTypedAssetFile(uri, mimeTypeFilter, opts, signal);
441aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey        }
442aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    }
443aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey}
444