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