summaryrefslogtreecommitdiffstats
path: root/packages/DocumentsUI/tests
diff options
context:
space:
mode:
authorBen Kwa <kenobi@google.com>2015-04-16 18:14:35 -0700
committerBen Kwa <kenobi@google.com>2015-04-21 15:39:12 -0700
commit448dbbbf0e66340e262a5c163ee1829121018523 (patch)
tree60490a0b18df08c398fd8954ff798ba5ea07c98a /packages/DocumentsUI/tests
parent5c1e306502a77d354def3d426dabdacea8cc4055 (diff)
downloadframeworks_base-448dbbbf0e66340e262a5c163ee1829121018523.zip
frameworks_base-448dbbbf0e66340e262a5c163ee1829121018523.tar.gz
frameworks_base-448dbbbf0e66340e262a5c163ee1829121018523.tar.bz2
Implement some tests for com.android.documentsui.CopyService.
- Add a unit test for CopyService. - Make some changes to StubProvider to make it more configurable, for testing. Change-Id: I3d726099feaf6b7a3fdd40bf2449f4ee3e848d77
Diffstat (limited to 'packages/DocumentsUI/tests')
-rw-r--r--packages/DocumentsUI/tests/Android.mk1
-rw-r--r--packages/DocumentsUI/tests/src/com/android/documentsui/CopyTest.java281
-rw-r--r--packages/DocumentsUI/tests/src/com/android/documentsui/StubProvider.java260
3 files changed, 482 insertions, 60 deletions
diff --git a/packages/DocumentsUI/tests/Android.mk b/packages/DocumentsUI/tests/Android.mk
index fdf4fab..3f191a9 100644
--- a/packages/DocumentsUI/tests/Android.mk
+++ b/packages/DocumentsUI/tests/Android.mk
@@ -7,6 +7,7 @@ LOCAL_MODULE_TAGS := tests
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_JAVA_LIBRARIES := android.test.runner
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4 mockito-target guava
LOCAL_PACKAGE_NAME := DocumentsUITests
LOCAL_INSTRUMENTATION_FOR := DocumentsUI
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/CopyTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/CopyTest.java
new file mode 100644
index 0000000..13f7daa
--- /dev/null
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/CopyTest.java
@@ -0,0 +1,281 @@
+/*
+ * Copyright (C) 2015 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.documentsui;
+
+import static com.android.documentsui.model.DocumentInfo.getCursorString;
+
+import android.app.NotificationManager;
+import android.content.ContentProviderClient;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.content.Intent;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.ParcelFileDescriptor;
+import android.os.Parcelable;
+import android.os.RemoteException;
+import android.provider.DocumentsContract;
+import android.provider.DocumentsContract.Document;
+import android.test.MoreAsserts;
+import android.test.ServiceTestCase;
+import android.util.Log;
+
+import com.android.documentsui.model.DocumentInfo;
+import com.android.documentsui.model.DocumentStack;
+import com.android.documentsui.model.RootInfo;
+import com.google.common.collect.Lists;
+
+import libcore.io.IoUtils;
+import libcore.io.Streams;
+
+import org.mockito.Mockito;
+
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+public class CopyTest extends ServiceTestCase<CopyService> {
+
+ public CopyTest() {
+ super(CopyService.class);
+ }
+
+ private static String TAG = "CopyTest";
+ // This must match the authority for the StubProvider.
+ private static String AUTHORITY = "com.android.documentsui.stubprovider";
+ private List<RootInfo> mRoots;
+ private Context mContext;
+ private ContentResolver mResolver;
+ private ContentProviderClient mClient;
+ private NotificationManager mNotificationManager;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ setupTestContext();
+
+ mResolver = mContext.getContentResolver();
+ mClient = mResolver.acquireContentProviderClient(AUTHORITY);
+
+ // Reset the stub provider's storage.
+ mClient.call("clear", "", null);
+
+ mRoots = Lists.newArrayList();
+ Uri queryUri = DocumentsContract.buildRootsUri(AUTHORITY);
+ Cursor cursor = null;
+ try {
+ cursor = mClient.query(queryUri, null, null, null, null);
+ while (cursor.moveToNext()) {
+ final RootInfo root = RootInfo.fromRootsCursor(AUTHORITY, cursor);
+ final String id = root.rootId;
+ mRoots.add(root);
+ }
+ } finally {
+ IoUtils.closeQuietly(cursor);
+ }
+
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ mClient.release();
+ super.tearDown();
+ }
+
+ public List<Uri> setupTestFiles() throws Exception {
+ Uri rootUri = DocumentsContract.buildDocumentUri(AUTHORITY, mRoots.get(0).documentId);
+ List<Uri> testFiles = Lists.newArrayList(
+ DocumentsContract.createDocument(mClient, rootUri, "text/plain", "test0.txt"),
+ DocumentsContract.createDocument(mClient, rootUri, "text/plain", "test1.txt"),
+ DocumentsContract.createDocument(mClient, rootUri, "text/plain", "test2.txt")
+ );
+ String testContent[] = {
+ "The five boxing wizards jump quickly",
+ "The quick brown fox jumps over the lazy dog",
+ "Jackdaws love my big sphinx of quartz"
+ };
+ for (int i = 0; i < testFiles.size(); ++i) {
+ ParcelFileDescriptor pfd = null;
+ OutputStream out = null;
+ try {
+ pfd = mClient.openFile(testFiles.get(i), "w");
+ out = new ParcelFileDescriptor.AutoCloseOutputStream(pfd);
+ out.write(testContent[i].getBytes());
+ } finally {
+ IoUtils.closeQuietly(out);
+ }
+ }
+ return testFiles;
+ }
+
+ /**
+ * Test copying a single file.
+ */
+ public void testCopyFile() throws Exception {
+ Uri testFile = setupTestFiles().get(0);
+
+ // Just copy one file.
+ copyToDestination(Lists.newArrayList(testFile));
+
+ // A call to NotificationManager.cancel marks the end of the copy operation.
+ Mockito.verify(mNotificationManager, Mockito.timeout(1000)).cancel(Mockito.anyString(),
+ Mockito.anyInt());
+
+ // Verify that one file was copied; check file contents.
+ assertDstFileCountEquals(1);
+ assertCopied(testFile);
+ }
+
+ /**
+ * Test copying multiple files.
+ */
+ public void testCopyMultipleFiles() throws Exception {
+ List<Uri> testFiles = setupTestFiles();
+ // Copy all the test files.
+ copyToDestination(testFiles);
+
+ // A call to NotificationManager.cancel marks the end of the copy operation.
+ Mockito.verify(mNotificationManager, Mockito.timeout(1000)).cancel(Mockito.anyString(),
+ Mockito.anyInt());
+
+ assertDstFileCountEquals(3);
+ for (Uri testFile : testFiles) {
+ assertCopied(testFile);
+ }
+ }
+
+ /**
+ * Copies the given files to a pre-determined destination.
+ *
+ * @throws FileNotFoundException
+ */
+ private void copyToDestination(List<Uri> srcs) throws FileNotFoundException {
+ final ArrayList<DocumentInfo> srcDocs = Lists.newArrayList();
+ for (Uri src : srcs) {
+ srcDocs.add(DocumentInfo.fromUri(mResolver, src));
+ }
+
+ final Uri dst = DocumentsContract.buildDocumentUri(AUTHORITY, mRoots.get(1).documentId);
+ DocumentStack stack = new DocumentStack();
+ stack.push(DocumentInfo.fromUri(mResolver, dst));
+ final Intent copyIntent = new Intent(mContext, CopyService.class);
+ copyIntent.putParcelableArrayListExtra(CopyService.EXTRA_SRC_LIST, srcDocs);
+ copyIntent.putExtra(CopyService.EXTRA_STACK, (Parcelable) stack);
+
+ startService(copyIntent);
+ }
+
+ /**
+ * Returns a count of the files in the given directory.
+ */
+ private void assertDstFileCountEquals(int expected) throws RemoteException {
+ final Uri queryUri = DocumentsContract.buildChildDocumentsUri(AUTHORITY,
+ mRoots.get(1).documentId);
+ Cursor c = null;
+ int count = 0;
+ try {
+ c = mClient.query(queryUri, null, null, null, null);
+ count = c.getCount();
+ } finally {
+ IoUtils.closeQuietly(c);
+ }
+ assertEquals("Incorrect file count after copy", expected, count);
+ }
+
+ /**
+ * Verifies that the file pointed to by the given URI was correctly copied to the destination.
+ */
+ private void assertCopied(Uri src) throws Exception {
+ Cursor cursor = null;
+ String srcName = null;
+ try {
+ cursor = mClient.query(src, null, null, null, null);
+ if (cursor.moveToFirst()) {
+ srcName = getCursorString(cursor, Document.COLUMN_DISPLAY_NAME);
+ }
+ } finally {
+ IoUtils.closeQuietly(cursor);
+ }
+ Uri dst = getDstFileUri(srcName);
+
+ InputStream in0 = null;
+ InputStream in1 = null;
+ try {
+ in0 = new ParcelFileDescriptor.AutoCloseInputStream(mClient.openFile(src, "r"));
+ in1 = new ParcelFileDescriptor.AutoCloseInputStream(mClient.openFile(dst, "r"));
+
+ byte[] buffer0 = Streams.readFully(in0);
+ byte[] buffer1 = Streams.readFully(in1);
+
+ MoreAsserts.assertEquals(buffer0, buffer1);
+ } finally {
+ IoUtils.closeQuietly(in0);
+ IoUtils.closeQuietly(in1);
+ }
+ }
+
+ /**
+ * Generates a file URI from a given filename. This assumes the file already exists in the
+ * destination root.
+ */
+ private Uri getDstFileUri(String filename) throws RemoteException {
+ final Uri dstFileQuery = DocumentsContract.buildChildDocumentsUri(AUTHORITY,
+ mRoots.get(1).documentId);
+ Cursor cursor = null;
+ try {
+ // StubProvider doesn't seem to support query strings; filter the results manually.
+ cursor = mClient.query(dstFileQuery, null, null, null, null);
+ while (cursor.moveToNext()) {
+ if (filename.equals(getCursorString(cursor, Document.COLUMN_DISPLAY_NAME))) {
+ return DocumentsContract.buildDocumentUri(AUTHORITY,
+ getCursorString(cursor, Document.COLUMN_DOCUMENT_ID));
+ }
+ }
+ } finally {
+ IoUtils.closeQuietly(cursor);
+ }
+ return null;
+ }
+
+ /**
+ * Sets up a ContextWrapper that substitutes a stub NotificationManager. This allows the test to
+ * listen for notification events, to gauge copy progress.
+ */
+ private void setupTestContext() {
+ mContext = getSystemContext();
+ System.setProperty("dexmaker.dexcache", mContext.getCacheDir().getPath());
+
+ mNotificationManager = Mockito.spy((NotificationManager) mContext
+ .getSystemService(Context.NOTIFICATION_SERVICE));
+
+ // Insert a stub NotificationManager that enables us to listen for when copying is complete.
+ setContext(new ContextWrapper(mContext) {
+ @Override
+ public Object getSystemService(String name) {
+ if (Context.NOTIFICATION_SERVICE.equals(name)) {
+ return mNotificationManager;
+ } else {
+ return super.getSystemService(name);
+ }
+ }
+ });
+ }
+}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/StubProvider.java b/packages/DocumentsUI/tests/src/com/android/documentsui/StubProvider.java
index 75effa7..438f6cd 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/StubProvider.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/StubProvider.java
@@ -17,34 +17,45 @@
package com.android.documentsui;
import android.content.Context;
+import android.content.SharedPreferences;
import android.content.pm.ProviderInfo;
import android.content.res.AssetFileDescriptor;
import android.database.Cursor;
import android.database.MatrixCursor.RowBuilder;
import android.database.MatrixCursor;
import android.graphics.Point;
+import android.os.Bundle;
import android.os.CancellationSignal;
import android.os.FileUtils;
import android.os.ParcelFileDescriptor;
import android.provider.DocumentsContract;
import android.provider.DocumentsContract.Document;
import android.provider.DocumentsContract.Root;
-import android.provider.DocumentsContract.Root;
import android.provider.DocumentsProvider;
+import android.util.Log;
+
+import com.google.android.collect.Maps;
+
+import libcore.io.IoUtils;
-import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Arrays;
+import java.util.Collection;
import java.util.HashMap;
-import java.util.List;
+import java.util.Map;
public class StubProvider extends DocumentsProvider {
- private static int STORAGE_SIZE = 1024 * 1024; // 1 MB.
+ private static final String EXTRA_SIZE = "com.android.documentsui.stubprovider.SIZE";
+ private static final String EXTRA_ROOT = "com.android.documentsui.stubprovider.ROOT";
+ private static final String STORAGE_SIZE_KEY = "documentsui.stubprovider.size";
+ private static int DEFAULT_SIZE = 1024 * 1024; // 1 MB.
private static final String TAG = "StubProvider";
- private static final String MY_ROOT_ID = "myRoot";
-
+ private static final String MY_ROOT_ID = "sd0";
private static final String[] DEFAULT_ROOT_PROJECTION = new String[] {
Root.COLUMN_ROOT_ID, Root.COLUMN_FLAGS, Root.COLUMN_TITLE, Root.COLUMN_DOCUMENT_ID,
Root.COLUMN_AVAILABLE_BYTES
@@ -54,11 +65,11 @@ public class StubProvider extends DocumentsProvider {
Document.COLUMN_LAST_MODIFIED, Document.COLUMN_FLAGS, Document.COLUMN_SIZE,
};
- private String mRootDocumentId;
private HashMap<String, StubDocument> mStorage = new HashMap<String, StubDocument>();
- private int mStorageUsedBytes;
private Object mWriteLock = new Object();
private String mAuthority;
+ private SharedPreferences mPrefs;
+ private Map<String, RootInfo> mRoots;
@Override
public void attachInfo(Context context, ProviderInfo info) {
@@ -68,29 +79,61 @@ public class StubProvider extends DocumentsProvider {
@Override
public boolean onCreate() {
+ clearCacheAndBuildRoots();
+ return true;
+ }
+
+ private void clearCacheAndBuildRoots() {
final File cacheDir = getContext().getCacheDir();
removeRecursively(cacheDir);
- final StubDocument document = new StubDocument(cacheDir, Document.MIME_TYPE_DIR, null);
- mRootDocumentId = document.documentId;
- mStorage.put(mRootDocumentId, document);
- return true;
+ mStorage.clear();
+
+ mPrefs = getContext().getSharedPreferences(
+ "com.android.documentsui.stubprovider.preferences", Context.MODE_PRIVATE);
+ Collection<String> rootIds = mPrefs.getStringSet("roots", null);
+ if (rootIds == null) {
+ rootIds = Arrays.asList(new String[] {
+ "sd0", "sd1"
+ });
+ }
+ // Create new roots.
+ mRoots = Maps.newHashMap();
+ for (String rootId : rootIds) {
+ final RootInfo rootInfo = new RootInfo(rootId, getSize(rootId));
+ mRoots.put(rootId, rootInfo);
+ }
+ }
+
+ /**
+ * @return Storage size, in bytes.
+ */
+ private long getSize(String rootId) {
+ final String key = STORAGE_SIZE_KEY + "." + rootId;
+ return mPrefs.getLong(key, DEFAULT_SIZE);
}
@Override
public Cursor queryRoots(String[] projection) throws FileNotFoundException {
- final MatrixCursor result = new MatrixCursor(projection != null ? projection : DEFAULT_ROOT_PROJECTION);
- final RowBuilder row = result.newRow();
- row.add(Root.COLUMN_ROOT_ID, MY_ROOT_ID);
- row.add(Root.COLUMN_FLAGS, Root.FLAG_SUPPORTS_CREATE | Root.FLAG_SUPPORTS_IS_CHILD);
- row.add(Root.COLUMN_TITLE, "Foobar SD 4GB");
- row.add(Root.COLUMN_DOCUMENT_ID, mRootDocumentId);
- row.add(Root.COLUMN_AVAILABLE_BYTES, STORAGE_SIZE - mStorageUsedBytes);
+ final MatrixCursor result = new MatrixCursor(projection != null ? projection
+ : DEFAULT_ROOT_PROJECTION);
+ for (Map.Entry<String, RootInfo> entry : mRoots.entrySet()) {
+ final String id = entry.getKey();
+ final RootInfo info = entry.getValue();
+ final RowBuilder row = result.newRow();
+ row.add(Root.COLUMN_ROOT_ID, id);
+ row.add(Root.COLUMN_FLAGS, Root.FLAG_SUPPORTS_CREATE | Root.FLAG_SUPPORTS_IS_CHILD);
+ row.add(Root.COLUMN_TITLE, id);
+ row.add(Root.COLUMN_DOCUMENT_ID, info.rootDocument.documentId);
+ row.add(Root.COLUMN_AVAILABLE_BYTES, info.getRemainingCapacity());
+ }
return result;
}
@Override
- public Cursor queryDocument(String documentId, String[] projection) throws FileNotFoundException {
- final MatrixCursor result = new MatrixCursor(projection != null ? projection : DEFAULT_DOCUMENT_PROJECTION);
+ public Cursor queryDocument(String documentId, String[] projection)
+ throws FileNotFoundException {
+ final MatrixCursor result = new MatrixCursor(projection != null ? projection
+ : DEFAULT_DOCUMENT_PROJECTION);
final StubDocument file = mStorage.get(documentId);
if (file == null) {
throw new FileNotFoundException();
@@ -123,14 +166,12 @@ public class StubProvider extends DocumentsProvider {
if (!file.createNewFile()) {
throw new FileNotFoundException();
}
- }
- catch (IOException e) {
+ } catch (IOException e) {
throw new FileNotFoundException();
}
}
final StubDocument document = new StubDocument(file, mimeType, parentDocument);
- mStorage.put(document.documentId, document);
notifyParentChanged(document.parentId);
return document.documentId;
}
@@ -143,7 +184,7 @@ public class StubProvider extends DocumentsProvider {
if (document == null || !document.file.delete())
throw new FileNotFoundException();
synchronized (mWriteLock) {
- mStorageUsedBytes -= fileSize;
+ document.rootInfo.size -= fileSize;
}
notifyParentChanged(document.parentId);
}
@@ -155,12 +196,13 @@ public class StubProvider extends DocumentsProvider {
if (parentDocument == null || parentDocument.file.isFile()) {
throw new FileNotFoundException();
}
- final MatrixCursor result = new MatrixCursor(projection != null ? projection : DEFAULT_DOCUMENT_PROJECTION);
+ final MatrixCursor result = new MatrixCursor(projection != null ? projection
+ : DEFAULT_DOCUMENT_PROJECTION);
result.setNotificationUri(getContext().getContentResolver(),
DocumentsContract.buildChildDocumentsUri(mAuthority, parentDocumentId));
StubDocument document;
for (File file : parentDocument.file.listFiles()) {
- document = mStorage.get(StubDocument.getDocumentIdForFile(file));
+ document = mStorage.get(getDocumentIdForFile(file));
if (document != null) {
includeDocument(result, document);
}
@@ -171,7 +213,9 @@ public class StubProvider extends DocumentsProvider {
@Override
public Cursor queryRecentDocuments(String rootId, String[] projection)
throws FileNotFoundException {
- throw new FileNotFoundException();
+ final MatrixCursor result = new MatrixCursor(projection != null ? projection
+ : DEFAULT_DOCUMENT_PROJECTION);
+ return result;
}
@Override
@@ -202,8 +246,7 @@ public class StubProvider extends DocumentsProvider {
ParcelFileDescriptor[] pipe;
try {
pipe = ParcelFileDescriptor.createReliablePipe();
- }
- catch (IOException exception) {
+ } catch (IOException exception) {
throw new FileNotFoundException();
}
final ParcelFileDescriptor readPipe = pipe[0];
@@ -212,15 +255,19 @@ public class StubProvider extends DocumentsProvider {
new Thread() {
@Override
public void run() {
+ InputStream inputStream = null;
+ OutputStream outputStream = null;
try {
- final FileInputStream inputStream = new FileInputStream(readPipe.getFileDescriptor());
- final FileOutputStream outputStream = new FileOutputStream(document.file);
+ inputStream = new ParcelFileDescriptor.AutoCloseInputStream(readPipe);
+ outputStream = new FileOutputStream(document.file);
byte[] buffer = new byte[32 * 1024];
int bytesToRead;
int bytesRead = 0;
while (bytesRead != -1) {
synchronized (mWriteLock) {
- bytesToRead = Math.min(STORAGE_SIZE - mStorageUsedBytes, buffer.length);
+ // This cast is safe because the max possible value is buffer.length.
+ bytesToRead = (int) Math.min(document.rootInfo.getRemainingCapacity(),
+ buffer.length);
if (bytesToRead == 0) {
closePipeWithErrorSilently(readPipe, "Not enough space.");
break;
@@ -230,15 +277,14 @@ public class StubProvider extends DocumentsProvider {
break;
}
outputStream.write(buffer, 0, bytesRead);
- mStorageUsedBytes += bytesRead;
+ document.rootInfo.size += bytesRead;
}
}
- }
- catch (IOException e) {
+ } catch (IOException e) {
closePipeWithErrorSilently(readPipe, e.getMessage());
- }
- finally {
- closePipeSilently(readPipe);
+ } finally {
+ IoUtils.closeQuietly(inputStream);
+ IoUtils.closeQuietly(outputStream);
notifyParentChanged(document.parentId);
}
}
@@ -250,24 +296,38 @@ public class StubProvider extends DocumentsProvider {
private void closePipeWithErrorSilently(ParcelFileDescriptor pipe, String error) {
try {
pipe.closeWithError(error);
- }
- catch (IOException ignore) {
+ } catch (IOException ignore) {
}
}
- private void closePipeSilently(ParcelFileDescriptor pipe) {
- try {
- pipe.close();
- }
- catch (IOException ignore) {
+ @Override
+ public Bundle call(String method, String arg, Bundle extras) {
+ Log.d(TAG, "call: " + method + arg);
+ switch (method) {
+ case "clear":
+ clearCacheAndBuildRoots();
+ return null;
+ case "configure":
+ configure(arg, extras);
+ return null;
+ default:
+ return super.call(method, arg, extras);
}
}
+ private void configure(String arg, Bundle extras) {
+ Log.d(TAG, "Configure " + arg);
+ String rootName = extras.getString(EXTRA_ROOT, MY_ROOT_ID);
+ long rootSize = extras.getLong(EXTRA_SIZE, 1) * 1024 * 1024;
+ setSize(rootName, rootSize);
+ }
+
private void notifyParentChanged(String parentId) {
getContext().getContentResolver().notifyChange(
DocumentsContract.buildChildDocumentsUri(mAuthority, parentId), null, false);
// Notify also about possible change in remaining space on the root.
- getContext().getContentResolver().notifyChange(DocumentsContract.buildRootsUri(mAuthority), null, false);
+ getContext().getContentResolver().notifyChange(DocumentsContract.buildRootsUri(mAuthority),
+ null, false);
}
private void includeDocument(MatrixCursor result, StubDocument document) {
@@ -295,22 +355,102 @@ public class StubProvider extends DocumentsProvider {
childFile.delete();
}
}
-}
-class StubDocument {
- public final File file;
- public final String mimeType;
- public final String documentId;
- public final String parentId;
-
- StubDocument(File file, String mimeType, StubDocument parent) {
- this.file = file;
- this.mimeType = mimeType;
- this.documentId = getDocumentIdForFile(file);
- this.parentId = parent != null ? parent.documentId : null;
+ public void setSize(String rootId, long rootSize) {
+ RootInfo root = mRoots.get(rootId);
+ if (root != null) {
+ final String key = STORAGE_SIZE_KEY + "." + rootId;
+ Log.d(TAG, "Set size of " + key + " : " + rootSize);
+
+ // Persist the size.
+ SharedPreferences.Editor editor = mPrefs.edit();
+ editor.putLong(key, rootSize);
+ editor.apply();
+ // Apply the size in the current instance of this provider.
+ root.capacity = rootSize;
+ getContext().getContentResolver().notifyChange(
+ DocumentsContract.buildRootsUri(mAuthority),
+ null, false);
+ } else {
+ Log.e(TAG, "Attempt to configure non-existent root: " + rootId);
+ }
+ }
+
+ public File createFile(String rootId, File parent, String mimeType, String name)
+ throws IOException {
+ StubDocument parentDoc = null;
+ if (parent == null) {
+ // Use the root dir as the parent, if one wasn't specified.
+ parentDoc = mRoots.get(rootId).rootDocument;
+ } else {
+ // Verify that the parent exists and is a directory.
+ parentDoc = mStorage.get(getDocumentIdForFile(parent));
+ if (parentDoc == null) {
+ throw new IllegalArgumentException("Parent file not found.");
+ }
+ if (!Document.MIME_TYPE_DIR.equals(parentDoc.mimeType)) {
+ throw new IllegalArgumentException("Parent file must be a directory.");
+ }
+ }
+ File file = new File(parentDoc.file, name);
+ if (Document.MIME_TYPE_DIR.equals(mimeType)) {
+ file.mkdir();
+ } else {
+ file.createNewFile();
+ }
+ new StubDocument(file, mimeType, parentDoc);
+ return file;
+ }
+
+ final class RootInfo {
+ public final String name;
+ public final StubDocument rootDocument;
+ public long capacity;
+ public long size;
+
+ RootInfo(String name, long capacity) {
+ this.name = name;
+ this.capacity = 1024 * 1024;
+ // Make a subdir in the cache dir for each root.
+ File rootDir = new File(getContext().getCacheDir(), name);
+ rootDir.mkdir();
+ this.rootDocument = new StubDocument(rootDir, Document.MIME_TYPE_DIR, this);
+ this.capacity = capacity;
+ this.size = 0;
+ }
+
+ public long getRemainingCapacity() {
+ return capacity - size;
+ }
+ }
+
+ final class StubDocument {
+ public final File file;
+ public final String mimeType;
+ public final String documentId;
+ public final String parentId;
+ public final RootInfo rootInfo;
+
+ StubDocument(File file, String mimeType, StubDocument parent) {
+ this.file = file;
+ this.mimeType = mimeType;
+ this.documentId = getDocumentIdForFile(file);
+ this.parentId = parent.documentId;
+ this.rootInfo = parent.rootInfo;
+ mStorage.put(this.documentId, this);
+ }
+
+ StubDocument(File file, String mimeType, RootInfo rootInfo) {
+ this.file = file;
+ this.mimeType = mimeType;
+ this.documentId = getDocumentIdForFile(file);
+ this.parentId = null;
+ this.rootInfo = rootInfo;
+ mStorage.put(this.documentId, this);
+ }
}
- public static String getDocumentIdForFile(File file) {
+ private static String getDocumentIdForFile(File file) {
return file.getAbsolutePath();
}
}