diff options
author | Garfield Tan <xutan@google.com> | 2017-02-08 15:32:56 -0800 |
---|---|---|
committer | Garfield Tan <xutan@google.com> | 2017-02-24 18:30:03 -0800 |
commit | 75379db42dcd7c5081aed8a90b7d6077b637ffe0 (patch) | |
tree | b63a54367a44a796141bcb91c1a9753583172217 /packages/ExternalStorageProvider/src | |
parent | d7f52c1b7644396388b9c63a403dd9cb745d91f0 (diff) |
Strip out some logics from ESP to FSP that DSP can use.
Also notify MediaStore when move happens.
Test: build & smoke tested.
Change-Id: I01576765c0b25089a81b77ce0904abea8b24d485
Diffstat (limited to 'packages/ExternalStorageProvider/src')
-rw-r--r-- | packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java | 382 |
1 files changed, 14 insertions, 368 deletions
diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java index 22a5b7ffd520..3cc9f65ecd85 100644 --- a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java +++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java @@ -56,6 +56,7 @@ import android.util.Pair; import android.webkit.MimeTypeMap; import com.android.internal.annotations.GuardedBy; +import com.android.internal.content.FileSystemProvider; import com.android.internal.util.IndentingPrintWriter; import java.io.File; @@ -63,15 +64,15 @@ import java.io.FileDescriptor; import java.io.FileNotFoundException; import java.io.IOException; import java.io.PrintWriter; +import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.Objects; -public class ExternalStorageProvider extends DocumentsProvider { +public class ExternalStorageProvider extends FileSystemProvider { private static final String TAG = "ExternalStorage"; private static final boolean DEBUG = false; - private static final boolean LOG_INOTIFY = false; public static final String AUTHORITY = "com.android.externalstorage.documents"; @@ -105,20 +106,17 @@ public class ExternalStorageProvider extends DocumentsProvider { private static final String ROOT_ID_HOME = "home"; private StorageManager mStorageManager; - private Handler mHandler; private final Object mRootsLock = new Object(); @GuardedBy("mRootsLock") private ArrayMap<String, RootInfo> mRoots = new ArrayMap<>(); - @GuardedBy("mObservers") - private ArrayMap<File, DirectoryObserver> mObservers = new ArrayMap<>(); - @Override public boolean onCreate() { + super.onCreate(DEFAULT_DOCUMENT_PROJECTION); + mStorageManager = (StorageManager) getContext().getSystemService(Context.STORAGE_SERVICE); - mHandler = new Handler(); updateVolumes(); return true; @@ -274,11 +272,8 @@ public class ExternalStorageProvider extends DocumentsProvider { return projection != null ? projection : DEFAULT_ROOT_PROJECTION; } - private static String[] resolveDocumentProjection(String[] projection) { - return projection != null ? projection : DEFAULT_DOCUMENT_PROJECTION; - } - - private String getDocIdForFile(File file) throws FileNotFoundException { + @Override + protected String getDocIdForFile(File file) throws FileNotFoundException { return getDocIdForFileMaybeCreate(file, false); } @@ -344,11 +339,8 @@ public class ExternalStorageProvider extends DocumentsProvider { return mostSpecificRoot; } - private File getFileForDocId(String docId) throws FileNotFoundException { - return getFileForDocId(docId, false); - } - - private File getFileForDocId(String docId, boolean visible) throws FileNotFoundException { + @Override + protected File getFileForDocId(String docId, boolean visible) throws FileNotFoundException { RootInfo root = getRootFromDocId(docId); return buildFile(root, docId, visible); } @@ -393,48 +385,9 @@ public class ExternalStorageProvider extends DocumentsProvider { return target; } - private void includeFile(MatrixCursor result, String docId, File file) - throws FileNotFoundException { - if (docId == null) { - docId = getDocIdForFile(file); - } else { - file = getFileForDocId(docId); - } - - int flags = 0; - - if (file.canWrite()) { - if (file.isDirectory()) { - flags |= Document.FLAG_DIR_SUPPORTS_CREATE; - flags |= Document.FLAG_SUPPORTS_DELETE; - flags |= Document.FLAG_SUPPORTS_RENAME; - flags |= Document.FLAG_SUPPORTS_MOVE; - } else { - flags |= Document.FLAG_SUPPORTS_WRITE; - flags |= Document.FLAG_SUPPORTS_DELETE; - flags |= Document.FLAG_SUPPORTS_RENAME; - flags |= Document.FLAG_SUPPORTS_MOVE; - } - } - - final String mimeType = getTypeForFile(file); - final String displayName = file.getName(); - if (mimeType.startsWith("image/")) { - flags |= Document.FLAG_SUPPORTS_THUMBNAIL; - } - - final RowBuilder row = result.newRow(); - row.add(Document.COLUMN_DOCUMENT_ID, docId); - row.add(Document.COLUMN_DISPLAY_NAME, displayName); - row.add(Document.COLUMN_SIZE, file.length()); - row.add(Document.COLUMN_MIME_TYPE, mimeType); - row.add(Document.COLUMN_FLAGS, flags); - - // Only publish dates reasonably after epoch - long lastModified = file.lastModified(); - if (lastModified > 31536000000L) { - row.add(Document.COLUMN_LAST_MODIFIED, lastModified); - } + @Override + protected Uri buildNotificationUri(String docId) { + return DocumentsContract.buildChildDocumentsUri(AUTHORITY, docId); } @Override @@ -455,22 +408,8 @@ public class ExternalStorageProvider extends DocumentsProvider { } @Override - public boolean isChildDocument(String parentDocId, String docId) { - try { - final File parent = getFileForDocId(parentDocId).getCanonicalFile(); - final File doc = getFileForDocId(docId).getCanonicalFile(); - return FileUtils.contains(parent, doc); - } catch (IOException e) { - throw new IllegalArgumentException( - "Failed to determine if " + docId + " is child of " + parentDocId + ": " + e); - } - } - - @Override public Path findDocumentPath(String childDocId, @Nullable String parentDocId) throws FileNotFoundException { - LinkedList<String> path = new LinkedList<>(); - final Pair<RootInfo, File> resolvedDocId = resolveDocId(childDocId, false); final RootInfo root = resolvedDocId.first; File child = resolvedDocId.second; @@ -479,49 +418,7 @@ public class ExternalStorageProvider extends DocumentsProvider { ? root.path : getFileForDocId(parentDocId); - if (!child.exists()) { - throw new FileNotFoundException(childDocId + " is not found."); - } - - if (!child.getAbsolutePath().startsWith(parent.getAbsolutePath())) { - throw new FileNotFoundException(childDocId + " is not found under " + parentDocId); - } - - while (child != null && child.getAbsolutePath().startsWith(parent.getAbsolutePath())) { - path.addFirst(getDocIdForFile(child)); - - child = child.getParentFile(); - } - - return new Path(parentDocId == null ? root.rootId : null, path); - } - - @Override - public String createDocument(String docId, String mimeType, String displayName) - throws FileNotFoundException { - displayName = FileUtils.buildValidFatFilename(displayName); - - final File parent = getFileForDocId(docId); - if (!parent.isDirectory()) { - throw new IllegalArgumentException("Parent document isn't a directory"); - } - - final File file = FileUtils.buildUniqueFile(parent, mimeType, displayName); - if (Document.MIME_TYPE_DIR.equals(mimeType)) { - if (!file.mkdir()) { - throw new IllegalStateException("Failed to mkdir " + file); - } - } else { - 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); + return new Path(parentDocId == null ? root.rootId : null, findDocumentPath(parent, child)); } private Uri getDocumentUri(String path, List<UriPermission> accessUriPermissions) @@ -587,120 +484,14 @@ public class ExternalStorageProvider extends DocumentsProvider { } @Override - public String renameDocument(String docId, String displayName) throws FileNotFoundException { - // Since this provider treats renames as generating a completely new - // docId, we're okay with letting the MIME type change. - displayName = FileUtils.buildValidFatFilename(displayName); - - final File before = getFileForDocId(docId); - final File after = FileUtils.buildUniqueFile(before.getParentFile(), displayName); - if (!before.renameTo(after)) { - throw new IllegalStateException("Failed to rename to " + after); - } - final String afterDocId = getDocIdForFile(after); - if (!TextUtils.equals(docId, afterDocId)) { - return afterDocId; - } else { - return null; - } - } - - @Override - public void deleteDocument(String docId) throws FileNotFoundException { - final File file = getFileForDocId(docId); - final File visibleFile = getFileForDocId(docId, true); - - final boolean isDirectory = file.isDirectory(); - if (isDirectory) { - FileUtils.deleteContents(file); - } - if (!file.delete()) { - throw new IllegalStateException("Failed to delete " + file); - } - - if (visibleFile != null) { - final ContentResolver resolver = getContext().getContentResolver(); - final Uri externalUri = MediaStore.Files.getContentUri("external"); - - // Remove media store entries for any files inside this directory, using - // path prefix match. Logic borrowed from MtpDatabase. - if (isDirectory) { - final String path = visibleFile.getAbsolutePath() + "/"; - resolver.delete(externalUri, - "_data LIKE ?1 AND lower(substr(_data,1,?2))=lower(?3)", - new String[] { path + "%", Integer.toString(path.length()), path }); - } - - // Remove media store entry for this exact file. - final String path = visibleFile.getAbsolutePath(); - resolver.delete(externalUri, - "_data LIKE ?1 AND lower(_data)=lower(?2)", - new String[] { path, path }); - } - } - - @Override - public String moveDocument(String sourceDocumentId, String sourceParentDocumentId, - String targetParentDocumentId) - throws FileNotFoundException { - final File before = getFileForDocId(sourceDocumentId); - final File after = new File(getFileForDocId(targetParentDocumentId), before.getName()); - - if (after.exists()) { - throw new IllegalStateException("Already exists " + after); - } - if (!before.renameTo(after)) { - throw new IllegalStateException("Failed to move to " + after); - } - return getDocIdForFile(after); - } - - @Override - public Cursor queryDocument(String documentId, String[] projection) - throws FileNotFoundException { - final MatrixCursor result = new MatrixCursor(resolveDocumentProjection(projection)); - includeFile(result, documentId, null); - return result; - } - - @Override - public Cursor queryChildDocuments( - String parentDocumentId, String[] projection, String sortOrder) - throws FileNotFoundException { - final File parent = getFileForDocId(parentDocumentId); - final MatrixCursor result = new DirectoryCursor( - resolveDocumentProjection(projection), parentDocumentId, parent); - for (File file : parent.listFiles()) { - includeFile(result, null, file); - } - return result; - } - - @Override public Cursor querySearchDocuments(String rootId, String query, String[] projection) throws FileNotFoundException { - final MatrixCursor result = new MatrixCursor(resolveDocumentProjection(projection)); - - query = query.toLowerCase(); final File parent; synchronized (mRootsLock) { parent = mRoots.get(rootId).path; } - final LinkedList<File> pending = new LinkedList<>(); - pending.add(parent); - while (!pending.isEmpty() && result.getCount() < 24) { - final File file = pending.removeFirst(); - if (file.isDirectory()) { - for (File child : file.listFiles()) { - pending.add(child); - } - } - if (file.getName().toLowerCase().contains(query)) { - includeFile(result, null, file); - } - } - return result; + return querySearchDocuments(parent, query, projection, Collections.emptySet()); } @Override @@ -722,48 +513,6 @@ public class ExternalStorageProvider extends DocumentsProvider { } @Override - public String getDocumentType(String documentId) throws FileNotFoundException { - final File file = getFileForDocId(documentId); - return getTypeForFile(file); - } - - @Override - public ParcelFileDescriptor openDocument( - String documentId, String mode, CancellationSignal signal) - throws FileNotFoundException { - final File file = getFileForDocId(documentId); - final File visibleFile = getFileForDocId(documentId, true); - - final int pfdMode = ParcelFileDescriptor.parseMode(mode); - if (pfdMode == ParcelFileDescriptor.MODE_READ_ONLY || visibleFile == null) { - return ParcelFileDescriptor.open(file, pfdMode); - } else { - try { - // When finished writing, kick off media scanner - return ParcelFileDescriptor.open(file, pfdMode, mHandler, new OnCloseListener() { - @Override - public void onClose(IOException e) { - final Intent intent = new Intent( - Intent.ACTION_MEDIA_SCANNER_SCAN_FILE); - intent.setData(Uri.fromFile(visibleFile)); - getContext().sendBroadcast(intent); - } - }); - } catch (IOException e) { - throw new FileNotFoundException("Failed to open for writing: " + e); - } - } - } - - @Override - public AssetFileDescriptor openDocumentThumbnail( - String documentId, Point sizeHint, CancellationSignal signal) - throws FileNotFoundException { - final File file = getFileForDocId(documentId); - return DocumentsContract.openImageThumbnail(file); - } - - @Override public void dump(FileDescriptor fd, PrintWriter writer, String[] args) { final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " ", 160); synchronized (mRootsLock) { @@ -826,107 +575,4 @@ public class ExternalStorageProvider extends DocumentsProvider { } return bundle; } - - private static String getTypeForFile(File file) { - if (file.isDirectory()) { - return Document.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).toLowerCase(); - final String mime = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension); - if (mime != null) { - return mime; - } - } - - return "application/octet-stream"; - } - - private void startObserving(File file, Uri notifyUri) { - synchronized (mObservers) { - DirectoryObserver observer = mObservers.get(file); - if (observer == null) { - observer = new DirectoryObserver( - file, getContext().getContentResolver(), notifyUri); - observer.startWatching(); - mObservers.put(file, observer); - } - observer.mRefCount++; - - if (LOG_INOTIFY) Log.d(TAG, "after start: " + observer); - } - } - - private void stopObserving(File file) { - synchronized (mObservers) { - DirectoryObserver observer = mObservers.get(file); - if (observer == null) return; - - observer.mRefCount--; - if (observer.mRefCount == 0) { - mObservers.remove(file); - observer.stopWatching(); - } - - if (LOG_INOTIFY) Log.d(TAG, "after stop: " + observer); - } - } - - private static class DirectoryObserver extends FileObserver { - private static final int NOTIFY_EVENTS = ATTRIB | CLOSE_WRITE | MOVED_FROM | MOVED_TO - | CREATE | DELETE | DELETE_SELF | MOVE_SELF; - - private final File mFile; - private final ContentResolver mResolver; - private final Uri mNotifyUri; - - private int mRefCount = 0; - - public DirectoryObserver(File file, ContentResolver resolver, Uri notifyUri) { - super(file.getAbsolutePath(), NOTIFY_EVENTS); - mFile = file; - mResolver = resolver; - mNotifyUri = notifyUri; - } - - @Override - public void onEvent(int event, String path) { - if ((event & NOTIFY_EVENTS) != 0) { - if (LOG_INOTIFY) Log.d(TAG, "onEvent() " + event + " at " + path); - mResolver.notifyChange(mNotifyUri, null, false); - } - } - - @Override - public String toString() { - return "DirectoryObserver{file=" + mFile.getAbsolutePath() + ", ref=" + mRefCount + "}"; - } - } - - private class DirectoryCursor extends MatrixCursor { - private final File mFile; - - public DirectoryCursor(String[] columnNames, String docId, File file) { - super(columnNames); - - final Uri notifyUri = DocumentsContract.buildChildDocumentsUri( - AUTHORITY, docId); - setNotificationUri(getContext().getContentResolver(), notifyUri); - - mFile = file; - startObserving(mFile, notifyUri); - } - - @Override - public void close() { - super.close(); - stopObserving(mFile); - } - } } |