summaryrefslogtreecommitdiffstats
path: root/packages/ExternalStorageProvider
diff options
context:
space:
mode:
authorJeff Sharkey <jsharkey@android.com>2013-08-29 04:27:02 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2013-08-29 04:27:02 +0000
commit9fd81a9008d5c8dd33272b6a451d89fa2fa1841e (patch)
tree972eb1e03b7baf79f25363cb55954aaa1e216eea /packages/ExternalStorageProvider
parent166853e6c90abe84c556a574589419f576c5e986 (diff)
parentaeb16e2435f9975b9fa1fc4b747796647a21292e (diff)
downloadframeworks_base-9fd81a9008d5c8dd33272b6a451d89fa2fa1841e.zip
frameworks_base-9fd81a9008d5c8dd33272b6a451d89fa2fa1841e.tar.gz
frameworks_base-9fd81a9008d5c8dd33272b6a451d89fa2fa1841e.tar.bz2
Merge "Stronger DocumentsProvider contract." into klp-dev
Diffstat (limited to 'packages/ExternalStorageProvider')
-rw-r--r--packages/ExternalStorageProvider/AndroidManifest.xml13
-rw-r--r--packages/ExternalStorageProvider/src/com/android/externalstorage/CloudTestDocumentsProvider.java253
-rw-r--r--packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java473
3 files changed, 186 insertions, 553 deletions
diff --git a/packages/ExternalStorageProvider/AndroidManifest.xml b/packages/ExternalStorageProvider/AndroidManifest.xml
index 8bd2a6d..5272166 100644
--- a/packages/ExternalStorageProvider/AndroidManifest.xml
+++ b/packages/ExternalStorageProvider/AndroidManifest.xml
@@ -15,18 +15,5 @@
android:name="android.content.DOCUMENT_PROVIDER"
android:resource="@xml/document_provider" />
</provider>
-
- <!-- TODO: remove when we have real providers -->
- <provider
- android:name=".CloudTestDocumentsProvider"
- android:authorities="com.android.externalstorage.cloudtest"
- android:grantUriPermissions="true"
- android:exported="true"
- android:enabled="false"
- android:permission="android.permission.MANAGE_DOCUMENTS">
- <meta-data
- android:name="android.content.DOCUMENT_PROVIDER"
- android:resource="@xml/document_provider" />
- </provider>
</application>
</manifest>
diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/CloudTestDocumentsProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/CloudTestDocumentsProvider.java
deleted file mode 100644
index 119d92e..0000000
--- a/packages/ExternalStorageProvider/src/com/android/externalstorage/CloudTestDocumentsProvider.java
+++ /dev/null
@@ -1,253 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.externalstorage;
-
-import android.content.ContentProvider;
-import android.content.ContentValues;
-import android.content.UriMatcher;
-import android.database.Cursor;
-import android.database.MatrixCursor;
-import android.database.MatrixCursor.RowBuilder;
-import android.net.Uri;
-import android.os.AsyncTask;
-import android.os.Bundle;
-import android.os.ParcelFileDescriptor;
-import android.os.SystemClock;
-import android.provider.DocumentsContract;
-import android.provider.DocumentsContract.DocumentColumns;
-import android.provider.DocumentsContract.Documents;
-import android.provider.DocumentsContract.RootColumns;
-import android.provider.DocumentsContract.Roots;
-import android.util.Log;
-
-import com.google.android.collect.Lists;
-
-import libcore.io.IoUtils;
-
-import java.io.FileNotFoundException;
-import java.util.List;
-
-public class CloudTestDocumentsProvider extends ContentProvider {
- private static final String TAG = "CloudTest";
-
- private static final String AUTHORITY = "com.android.externalstorage.cloudtest";
-
- private static final UriMatcher sMatcher = new UriMatcher(UriMatcher.NO_MATCH);
-
- private static final int URI_ROOTS = 1;
- private static final int URI_ROOTS_ID = 2;
- private static final int URI_DOCS_ID = 3;
- private static final int URI_DOCS_ID_CONTENTS = 4;
- private static final int URI_DOCS_ID_SEARCH = 5;
-
- static {
- sMatcher.addURI(AUTHORITY, "roots", URI_ROOTS);
- sMatcher.addURI(AUTHORITY, "roots/*", URI_ROOTS_ID);
- sMatcher.addURI(AUTHORITY, "roots/*/docs/*", URI_DOCS_ID);
- sMatcher.addURI(AUTHORITY, "roots/*/docs/*/contents", URI_DOCS_ID_CONTENTS);
- sMatcher.addURI(AUTHORITY, "roots/*/docs/*/search", URI_DOCS_ID_SEARCH);
- }
-
- private static final String[] ALL_ROOTS_COLUMNS = new String[] {
- RootColumns.ROOT_ID, RootColumns.ROOT_TYPE, RootColumns.ICON, RootColumns.TITLE,
- RootColumns.SUMMARY, RootColumns.AVAILABLE_BYTES
- };
-
- private static final String[] ALL_DOCUMENTS_COLUMNS = new String[] {
- DocumentColumns.DOC_ID, DocumentColumns.DISPLAY_NAME, DocumentColumns.SIZE,
- DocumentColumns.MIME_TYPE, DocumentColumns.LAST_MODIFIED, DocumentColumns.FLAGS
- };
-
- private List<String> mKnownDocs = Lists.newArrayList("meow.png", "kittens.pdf");
-
- private int mPage;
-
- @Override
- public boolean onCreate() {
- return true;
- }
-
- @Override
- public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
- String sortOrder) {
- switch (sMatcher.match(uri)) {
- case URI_ROOTS: {
- final MatrixCursor result = new MatrixCursor(
- projection != null ? projection : ALL_ROOTS_COLUMNS);
- includeDefaultRoot(result);
- return result;
- }
- case URI_ROOTS_ID: {
- final MatrixCursor result = new MatrixCursor(
- projection != null ? projection : ALL_ROOTS_COLUMNS);
- includeDefaultRoot(result);
- return result;
- }
- case URI_DOCS_ID: {
- final String docId = DocumentsContract.getDocId(uri);
- final MatrixCursor result = new MatrixCursor(
- projection != null ? projection : ALL_DOCUMENTS_COLUMNS);
- includeDoc(result, docId);
- return result;
- }
- case URI_DOCS_ID_CONTENTS: {
- final CloudCursor result = new CloudCursor(
- projection != null ? projection : ALL_DOCUMENTS_COLUMNS, uri);
- for (String docId : mKnownDocs) {
- includeDoc(result, docId);
- }
- if (mPage < 3) {
- result.setHasMore();
- }
- result.setNotificationUri(getContext().getContentResolver(), uri);
- return result;
- }
- default: {
- throw new UnsupportedOperationException("Unsupported Uri " + uri);
- }
- }
- }
-
- private void includeDefaultRoot(MatrixCursor result) {
- final RowBuilder row = result.newRow();
- row.offer(RootColumns.ROOT_ID, "testroot");
- row.offer(RootColumns.ROOT_TYPE, Roots.ROOT_TYPE_SERVICE);
- row.offer(RootColumns.TITLE, "_TestTitle");
- row.offer(RootColumns.SUMMARY, "_TestSummary");
- }
-
- private void includeDoc(MatrixCursor result, String docId) {
- int flags = 0;
-
- final String mimeType;
- if (Documents.DOC_ID_ROOT.equals(docId)) {
- mimeType = Documents.MIME_TYPE_DIR;
- } else {
- mimeType = "application/octet-stream";
- }
-
- final RowBuilder row = result.newRow();
- row.offer(DocumentColumns.DOC_ID, docId);
- row.offer(DocumentColumns.DISPLAY_NAME, docId);
- row.offer(DocumentColumns.MIME_TYPE, mimeType);
- row.offer(DocumentColumns.LAST_MODIFIED, System.currentTimeMillis());
- row.offer(DocumentColumns.FLAGS, flags);
- }
-
- private class CloudCursor extends MatrixCursor {
- private final Uri mUri;
- private Bundle mExtras = new Bundle();
-
- public CloudCursor(String[] columnNames, Uri uri) {
- super(columnNames);
- mUri = uri;
- }
-
- public void setHasMore() {
- mExtras.putBoolean(DocumentsContract.EXTRA_HAS_MORE, true);
- }
-
- @Override
- public Bundle getExtras() {
- Log.d(TAG, "getExtras() " + mExtras);
- return mExtras;
- }
-
- @Override
- public Bundle respond(Bundle extras) {
- extras.size();
- Log.d(TAG, "respond() " + extras);
- if (extras.getBoolean(DocumentsContract.EXTRA_REQUEST_MORE, false)) {
- new CloudTask().execute(mUri);
- }
- return Bundle.EMPTY;
- }
- }
-
- private class CloudTask extends AsyncTask<Uri, Void, Void> {
- @Override
- protected Void doInBackground(Uri... uris) {
- final Uri uri = uris[0];
-
- SystemClock.sleep(1000);
-
- // Grab some files from the cloud
- for (int i = 0; i < 5; i++) {
- mKnownDocs.add("cloud-page" + mPage + "-file" + i);
- }
- mPage++;
-
- Log.d(TAG, "Loaded more; notifying " + uri);
- getContext().getContentResolver().notifyChange(uri, null, false);
- return null;
- }
- }
-
- private interface TypeQuery {
- final String[] PROJECTION = {
- DocumentColumns.MIME_TYPE };
-
- final int MIME_TYPE = 0;
- }
-
- @Override
- public String getType(Uri uri) {
- switch (sMatcher.match(uri)) {
- case URI_ROOTS: {
- return Roots.MIME_TYPE_DIR;
- }
- case URI_ROOTS_ID: {
- return Roots.MIME_TYPE_ITEM;
- }
- case URI_DOCS_ID: {
- final Cursor cursor = query(uri, TypeQuery.PROJECTION, null, null, null);
- try {
- if (cursor.moveToFirst()) {
- return cursor.getString(TypeQuery.MIME_TYPE);
- } else {
- return null;
- }
- } finally {
- IoUtils.closeQuietly(cursor);
- }
- }
- default: {
- throw new UnsupportedOperationException("Unsupported Uri " + uri);
- }
- }
- }
-
- @Override
- public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
- throw new UnsupportedOperationException("Unsupported Uri " + uri);
- }
-
- @Override
- public Uri insert(Uri uri, ContentValues values) {
- throw new UnsupportedOperationException("Unsupported Uri " + uri);
- }
-
- @Override
- public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
- throw new UnsupportedOperationException("Unsupported Uri " + uri);
- }
-
- @Override
- public int delete(Uri uri, String selection, String[] selectionArgs) {
- throw new UnsupportedOperationException("Unsupported Uri " + uri);
- }
-}
diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
index 8843e19..583ecc9 100644
--- a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
+++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
@@ -16,205 +16,130 @@
package com.android.externalstorage;
-import android.content.ContentProvider;
import android.content.ContentResolver;
-import android.content.ContentValues;
-import android.content.UriMatcher;
import android.content.res.AssetFileDescriptor;
import android.database.Cursor;
import android.database.MatrixCursor;
import android.database.MatrixCursor.RowBuilder;
+import android.graphics.Point;
import android.media.ExifInterface;
-import android.net.Uri;
-import android.os.Bundle;
+import android.os.CancellationSignal;
import android.os.Environment;
import android.os.ParcelFileDescriptor;
-import android.provider.DocumentsContract;
import android.provider.DocumentsContract.DocumentColumns;
+import android.provider.DocumentsContract.DocumentRoot;
import android.provider.DocumentsContract.Documents;
-import android.provider.DocumentsContract.RootColumns;
-import android.provider.DocumentsContract.Roots;
-import android.util.Log;
+import android.provider.DocumentsProvider;
import android.webkit.MimeTypeMap;
+import com.google.android.collect.Lists;
import com.google.android.collect.Maps;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
-public class ExternalStorageProvider extends ContentProvider {
+public class ExternalStorageProvider extends DocumentsProvider {
private static final String TAG = "ExternalStorage";
- private static final String AUTHORITY = "com.android.externalstorage.documents";
+ // docId format: root:path/to/file
- // TODO: support multiple storage devices
-
- private static final UriMatcher sMatcher = new UriMatcher(UriMatcher.NO_MATCH);
-
- private static final int URI_ROOTS = 1;
- private static final int URI_ROOTS_ID = 2;
- private static final int URI_DOCS_ID = 3;
- private static final int URI_DOCS_ID_CONTENTS = 4;
- private static final int URI_DOCS_ID_SEARCH = 5;
-
- static {
- sMatcher.addURI(AUTHORITY, "roots", URI_ROOTS);
- sMatcher.addURI(AUTHORITY, "roots/*", URI_ROOTS_ID);
- sMatcher.addURI(AUTHORITY, "roots/*/docs/*", URI_DOCS_ID);
- sMatcher.addURI(AUTHORITY, "roots/*/docs/*/contents", URI_DOCS_ID_CONTENTS);
- sMatcher.addURI(AUTHORITY, "roots/*/docs/*/search", URI_DOCS_ID_SEARCH);
- }
-
- private HashMap<String, Root> mRoots = Maps.newHashMap();
-
- private static class Root {
- public int rootType;
- public String name;
- public int icon = 0;
- public String title = null;
- public String summary = null;
- public File path;
- }
-
- private static final String[] ALL_ROOTS_COLUMNS = new String[] {
- RootColumns.ROOT_ID, RootColumns.ROOT_TYPE, RootColumns.ICON, RootColumns.TITLE,
- RootColumns.SUMMARY, RootColumns.AVAILABLE_BYTES
- };
-
- private static final String[] ALL_DOCUMENTS_COLUMNS = new String[] {
+ private static final String[] SUPPORTED_COLUMNS = new String[] {
DocumentColumns.DOC_ID, DocumentColumns.DISPLAY_NAME, DocumentColumns.SIZE,
DocumentColumns.MIME_TYPE, DocumentColumns.LAST_MODIFIED, DocumentColumns.FLAGS
};
+ private ArrayList<DocumentRoot> mRoots;
+ private HashMap<String, DocumentRoot> mTagToRoot;
+ private HashMap<String, File> mTagToPath;
+
@Override
public boolean onCreate() {
- mRoots.clear();
-
- final Root root = new Root();
- root.rootType = Roots.ROOT_TYPE_DEVICE_ADVANCED;
- root.name = "primary";
- root.title = getContext().getString(R.string.root_internal_storage);
- root.path = Environment.getExternalStorageDirectory();
- mRoots.put(root.name, root);
+ mRoots = Lists.newArrayList();
+ mTagToRoot = Maps.newHashMap();
+ mTagToPath = Maps.newHashMap();
+
+ // TODO: support multiple storage devices
+
+ try {
+ final String tag = "primary";
+ final File path = Environment.getExternalStorageDirectory();
+ mTagToPath.put(tag, path);
+
+ final DocumentRoot root = new DocumentRoot();
+ root.docId = getDocIdForFile(path);
+ root.rootType = DocumentRoot.ROOT_TYPE_DEVICE_ADVANCED;
+ root.title = getContext().getString(R.string.root_internal_storage);
+ root.icon = R.drawable.ic_pdf;
+ root.flags = DocumentRoot.FLAG_LOCAL_ONLY;
+ mRoots.add(root);
+ mTagToRoot.put(tag, root);
+ } catch (FileNotFoundException e) {
+ throw new IllegalStateException(e);
+ }
return true;
}
- @Override
- public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
- String sortOrder) {
- switch (sMatcher.match(uri)) {
- case URI_ROOTS: {
- final MatrixCursor result = new MatrixCursor(
- projection != null ? projection : ALL_ROOTS_COLUMNS);
- for (Root root : mRoots.values()) {
- includeRoot(result, root);
- }
- return result;
- }
- case URI_ROOTS_ID: {
- final Root root = mRoots.get(DocumentsContract.getRootId(uri));
+ private String getDocIdForFile(File file) throws FileNotFoundException {
+ String path = file.getAbsolutePath();
- final MatrixCursor result = new MatrixCursor(
- projection != null ? projection : ALL_ROOTS_COLUMNS);
- includeRoot(result, root);
- return result;
+ // Find the most-specific root path
+ Map.Entry<String, File> mostSpecific = null;
+ for (Map.Entry<String, File> root : mTagToPath.entrySet()) {
+ final String rootPath = root.getValue().getPath();
+ if (path.startsWith(rootPath) && (mostSpecific == null
+ || rootPath.length() > mostSpecific.getValue().getPath().length())) {
+ mostSpecific = root;
}
- case URI_DOCS_ID: {
- final Root root = mRoots.get(DocumentsContract.getRootId(uri));
- final String docId = DocumentsContract.getDocId(uri);
-
- final MatrixCursor result = new MatrixCursor(
- projection != null ? projection : ALL_DOCUMENTS_COLUMNS);
- final File file = docIdToFile(root, docId);
- includeFile(result, root, file);
- return result;
- }
- case URI_DOCS_ID_CONTENTS: {
- final Root root = mRoots.get(DocumentsContract.getRootId(uri));
- final String docId = DocumentsContract.getDocId(uri);
-
- final MatrixCursor result = new MatrixCursor(
- projection != null ? projection : ALL_DOCUMENTS_COLUMNS);
- final File parent = docIdToFile(root, docId);
-
- for (File file : parent.listFiles()) {
- includeFile(result, root, file);
- }
+ }
- return result;
- }
- case URI_DOCS_ID_SEARCH: {
- final Root root = mRoots.get(DocumentsContract.getRootId(uri));
- final String docId = DocumentsContract.getDocId(uri);
- final String query = DocumentsContract.getSearchQuery(uri).toLowerCase();
-
- final MatrixCursor result = new MatrixCursor(
- projection != null ? projection : ALL_DOCUMENTS_COLUMNS);
- final File parent = docIdToFile(root, docId);
-
- final LinkedList<File> pending = new LinkedList<File>();
- pending.add(parent);
- while (!pending.isEmpty() && result.getCount() < 20) {
- final File file = pending.removeFirst();
- if (file.isDirectory()) {
- for (File child : file.listFiles()) {
- pending.add(child);
- }
- } else {
- if (file.getName().toLowerCase().contains(query)) {
- includeFile(result, root, file);
- }
- }
- }
+ if (mostSpecific == null) {
+ throw new FileNotFoundException("Failed to find root that contains " + path);
+ }
- return result;
- }
- default: {
- throw new UnsupportedOperationException("Unsupported Uri " + uri);
- }
+ // Start at first char of path under root
+ final String rootPath = mostSpecific.getValue().getPath();
+ if (rootPath.equals(path)) {
+ path = "";
+ } else if (rootPath.endsWith("/")) {
+ path = path.substring(rootPath.length());
+ } else {
+ path = path.substring(rootPath.length() + 1);
}
+
+ return mostSpecific.getKey() + ':' + path;
}
- private String fileToDocId(Root root, File file) {
- String rootPath = root.path.getAbsolutePath();
- final String path = file.getAbsolutePath();
- if (path.equals(rootPath)) {
- return Documents.DOC_ID_ROOT;
- }
+ private File getFileForDocId(String docId) throws FileNotFoundException {
+ final int splitIndex = docId.indexOf(':', 1);
+ final String tag = docId.substring(0, splitIndex);
+ final String path = docId.substring(splitIndex + 1);
- if (!rootPath.endsWith("/")) {
- rootPath += "/";
+ File target = mTagToPath.get(tag);
+ if (target == null) {
+ throw new FileNotFoundException("No root for " + tag);
}
- if (!path.startsWith(rootPath)) {
- throw new IllegalArgumentException("File " + path + " outside root " + root.path);
- } else {
- return path.substring(rootPath.length());
+ target = new File(target, path);
+ if (!target.exists()) {
+ throw new FileNotFoundException("Missing file for " + docId + " at " + target);
}
+ return target;
}
- private File docIdToFile(Root root, String docId) {
- if (Documents.DOC_ID_ROOT.equals(docId)) {
- return root.path;
+ private void includeFile(MatrixCursor result, String docId, File file)
+ throws FileNotFoundException {
+ if (docId == null) {
+ docId = getDocIdForFile(file);
} else {
- return new File(root.path, docId);
+ file = getFileForDocId(docId);
}
- }
- private void includeRoot(MatrixCursor result, Root root) {
- final RowBuilder row = result.newRow();
- row.offer(RootColumns.ROOT_ID, root.name);
- row.offer(RootColumns.ROOT_TYPE, root.rootType);
- row.offer(RootColumns.ICON, root.icon);
- row.offer(RootColumns.TITLE, root.title);
- row.offer(RootColumns.SUMMARY, root.summary);
- row.offer(RootColumns.AVAILABLE_BYTES, root.path.getFreeSpace());
- }
-
- private void includeFile(MatrixCursor result, Root root, File file) {
int flags = 0;
if (file.isDirectory()) {
@@ -229,19 +154,12 @@ public class ExternalStorageProvider extends ContentProvider {
flags |= Documents.FLAG_SUPPORTS_DELETE;
}
+ final String displayName = file.getName();
final String mimeType = getTypeForFile(file);
if (mimeType.startsWith("image/")) {
flags |= Documents.FLAG_SUPPORTS_THUMBNAIL;
}
- final String docId = fileToDocId(root, file);
- final String displayName;
- if (Documents.DOC_ID_ROOT.equals(docId)) {
- displayName = root.title;
- } else {
- displayName = file.getName();
- }
-
final RowBuilder row = result.newRow();
row.offer(DocumentColumns.DOC_ID, docId);
row.offer(DocumentColumns.DISPLAY_NAME, displayName);
@@ -252,169 +170,150 @@ public class ExternalStorageProvider extends ContentProvider {
}
@Override
- public String getType(Uri uri) {
- switch (sMatcher.match(uri)) {
- case URI_ROOTS: {
- return Roots.MIME_TYPE_DIR;
- }
- case URI_ROOTS_ID: {
- return Roots.MIME_TYPE_ITEM;
- }
- case URI_DOCS_ID: {
- final Root root = mRoots.get(DocumentsContract.getRootId(uri));
- final String docId = DocumentsContract.getDocId(uri);
- return getTypeForFile(docIdToFile(root, docId));
- }
- default: {
- throw new UnsupportedOperationException("Unsupported Uri " + uri);
- }
+ public List<DocumentRoot> getDocumentRoots() {
+ // Update free space
+ for (String tag : mTagToRoot.keySet()) {
+ final DocumentRoot root = mTagToRoot.get(tag);
+ final File path = mTagToPath.get(tag);
+ root.availableBytes = path.getFreeSpace();
}
+ return mRoots;
}
- private String getTypeForFile(File file) {
- if (file.isDirectory()) {
- return Documents.MIME_TYPE_DIR;
+ @Override
+ public String createDocument(String docId, String mimeType, String displayName)
+ throws FileNotFoundException {
+ final File parent = getFileForDocId(docId);
+ displayName = validateDisplayName(mimeType, displayName);
+
+ final File file = new File(parent, displayName);
+ if (Documents.MIME_TYPE_DIR.equals(mimeType)) {
+ if (!file.mkdir()) {
+ throw new IllegalStateException("Failed to mkdir " + file);
+ }
} else {
- return getTypeForName(file.getName());
+ try {
+ if (!file.createNewFile()) {
+ throw new IllegalStateException("Failed to touch " + file);
+ }
+ } catch (IOException e) {
+ throw new IllegalStateException("Failed to touch " + file + ": " + e);
+ }
}
+ return getDocIdForFile(file);
}
- private String getTypeForName(String name) {
- final int lastDot = name.lastIndexOf('.');
- if (lastDot >= 0) {
- final String extension = name.substring(lastDot + 1);
- final String mime = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
- if (mime != null) {
- return mime;
- }
+ @Override
+ public void renameDocument(String docId, String displayName) throws FileNotFoundException {
+ final File file = getFileForDocId(docId);
+ final File newFile = new File(file.getParentFile(), displayName);
+ if (!file.renameTo(newFile)) {
+ throw new IllegalStateException("Failed to rename " + docId);
}
-
- return "application/octet-stream";
+ // TODO: update any outstanding grants
}
@Override
- public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
- switch (sMatcher.match(uri)) {
- case URI_DOCS_ID: {
- final Root root = mRoots.get(DocumentsContract.getRootId(uri));
- final String docId = DocumentsContract.getDocId(uri);
-
- final File file = docIdToFile(root, docId);
- return ParcelFileDescriptor.open(file, ContentResolver.modeToMode(uri, mode));
- }
- default: {
- throw new UnsupportedOperationException("Unsupported Uri " + uri);
- }
+ public void deleteDocument(String docId) throws FileNotFoundException {
+ final File file = getFileForDocId(docId);
+ if (!file.delete()) {
+ throw new IllegalStateException("Failed to delete " + file);
}
}
@Override
- public AssetFileDescriptor openTypedAssetFile(Uri uri, String mimeTypeFilter, Bundle opts)
- throws FileNotFoundException {
- if (opts == null || !opts.containsKey(DocumentsContract.EXTRA_THUMBNAIL_SIZE)) {
- return super.openTypedAssetFile(uri, mimeTypeFilter, opts);
+ public Cursor queryDocument(String docId) throws FileNotFoundException {
+ final MatrixCursor result = new MatrixCursor(SUPPORTED_COLUMNS);
+ includeFile(result, docId, null);
+ return result;
+ }
+
+ @Override
+ public Cursor queryDocumentChildren(String docId) throws FileNotFoundException {
+ final MatrixCursor result = new MatrixCursor(SUPPORTED_COLUMNS);
+ final File parent = getFileForDocId(docId);
+ for (File file : parent.listFiles()) {
+ includeFile(result, null, file);
}
+ return result;
+ }
- switch (sMatcher.match(uri)) {
- case URI_DOCS_ID: {
- final Root root = mRoots.get(DocumentsContract.getRootId(uri));
- final String docId = DocumentsContract.getDocId(uri);
-
- final File file = docIdToFile(root, docId);
- final ParcelFileDescriptor pfd = ParcelFileDescriptor.open(
- file, ParcelFileDescriptor.MODE_READ_ONLY);
-
- try {
- final ExifInterface exif = new ExifInterface(file.getAbsolutePath());
- final long[] thumb = exif.getThumbnailRange();
- if (thumb != null) {
- return new AssetFileDescriptor(pfd, thumb[0], thumb[1]);
- }
- } catch (IOException e) {
+ @Override
+ public Cursor querySearch(String docId, String query) throws FileNotFoundException {
+ final MatrixCursor result = new MatrixCursor(SUPPORTED_COLUMNS);
+ final File parent = getFileForDocId(docId);
+
+ final LinkedList<File> pending = new LinkedList<File>();
+ pending.add(parent);
+ while (!pending.isEmpty() && result.getCount() < 20) {
+ final File file = pending.removeFirst();
+ if (file.isDirectory()) {
+ for (File child : file.listFiles()) {
+ pending.add(child);
+ }
+ } else {
+ if (file.getName().toLowerCase().contains(query)) {
+ includeFile(result, null, file);
}
-
- return new AssetFileDescriptor(pfd, 0, AssetFileDescriptor.UNKNOWN_LENGTH);
- }
- default: {
- throw new UnsupportedOperationException("Unsupported Uri " + uri);
}
}
+ return result;
}
@Override
- public Uri insert(Uri uri, ContentValues values) {
- switch (sMatcher.match(uri)) {
- case URI_DOCS_ID: {
- final Root root = mRoots.get(DocumentsContract.getRootId(uri));
- final String docId = DocumentsContract.getDocId(uri);
-
- final File parent = docIdToFile(root, docId);
-
- final String mimeType = values.getAsString(DocumentColumns.MIME_TYPE);
- final String name = validateDisplayName(
- values.getAsString(DocumentColumns.DISPLAY_NAME), mimeType);
-
- final File file = new File(parent, name);
- if (Documents.MIME_TYPE_DIR.equals(mimeType)) {
- if (!file.mkdir()) {
- return null;
- }
-
- } else {
- try {
- if (!file.createNewFile()) {
- return null;
- }
- } catch (IOException e) {
- Log.w(TAG, "Failed to create file", e);
- return null;
- }
- }
+ public String getType(String docId) throws FileNotFoundException {
+ final File file = getFileForDocId(docId);
+ return getTypeForFile(file);
+ }
- final String newDocId = fileToDocId(root, file);
- return DocumentsContract.buildDocumentUri(AUTHORITY, root.name, newDocId);
- }
- default: {
- throw new UnsupportedOperationException("Unsupported Uri " + uri);
- }
- }
+ @Override
+ public ParcelFileDescriptor openDocument(String docId, String mode, CancellationSignal signal)
+ throws FileNotFoundException {
+ final File file = getFileForDocId(docId);
+ return ParcelFileDescriptor.open(file, ContentResolver.modeToMode(null, mode));
}
@Override
- public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
- switch (sMatcher.match(uri)) {
- case URI_DOCS_ID: {
- final Root root = mRoots.get(DocumentsContract.getRootId(uri));
- final String docId = DocumentsContract.getDocId(uri);
-
- final File file = docIdToFile(root, docId);
- final File newFile = new File(
- file.getParentFile(), values.getAsString(DocumentColumns.DISPLAY_NAME));
- return file.renameTo(newFile) ? 1 : 0;
- }
- default: {
- throw new UnsupportedOperationException("Unsupported Uri " + uri);
+ public AssetFileDescriptor openDocumentThumbnail(
+ String docId, Point sizeHint, CancellationSignal signal) throws FileNotFoundException {
+ final File file = getFileForDocId(docId);
+ final ParcelFileDescriptor pfd = ParcelFileDescriptor.open(
+ file, ParcelFileDescriptor.MODE_READ_ONLY);
+
+ try {
+ final ExifInterface exif = new ExifInterface(file.getAbsolutePath());
+ final long[] thumb = exif.getThumbnailRange();
+ if (thumb != null) {
+ return new AssetFileDescriptor(pfd, thumb[0], thumb[1]);
}
+ } catch (IOException e) {
}
+
+ return new AssetFileDescriptor(pfd, 0, AssetFileDescriptor.UNKNOWN_LENGTH);
}
- @Override
- public int delete(Uri uri, String selection, String[] selectionArgs) {
- switch (sMatcher.match(uri)) {
- case URI_DOCS_ID: {
- final Root root = mRoots.get(DocumentsContract.getRootId(uri));
- final String docId = DocumentsContract.getDocId(uri);
-
- final File file = docIdToFile(root, docId);
- return file.delete() ? 1 : 0;
- }
- default: {
- throw new UnsupportedOperationException("Unsupported Uri " + uri);
+ private static String getTypeForFile(File file) {
+ if (file.isDirectory()) {
+ return Documents.MIME_TYPE_DIR;
+ } else {
+ return getTypeForName(file.getName());
+ }
+ }
+
+ private static String getTypeForName(String name) {
+ final int lastDot = name.lastIndexOf('.');
+ if (lastDot >= 0) {
+ final String extension = name.substring(lastDot + 1);
+ final String mime = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
+ if (mime != null) {
+ return mime;
}
}
+
+ return "application/octet-stream";
}
- private String validateDisplayName(String displayName, String mimeType) {
+ private static String validateDisplayName(String mimeType, String displayName) {
if (Documents.MIME_TYPE_DIR.equals(mimeType)) {
return displayName;
} else {