New storage dialogs.

Show a helpful dialog when a volume is unmounted or unmountable, or
when disk is unsupported.  Add both missing private volumes and
unsupported disks in the storage list.  Dialog to confirm when
forgetting private volume.

Finish volume detail activities when the volume becomes unmounted.

Show used space instead of free space to match string.  When init'ing
a volume on non-adoptable disk, just format as public.

Bug: 21737573, 21666225, 21737666, 21471429
Change-Id: Id60d5a398e2b7923ebebdc5cfaef33248d8d77bb
diff --git a/src/com/android/settings/deviceinfo/PrivateVolumeForget.java b/src/com/android/settings/deviceinfo/PrivateVolumeForget.java
index c8b04e3..7e7207f 100644
--- a/src/com/android/settings/deviceinfo/PrivateVolumeForget.java
+++ b/src/com/android/settings/deviceinfo/PrivateVolumeForget.java
@@ -16,6 +16,12 @@
 
 package com.android.settings.deviceinfo;
 
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.DialogFragment;
+import android.app.Fragment;
+import android.content.Context;
+import android.content.DialogInterface;
 import android.os.Bundle;
 import android.os.storage.StorageManager;
 import android.os.storage.VolumeRecord;
@@ -32,6 +38,8 @@
 import com.android.settings.R;
 
 public class PrivateVolumeForget extends InstrumentedFragment {
+    private static final String TAG_FORGET_CONFIRM = "forget_confirm";
+
     private VolumeRecord mRecord;
 
     @Override
@@ -60,9 +68,46 @@
     private final OnClickListener mConfirmListener = new OnClickListener() {
         @Override
         public void onClick(View v) {
-            final StorageManager storage = getActivity().getSystemService(StorageManager.class);
-            storage.forgetVolume(mRecord.getFsUuid());
-            getActivity().finish();
+            ForgetConfirmFragment.show(PrivateVolumeForget.this, mRecord.getFsUuid());
         }
     };
+
+    private static class ForgetConfirmFragment extends DialogFragment {
+        public static void show(Fragment parent, String fsUuid) {
+            final Bundle args = new Bundle();
+            args.putString(VolumeRecord.EXTRA_FS_UUID, fsUuid);
+
+            final ForgetConfirmFragment dialog = new ForgetConfirmFragment();
+            dialog.setArguments(args);
+            dialog.setTargetFragment(parent, 0);
+            dialog.show(parent.getFragmentManager(), TAG_FORGET_CONFIRM);
+        }
+
+        @Override
+        public Dialog onCreateDialog(Bundle savedInstanceState) {
+            final Context context = getActivity();
+            final StorageManager storage = context.getSystemService(StorageManager.class);
+
+            final String fsUuid = getArguments().getString(VolumeRecord.EXTRA_FS_UUID);
+            final VolumeRecord record = storage.findRecordByUuid(fsUuid);
+
+            final AlertDialog.Builder builder = new AlertDialog.Builder(context);
+            builder.setTitle(TextUtils.expandTemplate(
+                    getText(R.string.storage_internal_forget_confirm_title), record.getNickname()));
+            builder.setMessage(TextUtils.expandTemplate(
+                    getText(R.string.storage_internal_forget_confirm), record.getNickname()));
+
+            builder.setPositiveButton(R.string.storage_menu_forget,
+                    new DialogInterface.OnClickListener() {
+                @Override
+                public void onClick(DialogInterface dialog, int which) {
+                    storage.forgetVolume(fsUuid);
+                    getActivity().finish();
+                }
+            });
+            builder.setNegativeButton(R.string.cancel, null);
+
+            return builder.create();
+        }
+    }
 }
diff --git a/src/com/android/settings/deviceinfo/PrivateVolumeSettings.java b/src/com/android/settings/deviceinfo/PrivateVolumeSettings.java
index 7cefe4a..9944c08 100644
--- a/src/com/android/settings/deviceinfo/PrivateVolumeSettings.java
+++ b/src/com/android/settings/deviceinfo/PrivateVolumeSettings.java
@@ -173,6 +173,8 @@
         screen.removeAll();
 
         if (!mVolume.isMountedReadable()) {
+            Log.d(TAG, "Leaving details fragment due to state " + mVolume.getState());
+            finish();
             return;
         }
 
@@ -288,6 +290,8 @@
             format.setVisible(true);
         }
 
+        format.setTitle(R.string.storage_menu_format_public);
+
         // Only offer to migrate when not current storage
         final VolumeInfo privateVol = getActivity().getPackageManager()
                 .getPrimaryStorageCurrentVolume();
diff --git a/src/com/android/settings/deviceinfo/PublicVolumeSettings.java b/src/com/android/settings/deviceinfo/PublicVolumeSettings.java
index 44c60e9..677a99b 100644
--- a/src/com/android/settings/deviceinfo/PublicVolumeSettings.java
+++ b/src/com/android/settings/deviceinfo/PublicVolumeSettings.java
@@ -16,6 +16,8 @@
 
 package com.android.settings.deviceinfo;
 
+import static com.android.settings.deviceinfo.StorageSettings.TAG;
+
 import android.content.Context;
 import android.content.Intent;
 import android.net.Uri;
@@ -29,6 +31,7 @@
 import android.preference.PreferenceScreen;
 import android.provider.DocumentsContract;
 import android.text.format.Formatter;
+import android.util.Log;
 
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.util.Preconditions;
@@ -61,8 +64,8 @@
 
     private Preference mMount;
     private Preference mUnmount;
-    private Preference mFormat;
-    private Preference mFormatInternal;
+    private Preference mFormatPublic;
+    private Preference mFormatPrivate;
 
     private long mTotalSize;
     private long mAvailSize;
@@ -106,8 +109,8 @@
 
         mMount = buildAction(R.string.storage_menu_mount);
         mUnmount = buildAction(R.string.storage_menu_unmount);
-        mFormat = buildAction(R.string.storage_menu_format);
-        mFormatInternal = buildAction(R.string.storage_menu_format_private);
+        mFormatPublic = buildAction(R.string.storage_menu_format);
+        mFormatPrivate = buildAction(R.string.storage_menu_format_private);
     }
 
     public void update() {
@@ -118,6 +121,12 @@
 
         screen.removeAll();
 
+        if (!mVolume.isMountedReadable()) {
+            Log.d(TAG, "Leaving details fragment due to state " + mVolume.getState());
+            finish();
+            return;
+        }
+
         if (mVolume.isMountedReadable()) {
             screen.addPreference(mGraph);
             screen.addPreference(mTotal);
@@ -142,9 +151,9 @@
         if (mVolume.isMountedReadable()) {
             screen.addPreference(mUnmount);
         }
-        screen.addPreference(mFormat);
+        screen.addPreference(mFormatPublic);
         if (mDisk.isAdoptable()) {
-            screen.addPreference(mFormatInternal);
+            screen.addPreference(mFormatPrivate);
         }
     }
 
@@ -196,12 +205,12 @@
             new MountTask(context, mVolume).execute();
         } else if (pref == mUnmount) {
             new UnmountTask(context, mVolume).execute();
-        } else if (pref == mFormat) {
+        } else if (pref == mFormatPublic) {
             final Intent intent = new Intent(context, StorageWizardFormatConfirm.class);
             intent.putExtra(DiskInfo.EXTRA_DISK_ID, mDisk.getId());
             intent.putExtra(StorageWizardFormatConfirm.EXTRA_FORMAT_PRIVATE, false);
             startActivity(intent);
-        } else if (pref == mFormatInternal) {
+        } else if (pref == mFormatPrivate) {
             final Intent intent = new Intent(context, StorageWizardFormatConfirm.class);
             intent.putExtra(DiskInfo.EXTRA_DISK_ID, mDisk.getId());
             intent.putExtra(StorageWizardFormatConfirm.EXTRA_FORMAT_PRIVATE, true);
diff --git a/src/com/android/settings/deviceinfo/StorageSettings.java b/src/com/android/settings/deviceinfo/StorageSettings.java
index b5b3841..546c716 100644
--- a/src/com/android/settings/deviceinfo/StorageSettings.java
+++ b/src/com/android/settings/deviceinfo/StorageSettings.java
@@ -16,20 +16,26 @@
 
 package com.android.settings.deviceinfo;
 
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.DialogFragment;
+import android.app.Fragment;
 import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
 import android.os.AsyncTask;
 import android.os.Bundle;
 import android.os.UserManager;
+import android.os.storage.DiskInfo;
 import android.os.storage.StorageEventListener;
 import android.os.storage.StorageManager;
 import android.os.storage.VolumeInfo;
+import android.os.storage.VolumeRecord;
 import android.preference.Preference;
 import android.preference.PreferenceCategory;
 import android.preference.PreferenceScreen;
+import android.text.TextUtils;
 import android.util.Log;
-import android.view.Menu;
-import android.view.MenuInflater;
-import android.view.MenuItem;
 import android.widget.Toast;
 
 import com.android.internal.logging.MetricsLogger;
@@ -50,8 +56,10 @@
 public class StorageSettings extends SettingsPreferenceFragment implements Indexable {
     static final String TAG = "StorageSettings";
 
+    private static final String TAG_VOLUME_UNMOUNTED = "volume_unmounted";
+    private static final String TAG_DISK_INIT = "disk_init";
+
     // TODO: badging to indicate devices running low on storage
-    // TODO: show currently ejected private volumes
 
     private UserManager mUserManager;
     private StorageManager mStorageManager;
@@ -127,6 +135,33 @@
             }
         }
 
+        // Show missing private volumes
+        final List<VolumeRecord> recs = mStorageManager.getVolumeRecords();
+        for (VolumeRecord rec : recs) {
+            if (rec.getType() == VolumeInfo.TYPE_PRIVATE
+                    && mStorageManager.findVolumeByUuid(rec.getFsUuid()) == null) {
+                final Preference pref = new Preference(context);
+                pref.setKey(rec.getFsUuid());
+                pref.setTitle(rec.getNickname());
+                pref.setSummary(com.android.internal.R.string.ext_media_status_missing);
+                pref.setIcon(R.drawable.ic_settings_storage);
+                mInternalCategory.addPreference(pref);
+            }
+        }
+
+        // Show unsupported disks to give a chance to init
+        final List<DiskInfo> disks = mStorageManager.getDisks();
+        for (DiskInfo disk : disks) {
+            if (disk.volumeCount == 0 && disk.size > 0) {
+                final Preference pref = new Preference(context);
+                pref.setKey(disk.getId());
+                pref.setTitle(disk.getDescription());
+                pref.setSummary(com.android.internal.R.string.ext_media_status_unsupported);
+                pref.setIcon(R.drawable.ic_sim_sd);
+                mExternalCategory.addPreference(pref);
+            }
+        }
+
         if (mInternalCategory.getPreferenceCount() > 0) {
             getPreferenceScreen().addPreference(mInternalCategory);
         }
@@ -150,29 +185,51 @@
 
     @Override
     public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference pref) {
-        final String volId = pref.getKey();
-        final VolumeInfo vol = mStorageManager.findVolumeById(volId);
-        if (vol == null) {
-            return false;
+        final String key = pref.getKey();
+        if (pref instanceof StorageVolumePreference) {
+            // Picked a normal volume
+            final VolumeInfo vol = mStorageManager.findVolumeById(key);
 
-        } else if (vol.getType() == VolumeInfo.TYPE_PRIVATE) {
-            final Bundle args = new Bundle();
-            args.putString(VolumeInfo.EXTRA_VOLUME_ID, volId);
-            startFragment(this, PrivateVolumeSettings.class.getCanonicalName(),
-                    -1, 0, args);
-            return true;
-
-        } else if (vol.getType() == VolumeInfo.TYPE_PUBLIC) {
-            if (vol.isMountedReadable()) {
-                startActivity(vol.buildBrowseIntent());
+            if (vol.getState() == VolumeInfo.STATE_UNMOUNTED) {
+                VolumeUnmountedFragment.show(this, vol.getId());
                 return true;
-            } else {
-                final Bundle args = new Bundle();
-                args.putString(VolumeInfo.EXTRA_VOLUME_ID, volId);
-                startFragment(this, PublicVolumeSettings.class.getCanonicalName(),
-                        -1, 0, args);
+            } else if (vol.getState() == VolumeInfo.STATE_UNMOUNTABLE) {
+                DiskInitFragment.show(this, R.string.storage_dialog_unmountable, vol.getDiskId());
                 return true;
             }
+
+            if (vol.getType() == VolumeInfo.TYPE_PRIVATE) {
+                final Bundle args = new Bundle();
+                args.putString(VolumeInfo.EXTRA_VOLUME_ID, vol.getId());
+                startFragment(this, PrivateVolumeSettings.class.getCanonicalName(),
+                        -1, 0, args);
+                return true;
+
+            } else if (vol.getType() == VolumeInfo.TYPE_PUBLIC) {
+                if (vol.isMountedReadable()) {
+                    startActivity(vol.buildBrowseIntent());
+                    return true;
+                } else {
+                    final Bundle args = new Bundle();
+                    args.putString(VolumeInfo.EXTRA_VOLUME_ID, vol.getId());
+                    startFragment(this, PublicVolumeSettings.class.getCanonicalName(),
+                            -1, 0, args);
+                    return true;
+                }
+            }
+
+        } else if (key.startsWith("disk:")) {
+            // Picked an unsupported disk
+            DiskInitFragment.show(this, R.string.storage_dialog_unsupported, key);
+            return true;
+
+        } else {
+            // Picked a missing private volume
+            final Bundle args = new Bundle();
+            args.putString(VolumeRecord.EXTRA_FS_UUID, key);
+            startFragment(this, PrivateVolumeForget.class.getCanonicalName(),
+                    R.string.storage_menu_forget, 0, args);
+            return true;
         }
 
         return false;
@@ -250,6 +307,81 @@
         }
     }
 
+    private static class VolumeUnmountedFragment extends DialogFragment {
+        public static void show(Fragment parent, String volumeId) {
+            final Bundle args = new Bundle();
+            args.putString(VolumeInfo.EXTRA_VOLUME_ID, volumeId);
+
+            final VolumeUnmountedFragment dialog = new VolumeUnmountedFragment();
+            dialog.setArguments(args);
+            dialog.setTargetFragment(parent, 0);
+            dialog.show(parent.getFragmentManager(), TAG_VOLUME_UNMOUNTED);
+        }
+
+        @Override
+        public Dialog onCreateDialog(Bundle savedInstanceState) {
+            final Context context = getActivity();
+            final StorageManager sm = context.getSystemService(StorageManager.class);
+
+            final String volumeId = getArguments().getString(VolumeInfo.EXTRA_VOLUME_ID);
+            final VolumeInfo vol = sm.findVolumeById(volumeId);
+
+            final AlertDialog.Builder builder = new AlertDialog.Builder(context);
+            builder.setMessage(TextUtils.expandTemplate(
+                    getText(R.string.storage_dialog_unmounted), vol.getDisk().getDescription()));
+
+            builder.setPositiveButton(R.string.storage_menu_mount,
+                    new DialogInterface.OnClickListener() {
+                @Override
+                public void onClick(DialogInterface dialog, int which) {
+                    new MountTask(context, vol).execute();
+                }
+            });
+            builder.setNegativeButton(R.string.cancel, null);
+
+            return builder.create();
+        }
+    }
+
+    private static class DiskInitFragment extends DialogFragment {
+        public static void show(Fragment parent, int resId, String diskId) {
+            final Bundle args = new Bundle();
+            args.putInt(Intent.EXTRA_TEXT, resId);
+            args.putString(DiskInfo.EXTRA_DISK_ID, diskId);
+
+            final DiskInitFragment dialog = new DiskInitFragment();
+            dialog.setArguments(args);
+            dialog.setTargetFragment(parent, 0);
+            dialog.show(parent.getFragmentManager(), TAG_DISK_INIT);
+        }
+
+        @Override
+        public Dialog onCreateDialog(Bundle savedInstanceState) {
+            final Context context = getActivity();
+            final StorageManager sm = context.getSystemService(StorageManager.class);
+
+            final int resId = getArguments().getInt(Intent.EXTRA_TEXT);
+            final String diskId = getArguments().getString(DiskInfo.EXTRA_DISK_ID);
+            final DiskInfo disk = sm.findDiskById(diskId);
+
+            final AlertDialog.Builder builder = new AlertDialog.Builder(context);
+            builder.setMessage(TextUtils.expandTemplate(getText(resId), disk.getDescription()));
+
+            builder.setPositiveButton(R.string.storage_menu_set_up,
+                    new DialogInterface.OnClickListener() {
+                @Override
+                public void onClick(DialogInterface dialog, int which) {
+                    final Intent intent = new Intent(context, StorageWizardInit.class);
+                    intent.putExtra(DiskInfo.EXTRA_DISK_ID, diskId);
+                    startActivity(intent);
+                }
+            });
+            builder.setNegativeButton(R.string.cancel, null);
+
+            return builder.create();
+        }
+    }
+
     /**
      * Enable indexing of searchable data
      */
diff --git a/src/com/android/settings/deviceinfo/StorageVolumePreference.java b/src/com/android/settings/deviceinfo/StorageVolumePreference.java
index 852aa39..e122bf8 100644
--- a/src/com/android/settings/deviceinfo/StorageVolumePreference.java
+++ b/src/com/android/settings/deviceinfo/StorageVolumePreference.java
@@ -50,9 +50,12 @@
         if (volume.isMountedReadable()) {
             // TODO: move statfs() to background thread
             final File path = volume.getPath();
-            final String free = Formatter.formatFileSize(context, path.getFreeSpace());
+            final long usedBytes = path.getTotalSpace() - path.getFreeSpace();
+            final String used = Formatter.formatFileSize(context, usedBytes);
             final String total = Formatter.formatFileSize(context, path.getTotalSpace());
-            setSummary(context.getString(R.string.storage_volume_summary, free, total));
+            setSummary(context.getString(R.string.storage_volume_summary, used, total));
+        } else {
+            setSummary(volume.getStateDescription());
         }
 
         // TODO: better icons
diff --git a/src/com/android/settings/deviceinfo/StorageWizardFormatConfirm.java b/src/com/android/settings/deviceinfo/StorageWizardFormatConfirm.java
index 874dc2c..b35b8ec 100644
--- a/src/com/android/settings/deviceinfo/StorageWizardFormatConfirm.java
+++ b/src/com/android/settings/deviceinfo/StorageWizardFormatConfirm.java
@@ -20,7 +20,6 @@
 import android.os.Bundle;
 import android.os.storage.DiskInfo;
 
-import com.android.internal.util.Preconditions;
 import com.android.settings.R;
 
 public class StorageWizardFormatConfirm extends StorageWizardBase {
diff --git a/src/com/android/settings/deviceinfo/StorageWizardFormatProgress.java b/src/com/android/settings/deviceinfo/StorageWizardFormatProgress.java
index df2adfd..75d1758 100644
--- a/src/com/android/settings/deviceinfo/StorageWizardFormatProgress.java
+++ b/src/com/android/settings/deviceinfo/StorageWizardFormatProgress.java
@@ -33,7 +33,6 @@
 import android.view.View;
 import android.widget.Toast;
 
-import com.android.internal.util.Preconditions;
 import com.android.settings.R;
 
 public class StorageWizardFormatProgress extends StorageWizardBase {
diff --git a/src/com/android/settings/deviceinfo/StorageWizardInit.java b/src/com/android/settings/deviceinfo/StorageWizardInit.java
index 61dfaaf..b0211bf 100644
--- a/src/com/android/settings/deviceinfo/StorageWizardInit.java
+++ b/src/com/android/settings/deviceinfo/StorageWizardInit.java
@@ -24,7 +24,6 @@
 import android.widget.CompoundButton.OnCheckedChangeListener;
 import android.widget.RadioButton;
 
-import com.android.internal.util.Preconditions;
 import com.android.settings.R;
 
 public class StorageWizardInit extends StorageWizardBase {
@@ -56,6 +55,13 @@
                 mRadioExternal.getCompoundPaddingRight(), 0);
 
         getNextButton().setEnabled(false);
+
+        if (!mDisk.isAdoptable()) {
+            // If not adoptable, we only have one choice
+            mRadioExternal.setChecked(true);
+            onNavigateNext();
+            finish();
+        }
     }
 
     private final OnCheckedChangeListener mRadioListener = new OnCheckedChangeListener() {