Surface storage usage of other users.

Bring up separate StorageMeasurement sessions bound to other users
on device, and surface their total usage as teal colors.  Exclude
app code size when measuring secondary users.  Shift preferences to
using keys instead of fragile index ordering.

Bug: 7003520
Change-Id: I214d0b223e53955df71104502596743f049f2027
This commit is contained in:
Jeff Sharkey
2012-08-30 15:20:10 -07:00
parent ca786f3989
commit 90c8b20ccf
6 changed files with 305 additions and 176 deletions

View File

@@ -25,6 +25,8 @@
<color name="memory_dcim">#793A7F</color> <color name="memory_dcim">#793A7F</color>
<color name="memory_music">#8E562A</color> <color name="memory_music">#8E562A</color>
<color name="memory_misc">#7C3030</color> <color name="memory_misc">#7C3030</color>
<color name="memory_user_light">#479392</color>
<color name="memory_user_dark">#316665</color>
<color name="crypt_keeper_clock_background">#ff9a9a9a</color> <color name="crypt_keeper_clock_background">#ff9a9a9a</color>
<color name="crypt_keeper_clock_foreground">#ff666666</color> <color name="crypt_keeper_clock_foreground">#ff666666</color>

View File

@@ -103,6 +103,7 @@ public class Settings extends PreferenceActivity
R.id.device_section, R.id.device_section,
R.id.sound_settings, R.id.sound_settings,
R.id.display_settings, R.id.display_settings,
R.id.storage_settings,
R.id.application_settings, R.id.application_settings,
R.id.personal_section, R.id.personal_section,
R.id.security_settings, R.id.security_settings,

View File

@@ -20,6 +20,7 @@ import android.app.Activity;
import android.app.ListActivity; import android.app.ListActivity;
import android.content.Context; import android.content.Context;
import android.os.Bundle; import android.os.Bundle;
import android.os.UserHandle;
import android.os.storage.StorageVolume; import android.os.storage.StorageVolume;
import android.text.format.Formatter; import android.text.format.Formatter;
import android.util.Log; import android.util.Log;
@@ -193,8 +194,8 @@ public class MiscFilesHandler extends ListActivity {
mContext = activity; mContext = activity;
final StorageVolume storageVolume = activity.getIntent().getParcelableExtra( final StorageVolume storageVolume = activity.getIntent().getParcelableExtra(
StorageVolume.EXTRA_STORAGE_VOLUME); StorageVolume.EXTRA_STORAGE_VOLUME);
StorageMeasurement mMeasurement = StorageMeasurement mMeasurement = StorageMeasurement.getInstance(
StorageMeasurement.getInstance(activity, storageVolume, false /*Unused as a key*/); activity, storageVolume, new UserHandle(UserHandle.USER_CURRENT), false);
if (mMeasurement == null) return; if (mMeasurement == null) return;
mData = (ArrayList<StorageMeasurement.FileInfo>) mMeasurement.mFileInfoForMisc; mData = (ArrayList<StorageMeasurement.FileInfo>) mMeasurement.mFileInfoForMisc;
if (mData != null) { if (mData != null) {

View File

@@ -0,0 +1,65 @@
/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.deviceinfo;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Color;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.shapes.RectShape;
import android.preference.Preference;
import com.android.settings.R;
public class StorageItemPreference extends Preference {
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, String key, CharSequence title, int colorRes) {
super(context);
//setLayoutResource(R.layout.app_percentage_item);
if (colorRes != 0) {
mColor = 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));
}
setKey(key);
setTitle(title);
setSummary(R.string.memory_calculating_size);
}
private static ShapeDrawable createRectShape(int width, int height, int color) {
ShapeDrawable shape = new ShapeDrawable(new RectShape());
shape.setIntrinsicHeight(height);
shape.setIntrinsicWidth(width);
shape.getPaint().setColor(color);
return shape;
}
public int getColor() {
return mColor;
}
}

View File

@@ -32,18 +32,21 @@ import android.os.IBinder;
import android.os.Looper; import android.os.Looper;
import android.os.Message; import android.os.Message;
import android.os.RemoteException; import android.os.RemoteException;
import android.os.UserHandle;
import android.os.storage.StorageVolume; import android.os.storage.StorageVolume;
import android.util.Log; import android.util.Log;
import android.util.Pair;
import com.android.internal.app.IMediaContainerService; import com.android.internal.app.IMediaContainerService;
import com.android.internal.util.Preconditions;
import com.google.android.collect.Maps;
import java.io.File; import java.io.File;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/** /**
* Measure the memory for various systems. * Measure the memory for various systems.
@@ -86,9 +89,8 @@ public class StorageMeasurement {
private final MeasurementHandler mHandler; private final MeasurementHandler mHandler;
private static Map<StorageVolume, StorageMeasurement> sInstances = private static HashMap<Pair<StorageVolume, UserHandle>, StorageMeasurement>
new ConcurrentHashMap<StorageVolume, StorageMeasurement>(); sInstances = Maps.newHashMap();
private static StorageMeasurement sInternalInstance;
private volatile WeakReference<MeasurementReceiver> mReceiver; private volatile WeakReference<MeasurementReceiver> mReceiver;
@@ -99,19 +101,24 @@ public class StorageMeasurement {
private long mMiscSize; private long mMiscSize;
private long[] mMediaSizes = new long[StorageVolumePreferenceCategory.sMediaCategories.length]; private long[] mMediaSizes = new long[StorageVolumePreferenceCategory.sMediaCategories.length];
final private StorageVolume mStorageVolume; private final StorageVolume mStorageVolume;
final private boolean mIsPrimary; private final UserHandle mUser;
final private boolean mIsInternal; private final boolean mIsPrimary;
private final boolean mIsInternal;
private boolean mIncludeAppCodeSize = true;
List<FileInfo> mFileInfoForMisc; List<FileInfo> mFileInfoForMisc;
public interface MeasurementReceiver { public interface MeasurementReceiver {
public void updateApproximate(Bundle bundle); public void updateApproximate(StorageMeasurement meas, Bundle bundle);
public void updateExact(Bundle bundle); public void updateExact(StorageMeasurement meas, Bundle bundle);
} }
private StorageMeasurement(Context context, StorageVolume storageVolume, boolean isPrimary) { private StorageMeasurement(
Context context, StorageVolume storageVolume, UserHandle user, boolean isPrimary) {
mStorageVolume = storageVolume; mStorageVolume = storageVolume;
mUser = Preconditions.checkNotNull(user);
mIsInternal = storageVolume == null; mIsInternal = storageVolume == null;
mIsPrimary = !mIsInternal && isPrimary; mIsPrimary = !mIsInternal && isPrimary;
@@ -121,29 +128,33 @@ public class StorageMeasurement {
mHandler = new MeasurementHandler(context, handlerThread.getLooper()); mHandler = new MeasurementHandler(context, handlerThread.getLooper());
} }
public void setIncludeAppCodeSize(boolean include) {
mIncludeAppCodeSize = include;
}
/** /**
* Get the singleton of the StorageMeasurement class. The application * Get the singleton of the StorageMeasurement class. The application
* context is used to avoid leaking activities. * context is used to avoid leaking activities.
* @param storageVolume The {@link StorageVolume} that will be measured * @param storageVolume The {@link StorageVolume} that will be measured
* @param isPrimary true when this storage volume is the primary volume * @param isPrimary true when this storage volume is the primary volume
*/ */
public static StorageMeasurement getInstance(Context context, StorageVolume storageVolume, public static StorageMeasurement getInstance(
boolean isPrimary) { Context context, StorageVolume storageVolume, UserHandle user, boolean isPrimary) {
if (storageVolume == null) { final Pair<StorageVolume, UserHandle> key = new Pair<StorageVolume, UserHandle>(
if (sInternalInstance == null) { storageVolume, user);
sInternalInstance = synchronized (sInstances) {
new StorageMeasurement(context.getApplicationContext(), storageVolume, isPrimary); StorageMeasurement value = sInstances.get(key);
if (value == null) {
value = new StorageMeasurement(
context.getApplicationContext(), storageVolume, user, isPrimary);
sInstances.put(key, value);
} }
return sInternalInstance; return value;
} }
if (sInstances.containsKey(storageVolume)) {
return sInstances.get(storageVolume);
} else {
StorageMeasurement storageMeasurement =
new StorageMeasurement(context.getApplicationContext(), storageVolume, isPrimary);
sInstances.put(storageVolume, storageMeasurement);
return storageMeasurement;
} }
public UserHandle getUser() {
return mUser;
} }
public void setReceiver(MeasurementReceiver receiver) { public void setReceiver(MeasurementReceiver receiver) {
@@ -178,7 +189,7 @@ public class StorageMeasurement {
bundle.putLong(TOTAL_SIZE, mTotalSize); bundle.putLong(TOTAL_SIZE, mTotalSize);
bundle.putLong(AVAIL_SIZE, mAvailSize); bundle.putLong(AVAIL_SIZE, mAvailSize);
receiver.updateApproximate(bundle); receiver.updateApproximate(this, bundle);
} }
private void sendExactUpdate() { private void sendExactUpdate() {
@@ -198,7 +209,7 @@ public class StorageMeasurement {
bundle.putLong(MISC_SIZE, mMiscSize); bundle.putLong(MISC_SIZE, mMiscSize);
bundle.putLongArray(MEDIA_SIZES, mMediaSizes); bundle.putLongArray(MEDIA_SIZES, mMediaSizes);
receiver.updateExact(bundle); receiver.updateExact(this, bundle);
} }
private class MeasurementHandler extends Handler { private class MeasurementHandler extends Handler {
@@ -265,7 +276,7 @@ public class StorageMeasurement {
} else { } else {
Intent service = new Intent().setComponent(DEFAULT_CONTAINER_COMPONENT); Intent service = new Intent().setComponent(DEFAULT_CONTAINER_COMPONENT);
context.bindService(service, mDefContainerConn, context.bindService(service, mDefContainerConn,
Context.BIND_AUTO_CREATE); Context.BIND_AUTO_CREATE, mUser.getIdentifier());
} }
} }
break; break;
@@ -327,13 +338,19 @@ public class StorageMeasurement {
if (succeeded) { if (succeeded) {
if (mIsInternal) { if (mIsInternal) {
mAppsSizeForThisStatsObserver += stats.codeSize + stats.dataSize; if (mIncludeAppCodeSize) {
mAppsSizeForThisStatsObserver += stats.codeSize;
}
mAppsSizeForThisStatsObserver += stats.dataSize;
} else if (!Environment.isExternalStorageEmulated()) { } else if (!Environment.isExternalStorageEmulated()) {
mAppsSizeForThisStatsObserver += stats.externalObbSize + mAppsSizeForThisStatsObserver += stats.externalObbSize +
stats.externalCodeSize + stats.externalDataSize + stats.externalCodeSize + stats.externalDataSize +
stats.externalCacheSize + stats.externalMediaSize; stats.externalCacheSize + stats.externalMediaSize;
} else { } else {
mAppsSizeForThisStatsObserver += stats.codeSize + stats.dataSize + if (mIncludeAppCodeSize) {
mAppsSizeForThisStatsObserver += stats.codeSize;
}
mAppsSizeForThisStatsObserver += stats.dataSize +
stats.externalCodeSize + stats.externalDataSize + stats.externalCodeSize + stats.externalDataSize +
stats.externalCacheSize + stats.externalMediaSize + stats.externalCacheSize + stats.externalMediaSize +
stats.externalObbSize; stats.externalObbSize;

View File

@@ -16,20 +16,22 @@
package com.android.settings.deviceinfo; package com.android.settings.deviceinfo;
import android.app.ActivityManagerNative;
import android.app.ActivityThread; import android.app.ActivityThread;
import android.app.DownloadManager; import android.app.DownloadManager;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.pm.IPackageManager; import android.content.pm.IPackageManager;
import android.content.pm.UserInfo;
import android.content.res.Resources; import android.content.res.Resources;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.shapes.RectShape;
import android.hardware.usb.UsbManager; import android.hardware.usb.UsbManager;
import android.os.Bundle; import android.os.Bundle;
import android.os.Environment; import android.os.Environment;
import android.os.Handler; import android.os.Handler;
import android.os.Message; import android.os.Message;
import android.os.RemoteException; import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.storage.StorageManager; import android.os.storage.StorageManager;
import android.os.storage.StorageVolume; import android.os.storage.StorageVolume;
import android.preference.Preference; import android.preference.Preference;
@@ -38,69 +40,55 @@ import android.text.format.Formatter;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.deviceinfo.StorageMeasurement.MeasurementReceiver; import com.android.settings.deviceinfo.StorageMeasurement.MeasurementReceiver;
import com.google.android.collect.Lists;
import java.util.HashSet; import java.util.HashSet;
import java.util.List;
import java.util.Set; import java.util.Set;
public class StorageVolumePreferenceCategory extends PreferenceCategory implements public class StorageVolumePreferenceCategory extends PreferenceCategory
MeasurementReceiver { implements MeasurementReceiver {
private static final String KEY_TOTAL_SIZE = "total_size";
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_AVAILABLE = "available";
private static final String KEY_USER_PREFIX = "user";
static final int TOTAL_SIZE = 0; private static final int ORDER_USAGE_BAR = -2;
static final int APPLICATIONS = 1; private static final int ORDER_STORAGE_LOW = -1;
static final int DCIM = 2; // Pictures and Videos
static final int MUSIC = 3;
static final int DOWNLOADS = 4;
static final int MISC = 5;
static final int AVAILABLE = 6;
private UsageBarPreference mUsageBarPreference; private UsageBarPreference mUsageBarPreference;
private Preference[] mPreferences;
private Preference mMountTogglePreference; private Preference mMountTogglePreference;
private Preference mFormatPreference; private Preference mFormatPreference;
private Preference mStorageLow; private Preference mStorageLow;
private int[] mColors;
private Resources mResources; private final Resources mResources;
private StorageVolume mStorageVolume; private final StorageVolume mStorageVolume;
private final StorageManager mStorageManager;
private StorageManager mStorageManager = null; /** Measurement for local user. */
private StorageMeasurement mLocalMeasure;
private StorageMeasurement mMeasurement; /** All used measurements, including other users. */
private List<StorageMeasurement> mAllMeasures = Lists.newArrayList();
private boolean mAllowFormat; private boolean mAllowFormat;
private final boolean mMeasureUsers;
private boolean mUsbConnected; private boolean mUsbConnected;
private String mUsbFunction; private String mUsbFunction;
private boolean mShowingApprox;
static class CategoryInfo {
final int mTitle;
final int mColor;
public CategoryInfo(int title, int color) {
mTitle = title;
mColor = color;
}
}
static final CategoryInfo[] sCategoryInfos = new CategoryInfo[] {
new CategoryInfo(R.string.memory_size, 0),
new CategoryInfo(R.string.memory_apps_usage, R.color.memory_apps_usage),
new CategoryInfo(R.string.memory_dcim_usage, R.color.memory_dcim),
new CategoryInfo(R.string.memory_music_usage, R.color.memory_music),
new CategoryInfo(R.string.memory_downloads_usage, R.color.memory_downloads),
new CategoryInfo(R.string.memory_media_misc_usage, R.color.memory_misc),
new CategoryInfo(R.string.memory_available, R.color.memory_avail),
};
public static final Set<String> sPathsExcludedForMisc = new HashSet<String>(); public static final Set<String> sPathsExcludedForMisc = new HashSet<String>();
static class MediaCategory { static class MediaCategory {
final String[] mDirPaths; final String[] mDirPaths;
final int mCategory; final String mCategory;
//final int mMediaType;
public MediaCategory(int category, String... directories) { public MediaCategory(String category, String... directories) {
mCategory = category; mCategory = category;
final int length = directories.length; final int length = directories.length;
mDirPaths = new String[length]; mDirPaths = new String[length];
@@ -115,9 +103,9 @@ public class StorageVolumePreferenceCategory extends PreferenceCategory implemen
} }
static final MediaCategory[] sMediaCategories = new MediaCategory[] { static final MediaCategory[] sMediaCategories = new MediaCategory[] {
new MediaCategory(DCIM, Environment.DIRECTORY_DCIM, Environment.DIRECTORY_MOVIES, new MediaCategory(KEY_DCIM, Environment.DIRECTORY_DCIM, Environment.DIRECTORY_MOVIES,
Environment.DIRECTORY_PICTURES), Environment.DIRECTORY_PICTURES),
new MediaCategory(MUSIC, Environment.DIRECTORY_MUSIC, Environment.DIRECTORY_ALARMS, new MediaCategory(KEY_MUSIC, Environment.DIRECTORY_MUSIC, Environment.DIRECTORY_ALARMS,
Environment.DIRECTORY_NOTIFICATIONS, Environment.DIRECTORY_RINGTONES, Environment.DIRECTORY_NOTIFICATIONS, Environment.DIRECTORY_RINGTONES,
Environment.DIRECTORY_PODCASTS) Environment.DIRECTORY_PODCASTS)
}; };
@@ -142,22 +130,36 @@ public class StorageVolumePreferenceCategory extends PreferenceCategory implemen
public void handleMessage(Message msg) { public void handleMessage(Message msg) {
switch (msg.what) { switch (msg.what) {
case MSG_UI_UPDATE_APPROXIMATE: { case MSG_UI_UPDATE_APPROXIMATE: {
Bundle bundle = msg.getData(); final UserHandle user = (UserHandle) msg.obj;
final Bundle bundle = msg.getData();
final long totalSize = bundle.getLong(StorageMeasurement.TOTAL_SIZE); final long totalSize = bundle.getLong(StorageMeasurement.TOTAL_SIZE);
final long availSize = bundle.getLong(StorageMeasurement.AVAIL_SIZE); final long availSize = bundle.getLong(StorageMeasurement.AVAIL_SIZE);
if (user.getIdentifier() == UserHandle.USER_CURRENT) {
updateApproximate(totalSize, availSize); updateApproximate(totalSize, availSize);
}
break; break;
} }
case MSG_UI_UPDATE_EXACT: { case MSG_UI_UPDATE_EXACT: {
Bundle bundle = msg.getData(); final UserHandle user = (UserHandle) msg.obj;
final Bundle bundle = msg.getData();
final long totalSize = bundle.getLong(StorageMeasurement.TOTAL_SIZE); final long totalSize = bundle.getLong(StorageMeasurement.TOTAL_SIZE);
final long availSize = bundle.getLong(StorageMeasurement.AVAIL_SIZE); final long availSize = bundle.getLong(StorageMeasurement.AVAIL_SIZE);
final long appsUsed = bundle.getLong(StorageMeasurement.APPS_USED); final long appsUsed = bundle.getLong(StorageMeasurement.APPS_USED);
final long downloadsSize = bundle.getLong(StorageMeasurement.DOWNLOADS_SIZE); final long downloadsSize = bundle.getLong(StorageMeasurement.DOWNLOADS_SIZE);
final long miscSize = bundle.getLong(StorageMeasurement.MISC_SIZE); final long miscSize = bundle.getLong(StorageMeasurement.MISC_SIZE);
final long[] mediaSizes = bundle.getLongArray(StorageMeasurement.MEDIA_SIZES); final long[] mediaSizes = bundle.getLongArray(StorageMeasurement.MEDIA_SIZES);
if (user.getIdentifier() == UserHandle.USER_CURRENT) {
updateExact(totalSize, availSize, appsUsed, downloadsSize, miscSize, updateExact(totalSize, availSize, appsUsed, downloadsSize, miscSize,
mediaSizes); mediaSizes);
} else {
long usedSize = appsUsed + downloadsSize + miscSize;
for (long mediaSize : mediaSizes) {
usedSize += mediaSize;
}
updateUserExact(user, totalSize, usedSize);
}
break; break;
} }
} }
@@ -172,54 +174,97 @@ public class StorageVolumePreferenceCategory extends PreferenceCategory implemen
mStorageManager = storageManager; mStorageManager = storageManager;
setTitle(storageVolume != null ? storageVolume.getDescription(context) setTitle(storageVolume != null ? storageVolume.getDescription(context)
: resources.getText(R.string.internal_storage)); : resources.getText(R.string.internal_storage));
mMeasurement = StorageMeasurement.getInstance(context, storageVolume, isPrimary); mLocalMeasure = StorageMeasurement.getInstance(
mMeasurement.setReceiver(this); context, storageVolume, new UserHandle(UserHandle.USER_CURRENT), isPrimary);
mAllMeasures.add(mLocalMeasure);
// Cannot format emulated storage // Cannot format emulated storage
mAllowFormat = mStorageVolume != null && !mStorageVolume.isEmulated(); mAllowFormat = mStorageVolume != null && !mStorageVolume.isEmulated();
// For now we are disabling reformatting secondary external storage // For now we are disabling reformatting secondary external storage
// until some interoperability problems with MTP are fixed // until some interoperability problems with MTP are fixed
if (!isPrimary) mAllowFormat = false; if (!isPrimary) mAllowFormat = false;
// Measure other users when showing primary emulated storage
mMeasureUsers = (mStorageVolume != null && mStorageVolume.isEmulated()) && isPrimary;
}
private void addStorageItem(String key, int titleRes, int colorRes) {
addPreference(new StorageItemPreference(getContext(), key, titleRes, colorRes));
}
private static String buildUserKey(UserHandle user) {
return KEY_USER_PREFIX + user.getIdentifier();
} }
public void init() { public void init() {
mUsageBarPreference = new UsageBarPreference(getContext()); final Context context = getContext();
final int width = (int) mResources.getDimension(R.dimen.device_memory_usage_button_width); mUsageBarPreference = new UsageBarPreference(context);
final int height = (int) mResources.getDimension(R.dimen.device_memory_usage_button_height); mUsageBarPreference.setOrder(ORDER_USAGE_BAR);
addPreference(mUsageBarPreference);
final int numberOfCategories = sCategoryInfos.length; addStorageItem(KEY_TOTAL_SIZE, R.string.memory_size, 0);
mPreferences = new Preference[numberOfCategories]; addStorageItem(KEY_APPLICATIONS, R.string.memory_apps_usage, R.color.memory_apps_usage);
mColors = new int[numberOfCategories]; addStorageItem(KEY_DCIM, R.string.memory_dcim_usage, R.color.memory_dcim);
for (int i = 0; i < numberOfCategories; i++) { addStorageItem(KEY_MUSIC, R.string.memory_music_usage, R.color.memory_music);
final Preference preference = new Preference(getContext()); addStorageItem(KEY_DOWNLOADS, R.string.memory_downloads_usage, R.color.memory_downloads);
mPreferences[i] = preference; addStorageItem(KEY_MISC, R.string.memory_media_misc_usage, R.color.memory_misc);
preference.setTitle(sCategoryInfos[i].mTitle); addStorageItem(KEY_AVAILABLE, R.string.memory_available, R.color.memory_avail);
preference.setSummary(R.string.memory_calculating_size);
if (i != TOTAL_SIZE) { if (mMeasureUsers) {
// TOTAL_SIZE has no associated color final UserManager userManager = (UserManager) context.getSystemService(
mColors[i] = mResources.getColor(sCategoryInfos[i].mColor); Context.USER_SERVICE);
preference.setIcon(createRectShape(width, height, mColors[i]));
final UserInfo currentUser;
try {
currentUser = ActivityManagerNative.getDefault().getCurrentUser();
} catch (RemoteException e) {
throw new RuntimeException("Failed to get current user");
}
int count = 0;
for (UserInfo info : userManager.getUsers()) {
// Only measure other users
if (info.id == currentUser.id) {
continue;
}
final UserHandle user = new UserHandle(info.id);
final String key = buildUserKey(user);
final StorageMeasurement measure = StorageMeasurement.getInstance(
context, mStorageVolume, user, true);
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));
} }
} }
mMountTogglePreference = new Preference(getContext()); mMountTogglePreference = new Preference(context);
mMountTogglePreference.setTitle(R.string.sd_eject); mMountTogglePreference.setTitle(R.string.sd_eject);
mMountTogglePreference.setSummary(R.string.sd_eject_summary); mMountTogglePreference.setSummary(R.string.sd_eject_summary);
addPreference(mMountTogglePreference);
if (mAllowFormat) { if (mAllowFormat) {
mFormatPreference = new Preference(getContext()); mFormatPreference = new Preference(context);
mFormatPreference.setTitle(R.string.sd_format); mFormatPreference.setTitle(R.string.sd_format);
mFormatPreference.setSummary(R.string.sd_format_summary); mFormatPreference.setSummary(R.string.sd_format_summary);
addPreference(mFormatPreference);
} }
final IPackageManager pm = ActivityThread.getPackageManager(); final IPackageManager pm = ActivityThread.getPackageManager();
try { try {
if (pm.isStorageLow()) { if (pm.isStorageLow()) {
mStorageLow = new Preference(getContext()); mStorageLow = new Preference(context);
mStorageLow.setOrder(ORDER_STORAGE_LOW);
mStorageLow.setTitle(R.string.storage_low_title); mStorageLow.setTitle(R.string.storage_low_title);
mStorageLow.setSummary(R.string.storage_low_summary); mStorageLow.setSummary(R.string.storage_low_summary);
} else { addPreference(mStorageLow);
} else if (mStorageLow != null) {
removePreference(mStorageLow);
mStorageLow = null; mStorageLow = null;
} }
} catch (RemoteException e) { } catch (RemoteException e) {
@@ -230,39 +275,8 @@ public class StorageVolumePreferenceCategory extends PreferenceCategory implemen
return mStorageVolume; return mStorageVolume;
} }
/**
* Successive mounts can change the list of visible preferences.
* This makes sure all preferences are visible and displayed in the right order.
*/
private void resetPreferences() {
final int numberOfCategories = sCategoryInfos.length;
removePreference(mUsageBarPreference);
for (int i = 0; i < numberOfCategories; i++) {
removePreference(mPreferences[i]);
}
removePreference(mMountTogglePreference);
if (mFormatPreference != null) {
removePreference(mFormatPreference);
}
addPreference(mUsageBarPreference);
if (mStorageLow != null) {
addPreference(mStorageLow);
}
for (int i = 0; i < numberOfCategories; i++) {
addPreference(mPreferences[i]);
}
addPreference(mMountTogglePreference);
if (mFormatPreference != null) {
addPreference(mFormatPreference);
}
mMountTogglePreference.setEnabled(true);
}
private void updatePreferencesFromState() { private void updatePreferencesFromState() {
resetPreferences(); mMountTogglePreference.setEnabled(true);
String state = mStorageVolume != null String state = mStorageVolume != null
? mStorageManager.getVolumeState(mStorageVolume.getPath()) ? mStorageManager.getVolumeState(mStorageVolume.getPath())
@@ -285,7 +299,8 @@ public class StorageVolumePreferenceCategory extends PreferenceCategory implemen
} }
if (Environment.MEDIA_MOUNTED.equals(state)) { if (Environment.MEDIA_MOUNTED.equals(state)) {
mPreferences[AVAILABLE].setSummary(mPreferences[AVAILABLE].getSummary() + readOnly); final Preference pref = findPreference(KEY_AVAILABLE);
pref.setSummary(pref.getSummary() + readOnly);
mMountTogglePreference.setEnabled(true); mMountTogglePreference.setEnabled(true);
mMountTogglePreference.setTitle(mResources.getString(R.string.sd_eject)); mMountTogglePreference.setTitle(mResources.getString(R.string.sd_eject));
@@ -303,8 +318,8 @@ public class StorageVolumePreferenceCategory extends PreferenceCategory implemen
} }
removePreference(mUsageBarPreference); removePreference(mUsageBarPreference);
removePreference(mPreferences[TOTAL_SIZE]); removePreference(findPreference(KEY_TOTAL_SIZE));
removePreference(mPreferences[AVAILABLE]); removePreference(findPreference(KEY_AVAILABLE));
if (mFormatPreference != null) { if (mFormatPreference != null) {
removePreference(mFormatPreference); removePreference(mFormatPreference);
} }
@@ -329,67 +344,98 @@ public class StorageVolumePreferenceCategory extends PreferenceCategory implemen
} }
public void updateApproximate(long totalSize, long availSize) { public void updateApproximate(long totalSize, long availSize) {
mPreferences[TOTAL_SIZE].setSummary(formatSize(totalSize)); findPreference(KEY_TOTAL_SIZE).setSummary(formatSize(totalSize));
mPreferences[AVAILABLE].setSummary(formatSize(availSize)); findPreference(KEY_AVAILABLE).setSummary(formatSize(availSize));
final long usedSize = totalSize - availSize; final long usedSize = totalSize - availSize;
mUsageBarPreference.clear(); mUsageBarPreference.clear();
mUsageBarPreference.addEntry(usedSize / (float) totalSize, android.graphics.Color.GRAY); mUsageBarPreference.addEntry(usedSize / (float) totalSize, android.graphics.Color.GRAY);
mUsageBarPreference.commit(); mUsageBarPreference.commit();
mShowingApprox = true;
updatePreferencesFromState(); updatePreferencesFromState();
} }
public void updateExact(long totalSize, long availSize, long appsSize, long downloadsSize, public void updateExact(long totalSize, long availSize, long appsSize, long downloadsSize,
long miscSize, long[] mediaSizes) { long miscSize, long[] mediaSizes) {
if (mShowingApprox) {
mUsageBarPreference.clear(); mUsageBarPreference.clear();
mShowingApprox = false;
}
mPreferences[TOTAL_SIZE].setSummary(formatSize(totalSize)); findPreference(KEY_TOTAL_SIZE).setSummary(formatSize(totalSize));
if (mMeasurement.isExternalSDCard()) { if (mLocalMeasure.isExternalSDCard()) {
// TODO FIXME: external SD card will not report any size. Show used space in bar graph // TODO FIXME: external SD card will not report any size. Show used space in bar graph
final long usedSize = totalSize - availSize; final long usedSize = totalSize - availSize;
mUsageBarPreference.addEntry(usedSize / (float) totalSize, android.graphics.Color.GRAY); mUsageBarPreference.addEntry(usedSize / (float) totalSize, android.graphics.Color.GRAY);
} }
updatePreference(appsSize, totalSize, APPLICATIONS); updatePreference(appsSize, totalSize, KEY_APPLICATIONS);
long totalMediaSize = 0; long totalMediaSize = 0;
for (int i = 0; i < sMediaCategories.length; i++) { for (int i = 0; i < sMediaCategories.length; i++) {
final int category = sMediaCategories[i].mCategory; final String category = sMediaCategories[i].mCategory;
final long size = mediaSizes[i]; final long size = mediaSizes[i];
updatePreference(size, totalSize, category); updatePreference(size, totalSize, category);
totalMediaSize += size; totalMediaSize += size;
} }
updatePreference(downloadsSize, totalSize, DOWNLOADS); updatePreference(downloadsSize, totalSize, KEY_DOWNLOADS);
// Note miscSize != totalSize - availSize - appsSize - downloadsSize - totalMediaSize // Note miscSize != totalSize - availSize - appsSize - downloadsSize - totalMediaSize
// Block size is taken into account. That can be extra space from folders. TODO Investigate // Block size is taken into account. That can be extra space from folders. TODO Investigate
updatePreference(miscSize, totalSize, MISC); updatePreference(miscSize, totalSize, KEY_MISC);
updatePreference(availSize, totalSize, AVAILABLE); updatePreference(availSize, totalSize, KEY_AVAILABLE, false);
mUsageBarPreference.commit(); mUsageBarPreference.commit();
} }
private void updatePreference(long size, long totalSize, int category) { 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) {
updatePreference(size, totalSize, category, true);
}
private void updatePreference(long size, long totalSize, String category, boolean showBar) {
final StorageItemPreference pref = (StorageItemPreference) findPreference(category);
if (pref != null) {
if (size > 0) { if (size > 0) {
mPreferences[category].setSummary(formatSize(size)); pref.setSummary(formatSize(size));
mUsageBarPreference.addEntry(size / (float) totalSize, mColors[category]); if (showBar) {
mUsageBarPreference.addEntry(size / (float) totalSize, pref.getColor());
}
} else { } else {
removePreference(mPreferences[category]); removePreference(pref);
}
} }
} }
private void measure() { private void measure() {
mMeasurement.invalidate(); for (StorageMeasurement measure : mAllMeasures) {
mMeasurement.measure(); measure.invalidate();
measure.measure();
}
} }
public void onResume() { public void onResume() {
mMeasurement.setReceiver(this); for (StorageMeasurement measure : mAllMeasures) {
measure.setReceiver(this);
}
measure(); measure();
} }
@@ -407,15 +453,9 @@ public class StorageVolumePreferenceCategory extends PreferenceCategory implemen
} }
public void onPause() { public void onPause() {
mMeasurement.cleanUp(); for (StorageMeasurement measure : mAllMeasures) {
measure.cleanUp();
} }
private static ShapeDrawable createRectShape(int width, int height, int color) {
ShapeDrawable shape = new ShapeDrawable(new RectShape());
shape.setIntrinsicHeight(height);
shape.setIntrinsicWidth(width);
shape.getPaint().setColor(color);
return shape;
} }
private String formatSize(long size) { private String formatSize(long size) {
@@ -423,15 +463,17 @@ public class StorageVolumePreferenceCategory extends PreferenceCategory implemen
} }
@Override @Override
public void updateApproximate(Bundle bundle) { public void updateApproximate(StorageMeasurement meas, Bundle bundle) {
final Message message = mUpdateHandler.obtainMessage(MSG_UI_UPDATE_APPROXIMATE); final Message message = mUpdateHandler.obtainMessage(MSG_UI_UPDATE_APPROXIMATE);
message.obj = meas.getUser();
message.setData(bundle); message.setData(bundle);
mUpdateHandler.sendMessage(message); mUpdateHandler.sendMessage(message);
} }
@Override @Override
public void updateExact(Bundle bundle) { public void updateExact(StorageMeasurement meas, Bundle bundle) {
final Message message = mUpdateHandler.obtainMessage(MSG_UI_UPDATE_EXACT); final Message message = mUpdateHandler.obtainMessage(MSG_UI_UPDATE_EXACT);
message.obj = meas.getUser();
message.setData(bundle); message.setData(bundle);
mUpdateHandler.sendMessage(message); mUpdateHandler.sendMessage(message);
} }
@@ -440,34 +482,35 @@ public class StorageVolumePreferenceCategory extends PreferenceCategory implemen
return preference == mMountTogglePreference; return preference == mMountTogglePreference;
} }
public Intent intentForClick(Preference preference) { public Intent intentForClick(Preference pref) {
Intent intent = null; Intent intent = null;
// TODO The current "delete" story is not fully handled by the respective applications. // TODO The current "delete" story is not fully handled by the respective applications.
// When it is done, make sure the intent types below are correct. // When it is done, make sure the intent types below are correct.
// If that cannot be done, remove these intents. // If that cannot be done, remove these intents.
if (preference == mFormatPreference) { final String key = pref.getKey();
if (pref == mFormatPreference) {
intent = new Intent(Intent.ACTION_VIEW); intent = new Intent(Intent.ACTION_VIEW);
intent.setClass(getContext(), com.android.settings.MediaFormat.class); intent.setClass(getContext(), com.android.settings.MediaFormat.class);
intent.putExtra(StorageVolume.EXTRA_STORAGE_VOLUME, mStorageVolume); intent.putExtra(StorageVolume.EXTRA_STORAGE_VOLUME, mStorageVolume);
} else if (preference == mPreferences[APPLICATIONS]) { } else if (KEY_APPLICATIONS.equals(key)) {
intent = new Intent(Intent.ACTION_MANAGE_PACKAGE_STORAGE); intent = new Intent(Intent.ACTION_MANAGE_PACKAGE_STORAGE);
intent.setClass(getContext(), intent.setClass(getContext(),
com.android.settings.Settings.ManageApplicationsActivity.class); com.android.settings.Settings.ManageApplicationsActivity.class);
} else if (preference == mPreferences[DOWNLOADS]) { } else if (KEY_DOWNLOADS.equals(key)) {
intent = new Intent(DownloadManager.ACTION_VIEW_DOWNLOADS).putExtra( intent = new Intent(DownloadManager.ACTION_VIEW_DOWNLOADS).putExtra(
DownloadManager.INTENT_EXTRAS_SORT_BY_SIZE, true); DownloadManager.INTENT_EXTRAS_SORT_BY_SIZE, true);
} else if (preference == mPreferences[MUSIC]) { } else if (KEY_MUSIC.equals(key)) {
intent = new Intent(Intent.ACTION_GET_CONTENT); intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("audio/mp3"); intent.setType("audio/mp3");
} else if (preference == mPreferences[DCIM]) { } else if (KEY_DCIM.equals(key)) {
intent = new Intent(Intent.ACTION_VIEW); intent = new Intent(Intent.ACTION_VIEW);
intent.putExtra(Intent.EXTRA_LOCAL_ONLY, true); intent.putExtra(Intent.EXTRA_LOCAL_ONLY, true);
// TODO Create a Videos category, type = vnd.android.cursor.dir/video // TODO Create a Videos category, type = vnd.android.cursor.dir/video
intent.setType("vnd.android.cursor.dir/image"); intent.setType("vnd.android.cursor.dir/image");
} else if (preference == mPreferences[MISC]) { } else if (KEY_MISC.equals(key)) {
Context context = getContext().getApplicationContext(); Context context = getContext().getApplicationContext();
if (mMeasurement.getMiscSize() > 0) { if (mLocalMeasure.getMiscSize() > 0) {
intent = new Intent(context, MiscFilesHandler.class); intent = new Intent(context, MiscFilesHandler.class);
intent.putExtra(StorageVolume.EXTRA_STORAGE_VOLUME, mStorageVolume); intent.putExtra(StorageVolume.EXTRA_STORAGE_VOLUME, mStorageVolume);
} }