package com.android.settings.deviceinfo;
-import com.android.internal.app.IMediaContainerService;
import com.android.settings.R;
import com.android.settings.SettingsPreferenceFragment;
+import com.android.settings.deviceinfo.MemoryMeasurement.MeasurementReceiver;
-import android.app.Activity;
import android.app.ActivityManager;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.BroadcastReceiver;
-import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.ServiceConnection;
import android.content.DialogInterface.OnCancelListener;
import android.content.pm.ApplicationInfo;
-import android.content.pm.IPackageStatsObserver;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageStats;
import android.content.res.Resources;
+import android.graphics.drawable.ShapeDrawable;
+import android.graphics.drawable.shapes.RectShape;
+import android.graphics.drawable.shapes.RoundRectShape;
import android.hardware.UsbManager;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
-import android.os.HandlerThread;
import android.os.IBinder;
-import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
import android.os.ServiceManager;
-import android.os.StatFs;
import android.os.storage.IMountService;
import android.os.storage.StorageEventListener;
import android.os.storage.StorageManager;
import android.util.Log;
import android.widget.Toast;
-import java.io.File;
-import java.util.ArrayList;
import java.util.List;
-public class Memory extends SettingsPreferenceFragment implements OnCancelListener {
+public class Memory extends SettingsPreferenceFragment implements OnCancelListener,
+ MeasurementReceiver {
private static final String TAG = "Memory";
- private static final boolean localLOGV = false;
+ static final boolean localLOGV = false;
private static final String MEMORY_SD_SIZE = "memory_sd_size";
private int mInternalAppsColor;
private int mInternalUsedColor;
- // Internal memory fields
- private long mInternalTotalSize;
- private long mInternalUsedSize;
- private long mInternalMediaSize;
- private long mInternalAppsSize;
- private boolean mMeasured = false;
-
boolean mSdMountToggleAdded = true;
// Access using getMountService()
private StorageManager mStorageManager = null;
// Updates the memory usage bar graph.
- private static final int MSG_UI_UPDATE_APPROXIMATE = 1;
+ private static final int MSG_UI_UPDATE_INTERNAL_APPROXIMATE = 1;
// Updates the memory usage bar graph.
- private static final int MSG_UI_UPDATE_EXACT = 2;
-
- private Handler mUpdateHandler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MSG_UI_UPDATE_APPROXIMATE:
- updateUiApproximate();
- break;
- case MSG_UI_UPDATE_EXACT:
- updateUiExact();
- mMeasured = true;
- break;
- }
- }
- };
-
- private static final String DEFAULT_CONTAINER_PACKAGE = "com.android.defcontainer";
-
- private static final ComponentName DEFAULT_CONTAINER_COMPONENT = new ComponentName(
- DEFAULT_CONTAINER_PACKAGE, "com.android.defcontainer.DefaultContainerService");
-
- class MemoryMeasurementHandler extends Handler {
- public static final int MSG_MEASURE_ALL = 1;
-
- public static final int MSG_CONNECTED = 2;
-
- public static final int MSG_DISCONNECTED = 3;
-
- private List<String> mPendingApps = new ArrayList<String>();
+ private static final int MSG_UI_UPDATE_INTERNAL_EXACT = 2;
- private volatile boolean mBound = false;
-
- private long mAppsSize = 0;
-
- final private ServiceConnection mDefContainerConn = new ServiceConnection() {
- public void onServiceConnected(ComponentName name, IBinder service) {
- mBound = true;
- IMediaContainerService imcs = IMediaContainerService.Stub.asInterface(service);
- mMeasurementHandler.sendMessage(mMeasurementHandler.obtainMessage(
- MemoryMeasurementHandler.MSG_CONNECTED, imcs));
- }
-
- public void onServiceDisconnected(ComponentName name) {
- mBound = false;
- }
- };
-
- MemoryMeasurementHandler(Looper looper) {
- super(looper);
- }
+ // Updates the memory usage stats for external.
+ private static final int MSG_UI_UPDATE_EXTERNAL_APPROXIMATE = 3;
+ private Handler mUpdateHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
- case MSG_MEASURE_ALL: {
- updateExternalStorage();
- updateApproximateInternalStorage();
-
- Intent service = new Intent().setComponent(DEFAULT_CONTAINER_COMPONENT);
- getActivity().bindService(service, mDefContainerConn, Context.BIND_AUTO_CREATE);
-
- mUpdateHandler.sendEmptyMessage(MSG_UI_UPDATE_APPROXIMATE);
+ case MSG_UI_UPDATE_INTERNAL_APPROXIMATE: {
+ Bundle bundle = msg.getData();
+ final long totalSize = bundle.getLong(MemoryMeasurement.TOTAL_SIZE);
+ final long availSize = bundle.getLong(MemoryMeasurement.AVAIL_SIZE);
+ updateUiApproximate(totalSize, availSize);
break;
}
- case MSG_CONNECTED: {
- IMediaContainerService imcs = (IMediaContainerService) msg.obj;
- updateExactInternalStorage(imcs);
- }
- }
- }
-
- public void cleanUp() {
- if (mBound) {
- getActivity().unbindService(mDefContainerConn);
- }
- }
-
- public void queuePackageMeasurementLocked(String packageName) {
- mPendingApps.add(packageName);
- }
-
- public void requestQueuedMeasurementsLocked() {
- final Activity activity = getActivity();
- if (activity == null) {
- return;
- }
-
- final PackageManager pm = activity.getPackageManager();
- if (pm == null) {
- return;
- }
-
- final int N = mPendingApps.size();
- for (int i = 0; i < N; i++) {
- pm.getPackageSizeInfo(mPendingApps.get(i), mStatsObserver);
- }
- }
-
- final IPackageStatsObserver.Stub mStatsObserver = new IPackageStatsObserver.Stub() {
- public void onGetStatsCompleted(PackageStats stats, boolean succeeded) {
- if (succeeded) {
- mAppsSize += stats.codeSize + stats.dataSize;
- }
-
- synchronized (mPendingApps) {
- mPendingApps.remove(stats.packageName);
-
- if (mPendingApps.size() == 0) {
- mInternalAppsSize = mAppsSize;
-
- mUpdateHandler.sendEmptyMessage(MSG_UI_UPDATE_EXACT);
- }
- }
- }
- };
-
- private void updateApproximateInternalStorage() {
- final File dataPath = Environment.getDataDirectory();
- final StatFs stat = new StatFs(dataPath.getPath());
- final long blockSize = stat.getBlockSize();
- final long totalBlocks = stat.getBlockCount();
- final long availableBlocks = stat.getAvailableBlocks();
-
- final long totalSize = totalBlocks * blockSize;
- final long availSize = availableBlocks * blockSize;
- mInternalSize.setSummary(formatSize(totalSize));
- mInternalAvail.setSummary(formatSize(availSize));
-
- mInternalTotalSize = totalSize;
- mInternalUsedSize = totalSize - availSize;
- }
-
- private void updateExactInternalStorage(IMediaContainerService imcs) {
- long mediaSize;
- try {
- // TODO get these directories from somewhere
- mediaSize = imcs.calculateDirectorySize("/data/media");
- } catch (Exception e) {
- Log.i(TAG, "Could not read memory from default container service");
- return;
- }
-
- mInternalMediaSize = mediaSize;
-
- // We have to get installd to measure the package sizes.
- PackageManager pm = getPackageManager();
- List<ApplicationInfo> apps = pm
- .getInstalledApplications(PackageManager.GET_UNINSTALLED_PACKAGES
- | PackageManager.GET_DISABLED_COMPONENTS);
- if (apps != null) {
- synchronized (mPendingApps) {
- for (int i = 0; i < apps.size(); i++) {
- final ApplicationInfo info = apps.get(i);
- queuePackageMeasurementLocked(info.packageName);
- }
-
- requestQueuedMeasurementsLocked();
- }
- }
- }
-
- private void updateExternalStorage() {
- if (Environment.isExternalStorageEmulated()) {
- return;
- }
-
- String status = Environment.getExternalStorageState();
- String readOnly = "";
- if (status.equals(Environment.MEDIA_MOUNTED_READ_ONLY)) {
- status = Environment.MEDIA_MOUNTED;
- readOnly = mRes.getString(R.string.read_only);
- }
-
- if (status.equals(Environment.MEDIA_MOUNTED)) {
- if (!Environment.isExternalStorageRemovable()) {
- // This device has built-in storage that is not removable.
- // There is no reason for the user to unmount it.
- if (mSdMountToggleAdded) {
- mSdMountPreferenceGroup.removePreference(mSdMountToggle);
- mSdMountToggleAdded = false;
- }
- }
- try {
- File path = Environment.getExternalStorageDirectory();
- StatFs stat = new StatFs(path.getPath());
- long blockSize = stat.getBlockSize();
- long totalBlocks = stat.getBlockCount();
- long availableBlocks = stat.getAvailableBlocks();
-
- mSdSize.setSummary(formatSize(totalBlocks * blockSize));
- mSdAvail.setSummary(formatSize(availableBlocks * blockSize) + readOnly);
-
- mSdMountToggle.setEnabled(true);
- mSdMountToggle.setTitle(mRes.getString(R.string.sd_eject));
- mSdMountToggle.setSummary(mRes.getString(R.string.sd_eject_summary));
-
- } catch (IllegalArgumentException e) {
- // this can occur if the SD card is removed, but we haven't
- // received the
- // ACTION_MEDIA_REMOVED Intent yet.
- status = Environment.MEDIA_REMOVED;
- }
- } else {
- mSdSize.setSummary(mRes.getString(R.string.sd_unavailable));
- mSdAvail.setSummary(mRes.getString(R.string.sd_unavailable));
-
- if (!Environment.isExternalStorageRemovable()) {
- if (status.equals(Environment.MEDIA_UNMOUNTED)) {
- if (!mSdMountToggleAdded) {
- mSdMountPreferenceGroup.addPreference(mSdMountToggle);
- mSdMountToggleAdded = true;
- }
- }
+ case MSG_UI_UPDATE_INTERNAL_EXACT: {
+ Bundle bundle = msg.getData();
+ final long totalSize = bundle.getLong(MemoryMeasurement.TOTAL_SIZE);
+ final long availSize = bundle.getLong(MemoryMeasurement.AVAIL_SIZE);
+ final long mediaUsed = bundle.getLong(MemoryMeasurement.MEDIA_USED);
+ final long appsUsed = bundle.getLong(MemoryMeasurement.APPS_USED);
+ updateUiExact(totalSize, availSize, mediaUsed, appsUsed);
+ break;
}
-
- if (status.equals(Environment.MEDIA_UNMOUNTED) ||
- status.equals(Environment.MEDIA_NOFS) ||
- status.equals(Environment.MEDIA_UNMOUNTABLE) ) {
- mSdMountToggle.setEnabled(true);
- mSdMountToggle.setTitle(mRes.getString(R.string.sd_mount));
- mSdMountToggle.setSummary(mRes.getString(R.string.sd_mount_summary));
- } else {
- mSdMountToggle.setEnabled(false);
- mSdMountToggle.setTitle(mRes.getString(R.string.sd_mount));
- mSdMountToggle.setSummary(mRes.getString(R.string.sd_insert_summary));
+ case MSG_UI_UPDATE_EXTERNAL_APPROXIMATE: {
+ Bundle bundle = msg.getData();
+ final long totalSize = bundle.getLong(MemoryMeasurement.TOTAL_SIZE);
+ final long availSize = bundle.getLong(MemoryMeasurement.AVAIL_SIZE);
+ updateExternalStorage(totalSize, availSize);
+ break;
}
}
}
- }
+ };
- private MemoryMeasurementHandler mMeasurementHandler;
+ private MemoryMeasurement mMeasurement;
@Override
public void onCreate(Bundle icicle) {
mSdMountPreferenceGroup = (PreferenceGroup)findPreference(MEMORY_SD_GROUP);
if (Environment.isExternalStorageEmulated()) {
- mSdMountPreferenceGroup.removePreference(mSdSize);
- mSdMountPreferenceGroup.removePreference(mSdAvail);
- mSdMountPreferenceGroup.removePreference(mSdMountToggle);
+ getPreferenceScreen().removePreference(mSdMountPreferenceGroup);
}
mInternalSize = findPreference(MEMORY_INTERNAL_SIZE);
mInternalAppsColor = mRes.getColor(R.color.memory_apps_usage);
mInternalUsedColor = mRes.getColor(R.color.memory_used);
+ float[] radius = new float[] {
+ 5f, 5f, 5f, 5f, 5f, 5f, 5f, 5f
+ };
+ RoundRectShape shape1 = new RoundRectShape(radius, null, null);
+
+ ShapeDrawable mediaShape = new ShapeDrawable(shape1);
+ mediaShape.setIntrinsicWidth(32);
+ mediaShape.setIntrinsicHeight(32);
+ mediaShape.getPaint().setColor(mInternalMediaColor);
+ mInternalMediaUsage.setIcon(mediaShape);
+
+ ShapeDrawable appsShape = new ShapeDrawable(shape1);
+ appsShape.setIntrinsicWidth(32);
+ appsShape.setIntrinsicHeight(32);
+ appsShape.getPaint().setColor(mInternalAppsColor);
+ mInternalAppsUsage.setIcon(appsShape);
+
mInternalUsageChart = (UsageBarPreference) findPreference(MEMORY_INTERNAL_CHART);
- // Start the thread that will measure the disk usage.
- final HandlerThread t = new HandlerThread("MeasurementHandler");
- t.start();
- mMeasurementHandler = new MemoryMeasurementHandler(t.getLooper());
+ mMeasurement = MemoryMeasurement.getInstance(getActivity());
+ mMeasurement.setReceiver(this);
}
@Override
intentFilter.addDataScheme("file");
getActivity().registerReceiver(mReceiver, intentFilter);
- if (!mMeasured) {
- mMeasurementHandler.sendEmptyMessage(MemoryMeasurementHandler.MSG_MEASURE_ALL);
+ mMeasurement.invalidate();
+ if (!Environment.isExternalStorageEmulated()) {
+ mMeasurement.measureExternal();
}
+ mMeasurement.measureInternal();
}
StorageEventListener mStorageListener = new StorageEventListener() {
Log.i(TAG, "Received storage state changed notification that " +
path + " changed state from " + oldState +
" to " + newState);
- mMeasurementHandler.sendEmptyMessage(MemoryMeasurementHandler.MSG_MEASURE_ALL);
+ if (!Environment.isExternalStorageEmulated()) {
+ mMeasurement.measureExternal();
+ }
}
};
public void onPause() {
super.onPause();
getActivity().unregisterReceiver(mReceiver);
- mMeasurementHandler.removeMessages(MemoryMeasurementHandler.MSG_MEASURE_ALL);
+ mMeasurement.cleanUp();
}
@Override
if (mStorageManager != null && mStorageListener != null) {
mStorageManager.unregisterListener(mStorageListener);
}
- mMeasurementHandler.cleanUp();
super.onDestroy();
}
intent.setClass(getActivity(), com.android.settings.MediaFormat.class);
startActivity(intent);
return true;
+ } else if (preference == mInternalAppsUsage) {
+ Intent intent = new Intent(Intent.ACTION_MANAGE_PACKAGE_STORAGE);
+ intent.setClass(getActivity(),
+ com.android.settings.Settings.ManageApplicationsActivity.class);
+ startActivity(intent);
+ return true;
}
return false;
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- mMeasurementHandler.sendEmptyMessage(MemoryMeasurementHandler.MSG_MEASURE_ALL);
+ mMeasurement.invalidate();
+
+ if (!Environment.isExternalStorageEmulated()) {
+ mMeasurement.measureExternal();
+ }
+ mMeasurement.measureInternal();
}
};
}})
.setNegativeButton(R.string.cancel, null)
.setMessage(R.string.dlg_confirm_unmount_text)
- .setOnCancelListener(this)
.create();
case DLG_ERROR_UNMOUNT:
return new AlertDialog.Builder(getActivity())
.setTitle(R.string.dlg_error_unmount_title)
.setNeutralButton(R.string.dlg_ok, null)
.setMessage(R.string.dlg_error_unmount_text)
- .setOnCancelListener(this)
.create();
}
return null;
}
+ @Override
+ protected void showDialog(int id) {
+ super.showDialog(id);
+
+ switch (id) {
+ case DLG_CONFIRM_UNMOUNT:
+ case DLG_ERROR_UNMOUNT:
+ setOnCancelListener(this);
+ break;
+ }
+ }
+
private void doUnmount(boolean force) {
// Present a toast here
Toast.makeText(getActivity(), R.string.unmount_inform_text, Toast.LENGTH_SHORT).show();
}
}
- private void updateUiExact() {
- final float totalSize = mInternalTotalSize;
-
- final long mediaSize = mInternalMediaSize;
- final long appsSize = mInternalAppsSize;
+ private void updateUiExact(long totalSize, long availSize, long mediaSize, long appsSize) {
+ mInternalSize.setSummary(formatSize(totalSize));
+ mInternalAvail.setSummary(formatSize(availSize));
+ mInternalMediaUsage.setSummary(formatSize(mediaSize));
+ mInternalAppsUsage.setSummary(formatSize(appsSize));
mInternalUsageChart.clear();
- mInternalUsageChart.addEntry(mediaSize / totalSize, mInternalMediaColor);
- mInternalUsageChart.addEntry(appsSize / totalSize, mInternalAppsColor);
+ mInternalUsageChart.addEntry(mediaSize / (float) totalSize, mInternalMediaColor);
+ mInternalUsageChart.addEntry(appsSize / (float) totalSize, mInternalAppsColor);
+
+ final long usedSize = totalSize - availSize;
// There are other things that can take up storage, but we didn't
// measure it.
- final long remaining = mInternalUsedSize - (mediaSize + appsSize);
+ final long remaining = usedSize - (mediaSize + appsSize);
if (remaining > 0) {
- mInternalUsageChart.addEntry(remaining / totalSize, mInternalUsedColor);
+ mInternalUsageChart.addEntry(remaining / (float) totalSize, mInternalUsedColor);
}
mInternalUsageChart.commit();
-
- mInternalMediaUsage.setSummary(formatSize(mediaSize));
- mInternalAppsUsage.setSummary(formatSize(appsSize));
}
- private void updateUiApproximate() {
+ private void updateUiApproximate(long totalSize, long availSize) {
+ mInternalSize.setSummary(formatSize(totalSize));
+ mInternalAvail.setSummary(formatSize(availSize));
+
+ final long usedSize = totalSize - availSize;
+
mInternalUsageChart.clear();
- mInternalUsageChart.addEntry(mInternalUsedSize / (float) mInternalTotalSize, getResources()
- .getColor(R.color.memory_used));
+ mInternalUsageChart.addEntry(usedSize / (float) totalSize, mInternalUsedColor);
mInternalUsageChart.commit();
}
+ private void updateExternalStorage(long totalSize, long availSize) {
+ String status = Environment.getExternalStorageState();
+ String readOnly = "";
+ if (status.equals(Environment.MEDIA_MOUNTED_READ_ONLY)) {
+ status = Environment.MEDIA_MOUNTED;
+ readOnly = mRes.getString(R.string.read_only);
+ }
+
+ if (status.equals(Environment.MEDIA_MOUNTED)) {
+ if (!Environment.isExternalStorageRemovable()) {
+ // This device has built-in storage that is not removable.
+ // There is no reason for the user to unmount it.
+ if (mSdMountToggleAdded) {
+ mSdMountPreferenceGroup.removePreference(mSdMountToggle);
+ mSdMountToggleAdded = false;
+ }
+ }
+ try {
+ mSdSize.setSummary(formatSize(totalSize));
+ mSdAvail.setSummary(formatSize(availSize) + readOnly);
+
+ mSdMountToggle.setEnabled(true);
+ mSdMountToggle.setTitle(mRes.getString(R.string.sd_eject));
+ mSdMountToggle.setSummary(mRes.getString(R.string.sd_eject_summary));
+
+ } catch (IllegalArgumentException e) {
+ // this can occur if the SD card is removed, but we haven't
+ // received the
+ // ACTION_MEDIA_REMOVED Intent yet.
+ status = Environment.MEDIA_REMOVED;
+ }
+ } else {
+ mSdSize.setSummary(mRes.getString(R.string.sd_unavailable));
+ mSdAvail.setSummary(mRes.getString(R.string.sd_unavailable));
+
+ if (!Environment.isExternalStorageRemovable()) {
+ if (status.equals(Environment.MEDIA_UNMOUNTED)) {
+ if (!mSdMountToggleAdded) {
+ mSdMountPreferenceGroup.addPreference(mSdMountToggle);
+ mSdMountToggleAdded = true;
+ }
+ }
+ }
+
+ if (status.equals(Environment.MEDIA_UNMOUNTED) || status.equals(Environment.MEDIA_NOFS)
+ || status.equals(Environment.MEDIA_UNMOUNTABLE)) {
+ mSdMountToggle.setEnabled(true);
+ mSdMountToggle.setTitle(mRes.getString(R.string.sd_mount));
+ mSdMountToggle.setSummary(mRes.getString(R.string.sd_mount_summary));
+ } else {
+ mSdMountToggle.setEnabled(false);
+ mSdMountToggle.setTitle(mRes.getString(R.string.sd_mount));
+ mSdMountToggle.setSummary(mRes.getString(R.string.sd_insert_summary));
+ }
+ }
+ }
+
private String formatSize(long size) {
return Formatter.formatFileSize(getActivity(), size);
}
// TODO: Is this really required?
// finish();
}
+
+ @Override
+ public void updateApproximateExternal(Bundle bundle) {
+ final Message message = mUpdateHandler.obtainMessage(MSG_UI_UPDATE_EXTERNAL_APPROXIMATE);
+ message.setData(bundle);
+ mUpdateHandler.sendMessage(message);
+ }
+
+ @Override
+ public void updateApproximateInternal(Bundle bundle) {
+ final Message message = mUpdateHandler.obtainMessage(MSG_UI_UPDATE_INTERNAL_APPROXIMATE);
+ message.setData(bundle);
+ mUpdateHandler.sendMessage(message);
+ }
+
+ @Override
+ public void updateExactInternal(Bundle bundle) {
+ final Message message = mUpdateHandler.obtainMessage(MSG_UI_UPDATE_INTERNAL_EXACT);
+ message.setData(bundle);
+ mUpdateHandler.sendMessage(message);
+ }
}