Refactor DocsUI to break out a new ManageRootActivity.

- Split all ACTION_MANAGE-related functionality off from
  DocumentsActivity, into a new activity.
- Create new full-screen layouts for said activity.
- Fix some styling issues in {Documents,Files}Activity.

Change-Id: I0384715ad3c7d70a3a3daf510f1a09e8c5732348
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index d578769..97bc8fd 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -36,12 +36,18 @@
                 <category android:name="android.intent.category.DEFAULT" />
             </intent-filter>
             <intent-filter>
-                <action android:name="android.provider.action.MANAGE_ROOT" />
+                <action android:name="android.provider.action.BROWSE_DOCUMENT_ROOT" />
                 <category android:name="android.intent.category.DEFAULT" />
                 <data android:mimeType="vnd.android.document/root" />
             </intent-filter>
+        </activity>
+
+        <activity
+            android:name=".ManageRootActivity"
+            android:theme="@style/DocumentsNonDialogTheme"
+            android:icon="@drawable/ic_doc_text">
             <intent-filter>
-                <action android:name="android.provider.action.BROWSE_DOCUMENT_ROOT" />
+                <action android:name="android.provider.action.MANAGE_ROOT" />
                 <category android:name="android.intent.category.DEFAULT" />
                 <data android:mimeType="vnd.android.document/root" />
             </intent-filter>
diff --git a/res/layout/directory_cluster.xml b/res/layout/directory_cluster.xml
new file mode 100644
index 0000000..e47e196
--- /dev/null
+++ b/res/layout/directory_cluster.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
+
+    <com.android.documentsui.DirectoryContainerView
+        android:id="@+id/container_directory"
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_weight="1" />
+
+    <FrameLayout
+        android:id="@+id/container_save"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:background="@color/material_grey_50"
+        android:elevation="8dp" />
+
+</LinearLayout>
diff --git a/res/layout/drawer_layout.xml b/res/layout/drawer_layout.xml
index 32431e3..dec4e92 100644
--- a/res/layout/drawer_layout.xml
+++ b/res/layout/drawer_layout.xml
@@ -30,7 +30,8 @@
             android:layout_height="?android:attr/actionBarSize"
             android:background="?android:attr/colorPrimary"
             android:elevation="8dp"
-            android:theme="?android:attr/actionBarTheme">
+            android:theme="?actionBarTheme"
+            android:popupTheme="?actionBarPopupTheme">
 
             <Spinner
                 android:id="@+id/stack"
@@ -41,18 +42,7 @@
 
         </com.android.documentsui.DocumentsToolBar>
 
-        <com.android.documentsui.DirectoryContainerView
-            android:id="@+id/container_directory"
-            android:layout_width="match_parent"
-            android:layout_height="0dp"
-            android:layout_weight="1" />
-
-        <FrameLayout
-            android:id="@+id/container_save"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:background="@color/material_grey_50"
-            android:elevation="8dp" />
+        <include layout="@layout/directory_cluster"/>
 
     </LinearLayout>
 
@@ -71,7 +61,8 @@
             android:layout_height="?android:attr/actionBarSize"
             android:background="?android:attr/colorPrimary"
             android:elevation="8dp"
-            android:theme="?android:attr/actionBarTheme" />
+            android:theme="?actionBarTheme"
+            android:popupTheme="?actionBarPopupTheme" />
 
         <FrameLayout
             android:id="@+id/container_roots"
diff --git a/res/layout/fixed_layout.xml b/res/layout/fixed_layout.xml
index 9769f26..eba9af4 100644
--- a/res/layout/fixed_layout.xml
+++ b/res/layout/fixed_layout.xml
@@ -51,28 +51,11 @@
             android:layout_width="256dp"
             android:layout_height="match_parent" />
 
-        <LinearLayout
+        <include layout="@layout/directory_cluster"
             android:layout_width="0dp"
-            android:layout_height="match_parent"
             android:layout_weight="1"
-            android:orientation="vertical"
-            android:background="@color/material_grey_50"
-            android:elevation="8dp">
-
-            <com.android.documentsui.DirectoryContainerView
-                android:id="@+id/container_directory"
-                android:layout_width="match_parent"
-                android:layout_height="0dp"
-                android:layout_weight="1" />
-
-            <FrameLayout
-                android:id="@+id/container_save"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:background="@color/material_grey_50"
-                android:elevation="8dp" />
-
-        </LinearLayout>
+            android:elevation="8dp"
+            android:background="@color/material_grey_50" />
 
     </LinearLayout>
 
diff --git a/res/layout/single_pane_layout.xml b/res/layout/single_pane_layout.xml
new file mode 100644
index 0000000..20c3232
--- /dev/null
+++ b/res/layout/single_pane_layout.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
+
+    <com.android.documentsui.DocumentsToolBar
+        android:id="@+id/toolbar"
+        android:layout_width="match_parent"
+        android:layout_height="?android:attr/actionBarSize"
+        android:background="?android:attr/colorPrimary"
+        android:elevation="8dp"
+        android:theme="?actionBarTheme"
+        android:popupTheme="?actionBarPopupTheme">
+
+        <Spinner
+            android:id="@+id/stack"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginStart="4dp"
+            android:overlapAnchor="true" />
+
+    </com.android.documentsui.DocumentsToolBar>
+
+    <include layout="@layout/directory_cluster"/>
+
+</LinearLayout>
diff --git a/res/menu/activity.xml b/res/menu/activity.xml
index e1f6562..7df152f 100644
--- a/res/menu/activity.xml
+++ b/res/menu/activity.xml
@@ -26,7 +26,8 @@
         android:id="@+id/menu_create_dir"
         android:title="@string/menu_create_dir"
         android:icon="@drawable/ic_menu_new_folder"
-        android:showAsAction="always" />
+        android:showAsAction="always"
+        android:visible="false" />
     <item
         android:id="@+id/menu_sort"
         android:title="@string/menu_sort"
@@ -62,10 +63,12 @@
         android:visible="false" />
     <item
         android:id="@+id/menu_advanced"
-        android:showAsAction="never" />
+        android:showAsAction="never"
+        android:visible="false" />
     <item
         android:id="@+id/menu_file_size"
-        android:showAsAction="never" />
+        android:showAsAction="never"
+        android:visible="false" />
     <item
         android:id="@+id/menu_settings"
         android:title="@string/menu_settings"
diff --git a/res/values/layouts.xml b/res/values/layouts.xml
index c73a1cb..8ac1ac2 100644
--- a/res/values/layouts.xml
+++ b/res/values/layouts.xml
@@ -17,4 +17,5 @@
 <resources>
     <item name="docs_activity" type="layout">@layout/drawer_layout</item>
     <item name="files_activity" type="layout">@layout/drawer_layout</item>
+    <item name="manage_roots_activity" type="layout">@layout/single_pane_layout</item>
 </resources>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 22add98..e67f956 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -57,6 +57,10 @@
         <item name="android:colorPrimaryDark">@color/primary_dark</item>
         <item name="android:colorPrimary">@color/primary</item>
         <item name="android:colorAccent">@color/accent</item>
+
+        <item name="android:actionModeStyle">@style/ActionModeStyle</item>
+
+        <item name="android:alertDialogTheme">@style/AlertDialogTheme</item>
     </style>
 
     <style name="ActionModeStyle" parent="@android:style/Widget.Material.Light.ActionMode">
diff --git a/src/com/android/documentsui/BaseActivity.java b/src/com/android/documentsui/BaseActivity.java
index 2835106..1e7a42f 100644
--- a/src/com/android/documentsui/BaseActivity.java
+++ b/src/com/android/documentsui/BaseActivity.java
@@ -16,6 +16,13 @@
 
 package com.android.documentsui;
 
+import static com.android.documentsui.BaseActivity.State.ACTION_BROWSE;
+import static com.android.documentsui.BaseActivity.State.ACTION_CREATE;
+import static com.android.documentsui.BaseActivity.State.ACTION_GET_CONTENT;
+import static com.android.documentsui.BaseActivity.State.ACTION_MANAGE;
+import static com.android.documentsui.BaseActivity.State.ACTION_OPEN;
+import static com.android.documentsui.BaseActivity.State.ACTION_OPEN_COPY_DESTINATION;
+import static com.android.documentsui.BaseActivity.State.ACTION_OPEN_TREE;
 import static com.android.documentsui.DirectoryFragment.ANIM_DOWN;
 import static com.android.documentsui.DirectoryFragment.ANIM_NONE;
 import static com.android.documentsui.DirectoryFragment.ANIM_SIDE;
@@ -47,7 +54,6 @@
 import android.view.MenuItem.OnActionExpandListener;
 import android.view.View;
 import android.view.ViewGroup;
-import android.view.ViewStub;
 import android.widget.AdapterView;
 import android.widget.AdapterView.OnItemSelectedListener;
 import android.widget.BaseAdapter;
@@ -85,7 +91,6 @@
     private int mLayoutId;
     private final String mTag;
 
-    public abstract State getDisplayState();
     public abstract void onDocumentPicked(DocumentInfo doc, @Nullable DocumentContext siblings);
     public abstract void onDocumentsPicked(List<DocumentInfo> docs);
 
@@ -93,7 +98,7 @@
     abstract void onDirectoryChanged(int anim);
     abstract void updateActionBar();
     abstract void saveStackBlocking();
-    abstract State buildDefaultState();
+    abstract State buildState();
 
     public BaseActivity(@LayoutRes int layoutId, String tag) {
         mLayoutId = layoutId;
@@ -106,7 +111,7 @@
 
         mState = (icicle != null)
                 ? icicle.<State>getParcelable(EXTRA_STATE)
-                        : buildDefaultState();
+                        : buildState();
 
         setContentView(mLayoutId);
 
@@ -154,30 +159,46 @@
         final MenuItem sortSize = menu.findItem(R.id.menu_sort_size);
         final MenuItem grid = menu.findItem(R.id.menu_grid);
         final MenuItem list = menu.findItem(R.id.menu_list);
-
         final MenuItem advanced = menu.findItem(R.id.menu_advanced);
         final MenuItem fileSize = menu.findItem(R.id.menu_file_size);
+        final MenuItem settings = menu.findItem(R.id.menu_settings);
 
         mSearchManager.update(root);
 
         // Search uses backend ranking; no sorting
         sort.setVisible(cwd != null && !mSearchManager.isSearching());
 
-        State state = getDisplayState();
-        grid.setVisible(state.derivedMode != State.MODE_GRID);
-        list.setVisible(state.derivedMode != State.MODE_LIST);
-
-        // Only sort by size when visible
-        sortSize.setVisible(state.showSize);
-
         advanced.setTitle(LocalPreferences.getDisplayAdvancedDevices(this)
                 ? R.string.menu_advanced_hide : R.string.menu_advanced_show);
         fileSize.setTitle(LocalPreferences.getDisplayFileSize(this)
                 ? R.string.menu_file_size_hide : R.string.menu_file_size_show);
 
+        State state = getDisplayState();
+
+        sortSize.setVisible(state.showSize); // Only sort by size when visible
+        grid.setVisible(state.derivedMode != State.MODE_GRID);
+        list.setVisible(state.derivedMode != State.MODE_LIST);
+        settings.setVisible((root.flags & Root.FLAG_HAS_SETTINGS) != 0);
+
         return shown;
     }
 
+    State buildDefaultState() {
+        State state = new State();
+
+        final Intent intent = getIntent();
+        final String action = intent.getAction();
+
+        state.localOnly = intent.getBooleanExtra(Intent.EXTRA_LOCAL_ONLY, false);
+        state.forceAdvanced = intent.getBooleanExtra(DocumentsContract.EXTRA_SHOW_ADVANCED, false);
+        state.showAdvanced = state.forceAdvanced ||
+                LocalPreferences.getDisplayAdvancedDevices(this);
+
+        state.excludedAuthorities = getExcludedAuthorities();
+
+        return state;
+    }
+
     void onStackRestored(boolean restored, boolean external) {}
 
     void onRootPicked(RootInfo root) {
@@ -344,6 +365,10 @@
         return (BaseActivity) fragment.getActivity();
     }
 
+    public State getDisplayState() {
+        return mState;
+    }
+
     public static abstract class DocumentsIntent {
         /** Intent action name to open copy destination. */
         public static String ACTION_OPEN_COPY_DESTINATION =
@@ -664,6 +689,33 @@
         }
     }
 
+    final class RestoreRootTask extends AsyncTask<Void, Void, RootInfo> {
+        private Uri mRootUri;
+
+        public RestoreRootTask(Uri rootUri) {
+            mRootUri = rootUri;
+        }
+
+        @Override
+        protected RootInfo doInBackground(Void... params) {
+            final String rootId = DocumentsContract.getRootId(mRootUri);
+            return mRoots.getRootOneshot(mRootUri.getAuthority(), rootId);
+        }
+
+        @Override
+        protected void onPostExecute(RootInfo root) {
+            if (isDestroyed()) return;
+            mState.restored = true;
+
+            if (root != null) {
+                onRootPicked(root);
+            } else {
+                Log.w(mTag, "Failed to find root: " + mRootUri);
+                finish();
+            }
+        }
+    }
+
     final class ItemSelectedListener implements OnItemSelectedListener {
 
         boolean mIgnoreNextNavigation;
diff --git a/src/com/android/documentsui/DirectoryFragment.java b/src/com/android/documentsui/DirectoryFragment.java
index 93921dd..4ce404b 100644
--- a/src/com/android/documentsui/DirectoryFragment.java
+++ b/src/com/android/documentsui/DirectoryFragment.java
@@ -77,6 +77,7 @@
 import android.util.Log;
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
+import android.util.TypedValue;
 import android.view.ActionMode;
 import android.view.DragEvent;
 import android.view.GestureDetector;
@@ -650,8 +651,12 @@
                 if (mActionMode != null) {
                     mActionMode.finish();
                 }
-                getActivity().getWindow().setStatusBarColor(
-                    getResources().getColor(R.color.status_bar_background));
+                // Obtain the original status bar color from the theme, and restore it.
+                TypedValue color = new TypedValue();
+                getActivity().getTheme().resolveAttribute(
+                    android.R.attr.colorPrimaryDark, color, true);
+                getActivity().getWindow().setStatusBarColor(color.data);
+
             }
 
             if (mActionMode != null) {
diff --git a/src/com/android/documentsui/DocumentsActivity.java b/src/com/android/documentsui/DocumentsActivity.java
index fdc4bb0..1de1c6a 100644
--- a/src/com/android/documentsui/DocumentsActivity.java
+++ b/src/com/android/documentsui/DocumentsActivity.java
@@ -19,7 +19,6 @@
 import static com.android.documentsui.BaseActivity.State.ACTION_BROWSE;
 import static com.android.documentsui.BaseActivity.State.ACTION_CREATE;
 import static com.android.documentsui.BaseActivity.State.ACTION_GET_CONTENT;
-import static com.android.documentsui.BaseActivity.State.ACTION_MANAGE;
 import static com.android.documentsui.BaseActivity.State.ACTION_OPEN;
 import static com.android.documentsui.BaseActivity.State.ACTION_OPEN_COPY_DESTINATION;
 import static com.android.documentsui.BaseActivity.State.ACTION_OPEN_TREE;
@@ -67,7 +66,7 @@
 
 public class DocumentsActivity extends BaseActivity {
     private static final int CODE_FORWARD = 42;
-    public static final String TAG = "Documents";
+    private static final String TAG = "DocumentsActivity";
 
     private boolean mShowAsDialog;
 
@@ -90,8 +89,7 @@
         super.onCreate(icicle);
 
         final Resources res = getResources();
-        mShowAsDialog = res.getBoolean(R.bool.show_as_dialog) && mState.action != ACTION_MANAGE &&
-                mState.action != ACTION_BROWSE;
+        mShowAsDialog = res.getBoolean(R.bool.show_as_dialog) && mState.action != ACTION_BROWSE;
 
         if (!mShowAsDialog) {
             setTheme(R.style.DocumentsNonDialogTheme);
@@ -119,8 +117,6 @@
         mDirectoryContainer = (DirectoryContainerView) findViewById(R.id.container_directory);
 
         mToolbar = (Toolbar) findViewById(R.id.toolbar);
-        mToolbar.setTitleTextAppearance(context,
-                android.R.style.TextAppearance_DeviceDefault_Widget_ActionBar_Title);
 
         mStackAdapter = new StackAdapter();
         mStackListener = new ItemSelectedListener();
@@ -128,15 +124,11 @@
         mToolbarStack.setOnItemSelectedListener(mStackListener);
 
         mRootsToolbar = (Toolbar) findViewById(R.id.roots_toolbar);
-        if (mRootsToolbar != null) {
-            mRootsToolbar.setTitleTextAppearance(context,
-                    android.R.style.TextAppearance_DeviceDefault_Widget_ActionBar_Title);
-        }
 
         setActionBar(mToolbar);
 
         // Hide roots when we're managing a specific root
-        if (mState.action == ACTION_MANAGE || mState.action == ACTION_BROWSE) {
+        if (mState.action == ACTION_BROWSE) {
             mDrawer.lockClosed();
             if (mShowAsDialog) {
                 findViewById(R.id.container_roots).setVisibility(View.GONE);
@@ -168,7 +160,7 @@
             // In this case, we set the activity title in AsyncTask.onPostExecute().  To prevent
             // talkback from reading aloud the default title, we clear it here.
             setTitle("");
-            if (mState.action == ACTION_MANAGE || mState.action == ACTION_BROWSE) {
+            if (mState.action == ACTION_BROWSE) {
                 final Uri rootUri = getIntent().getData();
                 new RestoreRootTask(rootUri).executeOnExecutor(getCurrentExecutor());
             } else {
@@ -180,8 +172,8 @@
     }
 
     @Override
-    State buildDefaultState() {
-        State state = new State();
+    State buildState() {
+        State state = buildDefaultState();
 
         final Intent intent = getIntent();
         final String action = intent.getAction();
@@ -193,8 +185,6 @@
             state.action = ACTION_GET_CONTENT;
         } else if (Intent.ACTION_OPEN_DOCUMENT_TREE.equals(action)) {
             state.action = ACTION_OPEN_TREE;
-        } else if (DocumentsContract.ACTION_MANAGE_ROOT.equals(action)) {
-            state.action = ACTION_MANAGE;
         } else if (DocumentsContract.ACTION_BROWSE_DOCUMENT_ROOT.equals(action)) {
             state.action = ACTION_BROWSE;
         } else if (DocumentsIntent.ACTION_OPEN_COPY_DESTINATION.equals(action)) {
@@ -206,7 +196,7 @@
                     Intent.EXTRA_ALLOW_MULTIPLE, false);
         }
 
-        if (state.action == ACTION_MANAGE || state.action == ACTION_BROWSE) {
+        if (state.action == ACTION_BROWSE) {
             state.acceptMimes = new String[] { "*/*" };
             state.allowMultiple = true;
         } else if (intent.hasExtra(Intent.EXTRA_MIME_TYPES)) {
@@ -215,12 +205,7 @@
             state.acceptMimes = new String[] { intent.getType() };
         }
 
-        state.localOnly = intent.getBooleanExtra(Intent.EXTRA_LOCAL_ONLY, false);
-        state.forceAdvanced = intent.getBooleanExtra(DocumentsContract.EXTRA_SHOW_ADVANCED, false);
-        state.showAdvanced = state.forceAdvanced
-                | LocalPreferences.getDisplayAdvancedDevices(this);
-
-        if (state.action == ACTION_MANAGE || state.action == ACTION_BROWSE) {
+        if (state.action == ACTION_BROWSE) {
             state.showSize = true;
         } else {
             state.showSize = LocalPreferences.getDisplayFileSize(this);
@@ -232,38 +217,9 @@
                     CopyService.TRANSFER_MODE_NONE);
         }
 
-        state.excludedAuthorities = getExcludedAuthorities();
-
         return state;
     }
 
-    private class RestoreRootTask extends AsyncTask<Void, Void, RootInfo> {
-        private Uri mRootUri;
-
-        public RestoreRootTask(Uri rootUri) {
-            mRootUri = rootUri;
-        }
-
-        @Override
-        protected RootInfo doInBackground(Void... params) {
-            final String rootId = DocumentsContract.getRootId(mRootUri);
-            return mRoots.getRootOneshot(mRootUri.getAuthority(), rootId);
-        }
-
-        @Override
-        protected void onPostExecute(RootInfo root) {
-            if (isDestroyed()) return;
-            mState.restored = true;
-
-            if (root != null) {
-                onRootPicked(root);
-            } else {
-                Log.w(TAG, "Failed to find root: " + mRootUri);
-                finish();
-            }
-        }
-    }
-
     @Override
     void onStackRestored(boolean restored, boolean external) {
         // Show drawer when no stack restored, but only when requesting
@@ -405,8 +361,11 @@
         final MenuItem fileSize = menu.findItem(R.id.menu_file_size);
         final MenuItem settings = menu.findItem(R.id.menu_settings);
 
-        boolean fileSizeVisible = !(mState.action == ACTION_MANAGE
-                || mState.action == ACTION_BROWSE);
+        // File size is locked visible for browse because that is the action triggered by Settings,
+        // where the user is trying to find large files to clean up.
+        // TODO: instead of setting this according to the action, use a local preference, but
+        // provide a @hide extra to let callers like Settings force-enable size visibility.
+        boolean fileSizeVisible = mState.action != ACTION_BROWSE;
         if (mState.action == ACTION_CREATE
                 || mState.action == ACTION_OPEN_TREE
                 || mState.action == ACTION_OPEN_COPY_DESTINATION) {
@@ -428,11 +387,10 @@
             createDir.setVisible(false);
         }
 
-        advanced.setVisible(!(mState.action == ACTION_MANAGE || mState.action == ACTION_BROWSE) &&
-                !mState.forceAdvanced);
+        advanced.setVisible(mState.action != ACTION_BROWSE && !mState.forceAdvanced);
         fileSize.setVisible(fileSizeVisible);
 
-        settings.setVisible((mState.action == ACTION_MANAGE || mState.action == ACTION_BROWSE)
+        settings.setVisible(mState.action == ACTION_BROWSE
                 && (root.flags & Root.FLAG_HAS_SETTINGS) != 0);
 
         return true;
@@ -444,11 +402,6 @@
     }
 
     @Override
-    public State getDisplayState() {
-        return mState;
-    }
-
-    @Override
     void onDirectoryChanged(int anim) {
         final FragmentManager fm = getFragmentManager();
         final RootInfo root = getCurrentRoot();
@@ -523,26 +476,6 @@
         } else if (mState.action == ACTION_CREATE) {
             // Replace selected file
             SaveFragment.get(fm).setReplaceTarget(doc);
-        } else if (mState.action == ACTION_MANAGE) {
-            // First try managing the document; we expect manager to filter
-            // based on authority, so we don't grant.
-            final Intent manage = new Intent(DocumentsContract.ACTION_MANAGE_DOCUMENT);
-            manage.setData(doc.derivedUri);
-
-            try {
-                startActivity(manage);
-            } catch (ActivityNotFoundException ex) {
-                // Fall back to viewing
-                final Intent view = new Intent(Intent.ACTION_VIEW);
-                view.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
-                view.setData(doc.derivedUri);
-
-                try {
-                    startActivity(view);
-                } catch (ActivityNotFoundException ex2) {
-                    Toast.makeText(this, R.string.toast_no_application, Toast.LENGTH_SHORT).show();
-                }
-            }
         } else if (mState.action == ACTION_BROWSE) {
             // Go straight to viewing
             final Intent view = new Intent(Intent.ACTION_VIEW);
diff --git a/src/com/android/documentsui/FilesActivity.java b/src/com/android/documentsui/FilesActivity.java
index 7c445bf..8f9025a 100644
--- a/src/com/android/documentsui/FilesActivity.java
+++ b/src/com/android/documentsui/FilesActivity.java
@@ -30,7 +30,6 @@
 import android.net.Uri;
 import android.os.Bundle;
 import android.provider.DocumentsContract;
-import android.provider.DocumentsContract.Root;
 import android.support.annotation.Nullable;
 import android.util.Log;
 import android.view.KeyEvent;
@@ -58,12 +57,11 @@
  */
 public class FilesActivity extends BaseActivity {
 
-    public static final String TAG = "StandaloneFileManagement";
+    public static final String TAG = "FilesActivity";
     static final boolean DEBUG = false;
 
     private Toolbar mToolbar;
     private Spinner mToolbarStack;
-    private Toolbar mRootsToolbar;
     private DirectoryContainerView mDirectoryContainer;
     private ItemSelectedListener mStackListener;
     private BaseAdapter mStackAdapter;
@@ -82,20 +80,12 @@
         mDirectoryContainer = (DirectoryContainerView) findViewById(R.id.container_directory);
 
         mToolbar = (Toolbar) findViewById(R.id.toolbar);
-        mToolbar.setTitleTextAppearance(context,
-                android.R.style.TextAppearance_DeviceDefault_Widget_ActionBar_Title);
 
         mStackAdapter = new StackAdapter();
         mStackListener = new ItemSelectedListener();
         mToolbarStack = (Spinner) findViewById(R.id.stack);
         mToolbarStack.setOnItemSelectedListener(mStackListener);
 
-        mRootsToolbar = (Toolbar) findViewById(R.id.roots_toolbar);
-        if (mRootsToolbar != null) {
-            mRootsToolbar.setTitleTextAppearance(context,
-                    android.R.style.TextAppearance_DeviceDefault_Widget_ActionBar_Title);
-        }
-
         setActionBar(mToolbar);
 
         mClipper = new DocumentClipper(this);
@@ -127,14 +117,14 @@
     }
 
     @Override
-    State buildDefaultState() {
-        State state = new State();
+    State buildState() {
+        State state = buildDefaultState();
 
         final Intent intent = getIntent();
+
         state.action = State.ACTION_BROWSE_ALL;
-        state.acceptMimes = new String[] { "*/*" };
-        state.allowMultiple = true;
         state.acceptMimes = new String[] { intent.getType() };
+        state.allowMultiple = true;
 
         // These options are specific to the DocumentsActivity.
         Preconditions.checkArgument(
@@ -223,8 +213,6 @@
         createDir.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
         createDir.setVisible(canCreateDir);
 
-        settings.setVisible((getCurrentRoot().flags & Root.FLAG_HAS_SETTINGS) != 0);
-
         pasteFromCb.setVisible(true);
         pasteFromCb.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
         pasteFromCb.setEnabled(mClipper.hasItemsToPaste());
@@ -246,11 +234,6 @@
     }
 
     @Override
-    public State getDisplayState() {
-        return mState;
-    }
-
-    @Override
     void onDirectoryChanged(int anim) {
         final FragmentManager fm = getFragmentManager();
         final RootInfo root = getCurrentRoot();
diff --git a/src/com/android/documentsui/IconUtils.java b/src/com/android/documentsui/IconUtils.java
index 9959265..ec1cb1d 100644
--- a/src/com/android/documentsui/IconUtils.java
+++ b/src/com/android/documentsui/IconUtils.java
@@ -222,7 +222,7 @@
                 return context.getDrawable(R.drawable.ic_doc_album);
             }
 
-            if (mode == DocumentsActivity.State.MODE_GRID) {
+            if (mode == BaseActivity.State.MODE_GRID) {
                 return context.getDrawable(R.drawable.ic_grid_folder);
             } else {
                 return context.getDrawable(R.drawable.ic_doc_folder);
diff --git a/src/com/android/documentsui/ManageRootActivity.java b/src/com/android/documentsui/ManageRootActivity.java
new file mode 100644
index 0000000..7401578
--- /dev/null
+++ b/src/com/android/documentsui/ManageRootActivity.java
@@ -0,0 +1,244 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.documentsui;
+
+import static com.android.documentsui.BaseActivity.State.ACTION_MANAGE;
+import static com.android.documentsui.DirectoryFragment.ANIM_DOWN;
+import static com.android.documentsui.DirectoryFragment.ANIM_NONE;
+
+import android.app.Activity;
+import android.app.Fragment;
+import android.app.FragmentManager;
+import android.content.ActivityNotFoundException;
+import android.content.ClipData;
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+import android.provider.DocumentsContract;
+import android.util.Log;
+import android.view.Menu;
+import android.view.View;
+import android.widget.BaseAdapter;
+import android.widget.Spinner;
+import android.widget.Toast;
+import android.widget.Toolbar;
+
+import com.android.documentsui.RecentsProvider.ResumeColumns;
+import com.android.documentsui.model.DocumentInfo;
+import com.android.documentsui.model.DurableUtils;
+import com.android.documentsui.model.RootInfo;
+import com.android.internal.util.Preconditions;
+
+import java.util.Arrays;
+import java.util.List;
+
+public class ManageRootActivity extends BaseActivity {
+    private static final int CODE_FORWARD = 42;
+    private static final String TAG = "ManageRootsActivity";
+
+    private Toolbar mToolbar;
+    private Spinner mToolbarStack;
+
+    private DirectoryContainerView mDirectoryContainer;
+
+    private ItemSelectedListener mStackListener;
+    private BaseAdapter mStackAdapter;
+
+    public ManageRootActivity() {
+        super(R.layout.manage_roots_activity, TAG);
+    }
+
+    @Override
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+
+        final Context context = this;
+
+        mDrawer = DrawerController.createDummy();
+
+        mDirectoryContainer = (DirectoryContainerView) findViewById(R.id.container_directory);
+
+        mToolbar = (Toolbar) findViewById(R.id.toolbar);
+        mToolbar.setTitleTextAppearance(context,
+                android.R.style.TextAppearance_DeviceDefault_Widget_ActionBar_Title);
+
+        mStackAdapter = new StackAdapter();
+        mStackListener = new ItemSelectedListener();
+        mToolbarStack = (Spinner) findViewById(R.id.stack);
+        mToolbarStack.setOnItemSelectedListener(mStackListener);
+
+        setActionBar(mToolbar);
+
+        if (!mState.restored) {
+            // In this case, we set the activity title in AsyncTask.onPostExecute(). To prevent
+            // talkback from reading aloud the default title, we clear it here.
+            setTitle("");
+            final Uri rootUri = getIntent().getData();
+            new RestoreRootTask(rootUri).executeOnExecutor(getCurrentExecutor());
+        } else {
+            onCurrentDirectoryChanged(ANIM_NONE);
+        }
+    }
+
+    @Override
+    State buildState() {
+        State state = buildDefaultState();
+
+        state.action = ACTION_MANAGE;
+        state.acceptMimes = new String[] { "*/*" };
+        state.allowMultiple = true;
+        state.showSize = true;
+        state.excludedAuthorities = getExcludedAuthorities();
+
+        return state;
+    }
+
+    @Override
+    protected void onPostCreate(Bundle savedInstanceState) {
+        super.onPostCreate(savedInstanceState);
+        updateActionBar();
+    }
+
+    @Override
+    public void updateActionBar() {
+        // No navigation in manage root mode.
+        mToolbar.setNavigationIcon(null);
+        mToolbar.setNavigationOnClickListener(null);
+
+        if (mSearchManager.isExpanded()) {
+            mToolbar.setTitle(null);
+            mToolbarStack.setVisibility(View.GONE);
+            mToolbarStack.setAdapter(null);
+        } else {
+            if (mState.stack.size() <= 1) {
+                mToolbar.setTitle(getCurrentRoot().title);
+                mToolbarStack.setVisibility(View.GONE);
+                mToolbarStack.setAdapter(null);
+            } else {
+                mToolbar.setTitle(null);
+                mToolbarStack.setVisibility(View.VISIBLE);
+                mToolbarStack.setAdapter(mStackAdapter);
+
+                mStackListener.mIgnoreNextNavigation = true;
+                mToolbarStack.setSelection(mStackAdapter.getCount() - 1);
+            }
+        }
+    }
+
+    @Override
+    public boolean onPrepareOptionsMenu(Menu menu) {
+        super.onPrepareOptionsMenu(menu);
+        return true;
+    }
+
+    @Override
+    void onDirectoryChanged(int anim) {
+        final FragmentManager fm = getFragmentManager();
+        final RootInfo root = getCurrentRoot();
+        final DocumentInfo cwd = getCurrentDirectory();
+
+        // If started in manage roots mode, there has to be a cwd (i.e. the root dir of the managed
+        // root).
+        Preconditions.checkNotNull(cwd);
+        mDirectoryContainer.setDrawDisappearingFirst(anim == ANIM_DOWN);
+
+        if (mState.currentSearch != null) {
+            // Ongoing search
+            DirectoryFragment.showSearch(fm, root, mState.currentSearch, anim);
+        } else {
+            // Normal boring directory
+            DirectoryFragment.showNormal(fm, root, cwd, anim);
+        }
+    }
+
+    @Override
+    public void onDocumentPicked(DocumentInfo doc, DocumentContext context) {
+        final FragmentManager fm = getFragmentManager();
+        if (doc.isDirectory()) {
+            openDirectory(doc);
+        } else {
+            // First try managing the document; we expect manager to filter
+            // based on authority, so we don't grant.
+            final Intent manage = new Intent(DocumentsContract.ACTION_MANAGE_DOCUMENT);
+            manage.setData(doc.derivedUri);
+
+            try {
+                startActivity(manage);
+            } catch (ActivityNotFoundException ex) {
+                // Fall back to viewing
+                final Intent view = new Intent(Intent.ACTION_VIEW);
+                view.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+                view.setData(doc.derivedUri);
+
+                try {
+                    startActivity(view);
+                } catch (ActivityNotFoundException ex2) {
+                    Toast.makeText(this, R.string.toast_no_application, Toast.LENGTH_SHORT).show();
+                }
+            }
+        }
+    }
+
+    @Override
+    public void onDocumentsPicked(List<DocumentInfo> docs) {}
+
+    @Override
+    void saveStackBlocking() {
+        final ContentResolver resolver = getContentResolver();
+        final ContentValues values = new ContentValues();
+
+        final byte[] rawStack = DurableUtils.writeToArrayOrNull(mState.stack);
+
+        // Remember location for next app launch
+        final String packageName = getCallingPackageMaybeExtra();
+        values.clear();
+        values.put(ResumeColumns.STACK, rawStack);
+        values.put(ResumeColumns.EXTERNAL, 0);
+        resolver.insert(RecentsProvider.buildResume(packageName), values);
+    }
+
+    @Override
+    void onTaskFinished(Uri... uris) {
+        Log.d(TAG, "onFinished() " + Arrays.toString(uris));
+
+        final Intent intent = new Intent();
+        if (uris.length == 1) {
+            intent.setData(uris[0]);
+        } else if (uris.length > 1) {
+            final ClipData clipData = new ClipData(
+                    null, mState.acceptMimes, new ClipData.Item(uris[0]));
+            for (int i = 1; i < uris.length; i++) {
+                clipData.addItem(new ClipData.Item(uris[i]));
+            }
+            intent.setClipData(clipData);
+        }
+
+        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION
+                | Intent.FLAG_GRANT_WRITE_URI_PERMISSION
+                | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
+
+        setResult(Activity.RESULT_OK, intent);
+        finish();
+    }
+
+    public static ManageRootActivity get(Fragment fragment) {
+        return (ManageRootActivity) fragment.getActivity();
+    }
+}