Merge "Filter roots based on supported MIME types." into klp-dev
diff --git a/api/current.txt b/api/current.txt
index 231f131..5b2543b 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -20786,17 +20786,15 @@
     field public static final java.lang.String COLUMN_DOCUMENT_ID = "document_id";
     field public static final java.lang.String COLUMN_FLAGS = "flags";
     field public static final java.lang.String COLUMN_ICON = "icon";
+    field public static final java.lang.String COLUMN_MIME_TYPES = "mime_types";
     field public static final java.lang.String COLUMN_ROOT_ID = "root_id";
     field public static final java.lang.String COLUMN_ROOT_TYPE = "root_type";
     field public static final java.lang.String COLUMN_SUMMARY = "summary";
     field public static final java.lang.String COLUMN_TITLE = "title";
     field public static final int FLAG_ADVANCED = 4; // 0x4
     field public static final int FLAG_LOCAL_ONLY = 2; // 0x2
-    field public static final int FLAG_PROVIDES_AUDIO = 8; // 0x8
-    field public static final int FLAG_PROVIDES_IMAGES = 32; // 0x20
-    field public static final int FLAG_PROVIDES_VIDEO = 16; // 0x10
     field public static final int FLAG_SUPPORTS_CREATE = 1; // 0x1
-    field public static final int FLAG_SUPPORTS_RECENTS = 64; // 0x40
+    field public static final int FLAG_SUPPORTS_RECENTS = 8; // 0x8
     field public static final int ROOT_TYPE_DEVICE = 3; // 0x3
     field public static final int ROOT_TYPE_SERVICE = 1; // 0x1
     field public static final int ROOT_TYPE_SHORTCUT = 2; // 0x2
diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java
index f445fd5..13b6cfb 100644
--- a/core/java/android/provider/DocumentsContract.java
+++ b/core/java/android/provider/DocumentsContract.java
@@ -337,6 +337,16 @@
         public static final String COLUMN_AVAILABLE_BYTES = "available_bytes";
 
         /**
+         * MIME types supported by this root, or {@code null} if the root
+         * supports all MIME types. Multiple MIME types can be separated by a
+         * newline. For example, a root supporting audio might use
+         * "audio/*\napplication/x-flac".
+         * <p>
+         * Type: String
+         */
+        public static final String COLUMN_MIME_TYPES = "mime_types";
+
+        /**
          * Type of root that represents a storage service, such as a cloud-based
          * service.
          *
@@ -386,40 +396,13 @@
         public static final int FLAG_ADVANCED = 1 << 2;
 
         /**
-         * Flag indicating that a root offers audio documents. When a user is
-         * selecting audio, roots not providing audio may be excluded.
-         *
-         * @see #COLUMN_FLAGS
-         * @see Intent#EXTRA_MIME_TYPES
-         */
-        public static final int FLAG_PROVIDES_AUDIO = 1 << 3;
-
-        /**
-         * Flag indicating that a root offers video documents. When a user is
-         * selecting video, roots not providing video may be excluded.
-         *
-         * @see #COLUMN_FLAGS
-         * @see Intent#EXTRA_MIME_TYPES
-         */
-        public static final int FLAG_PROVIDES_VIDEO = 1 << 4;
-
-        /**
-         * Flag indicating that a root offers image documents. When a user is
-         * selecting images, roots not providing images may be excluded.
-         *
-         * @see #COLUMN_FLAGS
-         * @see Intent#EXTRA_MIME_TYPES
-         */
-        public static final int FLAG_PROVIDES_IMAGES = 1 << 5;
-
-        /**
          * Flag indicating that this root can report recently modified
          * documents.
          *
          * @see #COLUMN_FLAGS
          * @see DocumentsContract#buildRecentDocumentsUri(String, String)
          */
-        public static final int FLAG_SUPPORTS_RECENTS = 1 << 6;
+        public static final int FLAG_SUPPORTS_RECENTS = 1 << 3;
     }
 
     /**
diff --git a/packages/DocumentsUI/src/com/android/documentsui/MimePredicate.java b/packages/DocumentsUI/src/com/android/documentsui/MimePredicate.java
index 15ad061..c65464a 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/MimePredicate.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/MimePredicate.java
@@ -16,9 +16,13 @@
 
 package com.android.documentsui;
 
+import android.util.Log;
+
 import com.android.documentsui.model.DocumentInfo;
 import com.android.internal.util.Predicate;
 
+import java.util.Arrays;
+
 public class MimePredicate implements Predicate<DocumentInfo> {
     private final String[] mFilters;
 
@@ -31,16 +35,29 @@
         if (doc.isDirectory()) {
             return true;
         }
-        for (String filter : mFilters) {
-            if (mimeMatches(filter, doc.mimeType)) {
+        if (mimeMatches(mFilters, doc.mimeType)) {
+            return true;
+        }
+        return false;
+    }
+
+    public static boolean mimeMatches(String[] filters, String[] tests) {
+        if (tests == null) {
+            return false;
+        }
+        for (String test : tests) {
+            if (mimeMatches(filters, test)) {
                 return true;
             }
         }
         return false;
     }
 
-    public static boolean mimeMatches(String filter, String[] tests) {
-        for (String test : tests) {
+    public static boolean mimeMatches(String[] filters, String test) {
+        if (filters == null) {
+            return true;
+        }
+        for (String filter : filters) {
             if (mimeMatches(filter, test)) {
                 return true;
             }
@@ -49,12 +66,12 @@
     }
 
     public static boolean mimeMatches(String filter, String test) {
-        if (test == null) {
+        if (filter == null || "*/*".equals(filter)) {
+            return true;
+        } else if (test == null) {
             return false;
         } else if (filter.equals(test)) {
             return true;
-        } else if ("*/*".equals(filter)) {
-            return true;
         } else if (filter.endsWith("/*")) {
             return filter.regionMatches(0, test, 0, filter.indexOf('/'));
         } else {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java b/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
index 0625011..d192378 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
@@ -21,15 +21,11 @@
 import android.content.ContentProviderClient;
 import android.content.ContentResolver;
 import android.content.Context;
-import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.content.pm.ProviderInfo;
-import android.content.pm.ResolveInfo;
 import android.database.Cursor;
-import android.graphics.drawable.Drawable;
 import android.net.Uri;
 import android.provider.DocumentsContract;
-import android.provider.DocumentsContract.Document;
 import android.provider.DocumentsContract.Root;
 import android.util.Log;
 
@@ -153,33 +149,8 @@
         return mRoots;
     }
 
-    /**
-     * Flags that declare explicit content types.
-     */
-    private static final int FLAGS_CONTENT_MASK = Root.FLAG_PROVIDES_IMAGES
-            | Root.FLAG_PROVIDES_AUDIO | Root.FLAG_PROVIDES_VIDEO;
-
     @GuardedBy("ActivityThread")
     public List<RootInfo> getMatchingRoots(State state) {
-
-        // Determine acceptable content flags
-        int includeFlags = 0;
-        for (String acceptMime : state.acceptMimes) {
-            final String[] type = acceptMime.split("/");
-            if (type.length != 2) continue;
-
-            if ("image".equals(type[0])) {
-                includeFlags |= Root.FLAG_PROVIDES_IMAGES;
-            } else if ("audio".equals(type[0])) {
-                includeFlags |= Root.FLAG_PROVIDES_AUDIO;
-            } else if ("video".equals(type[0])) {
-                includeFlags |= Root.FLAG_PROVIDES_VIDEO;
-            } else if ("*".equals(type[0])) {
-                includeFlags |= Root.FLAG_PROVIDES_IMAGES | Root.FLAG_PROVIDES_AUDIO
-                        | Root.FLAG_PROVIDES_VIDEO;
-            }
-        }
-
         ArrayList<RootInfo> matching = Lists.newArrayList();
         for (RootInfo root : mRoots) {
             final boolean supportsCreate = (root.flags & Root.FLAG_SUPPORTS_CREATE) != 0;
@@ -193,13 +164,9 @@
             // Exclude non-local devices when local only
             if (state.localOnly && !localOnly) continue;
 
-            if ((root.flags & FLAGS_CONTENT_MASK) != 0) {
-                // This root offers specific content, so only include if the
-                // caller asked for that content type.
-                if ((root.flags & includeFlags) == 0) {
-                    // Sorry, no overlap.
-                    continue;
-                }
+            // Only include roots that serve requested content
+            if (!MimePredicate.mimeMatches(root.mimeTypes, state.acceptMimes)) {
+                continue;
             }
 
             matching.add(root);
diff --git a/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java b/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java
index c3698a0..75baa0a 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java
@@ -42,6 +42,7 @@
     public String summary;
     public String documentId;
     public long availableBytes;
+    public String[] mimeTypes;
 
     public static RootInfo fromRootsCursor(String authority, Cursor cursor) {
         final RootInfo root = new RootInfo();
@@ -55,11 +56,8 @@
         root.documentId = getCursorString(cursor, Root.COLUMN_DOCUMENT_ID);
         root.availableBytes = getCursorLong(cursor, Root.COLUMN_AVAILABLE_BYTES);
 
-        // TODO: remove this hack
-        if ("com.google.android.apps.docs.storage".equals(root.authority)) {
-            root.flags &= ~(Root.FLAG_PROVIDES_AUDIO | Root.FLAG_PROVIDES_IMAGES
-                    | Root.FLAG_PROVIDES_VIDEO);
-        }
+        final String raw = getCursorString(cursor, Root.COLUMN_MIME_TYPES);
+        root.mimeTypes = (raw != null) ? raw.split("\n") : null;
 
         return root;
     }