summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Android.mk2
-rw-r--r--res/values/strings.xml3
-rw-r--r--src/com/android/settings/deviceinfo/Memory.java31
-rw-r--r--src/com/android/settings/deviceinfo/MiscFilesHandler.java3
-rw-r--r--src/com/android/settings/deviceinfo/StorageItemPreference.java26
-rw-r--r--src/com/android/settings/deviceinfo/StorageMeasurement.java526
-rw-r--r--src/com/android/settings/deviceinfo/StorageVolumePreferenceCategory.java426
7 files changed, 426 insertions, 591 deletions
diff --git a/Android.mk b/Android.mk
index 9c9a23a..fe8ed2d 100644
--- a/Android.mk
+++ b/Android.mk
@@ -2,7 +2,7 @@ LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_JAVA_LIBRARIES := bouncycastle telephony-common
-LOCAL_STATIC_JAVA_LIBRARIES := guava android-support-v4
+LOCAL_STATIC_JAVA_LIBRARIES := guava android-support-v4 jsr305
LOCAL_MODULE_TAGS := optional
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 8895de2..8bef5aa 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1863,6 +1863,8 @@
<string name="sd_memory" product="default">SD card</string>
<!-- SD card & phone storage settings title. The amount of free space for some storage partition. For example, this is listed under both the "Internal phone storage" section and the "SD card" section. -->
<string name="memory_available">Available</string>
+ <!-- SD card & phone storage settings title. The amount of free space for some storage partition when the volume is read-only. [CHAR LIMIT=64] -->
+ <string name="memory_available_read_only">Available (read-only)</string>
<!-- SD card & phone storage settings screen heading. The total amount of storage space for some storage partition. For example, this is listed under both the "Internal phone storage" section and the "SD card" section -->
<string name="memory_size">Total space</string>
<!-- SD card & phone storage settings summary. Displayed when the total memory usage is being calculated. Will be replaced with a number like "12.3 GB" when finished calucating. [CHAR LIMIT=30] -->
@@ -1916,7 +1918,6 @@
<!-- SD card & phone storage settings item summary that will result in the phone connected to PC and MTP/PTP enabled. [CHAR LIMIT=80] -->
<string name="mtp_ptp_mode_summary">MTP or PTP function is active</string>
- <string name="read_only">\u0020(Read-only)</string>
<!-- SD card eject confirmation dialog title [CHAR LIMIT=25] -->
<string name="dlg_confirm_unmount_title" product="nosdcard">Unmount USB storage?</string>
<!-- SD card eject confirmation dialog title -->
diff --git a/src/com/android/settings/deviceinfo/Memory.java b/src/com/android/settings/deviceinfo/Memory.java
index f679589..057f329 100644
--- a/src/com/android/settings/deviceinfo/Memory.java
+++ b/src/com/android/settings/deviceinfo/Memory.java
@@ -66,9 +66,9 @@ public class Memory extends SettingsPreferenceFragment {
private static String sClickedMountPoint;
// Access using getMountService()
- private IMountService mMountService = null;
- private StorageManager mStorageManager = null;
- private UsbManager mUsbManager = null;
+ private IMountService mMountService;
+ private StorageManager mStorageManager;
+ private UsbManager mUsbManager;
private ArrayList<StorageVolumePreferenceCategory> mCategories = Lists.newArrayList();
@@ -76,33 +76,28 @@ public class Memory extends SettingsPreferenceFragment {
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
- mUsbManager = (UsbManager)getSystemService(Context.USB_SERVICE);
+ final Context context = getActivity();
- if (mStorageManager == null) {
- mStorageManager = (StorageManager) getSystemService(Context.STORAGE_SERVICE);
- mStorageManager.registerListener(mStorageListener);
- }
+ mUsbManager = (UsbManager) getSystemService(Context.USB_SERVICE);
+
+ mStorageManager = StorageManager.from(context);
+ mStorageManager.registerListener(mStorageListener);
addPreferencesFromResource(R.xml.device_info_memory);
- if (!Environment.isExternalStorageEmulated()) {
- // External storage is separate from internal storage; need to
- // show internal storage as a separate item.
- addCategoryForVolume(null);
- }
+ addCategory(StorageVolumePreferenceCategory.buildForInternal(context));
final StorageVolume[] storageVolumes = mStorageManager.getVolumeList();
for (StorageVolume volume : storageVolumes) {
- addCategoryForVolume(volume);
+ if (!volume.isEmulated()) {
+ addCategory(StorageVolumePreferenceCategory.buildForPhysical(context, volume));
+ }
}
setHasOptionsMenu(true);
}
- private void addCategoryForVolume(StorageVolume volume) {
- // TODO: Cluster multi-user emulated volumes into single category
- final StorageVolumePreferenceCategory category = new StorageVolumePreferenceCategory(
- getActivity(), volume);
+ private void addCategory(StorageVolumePreferenceCategory category) {
mCategories.add(category);
getPreferenceScreen().addPreference(category);
category.init();
diff --git a/src/com/android/settings/deviceinfo/MiscFilesHandler.java b/src/com/android/settings/deviceinfo/MiscFilesHandler.java
index 7f5c746..1e0cc46 100644
--- a/src/com/android/settings/deviceinfo/MiscFilesHandler.java
+++ b/src/com/android/settings/deviceinfo/MiscFilesHandler.java
@@ -20,7 +20,6 @@ import android.app.Activity;
import android.app.ListActivity;
import android.content.Context;
import android.os.Bundle;
-import android.os.UserHandle;
import android.os.storage.StorageVolume;
import android.text.format.Formatter;
import android.util.Log;
@@ -195,7 +194,7 @@ public class MiscFilesHandler extends ListActivity {
final StorageVolume storageVolume = activity.getIntent().getParcelableExtra(
StorageVolume.EXTRA_STORAGE_VOLUME);
StorageMeasurement mMeasurement = StorageMeasurement.getInstance(
- activity, storageVolume, UserHandle.CURRENT);
+ activity, storageVolume);
if (mMeasurement == null) return;
mData = (ArrayList<StorageMeasurement.FileInfo>) mMeasurement.mFileInfoForMisc;
if (mData != null) {
diff --git a/src/com/android/settings/deviceinfo/StorageItemPreference.java b/src/com/android/settings/deviceinfo/StorageItemPreference.java
index 6a76a86..e4f3ff9 100644
--- a/src/com/android/settings/deviceinfo/StorageItemPreference.java
+++ b/src/com/android/settings/deviceinfo/StorageItemPreference.java
@@ -21,34 +21,38 @@ import android.content.res.Resources;
import android.graphics.Color;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.shapes.RectShape;
+import android.os.UserHandle;
import android.preference.Preference;
import com.android.settings.R;
public class StorageItemPreference extends Preference {
+ public final int color;
+ public final int userHandle;
- private int mColor = Color.MAGENTA;
-
- public StorageItemPreference(Context context, String key, int titleRes, int colorRes) {
- this(context, key, context.getText(titleRes), colorRes);
+ public StorageItemPreference(Context context, int titleRes, int colorRes) {
+ this(context, context.getText(titleRes), colorRes, UserHandle.USER_NULL);
}
- public StorageItemPreference(Context context, String key, CharSequence title, int colorRes) {
+ public StorageItemPreference(
+ Context context, CharSequence title, int colorRes, int userHandle) {
super(context);
- //setLayoutResource(R.layout.app_percentage_item);
if (colorRes != 0) {
- mColor = context.getResources().getColor(colorRes);
+ this.color = context.getResources().getColor(colorRes);
final Resources res = context.getResources();
final int width = res.getDimensionPixelSize(R.dimen.device_memory_usage_button_width);
final int height = res.getDimensionPixelSize(R.dimen.device_memory_usage_button_height);
- setIcon(createRectShape(width, height, mColor));
+ setIcon(createRectShape(width, height, this.color));
+ } else {
+ this.color = Color.MAGENTA;
}
- setKey(key);
setTitle(title);
setSummary(R.string.memory_calculating_size);
+
+ this.userHandle = userHandle;
}
private static ShapeDrawable createRectShape(int width, int height, int color) {
@@ -58,8 +62,4 @@ public class StorageItemPreference extends Preference {
shape.getPaint().setColor(color);
return shape;
}
-
- public int getColor() {
- return mColor;
- }
}
diff --git a/src/com/android/settings/deviceinfo/StorageMeasurement.java b/src/com/android/settings/deviceinfo/StorageMeasurement.java
index e81bfd8..50238f3 100644
--- a/src/com/android/settings/deviceinfo/StorageMeasurement.java
+++ b/src/com/android/settings/deviceinfo/StorageMeasurement.java
@@ -16,6 +16,7 @@
package com.android.settings.deviceinfo;
+import android.app.ActivityManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -24,7 +25,7 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageStatsObserver;
import android.content.pm.PackageManager;
import android.content.pm.PackageStats;
-import android.os.Bundle;
+import android.content.pm.UserInfo;
import android.os.Environment;
import android.os.Environment.UserEnvironment;
import android.os.Handler;
@@ -32,15 +33,15 @@ import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
-import android.os.RemoteException;
import android.os.UserHandle;
+import android.os.UserManager;
import android.os.storage.StorageVolume;
import android.util.Log;
-import android.util.Pair;
+import android.util.SparseLongArray;
import com.android.internal.app.IMediaContainerService;
-import com.android.internal.util.Preconditions;
import com.google.android.collect.Maps;
+import com.google.common.collect.Sets;
import java.io.File;
import java.lang.ref.WeakReference;
@@ -48,22 +49,14 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
+import java.util.Set;
+
+import javax.annotation.concurrent.GuardedBy;
/**
- * Measure the memory for various systems.
- *
- * TODO: This class should ideally have less knowledge about what the context
- * it's measuring is. In the future, reduce the amount of stuff it needs to
- * know about by just keeping an array of measurement types of the following
- * properties:
- *
- * Filesystem stats (using DefaultContainerService)
- * Directory measurements (using DefaultContainerService.measureDir)
- * Application measurements (using PackageManager)
- *
- * Then the calling application would just specify the type and an argument.
- * This class would keep track of it while the calling application would
- * decide on how to use it.
+ * Utility for measuring the disk usage of internal storage or a physical
+ * {@link StorageVolume}. Connects with a remote {@link IMediaContainerService}
+ * and delivers results to {@link MeasurementReceiver}.
*/
public class StorageMeasurement {
private static final String TAG = "StorageMeasurement";
@@ -71,56 +64,99 @@ public class StorageMeasurement {
private static final boolean LOCAL_LOGV = true;
static final boolean LOGV = LOCAL_LOGV && Log.isLoggable(TAG, Log.VERBOSE);
- public static final String TOTAL_SIZE = "total_size";
+ private static final String DEFAULT_CONTAINER_PACKAGE = "com.android.defcontainer";
- public static final String AVAIL_SIZE = "avail_size";
+ public static final ComponentName DEFAULT_CONTAINER_COMPONENT = new ComponentName(
+ DEFAULT_CONTAINER_PACKAGE, "com.android.defcontainer.DefaultContainerService");
- public static final String APPS_USED = "apps_used";
+ /** Media types to measure on external storage. */
+ private static final Set<String> sMeasureMediaTypes = Sets.newHashSet(
+ Environment.DIRECTORY_DCIM, Environment.DIRECTORY_MOVIES,
+ Environment.DIRECTORY_PICTURES, Environment.DIRECTORY_MUSIC,
+ Environment.DIRECTORY_ALARMS, Environment.DIRECTORY_NOTIFICATIONS,
+ Environment.DIRECTORY_RINGTONES, Environment.DIRECTORY_PODCASTS,
+ Environment.DIRECTORY_DOWNLOADS, Environment.DIRECTORY_ANDROID);
- public static final String DOWNLOADS_SIZE = "downloads_size";
+ @GuardedBy("sInstances")
+ private static HashMap<StorageVolume, StorageMeasurement> sInstances = Maps.newHashMap();
- public static final String MISC_SIZE = "misc_size";
+ /**
+ * Obtain shared instance of {@link StorageMeasurement} for given physical
+ * {@link StorageVolume}, or internal storage if {@code null}.
+ */
+ public static StorageMeasurement getInstance(Context context, StorageVolume volume) {
+ synchronized (sInstances) {
+ StorageMeasurement value = sInstances.get(volume);
+ if (value == null) {
+ value = new StorageMeasurement(context.getApplicationContext(), volume);
+ sInstances.put(volume, value);
+ }
+ return value;
+ }
+ }
- public static final String MEDIA_SIZES = "media_sizes";
+ public static class MeasurementDetails {
+ /**
+ * Total apps disk usage.
+ * <p>
+ * When measuring internal storage, this value includes the code size of
+ * all apps (regardless of install status for current user), and
+ * internal disk used by the current user's apps. When the device
+ * emulates external storage, this value also includes emulated storage
+ * used by the current user's apps.
+ * <p>
+ * When measuring a physical {@link StorageVolume}, this value includes
+ * usage by all apps on that volume.
+ */
+ public long appsSize;
- private static final String DEFAULT_CONTAINER_PACKAGE = "com.android.defcontainer";
+ /**
+ * Total media disk usage, categorized by types such as
+ * {@link Environment#DIRECTORY_MUSIC}.
+ * <p>
+ * When measuring internal storage, this reflects media on emulated
+ * storage for the current user.
+ * <p>
+ * When measuring a physical {@link StorageVolume}, this reflects media
+ * on that volume.
+ */
+ public HashMap<String, Long> mediaSize = Maps.newHashMap();
- public static final ComponentName DEFAULT_CONTAINER_COMPONENT = new ComponentName(
- DEFAULT_CONTAINER_PACKAGE, "com.android.defcontainer.DefaultContainerService");
+ /**
+ * Misc external disk usage for the current user, unaccounted in
+ * {@link #mediaSize}.
+ */
+ public long miscSize;
- private final MeasurementHandler mHandler;
+ /**
+ * Total disk usage for users, which is only meaningful for emulated
+ * internal storage. Key is {@link UserHandle}.
+ */
+ public SparseLongArray usersSize = new SparseLongArray();
+ }
- private static HashMap<Pair<StorageVolume, UserHandle>, StorageMeasurement>
- sInstances = Maps.newHashMap();
+ public interface MeasurementReceiver {
+ public void updateApproximate(StorageMeasurement meas, long totalSize, long availSize);
+ public void updateDetails(StorageMeasurement meas, MeasurementDetails details);
+ }
private volatile WeakReference<MeasurementReceiver> mReceiver;
- private long mTotalSize;
- private long mAvailSize;
- private long mAppsSize;
- private long mDownloadsSize;
- private long mMiscSize;
- private long[] mMediaSizes = new long[StorageVolumePreferenceCategory.sMediaCategories.length];
-
- private final StorageVolume mStorageVolume;
- private final UserHandle mUser;
- private final UserEnvironment mUserEnv;
- private final boolean mIsPrimary;
+ /** Physical volume being measured, or {@code null} for internal. */
+ private final StorageVolume mVolume;
+
private final boolean mIsInternal;
+ private final boolean mIsPrimary;
- private boolean mIncludeAppCodeSize = true;
+ private final MeasurementHandler mHandler;
- List<FileInfo> mFileInfoForMisc;
+ private long mTotalSize;
+ private long mAvailSize;
- public interface MeasurementReceiver {
- public void updateApproximate(StorageMeasurement meas, Bundle bundle);
- public void updateExact(StorageMeasurement meas, Bundle bundle);
- }
+ List<FileInfo> mFileInfoForMisc;
- private StorageMeasurement(Context context, StorageVolume volume, UserHandle user) {
- mStorageVolume = volume;
- mUser = Preconditions.checkNotNull(user);
- mUserEnv = new UserEnvironment(mUser.getIdentifier());
+ private StorageMeasurement(Context context, StorageVolume volume) {
+ mVolume = volume;
mIsInternal = volume == null;
mIsPrimary = volume != null ? volume.isPrimary() : false;
@@ -130,35 +166,6 @@ public class StorageMeasurement {
mHandler = new MeasurementHandler(context, handlerThread.getLooper());
}
- public void setIncludeAppCodeSize(boolean include) {
- mIncludeAppCodeSize = include;
- }
-
- /**
- * Get the singleton of the StorageMeasurement class. The application
- * context is used to avoid leaking activities.
- * @param storageVolume The {@link StorageVolume} that will be measured
- * @param isPrimary true when this storage volume is the primary volume
- */
- public static StorageMeasurement getInstance(
- Context context, StorageVolume storageVolume, UserHandle user) {
- final Pair<StorageVolume, UserHandle> key = new Pair<StorageVolume, UserHandle>(
- storageVolume, user);
- synchronized (sInstances) {
- StorageMeasurement value = sInstances.get(key);
- if (value == null) {
- value = new StorageMeasurement(
- context.getApplicationContext(), storageVolume, user);
- sInstances.put(key, value);
- }
- return value;
- }
- }
-
- public UserHandle getUser() {
- return mUser;
- }
-
public void setReceiver(MeasurementReceiver receiver) {
if (mReceiver == null || mReceiver.get() == null) {
mReceiver = new WeakReference<MeasurementReceiver>(receiver);
@@ -186,15 +193,10 @@ public class StorageMeasurement {
if (receiver == null) {
return;
}
-
- Bundle bundle = new Bundle();
- bundle.putLong(TOTAL_SIZE, mTotalSize);
- bundle.putLong(AVAIL_SIZE, mAvailSize);
-
- receiver.updateApproximate(this, bundle);
+ receiver.updateApproximate(this, mTotalSize, mAvailSize);
}
- private void sendExactUpdate() {
+ private void sendExactUpdate(MeasurementDetails details) {
MeasurementReceiver receiver = (mReceiver != null) ? mReceiver.get() : null;
if (receiver == null) {
if (LOGV) {
@@ -202,27 +204,76 @@ public class StorageMeasurement {
}
return;
}
+ receiver.updateDetails(this, details);
+ }
- Bundle bundle = new Bundle();
- bundle.putLong(TOTAL_SIZE, mTotalSize);
- bundle.putLong(AVAIL_SIZE, mAvailSize);
- bundle.putLong(APPS_USED, mAppsSize);
- bundle.putLong(DOWNLOADS_SIZE, mDownloadsSize);
- bundle.putLong(MISC_SIZE, mMiscSize);
- bundle.putLongArray(MEDIA_SIZES, mMediaSizes);
+ private static class StatsObserver extends IPackageStatsObserver.Stub {
+ private final boolean mIsInternal;
+ private final MeasurementDetails mDetails;
+ private final int mCurrentUser;
+ private final Message mFinished;
+
+ private int mRemaining;
+
+ public StatsObserver(boolean isInternal, MeasurementDetails details, int currentUser,
+ Message finished, int remaining) {
+ mIsInternal = isInternal;
+ mDetails = details;
+ mCurrentUser = currentUser;
+ mFinished = finished;
+ mRemaining = remaining;
+ }
- receiver.updateExact(this, bundle);
+ @Override
+ public void onGetStatsCompleted(PackageStats stats, boolean succeeded) {
+ synchronized (mDetails) {
+ if (succeeded) {
+ addStatsLocked(stats);
+ }
+ if (--mRemaining == 0) {
+ mFinished.sendToTarget();
+ }
+ }
+ }
+
+ private void addStatsLocked(PackageStats stats) {
+ final long externalSize = stats.externalCodeSize + stats.externalDataSize
+ + stats.externalCacheSize + stats.externalMediaSize;
+
+ if (mIsInternal) {
+ final long codeSize;
+ final long dataSize;
+ if (Environment.isExternalStorageEmulated()) {
+ // OBB is shared on emulated storage, so count once as code,
+ // and data includes emulated storage.
+ codeSize = stats.codeSize + stats.externalObbSize;
+ dataSize = stats.dataSize + externalSize;
+ } else {
+ codeSize = stats.codeSize;
+ dataSize = stats.dataSize;
+ }
+
+ // Include code and combined data for current user
+ if (stats.userHandle == mCurrentUser) {
+ mDetails.appsSize += codeSize;
+ mDetails.appsSize += dataSize;
+ }
+
+ // Include combined data for user summary
+ addValue(mDetails.usersSize, stats.userHandle, dataSize);
+
+ } else {
+ // Physical storage; only count external sizes
+ mDetails.appsSize += externalSize + stats.externalObbSize;
+ }
+ }
}
private class MeasurementHandler extends Handler {
public static final int MSG_MEASURE = 1;
-
public static final int MSG_CONNECTED = 2;
-
public static final int MSG_DISCONNECT = 3;
-
public static final int MSG_COMPLETED = 4;
-
public static final int MSG_INVALIDATE = 5;
private Object mLock = new Object();
@@ -231,21 +282,21 @@ public class StorageMeasurement {
private volatile boolean mBound = false;
- private volatile boolean mMeasured = false;
-
- private StatsObserver mStatsObserver;
+ private MeasurementDetails mCached;
private final WeakReference<Context> mContext;
- final private ServiceConnection mDefContainerConn = new ServiceConnection() {
+ private final ServiceConnection mDefContainerConn = new ServiceConnection() {
+ @Override
public void onServiceConnected(ComponentName name, IBinder service) {
- final IMediaContainerService imcs = IMediaContainerService.Stub
- .asInterface(service);
+ final IMediaContainerService imcs = IMediaContainerService.Stub.asInterface(
+ service);
mDefaultContainer = imcs;
mBound = true;
sendMessage(obtainMessage(MSG_CONNECTED, imcs));
}
+ @Override
public void onServiceDisconnected(ComponentName name) {
mBound = false;
removeMessages(MSG_CONNECTED);
@@ -261,8 +312,8 @@ public class StorageMeasurement {
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_MEASURE: {
- if (mMeasured) {
- sendExactUpdate();
+ if (mCached != null) {
+ sendExactUpdate(mCached);
break;
}
@@ -277,8 +328,8 @@ public class StorageMeasurement {
sendMessage(obtainMessage(MSG_CONNECTED, mDefaultContainer));
} else {
Intent service = new Intent().setComponent(DEFAULT_CONTAINER_COMPONENT);
- context.bindService(service, mDefContainerConn,
- Context.BIND_AUTO_CREATE, mUser.getIdentifier());
+ context.bindService(service, mDefContainerConn, Context.BIND_AUTO_CREATE,
+ UserHandle.USER_OWNER);
}
}
break;
@@ -304,89 +355,19 @@ public class StorageMeasurement {
break;
}
case MSG_COMPLETED: {
- mMeasured = true;
- sendExactUpdate();
+ mCached = (MeasurementDetails) msg.obj;
+ sendExactUpdate(mCached);
break;
}
case MSG_INVALIDATE: {
- mMeasured = false;
+ mCached = null;
break;
}
}
}
- /**
- * Request measurement of each package.
- *
- * @param pm PackageManager instance to query
- */
- public void requestQueuedMeasurementsLocked(PackageManager pm) {
- final String[] appsList = mStatsObserver.getAppsList();
- final int N = appsList.length;
- for (int i = 0; i < N; i++) {
- pm.getPackageSizeInfo(appsList[i], mStatsObserver);
- }
- }
-
- private class StatsObserver extends IPackageStatsObserver.Stub {
- private long mAppsSizeForThisStatsObserver = 0;
- private final List<String> mAppsList = new ArrayList<String>();
-
- public void onGetStatsCompleted(PackageStats stats, boolean succeeded) {
- if (!mStatsObserver.equals(this)) {
- // this callback's class object is no longer in use. ignore this callback.
- return;
- }
-
- if (succeeded) {
- if (mIsInternal) {
- if (mIncludeAppCodeSize) {
- mAppsSizeForThisStatsObserver += stats.codeSize;
- }
- mAppsSizeForThisStatsObserver += stats.dataSize;
- } else if (!Environment.isExternalStorageEmulated()) {
- mAppsSizeForThisStatsObserver += stats.externalObbSize +
- stats.externalCodeSize + stats.externalDataSize +
- stats.externalCacheSize + stats.externalMediaSize;
- } else {
- if (mIncludeAppCodeSize) {
- mAppsSizeForThisStatsObserver += stats.codeSize;
- }
- mAppsSizeForThisStatsObserver += stats.dataSize +
- stats.externalCodeSize + stats.externalDataSize +
- stats.externalCacheSize + stats.externalMediaSize +
- stats.externalObbSize;
- }
- }
-
- synchronized (mAppsList) {
- mAppsList.remove(stats.packageName);
- if (mAppsList.size() > 0) return;
- }
-
- mAppsSize = mAppsSizeForThisStatsObserver;
- onInternalMeasurementComplete();
- }
-
- public void queuePackageMeasurementLocked(String packageName) {
- synchronized (mAppsList) {
- mAppsList.add(packageName);
- }
- }
-
- public String[] getAppsList() {
- synchronized (mAppsList) {
- return mAppsList.toArray(new String[mAppsList.size()]);
- }
- }
- }
-
- private void onInternalMeasurementComplete() {
- sendEmptyMessage(MSG_COMPLETED);
- }
-
private void measureApproximateStorage(IMediaContainerService imcs) {
- final String path = mStorageVolume != null ? mStorageVolume.getPath()
+ final String path = mVolume != null ? mVolume.getPath()
: Environment.getDataDirectory().getPath();
try {
final long[] stats = imcs.getFileSystemStats(path);
@@ -400,146 +381,116 @@ public class StorageMeasurement {
}
private void measureExactStorage(IMediaContainerService imcs) {
- Context context = mContext != null ? mContext.get() : null;
+ final Context context = mContext != null ? mContext.get() : null;
if (context == null) {
return;
}
- // Media
- for (int i = 0; i < StorageVolumePreferenceCategory.sMediaCategories.length; i++) {
- if (mIsPrimary) {
- String[] dirs = StorageVolumePreferenceCategory.sMediaCategories[i].mDirPaths;
- final int length = dirs.length;
- mMediaSizes[i] = 0;
- for (int d = 0; d < length; d++) {
- final String path = dirs[d];
- mMediaSizes[i] += getDirectorySize(imcs, path);
- }
- } else {
- // TODO Compute sizes using the MediaStore
- mMediaSizes[i] = 0;
+ final MeasurementDetails details = new MeasurementDetails();
+ final Message finished = obtainMessage(MSG_COMPLETED, details);
+
+ final UserManager userManager = (UserManager) context.getSystemService(
+ Context.USER_SERVICE);
+ final List<UserInfo> users = userManager.getUsers();
+
+ final int currentUser = ActivityManager.getCurrentUser();
+ final UserEnvironment currentEnv = new UserEnvironment(currentUser);
+
+ // Measure media types for emulated storage, or for primary physical
+ // external volume
+ final boolean measureMedia = (mIsInternal && Environment.isExternalStorageEmulated())
+ || mIsPrimary;
+ if (measureMedia) {
+ for (String type : sMeasureMediaTypes) {
+ final File path = currentEnv.getExternalStoragePublicDirectory(type);
+ final long size = getDirectorySize(imcs, path);
+ details.mediaSize.put(type, size);
}
}
- /* Compute sizes using the media provider
- // Media sizes are measured by the MediaStore. Query database.
- ContentResolver contentResolver = context.getContentResolver();
- // TODO "external" as a static String from MediaStore?
- Uri audioUri = MediaStore.Files.getContentUri("external");
- final String[] projection =
- new String[] { "sum(" + MediaStore.Files.FileColumns.SIZE + ")" };
- final String selection =
- MediaStore.Files.FileColumns.STORAGE_ID + "=" +
- Integer.toString(mStorageVolume.getStorageId()) + " AND " +
- MediaStore.Files.FileColumns.MEDIA_TYPE + "=?";
-
- for (int i = 0; i < StorageVolumePreferenceCategory.sMediaCategories.length; i++) {
- mMediaSizes[i] = 0;
- int mediaType = StorageVolumePreferenceCategory.sMediaCategories[i].mediaType;
- Cursor c = null;
- try {
- c = contentResolver.query(audioUri, projection, selection,
- new String[] { Integer.toString(mediaType) } , null);
-
- if (c != null && c.moveToNext()) {
- long size = c.getLong(0);
- mMediaSizes[i] = size;
- }
- } finally {
- if (c != null) c.close();
- }
+ // Measure misc files not counted under media
+ if (mIsInternal || mIsPrimary) {
+ final File path = mIsInternal ? currentEnv.getExternalStorageDirectory()
+ : mVolume.getPathFile();
+ details.miscSize = measureMisc(imcs, path);
}
- */
- // Downloads (primary volume only)
- if (mIsPrimary) {
- final String downloadsPath = mUserEnv.getExternalStoragePublicDirectory(
- Environment.DIRECTORY_DOWNLOADS).getAbsolutePath();
- mDownloadsSize = getDirectorySize(imcs, downloadsPath);
- } else {
- mDownloadsSize = 0;
+ // Measure total emulated storage of all users; internal apps data
+ // will be spliced in later
+ for (UserInfo user : users) {
+ final UserEnvironment userEnv = new UserEnvironment(user.id);
+ final long size = getDirectorySize(imcs, userEnv.getExternalStorageDirectory());
+ addValue(details.usersSize, user.id, size);
}
- // Misc
- mMiscSize = 0;
- if (mIsPrimary) {
- measureSizesOfMisc(imcs);
- }
+ // Measure all apps for all users
+ final PackageManager pm = context.getPackageManager();
+ if (mIsInternal || mIsPrimary) {
+ final List<ApplicationInfo> apps = pm.getInstalledApplications(
+ PackageManager.GET_UNINSTALLED_PACKAGES
+ | PackageManager.GET_DISABLED_COMPONENTS);
- // Apps
- // We have to get installd to measure the package sizes.
- PackageManager pm = context.getPackageManager();
- if (pm == null) {
- return;
- }
- final List<ApplicationInfo> apps;
- if (mIsPrimary || mIsInternal) {
- apps = pm.getInstalledApplications(PackageManager.GET_UNINSTALLED_PACKAGES |
- PackageManager.GET_DISABLED_COMPONENTS);
- } else {
- // TODO also measure apps installed on the SD card
- apps = Collections.emptyList();
- }
+ final int count = users.size() * apps.size();
+ final StatsObserver observer = new StatsObserver(
+ mIsInternal, details, currentUser, finished, count);
- if (apps != null && apps.size() > 0) {
- // initiate measurement of all package sizes. need new StatsObserver object.
- mStatsObserver = new StatsObserver();
- synchronized (mStatsObserver.mAppsList) {
- for (int i = 0; i < apps.size(); i++) {
- final ApplicationInfo info = apps.get(i);
- mStatsObserver.queuePackageMeasurementLocked(info.packageName);
+ for (UserInfo user : users) {
+ for (ApplicationInfo app : apps) {
+ pm.getPackageSizeInfo(app.packageName, user.id, observer);
}
}
- requestQueuedMeasurementsLocked(pm);
- // Sending of the message back to the MeasurementReceiver is
- // completed in the PackageObserver
} else {
- onInternalMeasurementComplete();
+ finished.sendToTarget();
}
}
}
- private long getDirectorySize(IMediaContainerService imcs, String dir) {
+ private static long getDirectorySize(IMediaContainerService imcs, File path) {
try {
- return imcs.calculateDirectorySize(dir);
+ final long size = imcs.calculateDirectorySize(path.toString());
+ Log.d(TAG, "getDirectorySize(" + path + ") returned " + size);
+ return size;
} catch (Exception e) {
- Log.w(TAG, "Could not read memory from default container service for " + dir, e);
+ Log.w(TAG, "Could not read memory from default container service for " + path, e);
return 0;
}
}
- long getMiscSize() {
- return mMiscSize;
- }
-
- private void measureSizesOfMisc(IMediaContainerService imcs) {
- File top = new File(mStorageVolume.getPath());
+ private long measureMisc(IMediaContainerService imcs, File dir) {
mFileInfoForMisc = new ArrayList<FileInfo>();
- File[] files = top.listFiles();
- if (files == null) return;
- final int len = files.length;
- // Get sizes of all top level nodes except the ones already computed...
+
+ final File[] files = dir.listFiles();
+ if (files == null) return 0;
+
+ // Get sizes of all top level nodes except the ones already computed
long counter = 0;
- for (int i = 0; i < len; i++) {
- String path = files[i].getAbsolutePath();
- if (StorageVolumePreferenceCategory.sPathsExcludedForMisc.contains(path)) {
+ long miscSize = 0;
+
+ for (File file : files) {
+ final String path = file.getAbsolutePath();
+ final String name = file.getName();
+ if (sMeasureMediaTypes.contains(name)) {
continue;
}
- if (files[i].isFile()) {
- final long fileSize = files[i].length();
+
+ if (file.isFile()) {
+ final long fileSize = file.length();
mFileInfoForMisc.add(new FileInfo(path, fileSize, counter++));
- mMiscSize += fileSize;
- } else if (files[i].isDirectory()) {
- final long dirSize = getDirectorySize(imcs, path);
+ miscSize += fileSize;
+ } else if (file.isDirectory()) {
+ final long dirSize = getDirectorySize(imcs, file);
mFileInfoForMisc.add(new FileInfo(path, dirSize, counter++));
- mMiscSize += dirSize;
+ miscSize += dirSize;
} else {
// Non directory, non file: not listed
}
}
+
// sort the list of FileInfo objects collected above in descending order of their sizes
Collections.sort(mFileInfoForMisc);
+
+ return miscSize;
}
static class FileInfo implements Comparable<FileInfo> {
@@ -565,10 +516,7 @@ public class StorageMeasurement {
}
}
- /**
- * TODO remove this method, only used because external SD Card needs a special treatment.
- */
- boolean isExternalSDCard() {
- return !mIsPrimary && !mIsInternal;
+ private static void addValue(SparseLongArray array, int key, long value) {
+ array.put(key, array.get(key) + value);
}
}
diff --git a/src/com/android/settings/deviceinfo/StorageVolumePreferenceCategory.java b/src/com/android/settings/deviceinfo/StorageVolumePreferenceCategory.java
index 5be9e15..469dbc7 100644
--- a/src/com/android/settings/deviceinfo/StorageVolumePreferenceCategory.java
+++ b/src/com/android/settings/deviceinfo/StorageVolumePreferenceCategory.java
@@ -25,13 +25,10 @@ import android.content.pm.IPackageManager;
import android.content.pm.UserInfo;
import android.content.res.Resources;
import android.hardware.usb.UsbManager;
-import android.os.Bundle;
import android.os.Environment;
-import android.os.Environment.UserEnvironment;
import android.os.Handler;
import android.os.Message;
import android.os.RemoteException;
-import android.os.UserHandle;
import android.os.UserManager;
import android.os.storage.StorageManager;
import android.os.storage.StorageVolume;
@@ -40,179 +37,98 @@ import android.preference.PreferenceCategory;
import android.text.format.Formatter;
import com.android.settings.R;
+import com.android.settings.deviceinfo.StorageMeasurement.MeasurementDetails;
import com.android.settings.deviceinfo.StorageMeasurement.MeasurementReceiver;
import com.google.android.collect.Lists;
-import java.util.HashSet;
+import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
-import java.util.Set;
-
-public class StorageVolumePreferenceCategory extends PreferenceCategory
- implements MeasurementReceiver {
- private static final String KEY_TOTAL_SIZE = "total_size";
- private static final String KEY_AVAILABLE = "available";
-
- private static final String KEY_APPLICATIONS = "applications";
- private static final String KEY_DCIM = "dcim"; // Pictures and Videos
- private static final String KEY_MUSIC = "music";
- private static final String KEY_DOWNLOADS = "downloads";
- private static final String KEY_MISC = "misc";
- private static final String KEY_USER_PREFIX = "user";
+public class StorageVolumePreferenceCategory extends PreferenceCategory {
private static final int ORDER_USAGE_BAR = -2;
private static final int ORDER_STORAGE_LOW = -1;
- private Preference mItemTotal;
- private Preference mItemAvailable;
-
- private UsageBarPreference mUsageBarPreference;
- private Preference mMountTogglePreference;
- private Preference mFormatPreference;
- private Preference mStorageLow;
-
+ /** Physical volume being measured, or {@code null} for internal. */
private final StorageVolume mVolume;
-
- private final boolean mIsEmulated;
- private final boolean mIsPrimary;
+ private final StorageMeasurement mMeasure;
private final Resources mResources;
private final StorageManager mStorageManager;
private final UserManager mUserManager;
- @Deprecated
- private static final UserEnvironment sOwnerEnv = new UserEnvironment(UserHandle.USER_OWNER);
-
- /** Measurement for local user. */
- private StorageMeasurement mLocalMeasure;
- /** All used measurements, including other users. */
- private List<StorageMeasurement> mAllMeasures = Lists.newArrayList();
+ private UsageBarPreference mUsageBarPreference;
+ private Preference mMountTogglePreference;
+ private Preference mFormatPreference;
+ private Preference mStorageLow;
- private boolean mAllowFormat;
+ private StorageItemPreference mItemTotal;
+ private StorageItemPreference mItemAvailable;
+ private StorageItemPreference mItemApps;
+ private StorageItemPreference mItemDcim;
+ private StorageItemPreference mItemMusic;
+ private StorageItemPreference mItemDownloads;
+ private StorageItemPreference mItemMisc;
+ private List<StorageItemPreference> mItemUsers = Lists.newArrayList();
private boolean mUsbConnected;
private String mUsbFunction;
- private boolean mShowingApprox;
-
- public static final Set<String> sPathsExcludedForMisc = new HashSet<String>();
-
- static class MediaCategory {
- final String[] mDirPaths;
- final String mCategory;
-
- public MediaCategory(String category, String... directories) {
- mCategory = category;
- final int length = directories.length;
- mDirPaths = new String[length];
- for (int i = 0; i < length; i++) {
- final String name = directories[i];
- final String path = sOwnerEnv.getExternalStoragePublicDirectory(name).
- getAbsolutePath();
- mDirPaths[i] = path;
- sPathsExcludedForMisc.add(path);
- }
- }
- }
- static final MediaCategory[] sMediaCategories = new MediaCategory[] {
- new MediaCategory(KEY_DCIM, Environment.DIRECTORY_DCIM, Environment.DIRECTORY_MOVIES,
- Environment.DIRECTORY_PICTURES),
- new MediaCategory(KEY_MUSIC, Environment.DIRECTORY_MUSIC, Environment.DIRECTORY_ALARMS,
- Environment.DIRECTORY_NOTIFICATIONS, Environment.DIRECTORY_RINGTONES,
- Environment.DIRECTORY_PODCASTS)
- };
-
- static {
- // Downloads
- sPathsExcludedForMisc.add(sOwnerEnv.getExternalStoragePublicDirectory(
- Environment.DIRECTORY_DOWNLOADS).getAbsolutePath());
- // Apps
- sPathsExcludedForMisc.add(sOwnerEnv.getExternalStorageDirectory().getAbsolutePath() +
- "/Android");
- }
+ private long mTotalSize;
- // Updates the memory usage bar graph.
private static final int MSG_UI_UPDATE_APPROXIMATE = 1;
-
- // Updates the memory usage bar graph.
- private static final int MSG_UI_UPDATE_EXACT = 2;
+ private static final int MSG_UI_UPDATE_DETAILS = 2;
private Handler mUpdateHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_UI_UPDATE_APPROXIMATE: {
- final UserHandle user = (UserHandle) msg.obj;
- final Bundle bundle = msg.getData();
- final long totalSize = bundle.getLong(StorageMeasurement.TOTAL_SIZE);
- final long availSize = bundle.getLong(StorageMeasurement.AVAIL_SIZE);
-
- if (user.getIdentifier() == UserHandle.USER_CURRENT) {
- updateApproximate(totalSize, availSize);
- }
+ final long[] size = (long[]) msg.obj;
+ updateApproximate(size[0], size[1]);
break;
}
- case MSG_UI_UPDATE_EXACT: {
- final UserHandle user = (UserHandle) msg.obj;
- final Bundle bundle = msg.getData();
- final long totalSize = bundle.getLong(StorageMeasurement.TOTAL_SIZE);
- final long availSize = bundle.getLong(StorageMeasurement.AVAIL_SIZE);
- final long appsUsed = bundle.getLong(StorageMeasurement.APPS_USED);
- final long downloadsSize = bundle.getLong(StorageMeasurement.DOWNLOADS_SIZE);
- final long miscSize = bundle.getLong(StorageMeasurement.MISC_SIZE);
- final long[] mediaSizes = bundle.getLongArray(StorageMeasurement.MEDIA_SIZES);
-
- if (user.getIdentifier() == UserHandle.USER_CURRENT) {
- updateExact(totalSize, availSize, appsUsed, downloadsSize, miscSize,
- mediaSizes);
- } else {
- long usedSize = appsUsed + downloadsSize + miscSize;
- for (long mediaSize : mediaSizes) {
- usedSize += mediaSize;
- }
- updateUserExact(user, totalSize, usedSize);
- }
+ case MSG_UI_UPDATE_DETAILS: {
+ final MeasurementDetails details = (MeasurementDetails) msg.obj;
+ updateDetails(details);
break;
}
}
}
};
- public StorageVolumePreferenceCategory(Context context, StorageVolume volume) {
+ /**
+ * Build category to summarize internal storage, including any emulated
+ * {@link StorageVolume}.
+ */
+ public static StorageVolumePreferenceCategory buildForInternal(Context context) {
+ return new StorageVolumePreferenceCategory(context, null);
+ }
+
+ /**
+ * Build category to summarize specific physical {@link StorageVolume}.
+ */
+ public static StorageVolumePreferenceCategory buildForPhysical(
+ Context context, StorageVolume volume) {
+ return new StorageVolumePreferenceCategory(context, volume);
+ }
+
+ private StorageVolumePreferenceCategory(Context context, StorageVolume volume) {
super(context);
mVolume = volume;
-
- mIsPrimary = volume != null ? volume.isPrimary() : false;
- mIsEmulated = volume != null ? volume.isEmulated() : false;
+ mMeasure = StorageMeasurement.getInstance(context, volume);
mResources = context.getResources();
- mStorageManager = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE);
+ mStorageManager = StorageManager.from(context);
mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
setTitle(volume != null ? volume.getDescription(context)
: context.getText(R.string.internal_storage));
-
- mLocalMeasure = StorageMeasurement.getInstance(context, volume, UserHandle.CURRENT);
- mAllMeasures.add(mLocalMeasure);
-
- // Cannot format emulated storage
- mAllowFormat = mVolume != null && !mVolume.isEmulated();
-
- // For now we are disabling reformatting secondary external storage
- // until some interoperability problems with MTP are fixed
- if (!mIsPrimary) mAllowFormat = false;
- }
-
- private StorageItemPreference addStorageItem(String key, int titleRes, int colorRes) {
- final StorageItemPreference pref = new StorageItemPreference(
- getContext(), key, titleRes, colorRes);
- addPreference(pref);
- return pref;
}
- private static String buildUserKey(UserHandle user) {
- return KEY_USER_PREFIX + user.getIdentifier();
+ private StorageItemPreference buildItem(int titleRes, int colorRes) {
+ return new StorageItemPreference(getContext(), titleRes, colorRes);
}
public void init() {
@@ -226,51 +142,62 @@ public class StorageVolumePreferenceCategory extends PreferenceCategory
}
final List<UserInfo> otherUsers = getUsersExcluding(currentUser);
- final boolean measureUsers = mIsEmulated && mIsPrimary && otherUsers.size() > 0;
+ final boolean showUsers = mVolume == null && otherUsers.size() > 0;
mUsageBarPreference = new UsageBarPreference(context);
mUsageBarPreference.setOrder(ORDER_USAGE_BAR);
addPreference(mUsageBarPreference);
- mItemTotal = addStorageItem(KEY_TOTAL_SIZE, R.string.memory_size, 0);
- mItemAvailable = addStorageItem(
- KEY_AVAILABLE, R.string.memory_available, R.color.memory_avail);
-
- if (measureUsers) {
- addPreference(new PreferenceHeader(context, currentUser.name));
- }
-
- addStorageItem(KEY_APPLICATIONS, R.string.memory_apps_usage, R.color.memory_apps_usage);
- addStorageItem(KEY_DCIM, R.string.memory_dcim_usage, R.color.memory_dcim);
- addStorageItem(KEY_MUSIC, R.string.memory_music_usage, R.color.memory_music);
- addStorageItem(KEY_DOWNLOADS, R.string.memory_downloads_usage, R.color.memory_downloads);
- addStorageItem(KEY_MISC, R.string.memory_media_misc_usage, R.color.memory_misc);
-
- if (measureUsers) {
- addPreference(new PreferenceHeader(context, R.string.storage_other_users));
-
- int count = 0;
- for (UserInfo info : otherUsers) {
- final UserHandle user = new UserHandle(info.id);
- final String key = buildUserKey(user);
-
- final StorageMeasurement measure = StorageMeasurement.getInstance(
- context, mVolume, user);
- measure.setIncludeAppCodeSize(false);
- mAllMeasures.add(measure);
+ mItemTotal = buildItem(R.string.memory_size, 0);
+ mItemAvailable = buildItem(R.string.memory_available, R.color.memory_avail);
+ addPreference(mItemTotal);
+ addPreference(mItemAvailable);
+
+ mItemApps = buildItem(R.string.memory_apps_usage, R.color.memory_apps_usage);
+ mItemDcim = buildItem(R.string.memory_dcim_usage, R.color.memory_dcim);
+ mItemMusic = buildItem(R.string.memory_music_usage, R.color.memory_music);
+ mItemDownloads = buildItem(R.string.memory_downloads_usage, R.color.memory_downloads);
+ mItemMisc = buildItem(R.string.memory_media_misc_usage, R.color.memory_misc);
+
+ final boolean showDetails = mVolume == null || mVolume.isPrimary();
+ if (showDetails) {
+ if (showUsers) {
+ addPreference(new PreferenceHeader(context, currentUser.name));
+ }
- final int colorRes = count++ % 2 == 0 ? R.color.memory_user_light
- : R.color.memory_user_dark;
- addPreference(new StorageItemPreference(getContext(), key, info.name, colorRes));
+ addPreference(mItemApps);
+ addPreference(mItemDcim);
+ addPreference(mItemMusic);
+ addPreference(mItemDownloads);
+ addPreference(mItemMisc);
+
+ if (showUsers) {
+ addPreference(new PreferenceHeader(context, R.string.storage_other_users));
+
+ int count = 0;
+ for (UserInfo info : otherUsers) {
+ final int colorRes = count++ % 2 == 0 ? R.color.memory_user_light
+ : R.color.memory_user_dark;
+ final StorageItemPreference userPref = new StorageItemPreference(
+ getContext(), info.name, colorRes, info.id);
+ mItemUsers.add(userPref);
+ addPreference(userPref);
+ }
}
}
- mMountTogglePreference = new Preference(context);
- mMountTogglePreference.setTitle(R.string.sd_eject);
- mMountTogglePreference.setSummary(R.string.sd_eject_summary);
- addPreference(mMountTogglePreference);
+ final boolean isRemovable = mVolume != null ? mVolume.isRemovable() : false;
+ if (isRemovable) {
+ mMountTogglePreference = new Preference(context);
+ mMountTogglePreference.setTitle(R.string.sd_eject);
+ mMountTogglePreference.setSummary(R.string.sd_eject_summary);
+ addPreference(mMountTogglePreference);
+ }
- if (mAllowFormat) {
+ // Only allow formatting of primary physical storage
+ // TODO: enable for non-primary volumes once MTP is fixed
+ final boolean allowFormat = mVolume != null ? mVolume.isPrimary() : false;
+ if (allowFormat) {
mFormatPreference = new Preference(context);
mFormatPreference.setTitle(R.string.sd_format);
mFormatPreference.setSummary(R.string.sd_format_summary);
@@ -298,33 +225,24 @@ public class StorageVolumePreferenceCategory extends PreferenceCategory
}
private void updatePreferencesFromState() {
+ // Only update for physical volumes
+ if (mVolume == null) return;
+
mMountTogglePreference.setEnabled(true);
- String state = mVolume != null
- ? mStorageManager.getVolumeState(mVolume.getPath())
- : Environment.MEDIA_MOUNTED;
+ final String state = mStorageManager.getVolumeState(mVolume.getPath());
- String readOnly = "";
if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
- state = Environment.MEDIA_MOUNTED;
- readOnly = mResources.getString(R.string.read_only);
+ mItemAvailable.setSummary(R.string.memory_available_read_only);
if (mFormatPreference != null) {
removePreference(mFormatPreference);
}
+ } else {
+ mItemAvailable.setSummary(R.string.memory_available);
}
- if ((mVolume == null || !mVolume.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);
- }
-
- if (Environment.MEDIA_MOUNTED.equals(state)) {
- // TODO: create better i18n strings here; we might end up appending
- // multiple times
- mItemAvailable.setSummary(mItemAvailable.getSummary() + readOnly);
-
+ if (Environment.MEDIA_MOUNTED.equals(state)
+ || Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
mMountTogglePreference.setEnabled(true);
mMountTogglePreference.setTitle(mResources.getString(R.string.sd_eject));
mMountTogglePreference.setSummary(mResources.getString(R.string.sd_eject_summary));
@@ -351,8 +269,10 @@ public class StorageVolumePreferenceCategory extends PreferenceCategory
if (mUsbConnected && (UsbManager.USB_FUNCTION_MTP.equals(mUsbFunction) ||
UsbManager.USB_FUNCTION_PTP.equals(mUsbFunction))) {
mMountTogglePreference.setEnabled(false);
- if (Environment.MEDIA_MOUNTED.equals(state)) {
- mMountTogglePreference.setSummary(mResources.getString(R.string.mtp_ptp_mode_summary));
+ if (Environment.MEDIA_MOUNTED.equals(state)
+ || Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
+ mMountTogglePreference.setSummary(
+ mResources.getString(R.string.mtp_ptp_mode_summary));
}
if (mFormatPreference != null) {
@@ -363,99 +283,78 @@ public class StorageVolumePreferenceCategory extends PreferenceCategory
mFormatPreference.setEnabled(true);
mFormatPreference.setSummary(mResources.getString(R.string.sd_format_summary));
}
-
}
public void updateApproximate(long totalSize, long availSize) {
mItemTotal.setSummary(formatSize(totalSize));
mItemAvailable.setSummary(formatSize(availSize));
+ mTotalSize = totalSize;
+
final long usedSize = totalSize - availSize;
mUsageBarPreference.clear();
mUsageBarPreference.addEntry(0, usedSize / (float) totalSize, android.graphics.Color.GRAY);
mUsageBarPreference.commit();
- mShowingApprox = true;
updatePreferencesFromState();
}
- public void updateExact(long totalSize, long availSize, long appsSize, long downloadsSize,
- long miscSize, long[] mediaSizes) {
- if (mShowingApprox) {
- mUsageBarPreference.clear();
- mShowingApprox = false;
+ private static long totalValues(HashMap<String, Long> map, String... keys) {
+ long total = 0;
+ for (String key : keys) {
+ total += map.get(key);
}
+ return total;
+ }
- mItemTotal.setSummary(formatSize(totalSize));
+ public void updateDetails(MeasurementDetails details) {
+ final boolean showDetails = mVolume == null || mVolume.isPrimary();
+ if (!showDetails) return;
- if (mLocalMeasure.isExternalSDCard()) {
- // TODO FIXME: external SD card will not report any size. Show used space in bar graph
- final long usedSize = totalSize - availSize;
- mUsageBarPreference.addEntry(
- 0, usedSize / (float) totalSize, android.graphics.Color.GRAY);
- }
+ mUsageBarPreference.clear();
- updatePreference(appsSize, totalSize, KEY_APPLICATIONS);
+ updatePreference(mItemApps, details.appsSize);
- long totalMediaSize = 0;
- for (int i = 0; i < sMediaCategories.length; i++) {
- final String category = sMediaCategories[i].mCategory;
- final long size = mediaSizes[i];
- updatePreference(size, totalSize, category);
- totalMediaSize += size;
- }
+ final long dcimSize = totalValues(details.mediaSize, Environment.DIRECTORY_DCIM,
+ Environment.DIRECTORY_MOVIES, Environment.DIRECTORY_PICTURES);
+ updatePreference(mItemDcim, dcimSize);
- updatePreference(downloadsSize, totalSize, KEY_DOWNLOADS);
+ final long musicSize = totalValues(details.mediaSize, Environment.DIRECTORY_MUSIC,
+ Environment.DIRECTORY_ALARMS, Environment.DIRECTORY_NOTIFICATIONS,
+ Environment.DIRECTORY_RINGTONES, Environment.DIRECTORY_PODCASTS);
+ updatePreference(mItemMusic, musicSize);
- // Note miscSize != totalSize - availSize - appsSize - downloadsSize - totalMediaSize
- // Block size is taken into account. That can be extra space from folders. TODO Investigate
- updatePreference(miscSize, totalSize, KEY_MISC);
+ final long downloadsSize = totalValues(details.mediaSize, Environment.DIRECTORY_DOWNLOADS);
+ updatePreference(mItemDownloads, musicSize);
- mItemAvailable.setSummary(formatSize(availSize));
+ updatePreference(mItemMisc, details.miscSize);
- mUsageBarPreference.commit();
- }
-
- public void updateUserExact(UserHandle user, long totalSize, long usedSize) {
- if (mShowingApprox) {
- mUsageBarPreference.clear();
- mShowingApprox = false;
+ for (StorageItemPreference userPref : mItemUsers) {
+ final long userSize = details.usersSize.get(userPref.userHandle);
+ updatePreference(userPref, userSize);
}
- final String key = buildUserKey(user);
-
- findPreference(key).setSummary(formatSize(usedSize));
- updatePreference(usedSize, totalSize, key);
-
mUsageBarPreference.commit();
}
- private void updatePreference(long size, long totalSize, String category) {
- final StorageItemPreference pref = (StorageItemPreference) findPreference(category);
-
- if (pref != null) {
- if (size > 0) {
- pref.setSummary(formatSize(size));
- final int order = pref.getOrder();
- mUsageBarPreference.addEntry(order, size / (float) totalSize, pref.getColor());
- } else {
- removePreference(pref);
- }
+ private void updatePreference(StorageItemPreference pref, long size) {
+ if (size > 0) {
+ pref.setSummary(formatSize(size));
+ final int order = pref.getOrder();
+ mUsageBarPreference.addEntry(order, size / (float) mTotalSize, pref.color);
+ } else {
+ removePreference(pref);
}
}
private void measure() {
- for (StorageMeasurement measure : mAllMeasures) {
- measure.invalidate();
- measure.measure();
- }
+ mMeasure.invalidate();
+ mMeasure.measure();
}
public void onResume() {
- for (StorageMeasurement measure : mAllMeasures) {
- measure.setReceiver(this);
- }
+ mMeasure.setReceiver(mReceiver);
measure();
}
@@ -474,30 +373,25 @@ public class StorageVolumePreferenceCategory extends PreferenceCategory
}
public void onPause() {
- for (StorageMeasurement measure : mAllMeasures) {
- measure.cleanUp();
- }
+ mMeasure.cleanUp();
}
private String formatSize(long size) {
return Formatter.formatFileSize(getContext(), size);
}
- @Override
- public void updateApproximate(StorageMeasurement meas, Bundle bundle) {
- final Message message = mUpdateHandler.obtainMessage(MSG_UI_UPDATE_APPROXIMATE);
- message.obj = meas.getUser();
- message.setData(bundle);
- mUpdateHandler.sendMessage(message);
- }
+ private MeasurementReceiver mReceiver = new MeasurementReceiver() {
+ @Override
+ public void updateApproximate(StorageMeasurement meas, long totalSize, long availSize) {
+ mUpdateHandler.obtainMessage(MSG_UI_UPDATE_APPROXIMATE, new long[] {
+ totalSize, availSize }).sendToTarget();
+ }
- @Override
- public void updateExact(StorageMeasurement meas, Bundle bundle) {
- final Message message = mUpdateHandler.obtainMessage(MSG_UI_UPDATE_EXACT);
- message.obj = meas.getUser();
- message.setData(bundle);
- mUpdateHandler.sendMessage(message);
- }
+ @Override
+ public void updateDetails(StorageMeasurement meas, MeasurementDetails details) {
+ mUpdateHandler.obtainMessage(MSG_UI_UPDATE_DETAILS, details).sendToTarget();
+ }
+ };
public boolean mountToggleClicked(Preference preference) {
return preference == mMountTogglePreference;
@@ -514,27 +408,25 @@ public class StorageVolumePreferenceCategory extends PreferenceCategory
intent = new Intent(Intent.ACTION_VIEW);
intent.setClass(getContext(), com.android.settings.MediaFormat.class);
intent.putExtra(StorageVolume.EXTRA_STORAGE_VOLUME, mVolume);
- } else if (KEY_APPLICATIONS.equals(key)) {
+ } else if (pref == mItemApps) {
intent = new Intent(Intent.ACTION_MANAGE_PACKAGE_STORAGE);
intent.setClass(getContext(),
com.android.settings.Settings.ManageApplicationsActivity.class);
- } else if (KEY_DOWNLOADS.equals(key)) {
+ } else if (pref == mItemDownloads) {
intent = new Intent(DownloadManager.ACTION_VIEW_DOWNLOADS).putExtra(
DownloadManager.INTENT_EXTRAS_SORT_BY_SIZE, true);
- } else if (KEY_MUSIC.equals(key)) {
+ } else if (pref == mItemMusic) {
intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("audio/mp3");
- } else if (KEY_DCIM.equals(key)) {
+ } else if (pref == mItemDcim) {
intent = new Intent(Intent.ACTION_VIEW);
intent.putExtra(Intent.EXTRA_LOCAL_ONLY, true);
// TODO Create a Videos category, type = vnd.android.cursor.dir/video
intent.setType("vnd.android.cursor.dir/image");
- } else if (KEY_MISC.equals(key)) {
+ } else if (pref == mItemMisc) {
Context context = getContext().getApplicationContext();
- if (mLocalMeasure.getMiscSize() > 0) {
- intent = new Intent(context, MiscFilesHandler.class);
- intent.putExtra(StorageVolume.EXTRA_STORAGE_VOLUME, mVolume);
- }
+ intent = new Intent(context, MiscFilesHandler.class);
+ intent.putExtra(StorageVolume.EXTRA_STORAGE_VOLUME, mVolume);
}
return intent;