Move search to roots; Documents root; hide empty.

Documents searches now happen root-wide, instead of only under a
subdirectory.  Updates abstract class and flags to match.  Add flag
for a root to indicate it's empty, and hide empty roots in UI unless
creating.

Define "Documents" public directory and storage backend to contain
files.

Bug: 10712057, 10710865, 10710758
Change-Id: I8716367568969f9cb1d83927b2bf5a7013809350
diff --git a/src/com/android/documentsui/DirectoryFragment.java b/src/com/android/documentsui/DirectoryFragment.java
index b2981db..aee865b 100644
--- a/src/com/android/documentsui/DirectoryFragment.java
+++ b/src/com/android/documentsui/DirectoryFragment.java
@@ -125,9 +125,8 @@
         show(fm, TYPE_NORMAL, root, doc, null);
     }
 
-    public static void showSearch(
-            FragmentManager fm, RootInfo root, DocumentInfo doc, String query) {
-        show(fm, TYPE_SEARCH, root, doc, query);
+    public static void showSearch(FragmentManager fm, RootInfo root, String query) {
+        show(fm, TYPE_SEARCH, root, null, query);
     }
 
     public static void showRecentsOpen(FragmentManager fm) {
@@ -205,7 +204,7 @@
                                 context, mType, root, doc, contentsUri, state.userSortOrder);
                     case TYPE_SEARCH:
                         contentsUri = DocumentsContract.buildSearchDocumentsUri(
-                                doc.authority, doc.documentId, query);
+                                root.authority, root.rootId, query);
                         if (state.action == ACTION_MANAGE) {
                             contentsUri = DocumentsContract.setManageMode(contentsUri);
                         }
@@ -274,7 +273,7 @@
         final RootInfo root = getArguments().getParcelable(EXTRA_ROOT);
         final DocumentInfo doc = getArguments().getParcelable(EXTRA_DOC);
 
-        if (root != null) {
+        if (root != null && doc != null) {
             final Uri stateUri = RecentsProvider.buildState(
                     root.authority, root.rootId, doc.documentId);
             final ContentValues values = new ContentValues();
diff --git a/src/com/android/documentsui/DirectoryLoader.java b/src/com/android/documentsui/DirectoryLoader.java
index 334e262..8627ecf 100644
--- a/src/com/android/documentsui/DirectoryLoader.java
+++ b/src/com/android/documentsui/DirectoryLoader.java
@@ -32,6 +32,7 @@
 import android.net.Uri;
 import android.os.CancellationSignal;
 import android.os.OperationCanceledException;
+import android.provider.DocumentsContract;
 import android.provider.DocumentsContract.Document;
 import android.util.Log;
 
@@ -42,6 +43,8 @@
 
 import libcore.io.IoUtils;
 
+import java.io.FileNotFoundException;
+
 class DirectoryResult implements AutoCloseable {
     ContentProviderClient client;
     Cursor cursor;
@@ -64,7 +67,7 @@
 
     private final int mType;
     private final RootInfo mRoot;
-    private final DocumentInfo mDoc;
+    private DocumentInfo mDoc;
     private final Uri mUri;
     private final int mUserSortOrder;
 
@@ -97,6 +100,19 @@
 
         int userMode = State.MODE_UNKNOWN;
 
+        // Use default document when searching
+        if (mType == DirectoryFragment.TYPE_SEARCH) {
+            final Uri docUri = DocumentsContract.buildDocumentUri(
+                    mRoot.authority, mRoot.documentId);
+            try {
+                mDoc = DocumentInfo.fromUri(resolver, docUri);
+            } catch (FileNotFoundException e) {
+                Log.w(TAG, "Failed to query", e);
+                result.exception = e;
+                return result;
+            }
+        }
+
         // Pick up any custom modes requested by user
         Cursor cursor = null;
         try {
@@ -157,7 +173,7 @@
 
             result.cursor = cursor;
         } catch (Exception e) {
-            Log.d(TAG, "Failed to query", e);
+            Log.w(TAG, "Failed to query", e);
             result.exception = e;
             ContentProviderClient.closeQuietly(result.client);
         } finally {
diff --git a/src/com/android/documentsui/DocumentsActivity.java b/src/com/android/documentsui/DocumentsActivity.java
index eb51fb5..b1e51a0 100644
--- a/src/com/android/documentsui/DocumentsActivity.java
+++ b/src/com/android/documentsui/DocumentsActivity.java
@@ -45,6 +45,7 @@
 import android.os.Bundle;
 import android.os.Parcel;
 import android.provider.DocumentsContract;
+import android.provider.DocumentsContract.Root;
 import android.support.v4.app.ActionBarDrawerToggle;
 import android.support.v4.view.GravityCompat;
 import android.support.v4.widget.DrawerLayout;
@@ -442,6 +443,8 @@
         super.onPrepareOptionsMenu(menu);
 
         final FragmentManager fm = getFragmentManager();
+
+        final RootInfo root = getCurrentRoot();
         final DocumentInfo cwd = getCurrentDirectory();
 
         final MenuItem createDir = menu.findItem(R.id.menu_create_dir);
@@ -503,7 +506,9 @@
             SaveFragment.get(fm).setSaveEnabled(cwd != null && cwd.isCreateSupported());
         } else {
             createDir.setVisible(false);
-            searchVisible = cwd != null && cwd.isSearchSupported();
+
+            searchVisible = root != null
+                    && ((root.flags & Root.FLAG_SUPPORTS_SEARCH) != 0);
         }
 
         // TODO: close any search in-progress when hiding
@@ -722,7 +727,7 @@
         } else {
             if (mState.currentSearch != null) {
                 // Ongoing search
-                DirectoryFragment.showSearch(fm, root, cwd, mState.currentSearch);
+                DirectoryFragment.showSearch(fm, root, mState.currentSearch);
             } else {
                 // Normal boring directory
                 DirectoryFragment.showNormal(fm, root, cwd);
diff --git a/src/com/android/documentsui/RootsCache.java b/src/com/android/documentsui/RootsCache.java
index b48674c..4d313e8 100644
--- a/src/com/android/documentsui/RootsCache.java
+++ b/src/com/android/documentsui/RootsCache.java
@@ -176,6 +176,7 @@
             final boolean supportsCreate = (root.flags & Root.FLAG_SUPPORTS_CREATE) != 0;
             final boolean advanced = (root.flags & Root.FLAG_ADVANCED) != 0;
             final boolean localOnly = (root.flags & Root.FLAG_LOCAL_ONLY) != 0;
+            final boolean empty = (root.flags & Root.FLAG_EMPTY) != 0;
 
             // Exclude read-only devices when creating
             if (state.action == State.ACTION_CREATE && !supportsCreate) continue;
@@ -183,6 +184,8 @@
             if (!state.showAdvanced && advanced) continue;
             // Exclude non-local devices when local only
             if (state.localOnly && !localOnly) continue;
+            // Only show empty roots when creating
+            if (state.action != State.ACTION_CREATE && empty) continue;
 
             // Only include roots that serve requested content
             final boolean overlap =
diff --git a/src/com/android/documentsui/model/DocumentInfo.java b/src/com/android/documentsui/model/DocumentInfo.java
index c69103e..ab55d94 100644
--- a/src/com/android/documentsui/model/DocumentInfo.java
+++ b/src/com/android/documentsui/model/DocumentInfo.java
@@ -188,10 +188,6 @@
         return (flags & Document.FLAG_DIR_SUPPORTS_CREATE) != 0;
     }
 
-    public boolean isSearchSupported() {
-        return (flags & Document.FLAG_DIR_SUPPORTS_SEARCH) != 0;
-    }
-
     public boolean isThumbnailSupported() {
         return (flags & Document.FLAG_SUPPORTS_THUMBNAIL) != 0;
     }
diff --git a/src/com/android/documentsui/model/RootInfo.java b/src/com/android/documentsui/model/RootInfo.java
index b5a198c..1afc80a 100644
--- a/src/com/android/documentsui/model/RootInfo.java
+++ b/src/com/android/documentsui/model/RootInfo.java
@@ -161,15 +161,21 @@
 
         // TODO: remove these special case icons
         if ("com.android.externalstorage.documents".equals(authority)) {
-            derivedIcon = R.drawable.ic_root_sdcard;
+            if ("documents".equals(rootId)) {
+                derivedIcon = R.drawable.ic_doc_text;
+            } else {
+                derivedIcon = R.drawable.ic_root_sdcard;
+            }
         }
         if ("com.android.providers.downloads.documents".equals(authority)) {
             derivedIcon = R.drawable.ic_root_download;
         }
         if ("com.android.providers.media.documents".equals(authority)) {
-            if ("image".equals(rootId)) {
+            if ("images_root".equals(rootId)) {
                 derivedIcon = R.drawable.ic_doc_image;
-            } else if ("audio".equals(rootId)) {
+            } else if ("videos_root".equals(rootId)) {
+                derivedIcon = R.drawable.ic_doc_video;
+            } else if ("audio_root".equals(rootId)) {
                 derivedIcon = R.drawable.ic_doc_audio;
             }
         }