diff --git a/api/current.txt b/api/current.txt index 2338373194b8e..4bc700c908636 100644 --- a/api/current.txt +++ b/api/current.txt @@ -30788,6 +30788,7 @@ package android.provider { field public static final int FLAG_SUPPORTS_MOVE = 256; // 0x100 field public static final int FLAG_SUPPORTS_RENAME = 64; // 0x40 field public static final int FLAG_SUPPORTS_THUMBNAIL = 1; // 0x1 + field public static final int FLAG_SUPPORTS_TYPED_DOCUMENT = 512; // 0x200 field public static final int FLAG_SUPPORTS_WRITE = 2; // 0x2 field public static final int FLAG_VIRTUAL_DOCUMENT = 1024; // 0x400 field public static final java.lang.String MIME_TYPE_DIR = "vnd.android.document/directory"; diff --git a/api/system-current.txt b/api/system-current.txt index 460e5b9c7709e..ca6aa9382cd84 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -32821,6 +32821,7 @@ package android.provider { field public static final int FLAG_SUPPORTS_MOVE = 256; // 0x100 field public static final int FLAG_SUPPORTS_RENAME = 64; // 0x40 field public static final int FLAG_SUPPORTS_THUMBNAIL = 1; // 0x1 + field public static final int FLAG_SUPPORTS_TYPED_DOCUMENT = 512; // 0x200 field public static final int FLAG_SUPPORTS_WRITE = 2; // 0x2 field public static final int FLAG_VIRTUAL_DOCUMENT = 1024; // 0x400 field public static final java.lang.String MIME_TYPE_DIR = "vnd.android.document/directory"; diff --git a/api/test-current.txt b/api/test-current.txt index 5a2d483286000..81e7449582b68 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -30800,6 +30800,7 @@ package android.provider { field public static final int FLAG_SUPPORTS_MOVE = 256; // 0x100 field public static final int FLAG_SUPPORTS_RENAME = 64; // 0x40 field public static final int FLAG_SUPPORTS_THUMBNAIL = 1; // 0x1 + field public static final int FLAG_SUPPORTS_TYPED_DOCUMENT = 512; // 0x200 field public static final int FLAG_SUPPORTS_WRITE = 2; // 0x2 field public static final int FLAG_VIRTUAL_DOCUMENT = 1024; // 0x400 field public static final java.lang.String MIME_TYPE_DIR = "vnd.android.document/directory"; diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java index a401ac2ff864e..084ff7728ca4d 100644 --- a/core/java/android/provider/DocumentsContract.java +++ b/core/java/android/provider/DocumentsContract.java @@ -230,6 +230,7 @@ public final class DocumentsContract { * @see #FLAG_SUPPORTS_WRITE * @see #FLAG_SUPPORTS_DELETE * @see #FLAG_SUPPORTS_THUMBNAIL + * @see #FLAG_SUPPORTS_TYPED_DOCUMENT * @see #FLAG_DIR_PREFERS_GRID * @see #FLAG_DIR_PREFERS_LAST_MODIFIED * @see #FLAG_VIRTUAL_DOCUMENT @@ -347,6 +348,15 @@ public final class DocumentsContract { */ public static final int FLAG_SUPPORTS_MOVE = 1 << 8; + /** + * Flag indicating that a document can be converted to alternative types. + * + * @see #COLUMN_FLAGS + * @see DocumentsProvider#openTypedDocument(String, String, Bundle, + * android.os.CancellationSignal) + */ + public static final int FLAG_SUPPORTS_TYPED_DOCUMENT = 1 << 9; + /** * Flag indicating that a document is virtual, and doesn't have byte * representation in the MIME type specified as {@link #COLUMN_MIME_TYPE}. @@ -356,7 +366,7 @@ public final class DocumentsContract { * @see DocumentsProvider#openTypedDocument(String, String, Bundle, * android.os.CancellationSignal) */ - public static final int FLAG_VIRTUAL_DOCUMENT = 1 << 9; + public static final int FLAG_VIRTUAL_DOCUMENT = 1 << 10; /** * Flag indicating that a document is an archive, and it's contents can be @@ -368,7 +378,7 @@ public final class DocumentsContract { * @see #COLUMN_FLAGS * @see DocumentsProvider#queryChildDocuments(String, String[], String) */ - public static final int FLAG_ARCHIVE = 1 << 10; + public static final int FLAG_ARCHIVE = 1 << 11; /** * Flag indicating that document titles should be hidden when viewing diff --git a/core/java/android/provider/DocumentsProvider.java b/core/java/android/provider/DocumentsProvider.java index 94b41575d0a36..e25ba35c8bb6c 100644 --- a/core/java/android/provider/DocumentsProvider.java +++ b/core/java/android/provider/DocumentsProvider.java @@ -517,12 +517,13 @@ public abstract class DocumentsProvider extends ContentProvider { * provider. * @param signal used by the caller to signal if the request should be * cancelled. May be null. + * @see Document#FLAG_SUPPORTS_TYPED_DOCUMENT */ @SuppressWarnings("unused") public AssetFileDescriptor openTypedDocument( String documentId, String mimeTypeFilter, Bundle opts, CancellationSignal signal) throws FileNotFoundException { - throw new FileNotFoundException("The requested MIME type is not supported."); + throw new UnsupportedOperationException("Typed documents not supported"); } /** diff --git a/packages/DocumentsUI/src/com/android/documentsui/CopyService.java b/packages/DocumentsUI/src/com/android/documentsui/CopyService.java index 34614b414645d..6a5911bb1bfd2 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/CopyService.java +++ b/packages/DocumentsUI/src/com/android/documentsui/CopyService.java @@ -502,6 +502,11 @@ 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()) { + 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 != null && streamTypes.length > 0) { @@ -511,7 +516,8 @@ public class CopyService extends IntentService { dstDisplayName = srcInfo.displayName + (extension != null ? "." + extension : srcInfo.displayName); } else { - // The virtual file is not available as any alternative streamable format. + // 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; @@ -634,8 +640,9 @@ public class CopyService extends IntentService { boolean success = true; try { - // If the file is virtual, then try to copy it as an alternative format. - if (srcInfo.isVirtualDocument()) { + // If the file is virtual, but can be converted to another format, then try to copy it + // as such format. + if (srcInfo.isVirtualDocument() && srcInfo.isTypedDocument()) { final AssetFileDescriptor srcFileAsAsset = mSrcClient.openTypedAssetFileDescriptor( srcInfo.derivedUri, mimeType, null, canceller); diff --git a/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java b/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java index 83df18cdca132..215c6e696bb7d 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java +++ b/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java @@ -255,6 +255,10 @@ public class DocumentInfo implements Durable, Parcelable { return (flags & Document.FLAG_VIRTUAL_DOCUMENT) != 0; } + public boolean isTypedDocument() { + return (flags & Document.FLAG_SUPPORTS_TYPED_DOCUMENT) != 0; + } + public int hashCode() { return derivedUri.hashCode() + mimeType.hashCode(); } diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/CopyServiceTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/CopyServiceTest.java index 4ce018529356a..24a811393b650 100644 --- a/packages/DocumentsUI/tests/src/com/android/documentsui/CopyServiceTest.java +++ b/packages/DocumentsUI/tests/src/com/android/documentsui/CopyServiceTest.java @@ -311,8 +311,10 @@ public class CopyServiceTest extends ServiceTestCase { public void testCopyVirtualNonTypedFile() throws Exception { String srcPath = "/non-typed.sth"; + // Empty stream types causes the FLAG_SUPPORTS_TYPED_DOCUMENT to be not set. + ArrayList streamTypes = new ArrayList<>(); Uri testFile = mStorage.createVirtualFile(SRC_ROOT, srcPath, "virtual/mime-type", - null /* streamTypes */, "I love Tokyo!".getBytes()); + streamTypes, "I love Tokyo!".getBytes()); Intent intent = createCopyIntent(Lists.newArrayList(testFile)); startService(intent); diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/StubProvider.java b/packages/DocumentsUI/tests/src/com/android/documentsui/StubProvider.java index 50f462807bfeb..2c311a7cc1928 100644 --- a/packages/DocumentsUI/tests/src/com/android/documentsui/StubProvider.java +++ b/packages/DocumentsUI/tests/src/com/android/documentsui/StubProvider.java @@ -316,9 +316,12 @@ public class StubProvider extends DocumentsProvider { String documentId, String mimeTypeFilter, Bundle opts, CancellationSignal signal) throws FileNotFoundException { final StubDocument document = mStorage.get(documentId); - if (document == null || !document.file.isFile() || document.streamTypes == null) { + if (document == null || !document.file.isFile()) { throw new FileNotFoundException(); } + if ((document.flags & Document.FLAG_SUPPORTS_TYPED_DOCUMENT) == 0) { + throw new IllegalStateException("Tried to open a non-typed document as typed."); + } 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 getStreamTypes nor openTypedDocument. @@ -346,13 +349,13 @@ public class StubProvider extends DocumentsProvider { 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(); } - if (document.streamTypes == null) { - return null; - } return document.streamTypes.toArray(new String[document.streamTypes.size()]); } @@ -625,6 +628,9 @@ public class StubProvider extends DocumentsProvider { File file, String mimeType, List streamTypes, StubDocument parent) { int flags = Document.FLAG_SUPPORTS_DELETE | Document.FLAG_SUPPORTS_WRITE | Document.FLAG_VIRTUAL_DOCUMENT; + if (streamTypes.size() > 0) { + flags |= Document.FLAG_SUPPORTS_TYPED_DOCUMENT; + } return new StubDocument(file, mimeType, streamTypes, flags, parent); }