Files
app_Settings/src/com/android/settings/deviceinfo/PrivateVolumeSettings.java
Daniel Nishi dfed8a2acb Add support for visualizing secondary users.
This functionality adds the secondary users to the screen, but
currently does not populate the information for them. Once the
external stats query works, I will add a loader which will
populate this information.

This also does not cover work profiles. Support for that is
forthcoming.

Bug: 34715777, 34225103
Test: Settings Robotest
Change-Id: Ib9b692b214f5ce5d303dfd64516381443d4acebd
2017-02-21 12:07:23 -08:00

915 lines
36 KiB
Java

/*
* 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.app.AlertDialog;
import android.app.Dialog;
import android.app.Fragment;
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.os.storage.VolumeRecord;
import android.provider.DocumentsContract;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceCategory;
import android.support.v7.preference.PreferenceGroup;
import android.support.v7.preference.PreferenceScreen;
import android.text.TextUtils;
import android.text.format.Formatter;
import android.text.format.Formatter.BytesResult;
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.nano.MetricsProto.MetricsEvent;
import com.android.settings.R;
import com.android.settings.Settings.StorageUseActivity;
import com.android.settings.SettingsPreferenceFragment;
import com.android.settings.Utils;
import com.android.settings.applications.ManageApplications;
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
import com.android.settings.deletionhelper.AutomaticStorageManagerSettings;
import com.android.settings.deviceinfo.StorageSettings.MountTask;
import com.android.settingslib.deviceinfo.StorageMeasurement;
import com.android.settingslib.deviceinfo.StorageMeasurement.MeasurementDetails;
import com.android.settingslib.deviceinfo.StorageMeasurement.MeasurementReceiver;
import com.google.android.collect.Lists;
import java.util.HashMap;
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
// TODO: warn when mounted read-only
private static final String TAG = "PrivateVolumeSettings";
private static final boolean LOGV = false;
private static final String TAG_RENAME = "rename";
private static final String TAG_OTHER_INFO = "otherInfo";
private static final String TAG_SYSTEM_INFO = "systemInfo";
private static final String TAG_USER_INFO = "userInfo";
private static final String TAG_CONFIRM_CLEAR_CACHE = "confirmClearCache";
private static final String EXTRA_VOLUME_SIZE = "volume_size";
private static final String AUTHORITY_MEDIA = "com.android.providers.media.documents";
private static final int[] ITEMS_NO_SHOW_SHARED = new int[] {
R.string.storage_detail_apps,
R.string.storage_detail_system,
};
private static final int[] ITEMS_SHOW_SHARED = new int[] {
R.string.storage_detail_apps,
R.string.storage_detail_images,
R.string.storage_detail_videos,
R.string.storage_detail_audio,
R.string.storage_detail_system,
R.string.storage_detail_other,
};
private StorageManager mStorageManager;
private UserManager mUserManager;
private String mVolumeId;
private VolumeInfo mVolume;
private VolumeInfo mSharedVolume;
private long mTotalSize;
private long mSystemSize;
private StorageMeasurement mMeasure;
private UserInfo mCurrentUser;
private StorageSummaryPreference mSummary;
private List<StorageItemPreference> mItemPreferencePool = Lists.newArrayList();
private List<PreferenceCategory> mHeaderPreferencePool = Lists.newArrayList();
private int mHeaderPoolIndex;
private int mItemPoolIndex;
private Preference mExplore;
private Preference mAutomaticStorageManagement;
private boolean mNeedsUpdate;
private boolean isVolumeValid() {
return (mVolume != null) && (mVolume.getType() == VolumeInfo.TYPE_PRIVATE)
&& mVolume.isMountedReadable();
}
public PrivateVolumeSettings() {
setRetainInstance(true);
}
@Override
public int getMetricsCategory() {
return MetricsEvent.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);
mVolumeId = getArguments().getString(VolumeInfo.EXTRA_VOLUME_ID);
mVolume = mStorageManager.findVolumeById(mVolumeId);
final long sharedDataSize = mVolume.getPath().getTotalSpace();
mTotalSize = getArguments().getLong(EXTRA_VOLUME_SIZE, 0);
mSystemSize = mTotalSize - sharedDataSize;
if (LOGV) Log.v(TAG,
"onCreate() mTotalSize: " + mTotalSize + " sharedDataSize: " + sharedDataSize);
if (mTotalSize <= 0) {
mTotalSize = sharedDataSize;
mSystemSize = 0;
}
// Find the emulated shared storage layered above this private volume
mSharedVolume = mStorageManager.findEmulatedForPrivate(mVolume);
mMeasure = new StorageMeasurement(context, mVolume, mSharedVolume);
mMeasure.setReceiver(mReceiver);
if (!isVolumeValid()) {
getActivity().finish();
return;
}
addPreferencesFromResource(R.xml.device_info_storage_volume);
getPreferenceScreen().setOrderingAsAdded(true);
mSummary = new StorageSummaryPreference(getPrefContext());
mCurrentUser = mUserManager.getUserInfo(UserHandle.myUserId());
mExplore = buildAction(R.string.storage_menu_explore);
mAutomaticStorageManagement = buildAction(R.string.storage_menu_manage);
mNeedsUpdate = true;
setHasOptionsMenu(true);
}
private void setTitle() {
getActivity().setTitle(mStorageManager.getBestVolumeDescription(mVolume));
}
private void update() {
if (!isVolumeValid()) {
getActivity().finish();
return;
}
setTitle();
// Valid options may have changed
getFragmentManager().invalidateOptionsMenu();
final Context context = getActivity();
final PreferenceScreen screen = getPreferenceScreen();
screen.removeAll();
if (getResources().getBoolean(R.bool.config_storage_manager_settings_enabled)) {
addPreference(screen, mAutomaticStorageManagement);
}
addPreference(screen, mSummary);
List<UserInfo> allUsers = mUserManager.getUsers();
final int userCount = allUsers.size();
final boolean showHeaders = userCount > 1;
final boolean showShared = (mSharedVolume != null) && mSharedVolume.isMountedReadable();
mItemPoolIndex = 0;
mHeaderPoolIndex = 0;
int addedUserCount = 0;
// Add current user and its profiles first
for (int userIndex = 0; userIndex < userCount; ++userIndex) {
final UserInfo userInfo = allUsers.get(userIndex);
if (Utils.isProfileOf(mCurrentUser, userInfo)) {
final PreferenceGroup details = showHeaders ?
addCategory(screen, userInfo.name) : screen;
addDetailItems(details, showShared, userInfo.id);
++addedUserCount;
}
}
// Add rest of users
if (userCount - addedUserCount > 0) {
PreferenceGroup otherUsers = addCategory(screen,
getText(R.string.storage_other_users));
for (int userIndex = 0; userIndex < userCount; ++userIndex) {
final UserInfo userInfo = allUsers.get(userIndex);
if (!Utils.isProfileOf(mCurrentUser, userInfo)) {
addItem(otherUsers, /* titleRes */ 0, userInfo.name, userInfo.id);
}
}
}
addItem(screen, R.string.storage_detail_cached, null, UserHandle.USER_NULL);
if (showShared) {
addPreference(screen, mExplore);
}
final long freeBytes = mVolume.getPath().getFreeSpace();
final long usedBytes = mTotalSize - freeBytes;
if (LOGV) Log.v(TAG, "update() freeBytes: " + freeBytes + " usedBytes: " + usedBytes);
final BytesResult result = Formatter.formatBytes(getResources(), usedBytes, 0);
mSummary.setTitle(TextUtils.expandTemplate(getText(R.string.storage_size_large),
result.value, result.units));
mSummary.setSummary(getString(R.string.storage_volume_used,
Formatter.formatFileSize(context, mTotalSize)));
mSummary.setPercent(usedBytes, mTotalSize);
mMeasure.forceMeasure();
mNeedsUpdate = false;
}
private void addPreference(PreferenceGroup group, Preference pref) {
pref.setOrder(Preference.DEFAULT_ORDER);
group.addPreference(pref);
}
private PreferenceCategory addCategory(PreferenceGroup group, CharSequence title) {
PreferenceCategory category;
if (mHeaderPoolIndex < mHeaderPreferencePool.size()) {
category = mHeaderPreferencePool.get(mHeaderPoolIndex);
} else {
category = new PreferenceCategory(getPrefContext());
mHeaderPreferencePool.add(category);
}
category.setTitle(title);
category.removeAll();
addPreference(group, category);
++mHeaderPoolIndex;
return category;
}
private void addDetailItems(PreferenceGroup category, boolean showShared, int userId) {
final int[] itemsToAdd = (showShared ? ITEMS_SHOW_SHARED : ITEMS_NO_SHOW_SHARED);
for (int i = 0; i < itemsToAdd.length; ++i) {
addItem(category, itemsToAdd[i], null, userId);
}
}
private void addItem(PreferenceGroup group, int titleRes, CharSequence title, int userId) {
if (titleRes == R.string.storage_detail_system) {
if (mSystemSize <= 0) {
Log.w(TAG, "Skipping System storage because its size is " + mSystemSize);
return;
}
if (userId != UserHandle.myUserId()) {
// Only display system on current user.
return;
}
}
StorageItemPreference item;
if (mItemPoolIndex < mItemPreferencePool.size()) {
item = mItemPreferencePool.get(mItemPoolIndex);
} else {
item = buildItem();
mItemPreferencePool.add(item);
}
if (title != null) {
item.setTitle(title);
item.setKey(title.toString());
} else {
item.setTitle(titleRes);
item.setKey(Integer.toString(titleRes));
}
item.setSummary(R.string.memory_calculating_size);
item.userHandle = userId;
addPreference(group, item);
++mItemPoolIndex;
}
private StorageItemPreference buildItem() {
final StorageItemPreference item = new StorageItemPreference(getPrefContext());
return item;
}
private Preference buildAction(int titleRes) {
final Preference pref = new Preference(getPrefContext());
pref.setTitle(titleRes);
pref.setKey(Integer.toString(titleRes));
return pref;
}
static void setVolumeSize(Bundle args, long size) {
args.putLong(EXTRA_VOLUME_SIZE, size);
}
@Override
public void onResume() {
super.onResume();
// Refresh to verify that we haven't been formatted away
mVolume = mStorageManager.findVolumeById(mVolumeId);
if (!isVolumeValid()) {
getActivity().finish();
return;
}
mStorageManager.registerListener(mStorageListener);
if (mNeedsUpdate) {
update();
} else {
setTitle();
}
}
@Override
public void onPause() {
super.onPause();
mStorageManager.unregisterListener(mStorageListener);
}
@Override
public void onDestroy() {
super.onDestroy();
if (mMeasure != null) {
mMeasure.onDestroy();
}
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
inflater.inflate(R.menu.storage_volume, menu);
}
@Override
public void onPrepareOptionsMenu(Menu menu) {
if (!isVolumeValid()) return;
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 migrate = menu.findItem(R.id.storage_migrate);
final MenuItem manage = menu.findItem(R.id.storage_free);
// 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.getId())) {
rename.setVisible(false);
mount.setVisible(false);
unmount.setVisible(false);
format.setVisible(false);
manage.setVisible(getResources().getBoolean(
R.bool.config_storage_manager_settings_enabled));
} else {
rename.setVisible(mVolume.getType() == VolumeInfo.TYPE_PRIVATE);
mount.setVisible(mVolume.getState() == VolumeInfo.STATE_UNMOUNTED);
unmount.setVisible(mVolume.isMountedReadable());
format.setVisible(true);
manage.setVisible(false);
}
format.setTitle(R.string.storage_menu_format_public);
// Only offer to migrate when not current storage
final VolumeInfo privateVol = getActivity().getPackageManager()
.getPrimaryStorageCurrentVolume();
migrate.setVisible((privateVol != null)
&& (privateVol.getType() == VolumeInfo.TYPE_PRIVATE)
&& !Objects.equals(mVolume, privateVol));
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
final Context context = getActivity();
final Bundle args = new Bundle();
switch (item.getItemId()) {
case R.id.storage_rename:
RenameFragment.show(this, mVolume);
return true;
case R.id.storage_mount:
new MountTask(context, mVolume).execute();
return true;
case R.id.storage_unmount:
args.putString(VolumeInfo.EXTRA_VOLUME_ID, mVolume.getId());
startFragment(this, PrivateVolumeUnmount.class.getCanonicalName(),
R.string.storage_menu_unmount, 0, args);
return true;
case R.id.storage_format:
args.putString(VolumeInfo.EXTRA_VOLUME_ID, mVolume.getId());
startFragment(this, PrivateVolumeFormat.class.getCanonicalName(),
R.string.storage_menu_format, 0, args);
return true;
case R.id.storage_migrate:
final Intent intent = new Intent(context, StorageWizardMigrateConfirm.class);
intent.putExtra(VolumeInfo.EXTRA_VOLUME_ID, mVolume.getId());
startActivity(intent);
return true;
case R.id.storage_free:
final Intent deletion_helper_intent =
new Intent(StorageManager.ACTION_MANAGE_STORAGE);
startActivity(deletion_helper_intent);
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
public boolean onPreferenceTreeClick(Preference pref) {
// TODO: launch better intents for specific volume
final int userId = (pref instanceof StorageItemPreference ?
((StorageItemPreference) pref).userHandle : -1);
int itemTitleId;
try {
itemTitleId = Integer.parseInt(pref.getKey());
} catch (NumberFormatException e) {
itemTitleId = 0;
}
Intent intent = null;
switch (itemTitleId) {
case R.string.storage_detail_apps: {
Bundle args = new Bundle();
args.putString(ManageApplications.EXTRA_CLASSNAME,
StorageUseActivity.class.getName());
args.putString(ManageApplications.EXTRA_VOLUME_UUID, mVolume.getFsUuid());
args.putString(ManageApplications.EXTRA_VOLUME_NAME, mVolume.getDescription());
intent = Utils.onBuildStartFragmentIntent(getActivity(),
ManageApplications.class.getName(), args, null, R.string.apps_storage, null,
false, getMetricsCategory());
} break;
case R.string.storage_detail_images: {
intent = new Intent(DocumentsContract.ACTION_BROWSE);
intent.setData(DocumentsContract.buildRootUri(AUTHORITY_MEDIA, "images_root"));
intent.addCategory(Intent.CATEGORY_DEFAULT);
} break;
case R.string.storage_detail_videos: {
intent = new Intent(DocumentsContract.ACTION_BROWSE);
intent.setData(DocumentsContract.buildRootUri(AUTHORITY_MEDIA, "videos_root"));
intent.addCategory(Intent.CATEGORY_DEFAULT);
} break;
case R.string.storage_detail_audio: {
intent = new Intent(DocumentsContract.ACTION_BROWSE);
intent.setData(DocumentsContract.buildRootUri(AUTHORITY_MEDIA, "audio_root"));
intent.addCategory(Intent.CATEGORY_DEFAULT);
} break;
case R.string.storage_detail_system: {
SystemInfoFragment.show(this);
return true;
}
case R.string.storage_detail_other: {
OtherInfoFragment.show(this, mStorageManager.getBestVolumeDescription(mVolume),
mSharedVolume, userId);
return true;
}
case R.string.storage_detail_cached: {
ConfirmClearCacheFragment.show(this);
return true;
}
case R.string.storage_menu_explore: {
intent = mSharedVolume.buildBrowseIntent();
} break;
case R.string.storage_menu_manage: {
startFragment(this, AutomaticStorageManagerSettings.class.getCanonicalName(),
R.string.automatic_storage_manager_settings, 0, null);
return true;
}
case 0: {
UserInfoFragment.show(this, pref.getTitle(), pref.getSummary());
return true;
}
}
if (intent != null) {
intent.putExtra(Intent.EXTRA_USER_ID, userId);
Utils.launchIntent(this, intent);
return true;
}
return super.onPreferenceTreeClick(pref);
}
private final MeasurementReceiver mReceiver = new MeasurementReceiver() {
@Override
public void onDetailsChanged(MeasurementDetails details) {
updateDetails(details);
}
};
private void updateDetails(MeasurementDetails details) {
StorageItemPreference otherItem = null;
long accountedSize = 0;
long totalMiscSize = 0;
long totalDownloadsSize = 0;
for (int i = 0; i < mItemPoolIndex; ++i) {
StorageItemPreference item = mItemPreferencePool.get(i);
final int userId = item.userHandle;
int itemTitleId;
try {
itemTitleId = Integer.parseInt(item.getKey());
} catch (NumberFormatException e) {
itemTitleId = 0;
}
switch (itemTitleId) {
case R.string.storage_detail_system: {
updatePreference(item, mSystemSize);
accountedSize += mSystemSize;
if (LOGV) Log.v(TAG, "mSystemSize: " + mSystemSize
+ " accountedSize: " + accountedSize);
} break;
case R.string.storage_detail_apps: {
updatePreference(item, details.appsSize.get(userId));
accountedSize += details.appsSize.get(userId);
if (LOGV) Log.v(TAG, "appsSize: " + details.appsSize.get(userId)
+ " accountedSize: " + accountedSize);
} break;
case R.string.storage_detail_images: {
final long imagesSize = totalValues(details, userId,
Environment.DIRECTORY_DCIM, Environment.DIRECTORY_PICTURES);
updatePreference(item, imagesSize);
accountedSize += imagesSize;
if (LOGV) Log.v(TAG, "imagesSize: " + imagesSize
+ " accountedSize: " + accountedSize);
} break;
case R.string.storage_detail_videos: {
final long videosSize = totalValues(details, userId,
Environment.DIRECTORY_MOVIES);
updatePreference(item, videosSize);
accountedSize += videosSize;
if (LOGV) Log.v(TAG, "videosSize: " + videosSize
+ " accountedSize: " + accountedSize);
} break;
case R.string.storage_detail_audio: {
final long audioSize = totalValues(details, userId,
Environment.DIRECTORY_MUSIC,
Environment.DIRECTORY_ALARMS, Environment.DIRECTORY_NOTIFICATIONS,
Environment.DIRECTORY_RINGTONES, Environment.DIRECTORY_PODCASTS);
updatePreference(item, audioSize);
accountedSize += audioSize;
if (LOGV) Log.v(TAG, "audioSize: " + audioSize
+ " accountedSize: " + accountedSize);
} break;
case R.string.storage_detail_other: {
final long downloadsSize = totalValues(details, userId,
Environment.DIRECTORY_DOWNLOADS);
final long miscSize = details.miscSize.get(userId);
totalDownloadsSize += downloadsSize;
totalMiscSize += miscSize;
accountedSize += miscSize + downloadsSize;
if (LOGV)
Log.v(TAG, "miscSize for " + userId + ": " + miscSize + "(total: "
+ totalMiscSize + ") \ndownloadsSize: " + downloadsSize + "(total: "
+ totalDownloadsSize + ") accountedSize: " + accountedSize);
// Cannot display 'Other' until all known items are accounted for.
otherItem = item;
} break;
case R.string.storage_detail_cached: {
updatePreference(item, details.cacheSize);
accountedSize += details.cacheSize;
if (LOGV)
Log.v(TAG, "cacheSize: " + details.cacheSize + " accountedSize: "
+ accountedSize);
} break;
case 0: {
final long userSize = details.usersSize.get(userId);
updatePreference(item, userSize);
accountedSize += userSize;
if (LOGV) Log.v(TAG, "userSize: " + userSize
+ " accountedSize: " + accountedSize);
} break;
}
}
if (otherItem != null) {
final long usedSize = mTotalSize - details.availSize;
final long unaccountedSize = usedSize - accountedSize;
final long otherSize = totalMiscSize + totalDownloadsSize + unaccountedSize;
Log.v(TAG, "Other items: \n\tmTotalSize: " + mTotalSize + " availSize: "
+ details.availSize + " usedSize: " + usedSize + "\n\taccountedSize: "
+ accountedSize + " unaccountedSize size: " + unaccountedSize
+ "\n\ttotalMiscSize: " + totalMiscSize + " totalDownloadsSize: "
+ totalDownloadsSize + "\n\tdetails: " + details);
updatePreference(otherItem, otherSize);
}
}
private void updatePreference(StorageItemPreference pref, long size) {
pref.setStorageSize(size, mTotalSize);
}
private static long totalValues(MeasurementDetails details, int userId, String... keys) {
long total = 0;
HashMap<String, Long> map = details.mediaSize.get(userId);
if (map != null) {
for (String key : keys) {
if (map.containsKey(key)) {
total += map.get(key);
}
}
} else {
Log.w(TAG, "MeasurementDetails mediaSize array does not have key for user " + userId);
}
return total;
}
private final StorageEventListener mStorageListener = new StorageEventListener() {
@Override
public void onVolumeStateChanged(VolumeInfo vol, int oldState, int newState) {
if (Objects.equals(mVolume.getId(), vol.getId())) {
mVolume = vol;
update();
}
}
@Override
public void onVolumeRecordChanged(VolumeRecord rec) {
if (Objects.equals(mVolume.getFsUuid(), rec.getFsUuid())) {
mVolume = mStorageManager.findVolumeById(mVolumeId);
update();
}
}
};
/**
* Dialog that allows editing of volume nickname.
*/
public static class RenameFragment extends InstrumentedDialogFragment {
public static void show(PrivateVolumeSettings parent, VolumeInfo vol) {
if (!parent.isAdded()) return;
final RenameFragment dialog = new RenameFragment();
dialog.setTargetFragment(parent, 0);
final Bundle args = new Bundle();
args.putString(VolumeRecord.EXTRA_FS_UUID, vol.getFsUuid());
dialog.setArguments(args);
dialog.show(parent.getFragmentManager(), TAG_RENAME);
}
@Override
public int getMetricsCategory() {
return MetricsEvent.DIALOG_VOLUME_RENAME;
}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
final Context context = getActivity();
final StorageManager storageManager = context.getSystemService(StorageManager.class);
final String fsUuid = getArguments().getString(VolumeRecord.EXTRA_FS_UUID);
final VolumeInfo vol = storageManager.findVolumeByUuid(fsUuid);
final VolumeRecord rec = storageManager.findRecordByUuid(fsUuid);
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);
nickname.setText(rec.getNickname());
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: move to background thread
storageManager.setVolumeNickname(fsUuid,
nickname.getText().toString());
}
});
builder.setNegativeButton(R.string.cancel, null);
return builder.create();
}
}
public static class SystemInfoFragment extends InstrumentedDialogFragment {
public static void show(Fragment parent) {
if (!parent.isAdded()) return;
final SystemInfoFragment dialog = new SystemInfoFragment();
dialog.setTargetFragment(parent, 0);
dialog.show(parent.getFragmentManager(), TAG_SYSTEM_INFO);
}
@Override
public int getMetricsCategory() {
return MetricsEvent.DIALOG_STORAGE_SYSTEM_INFO;
}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
return new AlertDialog.Builder(getActivity())
.setMessage(R.string.storage_detail_dialog_system)
.setPositiveButton(android.R.string.ok, null)
.create();
}
}
public static class OtherInfoFragment extends InstrumentedDialogFragment {
public static void show(Fragment parent, String title, VolumeInfo sharedVol, int userId) {
if (!parent.isAdded()) return;
final OtherInfoFragment dialog = new OtherInfoFragment();
dialog.setTargetFragment(parent, 0);
final Bundle args = new Bundle();
args.putString(Intent.EXTRA_TITLE, title);
final Intent intent = sharedVol.buildBrowseIntent();
intent.putExtra(Intent.EXTRA_USER_ID, userId);
args.putParcelable(Intent.EXTRA_INTENT, intent);
dialog.setArguments(args);
dialog.show(parent.getFragmentManager(), TAG_OTHER_INFO);
}
@Override
public int getMetricsCategory() {
return MetricsEvent.DIALOG_STORAGE_OTHER_INFO;
}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
final Context context = getActivity();
final String title = getArguments().getString(Intent.EXTRA_TITLE);
final Intent intent = getArguments().getParcelable(Intent.EXTRA_INTENT);
final AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setMessage(
TextUtils.expandTemplate(getText(R.string.storage_detail_dialog_other), title));
builder.setPositiveButton(R.string.storage_menu_explore,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Utils.launchIntent(OtherInfoFragment.this, intent);
}
});
builder.setNegativeButton(android.R.string.cancel, null);
return builder.create();
}
}
public static class UserInfoFragment extends InstrumentedDialogFragment {
public static void show(Fragment parent, CharSequence userLabel, CharSequence userSize) {
if (!parent.isAdded()) return;
final UserInfoFragment dialog = new UserInfoFragment();
dialog.setTargetFragment(parent, 0);
final Bundle args = new Bundle();
args.putCharSequence(Intent.EXTRA_TITLE, userLabel);
args.putCharSequence(Intent.EXTRA_SUBJECT, userSize);
dialog.setArguments(args);
dialog.show(parent.getFragmentManager(), TAG_USER_INFO);
}
@Override
public int getMetricsCategory() {
return MetricsEvent.DIALOG_STORAGE_USER_INFO;
}
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
final Context context = getActivity();
final CharSequence userLabel = getArguments().getCharSequence(Intent.EXTRA_TITLE);
final CharSequence userSize = getArguments().getCharSequence(Intent.EXTRA_SUBJECT);
final AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setMessage(TextUtils.expandTemplate(
getText(R.string.storage_detail_dialog_user), userLabel, userSize));
builder.setPositiveButton(android.R.string.ok, null);
return builder.create();
}
}
/**
* Dialog to request user confirmation before clearing all cache data.
*/
public static class ConfirmClearCacheFragment extends InstrumentedDialogFragment {
public static void show(Fragment parent) {
if (!parent.isAdded()) return;
final ConfirmClearCacheFragment dialog = new ConfirmClearCacheFragment();
dialog.setTargetFragment(parent, 0);
dialog.show(parent.getFragmentManager(), TAG_CONFIRM_CLEAR_CACHE);
}
@Override
public int getMetricsCategory() {
return MetricsEvent.DIALOG_STORAGE_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 UserManager um = context.getSystemService(UserManager.class);
for (int userId : um.getProfileIdsWithDisabled(context.getUserId())) {
final List<PackageInfo> infos = pm.getInstalledPackagesAsUser(0, userId);
final ClearCacheObserver observer = new ClearCacheObserver(
target, infos.size());
for (PackageInfo info : infos) {
pm.deleteApplicationCacheFilesAsUser(info.packageName, userId,
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.getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
mTarget.update();
}
});
}
}
}
}
}