blob: 77cda8f40ff132dd93cf45402e7fb9da7c15b1d2 [file] [log] [blame]
/*
* 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.tv.settings.device.storage;
import android.app.ActivityManager;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.Environment;
import android.os.storage.StorageManager;
import android.os.storage.VolumeInfo;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
import android.text.TextUtils;
import android.util.Log;
import com.android.internal.logging.nano.MetricsProto;
import com.android.settingslib.deviceinfo.StorageMeasurement;
import com.android.tv.settings.R;
import com.android.tv.settings.SettingsPreferenceFragment;
import com.android.tv.settings.device.apps.AppsFragment;
import java.util.HashMap;
import java.util.List;
/**
* The screen in TV settings that lets users manage external storage devices and that shows the
* usage summary by data type such as apps, music, download and so on.
*/
public class StorageFragment extends SettingsPreferenceFragment {
private static final String TAG = "StorageFragment";
private static final String KEY_MIGRATE = "migrate";
private static final String KEY_EJECT = "eject";
private static final String KEY_ERASE = "erase";
private static final String KEY_APPS_USAGE = "apps_usage";
private static final String KEY_DCIM_USAGE = "dcim_usage";
private static final String KEY_MUSIC_USAGE = "music_usage";
private static final String KEY_DOWNLOADS_USAGE = "downloads_usage";
private static final String KEY_CACHE_USAGE = "cache_usage";
private static final String KEY_MISC_USAGE = "misc_usage";
private static final String KEY_AVAILABLE = "available";
private StorageManager mStorageManager;
private PackageManager mPackageManager;
private VolumeInfo mVolumeInfo;
private StorageMeasurement mMeasure;
private final StorageMeasurement.MeasurementReceiver mMeasurementReceiver =
new MeasurementReceiver();
private final StorageEventListener mStorageEventListener = new StorageEventListener();
private Preference mMigratePref;
private Preference mEjectPref;
private Preference mErasePref;
private StoragePreference mAppsUsagePref;
private StoragePreference mDcimUsagePref;
private StoragePreference mMusicUsagePref;
private StoragePreference mDownloadsUsagePref;
private StoragePreference mCacheUsagePref;
private StoragePreference mMiscUsagePref;
private StoragePreference mAvailablePref;
public static void prepareArgs(Bundle bundle, VolumeInfo volumeInfo) {
bundle.putString(VolumeInfo.EXTRA_VOLUME_ID, volumeInfo.getId());
}
@Override
public void onCreate(Bundle savedInstanceState) {
mStorageManager = getContext().getSystemService(StorageManager.class);
mPackageManager = getContext().getPackageManager();
mVolumeInfo = mStorageManager.findVolumeById(
getArguments().getString(VolumeInfo.EXTRA_VOLUME_ID));
super.onCreate(savedInstanceState);
}
@Override
public void onStart() {
super.onStart();
mStorageManager.registerListener(mStorageEventListener);
startMeasurement();
}
@Override
public void onResume() {
super.onResume();
mVolumeInfo = mStorageManager.findVolumeById(
getArguments().getString(VolumeInfo.EXTRA_VOLUME_ID));
if (mVolumeInfo == null || !mVolumeInfo.isMountedReadable()) {
getFragmentManager().popBackStack();
} else {
refresh();
}
}
@Override
public void onStop() {
super.onStop();
mStorageManager.unregisterListener(mStorageEventListener);
stopMeasurement();
}
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
setPreferencesFromResource(R.xml.storage, null);
final PreferenceScreen screen = getPreferenceScreen();
screen.setTitle(mStorageManager.getBestVolumeDescription(mVolumeInfo));
mMigratePref = findPreference(KEY_MIGRATE);
mEjectPref = findPreference(KEY_EJECT);
mErasePref = findPreference(KEY_ERASE);
mAppsUsagePref = (StoragePreference) findPreference(KEY_APPS_USAGE);
mDcimUsagePref = (StoragePreference) findPreference(KEY_DCIM_USAGE);
mMusicUsagePref = (StoragePreference) findPreference(KEY_MUSIC_USAGE);
mDownloadsUsagePref = (StoragePreference) findPreference(KEY_DOWNLOADS_USAGE);
mCacheUsagePref = (StoragePreference) findPreference(KEY_CACHE_USAGE);
mMiscUsagePref = (StoragePreference) findPreference(KEY_MISC_USAGE);
mAvailablePref = (StoragePreference) findPreference(KEY_AVAILABLE);
}
private void refresh() {
boolean showMigrate = false;
final VolumeInfo currentExternal = mPackageManager.getPrimaryStorageCurrentVolume();
// currentExternal will be null if the drive is not mounted. Don't offer the option to
// migrate if so.
if (currentExternal != null
&& !TextUtils.equals(currentExternal.getId(), mVolumeInfo.getId())) {
final List<VolumeInfo> candidates =
mPackageManager.getPrimaryStorageCandidateVolumes();
for (final VolumeInfo candidate : candidates) {
if (TextUtils.equals(candidate.getId(), mVolumeInfo.getId())) {
showMigrate = true;
break;
}
}
}
mMigratePref.setVisible(showMigrate);
mMigratePref.setIntent(
MigrateStorageActivity.getLaunchIntent(getContext(), mVolumeInfo.getId(), true));
final String description = mStorageManager.getBestVolumeDescription(mVolumeInfo);
final boolean privateInternal = VolumeInfo.ID_PRIVATE_INTERNAL.equals(mVolumeInfo.getId());
final boolean isPrivate = mVolumeInfo.getType() == VolumeInfo.TYPE_PRIVATE;
mEjectPref.setVisible(!privateInternal);
mEjectPref.setIntent(UnmountActivity.getIntent(getContext(), mVolumeInfo.getId(),
description));
mErasePref.setVisible(!privateInternal);
if (isPrivate) {
mErasePref.setIntent(
FormatActivity.getFormatAsPublicIntent(getContext(), mVolumeInfo.getDiskId()));
mErasePref.setTitle(R.string.storage_format_as_public);
} else {
mErasePref.setIntent(
FormatActivity.getFormatAsPrivateIntent(getContext(), mVolumeInfo.getDiskId()));
mErasePref.setTitle(R.string.storage_format_as_private);
}
mAppsUsagePref.setVisible(isPrivate);
mAppsUsagePref.setFragment(AppsFragment.class.getName());
AppsFragment.prepareArgs(mAppsUsagePref.getExtras(), mVolumeInfo.fsUuid, description);
mDcimUsagePref.setVisible(isPrivate);
mMusicUsagePref.setVisible(isPrivate);
mDownloadsUsagePref.setVisible(isPrivate);
mCacheUsagePref.setVisible(isPrivate);
mCacheUsagePref.setFragment(ConfirmClearCacheFragment.class.getName());
}
private void startMeasurement() {
if (mVolumeInfo != null && mVolumeInfo.isMountedReadable()) {
final VolumeInfo sharedVolume = mStorageManager.findEmulatedForPrivate(mVolumeInfo);
mMeasure = new StorageMeasurement(getContext(), mVolumeInfo, sharedVolume);
mMeasure.setReceiver(mMeasurementReceiver);
mMeasure.forceMeasure();
}
}
private void stopMeasurement() {
if (mMeasure != null) {
mMeasure.onDestroy();
}
}
private void updateDetails(StorageMeasurement.MeasurementDetails details) {
final int currentUser = ActivityManager.getCurrentUser();
final long dcimSize = totalValues(details.mediaSize.get(currentUser),
Environment.DIRECTORY_DCIM,
Environment.DIRECTORY_MOVIES, Environment.DIRECTORY_PICTURES);
final long musicSize = totalValues(details.mediaSize.get(currentUser),
Environment.DIRECTORY_MUSIC,
Environment.DIRECTORY_ALARMS, Environment.DIRECTORY_NOTIFICATIONS,
Environment.DIRECTORY_RINGTONES, Environment.DIRECTORY_PODCASTS);
final long downloadsSize = totalValues(details.mediaSize.get(currentUser),
Environment.DIRECTORY_DOWNLOADS);
mAvailablePref.setSize(details.availSize);
mAppsUsagePref.setSize(details.appsSize.get(currentUser));
mDcimUsagePref.setSize(dcimSize);
mMusicUsagePref.setSize(musicSize);
mDownloadsUsagePref.setSize(downloadsSize);
mCacheUsagePref.setSize(details.cacheSize);
mMiscUsagePref.setSize(details.miscSize.get(currentUser));
}
private static long totalValues(HashMap<String, Long> map, String... keys) {
long total = 0;
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 current user " +
ActivityManager.getCurrentUser());
}
return total;
}
private class MeasurementReceiver implements StorageMeasurement.MeasurementReceiver {
@Override
public void onDetailsChanged(StorageMeasurement.MeasurementDetails details) {
updateDetails(details);
}
}
private class StorageEventListener extends android.os.storage.StorageEventListener {
@Override
public void onVolumeStateChanged(VolumeInfo vol, int oldState, int newState) {
mVolumeInfo = vol;
if (isResumed()) {
if (mVolumeInfo.isMountedReadable()) {
refresh();
} else {
getFragmentManager().popBackStack();
}
}
}
}
@Override
public int getMetricsCategory() {
return MetricsProto.MetricsEvent.SETTINGS_STORAGE_CATEGORY;
}
}