DocumentsContract.java revision 20d96d8aff2193d548977e23ce5158657cac94e0
1/*
2 * Copyright (C) 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.provider;
18
19import android.content.ContentProvider;
20import android.content.ContentResolver;
21import android.content.ContentValues;
22import android.content.Intent;
23import android.content.pm.ProviderInfo;
24import android.content.res.AssetFileDescriptor;
25import android.database.Cursor;
26import android.graphics.Bitmap;
27import android.graphics.BitmapFactory;
28import android.graphics.Point;
29import android.net.Uri;
30import android.os.Bundle;
31import android.util.Log;
32
33import libcore.io.IoUtils;
34
35import java.io.IOException;
36import java.io.InputStream;
37
38/**
39 * The contract between a storage backend and the platform. Contains definitions
40 * for the supported URIs and columns.
41 */
42public final class DocumentsContract {
43    private static final String TAG = "Documents";
44
45    // content://com.example/roots/
46    // content://com.example/docs/0/
47    // content://com.example/docs/0/contents/
48    // content://com.example/docs/0/search/?query=pony
49
50    /**
51     * MIME type of a document which is a directory that may contain additional
52     * documents.
53     *
54     * @see #buildContentsUri(Uri)
55     */
56    public static final String MIME_TYPE_DIRECTORY = "vnd.android.cursor.dir/doc";
57
58    /** {@hide} */
59    public static final String META_DATA_DOCUMENT_PROVIDER = "android.content.DOCUMENT_PROVIDER";
60
61    /**
62     * {@link DocumentColumns#GUID} value representing the root directory of a
63     * storage backend.
64     */
65    public static final String ROOT_GUID = "0";
66
67    /**
68     * Flag indicating that a document is a directory that supports creation of
69     * new files within it.
70     *
71     * @see DocumentColumns#FLAGS
72     * @see #buildContentsUri(Uri)
73     */
74    public static final int FLAG_SUPPORTS_CREATE = 1;
75
76    /**
77     * Flag indicating that a document is renamable.
78     *
79     * @see DocumentColumns#FLAGS
80     * @see #renameDocument(ContentResolver, Uri, String)
81     */
82    public static final int FLAG_SUPPORTS_RENAME = 1 << 1;
83
84    /**
85     * Flag indicating that a document is deletable.
86     *
87     * @see DocumentColumns#FLAGS
88     */
89    public static final int FLAG_SUPPORTS_DELETE = 1 << 2;
90
91    /**
92     * Flag indicating that a document can be represented as a thumbnail.
93     *
94     * @see DocumentColumns#FLAGS
95     * @see #getThumbnail(ContentResolver, Uri, Point)
96     */
97    public static final int FLAG_SUPPORTS_THUMBNAIL = 1 << 3;
98
99    /**
100     * Flag indicating that a document is a directory that supports search.
101     *
102     * @see DocumentColumns#FLAGS
103     */
104    public static final int FLAG_SUPPORTS_SEARCH = 1 << 4;
105
106    /**
107     * Optimal dimensions for a document thumbnail request, stored as a
108     * {@link Point} object. This is only a hint, and the returned thumbnail may
109     * have different dimensions.
110     *
111     * @see ContentProvider#openTypedAssetFile(Uri, String, Bundle)
112     */
113    public static final String EXTRA_THUMBNAIL_SIZE = "thumbnail_size";
114
115    /**
116     * Extra boolean flag included in a directory {@link Cursor#getExtras()}
117     * indicating that the backend can provide additional data if requested,
118     * such as additional search results.
119     */
120    public static final String EXTRA_HAS_MORE = "has_more";
121
122    /**
123     * Extra boolean flag included in a {@link Cursor#respond(Bundle)} call to a
124     * directory to request that additional data should be fetched. When
125     * requested data is ready, the provider should send a change notification
126     * to cause a requery.
127     *
128     * @see Cursor#respond(Bundle)
129     * @see ContentResolver#notifyChange(Uri, android.database.ContentObserver,
130     *      boolean)
131     */
132    public static final String EXTRA_REQUEST_MORE = "request_more";
133
134    private static final String PATH_ROOTS = "roots";
135    private static final String PATH_DOCS = "docs";
136    private static final String PATH_CONTENTS = "contents";
137    private static final String PATH_SEARCH = "search";
138
139    public static final String PARAM_QUERY = "query";
140
141    /**
142     * Build URI representing the custom roots in a storage backend.
143     */
144    public static Uri buildRootsUri(String authority) {
145        return new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT)
146                .authority(authority).appendPath(PATH_ROOTS).build();
147    }
148
149    /**
150     * Build URI representing the given {@link DocumentColumns#GUID} in a
151     * storage backend.
152     */
153    public static Uri buildDocumentUri(String authority, String guid) {
154        return new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT)
155                .authority(authority).appendPath(PATH_DOCS).appendPath(guid).build();
156    }
157
158    /**
159     * Build URI representing a search for matching documents under a directory
160     * in a storage backend.
161     *
162     * @param documentUri directory to search under, which must have
163     *            {@link #FLAG_SUPPORTS_SEARCH}.
164     */
165    public static Uri buildSearchUri(Uri documentUri, String query) {
166        return documentUri.buildUpon()
167                .appendPath(PATH_SEARCH).appendQueryParameter(PARAM_QUERY, query).build();
168    }
169
170    /**
171     * Build URI representing the contents of the given directory in a storage
172     * backend. The given document must be {@link #MIME_TYPE_DIRECTORY}.
173     */
174    public static Uri buildContentsUri(Uri documentUri) {
175        return documentUri.buildUpon().appendPath(PATH_CONTENTS).build();
176    }
177
178    /**
179     * These are standard columns for document URIs. Storage backend providers
180     * <em>must</em> support at least these columns when queried.
181     *
182     * @see Intent#ACTION_OPEN_DOCUMENT
183     * @see Intent#ACTION_CREATE_DOCUMENT
184     */
185    public interface DocumentColumns extends OpenableColumns {
186        /**
187         * The globally unique ID for a document within a storage backend.
188         * Values <em>must</em> never change once returned. This field is
189         * read-only to document clients.
190         * <p>
191         * Type: STRING
192         *
193         * @see DocumentsContract#ROOT_GUID
194         */
195        public static final String GUID = "guid";
196
197        /**
198         * MIME type of a document, matching the value returned by
199         * {@link ContentResolver#getType(android.net.Uri)}. This field must be
200         * provided when a new document is created, but after that the field is
201         * read-only.
202         * <p>
203         * Type: STRING
204         *
205         * @see DocumentsContract#MIME_TYPE_DIRECTORY
206         */
207        public static final String MIME_TYPE = "mime_type";
208
209        /**
210         * Timestamp when a document was last modified, in milliseconds since
211         * January 1, 1970 00:00:00.0 UTC. This field is read-only to document
212         * clients.
213         * <p>
214         * Type: INTEGER (long)
215         *
216         * @see System#currentTimeMillis()
217         */
218        public static final String LAST_MODIFIED = "last_modified";
219
220        /**
221         * Flags that apply to a specific document. This field is read-only to
222         * document clients.
223         * <p>
224         * Type: INTEGER (int)
225         */
226        public static final String FLAGS = "flags";
227    }
228
229    public static final int ROOT_TYPE_SERVICE = 1;
230    public static final int ROOT_TYPE_SHORTCUT = 2;
231    public static final int ROOT_TYPE_DEVICE = 3;
232    public static final int ROOT_TYPE_DEVICE_ADVANCED = 4;
233
234    /**
235     * These are standard columns for the roots URI.
236     *
237     * @see DocumentsContract#buildRootsUri(String)
238     */
239    public interface RootColumns {
240        /**
241         * Storage root type, use for clustering.
242         * <p>
243         * Type: INTEGER (int)
244         *
245         * @see DocumentsContract#ROOT_TYPE_SERVICE
246         * @see DocumentsContract#ROOT_TYPE_DEVICE
247         */
248        public static final String ROOT_TYPE = "root_type";
249
250        /**
251         * GUID of directory entry for this storage root.
252         * <p>
253         * Type: STRING
254         */
255        public static final String GUID = "guid";
256
257        /**
258         * Icon resource ID for this storage root, or {@code 0} to use the
259         * default {@link ProviderInfo#icon}.
260         * <p>
261         * Type: INTEGER (int)
262         */
263        public static final String ICON = "icon";
264
265        /**
266         * Title for this storage root, or {@code null} to use the default
267         * {@link ProviderInfo#labelRes}.
268         * <p>
269         * Type: STRING
270         */
271        public static final String TITLE = "title";
272
273        /**
274         * Summary for this storage root, or {@code null} to omit.
275         * <p>
276         * Type: STRING
277         */
278        public static final String SUMMARY = "summary";
279
280        /**
281         * Number of free bytes of available in this storage root, or -1 if
282         * unknown or unbounded.
283         * <p>
284         * Type: INTEGER (long)
285         */
286        public static final String AVAILABLE_BYTES = "available_bytes";
287    }
288
289    /**
290     * Return thumbnail representing the document at the given URI. Callers are
291     * responsible for their own caching. Given document must have
292     * {@link #FLAG_SUPPORTS_THUMBNAIL} set.
293     *
294     * @return decoded thumbnail, or {@code null} if problem was encountered.
295     */
296    public static Bitmap getThumbnail(ContentResolver resolver, Uri documentUri, Point size) {
297        final Bundle opts = new Bundle();
298        opts.putParcelable(EXTRA_THUMBNAIL_SIZE, size);
299
300        InputStream is = null;
301        try {
302            is = new AssetFileDescriptor.AutoCloseInputStream(
303                    resolver.openTypedAssetFileDescriptor(documentUri, "image/*", opts));
304            return BitmapFactory.decodeStream(is);
305        } catch (IOException e) {
306            Log.w(TAG, "Failed to load thumbnail for " + documentUri + ": " + e);
307            return null;
308        } finally {
309            IoUtils.closeQuietly(is);
310        }
311    }
312
313    /**
314     * Rename the document at the given URI. Given document must have
315     * {@link #FLAG_SUPPORTS_RENAME} set.
316     *
317     * @return if rename was successful.
318     */
319    public static boolean renameDocument(
320            ContentResolver resolver, Uri documentUri, String displayName) {
321        final ContentValues values = new ContentValues();
322        values.put(DocumentColumns.DISPLAY_NAME, displayName);
323        return (resolver.update(documentUri, values, null, null) == 1);
324    }
325}
326