Fix up storage UI for old USB storage.

- In the storage overview, if storage is not emulated then we have a
new first section showing internal storage.
- In manage applications, we know show storage use on the SD card
separately from internal storage use.

Change-Id: I7eb993f59fdb5de5f5dcfe4a3bc2b95ae30d754a
diff --git a/res/layout/installed_app_details.xml b/res/layout/installed_app_details.xml
index 6392ee9..afec517 100644
--- a/res/layout/installed_app_details.xml
+++ b/res/layout/installed_app_details.xml
@@ -135,6 +135,43 @@
             </LinearLayout>
 
             <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:orientation="horizontal"
+                android:baselineAligned="true"
+                android:paddingTop="-1dip">
+                <TextView
+                    android:id="@+id/external_code_size_prefix"
+                    android:text="@string/external_code_size_label"
+                    android:textAppearance="?android:attr/textAppearanceMedium"
+                    android:layout_height="wrap_content"
+                    android:layout_width="wrap_content"
+                    android:maxLines="1"
+                    android:paddingTop="6dip"
+                    android:paddingLeft="6dip"/>
+                <ImageView
+                    android:id="@+id/info_size_dots"
+                    android:src="@drawable/dotted_line_480px"
+                    android:layout_width="0dip"
+                    android:layout_weight="1"
+                    android:layout_height="1px"
+                    android:layout_gravity="bottom"
+                    android:layout_marginLeft="1dip"
+                    android:layout_marginRight="1dip"
+                    android:layout_marginBottom="4dip"
+                    android:scaleType="center" />
+                <TextView
+                    android:id="@+id/external_code_size_text"
+                    android:textAppearance="?android:attr/textAppearanceMedium"
+                    android:paddingTop="6dip"
+                    android:paddingRight="6dip"
+                    android:layout_height="wrap_content"
+                    android:layout_width="wrap_content"
+                    android:maxLines="1" />
+
+            </LinearLayout>
+
+            <LinearLayout
                 android:id="@+id/info_size"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
@@ -179,8 +216,8 @@
                 android:baselineAligned="true"
                 android:paddingTop="-1dip">
                 <TextView
-                    android:id="@+id/external_size_prefix"
-                    android:text="@string/external_size_label"
+                    android:id="@+id/external_data_size_prefix"
+                    android:text="@string/external_data_size_label"
                     android:textAppearance="?android:attr/textAppearanceMedium"
                     android:layout_height="wrap_content"
                     android:layout_width="wrap_content"
@@ -199,7 +236,7 @@
                     android:layout_marginBottom="4dip"
                     android:scaleType="center" />
                 <TextView
-                    android:id="@+id/external_size_text"
+                    android:id="@+id/external_data_size_text"
                     android:textAppearance="?android:attr/textAppearanceMedium"
                     android:paddingTop="6dip"
                     android:paddingRight="6dip"
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 137b171..1cf4697 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -2193,12 +2193,14 @@
     <string name="total_size_label">Total</string>
     <!-- Manage applications, individual application info screen, label under Storage heading. The amount of space taken up by the application itself (for example, the java compield files and things like that) -->
     <string name="application_size_label">Application</string>
+    <!--  Manage applications, individual application info screen, label under Storage heading.  The amount of space taken up by the app's code on USB storage [CHARSIZE=40] -->
+    <string name="external_code_size_label">USB storage app</string>
     <!-- Manage applications, individual application info screen, label under Storage heading.  The amount of sapce taken up by the app's data (for example, downloaded emails or something like that) -->
     <string name="data_size_label">Data</string>
     <!--  Manage applications, individual application info screen, label under Storage heading.  The amount of space taken up by the app's data on USB storage [CHARSIZE=40] -->
-    <string name="external_size_label" product="nosdcard">USB storage</string>
+    <string name="external_data_size_label" product="nosdcard">USB storage data</string>
     <!--  Manage applications, individual application info screen, label under Storage heading.  The amount of space taken up by the app's data on the SD card [CHARSIZE=40] -->
-    <string name="external_size_label" product="default">SD card</string>
+    <string name="external_data_size_label" product="default">SD card</string>
     <!-- Manage applications, individual application info screen, button label under Storage heading. Button to remove the application from the system. -->
     <string name="uninstall_text">Uninstall</string>
     <!-- [CHAR LIMIT=25] Manage applications, individual application info screen, button label under Storage heading. Button to disable an existing application. -->
diff --git a/src/com/android/settings/applications/ApplicationsState.java b/src/com/android/settings/applications/ApplicationsState.java
index 31fd078..519c203 100644
--- a/src/com/android/settings/applications/ApplicationsState.java
+++ b/src/com/android/settings/applications/ApplicationsState.java
@@ -5,14 +5,11 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.IPackageStatsObserver;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageStats;
 import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.res.Configuration;
-import android.content.res.Resources;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
 import android.os.Handler;
@@ -74,7 +71,8 @@
         long cacheSize;
         long codeSize;
         long dataSize;
-        long externalSize;
+        long externalCodeSize;
+        long externalDataSize;
     }
     
     public static class AppEntry extends SizeInfo {
@@ -97,6 +95,8 @@
         ApplicationInfo info;
         Drawable icon;
         String sizeStr;
+        String internalSizeStr;
+        String externalSizeStr;
         boolean sizeStale;
         long sizeLoadStart;
 
@@ -660,8 +660,8 @@
 
     private long getTotalExternalSize(PackageStats ps) {
         if (ps != null) {
-            return ps.externalDataSize + ps.externalMediaSize + ps.externalCacheSize
-                    + ps.externalObbSize;
+            return ps.externalCodeSize + ps.externalDataSize
+                    + ps.externalMediaSize + ps.externalObbSize;
         }
         return SIZE_INVALID;
     }
@@ -693,19 +693,27 @@
                         synchronized (entry) {
                             entry.sizeStale = false;
                             entry.sizeLoadStart = 0;
-                            long externalSize = getTotalExternalSize(stats);
-                            long newSize = externalSize + getTotalInternalSize(stats);
+                            long externalCodeSize = stats.externalCodeSize
+                                    + stats.externalObbSize;
+                            long externalDataSize = stats.externalDataSize
+                                    + stats.externalMediaSize + stats.externalCacheSize;
+                            long newSize = externalCodeSize + externalDataSize
+                                    + getTotalInternalSize(stats);
                             if (entry.size != newSize ||
                                     entry.cacheSize != stats.cacheSize ||
                                     entry.codeSize != stats.codeSize ||
                                     entry.dataSize != stats.dataSize ||
-                                    entry.externalSize != externalSize) {
+                                    entry.externalCodeSize != externalCodeSize ||
+                                    entry.externalDataSize != externalDataSize) {
                                 entry.size = newSize;
                                 entry.cacheSize = stats.cacheSize;
                                 entry.codeSize = stats.codeSize;
                                 entry.dataSize = stats.dataSize;
-                                entry.externalSize = externalSize;
+                                entry.externalCodeSize = externalCodeSize;
+                                entry.externalDataSize = externalDataSize;
                                 entry.sizeStr = getSizeStr(entry.size);
+                                entry.internalSizeStr = getSizeStr(getTotalInternalSize(stats));
+                                entry.externalSizeStr = getSizeStr(getTotalExternalSize(stats));
                                 if (DEBUG) Log.i(TAG, "Set size of " + entry.label + " " + entry
                                         + ": " + entry.sizeStr);
                                 sizeChanged = true;
diff --git a/src/com/android/settings/applications/InstalledAppDetails.java b/src/com/android/settings/applications/InstalledAppDetails.java
index 1c02f74..ab46661 100644
--- a/src/com/android/settings/applications/InstalledAppDetails.java
+++ b/src/com/android/settings/applications/InstalledAppDetails.java
@@ -103,7 +103,8 @@
     private TextView mTotalSize;
     private TextView mAppSize;
     private TextView mDataSize;
-    private TextView mExternalSize;
+    private TextView mExternalCodeSize;
+    private TextView mExternalDataSize;
     private ClearUserDataObserver mClearDataObserver;
     // Views related to cache info
     private TextView mCacheSize;
@@ -118,7 +119,8 @@
     private boolean mHaveSizes = false;
     private long mLastCodeSize = -1;
     private long mLastDataSize = -1;
-    private long mLastExternalSize = -1;
+    private long mLastExternalCodeSize = -1;
+    private long mLastExternalDataSize = -1;
     private long mLastCacheSize = -1;
     private long mLastTotalSize = -1;
     
@@ -331,7 +333,8 @@
         mTotalSize = (TextView)view.findViewById(R.id.total_size_text);
         mAppSize = (TextView)view.findViewById(R.id.application_size_text);
         mDataSize = (TextView)view.findViewById(R.id.data_size_text);
-        mExternalSize = (TextView)view.findViewById(R.id.external_size_text);
+        mExternalCodeSize = (TextView)view.findViewById(R.id.external_code_size_text);
+        mExternalDataSize = (TextView)view.findViewById(R.id.external_data_size_text);
         
         // Get Control button panel
         View btnPanel = view.findViewById(R.id.control_buttons_panel);
@@ -547,9 +550,13 @@
                 mLastDataSize = mAppEntry.dataSize;
                 mDataSize.setText(getSizeStr(mAppEntry.dataSize));
             }
-            if (mLastExternalSize != mAppEntry.externalSize) {
-                mLastExternalSize = mAppEntry.externalSize;
-                mExternalSize.setText(getSizeStr(mAppEntry.externalSize));
+            if (mLastExternalCodeSize != mAppEntry.externalCodeSize) {
+                mLastExternalCodeSize = mAppEntry.externalCodeSize;
+                mExternalCodeSize.setText(getSizeStr(mAppEntry.externalCodeSize));
+            }
+            if (mLastExternalDataSize != mAppEntry.externalDataSize) {
+                mLastExternalDataSize = mAppEntry.externalDataSize;
+                mExternalDataSize.setText(getSizeStr(mAppEntry.externalDataSize));
             }
             if (mLastCacheSize != mAppEntry.cacheSize) {
                 mLastCacheSize = mAppEntry.cacheSize;
diff --git a/src/com/android/settings/applications/ManageApplications.java b/src/com/android/settings/applications/ManageApplications.java
index 85db45e..554ece3 100644
--- a/src/com/android/settings/applications/ManageApplications.java
+++ b/src/com/android/settings/applications/ManageApplications.java
@@ -121,6 +121,10 @@
     // constant value that can be used to check return code from sub activity.
     private static final int INSTALLED_APP_DETAILS = 1;
 
+    public static final int SIZE_TOTAL = 0;
+    public static final int SIZE_INTERNAL = 1;
+    public static final int SIZE_EXTERNAL = 2;
+
     // sort order that can be changed through the menu can be sorted alphabetically
     // or size(descending)
     private static final int MENU_OPTIONS_BASE = 0;
@@ -208,11 +212,21 @@
         TextView disabled;
         CheckBox checkBox;
         
-        void updateSizeText(ManageApplications ma) {
+        void updateSizeText(ManageApplications ma, int whichSize) {
             if (DEBUG) Log.i(TAG, "updateSizeText of " + entry.label + " " + entry
                     + ": " + entry.sizeStr);
             if (entry.sizeStr != null) {
-                appSize.setText(entry.sizeStr);
+                switch (whichSize) {
+                    case SIZE_INTERNAL:
+                        appSize.setText(entry.internalSizeStr);
+                        break;
+                    case SIZE_EXTERNAL:
+                        appSize.setText(entry.externalSizeStr);
+                        break;
+                    default:
+                        appSize.setText(entry.sizeStr);
+                        break;
+                }
             } else if (entry.size == ApplicationsState.SIZE_INVALID) {
                 appSize.setText(ma.mInvalidSizeStr);
             }
@@ -237,6 +251,7 @@
         private boolean mResumed;
         private int mLastFilterMode=-1, mLastSortMode=-1;
         private boolean mWaitingForData;
+        private int mWhichSize = SIZE_TOTAL;
         CharSequence mCurFilterPrefix;
 
         private Filter mFilter = new Filter() {
@@ -296,12 +311,21 @@
             if (DEBUG) Log.i(TAG, "Rebuilding app list...");
             ApplicationsState.AppFilter filterObj;
             Comparator<AppEntry> comparatorObj;
+            boolean emulated = Environment.isExternalStorageEmulated();
+            if (emulated) {
+                mWhichSize = SIZE_TOTAL;
+            } else {
+                mWhichSize = SIZE_INTERNAL;
+            }
             switch (mLastFilterMode) {
                 case FILTER_APPS_THIRD_PARTY:
                     filterObj = ApplicationsState.THIRD_PARTY_FILTER;
                     break;
                 case FILTER_APPS_SDCARD:
                     filterObj = ApplicationsState.ON_SD_CARD_FILTER;
+                    if (!emulated) {
+                        mWhichSize = SIZE_EXTERNAL;
+                    }
                     break;
                 default:
                     filterObj = null;
@@ -399,7 +423,7 @@
                 AppViewHolder holder = (AppViewHolder)mActive.get(i).getTag();
                 if (holder.entry.info.packageName.equals(packageName)) {
                     synchronized (holder.entry) {
-                        holder.updateSizeText(ManageApplications.this);
+                        holder.updateSizeText(ManageApplications.this, mWhichSize);
                     }
                     if (holder.entry.info.packageName.equals(mCurrentPkgName)
                             && mLastSortMode == SORT_ORDER_SIZE) {
@@ -478,7 +502,7 @@
                 if (entry.icon != null) {
                     holder.appIcon.setImageDrawable(entry.icon);
                 }
-                holder.updateSizeText(ManageApplications.this);
+                holder.updateSizeText(ManageApplications.this, mWhichSize);
                 if (InstalledAppDetails.SUPPORT_DISABLE_APPS) {
                     holder.disabled.setVisibility(entry.info.enabled ? View.GONE : View.VISIBLE);
                 } else {
@@ -777,6 +801,11 @@
             } catch (IllegalArgumentException e) {
                 // use the old value of mFreeMem
             }
+            final int N = mApplicationsAdapter.getCount();
+            for (int i=0; i<N; i++) {
+                ApplicationsState.AppEntry ae = mApplicationsAdapter.getAppEntry(i);
+                appStorage += ae.externalCodeSize + ae.externalDataSize;
+            }
         } else {
             if (!mLastShowedInternalStorage) {
                 mLastShowedInternalStorage = true;
@@ -790,10 +819,14 @@
                     mDataFileStats.getBlockSize();
             } catch (IllegalArgumentException e) {
             }
+            final boolean emulatedStorage = Environment.isExternalStorageEmulated();
             final int N = mApplicationsAdapter.getCount();
             for (int i=0; i<N; i++) {
                 ApplicationsState.AppEntry ae = mApplicationsAdapter.getAppEntry(i);
                 appStorage += ae.codeSize + ae.dataSize;
+                if (emulatedStorage) {
+                    appStorage += ae.externalCodeSize + ae.externalDataSize;
+                }
             }
             freeStorage += mApplicationsState.sumCacheSizes();
         }
diff --git a/src/com/android/settings/deviceinfo/Memory.java b/src/com/android/settings/deviceinfo/Memory.java
index db60c37..236bdee 100644
--- a/src/com/android/settings/deviceinfo/Memory.java
+++ b/src/com/android/settings/deviceinfo/Memory.java
@@ -60,6 +60,7 @@
 
     private StorageManager mStorageManager = null;
 
+    private StorageVolumePreferenceCategory mInternalStorageVolumePreferenceCategory;
     private StorageVolumePreferenceCategory[] mStorageVolumePreferenceCategories;
 
     @Override
@@ -75,6 +76,17 @@
 
         mResources = getResources();
 
+        if (!Environment.isExternalStorageEmulated()) {
+            // External storage is separate from internal storage; need to
+            // show internal storage as a separate item.
+            StorageVolumePreferenceCategory storagePreferenceCategory =
+                new StorageVolumePreferenceCategory(getActivity(), mResources, null,
+                        mStorageManager, true);
+            mInternalStorageVolumePreferenceCategory = storagePreferenceCategory;
+            getPreferenceScreen().addPreference(storagePreferenceCategory);
+            storagePreferenceCategory.init();
+        }
+
         StorageVolume[] storageVolumes = mStorageManager.getVolumeList();
         int length = storageVolumes.length;
         mStorageVolumePreferenceCategories = new StorageVolumePreferenceCategory[length];
@@ -97,6 +109,7 @@
         intentFilter.addDataScheme("file");
         getActivity().registerReceiver(mMediaScannerReceiver, intentFilter);
 
+        mInternalStorageVolumePreferenceCategory.onResume();
         for (int i = 0; i < mStorageVolumePreferenceCategories.length; i++) {
             mStorageVolumePreferenceCategories[i].onResume();
         }
@@ -122,6 +135,7 @@
     public void onPause() {
         super.onPause();
         getActivity().unregisterReceiver(mMediaScannerReceiver);
+        mInternalStorageVolumePreferenceCategory.onPause();
         for (int i = 0; i < mStorageVolumePreferenceCategories.length; i++) {
             mStorageVolumePreferenceCategories[i].onPause();
         }
diff --git a/src/com/android/settings/deviceinfo/StorageMeasurement.java b/src/com/android/settings/deviceinfo/StorageMeasurement.java
index 7fb309c..d574eab 100644
--- a/src/com/android/settings/deviceinfo/StorageMeasurement.java
+++ b/src/com/android/settings/deviceinfo/StorageMeasurement.java
@@ -88,6 +88,7 @@
 
     private static Map<StorageVolume, StorageMeasurement> sInstances =
         new ConcurrentHashMap<StorageVolume, StorageMeasurement>();
+    private static StorageMeasurement sInternalInstance;
 
     private volatile WeakReference<MeasurementReceiver> mReceiver;
 
@@ -100,6 +101,7 @@
 
     final private StorageVolume mStorageVolume;
     final private boolean mIsPrimary;
+    final private boolean mIsInternal;
 
     List<FileInfo> mFileInfoForMisc;
 
@@ -110,7 +112,8 @@
 
     private StorageMeasurement(Context context, StorageVolume storageVolume, boolean isPrimary) {
         mStorageVolume = storageVolume;
-        mIsPrimary = isPrimary;
+        mIsInternal = storageVolume == null;
+        mIsPrimary = !mIsInternal && isPrimary;
 
         // Start the thread that will measure the disk usage.
         final HandlerThread handlerThread = new HandlerThread("MemoryMeasurement");
@@ -126,6 +129,13 @@
      */
     public static StorageMeasurement getInstance(Context context, StorageVolume storageVolume,
             boolean isPrimary) {
+        if (storageVolume == null) {
+            if (sInternalInstance == null) {
+                sInternalInstance =
+                    new StorageMeasurement(context.getApplicationContext(), storageVolume, isPrimary);
+            }
+            return sInternalInstance;
+        }
         if (sInstances.containsKey(storageVolume)) {
             return sInstances.get(storageVolume);
         } else {
@@ -317,9 +327,18 @@
                 }
 
                 if (succeeded) {
-                    mAppsSizeForThisStatsObserver += stats.codeSize + stats.dataSize +
-                    stats.externalCacheSize + stats.externalDataSize +
-                    stats.externalMediaSize + stats.externalObbSize;
+                    if (mIsInternal) {
+                        mAppsSizeForThisStatsObserver += stats.codeSize + stats.dataSize;
+                    } else if (!Environment.isExternalStorageEmulated()) {
+                        mAppsSizeForThisStatsObserver += stats.externalObbSize +
+                                stats.externalCodeSize + stats.externalDataSize +
+                                stats.externalCacheSize + stats.externalMediaSize;
+                    } else {
+                        mAppsSizeForThisStatsObserver += stats.codeSize + stats.dataSize +
+                                stats.externalCodeSize + stats.externalDataSize +
+                                stats.externalCacheSize + stats.externalMediaSize +
+                                stats.externalObbSize;
+                    }
                 }
 
                 synchronized (mAppsList) {
@@ -349,7 +368,8 @@
         }
 
         private void measureApproximateStorage() {
-            final StatFs stat = new StatFs(mStorageVolume.getPath());
+            final StatFs stat = new StatFs(mStorageVolume != null
+                    ? mStorageVolume.getPath() : Environment.getDataDirectory().getPath());
             final long blockSize = stat.getBlockSize();
             final long totalBlocks = stat.getBlockCount();
             final long availableBlocks = stat.getAvailableBlocks();
@@ -434,7 +454,7 @@
                 return;
             }
             final List<ApplicationInfo> apps;
-            if (mIsPrimary) {
+            if (mIsPrimary || mIsInternal) {
                 apps = pm.getInstalledApplications(PackageManager.GET_UNINSTALLED_PACKAGES |
                         PackageManager.GET_DISABLED_COMPONENTS);
             } else {
diff --git a/src/com/android/settings/deviceinfo/StorageVolumePreferenceCategory.java b/src/com/android/settings/deviceinfo/StorageVolumePreferenceCategory.java
index 9dbff88..70b76e4 100644
--- a/src/com/android/settings/deviceinfo/StorageVolumePreferenceCategory.java
+++ b/src/com/android/settings/deviceinfo/StorageVolumePreferenceCategory.java
@@ -162,12 +162,13 @@
         mResources = resources;
         mStorageVolume = storageVolume;
         mStorageManager = storageManager;
-        setTitle(storageVolume.getDescription());
+        setTitle(storageVolume != null ? storageVolume.getDescription()
+                : resources.getText(R.string.internal_storage));
         mMeasurement = StorageMeasurement.getInstance(context, storageVolume, isPrimary);
         mMeasurement.setReceiver(this);
 
         // Cannot format emulated storage
-        mAllowFormat = !mStorageVolume.isEmulated();
+        mAllowFormat = mStorageVolume != null && !mStorageVolume.isEmulated();
         // For now we are disabling reformatting secondary external storage
         // until some interoperability problems with MTP are fixed
         if (!isPrimary) mAllowFormat = false;
@@ -240,7 +241,9 @@
     private void updatePreferencesFromState() {
         resetPreferences();
 
-        String state = mStorageManager.getVolumeState(mStorageVolume.getPath());
+        String state = mStorageVolume != null
+                ? mStorageManager.getVolumeState(mStorageVolume.getPath())
+                : Environment.MEDIA_MOUNTED;
 
         String readOnly = "";
         if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
@@ -255,7 +258,8 @@
             removePreference(mFormatPreference);
         }
 
-        if (!mStorageVolume.isRemovable() && !Environment.MEDIA_UNMOUNTED.equals(state)) {
+        if ((mStorageVolume == null || !mStorageVolume.isRemovable())
+                && !Environment.MEDIA_UNMOUNTED.equals(state)) {
             // This device has built-in storage that is not removable.
             // There is no reason for the user to unmount it.
             removePreference(mMountTogglePreference);