Merge "Settings, replace files, sorting by size, tweaks."
diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java
index 289531e..acaed73 100644
--- a/core/java/android/provider/DocumentsContract.java
+++ b/core/java/android/provider/DocumentsContract.java
@@ -105,6 +105,8 @@
      */
     public static final int FLAG_SUPPORTS_SEARCH = 1 << 4;
 
+    // TODO: flag indicating that document is writable?
+
     /**
      * Optimal dimensions for a document thumbnail request, stored as a
      * {@link Point} object. This is only a hint, and the returned thumbnail may
diff --git a/packages/DocumentsUI/AndroidManifest.xml b/packages/DocumentsUI/AndroidManifest.xml
index 1d97161..27f93c0 100644
--- a/packages/DocumentsUI/AndroidManifest.xml
+++ b/packages/DocumentsUI/AndroidManifest.xml
@@ -7,11 +7,13 @@
         android:label="@string/app_label"
         android:supportsRtl="true">
 
+        <!-- TODO: allow rotation when state saving is in better shape -->
         <activity
             android:name=".DocumentsActivity"
             android:finishOnCloseSystemDialogs="true"
             android:excludeFromRecents="true"
-            android:theme="@android:style/Theme.Holo.Light">
+            android:theme="@android:style/Theme.Holo.Light"
+            android:screenOrientation="nosensor">
             <intent-filter android:priority="100">
                 <action android:name="android.intent.action.OPEN_DOCUMENT" />
                 <category android:name="android.intent.category.DEFAULT" />
@@ -24,6 +26,12 @@
             </intent-filter>
         </activity>
 
+        <activity
+            android:name=".SettingsActivity"
+            android:title="@string/menu_settings"
+            android:theme="@android:style/Theme.Holo.Light"
+            android:exported="false" />
+
         <provider
             android:name=".RecentsProvider"
             android:authorities="com.android.documentsui.recents"
diff --git a/packages/DocumentsUI/res/layout/fragment_directory.xml b/packages/DocumentsUI/res/layout/fragment_directory.xml
index 638ac92..8dbd1de 100644
--- a/packages/DocumentsUI/res/layout/fragment_directory.xml
+++ b/packages/DocumentsUI/res/layout/fragment_directory.xml
@@ -18,6 +18,15 @@
     android:layout_width="match_parent"
     android:layout_height="match_parent">
 
+    <TextView
+        android:id="@android:id/empty"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:gravity="center"
+        android:text="@string/empty"
+        android:textAppearance="?android:attr/textAppearanceMedium"
+        android:visibility="gone" />
+
     <ListView
         android:id="@+id/list"
         android:layout_width="match_parent"
@@ -30,6 +39,7 @@
         android:layout_height="match_parent"
         android:listSelector="@android:color/transparent"
         android:paddingTop="?android:attr/listPreferredItemPaddingStart"
-        android:paddingStart="?android:attr/listPreferredItemPaddingStart" />
+        android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+        android:visibility="gone" />
 
 </FrameLayout>
diff --git a/packages/DocumentsUI/res/layout/fragment_save.xml b/packages/DocumentsUI/res/layout/fragment_save.xml
index 85c48b1..49038bc 100644
--- a/packages/DocumentsUI/res/layout/fragment_save.xml
+++ b/packages/DocumentsUI/res/layout/fragment_save.xml
@@ -36,7 +36,8 @@
         android:layout_width="0dip"
         android:layout_height="wrap_content"
         android:layout_weight="1"
-        android:singleLine="true" />
+        android:singleLine="true"
+        android:selectAllOnFocus="true" />
 
     <Button
         android:id="@android:id/button1"
diff --git a/packages/DocumentsUI/res/layout/item_doc_grid.xml b/packages/DocumentsUI/res/layout/item_doc_grid.xml
index ad8f51c..244214b 100644
--- a/packages/DocumentsUI/res/layout/item_doc_grid.xml
+++ b/packages/DocumentsUI/res/layout/item_doc_grid.xml
@@ -16,7 +16,7 @@
 
 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
-    android:layout_height="160dip"
+    android:layout_height="180dip"
     android:paddingBottom="?android:attr/listPreferredItemPaddingEnd"
     android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
 
@@ -30,6 +30,7 @@
         <LinearLayout
             android:layout_width="match_parent"
             android:layout_height="match_parent"
+            android:paddingBottom="6dp"
             android:orientation="vertical">
 
             <ImageView
@@ -54,10 +55,10 @@
                 android:textAlignment="viewStart" />
 
             <LinearLayout
+                android:id="@+id/summary_grid"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
                 android:orientation="horizontal"
-                android:paddingBottom="6dp"
                 android:paddingStart="?android:attr/listPreferredItemPaddingStart"
                 android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
 
@@ -75,12 +76,25 @@
                     android:layout_height="wrap_content"
                     android:layout_weight="1"
                     android:layout_gravity="center_vertical"
-                    android:layout_marginEnd="8dp"
                     android:singleLine="true"
                     android:ellipsize="marquee"
                     android:textAlignment="viewStart"
                     android:textAppearance="?android:attr/textAppearanceSmall" />
 
+            </LinearLayout>
+
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:orientation="horizontal"
+                android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+                android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
+
+                <View
+                    android:layout_width="0dip"
+                    android:layout_height="0dip"
+                    android:layout_weight="1" />
+
                 <TextView
                     android:id="@+id/size"
                     android:layout_width="70dp"
diff --git a/packages/DocumentsUI/res/layout/item_doc_list.xml b/packages/DocumentsUI/res/layout/item_doc_list.xml
index bb27173..37c5881 100644
--- a/packages/DocumentsUI/res/layout/item_doc_list.xml
+++ b/packages/DocumentsUI/res/layout/item_doc_list.xml
@@ -51,7 +51,7 @@
             android:textAlignment="viewStart" />
 
         <LinearLayout
-            android:id="@+id/line2"
+            android:id="@+id/summary_list"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:orientation="horizontal">
diff --git a/packages/DocumentsUI/res/menu/activity.xml b/packages/DocumentsUI/res/menu/activity.xml
index d57f88a..575336c 100644
--- a/packages/DocumentsUI/res/menu/activity.xml
+++ b/packages/DocumentsUI/res/menu/activity.xml
@@ -37,4 +37,8 @@
         android:title="@string/menu_list"
         android:icon="@drawable/ic_menu_list"
         android:showAsAction="ifRoom" />
+    <item
+        android:id="@+id/menu_settings"
+        android:title="@string/menu_settings"
+        android:showAsAction="never" />
 </menu>
diff --git a/packages/DocumentsUI/res/values/strings.xml b/packages/DocumentsUI/res/values/strings.xml
index 2ff5d03..84f89b4 100644
--- a/packages/DocumentsUI/res/values/strings.xml
+++ b/packages/DocumentsUI/res/values/strings.xml
@@ -25,6 +25,7 @@
     <string name="menu_list">List view</string>
     <string name="menu_sort">Sort by</string>
     <string name="menu_search">Search</string>
+    <string name="menu_settings">Settings</string>
 
     <string name="menu_open">Open</string>
     <string name="menu_save">Save</string>
@@ -33,6 +34,7 @@
 
     <string name="sort_name">By name</string>
     <string name="sort_date">By date modified</string>
+    <string name="sort_size">By size</string>
 
     <string name="drawer_open">Show roots</string>
     <string name="drawer_close">Hide roots</string>
@@ -40,9 +42,16 @@
     <string name="save_error">Failed to save document</string>
 
     <string name="root_recent">Recent</string>
+    <string name="root_available_bytes"><xliff:g id="size" example="3GB">%1$s</xliff:g> free</string>
 
     <string name="root_type_service">Services</string>
     <string name="root_type_shortcut">Shortcuts</string>
     <string name="root_type_device">Devices</string>
 
+    <string name="pref_advanced_devices">Display advanced devices</string>
+    <string name="pref_file_size">Display file size</string>
+    <string name="pref_device_size">Display device size</string>
+
+    <string name="empty">No items</string>
+
 </resources>
diff --git a/packages/DocumentsUI/res/xml/preferences.xml b/packages/DocumentsUI/res/xml/preferences.xml
new file mode 100644
index 0000000..5589ff1
--- /dev/null
+++ b/packages/DocumentsUI/res/xml/preferences.xml
@@ -0,0 +1,26 @@
+<?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.
+-->
+
+<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
+    <CheckBoxPreference
+        android:title="@string/pref_advanced_devices"
+        android:defaultValue="false"
+        android:key="advancedDevices" />
+    <CheckBoxPreference
+        android:title="@string/pref_file_size"
+        android:defaultValue="false"
+        android:key="fileSize" />
+</PreferenceScreen>
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
index d986a51..5a6060a 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
@@ -27,7 +27,6 @@
 import android.provider.DocumentsContract;
 import android.text.format.DateUtils;
 import android.text.format.Formatter;
-import android.util.Log;
 import android.util.SparseBooleanArray;
 import android.view.ActionMode;
 import android.view.LayoutInflater;
@@ -62,11 +61,14 @@
  */
 public class DirectoryFragment extends Fragment {
 
+    private View mEmptyView;
     private ListView mListView;
     private GridView mGridView;
 
     private AbsListView mCurrentView;
 
+    private Predicate<Document> mFilter;
+
     public static final int TYPE_NORMAL = 1;
     public static final int TYPE_SEARCH = 2;
     public static final int TYPE_RECENT_OPEN = 3;
@@ -121,6 +123,8 @@
 
         final View view = inflater.inflate(R.layout.fragment_directory, container, false);
 
+        mEmptyView = view.findViewById(android.R.id.empty);
+
         mListView = (ListView) view.findViewById(R.id.list);
         mListView.setOnItemClickListener(mItemListener);
         mListView.setMultiChoiceModeListener(mMultiListener);
@@ -138,6 +142,7 @@
             @Override
             public Loader<List<Document>> onCreateLoader(int id, Bundle args) {
                 final DisplayState state = getDisplayState(DirectoryFragment.this);
+                mFilter = new MimePredicate(state.acceptMimes);
 
                 final Uri contentsUri;
                 if (mType == TYPE_NORMAL) {
@@ -148,18 +153,18 @@
                     contentsUri = uri;
                 }
 
-                final Predicate<Document> filter = new MimePredicate(state.acceptMimes);
-
                 final Comparator<Document> sortOrder;
                 if (state.sortOrder == DisplayState.SORT_ORDER_DATE || mType == TYPE_RECENT_OPEN) {
                     sortOrder = new Document.DateComparator();
                 } else if (state.sortOrder == DisplayState.SORT_ORDER_NAME) {
                     sortOrder = new Document.NameComparator();
+                } else if (state.sortOrder == DisplayState.SORT_ORDER_SIZE) {
+                    sortOrder = new Document.SizeComparator();
                 } else {
                     throw new IllegalArgumentException("Unknown sort order " + state.sortOrder);
                 }
 
-                return new DirectoryLoader(context, contentsUri, mType, filter, sortOrder);
+                return new DirectoryLoader(context, contentsUri, mType, null, sortOrder);
             }
 
             @Override
@@ -181,6 +186,10 @@
     @Override
     public void onStart() {
         super.onStart();
+
+        final Context context = getActivity();
+        getDisplayState(this).showSize = SettingsActivity.getDisplayFileSize(context);
+
         getLoaderManager().restartLoader(mLoaderId, getArguments(), mCallbacks);
     }
 
@@ -193,7 +202,7 @@
     public void updateDisplayState() {
         final DisplayState state = getDisplayState(this);
 
-        // TODO: avoid kicking loader when sort didn't change
+        // TODO: avoid kicking loader when nothing changed
         getLoaderManager().restartLoader(mLoaderId, getArguments(), mCallbacks);
         mListView.smoothScrollToPosition(0);
         mGridView.smoothScrollToPosition(0);
@@ -302,6 +311,13 @@
 
         public void swapDocuments(List<Document> documents) {
             mDocuments = documents;
+
+            if (documents != null && documents.isEmpty()) {
+                mEmptyView.setVisibility(View.VISIBLE);
+            } else {
+                mEmptyView.setVisibility(View.GONE);
+            }
+
             notifyDataSetChanged();
         }
 
@@ -325,6 +341,7 @@
 
             final ImageView icon = (ImageView) convertView.findViewById(android.R.id.icon);
             final TextView title = (TextView) convertView.findViewById(android.R.id.title);
+            final View summaryGrid = convertView.findViewById(R.id.summary_grid);
             final ImageView icon1 = (ImageView) convertView.findViewById(android.R.id.icon1);
             final TextView summary = (TextView) convertView.findViewById(android.R.id.summary);
             final TextView date = (TextView) convertView.findViewById(R.id.date);
@@ -356,6 +373,11 @@
                 summary.setVisibility(View.VISIBLE);
             }
 
+            if (summaryGrid != null) {
+                summaryGrid.setVisibility(
+                        (summary.getVisibility() == View.VISIBLE) ? View.VISIBLE : View.GONE);
+            }
+
             // TODO: omit year from format
             date.setText(DateUtils.formatSameDayTime(
                     doc.lastModified, System.currentTimeMillis(), DateFormat.SHORT,
@@ -389,5 +411,16 @@
         public long getItemId(int position) {
             return getItem(position).uri.hashCode();
         }
+
+        @Override
+        public boolean areAllItemsEnabled() {
+            return false;
+        }
+
+        @Override
+        public boolean isEnabled(int position) {
+            final Document doc = getItem(position);
+            return mFilter.apply(doc);
+        }
     }
 }
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
index 6784d709d..fae5673 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
@@ -19,15 +19,18 @@
 import android.app.ActionBar;
 import android.app.ActionBar.OnNavigationListener;
 import android.app.Activity;
+import android.app.Fragment;
 import android.app.FragmentManager;
 import android.content.ClipData;
 import android.content.ContentResolver;
 import android.content.ContentValues;
 import android.content.Intent;
+import android.content.SharedPreferences;
 import android.database.Cursor;
 import android.graphics.drawable.ColorDrawable;
 import android.net.Uri;
 import android.os.Bundle;
+import android.preference.PreferenceManager;
 import android.provider.DocumentsContract.DocumentColumns;
 import android.support.v4.app.ActionBarDrawerToggle;
 import android.support.v4.view.GravityCompat;
@@ -139,7 +142,7 @@
             cursor.close();
         }
 
-        updateDirectoryFragment();
+        onCurrentDirectoryChanged();
     }
 
     private DrawerListener mDrawerListener = new DrawerListener() {
@@ -221,7 +224,7 @@
             @Override
             public boolean onQueryTextSubmit(String query) {
                 mCurrentSearch = query;
-                updateDirectoryFragment();
+                onCurrentDirectoryChanged();
                 mSearchView.setIconified(true);
                 return true;
             }
@@ -236,7 +239,7 @@
             @Override
             public boolean onClose() {
                 mCurrentSearch = null;
-                updateDirectoryFragment();
+                onCurrentDirectoryChanged();
                 return false;
             }
         });
@@ -248,23 +251,36 @@
     public boolean onPrepareOptionsMenu(Menu menu) {
         super.onPrepareOptionsMenu(menu);
 
+        final FragmentManager fm = getFragmentManager();
         final Document cwd = getCurrentDirectory();
 
         final MenuItem createDir = menu.findItem(R.id.menu_create_dir);
-        createDir.setVisible(mAction == ACTION_CREATE);
-        createDir.setEnabled(cwd != null && cwd.isCreateSupported());
-
-        // TODO: close any search in-progress when hiding
         final MenuItem search = menu.findItem(R.id.menu_search);
-        search.setVisible(cwd != null && cwd.isSearchSupported());
+        final MenuItem grid =  menu.findItem(R.id.menu_grid);
+        final MenuItem list = menu.findItem(R.id.menu_list);
 
+        grid.setVisible(mDisplayState.mode != DisplayState.MODE_GRID);
+        list.setVisible(mDisplayState.mode != DisplayState.MODE_LIST);
+
+        final boolean searchVisible;
         if (mAction == ACTION_CREATE) {
-            final FragmentManager fm = getFragmentManager();
+            createDir.setVisible(cwd != null && cwd.isCreateSupported());
+            searchVisible = false;
+
+            // No display options in recent directories
+            if (cwd == null) {
+                grid.setVisible(false);
+                list.setVisible(false);
+            }
+
             SaveFragment.get(fm).setSaveEnabled(cwd != null && cwd.isCreateSupported());
+        } else {
+            createDir.setVisible(false);
+            searchVisible = cwd != null && cwd.isSearchSupported();
         }
 
-        menu.findItem(R.id.menu_grid).setVisible(mDisplayState.mode != DisplayState.MODE_GRID);
-        menu.findItem(R.id.menu_list).setVisible(mDisplayState.mode != DisplayState.MODE_LIST);
+        // TODO: close any search in-progress when hiding
+        search.setVisible(searchVisible);
 
         return true;
     }
@@ -294,6 +310,9 @@
             updateDisplayState();
             invalidateOptionsMenu();
             return true;
+        } else if (id == R.id.menu_settings) {
+            startActivity(new Intent(this, SettingsActivity.class));
+            return true;
         } else {
             return super.onOptionsItemSelected(item);
         }
@@ -304,7 +323,7 @@
         final int size = mStack.size();
         if (size > 1) {
             mStack.pop();
-            updateDirectoryFragment();
+            onCurrentDirectoryChanged();
         } else if (size == 1 && !mDrawerLayout.isDrawerOpen(mRootsContainer)) {
             // TODO: open root drawer once we can capture back key
             super.onBackPressed();
@@ -317,7 +336,7 @@
     private BaseAdapter mSortAdapter = new BaseAdapter() {
         @Override
         public int getCount() {
-            return 2;
+            return mDisplayState.showSize ? 3 : 2;
         }
 
         @Override
@@ -327,6 +346,8 @@
                     return getText(R.string.sort_name);
                 case 1:
                     return getText(R.string.sort_date);
+                case 2:
+                    return getText(R.string.sort_size);
                 default:
                     return null;
             }
@@ -400,9 +421,10 @@
         return mDisplayState;
     }
 
-    private void updateDirectoryFragment() {
+    private void onCurrentDirectoryChanged() {
         final FragmentManager fm = getFragmentManager();
         final Document cwd = getCurrentDirectory();
+
         if (cwd == null) {
             // No directory means recents
             if (mAction == ACTION_CREATE) {
@@ -420,6 +442,14 @@
             }
         }
 
+        // Forget any replacement target
+        if (mAction == ACTION_CREATE) {
+            final SaveFragment save = SaveFragment.get(fm);
+            if (save != null) {
+                save.setReplaceTarget(null);
+            }
+        }
+
         updateActionBar();
         invalidateOptionsMenu();
         dumpStack();
@@ -432,7 +462,7 @@
 
     public void onStackPicked(DocumentStack stack) {
         mStack = stack;
-        updateDirectoryFragment();
+        onCurrentDirectoryChanged();
     }
 
     public void onRootPicked(Root root, boolean closeDrawer) {
@@ -442,7 +472,7 @@
         if (!root.isRecents) {
             onDocumentPicked(Document.fromRoot(getContentResolver(), root));
         } else {
-            updateDirectoryFragment();
+            onCurrentDirectoryChanged();
         }
 
         if (closeDrawer) {
@@ -454,13 +484,13 @@
         final FragmentManager fm = getFragmentManager();
         if (doc.isDirectory()) {
             mStack.push(doc);
-            updateDirectoryFragment();
+            onCurrentDirectoryChanged();
         } else if (mAction == ACTION_OPEN) {
             // Explicit file picked, return
             onFinished(doc.uri);
         } else if (mAction == ACTION_CREATE) {
-            // Overwrite current filename
-            SaveFragment.get(fm).setDisplayName(doc.displayName);
+            // Replace selected file
+            SaveFragment.get(fm).setReplaceTarget(doc);
         }
     }
 
@@ -473,9 +503,11 @@
         onFinished(uris);
     }
 
-    public void onSaveRequested(String mimeType, String displayName) {
-        // TODO: handle overwrite by using last-selected GUID
+    public void onSaveRequested(Document replaceTarget) {
+        onFinished(replaceTarget.uri);
+    }
 
+    public void onSaveRequested(String mimeType, String displayName) {
         final ContentValues values = new ContentValues();
         values.put(DocumentColumns.MIME_TYPE, mimeType);
         values.put(DocumentColumns.DISPLAY_NAME, displayName);
@@ -550,6 +582,7 @@
 
         public static final int SORT_ORDER_NAME = 0;
         public static final int SORT_ORDER_DATE = 1;
+        public static final int SORT_ORDER_SIZE = 2;
     }
 
     private void dumpStack() {
@@ -558,4 +591,8 @@
             Log.d(TAG, "--> " + doc);
         }
     }
+
+    public static DocumentsActivity get(Fragment fragment) {
+        return (DocumentsActivity) fragment.getActivity();
+    }
 }
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java b/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java
index 2651e4c..1e018e7 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java
@@ -169,24 +169,23 @@
 
             final ImageView icon = (ImageView) convertView.findViewById(android.R.id.icon);
             final TextView title = (TextView) convertView.findViewById(android.R.id.title);
-            final View line2 = convertView.findViewById(R.id.line2);
+            final View summaryList = convertView.findViewById(R.id.summary_list);
 
             final DocumentStack stack = getItem(position);
             final Root root = RootsCache.findRoot(context, stack.peek());
             icon.setImageDrawable(root != null ? root.icon : null);
 
             final StringBuilder builder = new StringBuilder();
-            final int size = stack.size();
-            for (int i = 0; i < size; i++) {
+            for (int i = stack.size() - 1; i >= 0; i--) {
                 builder.append(stack.get(i).displayName);
-                if (i <  size - 1) {
+                if (i > 0) {
                     builder.append(" \u232a ");
                 }
             }
             title.setText(builder.toString());
             title.setEllipsize(TruncateAt.MIDDLE);
 
-            line2.setVisibility(View.GONE);
+            summaryList.setVisibility(View.GONE);
 
             return convertView;
         }
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
index c4e9c15..427ad42 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
@@ -24,6 +24,7 @@
 import android.content.Context;
 import android.os.Bundle;
 import android.provider.DocumentsContract;
+import android.text.format.Formatter;
 import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -76,6 +77,14 @@
         return view;
     }
 
+    @Override
+    public void onStart() {
+        super.onStart();
+
+        final Context context = getActivity();
+        mAdapter.setShowAdvanced(SettingsActivity.getDisplayAdvancedDevices(context));
+    }
+
     private OnItemClickListener mItemListener = new OnItemClickListener() {
         @Override
         public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
@@ -94,8 +103,9 @@
 
         @Override
         public View getView(int position, View convertView, ViewGroup parent) {
+            final Context context = parent.getContext();
             if (convertView == null) {
-                convertView = LayoutInflater.from(parent.getContext())
+                convertView = LayoutInflater.from(context)
                         .inflate(R.layout.item_root, parent, false);
             }
 
@@ -107,8 +117,19 @@
             icon.setImageDrawable(root.icon);
             title.setText(root.title);
 
-            summary.setText(root.summary);
-            summary.setVisibility(root.summary != null ? View.VISIBLE : View.GONE);
+            // Device summary is always available space
+            final String summaryText;
+            if ((root.rootType == DocumentsContract.ROOT_TYPE_DEVICE
+                    || root.rootType == DocumentsContract.ROOT_TYPE_DEVICE_ADVANCED)
+                    && root.availableBytes >= 0) {
+                summaryText = context.getString(R.string.root_available_bytes,
+                        Formatter.formatFileSize(context, root.availableBytes));
+            } else {
+                summaryText = root.summary;
+            }
+
+            summary.setText(summaryText);
+            summary.setVisibility(summaryText != null ? View.VISIBLE : View.GONE);
 
             return convertView;
         }
@@ -163,9 +184,6 @@
             mShortcuts.sort(comp);
             mDevices.sort(comp);
             mDevicesAdvanced.sort(comp);
-
-            // TODO: switch to hide advanced items by default
-            setShowAdvanced(true);
         }
 
         public void setShowAdvanced(boolean showAdvanced) {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/SaveFragment.java b/packages/DocumentsUI/src/com/android/documentsui/SaveFragment.java
index 304f6e3..69010dd 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/SaveFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/SaveFragment.java
@@ -21,6 +21,9 @@
 import android.app.FragmentTransaction;
 import android.content.Context;
 import android.os.Bundle;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -28,14 +31,18 @@
 import android.widget.EditText;
 import android.widget.ImageView;
 
+import com.android.documentsui.model.Document;
+
 /**
  * Display document title editor and save button.
  */
 public class SaveFragment extends Fragment {
     public static final String TAG = "SaveFragment";
 
+    private Document mReplaceTarget;
     private EditText mDisplayName;
     private Button mSave;
+    private boolean mIgnoreNextEdit;
 
     private static final String EXTRA_MIME_TYPE = "mime_type";
     private static final String EXTRA_DISPLAY_NAME = "display_name";
@@ -69,6 +76,7 @@
                 context, null, getArguments().getString(EXTRA_MIME_TYPE)));
 
         mDisplayName = (EditText) view.findViewById(android.R.id.title);
+        mDisplayName.addTextChangedListener(mDisplayNameWatcher);
         mDisplayName.setText(getArguments().getString(EXTRA_DISPLAY_NAME));
 
         mSave = (Button) view.findViewById(android.R.id.button1);
@@ -78,18 +86,55 @@
         return view;
     }
 
-    private View.OnClickListener mSaveListener = new View.OnClickListener() {
+    private TextWatcher mDisplayNameWatcher = new TextWatcher() {
         @Override
-        public void onClick(View v) {
-            final String mimeType = getArguments().getString(EXTRA_MIME_TYPE);
-            final String displayName = mDisplayName.getText().toString();
-            ((DocumentsActivity) getActivity()).onSaveRequested(mimeType, displayName);
+        public void onTextChanged(CharSequence s, int start, int before, int count) {
+            if (mIgnoreNextEdit) {
+                mIgnoreNextEdit = false;
+            } else {
+                Log.d(TAG, "onTextChanged!");
+                mReplaceTarget = null;
+            }
+        }
+
+        @Override
+        public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+            // ignored
+        }
+
+        @Override
+        public void afterTextChanged(Editable s) {
+            // ignored
         }
     };
 
-    public void setDisplayName(String displayName) {
-        getArguments().putString(EXTRA_DISPLAY_NAME, displayName);
-        mDisplayName.setText(displayName);
+    private View.OnClickListener mSaveListener = new View.OnClickListener() {
+        @Override
+        public void onClick(View v) {
+            final DocumentsActivity activity = DocumentsActivity.get(SaveFragment.this);
+            if (mReplaceTarget != null) {
+                activity.onSaveRequested(mReplaceTarget);
+            } else {
+                final String mimeType = getArguments().getString(EXTRA_MIME_TYPE);
+                final String displayName = mDisplayName.getText().toString();
+                activity.onSaveRequested(mimeType, displayName);
+            }
+        }
+    };
+
+    /**
+     * Set given document as target for in-place writing if user hits save
+     * without changing the filename. Can be set to {@code null} if user
+     * navigates outside the target directory.
+     */
+    public void setReplaceTarget(Document replaceTarget) {
+        mReplaceTarget = replaceTarget;
+
+        if (mReplaceTarget != null) {
+            getArguments().putString(EXTRA_DISPLAY_NAME, replaceTarget.displayName);
+            mIgnoreNextEdit = true;
+            mDisplayName.setText(replaceTarget.displayName);
+        }
     }
 
     public void setSaveEnabled(boolean enabled) {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/SettingsActivity.java b/packages/DocumentsUI/src/com/android/documentsui/SettingsActivity.java
new file mode 100644
index 0000000..ceeaaae
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/SettingsActivity.java
@@ -0,0 +1,53 @@
+/*
+ * 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 android.app.Activity;
+import android.content.Context;
+import android.os.Bundle;
+import android.preference.PreferenceFragment;
+import android.preference.PreferenceManager;
+
+public class SettingsActivity extends Activity {
+    private static final String KEY_ADVANCED_DEVICES = "advancedDevices";
+    private static final String KEY_FILE_SIZE = "fileSize";
+
+    public static boolean getDisplayAdvancedDevices(Context context) {
+        return PreferenceManager.getDefaultSharedPreferences(context)
+                .getBoolean(KEY_ADVANCED_DEVICES, false);
+    }
+
+    public static boolean getDisplayFileSize(Context context) {
+        return PreferenceManager.getDefaultSharedPreferences(context)
+                .getBoolean(KEY_FILE_SIZE, false);
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        getFragmentManager()
+                .beginTransaction().replace(android.R.id.content, new SettingsFragment()).commit();
+    }
+
+    public static class SettingsFragment extends PreferenceFragment {
+        @Override
+        public void onCreate(Bundle savedInstanceState) {
+            super.onCreate(savedInstanceState);
+            addPreferencesFromResource(R.xml.preferences);
+        }
+    }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/model/Document.java b/packages/DocumentsUI/src/com/android/documentsui/model/Document.java
index 3b82ba8..f274465 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/model/Document.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/model/Document.java
@@ -21,6 +21,7 @@
 import android.net.Uri;
 import android.provider.DocumentsContract;
 import android.provider.DocumentsContract.DocumentColumns;
+import android.util.Log;
 
 import com.android.documentsui.RecentsProvider;
 
@@ -69,25 +70,25 @@
         return new Document(uri, mimeType, displayName, lastModified, flags, summary, size);
     }
 
-    public static Document fromRecentOpenCursor(ContentResolver resolver, Cursor cursor) {
-        final Uri uri = Uri.parse(getCursorString(cursor, RecentsProvider.COL_URI));
-        final long lastModified = getCursorLong(cursor, RecentsProvider.COL_TIMESTAMP);
+    public static Document fromRecentOpenCursor(ContentResolver resolver, Cursor recentCursor) {
+        final Uri uri = Uri.parse(getCursorString(recentCursor, RecentsProvider.COL_URI));
+        final long lastModified = getCursorLong(recentCursor, RecentsProvider.COL_TIMESTAMP);
 
-        final Cursor itemCursor = resolver.query(uri, null, null, null, null);
+        final Cursor cursor = resolver.query(uri, null, null, null, null);
         try {
-            if (!itemCursor.moveToFirst()) {
+            if (!cursor.moveToFirst()) {
                 throw new IllegalArgumentException("Missing details for " + uri);
             }
-            final String mimeType = getCursorString(itemCursor, DocumentColumns.MIME_TYPE);
-            final String displayName = getCursorString(itemCursor, DocumentColumns.DISPLAY_NAME);
-            final int flags = getCursorInt(itemCursor, DocumentColumns.FLAGS)
+            final String mimeType = getCursorString(cursor, DocumentColumns.MIME_TYPE);
+            final String displayName = getCursorString(cursor, DocumentColumns.DISPLAY_NAME);
+            final int flags = getCursorInt(cursor, DocumentColumns.FLAGS)
                     & DocumentsContract.FLAG_SUPPORTS_THUMBNAIL;
             final String summary = getCursorString(cursor, DocumentColumns.SUMMARY);
             final long size = getCursorLong(cursor, DocumentColumns.SIZE);
 
             return new Document(uri, mimeType, displayName, lastModified, flags, summary, size);
         } finally {
-            itemCursor.close();
+            cursor.close();
         }
     }
 
@@ -166,4 +167,11 @@
             return Long.compare(rhs.lastModified, lhs.lastModified);
         }
     }
+
+    public static class SizeComparator implements Comparator<Document> {
+        @Override
+        public int compare(Document lhs, Document rhs) {
+            return Long.compare(rhs.size, lhs.size);
+        }
+    }
 }
diff --git a/packages/DocumentsUI/src/com/android/documentsui/model/DocumentStack.java b/packages/DocumentsUI/src/com/android/documentsui/model/DocumentStack.java
index dade8a3..67dca07 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/model/DocumentStack.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/model/DocumentStack.java
@@ -42,7 +42,7 @@
     }
 
     public static DocumentStack deserialize(ContentResolver resolver, String raw) {
-        Log.d(TAG, "restoreStack: " + raw);
+        Log.d(TAG, "deserialize: " + raw);
 
         final DocumentStack stack = new DocumentStack();
         try {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/model/Root.java b/packages/DocumentsUI/src/com/android/documentsui/model/Root.java
index 629dbc4..0880731 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/model/Root.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/model/Root.java
@@ -27,7 +27,6 @@
 import android.provider.DocumentsContract.RootColumns;
 
 import com.android.documentsui.R;
-import com.android.documentsui.RecentsProvider;
 
 import java.util.Comparator;
 
@@ -41,6 +40,7 @@
     public Drawable icon;
     public String title;
     public String summary;
+    public long availableBytes = -1;
     public boolean isRecents;
 
     public static Root buildRecents(Context context) {
@@ -52,6 +52,7 @@
         root.icon = context.getResources().getDrawable(R.drawable.ic_dir);
         root.title = context.getString(R.string.root_recent);
         root.summary = null;
+        root.availableBytes = -1;
         root.isRecents = true;
         return root;
     }
@@ -67,6 +68,7 @@
                 info.providerInfo.authority, root.rootId, DocumentsContract.ROOT_DOC_ID);
         root.icon = info.providerInfo.loadIcon(pm);
         root.title = info.providerInfo.loadLabel(pm).toString();
+        root.availableBytes = cursor.getLong(cursor.getColumnIndex(RootColumns.AVAILABLE_BYTES));
         root.summary = null;
 
         final int icon = cursor.getInt(cursor.getColumnIndex(RootColumns.ICON));