Merge "Iteration on multi-user Storage UI." into jb-mr1-dev

This commit is contained in:
Jeff Sharkey
2012-09-13 01:31:46 -07:00
committed by Android (Google) Code Review
7 changed files with 433 additions and 598 deletions

View File

@@ -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();

View File

@@ -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) {

View File

@@ -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;
}
}

View File

@@ -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";
public static final String AVAIL_SIZE = "avail_size";
public static final String APPS_USED = "apps_used";
public static final String DOWNLOADS_SIZE = "downloads_size";
public static final String MISC_SIZE = "misc_size";
public static final String MEDIA_SIZES = "media_sizes";
private static final String DEFAULT_CONTAINER_PACKAGE = "com.android.defcontainer";
public static final ComponentName DEFAULT_CONTAINER_COMPONENT = new ComponentName(
DEFAULT_CONTAINER_PACKAGE, "com.android.defcontainer.DefaultContainerService");
private final MeasurementHandler mHandler;
/** 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);
private static HashMap<Pair<StorageVolume, UserHandle>, StorageMeasurement>
sInstances = Maps.newHashMap();
@GuardedBy("sInstances")
private static HashMap<StorageVolume, StorageMeasurement> sInstances = Maps.newHashMap();
/**
* 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 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;
/**
* 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();
/**
* Misc external disk usage for the current user, unaccounted in
* {@link #mediaSize}.
*/
public long miscSize;
/**
* Total disk usage for users, which is only meaningful for emulated
* internal storage. Key is {@link UserHandle}.
*/
public SparseLongArray usersSize = new SparseLongArray();
}
public interface MeasurementReceiver {
public void updateApproximate(StorageMeasurement meas, long totalSize, long availSize);
public void updateDetails(StorageMeasurement meas, MeasurementDetails details);
}
private volatile WeakReference<MeasurementReceiver> mReceiver;
/** Physical volume being measured, or {@code null} for internal. */
private final StorageVolume mVolume;
private final boolean mIsInternal;
private final boolean mIsPrimary;
private final MeasurementHandler mHandler;
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;
private final boolean mIsInternal;
private boolean mIncludeAppCodeSize = true;
List<FileInfo> mFileInfoForMisc;
public interface MeasurementReceiver {
public void updateApproximate(StorageMeasurement meas, Bundle bundle);
public void updateExact(StorageMeasurement meas, Bundle bundle);
}
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;
receiver.updateExact(this, bundle);
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;
}
@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();
}
}
*/
// Downloads (primary volume only)
if (mIsPrimary) {
final String downloadsPath = mUserEnv.getExternalStoragePublicDirectory(
Environment.DIRECTORY_DOWNLOADS).getAbsolutePath();
mDownloadsSize = getDirectorySize(imcs, downloadsPath);
} else {
mDownloadsSize = 0;
// Measure misc files not counted under media
if (mIsInternal || mIsPrimary) {
final File path = mIsInternal ? currentEnv.getExternalStorageDirectory()
: mVolume.getPathFile();
details.miscSize = measureMisc(imcs, path);
}
// Misc
mMiscSize = 0;
if (mIsPrimary) {
measureSizesOfMisc(imcs);
// 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);
}
// 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();
}
// 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);
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);
final int count = users.size() * apps.size();
final StatsObserver observer = new StatsObserver(
mIsInternal, details, currentUser, finished, count);
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);
}
}

View File

@@ -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;
/** Physical volume being measured, or {@code null} for internal. */
private final StorageVolume mVolume;
private final StorageMeasurement mMeasure;
private final Resources mResources;
private final StorageManager mStorageManager;
private final UserManager mUserManager;
private UsageBarPreference mUsageBarPreference;
private Preference mMountTogglePreference;
private Preference mFormatPreference;
private Preference mStorageLow;
private final StorageVolume mVolume;
private final boolean mIsEmulated;
private final boolean mIsPrimary;
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 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>();
private long mTotalSize;
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");
}
// 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);
mItemTotal = buildItem(R.string.memory_size, 0);
mItemAvailable = buildItem(R.string.memory_available, R.color.memory_avail);
addPreference(mItemTotal);
addPreference(mItemAvailable);
if (measureUsers) {
addPreference(new PreferenceHeader(context, currentUser.name));
}
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);
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);
final boolean showDetails = mVolume == null || mVolume.isPrimary();
if (showDetails) {
if (showUsers) {
addPreference(new PreferenceHeader(context, currentUser.name));
}
if (measureUsers) {
addPreference(new PreferenceHeader(context, R.string.storage_other_users));
addPreference(mItemApps);
addPreference(mItemDcim);
addPreference(mItemMusic);
addPreference(mItemDownloads);
addPreference(mItemMisc);
int count = 0;
for (UserInfo info : otherUsers) {
final UserHandle user = new UserHandle(info.id);
final String key = buildUserKey(user);
if (showUsers) {
addPreference(new PreferenceHeader(context, R.string.storage_other_users));
final StorageMeasurement measure = StorageMeasurement.getInstance(
context, mVolume, user);
measure.setIncludeAppCodeSize(false);
mAllMeasures.add(measure);
final int colorRes = count++ % 2 == 0 ? R.color.memory_user_light
: R.color.memory_user_dark;
addPreference(new StorageItemPreference(getContext(), key, info.name, colorRes));
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(mItemApps, details.appsSize);
final long dcimSize = totalValues(details.mediaSize, Environment.DIRECTORY_DCIM,
Environment.DIRECTORY_MOVIES, Environment.DIRECTORY_PICTURES);
updatePreference(mItemDcim, dcimSize);
final long musicSize = totalValues(details.mediaSize, Environment.DIRECTORY_MUSIC,
Environment.DIRECTORY_ALARMS, Environment.DIRECTORY_NOTIFICATIONS,
Environment.DIRECTORY_RINGTONES, Environment.DIRECTORY_PODCASTS);
updatePreference(mItemMusic, musicSize);
final long downloadsSize = totalValues(details.mediaSize, Environment.DIRECTORY_DOWNLOADS);
updatePreference(mItemDownloads, musicSize);
updatePreference(mItemMisc, details.miscSize);
for (StorageItemPreference userPref : mItemUsers) {
final long userSize = details.usersSize.get(userPref.userHandle);
updatePreference(userPref, userSize);
}
updatePreference(appsSize, totalSize, KEY_APPLICATIONS);
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;
}
updatePreference(downloadsSize, totalSize, KEY_DOWNLOADS);
// 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);
mItemAvailable.setSummary(formatSize(availSize));
mUsageBarPreference.commit();
}
public void updateUserExact(UserHandle user, long totalSize, long usedSize) {
if (mShowingApprox) {
mUsageBarPreference.clear();
mShowingApprox = false;
}
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;