Send virtual files with CATEGORY_TYPED_OPENABLE.

Test: Unit tests. Also tested manually with a testing apk.
Bug: 28409713
Change-Id: I086664d092f70ae4bba5dcf364c642ccb36590db
(cherry picked from commit d91a1854a08b542da2196da14ab8bd6217743ceb)
diff --git a/src/com/android/documentsui/dirlist/Model.java b/src/com/android/documentsui/dirlist/Model.java
index 64dc3d1..259529a 100644
--- a/src/com/android/documentsui/dirlist/Model.java
+++ b/src/com/android/documentsui/dirlist/Model.java
@@ -54,16 +54,23 @@
 public class Model {
 
     /**
-     * Filter that passes (returns true) all non-virtual, non-partial files, not archived files.
+     * Filter that passes (returns true) all non-partial files and non-archived files.
      */
-    public static final Predicate<Cursor> CONCRETE_FILE_FILTER = (Cursor c) -> {
+    public static final Predicate<Cursor> NO_PARTIAL_NOR_ARCHIVED_FILE_FILTER = (Cursor c) -> {
         int flags = getCursorInt(c, Document.COLUMN_FLAGS);
         String authority = getCursorString(c, RootCursorWrapper.COLUMN_AUTHORITY);
-        return (flags & Document.FLAG_VIRTUAL_DOCUMENT) == 0
-                && (flags & Document.FLAG_PARTIAL) == 0
+        return (flags & Document.FLAG_PARTIAL) == 0
                 && !ArchivesProvider.AUTHORITY.equals(authority);
     };
 
+    /**
+     * Filter that passes (returns true) only virtual documents.
+     */
+    public static final Predicate<Cursor> VIRTUAL_DOCUMENT_FILTER  = (Cursor c) -> {
+        int flags = getCursorInt(c, Document.COLUMN_FLAGS);
+        return (flags & Document.FLAG_VIRTUAL_DOCUMENT) != 0;
+    };
+
     private static final Predicate<Cursor> ANY_FILE_FILTER = (Cursor c) -> true;
 
     private static final String TAG = "Model";
diff --git a/src/com/android/documentsui/files/ActionHandler.java b/src/com/android/documentsui/files/ActionHandler.java
index e0583a2..fd5959a 100644
--- a/src/com/android/documentsui/files/ActionHandler.java
+++ b/src/com/android/documentsui/files/ActionHandler.java
@@ -290,23 +290,21 @@
 
         // Model must be accessed in UI thread, since underlying cursor is not threadsafe.
         List<DocumentInfo> docs =
-                mScope.model.loadDocuments(selection, Model.CONCRETE_FILE_FILTER);
+                mScope.model.loadDocuments(selection, Model.NO_PARTIAL_NOR_ARCHIVED_FILE_FILTER);
+
+        List<DocumentInfo> virtualDocs =
+                mScope.model.loadDocuments(selection, Model.VIRTUAL_DOCUMENT_FILTER);
 
         Intent intent;
 
         if (docs.size() == 1) {
-            final DocumentInfo doc = docs.get(0);
-
             intent = new Intent(Intent.ACTION_SEND);
-            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
-            intent.addCategory(Intent.CATEGORY_DEFAULT);
+            DocumentInfo doc = docs.get(0);
             intent.setType(doc.mimeType);
             intent.putExtra(Intent.EXTRA_STREAM, doc.derivedUri);
 
         } else if (docs.size() > 1) {
             intent = new Intent(Intent.ACTION_SEND_MULTIPLE);
-            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
-            intent.addCategory(Intent.CATEGORY_DEFAULT);
 
             final ArrayList<String> mimeTypes = new ArrayList<>();
             final ArrayList<Uri> uris = new ArrayList<>();
@@ -319,9 +317,16 @@
             intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris);
 
         } else {
+            // Everything filtered out, nothing to share.
             return;
         }
 
+        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+        intent.addCategory(Intent.CATEGORY_DEFAULT);
+        if (virtualDocs.size() > 0) {
+            intent.addCategory(Intent.CATEGORY_TYPED_OPENABLE);
+        }
+
         Intent chooserIntent = Intent.createChooser(
                 intent, mActivity.getResources().getText(R.string.share_via));
 
diff --git a/tests/unit/com/android/documentsui/files/ActionHandlerTest.java b/tests/unit/com/android/documentsui/files/ActionHandlerTest.java
index 4470b99..a13c5df 100644
--- a/tests/unit/com/android/documentsui/files/ActionHandlerTest.java
+++ b/tests/unit/com/android/documentsui/files/ActionHandlerTest.java
@@ -24,6 +24,7 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 
 import android.content.Intent;
@@ -35,6 +36,7 @@
 
 import com.android.documentsui.R;
 import com.android.documentsui.TestActionModeAddons;
+import com.android.documentsui.archives.ArchivesProvider;
 import com.android.documentsui.base.DocumentInfo;
 import com.android.documentsui.base.DocumentStack;
 import com.android.documentsui.base.RootInfo;
@@ -183,10 +185,26 @@
 
         Intent intent = assertHasExtraIntent(mActivity.startActivity.getLastValue());
         assertHasAction(intent, Intent.ACTION_SEND);
+        assertFalse(intent.hasCategory(Intent.CATEGORY_TYPED_OPENABLE));
+        assertFalse(intent.hasCategory(Intent.CATEGORY_OPENABLE));
         assertHasExtraUri(intent, Intent.EXTRA_STREAM);
     }
 
     @Test
+    public void testShareSelectedDocuments_ArchivedFile() {
+        mEnv = TestEnv.create(ArchivesProvider.AUTHORITY);
+        mHandler.reset(mEnv.model, false);
+
+        mActivity.resources.strings.put(R.string.share_via, "Sharezilla!");
+        mEnv.selectionMgr.clearSelection();
+        mEnv.selectDocument(TestEnv.FILE_PDF);
+        mHandler.shareSelectedDocuments();
+
+        Intent intent = mActivity.startActivity.getLastValue();
+        assertNull(intent);
+    }
+
+    @Test
     public void testShareSelectedDocuments_Multiple() {
         mActivity.resources.strings.put(R.string.share_via, "Sharezilla!");
         mEnv.selectDocument(TestEnv.FILE_PDF);
@@ -194,21 +212,40 @@
 
         Intent intent = assertHasExtraIntent(mActivity.startActivity.getLastValue());
         assertHasAction(intent, Intent.ACTION_SEND_MULTIPLE);
+        assertFalse(intent.hasCategory(Intent.CATEGORY_TYPED_OPENABLE));
+        assertFalse(intent.hasCategory(Intent.CATEGORY_OPENABLE));
         assertHasExtraList(intent, Intent.EXTRA_STREAM, 2);
     }
 
     @Test
-    public void testShareSelectedDocuments_OmitsVirtualFiles() {
+    public void testShareSelectedDocuments_VirtualFiles() {
         mActivity.resources.strings.put(R.string.share_via, "Sharezilla!");
+        mEnv.selectionMgr.clearSelection();
         mEnv.selectDocument(TestEnv.FILE_VIRTUAL);
         mHandler.shareSelectedDocuments();
 
         Intent intent = assertHasExtraIntent(mActivity.startActivity.getLastValue());
         assertHasAction(intent, Intent.ACTION_SEND);
+        assertTrue(intent.hasCategory(Intent.CATEGORY_TYPED_OPENABLE));
+        assertFalse(intent.hasCategory(Intent.CATEGORY_OPENABLE));
         assertHasExtraUri(intent, Intent.EXTRA_STREAM);
     }
 
     @Test
+    public void testShareSelectedDocuments_RegularAndVirtualFiles() {
+        mActivity.resources.strings.put(R.string.share_via, "Sharezilla!");
+        mEnv.selectDocument(TestEnv.FILE_PNG);
+        mEnv.selectDocument(TestEnv.FILE_VIRTUAL);
+        mHandler.shareSelectedDocuments();
+
+        Intent intent = assertHasExtraIntent(mActivity.startActivity.getLastValue());
+        assertHasAction(intent, Intent.ACTION_SEND_MULTIPLE);
+        assertTrue(intent.hasCategory(Intent.CATEGORY_TYPED_OPENABLE));
+        assertFalse(intent.hasCategory(Intent.CATEGORY_OPENABLE));
+        assertHasExtraList(intent, Intent.EXTRA_STREAM, 3);
+    }
+
+    @Test
     public void testShareSelectedDocuments_OmitsPartialFiles() {
         mActivity.resources.strings.put(R.string.share_via, "Sharezilla!");
         mEnv.selectDocument(TestEnv.FILE_PARTIAL);
@@ -217,6 +254,8 @@
 
         Intent intent = assertHasExtraIntent(mActivity.startActivity.getLastValue());
         assertHasAction(intent, Intent.ACTION_SEND_MULTIPLE);
+        assertFalse(intent.hasCategory(Intent.CATEGORY_TYPED_OPENABLE));
+        assertFalse(intent.hasCategory(Intent.CATEGORY_OPENABLE));
         assertHasExtraList(intent, Intent.EXTRA_STREAM, 2);
     }