Merge "Surface storage usage of other users." into jb-mr1-dev

This commit is contained in:
Jeff Sharkey
2012-08-30 15:26:50 -07:00
committed by Android (Google) Code Review
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>
@@ -34,4 +36,4 @@
<color name="title_color">@android:color/holo_blue_light</color> <color name="title_color">@android:color/holo_blue_light</color>
<color name="setup_divider_color">#333333</color> <color name="setup_divider_color">#333333</color>
</resources> </resources>

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,31 +128,35 @@ 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) {
if (mReceiver == null || mReceiver.get() == null) { if (mReceiver == null || mReceiver.get() == null) {
mReceiver = new WeakReference<MeasurementReceiver>(receiver); mReceiver = new WeakReference<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);
updateApproximate(totalSize, availSize);
if (user.getIdentifier() == UserHandle.USER_CURRENT) {
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);
updateExact(totalSize, availSize, appsUsed, downloadsSize, miscSize,
mediaSizes); 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);
}
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) {
mUsageBarPreference.clear(); if (mShowingApprox) {
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 (size > 0) { if (mShowingApprox) {
mPreferences[category].setSummary(formatSize(size)); mUsageBarPreference.clear();
mUsageBarPreference.addEntry(size / (float) totalSize, mColors[category]); mShowingApprox = false;
} else { }
removePreference(mPreferences[category]);
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) {
pref.setSummary(formatSize(size));
if (showBar) {
mUsageBarPreference.addEntry(size / (float) totalSize, pref.getColor());
}
} else {
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);
} }