failedSrcList, DocumentStack dstStack, int transferMode) {
// TODO: Add support for other failures than copy.
if (failure != CopyService.FAILURE_COPY) {
return;
@@ -54,6 +50,7 @@ public class FailureDialogFragment extends DialogFragment
final Bundle args = new Bundle();
args.putInt(CopyService.EXTRA_FAILURE, failure);
+ args.putInt(CopyService.EXTRA_TRANSFER_MODE, transferMode);
args.putParcelableArrayList(CopyService.EXTRA_SRC_LIST, failedSrcList);
final FragmentTransaction ft = fm.beginTransaction();
@@ -66,11 +63,12 @@ public class FailureDialogFragment extends DialogFragment
@Override
public void onClick(DialogInterface dialog, int whichButton) {
- if (whichButton == DialogInterface.BUTTON_POSITIVE) {
- CopyService.start(getActivity(), mFailedSrcList,
- (DocumentStack) getActivity().getIntent().getParcelableExtra(
- CopyService.EXTRA_STACK));
- }
+ if (whichButton == DialogInterface.BUTTON_POSITIVE) {
+ CopyService.start(getActivity(), mFailedSrcList,
+ (DocumentStack) getActivity().getIntent().getParcelableExtra(
+ CopyService.EXTRA_STACK),
+ mTransferMode);
+ }
}
@Override
@@ -78,6 +76,7 @@ public class FailureDialogFragment extends DialogFragment
super.onCreate(inState);
mFailure = getArguments().getInt(CopyService.EXTRA_FAILURE);
+ mTransferMode = getArguments().getInt(CopyService.EXTRA_TRANSFER_MODE);
mFailedSrcList = getArguments().getParcelableArrayList(CopyService.EXTRA_SRC_LIST);
final StringBuilder list = new StringBuilder("");
@@ -89,9 +88,9 @@ public class FailureDialogFragment extends DialogFragment
list.toString());
return new AlertDialog.Builder(getActivity())
- .setMessage(Html.fromHtml(message))
- .setPositiveButton(R.string.retry, this)
- .setNegativeButton(android.R.string.cancel, this)
- .create();
+ .setMessage(Html.fromHtml(message))
+ .setPositiveButton(R.string.retry, this)
+ .setNegativeButton(android.R.string.cancel, this)
+ .create();
}
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/StandaloneActivity.java b/packages/DocumentsUI/src/com/android/documentsui/StandaloneActivity.java
index 27fc5ef5ff4a0..d1e66c63b8bb0 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/StandaloneActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/StandaloneActivity.java
@@ -83,8 +83,8 @@ public class StandaloneActivity extends BaseActivity {
mDirectoryContainer = (DirectoryContainerView) findViewById(R.id.container_directory);
mState = (icicle != null)
- ? icicle.getParcelable(EXTRA_STATE)
- : buildDefaultState();
+ ? icicle. getParcelable(EXTRA_STATE)
+ : buildDefaultState();
mToolbar = (Toolbar) findViewById(R.id.toolbar);
mToolbar.setTitleTextAppearance(context,
@@ -111,10 +111,13 @@ public class StandaloneActivity extends BaseActivity {
final Intent intent = getIntent();
final DocumentStack dstStack = intent.getParcelableExtra(CopyService.EXTRA_STACK);
final int failure = intent.getIntExtra(CopyService.EXTRA_FAILURE, 0);
+ final int transferMode = intent.getIntExtra(CopyService.EXTRA_TRANSFER_MODE,
+ CopyService.TRANSFER_MODE_NONE);
if (failure != 0) {
final ArrayList failedSrcList =
intent.getParcelableArrayListExtra(CopyService.EXTRA_SRC_LIST);
- FailureDialogFragment.show(getFragmentManager(), failure, failedSrcList, dstStack);
+ FailureDialogFragment.show(getFragmentManager(), failure, failedSrcList, dstStack,
+ transferMode);
}
} else {
onCurrentDirectoryChanged(ANIM_NONE);
@@ -281,6 +284,7 @@ public class StandaloneActivity extends BaseActivity {
}
}
+ @Override
public void onDocumentsPicked(List docs) {
// TODO
}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/CopyTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/CopyTest.java
index b1c84ddbd4a3c..568e9e4039604 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/CopyTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/CopyTest.java
@@ -83,7 +83,7 @@ public class CopyTest extends ServiceTestCase {
// Signal that the test is now waiting for files.
mReadySignal.countDown();
if (!mNotificationSignal.await(timeOut, TimeUnit.MILLISECONDS)) {
- throw new TimeoutException("Timed out waiting for files to be copied.");
+ throw new TimeoutException("Timed out waiting for file operations to complete.");
}
}
@@ -159,7 +159,7 @@ public class CopyTest extends ServiceTestCase {
assertDstFileCountEquals(0);
- copyToDestination(Lists.newArrayList(testFile));
+ startService(createCopyIntent(Lists.newArrayList(testFile)));
// 2 operations: file creation, then writing data.
mResolver.waitForChanges(2);
@@ -169,6 +169,28 @@ public class CopyTest extends ServiceTestCase {
assertCopied(srcPath);
}
+ public void testMoveFile() throws Exception {
+ String srcPath = "/test0.txt";
+ String testContent = "The five boxing wizards jump quickly";
+ Uri testFile = mStorage.createFile(SRC, srcPath, "text/plain", testContent.getBytes());
+
+ assertDstFileCountEquals(0);
+
+ Intent moveIntent = createCopyIntent(Lists.newArrayList(testFile));
+ moveIntent.putExtra(CopyService.EXTRA_TRANSFER_MODE, CopyService.TRANSFER_MODE_MOVE);
+ startService(moveIntent);
+
+ // 3 operations: file creation, writing data, deleting original.
+ mResolver.waitForChanges(3);
+
+ // Verify that one file was moved; check file contents.
+ assertDstFileCountEquals(1);
+ assertDoesNotExist(SRC, srcPath);
+
+ byte[] dstContent = readFile(DST, srcPath);
+ MoreAsserts.assertEquals("Moved file contents differ", testContent.getBytes(), dstContent);
+ }
+
/**
* Test copying multiple files.
*/
@@ -191,7 +213,7 @@ public class CopyTest extends ServiceTestCase {
assertDstFileCountEquals(0);
// Copy all the test files.
- copyToDestination(testFiles);
+ startService(createCopyIntent(testFiles));
// 3 file creations, 3 file writes.
mResolver.waitForChanges(6);
@@ -209,40 +231,190 @@ public class CopyTest extends ServiceTestCase {
assertDstFileCountEquals(0);
- copyToDestination(Lists.newArrayList(testDir));
+ startService(createCopyIntent(Lists.newArrayList(testDir)));
// Just 1 operation: Directory creation.
mResolver.waitForChanges(1);
assertDstFileCountEquals(1);
+ // Verify that the dst exists and is a directory.
File dst = mStorage.getFile(DST, srcPath);
assertTrue(dst.isDirectory());
}
- public void testReadErrors() throws Exception {
+ public void testMoveEmptyDir() throws Exception {
+ String srcPath = "/emptyDir";
+ Uri testDir = mStorage.createFile(SRC, srcPath, DocumentsContract.Document.MIME_TYPE_DIR,
+ null);
+
+ assertDstFileCountEquals(0);
+
+ Intent moveIntent = createCopyIntent(Lists.newArrayList(testDir));
+ moveIntent.putExtra(CopyService.EXTRA_TRANSFER_MODE, CopyService.TRANSFER_MODE_MOVE);
+ startService(moveIntent);
+
+ // 2 operations: Directory creation, and removal of the original.
+ mResolver.waitForChanges(2);
+
+ assertDstFileCountEquals(1);
+
+ // Verify that the dst exists and is a directory.
+ File dst = mStorage.getFile(DST, srcPath);
+ assertTrue(dst.isDirectory());
+
+ // Verify that the src was cleaned up.
+ assertDoesNotExist(SRC, srcPath);
+ }
+
+ public void testMovePopulatedDir() throws Exception {
+ String testContent[] = {
+ "The five boxing wizards jump quickly",
+ "The quick brown fox jumps over the lazy dog",
+ "Jackdaws love my big sphinx of quartz"
+ };
+ String srcDir = "/testdir";
+ String srcFiles[] = {
+ srcDir + "/test0.txt",
+ srcDir + "/test1.txt",
+ srcDir + "/test2.txt"
+ };
+ // Create test dir; put some files in it.
+ Uri testDir = mStorage.createFile(SRC, srcDir, DocumentsContract.Document.MIME_TYPE_DIR,
+ null);
+ mStorage.createFile(SRC, srcFiles[0], "text/plain", testContent[0].getBytes());
+ mStorage.createFile(SRC, srcFiles[1], "text/plain", testContent[1].getBytes());
+ mStorage.createFile(SRC, srcFiles[2], "text/plain", testContent[2].getBytes());
+
+ Intent moveIntent = createCopyIntent(Lists.newArrayList(testDir));
+ moveIntent.putExtra(CopyService.EXTRA_TRANSFER_MODE, CopyService.TRANSFER_MODE_MOVE);
+ startService(moveIntent);
+
+ // dir creation, then creation and writing of 3 files, then removal of src dir and 3 src
+ // files.
+ mResolver.waitForChanges(11);
+
+ // Check the content of the moved files.
+ File dst = mStorage.getFile(DST, srcDir);
+ assertTrue(dst.isDirectory());
+ for (int i = 0; i < testContent.length; ++i) {
+ byte[] dstContent = readFile(DST, srcFiles[i]);
+ MoreAsserts.assertEquals("Copied file contents differ", testContent[i].getBytes(),
+ dstContent);
+ }
+
+ // Check that the src files were removed.
+ assertDoesNotExist(SRC, srcDir);
+ for (String srcFile : srcFiles) {
+ assertDoesNotExist(SRC, srcFile);
+ }
+ }
+
+ public void testCopyFileWithReadErrors() throws Exception {
String srcPath = "/test0.txt";
Uri testFile = mStorage.createFile(SRC, srcPath, "text/plain",
"The five boxing wizards jump quickly".getBytes());
assertDstFileCountEquals(0);
- mStorage.simulateReadErrors(true);
+ mStorage.simulateReadErrorsForFile(testFile);
- copyToDestination(Lists.newArrayList(testFile));
+ startService(createCopyIntent(Lists.newArrayList(testFile)));
// 3 operations: file creation, writing, then deletion (due to failed copy).
mResolver.waitForChanges(3);
+ // Verify that the failed copy was cleaned up.
assertDstFileCountEquals(0);
}
+ public void testMoveFileWithReadErrors() throws Exception {
+ String srcPath = "/test0.txt";
+ Uri testFile = mStorage.createFile(SRC, srcPath, "text/plain",
+ "The five boxing wizards jump quickly".getBytes());
+
+ assertDstFileCountEquals(0);
+
+ mStorage.simulateReadErrorsForFile(testFile);
+
+ Intent moveIntent = createCopyIntent(Lists.newArrayList(testFile));
+ moveIntent.putExtra(CopyService.EXTRA_TRANSFER_MODE, CopyService.TRANSFER_MODE_MOVE);
+ startService(moveIntent);
+
+ try {
+ // There should be 3 operations: file creation, writing, then deletion (due to failed
+ // copy). Wait for 4, in case the CopyService also attempts to do extra stuff (like
+ // delete the src file). This should time out.
+ mResolver.waitForChanges(4);
+ } catch (TimeoutException e) {
+ // Success path
+ return;
+ } finally {
+ // Verify that the failed copy was cleaned up, and the src file wasn't removed.
+ assertDstFileCountEquals(0);
+ assertExists(SRC, srcPath);
+ }
+ // The asserts above didn't fail, but the CopyService did something unexpected.
+ fail("Extra file operations were detected");
+ }
+
+ public void testMoveDirectoryWithReadErrors() throws Exception {
+ String testContent[] = {
+ "The five boxing wizards jump quickly",
+ "The quick brown fox jumps over the lazy dog",
+ "Jackdaws love my big sphinx of quartz"
+ };
+ String srcDir = "/testdir";
+ String srcFiles[] = {
+ srcDir + "/test0.txt",
+ srcDir + "/test1.txt",
+ srcDir + "/test2.txt"
+ };
+ // Create test dir; put some files in it.
+ Uri testDir = mStorage.createFile(SRC, srcDir, DocumentsContract.Document.MIME_TYPE_DIR,
+ null);
+ mStorage.createFile(SRC, srcFiles[0], "text/plain", testContent[0].getBytes());
+ Uri errFile = mStorage
+ .createFile(SRC, srcFiles[1], "text/plain", testContent[1].getBytes());
+ mStorage.createFile(SRC, srcFiles[2], "text/plain", testContent[2].getBytes());
+
+ mStorage.simulateReadErrorsForFile(errFile);
+
+ Intent moveIntent = createCopyIntent(Lists.newArrayList(testDir));
+ moveIntent.putExtra(CopyService.EXTRA_TRANSFER_MODE, CopyService.TRANSFER_MODE_MOVE);
+ startService(moveIntent);
+
+ // - dst dir creation,
+ // - creation and writing of 2 files, removal of 2 src files
+ // - creation and writing of 1 file, then removal of that file (due to error)
+ mResolver.waitForChanges(10);
+
+ // Check that both the src and dst dirs exist. The src dir shouldn't have been removed,
+ // because it should contain the one errFile.
+ assertTrue(mStorage.getFile(SRC, srcDir).isDirectory());
+ assertTrue(mStorage.getFile(DST, srcDir).isDirectory());
+
+ // Check the content of the moved files.
+ MoreAsserts.assertEquals("Copied file contents differ", testContent[0].getBytes(),
+ readFile(DST, srcFiles[0]));
+ MoreAsserts.assertEquals("Copied file contents differ", testContent[2].getBytes(),
+ readFile(DST, srcFiles[2]));
+
+ // Check that the src files were removed.
+ assertDoesNotExist(SRC, srcFiles[0]);
+ assertDoesNotExist(SRC, srcFiles[2]);
+
+ // Check that the error file was not copied over.
+ assertDoesNotExist(DST, srcFiles[1]);
+ assertExists(SRC, srcFiles[1]);
+ }
+
/**
* Copies the given files to a pre-determined destination.
*
* @throws FileNotFoundException
*/
- private void copyToDestination(List srcs) throws FileNotFoundException {
+ private Intent createCopyIntent(List srcs) throws FileNotFoundException {
final ArrayList srcDocs = Lists.newArrayList();
for (Uri src : srcs) {
srcDocs.add(DocumentInfo.fromUri(mResolver, src));
@@ -255,7 +427,8 @@ public class CopyTest extends ServiceTestCase {
copyIntent.putParcelableArrayListExtra(CopyService.EXTRA_SRC_LIST, srcDocs);
copyIntent.putExtra(CopyService.EXTRA_STACK, (Parcelable) stack);
- startService(copyIntent);
+ // startService(copyIntent);
+ return copyIntent;
}
/**
@@ -275,24 +448,34 @@ public class CopyTest extends ServiceTestCase {
assertEquals("Incorrect file count after copy", expected, count);
}
- private void assertCopied(String path) throws Exception {
- File srcFile = mStorage.getFile(SRC, path);
- File dstFile = mStorage.getFile(DST, path);
- assertNotNull(dstFile);
+ private void assertExists(String rootId, String path) throws Exception {
+ assertNotNull("An expected file was not found: " + path + " on root " + rootId,
+ mStorage.getFile(rootId, path));
+ }
- FileInputStream src = null;
- FileInputStream dst = null;
+ private void assertDoesNotExist(String rootId, String path) throws Exception {
+ assertNull("Unexpected file found: " + path + " on root " + rootId,
+ mStorage.getFile(rootId, path));
+ }
+
+ private byte[] readFile(String rootId, String path) throws Exception {
+ File file = mStorage.getFile(rootId, path);
+ byte[] buf = null;
+ assertNotNull(file);
+
+ FileInputStream in = null;
try {
- src = new FileInputStream(srcFile);
- dst = new FileInputStream(dstFile);
- byte[] srcbuf = Streams.readFully(src);
- byte[] dstbuf = Streams.readFully(dst);
-
- MoreAsserts.assertEquals(srcbuf, dstbuf);
+ in = new FileInputStream(file);
+ buf = Streams.readFully(in);
} finally {
- IoUtils.closeQuietly(src);
- IoUtils.closeQuietly(dst);
+ IoUtils.closeQuietly(in);
}
+ return buf;
+ }
+
+ private void assertCopied(String path) throws Exception {
+ MoreAsserts.assertEquals("Copied file contents differ", readFile(SRC, path),
+ readFile(DST, path));
}
/**
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/StubProvider.java b/packages/DocumentsUI/tests/src/com/android/documentsui/StubProvider.java
index 8cef433791b51..c2f176221f4b2 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/StubProvider.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/StubProvider.java
@@ -72,7 +72,7 @@ public class StubProvider extends DocumentsProvider {
private String mAuthority;
private SharedPreferences mPrefs;
private Map mRoots;
- private boolean mSimulateReadErrors;
+ private String mSimulateReadErrors;
@Override
public void attachInfo(Context context, ProviderInfo info) {
@@ -176,6 +176,7 @@ public class StubProvider extends DocumentsProvider {
}
final StubDocument document = new StubDocument(file, mimeType, parentDocument);
+ Log.d(TAG, "Created document " + document.documentId);
notifyParentChanged(document.parentId);
getContext().getContentResolver().notifyChange(
DocumentsContract.buildDocumentUri(mAuthority, document.documentId),
@@ -193,7 +194,9 @@ public class StubProvider extends DocumentsProvider {
throw new FileNotFoundException();
synchronized (mWriteLock) {
document.rootInfo.size -= fileSize;
+ mStorage.remove(documentId);
}
+ Log.d(TAG, "Document deleted: " + documentId);
notifyParentChanged(document.parentId);
getContext().getContentResolver().notifyChange(
DocumentsContract.buildDocumentUri(mAuthority, document.documentId),
@@ -239,7 +242,7 @@ public class StubProvider extends DocumentsProvider {
if ("r".equals(mode)) {
ParcelFileDescriptor pfd = ParcelFileDescriptor.open(document.file,
ParcelFileDescriptor.MODE_READ_ONLY);
- if (mSimulateReadErrors) {
+ if (docId.equals(mSimulateReadErrors)) {
pfd = new ParcelFileDescriptor(pfd) {
@Override
public void checkError() throws IOException {
@@ -257,8 +260,8 @@ public class StubProvider extends DocumentsProvider {
}
@VisibleForTesting
- public void simulateReadErrors(boolean b) {
- mSimulateReadErrors = b;
+ public void simulateReadErrorsForFile(Uri uri) {
+ mSimulateReadErrors = DocumentsContract.getDocumentId(uri);
}
@Override
@@ -284,6 +287,7 @@ public class StubProvider extends DocumentsProvider {
InputStream inputStream = null;
OutputStream outputStream = null;
try {
+ Log.d(TAG, "Opening write stream on file " + document.documentId);
inputStream = new ParcelFileDescriptor.AutoCloseInputStream(readPipe);
outputStream = new FileOutputStream(document.file);
byte[] buffer = new byte[32 * 1024];
@@ -312,6 +316,7 @@ public class StubProvider extends DocumentsProvider {
} finally {
IoUtils.closeQuietly(inputStream);
IoUtils.closeQuietly(outputStream);
+ Log.d(TAG, "Closing write stream on file " + document.documentId);
notifyParentChanged(document.parentId);
getContext().getContentResolver().notifyChange(
DocumentsContract.buildDocumentUri(mAuthority, document.documentId),
@@ -408,6 +413,7 @@ public class StubProvider extends DocumentsProvider {
@VisibleForTesting
public Uri createFile(String rootId, String path, String mimeType, byte[] content)
throws FileNotFoundException, IOException {
+ Log.d(TAG, "Creating file " + rootId + ":" + path);
StubDocument root = mRoots.get(rootId).rootDocument;
if (root == null) {
throw new FileNotFoundException("No roots with the ID " + rootId + " were found");
@@ -417,6 +423,9 @@ public class StubProvider extends DocumentsProvider {
if (parent == null) {
parent = mStorage.get(createFile(rootId, file.getParentFile().getPath(),
DocumentsContract.Document.MIME_TYPE_DIR, null));
+ Log.d(TAG, "Created parent " + parent.documentId);
+ } else {
+ Log.d(TAG, "Found parent " + parent.documentId);
}
if (DocumentsContract.Document.MIME_TYPE_DIR.equals(mimeType)) {