diff options
3 files changed, 117 insertions, 34 deletions
diff --git a/packages/DocumentsUI/src/com/android/documentsui/CopyService.java b/packages/DocumentsUI/src/com/android/documentsui/CopyService.java index c6c19612a88f..6a5911bb1bfd 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/CopyService.java +++ b/packages/DocumentsUI/src/com/android/documentsui/CopyService.java @@ -501,16 +501,23 @@ public class CopyService extends IntentService { // If the file is virtual, but can be converted to another format, then try to copy it // as such format. Also, append an extension for the target mime type (if known). - if (srcInfo.isVirtualDocument() && srcInfo.isTypedDocument()) { + if (srcInfo.isVirtualDocument()) { + if (!srcInfo.isTypedDocument()) { + // Impossible to copy a file which is virtual, but not typed. + mFailedFiles.add(srcInfo); + return false; + } final String[] streamTypes = getContentResolver().getStreamTypes( srcInfo.derivedUri, "*/*"); - if (streamTypes.length > 0) { + if (streamTypes != null && streamTypes.length > 0) { dstMimeType = streamTypes[0]; final String extension = MimeTypeMap.getSingleton(). getExtensionFromMimeType(dstMimeType); dstDisplayName = srcInfo.displayName + (extension != null ? "." + extension : srcInfo.displayName); } else { + // The provider says that it supports typed documents, but doesn't say + // anything about available formats. // TODO: Log failures. b/26192412 mFailedFiles.add(srcInfo); return false; diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/CopyServiceTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/CopyServiceTest.java index 079d59914de6..24a811393b65 100644 --- a/packages/DocumentsUI/tests/src/com/android/documentsui/CopyServiceTest.java +++ b/packages/DocumentsUI/tests/src/com/android/documentsui/CopyServiceTest.java @@ -97,7 +97,7 @@ public class CopyServiceTest extends ServiceTestCase<CopyService> { public void testCopyFile() throws Exception { String srcPath = "/test0.txt"; - Uri testFile = mStorage.createFile(SRC_ROOT, srcPath, "text/plain", + Uri testFile = mStorage.createRegularFile(SRC_ROOT, srcPath, "text/plain", "The five boxing wizards jump quickly".getBytes()); startService(createCopyIntent(Lists.newArrayList(testFile))); @@ -110,10 +110,33 @@ public class CopyServiceTest extends ServiceTestCase<CopyService> { assertCopied(srcPath); } + public void testCopyVirtualTypedFile() throws Exception { + String srcPath = "/virtual.sth"; + String expectedDstPath = "/virtual.sth.pdf"; + ArrayList<String> streamTypes = new ArrayList<>(); + streamTypes.add("application/pdf"); + streamTypes.add("text/html"); + String testContent = "I love fruit cakes!"; + Uri testFile = mStorage.createVirtualFile(SRC_ROOT, srcPath, "virtual/mime-type", + streamTypes, testContent.getBytes()); + + startService(createCopyIntent(Lists.newArrayList(testFile))); + + // 2 operations: file creation, then writing data. + mResolver.waitForChanges(2); + + // Verify that one file was copied. + assertDestFileCount(1); + + byte[] dstContent = readFile(DST_ROOT, expectedDstPath); + MoreAsserts.assertEquals("Moved file contents differ", testContent.getBytes(), dstContent); + } + public void testMoveFile() throws Exception { String srcPath = "/test0.txt"; String testContent = "The five boxing wizards jump quickly"; - Uri testFile = mStorage.createFile(SRC_ROOT, srcPath, "text/plain", testContent.getBytes()); + Uri testFile = mStorage.createRegularFile(SRC_ROOT, srcPath, "text/plain", + testContent.getBytes()); Intent moveIntent = createCopyIntent(Lists.newArrayList(testFile)); moveIntent.putExtra(CopyService.EXTRA_TRANSFER_MODE, CopyService.TRANSFER_MODE_MOVE); @@ -142,9 +165,12 @@ public class CopyServiceTest extends ServiceTestCase<CopyService> { "/test2.txt" }; List<Uri> testFiles = Lists.newArrayList( - mStorage.createFile(SRC_ROOT, srcPaths[0], "text/plain", testContent[0].getBytes()), - mStorage.createFile(SRC_ROOT, srcPaths[1], "text/plain", testContent[1].getBytes()), - mStorage.createFile(SRC_ROOT, srcPaths[2], "text/plain", testContent[2].getBytes())); + mStorage.createRegularFile(SRC_ROOT, srcPaths[0], "text/plain", + testContent[0].getBytes()), + mStorage.createRegularFile(SRC_ROOT, srcPaths[1], "text/plain", + testContent[1].getBytes()), + mStorage.createRegularFile(SRC_ROOT, srcPaths[2], "text/plain", + testContent[2].getBytes())); // Copy all the test files. startService(createCopyIntent(testFiles)); @@ -195,7 +221,6 @@ public class CopyServiceTest extends ServiceTestCase<CopyService> { Intent intent = createCopyIntent(Lists.newArrayList(testDir), descDir); startService(intent); - getService().addFinishedListener(mListener); mListener.waitForFinished(); @@ -240,9 +265,9 @@ public class CopyServiceTest extends ServiceTestCase<CopyService> { }; // Create test dir; put some files in it. Uri testDir = createTestDirectory(srcDir); - mStorage.createFile(SRC_ROOT, srcFiles[0], "text/plain", testContent[0].getBytes()); - mStorage.createFile(SRC_ROOT, srcFiles[1], "text/plain", testContent[1].getBytes()); - mStorage.createFile(SRC_ROOT, srcFiles[2], "text/plain", testContent[2].getBytes()); + mStorage.createRegularFile(SRC_ROOT, srcFiles[0], "text/plain", testContent[0].getBytes()); + mStorage.createRegularFile(SRC_ROOT, srcFiles[1], "text/plain", testContent[1].getBytes()); + mStorage.createRegularFile(SRC_ROOT, srcFiles[2], "text/plain", testContent[2].getBytes()); Intent moveIntent = createCopyIntent(Lists.newArrayList(testDir)); moveIntent.putExtra(CopyService.EXTRA_TRANSFER_MODE, CopyService.TRANSFER_MODE_MOVE); @@ -270,7 +295,7 @@ public class CopyServiceTest extends ServiceTestCase<CopyService> { public void testCopyFileWithReadErrors() throws Exception { String srcPath = "/test0.txt"; - Uri testFile = mStorage.createFile(SRC_ROOT, srcPath, "text/plain", + Uri testFile = mStorage.createRegularFile(SRC_ROOT, srcPath, "text/plain", "The five boxing wizards jump quickly".getBytes()); mStorage.simulateReadErrorsForFile(testFile); @@ -284,9 +309,26 @@ public class CopyServiceTest extends ServiceTestCase<CopyService> { assertDestFileCount(0); } + public void testCopyVirtualNonTypedFile() throws Exception { + String srcPath = "/non-typed.sth"; + // Empty stream types causes the FLAG_SUPPORTS_TYPED_DOCUMENT to be not set. + ArrayList<String> streamTypes = new ArrayList<>(); + Uri testFile = mStorage.createVirtualFile(SRC_ROOT, srcPath, "virtual/mime-type", + streamTypes, "I love Tokyo!".getBytes()); + + Intent intent = createCopyIntent(Lists.newArrayList(testFile)); + startService(intent); + getService().addFinishedListener(mListener); + + mListener.waitForFinished(); + mListener.assertFailedCount(1); + mListener.assertFileFailed("non-typed.sth"); + assertDestFileCount(0); + } + public void testMoveFileWithReadErrors() throws Exception { String srcPath = "/test0.txt"; - Uri testFile = mStorage.createFile(SRC_ROOT, srcPath, "text/plain", + Uri testFile = mStorage.createRegularFile(SRC_ROOT, srcPath, "text/plain", "The five boxing wizards jump quickly".getBytes()); mStorage.simulateReadErrorsForFile(testFile); @@ -326,10 +368,10 @@ public class CopyServiceTest extends ServiceTestCase<CopyService> { }; // Create test dir; put some files in it. Uri testDir = createTestDirectory(srcDir); - mStorage.createFile(SRC_ROOT, srcFiles[0], "text/plain", testContent[0].getBytes()); + mStorage.createRegularFile(SRC_ROOT, srcFiles[0], "text/plain", testContent[0].getBytes()); Uri errFile = mStorage - .createFile(SRC_ROOT, srcFiles[1], "text/plain", testContent[1].getBytes()); - mStorage.createFile(SRC_ROOT, srcFiles[2], "text/plain", testContent[2].getBytes()); + .createRegularFile(SRC_ROOT, srcFiles[1], "text/plain", testContent[1].getBytes()); + mStorage.createRegularFile(SRC_ROOT, srcFiles[2], "text/plain", testContent[2].getBytes()); mStorage.simulateReadErrorsForFile(errFile); @@ -363,7 +405,7 @@ public class CopyServiceTest extends ServiceTestCase<CopyService> { } private Uri createTestDirectory(String dir) throws IOException { - return mStorage.createFile( + return mStorage.createRegularFile( SRC_ROOT, dir, DocumentsContract.Document.MIME_TYPE_DIR, null); } @@ -473,6 +515,7 @@ public class CopyServiceTest extends ServiceTestCase<CopyService> { final CountDownLatch latch = new CountDownLatch(1); final List<DocumentInfo> failedDocs = new ArrayList<>(); + @Override public void onFinished(List<DocumentInfo> failed) { failedDocs.addAll(failed); diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/StubProvider.java b/packages/DocumentsUI/tests/src/com/android/documentsui/StubProvider.java index bcf946e310aa..63a519f4f2a1 100644 --- a/packages/DocumentsUI/tests/src/com/android/documentsui/StubProvider.java +++ b/packages/DocumentsUI/tests/src/com/android/documentsui/StubProvider.java @@ -324,11 +324,11 @@ public class StubProvider extends DocumentsProvider { } for (final String mimeType : document.streamTypes) { // Strict compare won't accept wildcards, but that's OK for tests, as DocumentsUI - // doesn't use them for openTypedDocument. + // doesn't use them for getStreamTypes nor openTypedDocument. if (mimeType.equals(mimeTypeFilter)) { ParcelFileDescriptor pfd = ParcelFileDescriptor.open( document.file, ParcelFileDescriptor.MODE_READ_ONLY); - if (!documentId.equals(mSimulateReadErrors)) { + if (documentId.equals(mSimulateReadErrors)) { pfd = new ParcelFileDescriptor(pfd) { @Override public void checkError() throws IOException { @@ -342,6 +342,23 @@ public class StubProvider extends DocumentsProvider { throw new IllegalArgumentException("Invalid MIME type filter for openTypedDocument()."); } + @Override + public String[] getStreamTypes(Uri uri, String mimeTypeFilter) { + final StubDocument document = mStorage.get(DocumentsContract.getDocumentId(uri)); + if (document == null) { + throw new IllegalArgumentException( + "The provided Uri is incorrect, or the file is gone."); + } + if ((document.flags & Document.FLAG_SUPPORTS_TYPED_DOCUMENT) == 0) { + return null; + } + if (!"*/*".equals(mimeTypeFilter)) { + // Not used by DocumentsUI, so don't bother implementing it. + throw new UnsupportedOperationException(); + } + return document.streamTypes.toArray(new String[document.streamTypes.size()]); + } + private ParcelFileDescriptor startWrite(final StubDocument document) throws FileNotFoundException { ParcelFileDescriptor[] pipe; @@ -476,23 +493,14 @@ public class StubProvider extends DocumentsProvider { } @VisibleForTesting - public Uri createFile(String rootId, String path, String mimeType, byte[] content) + public File createFile(String rootId, String path, String mimeType, byte[] content) throws FileNotFoundException, IOException { Log.d(TAG, "Creating test file " + rootId + ":" + path); StubDocument root = mRoots.get(rootId).document; if (root == null) { throw new FileNotFoundException("No roots with the ID " + rootId + " were found"); } - File file = new File(root.file, path.substring(1)); - StubDocument parent = mStorage.get(getDocumentIdForFile(file.getParentFile())); - 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); - } - + final File file = new File(root.file, path.substring(1)); if (DocumentsContract.Document.MIME_TYPE_DIR.equals(mimeType)) { if (!file.mkdirs()) { throw new FileNotFoundException("Couldn't create directory " + file.getPath()); @@ -501,10 +509,20 @@ public class StubProvider extends DocumentsProvider { if (!file.createNewFile()) { throw new FileNotFoundException("Couldn't create file " + file.getPath()); } - // Add content to the file. - FileOutputStream fout = new FileOutputStream(file); - fout.write(content); - fout.close(); + try (final FileOutputStream fout = new FileOutputStream(file)) { + fout.write(content); + } + } + return file; + } + + @VisibleForTesting + public Uri createRegularFile(String rootId, String path, String mimeType, byte[] content) + throws FileNotFoundException, IOException { + final File file = createFile(rootId, path, mimeType, content); + final StubDocument parent = mStorage.get(getDocumentIdForFile(file.getParentFile())); + if (parent == null) { + throw new FileNotFoundException("Parent not found."); } final StubDocument document = StubDocument.createRegularDocument(file, mimeType, parent); mStorage.put(document.documentId, document); @@ -512,6 +530,21 @@ public class StubProvider extends DocumentsProvider { } @VisibleForTesting + public Uri createVirtualFile( + String rootId, String path, String mimeType, List<String> streamTypes, byte[] content) + throws FileNotFoundException, IOException { + final File file = createFile(rootId, path, mimeType, content); + final StubDocument parent = mStorage.get(getDocumentIdForFile(file.getParentFile())); + if (parent == null) { + throw new FileNotFoundException("Parent not found."); + } + final StubDocument document = StubDocument.createVirtualDocument( + file, mimeType, streamTypes, parent); + mStorage.put(document.documentId, document); + return DocumentsContract.buildDocumentUri(mAuthority, document.documentId); + } + + @VisibleForTesting public File getFile(String rootId, String path) throws FileNotFoundException { StubDocument root = mRoots.get(rootId).document; if (root == null) { |