summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/com/android/settings/Settings.java1
-rw-r--r--src/com/android/settings/SettingsActivity.java6
-rw-r--r--src/com/android/settings/deviceinfo/Memory.java509
-rw-r--r--src/com/android/settings/deviceinfo/MiscFilesHandler.java286
-rw-r--r--src/com/android/settings/deviceinfo/PrivateVolumeSettings.java548
-rw-r--r--src/com/android/settings/deviceinfo/PublicVolumeSettings.java205
-rw-r--r--src/com/android/settings/deviceinfo/StorageItemPreference.java4
-rw-r--r--src/com/android/settings/deviceinfo/StorageMeasurement.java302
-rw-r--r--src/com/android/settings/deviceinfo/StorageSettings.java421
-rw-r--r--src/com/android/settings/deviceinfo/StorageVolumePreference.java89
-rw-r--r--src/com/android/settings/deviceinfo/StorageVolumePreferenceCategory.java483
-rw-r--r--src/com/android/settings/search/Ranking.java4
-rw-r--r--src/com/android/settings/search/SearchIndexableResources.java8
13 files changed, 1382 insertions, 1484 deletions
diff --git a/src/com/android/settings/Settings.java b/src/com/android/settings/Settings.java
index b58159e..fe0df59 100644
--- a/src/com/android/settings/Settings.java
+++ b/src/com/android/settings/Settings.java
@@ -33,6 +33,7 @@ public class Settings extends SettingsActivity {
public static class VpnSettingsActivity extends SettingsActivity { /* empty */ }
public static class DateTimeSettingsActivity extends SettingsActivity { /* empty */ }
public static class StorageSettingsActivity extends SettingsActivity { /* empty */ }
+ public static class StorageVolumeSettingsActivity extends SettingsActivity { /* empty */ }
public static class WifiSettingsActivity extends SettingsActivity { /* empty */ }
public static class WifiP2pSettingsActivity extends SettingsActivity { /* empty */ }
public static class InputMethodAndLanguageSettingsActivity extends SettingsActivity { /* empty */ }
diff --git a/src/com/android/settings/SettingsActivity.java b/src/com/android/settings/SettingsActivity.java
index 24209b0..7bfd249 100644
--- a/src/com/android/settings/SettingsActivity.java
+++ b/src/com/android/settings/SettingsActivity.java
@@ -82,7 +82,8 @@ import com.android.settings.dashboard.DashboardSummary;
import com.android.settings.dashboard.DashboardTile;
import com.android.settings.dashboard.NoHomeDialogFragment;
import com.android.settings.dashboard.SearchResultsSummary;
-import com.android.settings.deviceinfo.Memory;
+import com.android.settings.deviceinfo.PublicVolumeSettings;
+import com.android.settings.deviceinfo.StorageSettings;
import com.android.settings.deviceinfo.UsbSettings;
import com.android.settings.fuelgauge.BatterySaverSettings;
import com.android.settings.fuelgauge.PowerUsageSummary;
@@ -305,7 +306,8 @@ public class SettingsActivity extends Activity
CaptionPropertiesFragment.class.getName(),
com.android.settings.accessibility.ToggleDaltonizerPreferenceFragment.class.getName(),
TextToSpeechSettings.class.getName(),
- Memory.class.getName(),
+ StorageSettings.class.getName(),
+ PublicVolumeSettings.class.getName(),
DevelopmentSettings.class.getName(),
UsbSettings.class.getName(),
AndroidBeam.class.getName(),
diff --git a/src/com/android/settings/deviceinfo/Memory.java b/src/com/android/settings/deviceinfo/Memory.java
deleted file mode 100644
index a07f7c2..0000000
--- a/src/com/android/settings/deviceinfo/Memory.java
+++ /dev/null
@@ -1,509 +0,0 @@
-/*
- * Copyright (C) 2008 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.app.AlertDialog;
-import android.app.Dialog;
-import android.app.DialogFragment;
-import android.content.ActivityNotFoundException;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.IPackageDataObserver;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.hardware.usb.UsbManager;
-import android.os.Bundle;
-import android.os.Environment;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.os.UserManager;
-import android.os.storage.IMountService;
-import android.os.storage.StorageEventListener;
-import android.os.storage.StorageManager;
-import android.os.storage.StorageVolume;
-import android.preference.Preference;
-import android.preference.PreferenceScreen;
-import android.util.Log;
-import android.view.Menu;
-import android.view.MenuInflater;
-import android.view.MenuItem;
-import android.widget.Toast;
-
-import com.android.internal.logging.MetricsLogger;
-import com.android.settings.R;
-import com.android.settings.SettingsActivity;
-import com.android.settings.SettingsPreferenceFragment;
-import com.android.settings.Utils;
-import com.android.settings.search.BaseSearchIndexProvider;
-import com.android.settings.search.Indexable;
-import com.android.settings.search.SearchIndexableRaw;
-import com.google.android.collect.Lists;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Panel showing storage usage on disk for known {@link StorageVolume} returned
- * by {@link StorageManager}. Calculates and displays usage of data types.
- */
-public class Memory extends SettingsPreferenceFragment implements Indexable {
- private static final String TAG = "MemorySettings";
-
- private static final String TAG_CONFIRM_CLEAR_CACHE = "confirmClearCache";
-
- private static final int DLG_CONFIRM_UNMOUNT = 1;
- private static final int DLG_ERROR_UNMOUNT = 2;
-
- // The mountToggle Preference that has last been clicked.
- // Assumes no two successive unmount event on 2 different volumes are performed before the first
- // one's preference is disabled
- private static Preference sLastClickedMountToggle;
- private static String sClickedMountPoint;
-
- // Access using getMountService()
- private IMountService mMountService;
- private StorageManager mStorageManager;
- private UsbManager mUsbManager;
-
- private ArrayList<StorageVolumePreferenceCategory> mCategories = Lists.newArrayList();
-
- @Override
- protected int getMetricsCategory() {
- return MetricsLogger.DEVICEINFO_MEMORY;
- }
-
- @Override
- public void onCreate(Bundle icicle) {
- super.onCreate(icicle);
-
- final Context context = getActivity();
-
- mUsbManager = (UsbManager) getSystemService(Context.USB_SERVICE);
-
- mStorageManager = StorageManager.from(context);
- mStorageManager.registerListener(mStorageListener);
-
- addPreferencesFromResource(R.xml.device_info_memory);
-
- addCategory(StorageVolumePreferenceCategory.buildForInternal(context));
-
- final StorageVolume[] storageVolumes = mStorageManager.getVolumeList();
- for (StorageVolume volume : storageVolumes) {
- if (!volume.isEmulated()) {
- addCategory(StorageVolumePreferenceCategory.buildForPhysical(context, volume));
- }
- }
-
- setHasOptionsMenu(true);
- }
-
- private void addCategory(StorageVolumePreferenceCategory category) {
- mCategories.add(category);
- getPreferenceScreen().addPreference(category);
- category.init();
- }
-
- private boolean isMassStorageEnabled() {
- // Mass storage is enabled if primary volume supports it
- final StorageVolume[] volumes = mStorageManager.getVolumeList();
- final StorageVolume primary = StorageManager.getPrimaryVolume(volumes);
- return primary != null && primary.allowMassStorage();
- }
-
- @Override
- public void onResume() {
- super.onResume();
- IntentFilter intentFilter = new IntentFilter(Intent.ACTION_MEDIA_SCANNER_STARTED);
- intentFilter.addAction(Intent.ACTION_MEDIA_SCANNER_FINISHED);
- intentFilter.addDataScheme("file");
- getActivity().registerReceiver(mMediaScannerReceiver, intentFilter);
-
- intentFilter = new IntentFilter();
- intentFilter.addAction(UsbManager.ACTION_USB_STATE);
- getActivity().registerReceiver(mMediaScannerReceiver, intentFilter);
-
- for (StorageVolumePreferenceCategory category : mCategories) {
- category.onResume();
- }
- }
-
- StorageEventListener mStorageListener = new StorageEventListener() {
- @Override
- public void onStorageStateChanged(String path, String oldState, String newState) {
- Log.i(TAG, "Received storage state changed notification that " + path +
- " changed state from " + oldState + " to " + newState);
- for (StorageVolumePreferenceCategory category : mCategories) {
- final StorageVolume volume = category.getStorageVolume();
- if (volume != null && path.equals(volume.getPath())) {
- category.onStorageStateChanged();
- break;
- }
- }
- }
- };
-
- @Override
- public void onPause() {
- super.onPause();
- getActivity().unregisterReceiver(mMediaScannerReceiver);
- for (StorageVolumePreferenceCategory category : mCategories) {
- category.onPause();
- }
- }
-
- @Override
- public void onDestroy() {
- if (mStorageManager != null && mStorageListener != null) {
- mStorageManager.unregisterListener(mStorageListener);
- }
- super.onDestroy();
- }
-
- @Override
- public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
- inflater.inflate(R.menu.storage, menu);
- }
-
- @Override
- public void onPrepareOptionsMenu(Menu menu) {
- final MenuItem usb = menu.findItem(R.id.storage_usb);
- UserManager um = (UserManager)getActivity().getSystemService(Context.USER_SERVICE);
- boolean usbItemVisible = !isMassStorageEnabled()
- && !um.hasUserRestriction(UserManager.DISALLOW_USB_FILE_TRANSFER);
- usb.setVisible(usbItemVisible);
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case R.id.storage_usb:
- if (getActivity() instanceof SettingsActivity) {
- ((SettingsActivity) getActivity()).startPreferencePanel(
- UsbSettings.class.getCanonicalName(),
- null, R.string.storage_title_usb, null, this, 0);
- } else {
- startFragment(this, UsbSettings.class.getCanonicalName(),
- R.string.storage_title_usb, -1, null);
- }
- return true;
- }
- return super.onOptionsItemSelected(item);
- }
-
- private synchronized IMountService getMountService() {
- if (mMountService == null) {
- IBinder service = ServiceManager.getService("mount");
- if (service != null) {
- mMountService = IMountService.Stub.asInterface(service);
- } else {
- Log.e(TAG, "Can't get mount service");
- }
- }
- return mMountService;
- }
-
- @Override
- public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
- if (StorageVolumePreferenceCategory.KEY_CACHE.equals(preference.getKey())) {
- ConfirmClearCacheFragment.show(this);
- return true;
- }
-
- for (StorageVolumePreferenceCategory category : mCategories) {
- Intent intent = category.intentForClick(preference);
- if (intent != null) {
- // Don't go across app boundary if monkey is running
- if (!Utils.isMonkeyRunning()) {
- try {
- startActivity(intent);
- } catch (ActivityNotFoundException anfe) {
- Log.w(TAG, "No activity found for intent " + intent);
- }
- }
- return true;
- }
-
- final StorageVolume volume = category.getStorageVolume();
- if (volume != null && category.mountToggleClicked(preference)) {
- sLastClickedMountToggle = preference;
- sClickedMountPoint = volume.getPath();
- String state = mStorageManager.getVolumeState(volume.getPath());
- if (Environment.MEDIA_MOUNTED.equals(state) ||
- Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
- unmount();
- } else {
- mount();
- }
- return true;
- }
- }
-
- return false;
- }
-
- private final BroadcastReceiver mMediaScannerReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
- if (action.equals(UsbManager.ACTION_USB_STATE)) {
- boolean isUsbConnected = intent.getBooleanExtra(UsbManager.USB_CONNECTED, false);
- String usbFunction = mUsbManager.getDefaultFunction();
- for (StorageVolumePreferenceCategory category : mCategories) {
- category.onUsbStateChanged(isUsbConnected, usbFunction);
- }
- } else if (action.equals(Intent.ACTION_MEDIA_SCANNER_FINISHED)) {
- for (StorageVolumePreferenceCategory category : mCategories) {
- category.onMediaScannerFinished();
- }
- }
- }
- };
-
- @Override
- public Dialog onCreateDialog(int id) {
- switch (id) {
- case DLG_CONFIRM_UNMOUNT:
- return new AlertDialog.Builder(getActivity())
- .setTitle(R.string.dlg_confirm_unmount_title)
- .setPositiveButton(R.string.dlg_ok, new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- doUnmount();
- }})
- .setNegativeButton(R.string.cancel, null)
- .setMessage(R.string.dlg_confirm_unmount_text)
- .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)
- .create();
- }
- return null;
- }
-
- private void doUnmount() {
- // Present a toast here
- Toast.makeText(getActivity(), R.string.unmount_inform_text, Toast.LENGTH_SHORT).show();
- IMountService mountService = getMountService();
- try {
- sLastClickedMountToggle.setEnabled(false);
- sLastClickedMountToggle.setTitle(getString(R.string.sd_ejecting_title));
- sLastClickedMountToggle.setSummary(getString(R.string.sd_ejecting_summary));
- mountService.unmountVolume(sClickedMountPoint, true, false);
- } catch (RemoteException e) {
- // Informative dialog to user that unmount failed.
- showDialogInner(DLG_ERROR_UNMOUNT);
- }
- }
-
- private void showDialogInner(int id) {
- removeDialog(id);
- showDialog(id);
- }
-
- private boolean hasAppsAccessingStorage() throws RemoteException {
- IMountService mountService = getMountService();
- int stUsers[] = mountService.getStorageUsers(sClickedMountPoint);
- if (stUsers != null && stUsers.length > 0) {
- return true;
- }
- // TODO FIXME Parameterize with mountPoint and uncomment.
- // On HC-MR2, no apps can be installed on sd and the emulated internal storage is not
- // removable: application cannot interfere with unmount
- /*
- ActivityManager am = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE);
- List<ApplicationInfo> list = am.getRunningExternalApplications();
- if (list != null && list.size() > 0) {
- return true;
- }
- */
- // Better safe than sorry. Assume the storage is used to ask for confirmation.
- return true;
- }
-
- private void unmount() {
- // Check if external media is in use.
- try {
- if (hasAppsAccessingStorage()) {
- // Present dialog to user
- showDialogInner(DLG_CONFIRM_UNMOUNT);
- } else {
- doUnmount();
- }
- } catch (RemoteException e) {
- // Very unlikely. But present an error dialog anyway
- Log.e(TAG, "Is MountService running?");
- showDialogInner(DLG_ERROR_UNMOUNT);
- }
- }
-
- private void mount() {
- IMountService mountService = getMountService();
- try {
- if (mountService != null) {
- mountService.mountVolume(sClickedMountPoint);
- } else {
- Log.e(TAG, "Mount service is null, can't mount");
- }
- } catch (RemoteException ex) {
- // Not much can be done
- }
- }
-
- private void onCacheCleared() {
- for (StorageVolumePreferenceCategory category : mCategories) {
- category.onCacheCleared();
- }
- }
-
- private static class ClearCacheObserver extends IPackageDataObserver.Stub {
- private final Memory mTarget;
- private int mRemaining;
-
- public ClearCacheObserver(Memory target, int remaining) {
- mTarget = target;
- mRemaining = remaining;
- }
-
- @Override
- public void onRemoveCompleted(final String packageName, final boolean succeeded) {
- synchronized (this) {
- if (--mRemaining == 0) {
- mTarget.onCacheCleared();
- }
- }
- }
- }
-
- /**
- * Dialog to request user confirmation before clearing all cache data.
- */
- public static class ConfirmClearCacheFragment extends DialogFragment {
- public static void show(Memory parent) {
- if (!parent.isAdded()) return;
-
- final ConfirmClearCacheFragment dialog = new ConfirmClearCacheFragment();
- dialog.setTargetFragment(parent, 0);
- dialog.show(parent.getFragmentManager(), TAG_CONFIRM_CLEAR_CACHE);
- }
-
- @Override
- public Dialog onCreateDialog(Bundle savedInstanceState) {
- final Context context = getActivity();
-
- final AlertDialog.Builder builder = new AlertDialog.Builder(context);
- builder.setTitle(R.string.memory_clear_cache_title);
- builder.setMessage(getString(R.string.memory_clear_cache_message));
-
- builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- final Memory target = (Memory) getTargetFragment();
- final PackageManager pm = context.getPackageManager();
- final List<PackageInfo> infos = pm.getInstalledPackages(0);
- final ClearCacheObserver observer = new ClearCacheObserver(
- target, infos.size());
- for (PackageInfo info : infos) {
- pm.deleteApplicationCacheFiles(info.packageName, observer);
- }
- }
- });
- builder.setNegativeButton(android.R.string.cancel, null);
-
- return builder.create();
- }
- }
-
- /**
- * Enable indexing of searchable data
- */
- public static final SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
- new BaseSearchIndexProvider() {
- @Override
- public List<SearchIndexableRaw> getRawDataToIndex(Context context, boolean enabled) {
- final List<SearchIndexableRaw> result = new ArrayList<SearchIndexableRaw>();
-
- SearchIndexableRaw data = new SearchIndexableRaw(context);
- data.title = context.getString(R.string.storage_settings);
- data.screenTitle = context.getString(R.string.storage_settings);
- result.add(data);
-
- data = new SearchIndexableRaw(context);
- data.title = context.getString(R.string.internal_storage);
- data.screenTitle = context.getString(R.string.storage_settings);
- result.add(data);
-
- data = new SearchIndexableRaw(context);
- final StorageVolume[] storageVolumes = StorageManager.from(context).getVolumeList();
- for (StorageVolume volume : storageVolumes) {
- if (!volume.isEmulated()) {
- data.title = volume.getDescription(context);
- data.screenTitle = context.getString(R.string.storage_settings);
- result.add(data);
- }
- }
-
- data = new SearchIndexableRaw(context);
- data.title = context.getString(R.string.memory_size);
- data.screenTitle = context.getString(R.string.storage_settings);
- result.add(data);
-
- data = new SearchIndexableRaw(context);
- data.title = context.getString(R.string.memory_available);
- data.screenTitle = context.getString(R.string.storage_settings);
- result.add(data);
-
- data = new SearchIndexableRaw(context);
- data.title = context.getString(R.string.memory_apps_usage);
- data.screenTitle = context.getString(R.string.storage_settings);
- result.add(data);
-
- data = new SearchIndexableRaw(context);
- data.title = context.getString(R.string.memory_dcim_usage);
- data.screenTitle = context.getString(R.string.storage_settings);
- result.add(data);
-
- data = new SearchIndexableRaw(context);
- data.title = context.getString(R.string.memory_music_usage);
- data.screenTitle = context.getString(R.string.storage_settings);
- result.add(data);
-
- data = new SearchIndexableRaw(context);
- data.title = context.getString(R.string.memory_downloads_usage);
- data.screenTitle = context.getString(R.string.storage_settings);
- result.add(data);
-
- data = new SearchIndexableRaw(context);
- data.title = context.getString(R.string.memory_media_cache_usage);
- data.screenTitle = context.getString(R.string.storage_settings);
- result.add(data);
-
- data = new SearchIndexableRaw(context);
- data.title = context.getString(R.string.memory_media_misc_usage);
- data.screenTitle = context.getString(R.string.storage_settings);
- result.add(data);
-
- return result;
- }
- };
-
-}
diff --git a/src/com/android/settings/deviceinfo/MiscFilesHandler.java b/src/com/android/settings/deviceinfo/MiscFilesHandler.java
deleted file mode 100644
index 93e352b..0000000
--- a/src/com/android/settings/deviceinfo/MiscFilesHandler.java
+++ /dev/null
@@ -1,286 +0,0 @@
-/*
- * 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.app.Activity;
-import android.app.ListActivity;
-import android.content.Context;
-import android.os.Bundle;
-import android.os.storage.StorageVolume;
-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 com.android.settings.R;
-import com.android.settings.deviceinfo.StorageMeasurement.FileInfo;
-
-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 mNumSelectedFormat;
- private String mNumBytesSelectedFormat;
- private MemoryMearurementAdapter mAdapter;
- private LayoutInflater mInflater;
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setFinishOnTouchOutside(true);
- setTitle(R.string.misc_files);
- mNumSelectedFormat = getString(R.string.misc_files_selected_count);
- mNumBytesSelectedFormat = getString(R.string.misc_files_selected_count_bytes);
- 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 (StorageMeasurement.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) {
- String[] children = dir.list();
- if (children != null) {
- 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) {
- // This block intentionally left blank
- }
-
- public void onItemCheckedStateChanged(ActionMode mode, int position, long id,
- boolean checked) {
- ListView lv = getListView();
- int numChecked = lv.getCheckedItemCount();
- mode.setTitle(String.format(mNumSelectedFormat, numChecked, 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(String.format(mNumBytesSelectedFormat,
- Formatter.formatFileSize(mContext, selectedDataSize),
- Formatter.formatFileSize(mContext, mAdapter.getDataSize())));
- }
- }
-
- class MemoryMearurementAdapter extends BaseAdapter {
- private ArrayList<StorageMeasurement.FileInfo> mData = null;
- private long mDataSize = 0;
- private Context mContext;
-
- public MemoryMearurementAdapter(Activity activity) {
- mContext = activity;
- final StorageVolume storageVolume = activity.getIntent().getParcelableExtra(
- StorageVolume.EXTRA_STORAGE_VOLUME);
- StorageMeasurement mMeasurement = StorageMeasurement.getInstance(
- activity, storageVolume);
- if (mMeasurement == null) return;
- mData = (ArrayList<StorageMeasurement.FileInfo>) mMeasurement.mFileInfoForMisc;
- if (mData != null) {
- for (StorageMeasurement.FileInfo info : mData) {
- mDataSize += info.mSize;
- }
- }
- }
-
- @Override
- public int getCount() {
- return (mData == null) ? 0 : mData.size();
- }
-
- @Override
- public StorageMeasurement.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 -= ((StorageMeasurement.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;
- }
- }
-}
diff --git a/src/com/android/settings/deviceinfo/PrivateVolumeSettings.java b/src/com/android/settings/deviceinfo/PrivateVolumeSettings.java
new file mode 100644
index 0000000..efb9a07
--- /dev/null
+++ b/src/com/android/settings/deviceinfo/PrivateVolumeSettings.java
@@ -0,0 +1,548 @@
+/*
+ * Copyright (C) 2015 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 static com.android.settings.deviceinfo.StorageSettings.EXTRA_VOLUME_ID;
+import static com.android.settings.deviceinfo.StorageSettings.TAG;
+
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.app.DialogFragment;
+import android.app.DownloadManager;
+import android.content.ActivityNotFoundException;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.pm.IPackageDataObserver;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.UserInfo;
+import android.os.Bundle;
+import android.os.Environment;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.os.storage.StorageEventListener;
+import android.os.storage.StorageManager;
+import android.os.storage.VolumeInfo;
+import android.preference.Preference;
+import android.preference.PreferenceScreen;
+import android.provider.MediaStore;
+import android.text.TextUtils;
+import android.text.format.Formatter;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.widget.EditText;
+
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.util.Preconditions;
+import com.android.settings.R;
+import com.android.settings.Settings;
+import com.android.settings.SettingsPreferenceFragment;
+import com.android.settings.deviceinfo.StorageMeasurement.MeasurementDetails;
+import com.android.settings.deviceinfo.StorageMeasurement.MeasurementReceiver;
+import com.android.settings.deviceinfo.StorageSettings.FormatTask;
+import com.android.settings.deviceinfo.StorageSettings.MountTask;
+import com.android.settings.deviceinfo.StorageSettings.UnmountTask;
+import com.google.android.collect.Lists;
+
+import java.io.File;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Panel showing summary and actions for a {@link VolumeInfo#TYPE_PRIVATE}
+ * storage volume.
+ */
+public class PrivateVolumeSettings extends SettingsPreferenceFragment {
+ // TODO: disable unmount when providing over MTP/PTP
+
+ private static final String TAG_RENAME = "rename";
+ private static final String TAG_CONFIRM_CLEAR_CACHE = "confirmClearCache";
+
+ private StorageManager mStorageManager;
+ private UserManager mUserManager;
+
+ private VolumeInfo mVolume;
+ private VolumeInfo mSharedVolume;
+
+ private StorageMeasurement mMeasure;
+
+ private UserInfo mCurrentUser;
+
+ private int mNextOrder = 0;
+
+ private UsageBarPreference mGraph;
+ private StorageItemPreference mTotal;
+ private StorageItemPreference mAvailable;
+ private StorageItemPreference mApps;
+ private StorageItemPreference mDcim;
+ private StorageItemPreference mMusic;
+ private StorageItemPreference mDownloads;
+ private StorageItemPreference mCache;
+ private StorageItemPreference mMisc;
+ private List<StorageItemPreference> mUsers = Lists.newArrayList();
+
+ private long mTotalSize;
+ private long mAvailSize;
+
+ @Override
+ protected int getMetricsCategory() {
+ return MetricsLogger.DEVICEINFO_STORAGE;
+ }
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ final Context context = getActivity();
+
+ mUserManager = context.getSystemService(UserManager.class);
+ mStorageManager = context.getSystemService(StorageManager.class);
+
+ final String volId = getArguments().getString(EXTRA_VOLUME_ID);
+ mVolume = Preconditions.checkNotNull(mStorageManager.findVolumeById(volId));
+ Preconditions.checkState(mVolume.type == VolumeInfo.TYPE_PRIVATE);
+
+ addPreferencesFromResource(R.xml.device_info_storage_volume);
+
+ // Find the emulated shared storage layered above this private volume
+ mSharedVolume = mStorageManager.findVolumeById(
+ mVolume.id.replace("private", "emulated"));
+
+ mMeasure = new StorageMeasurement(context, mVolume, mSharedVolume);
+ mMeasure.setReceiver(mReceiver);
+
+ mGraph = buildGraph();
+ mTotal = buildItem(R.string.memory_size, 0);
+ mAvailable = buildItem(R.string.memory_available, R.color.memory_avail);
+
+ mApps = buildItem(R.string.memory_apps_usage, R.color.memory_apps_usage);
+ mDcim = buildItem(R.string.memory_dcim_usage, R.color.memory_dcim);
+ mMusic = buildItem(R.string.memory_music_usage, R.color.memory_music);
+ mDownloads = buildItem(R.string.memory_downloads_usage, R.color.memory_downloads);
+ mCache = buildItem(R.string.memory_media_cache_usage, R.color.memory_cache);
+ mMisc = buildItem(R.string.memory_media_misc_usage, R.color.memory_misc);
+
+ mCurrentUser = mUserManager.getUserInfo(UserHandle.myUserId());
+ final List<UserInfo> otherUsers = getUsersExcluding(mCurrentUser);
+ for (int i = 0; i < otherUsers.size(); i++) {
+ final UserInfo user = otherUsers.get(i);
+ final int colorRes = i % 2 == 0 ? R.color.memory_user_light
+ : R.color.memory_user_dark;
+ final StorageItemPreference userPref = new StorageItemPreference(
+ context, user.name, colorRes, user.id);
+ mUsers.add(userPref);
+ }
+
+ setHasOptionsMenu(true);
+ }
+
+ public void refresh() {
+ getActivity().setTitle(mStorageManager.getBestVolumeDescription(mVolume.id));
+
+ // Valid options may have changed
+ getFragmentManager().invalidateOptionsMenu();
+
+ final Context context = getActivity();
+ final PreferenceScreen screen = getPreferenceScreen();
+
+ screen.removeAll();
+
+ if (mVolume.state != VolumeInfo.STATE_MOUNTED) {
+ return;
+ }
+
+ screen.addPreference(mGraph);
+ screen.addPreference(mTotal);
+ screen.addPreference(mAvailable);
+
+ final boolean showUsers = !mUsers.isEmpty();
+ if (showUsers) {
+ screen.addPreference(new PreferenceHeader(context, mCurrentUser.name));
+ }
+
+ screen.addPreference(mApps);
+ screen.addPreference(mDcim);
+ screen.addPreference(mMusic);
+ screen.addPreference(mDownloads);
+ screen.addPreference(mCache);
+ screen.addPreference(mMisc);
+
+ if (showUsers) {
+ screen.addPreference(new PreferenceHeader(context, R.string.storage_other_users));
+ for (Preference pref : mUsers) {
+ screen.addPreference(pref);
+ }
+ }
+
+ for (int i = 0; i < screen.getPreferenceCount(); i++) {
+ final Preference pref = screen.getPreference(i);
+ if (pref instanceof StorageItemPreference) {
+ ((StorageItemPreference) pref).setLoading();
+ }
+ }
+
+ final File file = new File(mVolume.path);
+ mTotalSize = file.getTotalSpace();
+ mAvailSize = file.getFreeSpace();
+
+ mTotal.setSummary(Formatter.formatFileSize(context, mTotalSize));
+ mAvailable.setSummary(Formatter.formatFileSize(context, mAvailSize));
+
+ mGraph.clear();
+ mGraph.addEntry(0, (mTotalSize - mAvailSize) / (float) mTotalSize,
+ android.graphics.Color.GRAY);
+ mGraph.commit();
+
+ mMeasure.forceMeasure();
+ }
+
+ private UsageBarPreference buildGraph() {
+ final UsageBarPreference pref = new UsageBarPreference(getActivity());
+ pref.setOrder(mNextOrder++);
+ return pref;
+ }
+
+ private StorageItemPreference buildItem(int titleRes, int colorRes) {
+ final StorageItemPreference pref = new StorageItemPreference(getActivity(), titleRes,
+ colorRes);
+ pref.setOrder(mNextOrder++);
+ return pref;
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ mStorageManager.registerListener(mStorageListener);
+ refresh();
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ mStorageManager.unregisterListener(mStorageListener);
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ mMeasure.onDestroy();
+ }
+
+ @Override
+ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+ inflater.inflate(R.menu.storage_volume, menu);
+ }
+
+ @Override
+ public void onPrepareOptionsMenu(Menu menu) {
+ final MenuItem rename = menu.findItem(R.id.storage_rename);
+ final MenuItem mount = menu.findItem(R.id.storage_mount);
+ final MenuItem unmount = menu.findItem(R.id.storage_unmount);
+ final MenuItem format = menu.findItem(R.id.storage_format);
+ final MenuItem usb = menu.findItem(R.id.storage_usb);
+
+ // Actions live in menu for non-internal private volumes; they're shown
+ // as preference items for public volumes.
+ if (VolumeInfo.ID_PRIVATE_INTERNAL.equals(mVolume.id)) {
+ rename.setVisible(false);
+ mount.setVisible(false);
+ unmount.setVisible(false);
+ format.setVisible(false);
+ } else {
+ rename.setVisible(mVolume.type == VolumeInfo.TYPE_PRIVATE);
+ mount.setVisible(mVolume.state == VolumeInfo.STATE_UNMOUNTED);
+ unmount.setVisible(mVolume.state == VolumeInfo.STATE_MOUNTED);
+ format.setVisible(true);
+ }
+
+ // TODO: show usb if we jumped past first screen
+ usb.setVisible(false);
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ final Context context = getActivity();
+ switch (item.getItemId()) {
+ case R.id.storage_rename:
+ RenameFragment.show(this);
+ return true;
+ case R.id.storage_mount:
+ new MountTask(context, mVolume.id).execute();
+ return true;
+ case R.id.storage_unmount:
+ new UnmountTask(context, mVolume.id).execute();
+ return true;
+ case R.id.storage_format:
+ new FormatTask(context, mVolume.id).execute();
+ return true;
+ case R.id.storage_usb:
+ startFragment(this, UsbSettings.class.getCanonicalName(),
+ R.string.storage_title_usb, 0, null);
+ return true;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+ @Override
+ public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference pref) {
+ // TODO: launch better intents for specific volume
+
+ Intent intent = null;
+ if (pref == mApps) {
+ intent = new Intent(Intent.ACTION_MANAGE_PACKAGE_STORAGE);
+ intent.setClass(getActivity(), Settings.ManageApplicationsActivity.class);
+
+ } else if (pref == mDownloads) {
+ intent = new Intent(DownloadManager.ACTION_VIEW_DOWNLOADS).putExtra(
+ DownloadManager.INTENT_EXTRAS_SORT_BY_SIZE, true);
+
+ } else if (pref == mMusic) {
+ intent = new Intent(Intent.ACTION_GET_CONTENT);
+ intent.setType("audio/mp3");
+
+ } else if (pref == mDcim) {
+ intent = new Intent(Intent.ACTION_VIEW);
+ intent.putExtra(Intent.EXTRA_LOCAL_ONLY, true);
+ intent.setData(MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
+
+ } else if (pref == mCache) {
+ ConfirmClearCacheFragment.show(this);
+ return true;
+
+ } else if (pref == mMisc) {
+ intent = StorageSettings.buildBrowseIntent(mSharedVolume);
+ }
+
+ if (intent != null) {
+ try {
+ startActivity(intent);
+ } catch (ActivityNotFoundException e) {
+ Log.w(TAG, "No activity found for " + intent);
+ }
+ return true;
+ }
+ return super.onPreferenceTreeClick(preferenceScreen, pref);
+ }
+
+ private final MeasurementReceiver mReceiver = new MeasurementReceiver() {
+ @Override
+ public void onDetailsChanged(MeasurementDetails details) {
+ updateDetails(details);
+ }
+ };
+
+ private void updateDetails(MeasurementDetails details) {
+ mGraph.clear();
+
+ updatePreference(mApps, details.appsSize);
+
+ final long dcimSize = totalValues(details.mediaSize, Environment.DIRECTORY_DCIM,
+ Environment.DIRECTORY_MOVIES, Environment.DIRECTORY_PICTURES);
+ updatePreference(mDcim, dcimSize);
+
+ final long musicSize = totalValues(details.mediaSize, Environment.DIRECTORY_MUSIC,
+ Environment.DIRECTORY_ALARMS, Environment.DIRECTORY_NOTIFICATIONS,
+ Environment.DIRECTORY_RINGTONES, Environment.DIRECTORY_PODCASTS);
+ updatePreference(mMusic, musicSize);
+
+ final long downloadsSize = totalValues(details.mediaSize, Environment.DIRECTORY_DOWNLOADS);
+ updatePreference(mDownloads, downloadsSize);
+
+ updatePreference(mCache, details.cacheSize);
+ updatePreference(mMisc, details.miscSize);
+
+ for (StorageItemPreference userPref : mUsers) {
+ final long userSize = details.usersSize.get(userPref.userHandle);
+ updatePreference(userPref, userSize);
+ }
+
+ mGraph.commit();
+ }
+
+ private void updatePreference(StorageItemPreference pref, long size) {
+ pref.setSummary(Formatter.formatFileSize(getActivity(), size));
+ if (size > 0) {
+ final int order = pref.getOrder();
+ mGraph.addEntry(order, size / (float) mTotalSize, pref.color);
+ }
+ }
+
+ /**
+ * Return list of other users, excluding the current user.
+ */
+ private List<UserInfo> getUsersExcluding(UserInfo excluding) {
+ final List<UserInfo> users = mUserManager.getUsers();
+ final Iterator<UserInfo> i = users.iterator();
+ while (i.hasNext()) {
+ if (i.next().id == excluding.id) {
+ i.remove();
+ }
+ }
+ return users;
+ }
+
+ private static long totalValues(HashMap<String, Long> map, String... keys) {
+ long total = 0;
+ for (String key : keys) {
+ if (map.containsKey(key)) {
+ total += map.get(key);
+ }
+ }
+ return total;
+ }
+
+ private final StorageEventListener mStorageListener = new StorageEventListener() {
+ @Override
+ public void onVolumeStateChanged(VolumeInfo vol, int oldState, int newState) {
+ if (Objects.equals(mVolume.id, vol.id)) {
+ mVolume = vol;
+ refresh();
+ }
+ }
+ };
+
+ /**
+ * Dialog that allows editing of volume nickname.
+ */
+ public static class RenameFragment extends DialogFragment {
+ public static void show(PrivateVolumeSettings parent) {
+ if (!parent.isAdded()) return;
+
+ final RenameFragment dialog = new RenameFragment();
+ dialog.setTargetFragment(parent, 0);
+ dialog.setArguments(parent.getArguments());
+ dialog.show(parent.getFragmentManager(), TAG_RENAME);
+ }
+
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ final Context context = getActivity();
+ final StorageManager storageManager = context.getSystemService(StorageManager.class);
+
+ final String volId = getArguments().getString(EXTRA_VOLUME_ID);
+ final VolumeInfo vol = storageManager.findVolumeById(volId);
+
+ final AlertDialog.Builder builder = new AlertDialog.Builder(context);
+ final LayoutInflater dialogInflater = LayoutInflater.from(builder.getContext());
+
+ final View view = dialogInflater.inflate(R.layout.dialog_edittext, null, false);
+ final EditText nickname = (EditText) view.findViewById(R.id.edittext);
+
+ if (!TextUtils.isEmpty(vol.nickname)) {
+ nickname.setText(vol.nickname);
+ } else {
+ nickname.setText(storageManager.getBestVolumeDescription(volId));
+ }
+
+ builder.setTitle(R.string.storage_rename_title);
+ builder.setView(view);
+
+ builder.setPositiveButton(R.string.save,
+ new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ // TODO: persist the edited nickname!
+ }
+ });
+ builder.setNegativeButton(R.string.cancel, null);
+
+ return builder.create();
+ }
+ }
+
+ /**
+ * Dialog to request user confirmation before clearing all cache data.
+ */
+ public static class ConfirmClearCacheFragment extends DialogFragment {
+ public static void show(PrivateVolumeSettings parent) {
+ if (!parent.isAdded()) return;
+
+ final ConfirmClearCacheFragment dialog = new ConfirmClearCacheFragment();
+ dialog.setTargetFragment(parent, 0);
+ dialog.show(parent.getFragmentManager(), TAG_CONFIRM_CLEAR_CACHE);
+ }
+
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ final Context context = getActivity();
+
+ final AlertDialog.Builder builder = new AlertDialog.Builder(context);
+ builder.setTitle(R.string.memory_clear_cache_title);
+ builder.setMessage(getString(R.string.memory_clear_cache_message));
+
+ builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ final PrivateVolumeSettings target = (PrivateVolumeSettings) getTargetFragment();
+ final PackageManager pm = context.getPackageManager();
+ final List<PackageInfo> infos = pm.getInstalledPackages(0);
+ final ClearCacheObserver observer = new ClearCacheObserver(
+ target, infos.size());
+ for (PackageInfo info : infos) {
+ pm.deleteApplicationCacheFiles(info.packageName, observer);
+ }
+ }
+ });
+ builder.setNegativeButton(android.R.string.cancel, null);
+
+ return builder.create();
+ }
+ }
+
+ private static class ClearCacheObserver extends IPackageDataObserver.Stub {
+ private final PrivateVolumeSettings mTarget;
+ private int mRemaining;
+
+ public ClearCacheObserver(PrivateVolumeSettings target, int remaining) {
+ mTarget = target;
+ mRemaining = remaining;
+ }
+
+ @Override
+ public void onRemoveCompleted(final String packageName, final boolean succeeded) {
+ synchronized (this) {
+ if (--mRemaining == 0) {
+ mTarget.refresh();
+ }
+ }
+ }
+ }
+
+ public static class PreferenceHeader extends Preference {
+ public PreferenceHeader(Context context, int titleRes) {
+ super(context, null, com.android.internal.R.attr.preferenceCategoryStyle);
+ setTitle(titleRes);
+ }
+
+ public PreferenceHeader(Context context, CharSequence title) {
+ super(context, null, com.android.internal.R.attr.preferenceCategoryStyle);
+ setTitle(title);
+ }
+
+ @Override
+ public boolean isEnabled() {
+ return false;
+ }
+ }
+}
diff --git a/src/com/android/settings/deviceinfo/PublicVolumeSettings.java b/src/com/android/settings/deviceinfo/PublicVolumeSettings.java
new file mode 100644
index 0000000..6edfc92
--- /dev/null
+++ b/src/com/android/settings/deviceinfo/PublicVolumeSettings.java
@@ -0,0 +1,205 @@
+/*
+ * Copyright (C) 2015 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 static com.android.settings.deviceinfo.StorageSettings.EXTRA_VOLUME_ID;
+
+import android.content.Context;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.SystemProperties;
+import android.os.storage.StorageEventListener;
+import android.os.storage.StorageManager;
+import android.os.storage.VolumeInfo;
+import android.preference.Preference;
+import android.preference.PreferenceScreen;
+import android.provider.DocumentsContract;
+import android.text.format.Formatter;
+
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.util.Preconditions;
+import com.android.settings.R;
+import com.android.settings.SettingsPreferenceFragment;
+import com.android.settings.deviceinfo.StorageSettings.FormatTask;
+import com.android.settings.deviceinfo.StorageSettings.MountTask;
+import com.android.settings.deviceinfo.StorageSettings.UnmountTask;
+
+import java.io.File;
+import java.util.Objects;
+
+/**
+ * Panel showing summary and actions for a {@link VolumeInfo#TYPE_PUBLIC}
+ * storage volume.
+ */
+public class PublicVolumeSettings extends SettingsPreferenceFragment {
+ // TODO: disable unmount when providing over MTP/PTP
+
+ private static final String PREF_FORMAT_INTERNAL = "debug.format_internal";
+
+ private StorageManager mStorageManager;
+
+ private VolumeInfo mVolume;
+
+ private int mNextOrder = 0;
+
+ private UsageBarPreference mGraph;
+ private StorageItemPreference mTotal;
+ private StorageItemPreference mAvailable;
+
+ private Preference mMount;
+ private Preference mUnmount;
+ private Preference mFormat;
+ private Preference mFormatInternal;
+
+ private long mTotalSize;
+ private long mAvailSize;
+
+ @Override
+ protected int getMetricsCategory() {
+ return MetricsLogger.DEVICEINFO_STORAGE;
+ }
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ final Context context = getActivity();
+
+ mStorageManager = context.getSystemService(StorageManager.class);
+
+ if (DocumentsContract.ACTION_DOCUMENT_ROOT_SETTINGS.equals(
+ getActivity().getIntent().getAction())) {
+ final Uri rootUri = getActivity().getIntent().getData();
+ final String fsUuid = DocumentsContract.getRootId(rootUri);
+ mVolume = mStorageManager.findVolumeByUuid(fsUuid);
+ } else {
+ final String volId = getArguments().getString(EXTRA_VOLUME_ID);
+ mVolume = mStorageManager.findVolumeById(volId);
+ }
+
+ Preconditions.checkNotNull(mVolume);
+ Preconditions.checkState(mVolume.type == VolumeInfo.TYPE_PUBLIC);
+
+ addPreferencesFromResource(R.xml.device_info_storage_volume);
+
+ mGraph = buildGraph();
+ mTotal = buildItem(R.string.memory_size, 0);
+ mAvailable = buildItem(R.string.memory_available, R.color.memory_avail);
+
+ mMount = buildAction(R.string.storage_menu_mount);
+ mUnmount = buildAction(R.string.storage_menu_unmount);
+ mFormat = buildAction(R.string.storage_menu_format);
+ mFormatInternal = buildAction(R.string.storage_menu_format_internal);
+ }
+
+ public void refresh() {
+ getActivity().setTitle(mStorageManager.getBestVolumeDescription(mVolume.id));
+
+ final Context context = getActivity();
+ final PreferenceScreen screen = getPreferenceScreen();
+
+ screen.removeAll();
+
+ if (mVolume.state == VolumeInfo.STATE_MOUNTED) {
+ screen.addPreference(mGraph);
+ screen.addPreference(mTotal);
+ screen.addPreference(mAvailable);
+ }
+
+ if (mVolume.state == VolumeInfo.STATE_UNMOUNTED) {
+ screen.addPreference(mMount);
+ }
+ if (mVolume.state == VolumeInfo.STATE_MOUNTED) {
+ screen.addPreference(mUnmount);
+ }
+ screen.addPreference(mFormat);
+ if (SystemProperties.getBoolean(PREF_FORMAT_INTERNAL, false)) {
+ screen.addPreference(mFormatInternal);
+ }
+
+ final File file = new File(mVolume.path);
+ mTotalSize = file.getTotalSpace();
+ mAvailSize = file.getFreeSpace();
+
+ mTotal.setSummary(Formatter.formatFileSize(context, mTotalSize));
+ mAvailable.setSummary(Formatter.formatFileSize(context, mAvailSize));
+
+ mGraph.clear();
+ mGraph.addEntry(0, (mTotalSize - mAvailSize) / (float) mTotalSize,
+ android.graphics.Color.GRAY);
+ mGraph.commit();
+ }
+
+ private UsageBarPreference buildGraph() {
+ final UsageBarPreference pref = new UsageBarPreference(getActivity());
+ pref.setOrder(mNextOrder++);
+ return pref;
+ }
+
+ private StorageItemPreference buildItem(int titleRes, int colorRes) {
+ final StorageItemPreference pref = new StorageItemPreference(getActivity(), titleRes,
+ colorRes);
+ pref.setOrder(mNextOrder++);
+ return pref;
+ }
+
+ private Preference buildAction(int titleRes) {
+ final Preference pref = new Preference(getActivity());
+ pref.setTitle(titleRes);
+ pref.setOrder(mNextOrder++);
+ return pref;
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ mStorageManager.registerListener(mStorageListener);
+ refresh();
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ mStorageManager.unregisterListener(mStorageListener);
+ }
+
+ @Override
+ public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference pref) {
+ final Context context = getActivity();
+ if (pref == mMount) {
+ new MountTask(context, mVolume.id).execute();
+ } else if (pref == mUnmount) {
+ new UnmountTask(context, mVolume.id).execute();
+ } else if (pref == mFormat) {
+ new FormatTask(context, mVolume.id).execute();
+ } else if (pref == mFormatInternal) {
+ // TODO: implement this
+ }
+
+ return super.onPreferenceTreeClick(preferenceScreen, pref);
+ }
+
+ private final StorageEventListener mStorageListener = new StorageEventListener() {
+ @Override
+ public void onVolumeStateChanged(VolumeInfo vol, int oldState, int newState) {
+ if (Objects.equals(mVolume.id, vol.id)) {
+ mVolume = vol;
+ refresh();
+ }
+ }
+ };
+}
diff --git a/src/com/android/settings/deviceinfo/StorageItemPreference.java b/src/com/android/settings/deviceinfo/StorageItemPreference.java
index 87e827e..8d48cf0 100644
--- a/src/com/android/settings/deviceinfo/StorageItemPreference.java
+++ b/src/com/android/settings/deviceinfo/StorageItemPreference.java
@@ -62,4 +62,8 @@ public class StorageItemPreference extends Preference {
shape.getPaint().setColor(color);
return shape;
}
+
+ public void setLoading() {
+ setSummary(R.string.memory_calculating_size);
+ }
}
diff --git a/src/com/android/settings/deviceinfo/StorageMeasurement.java b/src/com/android/settings/deviceinfo/StorageMeasurement.java
index 34ef62b..db91fdb 100644
--- a/src/com/android/settings/deviceinfo/StorageMeasurement.java
+++ b/src/com/android/settings/deviceinfo/StorageMeasurement.java
@@ -27,7 +27,6 @@ import android.content.pm.PackageManager;
import android.content.pm.PackageStats;
import android.content.pm.UserInfo;
import android.os.Environment;
-import android.os.Environment.UserEnvironment;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
@@ -36,23 +35,22 @@ import android.os.Message;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.storage.StorageVolume;
+import android.os.storage.VolumeInfo;
import android.util.Log;
import android.util.SparseLongArray;
import com.android.internal.app.IMediaContainerService;
-import com.google.android.collect.Maps;
+import com.android.internal.util.ArrayUtils;
import com.google.android.collect.Sets;
import java.io.File;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.HashMap;
import java.util.List;
+import java.util.Objects;
import java.util.Set;
-import javax.annotation.concurrent.GuardedBy;
-
/**
* Utility for measuring the disk usage of internal storage or a physical
* {@link StorageVolume}. Connects with a remote {@link IMediaContainerService}
@@ -77,28 +75,7 @@ public class StorageMeasurement {
Environment.DIRECTORY_RINGTONES, Environment.DIRECTORY_PODCASTS,
Environment.DIRECTORY_DOWNLOADS, Environment.DIRECTORY_ANDROID);
- @GuardedBy("sInstances")
- private static HashMap<StorageVolume, StorageMeasurement> sInstances = Maps.newHashMap();
-
- /**
- * Obtain shared instance of {@link StorageMeasurement} for given physical
- * {@link StorageVolume}, or internal storage if {@code null}.
- */
- public static StorageMeasurement getInstance(Context context, StorageVolume volume) {
- synchronized (sInstances) {
- StorageMeasurement value = sInstances.get(volume);
- if (value == null) {
- value = new StorageMeasurement(context.getApplicationContext(), volume);
- sInstances.put(volume, value);
- }
- return value;
- }
- }
-
public static class MeasurementDetails {
- public long totalSize;
- public long availSize;
-
/**
* Total apps disk usage.
* <p>
@@ -128,7 +105,7 @@ public class StorageMeasurement {
* When measuring a physical {@link StorageVolume}, this reflects media
* on that volume.
*/
- public HashMap<String, Long> mediaSize = Maps.newHashMap();
+ public HashMap<String, Long> mediaSize = new HashMap<>();
/**
* Misc external disk usage for the current user, unaccounted in
@@ -144,34 +121,31 @@ public class StorageMeasurement {
}
public interface MeasurementReceiver {
- public void updateApproximate(StorageMeasurement meas, long totalSize, long availSize);
- public void updateDetails(StorageMeasurement meas, MeasurementDetails details);
+ public void onDetailsChanged(MeasurementDetails details);
}
- private volatile WeakReference<MeasurementReceiver> mReceiver;
-
- /** Physical volume being measured, or {@code null} for internal. */
- private final StorageVolume mVolume;
+ private WeakReference<MeasurementReceiver> mReceiver;
- private final boolean mIsInternal;
- private final boolean mIsPrimary;
+ private final Context mContext;
- private final MeasurementHandler mHandler;
+ private final VolumeInfo mVolume;
+ private final VolumeInfo mSharedVolume;
- private long mTotalSize;
- private long mAvailSize;
+ private final MainHandler mMainHandler;
+ private final MeasurementHandler mMeasurementHandler;
- List<FileInfo> mFileInfoForMisc;
+ public StorageMeasurement(Context context, VolumeInfo volume, VolumeInfo sharedVolume) {
+ mContext = context.getApplicationContext();
- private StorageMeasurement(Context context, StorageVolume volume) {
mVolume = volume;
- mIsInternal = volume == null;
- mIsPrimary = volume != null ? volume.isPrimary() : false;
+ mSharedVolume = sharedVolume;
// Start the thread that will measure the disk usage.
final HandlerThread handlerThread = new HandlerThread("MemoryMeasurement");
handlerThread.start();
- mHandler = new MeasurementHandler(context, handlerThread.getLooper());
+
+ mMainHandler = new MainHandler();
+ mMeasurementHandler = new MeasurementHandler(handlerThread.getLooper());
}
public void setReceiver(MeasurementReceiver receiver) {
@@ -180,52 +154,38 @@ public class StorageMeasurement {
}
}
+ public void forceMeasure() {
+ invalidate();
+ measure();
+ }
+
public void measure() {
- if (!mHandler.hasMessages(MeasurementHandler.MSG_MEASURE)) {
- mHandler.sendEmptyMessage(MeasurementHandler.MSG_MEASURE);
+ if (!mMeasurementHandler.hasMessages(MeasurementHandler.MSG_MEASURE)) {
+ mMeasurementHandler.sendEmptyMessage(MeasurementHandler.MSG_MEASURE);
}
}
- public void cleanUp() {
+ public void onDestroy() {
mReceiver = null;
- mHandler.removeMessages(MeasurementHandler.MSG_MEASURE);
- mHandler.sendEmptyMessage(MeasurementHandler.MSG_DISCONNECT);
- }
-
- public void invalidate() {
- mHandler.sendEmptyMessage(MeasurementHandler.MSG_INVALIDATE);
+ mMeasurementHandler.removeMessages(MeasurementHandler.MSG_MEASURE);
+ mMeasurementHandler.sendEmptyMessage(MeasurementHandler.MSG_DISCONNECT);
}
- private void sendInternalApproximateUpdate() {
- MeasurementReceiver receiver = (mReceiver != null) ? mReceiver.get() : null;
- if (receiver == null) {
- return;
- }
- receiver.updateApproximate(this, mTotalSize, mAvailSize);
- }
-
- private void sendExactUpdate(MeasurementDetails details) {
- MeasurementReceiver receiver = (mReceiver != null) ? mReceiver.get() : null;
- if (receiver == null) {
- if (LOGV) {
- Log.i(TAG, "measurements dropped because receiver is null! wasted effort");
- }
- return;
- }
- receiver.updateDetails(this, details);
+ private void invalidate() {
+ mMeasurementHandler.sendEmptyMessage(MeasurementHandler.MSG_INVALIDATE);
}
private static class StatsObserver extends IPackageStatsObserver.Stub {
- private final boolean mIsInternal;
+ private final boolean mIsPrivate;
private final MeasurementDetails mDetails;
private final int mCurrentUser;
private final Message mFinished;
private int mRemaining;
- public StatsObserver(boolean isInternal, MeasurementDetails details, int currentUser,
+ public StatsObserver(boolean isPrivate, MeasurementDetails details, int currentUser,
Message finished, int remaining) {
- mIsInternal = isInternal;
+ mIsPrivate = isPrivate;
mDetails = details;
mCurrentUser = currentUser;
mFinished = finished;
@@ -245,7 +205,7 @@ public class StorageMeasurement {
}
private void addStatsLocked(PackageStats stats) {
- if (mIsInternal) {
+ if (mIsPrivate) {
long codeSize = stats.codeSize;
long dataSize = stats.dataSize;
long cacheSize = stats.cacheSize;
@@ -279,6 +239,17 @@ public class StorageMeasurement {
}
}
+ private class MainHandler extends Handler {
+ @Override
+ public void handleMessage(Message msg) {
+ final MeasurementDetails details = (MeasurementDetails) msg.obj;
+ final MeasurementReceiver receiver = (mReceiver != null) ? mReceiver.get() : null;
+ if (receiver != null) {
+ receiver.onDetailsChanged(details);
+ }
+ }
+ }
+
private class MeasurementHandler extends Handler {
public static final int MSG_MEASURE = 1;
public static final int MSG_CONNECTED = 2;
@@ -294,8 +265,6 @@ public class StorageMeasurement {
private MeasurementDetails mCached;
- private final WeakReference<Context> mContext;
-
private final ServiceConnection mDefContainerConn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
@@ -313,9 +282,8 @@ public class StorageMeasurement {
}
};
- public MeasurementHandler(Context context, Looper looper) {
+ public MeasurementHandler(Looper looper) {
super(looper);
- mContext = new WeakReference<Context>(context);
}
@Override
@@ -323,50 +291,39 @@ public class StorageMeasurement {
switch (msg.what) {
case MSG_MEASURE: {
if (mCached != null) {
- sendExactUpdate(mCached);
+ mMainHandler.obtainMessage(0, mCached).sendToTarget();
break;
}
- final Context context = (mContext != null) ? mContext.get() : null;
- if (context == null) {
- return;
- }
-
synchronized (mLock) {
if (mBound) {
removeMessages(MSG_DISCONNECT);
sendMessage(obtainMessage(MSG_CONNECTED, mDefaultContainer));
} else {
Intent service = new Intent().setComponent(DEFAULT_CONTAINER_COMPONENT);
- context.bindServiceAsUser(service, mDefContainerConn, Context.BIND_AUTO_CREATE,
- UserHandle.OWNER);
+ mContext.bindServiceAsUser(service, mDefContainerConn,
+ Context.BIND_AUTO_CREATE, UserHandle.OWNER);
}
}
break;
}
case MSG_CONNECTED: {
- IMediaContainerService imcs = (IMediaContainerService) msg.obj;
- measureApproximateStorage(imcs);
+ final IMediaContainerService imcs = (IMediaContainerService) msg.obj;
measureExactStorage(imcs);
break;
}
case MSG_DISCONNECT: {
synchronized (mLock) {
if (mBound) {
- final Context context = (mContext != null) ? mContext.get() : null;
- if (context == null) {
- return;
- }
-
mBound = false;
- context.unbindService(mDefContainerConn);
+ mContext.unbindService(mDefContainerConn);
}
}
break;
}
case MSG_COMPLETED: {
mCached = (MeasurementDetails) msg.obj;
- sendExactUpdate(mCached);
+ mMainHandler.obtainMessage(0, mCached).sendToTarget();
break;
}
case MSG_INVALIDATE: {
@@ -375,87 +332,74 @@ public class StorageMeasurement {
}
}
}
+ }
- private void measureApproximateStorage(IMediaContainerService imcs) {
- final String path = mVolume != null ? mVolume.getPath()
- : Environment.getDataDirectory().getPath();
- try {
- final long[] stats = imcs.getFileSystemStats(path);
- mTotalSize = stats[0];
- mAvailSize = stats[1];
- } catch (Exception e) {
- Log.w(TAG, "Problem in container service", e);
- }
-
- sendInternalApproximateUpdate();
- }
-
- private void measureExactStorage(IMediaContainerService imcs) {
- final Context context = mContext != null ? mContext.get() : null;
- if (context == null) {
- return;
- }
-
- final MeasurementDetails details = new MeasurementDetails();
- final Message finished = obtainMessage(MSG_COMPLETED, details);
+ private void measureExactStorage(IMediaContainerService imcs) {
+ final UserManager userManager = mContext.getSystemService(UserManager.class);
+ final PackageManager packageManager = mContext.getPackageManager();
- details.totalSize = mTotalSize;
- details.availSize = mAvailSize;
+ final List<UserInfo> users = userManager.getUsers();
+ final int currentUser = ActivityManager.getCurrentUser();
- final UserManager userManager = (UserManager) context.getSystemService(
- Context.USER_SERVICE);
- final List<UserInfo> users = userManager.getUsers();
+ final MeasurementDetails details = new MeasurementDetails();
+ final Message finished = mMeasurementHandler.obtainMessage(MeasurementHandler.MSG_COMPLETED,
+ details);
- final int currentUser = ActivityManager.getCurrentUser();
- final UserEnvironment currentEnv = new UserEnvironment(currentUser);
+ if (mSharedVolume != null && mSharedVolume.state == VolumeInfo.STATE_MOUNTED) {
+ final File basePath = mSharedVolume.getPathForUser(currentUser);
// Measure media types for emulated storage, or for primary physical
// external volume
- final boolean measureMedia = (mIsInternal && Environment.isExternalStorageEmulated())
- || mIsPrimary;
- if (measureMedia) {
- for (String type : sMeasureMediaTypes) {
- final File path = currentEnv.getExternalStoragePublicDirectory(type);
- final long size = getDirectorySize(imcs, path);
- details.mediaSize.put(type, size);
- }
+ for (String type : sMeasureMediaTypes) {
+ final File path = new File(basePath, type);
+ final long size = getDirectorySize(imcs, path);
+ details.mediaSize.put(type, size);
}
// Measure misc files not counted under media
- if (measureMedia) {
- final File path = mIsInternal ? currentEnv.getExternalStorageDirectory()
- : mVolume.getPathFile();
- details.miscSize = measureMisc(imcs, path);
- }
+ details.miscSize = measureMisc(imcs, basePath);
- // Measure total emulated storage of all users; internal apps data
- // will be spliced in later
- for (UserInfo user : users) {
- final UserEnvironment userEnv = new UserEnvironment(user.id);
- final long size = getDirectorySize(imcs, userEnv.getExternalStorageDirectory());
- addValue(details.usersSize, user.id, size);
+ if (mSharedVolume.type == VolumeInfo.TYPE_EMULATED) {
+ // Measure total emulated storage of all users; internal apps data
+ // will be spliced in later
+ for (UserInfo user : users) {
+ final File userPath = mSharedVolume.getPathForUser(user.id);
+ final long size = getDirectorySize(imcs, userPath);
+ addValue(details.usersSize, user.id, size);
+ }
}
+ }
- // Measure all apps for all users
- final PackageManager pm = context.getPackageManager();
- if (mIsInternal || mIsPrimary) {
- final List<ApplicationInfo> apps = pm.getInstalledApplications(
- PackageManager.GET_UNINSTALLED_PACKAGES
- | PackageManager.GET_DISABLED_COMPONENTS);
-
- final int count = users.size() * apps.size();
- final StatsObserver observer = new StatsObserver(
- mIsInternal, details, currentUser, finished, count);
+ // Measure all apps hosted on this volume for all users
+ if (mVolume.type == VolumeInfo.TYPE_PRIVATE) {
+ final List<ApplicationInfo> apps = packageManager.getInstalledApplications(
+ PackageManager.GET_UNINSTALLED_PACKAGES
+ | PackageManager.GET_DISABLED_COMPONENTS);
- for (UserInfo user : users) {
- for (ApplicationInfo app : apps) {
- pm.getPackageSizeInfo(app.packageName, user.id, observer);
- }
+ final List<ApplicationInfo> volumeApps = new ArrayList<>();
+ for (ApplicationInfo app : apps) {
+ if (Objects.equals(app.volumeUuid, mVolume.fsUuid)) {
+ volumeApps.add(app);
}
+ }
- } else {
+ final int count = users.size() * volumeApps.size();
+ if (count == 0) {
finished.sendToTarget();
+ return;
+ }
+
+ final StatsObserver observer = new StatsObserver(
+ true, details, currentUser, finished, count);
+ for (UserInfo user : users) {
+ for (ApplicationInfo app : volumeApps) {
+ packageManager.getPackageSizeInfo(app.packageName, user.id, observer);
+ }
}
+
+ } else {
+ finished.sendToTarget();
+ return;
}
}
@@ -471,64 +415,26 @@ public class StorageMeasurement {
}
private long measureMisc(IMediaContainerService imcs, File dir) {
- mFileInfoForMisc = new ArrayList<FileInfo>();
-
final File[] files = dir.listFiles();
- if (files == null) return 0;
+ if (ArrayUtils.isEmpty(files)) return 0;
// Get sizes of all top level nodes except the ones already computed
- long counter = 0;
long miscSize = 0;
-
for (File file : files) {
- final String path = file.getAbsolutePath();
final String name = file.getName();
if (sMeasureMediaTypes.contains(name)) {
continue;
}
if (file.isFile()) {
- final long fileSize = file.length();
- mFileInfoForMisc.add(new FileInfo(path, fileSize, counter++));
- miscSize += fileSize;
+ miscSize += file.length();
} else if (file.isDirectory()) {
- final long dirSize = getDirectorySize(imcs, file);
- mFileInfoForMisc.add(new FileInfo(path, dirSize, counter++));
- miscSize += dirSize;
- } else {
- // Non directory, non file: not listed
+ miscSize += getDirectorySize(imcs, file);
}
}
-
- // sort the list of FileInfo objects collected above in descending order of their sizes
- Collections.sort(mFileInfoForMisc);
-
return miscSize;
}
- static class FileInfo implements Comparable<FileInfo> {
- final String mFileName;
- final long mSize;
- final 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 return (mSize < that.mSize) ? 1 : -1; // for descending sort
- }
-
- @Override
- public String toString() {
- return mFileName + " : " + mSize + ", id:" + mId;
- }
- }
-
private static void addValue(SparseLongArray array, int key, long value) {
array.put(key, array.get(key) + value);
}
diff --git a/src/com/android/settings/deviceinfo/StorageSettings.java b/src/com/android/settings/deviceinfo/StorageSettings.java
new file mode 100644
index 0000000..001f00d
--- /dev/null
+++ b/src/com/android/settings/deviceinfo/StorageSettings.java
@@ -0,0 +1,421 @@
+/*
+ * Copyright (C) 2015 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.Intent;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.os.UserManager;
+import android.os.storage.StorageEventListener;
+import android.os.storage.StorageManager;
+import android.os.storage.VolumeInfo;
+import android.preference.Preference;
+import android.preference.PreferenceCategory;
+import android.preference.PreferenceScreen;
+import android.provider.DocumentsContract;
+import android.util.Log;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.widget.Toast;
+
+import com.android.internal.logging.MetricsLogger;
+import com.android.settings.R;
+import com.android.settings.SettingsPreferenceFragment;
+import com.android.settings.search.BaseSearchIndexProvider;
+import com.android.settings.search.Indexable;
+import com.android.settings.search.SearchIndexableRaw;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+/**
+ * Panel showing both internal storage (both built-in storage and private
+ * volumes) and removable storage (public volumes).
+ */
+public class StorageSettings extends SettingsPreferenceFragment implements Indexable {
+ static final String TAG = "StorageSettings";
+
+ // TODO: badging to indicate devices running low on storage
+ // TODO: show currently ejected private volumes
+
+ public static final String EXTRA_VOLUME_ID = "volume_id";
+
+ private static final String DOCUMENT_AUTHORITY = "com.android.externalstorage.documents";
+ private static final String DOCUMENT_ROOT_PRIMARY_EMULATED = "primary";
+
+ /**
+ * Build an intent to browse the contents of given {@link VolumeInfo}.
+ */
+ public static Intent buildBrowseIntent(VolumeInfo vol) {
+ final Uri uri;
+ if (vol.type == VolumeInfo.TYPE_PUBLIC) {
+ uri = DocumentsContract.buildRootUri(DOCUMENT_AUTHORITY, vol.fsUuid);
+ } else if (VolumeInfo.ID_EMULATED_INTERNAL.equals(vol.id)) {
+ uri = DocumentsContract.buildRootUri(DOCUMENT_AUTHORITY,
+ DOCUMENT_ROOT_PRIMARY_EMULATED);
+ } else if (vol.type == VolumeInfo.TYPE_EMULATED) {
+ // TODO: build intent once supported
+ uri = null;
+ } else {
+ throw new IllegalArgumentException();
+ }
+
+ final Intent intent = new Intent(DocumentsContract.ACTION_BROWSE_DOCUMENT_ROOT);
+ intent.addCategory(Intent.CATEGORY_DEFAULT);
+ intent.setData(uri);
+ return intent;
+ }
+
+ private UserManager mUserManager;
+ private StorageManager mStorageManager;
+
+ private PreferenceCategory mInternalCategory;
+ private PreferenceCategory mExternalCategory;
+
+ @Override
+ protected int getMetricsCategory() {
+ return MetricsLogger.DEVICEINFO_STORAGE;
+ }
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ final Context context = getActivity();
+
+ mUserManager = context.getSystemService(UserManager.class);
+
+ mStorageManager = context.getSystemService(StorageManager.class);
+ mStorageManager.registerListener(mStorageListener);
+
+ addPreferencesFromResource(R.xml.device_info_storage);
+
+ mInternalCategory = (PreferenceCategory) findPreference("storage_internal");
+ mExternalCategory = (PreferenceCategory) findPreference("storage_external");
+
+ // TODO: if only one volume visible, shortcut into it
+
+ setHasOptionsMenu(true);
+ }
+
+ private static final Comparator<VolumeInfo> sVolumeComparator = new Comparator<VolumeInfo>() {
+ @Override
+ public int compare(VolumeInfo lhs, VolumeInfo rhs) {
+ if (VolumeInfo.ID_PRIVATE_INTERNAL.equals(lhs.id)) {
+ return -1;
+ } else if (lhs.getDescription() == null) {
+ return 1;
+ } else {
+ return lhs.getDescription().compareTo(rhs.getDescription());
+ }
+ }
+ };
+
+ private final StorageEventListener mStorageListener = new StorageEventListener() {
+ @Override
+ public void onVolumeStateChanged(VolumeInfo vol, int oldState, int newState) {
+ if (isInteresting(vol)) {
+ refresh();
+ }
+ }
+ };
+
+ private static boolean isInteresting(VolumeInfo vol) {
+ return vol.type == VolumeInfo.TYPE_PRIVATE || vol.type == VolumeInfo.TYPE_PUBLIC;
+ }
+
+ private void refresh() {
+ final Context context = getActivity();
+
+ getPreferenceScreen().removeAll();
+ mInternalCategory.removeAll();
+ mExternalCategory.removeAll();
+
+ final List<VolumeInfo> volumes = mStorageManager.getVolumes();
+ Collections.sort(volumes, sVolumeComparator);
+
+ for (VolumeInfo vol : volumes) {
+ if (vol.type == VolumeInfo.TYPE_PRIVATE) {
+ mInternalCategory.addPreference(new StorageVolumePreference(context, vol));
+ } else if (vol.type == VolumeInfo.TYPE_PUBLIC) {
+ mExternalCategory.addPreference(new StorageVolumePreference(context, vol));
+ }
+ }
+
+ if (mInternalCategory.getPreferenceCount() > 0) {
+ getPreferenceScreen().addPreference(mInternalCategory);
+ }
+ if (mExternalCategory.getPreferenceCount() > 0) {
+ getPreferenceScreen().addPreference(mExternalCategory);
+ }
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ mStorageManager.registerListener(mStorageListener);
+ refresh();
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ mStorageManager.unregisterListener(mStorageListener);
+ }
+
+ @Override
+ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+ inflater.inflate(R.menu.storage, menu);
+ }
+
+ @Override
+ public void onPrepareOptionsMenu(Menu menu) {
+ final MenuItem usb = menu.findItem(R.id.storage_usb);
+
+ usb.setVisible(!mUserManager.hasUserRestriction(UserManager.DISALLOW_USB_FILE_TRANSFER));
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch (item.getItemId()) {
+ case R.id.storage_usb:
+ startFragment(this, UsbSettings.class.getCanonicalName(),
+ R.string.storage_title_usb, 0, null);
+ return true;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+ @Override
+ public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference pref) {
+ final String volId = pref.getKey();
+ final VolumeInfo vol = mStorageManager.findVolumeById(volId);
+ if (vol == null) {
+ return false;
+
+ } else if (vol.type == VolumeInfo.TYPE_PRIVATE) {
+ final Bundle args = new Bundle();
+ args.putString(EXTRA_VOLUME_ID, volId);
+ startFragment(this, PrivateVolumeSettings.class.getCanonicalName(),
+ -1, 0, args);
+ return true;
+
+ } else if (vol.type == VolumeInfo.TYPE_PUBLIC) {
+ if (vol.state == VolumeInfo.STATE_MOUNTED) {
+ final Intent intent = buildBrowseIntent(vol);
+ startActivity(intent);
+ return true;
+ } else {
+ final Bundle args = new Bundle();
+ args.putString(EXTRA_VOLUME_ID, volId);
+ startFragment(this, PublicVolumeSettings.class.getCanonicalName(),
+ -1, 0, args);
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ public static class MountTask extends AsyncTask<Void, Void, Exception> {
+ private final Context mContext;
+ private final StorageManager mStorageManager;
+ private final String mVolumeId;
+ private final String mDescription;
+
+ public MountTask(Context context, String volumeId) {
+ mContext = context.getApplicationContext();
+ mStorageManager = mContext.getSystemService(StorageManager.class);
+ mVolumeId = volumeId;
+ mDescription = mStorageManager.getBestVolumeDescription(mVolumeId);
+ }
+
+ @Override
+ protected Exception doInBackground(Void... params) {
+ try {
+ mStorageManager.mount(mVolumeId);
+ return null;
+ } catch (Exception e) {
+ return e;
+ }
+ }
+
+ @Override
+ protected void onPostExecute(Exception e) {
+ if (e == null) {
+ Toast.makeText(mContext, mContext.getString(R.string.storage_mount_success,
+ mDescription), Toast.LENGTH_SHORT).show();
+ } else {
+ Log.e(TAG, "Failed to mount " + mVolumeId, e);
+ Toast.makeText(mContext, mContext.getString(R.string.storage_mount_failure,
+ mDescription), Toast.LENGTH_SHORT).show();
+ }
+ }
+ }
+
+ public static class UnmountTask extends AsyncTask<Void, Void, Exception> {
+ private final Context mContext;
+ private final StorageManager mStorageManager;
+ private final String mVolumeId;
+ private final String mDescription;
+
+ public UnmountTask(Context context, String volumeId) {
+ mContext = context.getApplicationContext();
+ mStorageManager = mContext.getSystemService(StorageManager.class);
+ mVolumeId = volumeId;
+ mDescription = mStorageManager.getBestVolumeDescription(mVolumeId);
+ }
+
+ @Override
+ protected Exception doInBackground(Void... params) {
+ try {
+ mStorageManager.unmount(mVolumeId);
+ return null;
+ } catch (Exception e) {
+ return e;
+ }
+ }
+
+ @Override
+ protected void onPostExecute(Exception e) {
+ if (e == null) {
+ Toast.makeText(mContext, mContext.getString(R.string.storage_unmount_success,
+ mDescription), Toast.LENGTH_SHORT).show();
+ } else {
+ Log.e(TAG, "Failed to unmount " + mVolumeId, e);
+ Toast.makeText(mContext, mContext.getString(R.string.storage_unmount_failure,
+ mDescription), Toast.LENGTH_SHORT).show();
+ }
+ }
+ }
+
+ public static class FormatTask extends AsyncTask<Void, Void, Exception> {
+ private final Context mContext;
+ private final StorageManager mStorageManager;
+ private final String mVolumeId;
+ private final String mDescription;
+
+ public FormatTask(Context context, String volumeId) {
+ mContext = context.getApplicationContext();
+ mStorageManager = mContext.getSystemService(StorageManager.class);
+ mVolumeId = volumeId;
+ mDescription = mStorageManager.getBestVolumeDescription(mVolumeId);
+ }
+
+ @Override
+ protected Exception doInBackground(Void... params) {
+ try {
+ mStorageManager.format(mVolumeId);
+ mStorageManager.mount(mVolumeId);
+ return null;
+ } catch (Exception e) {
+ return e;
+ }
+ }
+
+ @Override
+ protected void onPostExecute(Exception e) {
+ if (e == null) {
+ Toast.makeText(mContext, mContext.getString(R.string.storage_format_success,
+ mDescription), Toast.LENGTH_SHORT).show();
+ } else {
+ Log.e(TAG, "Failed to format " + mVolumeId, e);
+ Toast.makeText(mContext, mContext.getString(R.string.storage_format_failure,
+ mDescription), Toast.LENGTH_SHORT).show();
+ }
+ }
+ }
+
+ /**
+ * Enable indexing of searchable data
+ */
+ public static final SearchIndexProvider SEARCH_INDEX_DATA_PROVIDER =
+ new BaseSearchIndexProvider() {
+ @Override
+ public List<SearchIndexableRaw> getRawDataToIndex(Context context, boolean enabled) {
+ final List<SearchIndexableRaw> result = new ArrayList<SearchIndexableRaw>();
+
+ SearchIndexableRaw data = new SearchIndexableRaw(context);
+ data.title = context.getString(R.string.storage_settings);
+ data.screenTitle = context.getString(R.string.storage_settings);
+ result.add(data);
+
+ data = new SearchIndexableRaw(context);
+ data.title = context.getString(R.string.internal_storage);
+ data.screenTitle = context.getString(R.string.storage_settings);
+ result.add(data);
+
+ data = new SearchIndexableRaw(context);
+ final StorageManager storage = context.getSystemService(StorageManager.class);
+ final List<VolumeInfo> vols = storage.getVolumes();
+ for (VolumeInfo vol : vols) {
+ if (isInteresting(vol)) {
+ data.title = storage.getBestVolumeDescription(vol.id);
+ data.screenTitle = context.getString(R.string.storage_settings);
+ result.add(data);
+ }
+ }
+
+ data = new SearchIndexableRaw(context);
+ data.title = context.getString(R.string.memory_size);
+ data.screenTitle = context.getString(R.string.storage_settings);
+ result.add(data);
+
+ data = new SearchIndexableRaw(context);
+ data.title = context.getString(R.string.memory_available);
+ data.screenTitle = context.getString(R.string.storage_settings);
+ result.add(data);
+
+ data = new SearchIndexableRaw(context);
+ data.title = context.getString(R.string.memory_apps_usage);
+ data.screenTitle = context.getString(R.string.storage_settings);
+ result.add(data);
+
+ data = new SearchIndexableRaw(context);
+ data.title = context.getString(R.string.memory_dcim_usage);
+ data.screenTitle = context.getString(R.string.storage_settings);
+ result.add(data);
+
+ data = new SearchIndexableRaw(context);
+ data.title = context.getString(R.string.memory_music_usage);
+ data.screenTitle = context.getString(R.string.storage_settings);
+ result.add(data);
+
+ data = new SearchIndexableRaw(context);
+ data.title = context.getString(R.string.memory_downloads_usage);
+ data.screenTitle = context.getString(R.string.storage_settings);
+ result.add(data);
+
+ data = new SearchIndexableRaw(context);
+ data.title = context.getString(R.string.memory_media_cache_usage);
+ data.screenTitle = context.getString(R.string.storage_settings);
+ result.add(data);
+
+ data = new SearchIndexableRaw(context);
+ data.title = context.getString(R.string.memory_media_misc_usage);
+ data.screenTitle = context.getString(R.string.storage_settings);
+ result.add(data);
+
+ return result;
+ }
+ };
+}
diff --git a/src/com/android/settings/deviceinfo/StorageVolumePreference.java b/src/com/android/settings/deviceinfo/StorageVolumePreference.java
new file mode 100644
index 0000000..fbe34f6
--- /dev/null
+++ b/src/com/android/settings/deviceinfo/StorageVolumePreference.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2015 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.os.storage.StorageManager;
+import android.os.storage.VolumeInfo;
+import android.preference.Preference;
+import android.text.format.Formatter;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.TextView;
+
+import com.android.settings.R;
+import com.android.settings.deviceinfo.StorageSettings.UnmountTask;
+
+import java.io.File;
+
+/**
+ * Preference line representing a single {@link VolumeInfo}, possibly including
+ * quick actions like unmounting.
+ */
+public class StorageVolumePreference extends Preference {
+ private final StorageManager mStorageManager;
+ private final VolumeInfo mVolume;
+
+ public StorageVolumePreference(Context context, VolumeInfo volume) {
+ super(context);
+
+ mStorageManager = context.getSystemService(StorageManager.class);
+ mVolume = volume;
+
+ setKey(volume.id);
+ setTitle(mStorageManager.getBestVolumeDescription(volume.id));
+
+ switch (volume.state) {
+ case VolumeInfo.STATE_MOUNTED:
+ // TODO: move statfs() to background thread
+ final File path = new File(volume.path);
+ final String free = Formatter.formatFileSize(context, path.getFreeSpace());
+ final String total = Formatter.formatFileSize(context, path.getTotalSpace());
+ setSummary(context.getString(R.string.storage_volume_summary, free, total));
+ break;
+ }
+
+ // TODO: better icons
+ if (VolumeInfo.ID_PRIVATE_INTERNAL.equals(volume.id)) {
+ setIcon(context.getDrawable(R.drawable.ic_settings_storage));
+ } else {
+ setIcon(context.getDrawable(R.drawable.ic_sim_sd));
+ }
+
+ if (volume.type == VolumeInfo.TYPE_PUBLIC && volume.state == VolumeInfo.STATE_MOUNTED) {
+ setWidgetLayoutResource(R.layout.preference_storage_action);
+ }
+ }
+
+ @Override
+ protected void onBindView(View view) {
+ final TextView unmount = (TextView) view.findViewById(R.id.unmount);
+ if (unmount != null) {
+ unmount.setText("\u23CF");
+ unmount.setOnClickListener(mUnmountListener);
+ }
+
+ super.onBindView(view);
+ }
+
+ private final View.OnClickListener mUnmountListener = new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ new UnmountTask(getContext(), mVolume.id).execute();
+ }
+ };
+}
diff --git a/src/com/android/settings/deviceinfo/StorageVolumePreferenceCategory.java b/src/com/android/settings/deviceinfo/StorageVolumePreferenceCategory.java
deleted file mode 100644
index a98f8d9..0000000
--- a/src/com/android/settings/deviceinfo/StorageVolumePreferenceCategory.java
+++ /dev/null
@@ -1,483 +0,0 @@
-/*
- * 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.app.ActivityManagerNative;
-import android.app.ActivityThread;
-import android.app.DownloadManager;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.IPackageManager;
-import android.content.pm.UserInfo;
-import android.content.res.Resources;
-import android.hardware.usb.UsbManager;
-import android.os.Environment;
-import android.os.Handler;
-import android.os.Message;
-import android.os.RemoteException;
-import android.os.UserManager;
-import android.os.storage.StorageManager;
-import android.os.storage.StorageVolume;
-import android.preference.Preference;
-import android.preference.PreferenceCategory;
-import android.provider.MediaStore;
-import android.text.format.Formatter;
-
-import com.android.settings.R;
-import com.android.settings.Settings;
-import com.android.settings.deviceinfo.StorageMeasurement.MeasurementDetails;
-import com.android.settings.deviceinfo.StorageMeasurement.MeasurementReceiver;
-import com.google.android.collect.Lists;
-
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-
-public class StorageVolumePreferenceCategory extends PreferenceCategory {
- public static final String KEY_CACHE = "cache";
-
- private static final int ORDER_USAGE_BAR = -2;
- private static final int ORDER_STORAGE_LOW = -1;
-
- /** Physical volume being measured, or {@code null} for internal. */
- private final StorageVolume mVolume;
- private final StorageMeasurement mMeasure;
-
- private final Resources mResources;
- private final StorageManager mStorageManager;
- private final UserManager mUserManager;
-
- private UsageBarPreference mUsageBarPreference;
- private Preference mMountTogglePreference;
- private Preference mFormatPreference;
- private Preference mStorageLow;
-
- private StorageItemPreference mItemTotal;
- private StorageItemPreference mItemAvailable;
- private StorageItemPreference mItemApps;
- private StorageItemPreference mItemDcim;
- private StorageItemPreference mItemMusic;
- private StorageItemPreference mItemDownloads;
- private StorageItemPreference mItemCache;
- private StorageItemPreference mItemMisc;
- private List<StorageItemPreference> mItemUsers = Lists.newArrayList();
-
- private boolean mUsbConnected;
- private String mUsbFunction;
-
- private long mTotalSize;
-
- private static final int MSG_UI_UPDATE_APPROXIMATE = 1;
- private static final int MSG_UI_UPDATE_DETAILS = 2;
-
- private Handler mUpdateHandler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MSG_UI_UPDATE_APPROXIMATE: {
- final long[] size = (long[]) msg.obj;
- updateApproximate(size[0], size[1]);
- break;
- }
- case MSG_UI_UPDATE_DETAILS: {
- final MeasurementDetails details = (MeasurementDetails) msg.obj;
- updateDetails(details);
- break;
- }
- }
- }
- };
-
- /**
- * Build category to summarize internal storage, including any emulated
- * {@link StorageVolume}.
- */
- public static StorageVolumePreferenceCategory buildForInternal(Context context) {
- return new StorageVolumePreferenceCategory(context, null);
- }
-
- /**
- * Build category to summarize specific physical {@link StorageVolume}.
- */
- public static StorageVolumePreferenceCategory buildForPhysical(
- Context context, StorageVolume volume) {
- return new StorageVolumePreferenceCategory(context, volume);
- }
-
- private StorageVolumePreferenceCategory(Context context, StorageVolume volume) {
- super(context);
-
- mVolume = volume;
- mMeasure = StorageMeasurement.getInstance(context, volume);
-
- mResources = context.getResources();
- mStorageManager = StorageManager.from(context);
- mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
-
- setTitle(volume != null ? volume.getDescription(context)
- : context.getText(R.string.internal_storage));
- }
-
- private StorageItemPreference buildItem(int titleRes, int colorRes) {
- return new StorageItemPreference(getContext(), titleRes, colorRes);
- }
-
- public void init() {
- final Context context = getContext();
-
- removeAll();
-
- final UserInfo currentUser;
- try {
- currentUser = ActivityManagerNative.getDefault().getCurrentUser();
- } catch (RemoteException e) {
- throw new RuntimeException("Failed to get current user");
- }
-
- final List<UserInfo> otherUsers = getUsersExcluding(currentUser);
- final boolean showUsers = mVolume == null && otherUsers.size() > 0;
-
- mUsageBarPreference = new UsageBarPreference(context);
- mUsageBarPreference.setOrder(ORDER_USAGE_BAR);
- addPreference(mUsageBarPreference);
-
- mItemTotal = buildItem(R.string.memory_size, 0);
- mItemAvailable = buildItem(R.string.memory_available, R.color.memory_avail);
- addPreference(mItemTotal);
- addPreference(mItemAvailable);
-
- mItemApps = buildItem(R.string.memory_apps_usage, R.color.memory_apps_usage);
- mItemDcim = buildItem(R.string.memory_dcim_usage, R.color.memory_dcim);
- mItemMusic = buildItem(R.string.memory_music_usage, R.color.memory_music);
- mItemDownloads = buildItem(R.string.memory_downloads_usage, R.color.memory_downloads);
- mItemCache = buildItem(R.string.memory_media_cache_usage, R.color.memory_cache);
- mItemMisc = buildItem(R.string.memory_media_misc_usage, R.color.memory_misc);
-
- mItemCache.setKey(KEY_CACHE);
-
- final boolean showDetails = mVolume == null || mVolume.isPrimary();
- if (showDetails) {
- if (showUsers) {
- addPreference(new PreferenceHeader(context, currentUser.name));
- }
-
- addPreference(mItemApps);
- addPreference(mItemDcim);
- addPreference(mItemMusic);
- addPreference(mItemDownloads);
- addPreference(mItemCache);
- addPreference(mItemMisc);
-
- if (showUsers) {
- addPreference(new PreferenceHeader(context, R.string.storage_other_users));
-
- int count = 0;
- for (UserInfo info : otherUsers) {
- final int colorRes = count++ % 2 == 0 ? R.color.memory_user_light
- : R.color.memory_user_dark;
- final StorageItemPreference userPref = new StorageItemPreference(
- getContext(), info.name, colorRes, info.id);
- mItemUsers.add(userPref);
- addPreference(userPref);
- }
- }
- }
-
- final boolean isRemovable = mVolume != null ? mVolume.isRemovable() : false;
- // Always create the preference since many code rely on it existing
- mMountTogglePreference = new Preference(context);
- if (isRemovable) {
- mMountTogglePreference.setTitle(R.string.sd_eject);
- mMountTogglePreference.setSummary(R.string.sd_eject_summary);
- addPreference(mMountTogglePreference);
- }
-
- final boolean allowFormat = mVolume != null;
- if (allowFormat) {
- mFormatPreference = new Preference(context);
- mFormatPreference.setTitle(R.string.sd_format);
- mFormatPreference.setSummary(R.string.sd_format_summary);
- addPreference(mFormatPreference);
- }
-
- final IPackageManager pm = ActivityThread.getPackageManager();
- try {
- if (pm.isStorageLow()) {
- mStorageLow = new Preference(context);
- mStorageLow.setOrder(ORDER_STORAGE_LOW);
- mStorageLow.setTitle(R.string.storage_low_title);
- mStorageLow.setSummary(R.string.storage_low_summary);
- addPreference(mStorageLow);
- } else if (mStorageLow != null) {
- removePreference(mStorageLow);
- mStorageLow = null;
- }
- } catch (RemoteException e) {
- }
- }
-
- public StorageVolume getStorageVolume() {
- return mVolume;
- }
-
- private void updatePreferencesFromState() {
- // Only update for physical volumes
- if (mVolume == null) return;
-
- mMountTogglePreference.setEnabled(true);
-
- final String state = mStorageManager.getVolumeState(mVolume.getPath());
-
- if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
- mItemAvailable.setTitle(R.string.memory_available_read_only);
- } else {
- mItemAvailable.setTitle(R.string.memory_available);
- }
-
- if (Environment.MEDIA_MOUNTED.equals(state)
- || Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
- mMountTogglePreference.setEnabled(true);
- mMountTogglePreference.setTitle(mResources.getString(R.string.sd_eject));
- mMountTogglePreference.setSummary(mResources.getString(R.string.sd_eject_summary));
- addPreference(mUsageBarPreference);
- addPreference(mItemTotal);
- addPreference(mItemAvailable);
- } else {
- if (Environment.MEDIA_UNMOUNTED.equals(state) || Environment.MEDIA_NOFS.equals(state)
- || Environment.MEDIA_UNMOUNTABLE.equals(state)) {
- mMountTogglePreference.setEnabled(true);
- mMountTogglePreference.setTitle(mResources.getString(R.string.sd_mount));
- mMountTogglePreference.setSummary(mResources.getString(R.string.sd_mount_summary));
- } else {
- mMountTogglePreference.setEnabled(false);
- mMountTogglePreference.setTitle(mResources.getString(R.string.sd_mount));
- mMountTogglePreference.setSummary(mResources.getString(R.string.sd_insert_summary));
- }
-
- removePreference(mUsageBarPreference);
- removePreference(mItemTotal);
- removePreference(mItemAvailable);
- }
-
- if (mUsbConnected && (UsbManager.USB_FUNCTION_MTP.equals(mUsbFunction) ||
- UsbManager.USB_FUNCTION_PTP.equals(mUsbFunction))) {
- mMountTogglePreference.setEnabled(false);
- if (Environment.MEDIA_MOUNTED.equals(state)
- || Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
- mMountTogglePreference.setSummary(
- mResources.getString(R.string.mtp_ptp_mode_summary));
- }
-
- if (mFormatPreference != null) {
- mFormatPreference.setEnabled(false);
- mFormatPreference.setSummary(mResources.getString(R.string.mtp_ptp_mode_summary));
- }
- } else if (mFormatPreference != null) {
- mFormatPreference.setEnabled(mMountTogglePreference.isEnabled());
- mFormatPreference.setSummary(mResources.getString(R.string.sd_format_summary));
- }
- }
-
- public void updateApproximate(long totalSize, long availSize) {
- mItemTotal.setSummary(formatSize(totalSize));
- mItemAvailable.setSummary(formatSize(availSize));
-
- mTotalSize = totalSize;
-
- final long usedSize = totalSize - availSize;
-
- mUsageBarPreference.clear();
- mUsageBarPreference.addEntry(0, usedSize / (float) totalSize, android.graphics.Color.GRAY);
- mUsageBarPreference.commit();
-
- updatePreferencesFromState();
- }
-
- private static long totalValues(HashMap<String, Long> map, String... keys) {
- long total = 0;
- for (String key : keys) {
- if (map.containsKey(key)) {
- total += map.get(key);
- }
- }
- return total;
- }
-
- public void updateDetails(MeasurementDetails details) {
- final boolean showDetails = mVolume == null || mVolume.isPrimary();
- if (!showDetails) return;
-
- // Count caches as available space, since system manages them
- mItemTotal.setSummary(formatSize(details.totalSize));
- mItemAvailable.setSummary(formatSize(details.availSize));
-
- mUsageBarPreference.clear();
-
- updatePreference(mItemApps, details.appsSize);
-
- final long dcimSize = totalValues(details.mediaSize, Environment.DIRECTORY_DCIM,
- Environment.DIRECTORY_MOVIES, Environment.DIRECTORY_PICTURES);
- updatePreference(mItemDcim, dcimSize);
-
- final long musicSize = totalValues(details.mediaSize, Environment.DIRECTORY_MUSIC,
- Environment.DIRECTORY_ALARMS, Environment.DIRECTORY_NOTIFICATIONS,
- Environment.DIRECTORY_RINGTONES, Environment.DIRECTORY_PODCASTS);
- updatePreference(mItemMusic, musicSize);
-
- final long downloadsSize = totalValues(details.mediaSize, Environment.DIRECTORY_DOWNLOADS);
- updatePreference(mItemDownloads, downloadsSize);
-
- updatePreference(mItemCache, details.cacheSize);
- updatePreference(mItemMisc, details.miscSize);
-
- for (StorageItemPreference userPref : mItemUsers) {
- final long userSize = details.usersSize.get(userPref.userHandle);
- updatePreference(userPref, userSize);
- }
-
- mUsageBarPreference.commit();
- }
-
- private void updatePreference(StorageItemPreference pref, long size) {
- if (size > 0) {
- pref.setSummary(formatSize(size));
- final int order = pref.getOrder();
- mUsageBarPreference.addEntry(order, size / (float) mTotalSize, pref.color);
- } else {
- removePreference(pref);
- }
- }
-
- private void measure() {
- mMeasure.invalidate();
- mMeasure.measure();
- }
-
- public void onResume() {
- mMeasure.setReceiver(mReceiver);
- measure();
- }
-
- public void onStorageStateChanged() {
- init();
- measure();
- }
-
- public void onUsbStateChanged(boolean isUsbConnected, String usbFunction) {
- mUsbConnected = isUsbConnected;
- mUsbFunction = usbFunction;
- measure();
- }
-
- public void onMediaScannerFinished() {
- measure();
- }
-
- public void onCacheCleared() {
- measure();
- }
-
- public void onPause() {
- mMeasure.cleanUp();
- }
-
- private String formatSize(long size) {
- return Formatter.formatFileSize(getContext(), size);
- }
-
- private MeasurementReceiver mReceiver = new MeasurementReceiver() {
- @Override
- public void updateApproximate(StorageMeasurement meas, long totalSize, long availSize) {
- mUpdateHandler.obtainMessage(MSG_UI_UPDATE_APPROXIMATE, new long[] {
- totalSize, availSize }).sendToTarget();
- }
-
- @Override
- public void updateDetails(StorageMeasurement meas, MeasurementDetails details) {
- mUpdateHandler.obtainMessage(MSG_UI_UPDATE_DETAILS, details).sendToTarget();
- }
- };
-
- public boolean mountToggleClicked(Preference preference) {
- return preference == mMountTogglePreference;
- }
-
- public Intent intentForClick(Preference pref) {
- Intent intent = null;
-
- // 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.
- // If that cannot be done, remove these intents.
- final String key = pref.getKey();
- if (pref == mFormatPreference) {
- intent = new Intent(Intent.ACTION_VIEW);
- intent.setClass(getContext(), com.android.settings.MediaFormat.class);
- intent.putExtra(StorageVolume.EXTRA_STORAGE_VOLUME, mVolume);
- } else if (pref == mItemApps) {
- intent = new Intent(Intent.ACTION_MANAGE_PACKAGE_STORAGE);
- intent.setClass(getContext(), Settings.ManageApplicationsActivity.class);
- } else if (pref == mItemDownloads) {
- intent = new Intent(DownloadManager.ACTION_VIEW_DOWNLOADS).putExtra(
- DownloadManager.INTENT_EXTRAS_SORT_BY_SIZE, true);
- } else if (pref == mItemMusic) {
- intent = new Intent(Intent.ACTION_GET_CONTENT);
- intent.setType("audio/mp3");
- } else if (pref == mItemDcim) {
- intent = new Intent(Intent.ACTION_VIEW);
- intent.putExtra(Intent.EXTRA_LOCAL_ONLY, true);
- // TODO Create a Videos category, MediaStore.Video.Media.EXTERNAL_CONTENT_URI
- intent.setData(MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
- } else if (pref == mItemMisc) {
- Context context = getContext().getApplicationContext();
- intent = new Intent(context, MiscFilesHandler.class);
- intent.putExtra(StorageVolume.EXTRA_STORAGE_VOLUME, mVolume);
- }
-
- return intent;
- }
-
- public static class PreferenceHeader extends Preference {
- public PreferenceHeader(Context context, int titleRes) {
- super(context, null, com.android.internal.R.attr.preferenceCategoryStyle);
- setTitle(titleRes);
- }
-
- public PreferenceHeader(Context context, CharSequence title) {
- super(context, null, com.android.internal.R.attr.preferenceCategoryStyle);
- setTitle(title);
- }
-
- @Override
- public boolean isEnabled() {
- return false;
- }
- }
-
- /**
- * Return list of other users, excluding the current user.
- */
- private List<UserInfo> getUsersExcluding(UserInfo excluding) {
- final List<UserInfo> users = mUserManager.getUsers();
- final Iterator<UserInfo> i = users.iterator();
- while (i.hasNext()) {
- if (i.next().id == excluding.id) {
- i.remove();
- }
- }
- return users;
- }
-}
diff --git a/src/com/android/settings/search/Ranking.java b/src/com/android/settings/search/Ranking.java
index f37e1fc..2143d0d 100644
--- a/src/com/android/settings/search/Ranking.java
+++ b/src/com/android/settings/search/Ranking.java
@@ -32,7 +32,7 @@ import com.android.settings.WirelessSettings;
import com.android.settings.accessibility.AccessibilitySettings;
import com.android.settings.applications.AdvancedAppSettings;
import com.android.settings.bluetooth.BluetoothSettings;
-import com.android.settings.deviceinfo.Memory;
+import com.android.settings.deviceinfo.StorageSettings;
import com.android.settings.deviceinfo.UsbSettings;
import com.android.settings.fuelgauge.BatterySaverSettings;
import com.android.settings.fuelgauge.PowerUsageSummary;
@@ -129,7 +129,7 @@ public final class Ranking {
sRankMap.put(ZenModeAutomationSettings.class.getName(), RANK_NOTIFICATIONS);
// Storage
- sRankMap.put(Memory.class.getName(), RANK_STORAGE);
+ sRankMap.put(StorageSettings.class.getName(), RANK_STORAGE);
sRankMap.put(UsbSettings.class.getName(), RANK_STORAGE);
// Battery
diff --git a/src/com/android/settings/search/SearchIndexableResources.java b/src/com/android/settings/search/SearchIndexableResources.java
index dae8860..b7bb062 100644
--- a/src/com/android/settings/search/SearchIndexableResources.java
+++ b/src/com/android/settings/search/SearchIndexableResources.java
@@ -34,7 +34,7 @@ import com.android.settings.WirelessSettings;
import com.android.settings.accessibility.AccessibilitySettings;
import com.android.settings.applications.AdvancedAppSettings;
import com.android.settings.bluetooth.BluetoothSettings;
-import com.android.settings.deviceinfo.Memory;
+import com.android.settings.deviceinfo.StorageSettings;
import com.android.settings.deviceinfo.UsbSettings;
import com.android.settings.fuelgauge.BatterySaverSettings;
import com.android.settings.fuelgauge.PowerUsageSummary;
@@ -170,11 +170,11 @@ public final class SearchIndexableResources {
ZenModePrioritySettings.class.getName(),
R.drawable.ic_settings_notifications));
- sResMap.put(Memory.class.getName(),
+ sResMap.put(StorageSettings.class.getName(),
new SearchIndexableResource(
- Ranking.getRankForClassName(Memory.class.getName()),
+ Ranking.getRankForClassName(StorageSettings.class.getName()),
NO_DATA_RES_ID,
- Memory.class.getName(),
+ StorageSettings.class.getName(),
R.drawable.ic_settings_storage));
sResMap.put(UsbSettings.class.getName(),