display amount of storage on /sdcard by downloads, music etc
when music storage usage is clicked on, show music app when downloads storage usage is clicked on, show download app when pic/videos storage usage is clicked on, show gallery app Change-Id: Ia1c341013e550acb537e6f8a4f4558030888cc45
This commit is contained in:
102
src/com/android/settings/deviceinfo/Constants.java
Normal file
102
src/com/android/settings/deviceinfo/Constants.java
Normal file
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright (C) 2010 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.os.Environment;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Some of the constants used in this package
|
||||
*/
|
||||
class Constants {
|
||||
static final int MEDIA_INDEX = 0;
|
||||
static final int DOWNLOADS_INDEX = 1;
|
||||
static final int PIC_VIDEO_INDEX = 2;
|
||||
static final int MUSIC_INDEX = 3;
|
||||
static final int MEDIA_APPS_DATA_INDEX = 4;
|
||||
static final int MEDIA_MISC_INDEX = 5;
|
||||
static final int NUM_MEDIA_DIRS_TRACKED = MEDIA_MISC_INDEX + 1;
|
||||
|
||||
static class MediaDirectory {
|
||||
final String[] mDirPaths;
|
||||
final String mKey;
|
||||
final String mPreferenceName;
|
||||
MediaDirectory(String pref, String debugInfo, String... paths) {
|
||||
mDirPaths = paths;
|
||||
mKey = debugInfo;
|
||||
mPreferenceName = pref;
|
||||
}
|
||||
}
|
||||
static final ArrayList<MediaDirectory> mMediaDirs = new ArrayList<MediaDirectory>();
|
||||
static final List<String> ExclusionTargetsForMiscFiles = new ArrayList<String>();
|
||||
static {
|
||||
mMediaDirs.add(MEDIA_INDEX,
|
||||
new MediaDirectory(null,
|
||||
"/sdcard",
|
||||
Environment.getExternalStorageDirectory().getAbsolutePath()));
|
||||
mMediaDirs.add(DOWNLOADS_INDEX,
|
||||
new MediaDirectory("memory_internal_downloads",
|
||||
"/sdcard/download",
|
||||
Environment.getExternalStoragePublicDirectory(
|
||||
Environment.DIRECTORY_DOWNLOADS).getAbsolutePath()));
|
||||
mMediaDirs.add(PIC_VIDEO_INDEX,
|
||||
new MediaDirectory("memory_internal_dcim",
|
||||
"/sdcard/pic_video",
|
||||
Environment.getExternalStoragePublicDirectory(
|
||||
Environment.DIRECTORY_DCIM).getAbsolutePath(),
|
||||
Environment.getExternalStoragePublicDirectory(
|
||||
Environment.DIRECTORY_MOVIES).getAbsolutePath(),
|
||||
Environment.getExternalStoragePublicDirectory(
|
||||
Environment.DIRECTORY_PICTURES).getAbsolutePath()));
|
||||
mMediaDirs.add(MUSIC_INDEX,
|
||||
new MediaDirectory("memory_internal_music",
|
||||
"/sdcard/audio",
|
||||
Environment.getExternalStoragePublicDirectory(
|
||||
Environment.DIRECTORY_MUSIC).getAbsolutePath(),
|
||||
Environment.getExternalStoragePublicDirectory(
|
||||
Environment.DIRECTORY_ALARMS).getAbsolutePath(),
|
||||
Environment.getExternalStoragePublicDirectory(
|
||||
Environment.DIRECTORY_NOTIFICATIONS).getAbsolutePath(),
|
||||
Environment.getExternalStoragePublicDirectory(
|
||||
Environment.DIRECTORY_RINGTONES).getAbsolutePath(),
|
||||
Environment.getExternalStoragePublicDirectory(
|
||||
Environment.DIRECTORY_PODCASTS).getAbsolutePath()));
|
||||
mMediaDirs.add(MEDIA_APPS_DATA_INDEX,
|
||||
new MediaDirectory(null,
|
||||
"/sdcard/Android",
|
||||
Environment.getExternalStorageAndroidDataDir().getAbsolutePath()));
|
||||
mMediaDirs.add(MEDIA_MISC_INDEX,
|
||||
new MediaDirectory("memory_internal_media_misc",
|
||||
"misc on /sdcard",
|
||||
"not relevant"));
|
||||
// prepare a lit of strings representing dirpaths that should be skipped while looking
|
||||
// for 'other' files
|
||||
for (int j = 0; j < Constants.NUM_MEDIA_DIRS_TRACKED - 1; j++) {
|
||||
String[] dirs = Constants.mMediaDirs.get(j).mDirPaths;
|
||||
int len = dirs.length;
|
||||
if (len > 0) {
|
||||
for (int k = 0; k < len; k++) {
|
||||
ExclusionTargetsForMiscFiles.add(dirs[k]);
|
||||
}
|
||||
}
|
||||
// also add /sdcard/Android
|
||||
ExclusionTargetsForMiscFiles.add(
|
||||
Environment.getExternalStorageDirectory().getAbsolutePath() + "/Android");
|
||||
}
|
||||
}
|
||||
}
|
||||
78
src/com/android/settings/deviceinfo/FileItemInfoLayout.java
Normal file
78
src/com/android/settings/deviceinfo/FileItemInfoLayout.java
Normal file
@@ -0,0 +1,78 @@
|
||||
// Copyright 2011 Google Inc. All Rights Reserved.
|
||||
|
||||
package com.android.settings.deviceinfo;
|
||||
|
||||
import com.android.settings.R;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Environment;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.ViewDebug;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.Checkable;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
/**
|
||||
* Handles display of a single row entry on Settings --> Storage --> Misc Files screen
|
||||
*/
|
||||
public class FileItemInfoLayout extends RelativeLayout implements Checkable {
|
||||
private TextView mFileNameView;
|
||||
private TextView mFileSizeView;
|
||||
private CheckBox mCheckbox;
|
||||
private static final int mLengthExternalStorageDirPrefix =
|
||||
Environment.getExternalStorageDirectory().getAbsolutePath().length() + 1;
|
||||
|
||||
public FileItemInfoLayout(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public FileItemInfoLayout(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public FileItemInfoLayout(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
}
|
||||
|
||||
public void toggle() {
|
||||
setChecked(!mCheckbox.isChecked());
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see android.view.View#onFinishInflate()
|
||||
*/
|
||||
@Override
|
||||
protected void onFinishInflate() {
|
||||
super.onFinishInflate();
|
||||
mFileNameView = (TextView) findViewById(R.id.misc_filename);
|
||||
mFileSizeView = (TextView) findViewById(R.id.misc_filesize);
|
||||
mCheckbox = (CheckBox) findViewById(R.id.misc_checkbox);
|
||||
}
|
||||
|
||||
public void setFileName(String fileName) {
|
||||
mFileNameView.setText(fileName.substring(mLengthExternalStorageDirPrefix));
|
||||
}
|
||||
|
||||
public void setFileSize(String filesize) {
|
||||
mFileSizeView.setText(filesize);
|
||||
}
|
||||
|
||||
@ViewDebug.ExportedProperty
|
||||
public boolean isChecked() {
|
||||
return mCheckbox.isChecked();
|
||||
}
|
||||
|
||||
public CheckBox getCheckBox() {
|
||||
return mCheckbox;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Changes the checked state of this text view.</p>
|
||||
*
|
||||
* @param checked true to check the text, false to uncheck it
|
||||
*/
|
||||
public void setChecked(boolean checked) {
|
||||
mCheckbox.setChecked(checked);
|
||||
}
|
||||
}
|
||||
@@ -23,6 +23,7 @@ import com.android.settings.deviceinfo.MemoryMeasurement.MeasurementReceiver;
|
||||
import android.app.ActivityManager;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.Dialog;
|
||||
import android.app.DownloadManager;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
@@ -32,9 +33,7 @@ import android.content.DialogInterface.OnCancelListener;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
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;
|
||||
@@ -56,8 +55,7 @@ import java.util.List;
|
||||
|
||||
public class Memory extends SettingsPreferenceFragment implements OnCancelListener,
|
||||
MeasurementReceiver {
|
||||
private static final String TAG = "Memory";
|
||||
static final boolean localLOGV = false;
|
||||
private static final String TAG = "MemorySettings";
|
||||
|
||||
private static final String MEMORY_SD_SIZE = "memory_sd_size";
|
||||
|
||||
@@ -75,8 +73,6 @@ public class Memory extends SettingsPreferenceFragment implements OnCancelListen
|
||||
|
||||
private static final String MEMORY_INTERNAL_APPS = "memory_internal_apps";
|
||||
|
||||
private static final String MEMORY_INTERNAL_MEDIA = "memory_internal_media";
|
||||
|
||||
private static final String MEMORY_INTERNAL_CHART = "memory_internal_chart";
|
||||
|
||||
private static final int DLG_CONFIRM_UNMOUNT = 1;
|
||||
@@ -94,13 +90,13 @@ public class Memory extends SettingsPreferenceFragment implements OnCancelListen
|
||||
// Internal storage preferences
|
||||
private Preference mInternalSize;
|
||||
private Preference mInternalAvail;
|
||||
private Preference mInternalMediaUsage;
|
||||
private Preference mInternalAppsUsage;
|
||||
private final Preference[] mMediaPreferences = new Preference[Constants.NUM_MEDIA_DIRS_TRACKED];
|
||||
private UsageBarPreference mInternalUsageChart;
|
||||
|
||||
// Internal storage chart colors
|
||||
private int mInternalMediaColor;
|
||||
private int mInternalAppsColor;
|
||||
private int mInternalAvailColor;
|
||||
private int mInternalUsedColor;
|
||||
|
||||
boolean mSdMountToggleAdded = true;
|
||||
@@ -134,9 +130,12 @@ public class Memory extends SettingsPreferenceFragment implements OnCancelListen
|
||||
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);
|
||||
final long[] mediaSizes = new long[Constants.NUM_MEDIA_DIRS_TRACKED];
|
||||
for (int i = 0; i < Constants.NUM_MEDIA_DIRS_TRACKED; i++) {
|
||||
mediaSizes[i] = bundle.getLong(Constants.mMediaDirs.get(i).mKey);
|
||||
}
|
||||
updateUiExact(totalSize, availSize, appsUsed, mediaSizes);
|
||||
break;
|
||||
}
|
||||
case MSG_UI_UPDATE_EXTERNAL_APPROXIMATE: {
|
||||
@@ -175,31 +174,59 @@ public class Memory extends SettingsPreferenceFragment implements OnCancelListen
|
||||
}
|
||||
|
||||
mInternalSize = findPreference(MEMORY_INTERNAL_SIZE);
|
||||
mInternalAvail = findPreference(MEMORY_INTERNAL_AVAIL);
|
||||
mInternalMediaUsage = findPreference(MEMORY_INTERNAL_MEDIA);
|
||||
mInternalAppsUsage = findPreference(MEMORY_INTERNAL_APPS);
|
||||
|
||||
mInternalMediaColor = mRes.getColor(R.color.memory_media_usage);
|
||||
mInternalAppsColor = mRes.getColor(R.color.memory_apps_usage);
|
||||
mInternalUsedColor = android.graphics.Color.GRAY;
|
||||
|
||||
mInternalAvailColor = mRes.getColor(R.color.memory_avail);
|
||||
final int buttonSize = (int) mRes.getDimension(R.dimen.device_memory_usage_button_size);
|
||||
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);
|
||||
// total available space
|
||||
mInternalAvail = findPreference(MEMORY_INTERNAL_AVAIL);
|
||||
ShapeDrawable availShape = new ShapeDrawable(shape1);
|
||||
availShape.setIntrinsicWidth(buttonSize);
|
||||
availShape.setIntrinsicHeight(buttonSize);
|
||||
availShape.getPaint().setColor(mInternalAvailColor);
|
||||
mInternalAvail.setIcon(availShape);
|
||||
|
||||
// used by apps
|
||||
mInternalAppsUsage = findPreference(MEMORY_INTERNAL_APPS);
|
||||
ShapeDrawable appsShape = new ShapeDrawable(shape1);
|
||||
appsShape.setIntrinsicWidth(32);
|
||||
appsShape.setIntrinsicHeight(32);
|
||||
appsShape.setIntrinsicWidth(buttonSize);
|
||||
appsShape.setIntrinsicHeight(buttonSize);
|
||||
appsShape.getPaint().setColor(mInternalAppsColor);
|
||||
mInternalAppsUsage.setIcon(appsShape);
|
||||
|
||||
// space used by individual major directories on /sdcard
|
||||
for (int i = 0; i < Constants.NUM_MEDIA_DIRS_TRACKED; i++) {
|
||||
// nothing to be displayed for certain entries in Constants.mMediaDirs
|
||||
if (Constants.mMediaDirs.get(i).mPreferenceName == null) {
|
||||
continue;
|
||||
}
|
||||
mMediaPreferences[i] = findPreference(Constants.mMediaDirs.get(i).mPreferenceName);
|
||||
ShapeDrawable shape = new ShapeDrawable(shape1);
|
||||
shape.setIntrinsicWidth(buttonSize);
|
||||
shape.setIntrinsicHeight(buttonSize);
|
||||
int color = 0;
|
||||
switch (i) {
|
||||
case Constants.DOWNLOADS_INDEX:
|
||||
color = mRes.getColor(R.color.memory_downloads);
|
||||
break;
|
||||
case Constants.PIC_VIDEO_INDEX:
|
||||
color = mRes.getColor(R.color.memory_video);
|
||||
break;
|
||||
case Constants.MUSIC_INDEX:
|
||||
color = mRes.getColor(R.color.memory_audio);
|
||||
break;
|
||||
case Constants.MEDIA_MISC_INDEX:
|
||||
color = mRes.getColor(R.color.memory_misc);
|
||||
break;
|
||||
}
|
||||
shape.getPaint().setColor(color);
|
||||
mMediaPreferences[i].setIcon(shape);
|
||||
}
|
||||
mInternalUsageChart = (UsageBarPreference) findPreference(MEMORY_INTERNAL_CHART);
|
||||
|
||||
mMeasurement = MemoryMeasurement.getInstance(getActivity());
|
||||
@@ -209,7 +236,7 @@ public class Memory extends SettingsPreferenceFragment implements OnCancelListen
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
|
||||
mMeasurement.setReceiver(this);
|
||||
IntentFilter intentFilter = new IntentFilter(Intent.ACTION_MEDIA_SCANNER_STARTED);
|
||||
intentFilter.addAction(Intent.ACTION_MEDIA_SCANNER_FINISHED);
|
||||
intentFilter.addDataScheme("file");
|
||||
@@ -282,6 +309,27 @@ public class Memory extends SettingsPreferenceFragment implements OnCancelListen
|
||||
com.android.settings.Settings.ManageApplicationsActivity.class);
|
||||
startActivity(intent);
|
||||
return true;
|
||||
} else if (preference == mMediaPreferences[Constants.DOWNLOADS_INDEX]) {
|
||||
Intent intent = new Intent(DownloadManager.ACTION_VIEW_DOWNLOADS)
|
||||
.putExtra(DownloadManager.INTENT_EXTRAS_SORT_BY_SIZE, true);
|
||||
startActivity(intent);
|
||||
return true;
|
||||
} else if (preference == mMediaPreferences[Constants.MUSIC_INDEX]) {
|
||||
Intent intent = new Intent("android.intent.action.GET_CONTENT");
|
||||
intent.setType("audio/mp3");
|
||||
startActivity(intent);
|
||||
return true;
|
||||
} else if (preference == mMediaPreferences[Constants.PIC_VIDEO_INDEX]) {
|
||||
Intent intent = new Intent("android.intent.action.GET_CONTENT");
|
||||
intent.setType("image/jpeg");
|
||||
startActivity(intent);
|
||||
return true;
|
||||
} else if (preference == mMediaPreferences[Constants.MEDIA_MISC_INDEX]) {
|
||||
Context context = getActivity().getApplicationContext();
|
||||
if (MemoryMeasurement.getInstance(context).isSizeOfMiscCategorynonZero()) {
|
||||
startActivity(new Intent(context, MiscFilesHandler.class));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -375,7 +423,6 @@ public class Memory extends SettingsPreferenceFragment implements OnCancelListen
|
||||
// Check if external media is in use.
|
||||
try {
|
||||
if (hasAppsAccessingStorage()) {
|
||||
if (localLOGV) Log.i(TAG, "Do have storage users accessing media");
|
||||
// Present dialog to user
|
||||
showDialogInner(DLG_CONFIRM_UNMOUNT);
|
||||
} else {
|
||||
@@ -400,19 +447,45 @@ public class Memory extends SettingsPreferenceFragment implements OnCancelListen
|
||||
}
|
||||
}
|
||||
|
||||
private void updateUiExact(long totalSize, long availSize, long mediaSize, long appsSize) {
|
||||
private void updateUiExact(long totalSize, long availSize, long appsSize, long[] mediaSizes) {
|
||||
// There are other things that can take up storage, but we didn't measure it.
|
||||
// add that unaccounted-for-usage to Apps Usage
|
||||
final long appsPlusRemaining = totalSize - availSize - mediaSize;
|
||||
|
||||
long appsPlusRemaining = totalSize - availSize - mediaSizes[Constants.DOWNLOADS_INDEX] -
|
||||
mediaSizes[Constants.PIC_VIDEO_INDEX] - mediaSizes[Constants.MUSIC_INDEX] -
|
||||
mediaSizes[Constants.MEDIA_MISC_INDEX];
|
||||
mInternalSize.setSummary(formatSize(totalSize));
|
||||
mInternalAvail.setSummary(formatSize(availSize));
|
||||
mInternalMediaUsage.setSummary(formatSize(mediaSize));
|
||||
mInternalAppsUsage.setSummary(formatSize(appsPlusRemaining));
|
||||
|
||||
mInternalUsageChart.clear();
|
||||
mInternalUsageChart.addEntry(mediaSize / (float) totalSize, mInternalMediaColor);
|
||||
mInternalUsageChart.addEntry(appsPlusRemaining / (float) totalSize, mInternalAppsColor);
|
||||
|
||||
for (int i = 0; i < Constants.NUM_MEDIA_DIRS_TRACKED; i++) {
|
||||
if (Constants.mMediaDirs.get(i).mPreferenceName == null) {
|
||||
continue;
|
||||
}
|
||||
this.mMediaPreferences[i].setSummary(formatSize(mediaSizes[i]));
|
||||
// don't add entry to color chart for media usage and for zero-sized dirs
|
||||
if (i != Constants.MEDIA_INDEX && mediaSizes[i] > 0) {
|
||||
int color = 0;
|
||||
switch (i) {
|
||||
case Constants.DOWNLOADS_INDEX:
|
||||
color = mRes.getColor(R.color.memory_downloads);
|
||||
break;
|
||||
case Constants.PIC_VIDEO_INDEX:
|
||||
color = mRes.getColor(R.color.memory_video);
|
||||
break;
|
||||
case Constants.MUSIC_INDEX:
|
||||
color = mRes.getColor(R.color.memory_audio);
|
||||
break;
|
||||
case Constants.MEDIA_MISC_INDEX:
|
||||
color = mRes.getColor(R.color.memory_misc);
|
||||
break;
|
||||
}
|
||||
mInternalUsageChart.addEntry(mediaSizes[i] / (float) totalSize, color);
|
||||
}
|
||||
}
|
||||
mInternalUsageChart.addEntry(availSize / (float) totalSize, mInternalAvailColor);
|
||||
mInternalUsageChart.commit();
|
||||
}
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ import android.util.Log;
|
||||
import java.io.File;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -35,14 +36,16 @@ import java.util.List;
|
||||
*
|
||||
* Filesystem stats (using StatFs)
|
||||
* Directory measurements (using DefaultContainerService.measureDir)
|
||||
* Applicaiton measurements (using PackageManager)
|
||||
* Application measurements (using PackageManager)
|
||||
*
|
||||
* Then the calling application would just specify the type and an argument.
|
||||
* This class would keep track of it while the calling application would
|
||||
* decide on how to use it.
|
||||
*/
|
||||
public class MemoryMeasurement {
|
||||
private static final String TAG = "MemoryMeasurement";
|
||||
private static final String TAG = "MemorySettings";
|
||||
private static final boolean LOCAL_LOGV = true;
|
||||
static final boolean LOGV = LOCAL_LOGV && Log.isLoggable(TAG, Log.VERBOSE);
|
||||
|
||||
public static final String TOTAL_SIZE = "total_size";
|
||||
|
||||
@@ -50,7 +53,7 @@ public class MemoryMeasurement {
|
||||
|
||||
public static final String APPS_USED = "apps_used";
|
||||
|
||||
public static final String MEDIA_USED = "media_used";
|
||||
private long[] mMediaSizes = new long[Constants.NUM_MEDIA_DIRS_TRACKED];
|
||||
|
||||
private static final String DEFAULT_CONTAINER_PACKAGE = "com.android.defcontainer";
|
||||
|
||||
@@ -66,13 +69,13 @@ public class MemoryMeasurement {
|
||||
// Internal memory fields
|
||||
private long mInternalTotalSize;
|
||||
private long mInternalAvailSize;
|
||||
private long mInternalMediaSize;
|
||||
private long mInternalAppsSize;
|
||||
|
||||
// External memory fields
|
||||
private long mExternalTotalSize;
|
||||
|
||||
private long mExternalAvailSize;
|
||||
List<FileInfo> mFileInfoForMisc;
|
||||
|
||||
private MemoryMeasurement(Context context) {
|
||||
// Start the thread that will measure the disk usage.
|
||||
@@ -98,7 +101,9 @@ public class MemoryMeasurement {
|
||||
}
|
||||
|
||||
public void setReceiver(MeasurementReceiver receiver) {
|
||||
mReceiver = new WeakReference<MeasurementReceiver>(receiver);
|
||||
if (mReceiver == null || mReceiver.get() == null) {
|
||||
mReceiver = new WeakReference<MeasurementReceiver>(receiver);
|
||||
}
|
||||
}
|
||||
|
||||
public void measureExternal() {
|
||||
@@ -134,6 +139,9 @@ public class MemoryMeasurement {
|
||||
private void sendInternalExactUpdate() {
|
||||
MeasurementReceiver receiver = (mReceiver != null) ? mReceiver.get() : null;
|
||||
if (receiver == null) {
|
||||
if (LOGV) {
|
||||
Log.i(TAG, "measurements dropped because receiver is null! wasted effort");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -141,7 +149,9 @@ public class MemoryMeasurement {
|
||||
bundle.putLong(TOTAL_SIZE, mInternalTotalSize);
|
||||
bundle.putLong(AVAIL_SIZE, mInternalAvailSize);
|
||||
bundle.putLong(APPS_USED, mInternalAppsSize);
|
||||
bundle.putLong(MEDIA_USED, mInternalMediaSize);
|
||||
for (int i = 0; i < Constants.NUM_MEDIA_DIRS_TRACKED; i++) {
|
||||
bundle.putLong(Constants.mMediaDirs.get(i).mKey, mMediaSizes[i]);
|
||||
}
|
||||
|
||||
receiver.updateExactInternal(bundle);
|
||||
}
|
||||
@@ -252,6 +262,7 @@ public class MemoryMeasurement {
|
||||
case MSG_CONNECTED: {
|
||||
IMediaContainerService imcs = (IMediaContainerService) msg.obj;
|
||||
measureExactInternalStorage(imcs);
|
||||
break;
|
||||
}
|
||||
case MSG_DISCONNECT: {
|
||||
synchronized (mLock) {
|
||||
@@ -265,6 +276,7 @@ public class MemoryMeasurement {
|
||||
context.unbindService(mDefContainerConn);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MSG_COMPLETED: {
|
||||
mMeasured = true;
|
||||
@@ -356,24 +368,40 @@ public class MemoryMeasurement {
|
||||
if (context == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// We have to get installd to measure the package sizes.
|
||||
PackageManager pm = context.getPackageManager();
|
||||
if (pm == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
long mediaSize;
|
||||
try {
|
||||
mediaSize = imcs.calculateDirectorySize(
|
||||
Environment.getExternalStorageDirectory().getAbsolutePath());
|
||||
} catch (Exception e) {
|
||||
Log.i(TAG, "Could not read memory from default container service");
|
||||
return;
|
||||
// measure sizes for all except "media_misc" - which is computed
|
||||
for (int i = 0; i < Constants.NUM_MEDIA_DIRS_TRACKED - 1; i++) {
|
||||
mMediaSizes[i] = 0;
|
||||
String[] dirs = Constants.mMediaDirs.get(i).mDirPaths;
|
||||
int len = dirs.length;
|
||||
if (len > 0) {
|
||||
for (int k = 0; k < len; k++) {
|
||||
long dirSize = getSize(imcs, dirs[k]);
|
||||
mMediaSizes[i] += dirSize;
|
||||
if (LOGV) {
|
||||
Log.i(TAG, "size of " + dirs[k] + ": " + dirSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mInternalMediaSize = mediaSize;
|
||||
// compute the size of "misc"
|
||||
mMediaSizes[Constants.MEDIA_MISC_INDEX] = mMediaSizes[Constants.MEDIA_INDEX];
|
||||
for (int i = 1; i < Constants.NUM_MEDIA_DIRS_TRACKED - 1; i++) {
|
||||
mMediaSizes[Constants.MEDIA_MISC_INDEX] -= mMediaSizes[i];
|
||||
}
|
||||
if (LOGV) {
|
||||
Log.i(TAG, "media_misc size: " + mMediaSizes[Constants.MEDIA_MISC_INDEX]);
|
||||
}
|
||||
|
||||
// compute the sizes of each of the files/directories under 'misc' category
|
||||
measureSizesOfMisc(imcs);
|
||||
|
||||
// compute apps sizes
|
||||
final List<ApplicationInfo> apps = pm
|
||||
.getInstalledApplications(PackageManager.GET_UNINSTALLED_PACKAGES
|
||||
| PackageManager.GET_DISABLED_COMPONENTS);
|
||||
@@ -393,6 +421,43 @@ public class MemoryMeasurement {
|
||||
// Sending of the message back to the MeasurementReceiver is
|
||||
// completed in the PackageObserver
|
||||
}
|
||||
private void measureSizesOfMisc(IMediaContainerService imcs) {
|
||||
File top = Environment.getExternalStorageDirectory();
|
||||
mFileInfoForMisc = new ArrayList<FileInfo>();
|
||||
File[] files = top.listFiles();
|
||||
int len = files.length;
|
||||
if (len == 0) {
|
||||
return;
|
||||
}
|
||||
// get sizes of all top level nodes in /sdcard dir except the ones already computed...
|
||||
long counter = 0;
|
||||
for (int i = 0; i < len; i++) {
|
||||
String path = files[i].getAbsolutePath();
|
||||
if (Constants.ExclusionTargetsForMiscFiles.contains(path)) {
|
||||
continue;
|
||||
}
|
||||
if (files[i].isFile()) {
|
||||
mFileInfoForMisc.add(new FileInfo(path, files[i].length(), counter++));
|
||||
} else if (files[i].isDirectory()) {
|
||||
long dirSize = getSize(imcs, path);
|
||||
mFileInfoForMisc.add(new FileInfo(path, dirSize, counter++));
|
||||
} else {
|
||||
}
|
||||
}
|
||||
// sort the list of FileInfo objects collected above in descending order of their sizes
|
||||
Collections.sort(mFileInfoForMisc);
|
||||
}
|
||||
|
||||
private long getSize(IMediaContainerService imcs, String dir) {
|
||||
try {
|
||||
long size = imcs.calculateDirectorySize(dir);
|
||||
return size;
|
||||
} catch (Exception e) {
|
||||
Log.w(TAG, "Could not read memory from default container service for " +
|
||||
dir, e);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
public void measureApproximateExternalStorage() {
|
||||
File path = Environment.getExternalStorageDirectory();
|
||||
@@ -412,4 +477,29 @@ public class MemoryMeasurement {
|
||||
public void invalidate() {
|
||||
mHandler.sendEmptyMessage(MeasurementHandler.MSG_INVALIDATE);
|
||||
}
|
||||
|
||||
boolean isSizeOfMiscCategorynonZero() {
|
||||
return mFileInfoForMisc.size() > 0;
|
||||
}
|
||||
|
||||
static class FileInfo implements Comparable<FileInfo> {
|
||||
String mFileName;
|
||||
long mSize;
|
||||
long mId;
|
||||
FileInfo(String fileName, long size, long id) {
|
||||
mFileName = fileName;
|
||||
mSize = size;
|
||||
mId = id;
|
||||
}
|
||||
@Override
|
||||
public int compareTo(FileInfo that) {
|
||||
if (this == that || mSize == that.mSize) return 0;
|
||||
else if (mSize < that.mSize) return 1; // for descending sort
|
||||
else return -1;
|
||||
}
|
||||
@Override
|
||||
public String toString() {
|
||||
return mFileName + " : " + mSize + ", id:" + mId;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
279
src/com/android/settings/deviceinfo/MiscFilesHandler.java
Normal file
279
src/com/android/settings/deviceinfo/MiscFilesHandler.java
Normal file
@@ -0,0 +1,279 @@
|
||||
/*
|
||||
* Copyright (C) 2010 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 com.android.settings.R;
|
||||
import com.android.settings.deviceinfo.MemoryMeasurement.FileInfo;
|
||||
|
||||
import android.app.ListActivity;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.text.format.Formatter;
|
||||
import android.util.Log;
|
||||
import android.util.SparseBooleanArray;
|
||||
import android.view.ActionMode;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.view.View.OnLongClickListener;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.BaseAdapter;
|
||||
import android.widget.CompoundButton;
|
||||
import android.widget.CompoundButton.OnCheckedChangeListener;
|
||||
import android.widget.ListView;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* This class handles the selection and removal of Misc files.
|
||||
*/
|
||||
public class MiscFilesHandler extends ListActivity {
|
||||
private static final String TAG = "MemorySettings";
|
||||
private String mNumSelectedStr;
|
||||
private String mNumSelectedOutOfStr;
|
||||
private MemoryMearurementAdapter mAdapter;
|
||||
private LayoutInflater mInflater;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setFinishOnTouchOutside(true);
|
||||
setTitle(R.string.misc_files);
|
||||
mNumSelectedStr = getString(R.string.misc_files_selected_count);
|
||||
mNumSelectedOutOfStr = getString(R.string.misc_files_selected_count_out_of);
|
||||
mAdapter = new MemoryMearurementAdapter(this);
|
||||
mInflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
setContentView(R.layout.settings_storage_miscfiles_list);
|
||||
ListView lv = getListView();
|
||||
lv.setItemsCanFocus(true);
|
||||
lv.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
|
||||
lv.setMultiChoiceModeListener(new ModeCallback(this));
|
||||
setListAdapter(mAdapter);
|
||||
}
|
||||
|
||||
private class ModeCallback implements ListView.MultiChoiceModeListener {
|
||||
private int mDataCount;
|
||||
private final Context mContext;
|
||||
|
||||
public ModeCallback(Context context) {
|
||||
mContext = context;
|
||||
mDataCount = mAdapter.getCount();
|
||||
}
|
||||
|
||||
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
|
||||
final MenuInflater inflater = getMenuInflater();
|
||||
inflater.inflate(R.menu.misc_files_menu, menu);
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
|
||||
ListView lv = getListView();
|
||||
switch (item.getItemId()) {
|
||||
case R.id.action_delete:
|
||||
// delete the files selected
|
||||
SparseBooleanArray checkedItems = lv.getCheckedItemPositions();
|
||||
int checkedCount = getListView().getCheckedItemCount();
|
||||
if (checkedCount > mDataCount) {
|
||||
throw new IllegalStateException("checked item counts do not match. " +
|
||||
"checkedCount: " + checkedCount + ", dataSize: " + mDataCount);
|
||||
}
|
||||
if (mDataCount > 0) {
|
||||
ArrayList<Object> toRemove = new ArrayList<Object>();
|
||||
for (int i = 0; i < mDataCount; i++) {
|
||||
if (!checkedItems.get(i)) {
|
||||
//item not selected
|
||||
continue;
|
||||
}
|
||||
if (MemoryMeasurement.LOGV) {
|
||||
Log.i(TAG, "deleting: " + mAdapter.getItem(i));
|
||||
}
|
||||
// delete the file
|
||||
File file = new File(mAdapter.getItem(i).mFileName);
|
||||
if (file.isDirectory()) {
|
||||
deleteDir(file);
|
||||
} else {
|
||||
file.delete();
|
||||
}
|
||||
toRemove.add(mAdapter.getItem(i));
|
||||
}
|
||||
mAdapter.removeAll(toRemove);
|
||||
mAdapter.notifyDataSetChanged();
|
||||
mDataCount = mAdapter.getCount();
|
||||
}
|
||||
mode.finish();
|
||||
break;
|
||||
|
||||
case R.id.action_select_all:
|
||||
// check ALL items
|
||||
for (int i = 0; i < mDataCount; i++) {
|
||||
lv.setItemChecked(i, true);
|
||||
}
|
||||
// update the title and subtitle with number selected and numberBytes selected
|
||||
onItemCheckedStateChanged(mode, 1, 0, true);
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Deletes all files and subdirectories under given dir.
|
||||
// Returns true if all deletions were successful.
|
||||
// If a deletion fails, the method stops attempting to delete and returns false.
|
||||
private boolean deleteDir(File dir) {
|
||||
if (dir.isDirectory()) {
|
||||
String[] children = dir.list();
|
||||
for (int i=0; i < children.length; i++) {
|
||||
boolean success = deleteDir(new File(dir, children[i]));
|
||||
if (!success) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
// The directory is now empty so delete it
|
||||
return dir.delete();
|
||||
}
|
||||
|
||||
public void onDestroyActionMode(ActionMode mode) {
|
||||
}
|
||||
|
||||
public void onItemCheckedStateChanged(ActionMode mode, int position, long id,
|
||||
boolean checked) {
|
||||
ListView lv = getListView();
|
||||
int numChecked = lv.getCheckedItemCount();
|
||||
mode.setTitle(mNumSelectedStr + " : " + numChecked +
|
||||
" " + mNumSelectedOutOfStr + " " + mAdapter.getCount());
|
||||
|
||||
// total the sizes of all items selected so far
|
||||
SparseBooleanArray checkedItems = lv.getCheckedItemPositions();
|
||||
long selectedDataSize = 0;
|
||||
if (numChecked > 0) {
|
||||
for (int i = 0; i < mDataCount; i++) {
|
||||
if (checkedItems.get(i)) {
|
||||
// item is checked
|
||||
selectedDataSize += mAdapter.getItem(i).mSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
mode.setSubtitle(Formatter.formatFileSize(mContext, selectedDataSize) +
|
||||
" " + mNumSelectedOutOfStr + " " +
|
||||
Formatter.formatFileSize(mContext, mAdapter.getDataSize()));
|
||||
}
|
||||
}
|
||||
|
||||
public class MemoryMearurementAdapter extends BaseAdapter {
|
||||
private ArrayList<MemoryMeasurement.FileInfo> mData = null;
|
||||
private long mDataSize = 0;
|
||||
private Context mContext;
|
||||
|
||||
public MemoryMearurementAdapter(Context context) {
|
||||
mContext = context;
|
||||
MemoryMeasurement mMeasurement = MemoryMeasurement.getInstance(context);
|
||||
mData = (ArrayList<MemoryMeasurement.FileInfo>)mMeasurement.mFileInfoForMisc;
|
||||
if (mData != null) {
|
||||
for (MemoryMeasurement.FileInfo info : mData) {
|
||||
mDataSize += info.mSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return (mData == null) ? 0 : mData.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MemoryMeasurement.FileInfo getItem(int position) {
|
||||
if (mData == null || mData.size() <= position) {
|
||||
return null;
|
||||
}
|
||||
return mData.get(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId(int position) {
|
||||
if (mData == null || mData.size() <= position) {
|
||||
return 0;
|
||||
}
|
||||
return mData.get(position).mId;
|
||||
}
|
||||
public void removeAll(List<Object> objs) {
|
||||
if (mData == null) {
|
||||
return;
|
||||
}
|
||||
for (Object o : objs) {
|
||||
mData.remove(o);
|
||||
mDataSize -= ((MemoryMeasurement.FileInfo) o).mSize;
|
||||
}
|
||||
}
|
||||
|
||||
public long getDataSize() {
|
||||
return mDataSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyDataSetChanged() {
|
||||
super.notifyDataSetChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
final FileItemInfoLayout view = (convertView == null) ?
|
||||
(FileItemInfoLayout) mInflater.inflate(R.layout.settings_storage_miscfiles,
|
||||
parent, false) : (FileItemInfoLayout) convertView;
|
||||
FileInfo item = getItem(position);
|
||||
view.setFileName(item.mFileName);
|
||||
view.setFileSize(Formatter.formatFileSize(mContext, item.mSize));
|
||||
final ListView listView = (ListView) parent;
|
||||
final int listPosition = position;
|
||||
view.getCheckBox().setOnCheckedChangeListener(new OnCheckedChangeListener() {
|
||||
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
||||
listView.setItemChecked(listPosition, isChecked);
|
||||
}
|
||||
|
||||
});
|
||||
view.setOnLongClickListener(new OnLongClickListener() {
|
||||
@Override
|
||||
public boolean onLongClick(View v) {
|
||||
if (listView.getCheckedItemCount() > 0) {
|
||||
return false;
|
||||
}
|
||||
listView.setItemChecked(listPosition, !view.isChecked());
|
||||
return true;
|
||||
}
|
||||
});
|
||||
view.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (listView.getCheckedItemCount() > 0) {
|
||||
listView.setItemChecked(listPosition, !view.isChecked());
|
||||
}
|
||||
}
|
||||
});
|
||||
return view;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user