am 12c7a0c9: Merge "More UX updates around picking images." into klp-dev

* commit '12c7a0c970dfa56391f1e7f7a8ed41348acb14c4':
  More UX updates around picking images.
diff --git a/api/current.txt b/api/current.txt
index d4e23f3..57384a7 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -20812,6 +20812,7 @@
     field public static final java.lang.String COLUMN_MIME_TYPE = "mime_type";
     field public static final java.lang.String COLUMN_SIZE = "_size";
     field public static final java.lang.String COLUMN_SUMMARY = "summary";
+    field public static final int FLAG_DIR_HIDE_GRID_TITLES = 64; // 0x40
     field public static final int FLAG_DIR_PREFERS_GRID = 16; // 0x10
     field public static final int FLAG_DIR_PREFERS_LAST_MODIFIED = 32; // 0x20
     field public static final int FLAG_DIR_SUPPORTS_CREATE = 8; // 0x8
diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java
index 231e6a6..3f33e80 100644
--- a/core/java/android/provider/DocumentsContract.java
+++ b/core/java/android/provider/DocumentsContract.java
@@ -257,6 +257,18 @@
          * @see #COLUMN_FLAGS
          */
         public static final int FLAG_DIR_PREFERS_LAST_MODIFIED = 1 << 5;
+
+        /**
+         * Flag indicating that document titles should be hidden when viewing
+         * this directory in a larger format grid. For example, a directory
+         * containing only images may want the image thumbnails to speak for
+         * themselves. Only valid when {@link #COLUMN_MIME_TYPE} is
+         * {@link #MIME_TYPE_DIR}.
+         *
+         * @see #COLUMN_FLAGS
+         * @see #FLAG_DIR_PREFERS_GRID
+         */
+        public static final int FLAG_DIR_HIDE_GRID_TITLES = 1 << 6;
     }
 
     /**
diff --git a/packages/DocumentsUI/res/layout/item_doc_grid.xml b/packages/DocumentsUI/res/layout/item_doc_grid.xml
index 3cfae64..b745bb9 100644
--- a/packages/DocumentsUI/res/layout/item_doc_grid.xml
+++ b/packages/DocumentsUI/res/layout/item_doc_grid.xml
@@ -30,6 +30,7 @@
             android:layout_width="match_parent"
             android:layout_height="0dip"
             android:layout_weight="1"
+            android:layout_marginBottom="6dp"
             android:background="#fff">
 
             <FrameLayout
@@ -63,10 +64,10 @@
         </FrameLayout>
 
         <LinearLayout
+            android:id="@+id/line1"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:orientation="horizontal"
-            android:paddingTop="6dp"
             android:paddingStart="?android:attr/listPreferredItemPaddingStart"
             android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
 
@@ -121,6 +122,20 @@
                 android:textAlignment="viewStart"
                 style="@style/TextAppearance.Small" />
 
+            <Space
+                android:layout_width="0dp"
+                android:layout_height="0dp"
+                android:layout_weight="1" />
+
+            <ImageView
+                android:id="@android:id/icon2"
+                android:layout_width="@dimen/root_icon_size"
+                android:layout_height="@dimen/root_icon_size"
+                android:layout_marginStart="8dip"
+                android:scaleType="centerInside"
+                android:contentDescription="@null"
+                android:visibility="gone" />
+
         </LinearLayout>
 
     </LinearLayout>
diff --git a/packages/DocumentsUI/res/menu/activity.xml b/packages/DocumentsUI/res/menu/activity.xml
index 6c37a4e..d995376 100644
--- a/packages/DocumentsUI/res/menu/activity.xml
+++ b/packages/DocumentsUI/res/menu/activity.xml
@@ -19,7 +19,7 @@
         android:id="@+id/menu_create_dir"
         android:title="@string/menu_create_dir"
         android:icon="@drawable/ic_menu_new_folder"
-        android:showAsAction="ifRoom" />
+        android:showAsAction="always" />
     <item
         android:id="@+id/menu_search"
         android:title="@string/menu_search"
@@ -48,12 +48,12 @@
         android:id="@+id/menu_grid"
         android:title="@string/menu_grid"
         android:icon="@drawable/ic_menu_view_grid"
-        android:showAsAction="ifRoom" />
+        android:showAsAction="never" />
     <item
         android:id="@+id/menu_list"
         android:title="@string/menu_list"
         android:icon="@drawable/ic_menu_view_list"
-        android:showAsAction="ifRoom" />
+        android:showAsAction="never" />
     <item
         android:id="@+id/menu_settings"
         android:title="@string/menu_settings"
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
index aee865b..198927c 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
@@ -102,6 +102,8 @@
     private int mLastSortOrder = SORT_ORDER_UNKNOWN;
     private boolean mLastShowSize = false;
 
+    private boolean mHideGridTitles = false;
+
     private Point mThumbSize;
 
     private DocumentsAdapter mAdapter;
@@ -112,11 +114,6 @@
     private static final String EXTRA_DOC = "doc";
     private static final String EXTRA_QUERY = "query";
 
-    /**
-     * MIME types that should always show thumbnails in list mode.
-     */
-    private static final String[] LIST_THUMBNAIL_MIMES = new String[] { "image/*", "video/*" };
-
     private static AtomicInteger sLoaderId = new AtomicInteger(4000);
 
     private final int mLoaderId = sLoaderId.incrementAndGet();
@@ -182,14 +179,23 @@
         final Context context = getActivity();
         final State state = getDisplayState(DirectoryFragment.this);
 
+        final RootInfo root = getArguments().getParcelable(EXTRA_ROOT);
+        final DocumentInfo doc = getArguments().getParcelable(EXTRA_DOC);
+
         mAdapter = new DocumentsAdapter();
         mType = getArguments().getInt(EXTRA_TYPE);
 
+        if (mType == TYPE_RECENT_OPEN) {
+            // Hide titles when showing recents for picking images/videos
+            mHideGridTitles = MimePredicate.mimeMatches(
+                    MimePredicate.VISUAL_MIMES, state.acceptMimes);
+        } else {
+            mHideGridTitles = (doc != null) && doc.isGridTitlesHidden();
+        }
+
         mCallbacks = new LoaderCallbacks<DirectoryResult>() {
             @Override
             public Loader<DirectoryResult> onCreateLoader(int id, Bundle args) {
-                final RootInfo root = getArguments().getParcelable(EXTRA_ROOT);
-                final DocumentInfo doc = getArguments().getParcelable(EXTRA_DOC);
                 final String query = getArguments().getString(EXTRA_QUERY);
 
                 Uri contentsUri;
@@ -643,6 +649,8 @@
             final Context context = parent.getContext();
             final State state = getDisplayState(DirectoryFragment.this);
 
+            final DocumentInfo doc = getArguments().getParcelable(EXTRA_DOC);
+
             final RootsCache roots = DocumentsApplication.getRootsCache(context);
             final ThumbnailCache thumbs = DocumentsApplication.getThumbnailsCache(
                     context, mThumbSize);
@@ -671,12 +679,15 @@
             final String docSummary = getCursorString(cursor, Document.COLUMN_SUMMARY);
             final long docSize = getCursorLong(cursor, Document.COLUMN_SIZE);
 
+            final View line1 = convertView.findViewById(R.id.line1);
+            final View line2 = convertView.findViewById(R.id.line2);
+
             final View icon = convertView.findViewById(android.R.id.icon);
             final ImageView iconMime = (ImageView) convertView.findViewById(R.id.icon_mime);
             final ImageView iconThumb = (ImageView) convertView.findViewById(R.id.icon_thumb);
             final TextView title = (TextView) convertView.findViewById(android.R.id.title);
-            final View line2 = convertView.findViewById(R.id.line2);
             final ImageView icon1 = (ImageView) convertView.findViewById(android.R.id.icon1);
+            final ImageView icon2 = (ImageView) convertView.findViewById(android.R.id.icon2);
             final TextView summary = (TextView) convertView.findViewById(android.R.id.summary);
             final TextView date = (TextView) convertView.findViewById(R.id.date);
             final TextView size = (TextView) convertView.findViewById(R.id.size);
@@ -692,10 +703,11 @@
 
             final boolean supportsThumbnail = (docFlags & Document.FLAG_SUPPORTS_THUMBNAIL) != 0;
             final boolean allowThumbnail = (state.derivedMode == MODE_GRID)
-                    || MimePredicate.mimeMatches(LIST_THUMBNAIL_MIMES, docMimeType);
+                    || MimePredicate.mimeMatches(MimePredicate.VISUAL_MIMES, docMimeType);
+            final boolean showThumbnail = supportsThumbnail && allowThumbnail;
 
             boolean cacheHit = false;
-            if (supportsThumbnail && allowThumbnail) {
+            if (showThumbnail) {
                 final Uri uri = DocumentsContract.buildDocumentUri(docAuthority, docId);
                 final Bitmap cachedResult = thumbs.get(uri);
                 if (cachedResult != null) {
@@ -726,15 +738,19 @@
                 }
             }
 
-            title.setText(docDisplayName);
-
+            boolean hasLine1 = false;
             boolean hasLine2 = false;
 
+            final boolean hideTitle = (state.derivedMode == MODE_GRID) && mHideGridTitles;
+            if (!hideTitle) {
+                title.setText(docDisplayName);
+                hasLine1 = true;
+            }
+
+            Drawable iconDrawable = null;
             if (mType == TYPE_RECENT_OPEN) {
                 final RootInfo root = roots.getRoot(docAuthority, docRootId);
-                final Drawable iconDrawable = root.loadIcon(context);
-                icon1.setVisibility(View.VISIBLE);
-                icon1.setImageDrawable(iconDrawable);
+                iconDrawable = root.loadIcon(context);
 
                 if (summary != null) {
                     final boolean alwaysShowSummary = getResources()
@@ -756,7 +772,13 @@
                     }
                 }
             } else {
-                icon1.setVisibility(View.GONE);
+                // Directories showing thumbnails in grid mode get a little icon
+                // hint to remind user they're a directory.
+                if (Document.MIME_TYPE_DIR.equals(docMimeType) && state.derivedMode == MODE_GRID
+                        && showThumbnail) {
+                    iconDrawable = context.getResources().getDrawable(R.drawable.ic_root_folder);
+                }
+
                 if (summary != null) {
                     if (docSummary != null) {
                         summary.setText(docSummary);
@@ -768,6 +790,19 @@
                 }
             }
 
+            if (icon1 != null) icon1.setVisibility(View.GONE);
+            if (icon2 != null) icon2.setVisibility(View.GONE);
+
+            if (iconDrawable != null) {
+                if (hasLine1) {
+                    icon1.setVisibility(View.VISIBLE);
+                    icon1.setImageDrawable(iconDrawable);
+                } else {
+                    icon2.setVisibility(View.VISIBLE);
+                    icon2.setImageDrawable(iconDrawable);
+                }
+            }
+
             if (docLastModified == -1) {
                 date.setText(null);
             } else {
@@ -787,6 +822,9 @@
                 size.setVisibility(View.GONE);
             }
 
+            if (line1 != null) {
+                line1.setVisibility(hasLine1 ? View.VISIBLE : View.GONE);
+            }
             if (line2 != null) {
                 line2.setVisibility(hasLine2 ? View.VISIBLE : View.GONE);
             }
@@ -796,11 +834,13 @@
             if (enabled) {
                 setEnabledRecursive(convertView, true);
                 icon.setAlpha(1f);
-                icon1.setAlpha(1f);
+                if (icon1 != null) icon1.setAlpha(1f);
+                if (icon2 != null) icon2.setAlpha(1f);
             } else {
                 setEnabledRecursive(convertView, false);
                 icon.setAlpha(0.5f);
-                icon1.setAlpha(0.5f);
+                if (icon1 != null) icon1.setAlpha(0.5f);
+                if (icon2 != null) icon2.setAlpha(0.5f);
             }
 
             return convertView;
@@ -943,6 +983,7 @@
     }
 
     private void setEnabledRecursive(View v, boolean enabled) {
+        if (v == null) return;
         if (v.isEnabled() == enabled) return;
         v.setEnabled(enabled);
 
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
index b1e51a07..f6cb481 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
@@ -244,6 +244,7 @@
         } else {
             // Restore last stack for calling package
             // TODO: move into async loader
+            boolean restoredStack = false;
             final String packageName = getCallingPackage();
             final Cursor cursor = getContentResolver()
                     .query(RecentsProvider.buildResume(packageName), null, null, null, null);
@@ -252,6 +253,7 @@
                     final byte[] rawStack = cursor.getBlob(
                             cursor.getColumnIndex(ResumeColumns.STACK));
                     DurableUtils.readFromArray(rawStack, mState.stack);
+                    restoredStack = true;
                 }
             } catch (IOException e) {
                 Log.w(TAG, "Failed to resume", e);
@@ -264,10 +266,13 @@
             final List<RootInfo> matchingRoots = mRoots.getMatchingRoots(mState);
             if (!matchingRoots.contains(root)) {
                 mState.stack.reset();
+                restoredStack = false;
             }
 
-            // Only open drawer when showing recents
-            if (mState.stack.isRecents()) {
+            // Only open drawer when not restoring stack, and when not showing
+            // visual content.
+            if (!restoredStack
+                    && !MimePredicate.mimeMatches(MimePredicate.VISUAL_MIMES, mState.acceptMimes)) {
                 setRootsDrawerOpen(true);
             }
         }
diff --git a/packages/DocumentsUI/src/com/android/documentsui/MimePredicate.java b/packages/DocumentsUI/src/com/android/documentsui/MimePredicate.java
index b55ce82..2d96876 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/MimePredicate.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/MimePredicate.java
@@ -22,6 +22,12 @@
 public class MimePredicate implements Predicate<DocumentInfo> {
     private final String[] mFilters;
 
+    /**
+     * MIME types that are visual in nature. For example, they should always be
+     * shown as thumbnails in list mode.
+     */
+    public static final String[] VISUAL_MIMES = new String[] { "image/*", "video/*" };
+
     public MimePredicate(String[] filters) {
         mFilters = filters;
     }
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java b/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java
index a7173b6..1912010 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java
@@ -27,6 +27,7 @@
 import android.database.MergeCursor;
 import android.net.Uri;
 import android.provider.DocumentsContract;
+import android.provider.DocumentsContract.Document;
 import android.provider.DocumentsContract.Root;
 import android.util.Log;
 
@@ -176,7 +177,7 @@
                 try {
                     final Cursor cursor = task.get();
                     final FilteringCursorWrapper filtered = new FilteringCursorWrapper(
-                            cursor, mAcceptMimes) {
+                            cursor, mAcceptMimes, new String[] { Document.MIME_TYPE_DIR }) {
                         @Override
                         public void close() {
                             // Ignored, since we manage cursor lifecycle internally
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java b/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
index 4d313e8..9b54948 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
@@ -137,12 +137,14 @@
 
     @GuardedBy("ActivityThread")
     public boolean isIconUnique(RootInfo root) {
+        final int rootIcon = root.derivedIcon != 0 ? root.derivedIcon : root.icon;
         for (RootInfo test : mRoots) {
             if (Objects.equal(test.authority, root.authority)) {
                 if (Objects.equal(test.rootId, root.rootId)) {
                     continue;
                 }
-                if (test.icon == root.icon) {
+                final int testIcon = test.derivedIcon != 0 ? test.derivedIcon : test.icon;
+                if (testIcon == rootIcon) {
                     return false;
                 }
             }
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
index 54dcf1c..908729c 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
@@ -35,6 +35,7 @@
 import android.widget.ArrayAdapter;
 import android.widget.ImageView;
 import android.widget.ListView;
+import android.widget.Space;
 import android.widget.TextView;
 
 import com.android.documentsui.DocumentsActivity.State;
@@ -136,11 +137,8 @@
     };
 
     private static class RootsAdapter extends ArrayAdapter<RootInfo> implements SectionAdapter {
-        private int mHeaderId;
-
-        public RootsAdapter(Context context, int headerId) {
+        public RootsAdapter(Context context) {
             super(context, 0);
-            mHeaderId = headerId;
         }
 
         @Override
@@ -177,13 +175,8 @@
         @Override
         public View getHeaderView(View convertView, ViewGroup parent) {
             if (convertView == null) {
-                convertView = LayoutInflater.from(parent.getContext())
-                        .inflate(R.layout.item_root_header, parent, false);
+                convertView = new Space(parent.getContext());
             }
-
-            final TextView title = (TextView) convertView.findViewById(android.R.id.title);
-            title.setText(mHeaderId);
-
             return convertView;
         }
     }
@@ -237,9 +230,9 @@
         private final AppsAdapter mApps;
 
         public SectionedRootsAdapter(Context context, List<RootInfo> roots, Intent includeApps) {
-            mServices = new RootsAdapter(context, R.string.root_type_service);
-            mShortcuts = new RootsAdapter(context, R.string.root_type_shortcut);
-            mDevices = new RootsAdapter(context, R.string.root_type_device);
+            mServices = new RootsAdapter(context);
+            mShortcuts = new RootsAdapter(context);
+            mDevices = new RootsAdapter(context);
             mApps = new AppsAdapter(context);
 
             for (RootInfo root : roots) {
@@ -274,15 +267,15 @@
             mShortcuts.sort(comp);
             mDevices.sort(comp);
 
-            if (mServices.getCount() > 0) {
-                addSection(mServices);
-            }
             if (mShortcuts.getCount() > 0) {
                 addSection(mShortcuts);
             }
             if (mDevices.getCount() > 0) {
                 addSection(mDevices);
             }
+            if (mServices.getCount() > 0) {
+                addSection(mServices);
+            }
             if (mApps.getCount() > 0) {
                 addSection(mApps);
             }
diff --git a/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java b/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java
index ab55d94..681cc9b 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java
@@ -204,6 +204,10 @@
         return (flags & Document.FLAG_SUPPORTS_DELETE) != 0;
     }
 
+    public boolean isGridTitlesHidden() {
+        return (flags & Document.FLAG_DIR_HIDE_GRID_TITLES) != 0;
+    }
+
     public static String getCursorString(Cursor cursor, String columnName) {
         final int index = cursor.getColumnIndex(columnName);
         return (index != -1) ? cursor.getString(index) : null;