Revamp Storage Settings header part
1. Add new object StorageEntry to encapsulate VolumeInfo and
unsupported DiskInfo and missing VolumeRecord.
2. Replaces StorageSummaryDonutPreference with UsageProgressBarPreference.
3. Add storage select spinner.
4. Add a "Free up storage" preference to replace "Manage storage" button.
Bug: 174964885
Test: atest com.android.settings.deviceinfo.storage
atest com.android.settings.deviceinfo
manual
Insert an USB drive, select the drive in StorageDashboardFragment
and observe UI.
Change-Id: I83877f76869414de4fb2788b6b18fe507aa5cfcf
Merged-In: I83877f76869414de4fb2788b6b18fe507aa5cfcf
This commit is contained in:
@@ -82,4 +82,8 @@ public class PrivateVolumeOptionMenuController implements LifecycleObserver, OnC
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void setVolumeInfo(VolumeInfo volumeInfo) {
|
||||
mVolumeInfo = volumeInfo;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,39 +17,55 @@
|
||||
package com.android.settings.deviceinfo;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Dialog;
|
||||
import android.app.settings.SettingsEnums;
|
||||
import android.app.usage.StorageStatsManager;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Bundle;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
import android.os.storage.DiskInfo;
|
||||
import android.os.storage.StorageEventListener;
|
||||
import android.os.storage.StorageManager;
|
||||
import android.os.storage.VolumeInfo;
|
||||
import android.os.storage.VolumeRecord;
|
||||
import android.provider.SearchIndexableResource;
|
||||
import android.text.TextUtils;
|
||||
import android.util.SparseArray;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.loader.app.LoaderManager;
|
||||
import androidx.loader.content.Loader;
|
||||
import androidx.preference.Preference;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.Utils;
|
||||
import com.android.settings.core.SubSettingLauncher;
|
||||
import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
|
||||
import com.android.settings.dashboard.DashboardFragment;
|
||||
import com.android.settings.dashboard.profileselector.ProfileSelectFragment;
|
||||
import com.android.settings.deviceinfo.storage.AutomaticStorageManagementSwitchPreferenceController;
|
||||
import com.android.settings.deviceinfo.storage.CachedStorageValuesHelper;
|
||||
import com.android.settings.deviceinfo.storage.SecondaryUserController;
|
||||
import com.android.settings.deviceinfo.storage.StorageAsyncLoader;
|
||||
import com.android.settings.deviceinfo.storage.StorageEntry;
|
||||
import com.android.settings.deviceinfo.storage.StorageItemPreferenceController;
|
||||
import com.android.settings.deviceinfo.storage.StorageSelectionPreferenceController;
|
||||
import com.android.settings.deviceinfo.storage.StorageUsageProgressBarPreferenceController;
|
||||
import com.android.settings.deviceinfo.storage.UserIconLoader;
|
||||
import com.android.settings.deviceinfo.storage.VolumeSizesLoader;
|
||||
import com.android.settings.overlay.FeatureFactory;
|
||||
import com.android.settings.search.BaseSearchIndexProvider;
|
||||
import com.android.settings.widget.EntityHeaderController;
|
||||
import com.android.settingslib.applications.StorageStatsSource;
|
||||
import com.android.settingslib.core.AbstractPreferenceController;
|
||||
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
|
||||
import com.android.settingslib.deviceinfo.PrivateStorageInfo;
|
||||
import com.android.settingslib.deviceinfo.StorageManagerVolumeProvider;
|
||||
import com.android.settingslib.search.SearchIndexable;
|
||||
@@ -57,48 +73,184 @@ import com.android.settingslib.search.SearchIndexable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@SearchIndexable
|
||||
public class StorageDashboardFragment extends DashboardFragment
|
||||
implements
|
||||
LoaderManager.LoaderCallbacks<SparseArray<StorageAsyncLoader.AppsStorageResult>> {
|
||||
LoaderManager.LoaderCallbacks<SparseArray<StorageAsyncLoader.AppsStorageResult>>,
|
||||
Preference.OnPreferenceClickListener {
|
||||
private static final String TAG = "StorageDashboardFrag";
|
||||
private static final String SUMMARY_PREF_KEY = "storage_summary";
|
||||
private static final String FREE_UP_SPACE_PREF_KEY = "free_up_space";
|
||||
private static final String SELECTED_STORAGE_ENTRY_KEY = "selected_storage_entry_key";
|
||||
private static final int STORAGE_JOB_ID = 0;
|
||||
private static final int ICON_JOB_ID = 1;
|
||||
private static final int VOLUME_SIZE_JOB_ID = 2;
|
||||
|
||||
private VolumeInfo mVolume;
|
||||
private StorageManager mStorageManager;
|
||||
private final List<StorageEntry> mStorageEntries = new ArrayList<>();
|
||||
private StorageEntry mSelectedStorageEntry;
|
||||
private PrivateStorageInfo mStorageInfo;
|
||||
private SparseArray<StorageAsyncLoader.AppsStorageResult> mAppsResult;
|
||||
private CachedStorageValuesHelper mCachedStorageValuesHelper;
|
||||
|
||||
private StorageItemPreferenceController mPreferenceController;
|
||||
private PrivateVolumeOptionMenuController mOptionMenuController;
|
||||
private StorageSelectionPreferenceController mStorageSelectionController;
|
||||
private StorageUsageProgressBarPreferenceController mStorageUsageProgressBarController;
|
||||
private List<AbstractPreferenceController> mSecondaryUsers;
|
||||
private boolean mPersonalOnly;
|
||||
private Preference mFreeUpSpacePreference;
|
||||
|
||||
private final StorageEventListener mStorageEventListener = new StorageEventListener() {
|
||||
@Override
|
||||
public void onVolumeStateChanged(VolumeInfo volumeInfo, int oldState, int newState) {
|
||||
if (!isInteresting(volumeInfo)) {
|
||||
return;
|
||||
}
|
||||
|
||||
final StorageEntry storageEntry = new StorageEntry(getContext(), volumeInfo);
|
||||
switch (volumeInfo.getState()) {
|
||||
case VolumeInfo.STATE_MOUNTED:
|
||||
case VolumeInfo.STATE_MOUNTED_READ_ONLY:
|
||||
case VolumeInfo.STATE_UNMOUNTABLE:
|
||||
if (!mStorageEntries.contains(storageEntry)) {
|
||||
mStorageEntries.add(storageEntry);
|
||||
refreshUi();
|
||||
}
|
||||
break;
|
||||
case VolumeInfo.STATE_REMOVED:
|
||||
case VolumeInfo.STATE_UNMOUNTED:
|
||||
case VolumeInfo.STATE_BAD_REMOVAL:
|
||||
case VolumeInfo.STATE_EJECTING:
|
||||
if (mStorageEntries.remove(storageEntry)) {
|
||||
if (mSelectedStorageEntry.equals(storageEntry)) {
|
||||
mSelectedStorageEntry =
|
||||
StorageEntry.getDefaultInternalStorageEntry(getContext());
|
||||
}
|
||||
refreshUi();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// Do nothing.
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onVolumeRecordChanged(VolumeRecord volumeRecord) {
|
||||
final StorageEntry storageEntry = new StorageEntry(volumeRecord);
|
||||
if (!mStorageEntries.contains(storageEntry)) {
|
||||
mStorageEntries.add(storageEntry);
|
||||
refreshUi();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onVolumeForgotten(String fsUuid) {
|
||||
final StorageEntry storageEntry = new StorageEntry(
|
||||
new VolumeRecord(VolumeInfo.TYPE_PUBLIC, fsUuid));
|
||||
if (mStorageEntries.remove(storageEntry)) {
|
||||
if (mSelectedStorageEntry.equals(storageEntry)) {
|
||||
mSelectedStorageEntry =
|
||||
StorageEntry.getDefaultInternalStorageEntry(getContext());
|
||||
}
|
||||
refreshUi();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDiskScanned(DiskInfo disk, int volumeCount) {
|
||||
if (!isInteresting(disk)) {
|
||||
return;
|
||||
}
|
||||
final StorageEntry storageEntry = new StorageEntry(disk);
|
||||
if (!mStorageEntries.contains(storageEntry)) {
|
||||
mStorageEntries.add(storageEntry);
|
||||
refreshUi();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDiskDestroyed(DiskInfo disk) {
|
||||
final StorageEntry storageEntry = new StorageEntry(disk);
|
||||
if (mStorageEntries.remove(storageEntry)) {
|
||||
if (mSelectedStorageEntry.equals(storageEntry)) {
|
||||
mSelectedStorageEntry =
|
||||
StorageEntry.getDefaultInternalStorageEntry(getContext());
|
||||
}
|
||||
refreshUi();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private static boolean isInteresting(VolumeInfo volumeInfo) {
|
||||
switch (volumeInfo.getType()) {
|
||||
case VolumeInfo.TYPE_PRIVATE:
|
||||
case VolumeInfo.TYPE_PUBLIC:
|
||||
case VolumeInfo.TYPE_STUB:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Only interested in unsupported disk.
|
||||
private static boolean isInteresting(DiskInfo disk) {
|
||||
return disk.volumeCount == 0 && disk.size > 0;
|
||||
}
|
||||
|
||||
private void refreshUi() {
|
||||
mStorageSelectionController.setStorageEntries(mStorageEntries);
|
||||
mStorageSelectionController.setSelectedStorageEntry(mSelectedStorageEntry);
|
||||
mStorageUsageProgressBarController.setSelectedStorageEntry(mSelectedStorageEntry);
|
||||
|
||||
mOptionMenuController.setVolumeInfo(mSelectedStorageEntry.getVolumeInfo());
|
||||
|
||||
mPreferenceController.setVolume(mSelectedStorageEntry.getVolumeInfo());
|
||||
|
||||
if (mSelectedStorageEntry.isMounted()) {
|
||||
getLoaderManager().restartLoader(STORAGE_JOB_ID, Bundle.EMPTY, this);
|
||||
getLoaderManager()
|
||||
.restartLoader(VOLUME_SIZE_JOB_ID, Bundle.EMPTY, new VolumeSizeCallbacks());
|
||||
getLoaderManager().restartLoader(ICON_JOB_ID, Bundle.EMPTY, new IconLoaderCallbacks());
|
||||
} else {
|
||||
mPreferenceController.clearStorageSizeDisplay();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle icicle) {
|
||||
super.onCreate(icicle);
|
||||
|
||||
// Initialize the storage sizes that we can quickly calc.
|
||||
final Activity activity = getActivity();
|
||||
StorageManager sm = activity.getSystemService(StorageManager.class);
|
||||
mVolume = Utils.maybeInitializeVolume(sm, getArguments());
|
||||
mStorageManager = activity.getSystemService(StorageManager.class);
|
||||
mPersonalOnly = getArguments().getInt(ProfileSelectFragment.EXTRA_PROFILE)
|
||||
== ProfileSelectFragment.ProfileType.PERSONAL;
|
||||
if (mVolume == null) {
|
||||
activity.finish();
|
||||
return;
|
||||
|
||||
if (icicle == null) {
|
||||
final VolumeInfo specifiedVolumeInfo =
|
||||
Utils.maybeInitializeVolume(mStorageManager, getArguments());
|
||||
mSelectedStorageEntry = specifiedVolumeInfo == null
|
||||
? StorageEntry.getDefaultInternalStorageEntry(getContext())
|
||||
: new StorageEntry(getContext(), specifiedVolumeInfo);
|
||||
} else {
|
||||
mSelectedStorageEntry = icicle.getParcelable(SELECTED_STORAGE_ENTRY_KEY);
|
||||
}
|
||||
|
||||
initializePreference();
|
||||
initializeOptionsMenu(activity);
|
||||
}
|
||||
|
||||
private void initializePreference() {
|
||||
if (mPersonalOnly) {
|
||||
final Preference summary = getPreferenceScreen().findPreference(SUMMARY_PREF_KEY);
|
||||
if (summary != null) {
|
||||
summary.setVisible(false);
|
||||
}
|
||||
}
|
||||
mFreeUpSpacePreference = getPreferenceScreen().findPreference(FREE_UP_SPACE_PREF_KEY);
|
||||
mFreeUpSpacePreference.setOnPreferenceClickListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -106,12 +258,33 @@ public class StorageDashboardFragment extends DashboardFragment
|
||||
super.onAttach(context);
|
||||
use(AutomaticStorageManagementSwitchPreferenceController.class).setFragmentManager(
|
||||
getFragmentManager());
|
||||
mStorageSelectionController = use(StorageSelectionPreferenceController.class);
|
||||
mStorageSelectionController.setOnItemSelectedListener(storageEntry -> {
|
||||
mSelectedStorageEntry = storageEntry;
|
||||
refreshUi();
|
||||
|
||||
if (storageEntry.isUnsupportedDiskInfo() || storageEntry.isUnmountable()) {
|
||||
DiskInitFragment.show(this, R.string.storage_dialog_unmountable,
|
||||
storageEntry.getDiskId());
|
||||
} else if (storageEntry.isMissingVolumeRecord()) {
|
||||
final Bundle args = new Bundle();
|
||||
args.putString(VolumeRecord.EXTRA_FS_UUID, storageEntry.getFsUuid());
|
||||
new SubSettingLauncher(getContext())
|
||||
.setDestination(PrivateVolumeForget.class.getCanonicalName())
|
||||
.setTitleRes(R.string.storage_menu_forget)
|
||||
.setSourceMetricsCategory(getMetricsCategory())
|
||||
.setArguments(args)
|
||||
.launch();
|
||||
}
|
||||
});
|
||||
mStorageUsageProgressBarController = use(StorageUsageProgressBarPreferenceController.class);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void initializeOptionsMenu(Activity activity) {
|
||||
mOptionMenuController = new PrivateVolumeOptionMenuController(
|
||||
activity, mVolume, activity.getPackageManager());
|
||||
mOptionMenuController = new PrivateVolumeOptionMenuController(activity,
|
||||
mSelectedStorageEntry.getVolumeInfo(),
|
||||
activity.getPackageManager());
|
||||
getSettingsLifecycle().addObserver(mOptionMenuController);
|
||||
setHasOptionsMenu(true);
|
||||
activity.invalidateOptionsMenu();
|
||||
@@ -133,10 +306,37 @@ public class StorageDashboardFragment extends DashboardFragment
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
getLoaderManager().restartLoader(STORAGE_JOB_ID, Bundle.EMPTY, this);
|
||||
getLoaderManager()
|
||||
.restartLoader(VOLUME_SIZE_JOB_ID, Bundle.EMPTY, new VolumeSizeCallbacks());
|
||||
getLoaderManager().restartLoader(ICON_JOB_ID, Bundle.EMPTY, new IconLoaderCallbacks());
|
||||
|
||||
mStorageEntries.clear();
|
||||
mStorageEntries.addAll(mStorageManager.getVolumes().stream()
|
||||
.filter(volumeInfo -> isInteresting(volumeInfo))
|
||||
.map(volumeInfo -> new StorageEntry(getContext(), volumeInfo))
|
||||
.collect(Collectors.toList()));
|
||||
// Shows unsupported disks to give a chance to init.
|
||||
mStorageEntries.addAll(mStorageManager.getDisks().stream()
|
||||
.filter(disk -> isInteresting(disk))
|
||||
.map(disk -> new StorageEntry(disk))
|
||||
.collect(Collectors.toList()));
|
||||
// Shows missing private volumes.
|
||||
mStorageEntries.addAll(mStorageManager.getVolumeRecords().stream()
|
||||
.filter(volumeRecord -> volumeRecord.getType() == VolumeInfo.TYPE_PRIVATE
|
||||
&& mStorageManager.findVolumeByUuid(volumeRecord.getFsUuid()) == null)
|
||||
.map(volumeRecord -> new StorageEntry(volumeRecord))
|
||||
.collect(Collectors.toList()));
|
||||
refreshUi();
|
||||
mStorageManager.registerListener(mStorageEventListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
mStorageManager.unregisterListener(mStorageEventListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSaveInstanceState(Bundle outState) {
|
||||
outState.putParcelable(SELECTED_STORAGE_ENTRY_KEY, mSelectedStorageEntry);
|
||||
super.onSaveInstanceState(outState);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -148,7 +348,7 @@ public class StorageDashboardFragment extends DashboardFragment
|
||||
boolean stopLoading = false;
|
||||
if (mStorageInfo != null) {
|
||||
long privateUsedBytes = mStorageInfo.totalBytes - mStorageInfo.freeBytes;
|
||||
mPreferenceController.setVolume(mVolume);
|
||||
mPreferenceController.setVolume(mSelectedStorageEntry.getVolumeInfo());
|
||||
mPreferenceController.setUsedSize(privateUsedBytes);
|
||||
mPreferenceController.setTotalSize(mStorageInfo.totalBytes);
|
||||
for (int i = 0, size = mSecondaryUsers.size(); i < size; i++) {
|
||||
@@ -197,7 +397,7 @@ public class StorageDashboardFragment extends DashboardFragment
|
||||
|
||||
StorageManager sm = context.getSystemService(StorageManager.class);
|
||||
mPreferenceController = new StorageItemPreferenceController(context, this,
|
||||
mVolume, new StorageManagerVolumeProvider(sm));
|
||||
null /* volume */, new StorageManagerVolumeProvider(sm));
|
||||
controllers.add(mPreferenceController);
|
||||
|
||||
final UserManager userManager = context.getSystemService(UserManager.class);
|
||||
@@ -209,7 +409,7 @@ public class StorageDashboardFragment extends DashboardFragment
|
||||
|
||||
@VisibleForTesting
|
||||
protected void setVolume(VolumeInfo info) {
|
||||
mVolume = info;
|
||||
mSelectedStorageEntry = new StorageEntry(getContext(), info);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -260,7 +460,7 @@ public class StorageDashboardFragment extends DashboardFragment
|
||||
Bundle args) {
|
||||
final Context context = getContext();
|
||||
return new StorageAsyncLoader(context, context.getSystemService(UserManager.class),
|
||||
mVolume.fsUuid,
|
||||
mSelectedStorageEntry.getFsUuid(),
|
||||
new StorageStatsSource(context),
|
||||
context.getPackageManager());
|
||||
}
|
||||
@@ -277,6 +477,21 @@ public class StorageDashboardFragment extends DashboardFragment
|
||||
public void onLoaderReset(Loader<SparseArray<StorageAsyncLoader.AppsStorageResult>> loader) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPreferenceClick(Preference preference) {
|
||||
if (preference == mFreeUpSpacePreference) {
|
||||
final Context context = getContext();
|
||||
final MetricsFeatureProvider metricsFeatureProvider =
|
||||
FeatureFactory.getFactory(context).getMetricsFeatureProvider();
|
||||
metricsFeatureProvider.logClickedPreference(preference, getMetricsCategory());
|
||||
metricsFeatureProvider.action(context, SettingsEnums.STORAGE_FREE_UP_SPACE_NOW);
|
||||
final Intent intent = new Intent(StorageManager.ACTION_MANAGE_STORAGE);
|
||||
context.startActivity(intent);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public void setCachedStorageValuesHelper(CachedStorageValuesHelper helper) {
|
||||
mCachedStorageValuesHelper = helper;
|
||||
@@ -340,8 +555,9 @@ public class StorageDashboardFragment extends DashboardFragment
|
||||
}
|
||||
|
||||
private boolean isQuotaSupported() {
|
||||
final StorageStatsManager stats = getActivity().getSystemService(StorageStatsManager.class);
|
||||
return stats.isQuotaSupported(mVolume.fsUuid);
|
||||
return mSelectedStorageEntry.isMounted()
|
||||
&& getActivity().getSystemService(StorageStatsManager.class)
|
||||
.isQuotaSupported(mSelectedStorageEntry.getFsUuid());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -378,11 +594,12 @@ public class StorageDashboardFragment extends DashboardFragment
|
||||
implements LoaderManager.LoaderCallbacks<PrivateStorageInfo> {
|
||||
@Override
|
||||
public Loader<PrivateStorageInfo> onCreateLoader(int id, Bundle args) {
|
||||
Context context = getContext();
|
||||
StorageManager sm = context.getSystemService(StorageManager.class);
|
||||
StorageManagerVolumeProvider smvp = new StorageManagerVolumeProvider(sm);
|
||||
final Context context = getContext();
|
||||
final StorageManagerVolumeProvider smvp =
|
||||
new StorageManagerVolumeProvider(mStorageManager);
|
||||
final StorageStatsManager stats = context.getSystemService(StorageStatsManager.class);
|
||||
return new VolumeSizesLoader(context, smvp, stats, mVolume);
|
||||
return new VolumeSizesLoader(context, smvp, stats,
|
||||
mSelectedStorageEntry.getVolumeInfo());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -402,4 +619,52 @@ public class StorageDashboardFragment extends DashboardFragment
|
||||
onReceivedSizes();
|
||||
}
|
||||
}
|
||||
|
||||
/** A dialog which guides users to initialize a specified unsupported disk. */
|
||||
public static class DiskInitFragment extends InstrumentedDialogFragment {
|
||||
|
||||
private static final String TAG_DISK_INIT = "disk_init";
|
||||
|
||||
@Override
|
||||
public int getMetricsCategory() {
|
||||
return SettingsEnums.DIALOG_VOLUME_INIT;
|
||||
}
|
||||
|
||||
/** Shows the dialo for the specified diskId from DiskInfo. */
|
||||
public static void show(Fragment parent, int resId, String diskId) {
|
||||
final Bundle args = new Bundle();
|
||||
args.putInt(Intent.EXTRA_TEXT, resId);
|
||||
args.putString(DiskInfo.EXTRA_DISK_ID, diskId);
|
||||
|
||||
final DiskInitFragment dialog = new DiskInitFragment();
|
||||
dialog.setArguments(args);
|
||||
dialog.setTargetFragment(parent, 0);
|
||||
dialog.show(parent.getFragmentManager(), TAG_DISK_INIT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
final Context context = getActivity();
|
||||
final StorageManager storageManager = context.getSystemService(StorageManager.class);
|
||||
final int resId = getArguments().getInt(Intent.EXTRA_TEXT);
|
||||
final String diskId = getArguments().getString(DiskInfo.EXTRA_DISK_ID);
|
||||
final DiskInfo disk = storageManager.findDiskById(diskId);
|
||||
|
||||
final AlertDialog.Builder builder = new AlertDialog.Builder(context);
|
||||
builder.setMessage(TextUtils.expandTemplate(getText(resId), disk.getDescription()));
|
||||
|
||||
builder.setPositiveButton(R.string.storage_menu_set_up,
|
||||
new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
final Intent intent = new Intent(context, StorageWizardInit.class);
|
||||
intent.putExtra(DiskInfo.EXTRA_DISK_ID, diskId);
|
||||
startActivity(intent);
|
||||
}
|
||||
});
|
||||
builder.setNegativeButton(R.string.cancel, null);
|
||||
|
||||
return builder.create();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
283
src/com/android/settings/deviceinfo/storage/StorageEntry.java
Normal file
283
src/com/android/settings/deviceinfo/storage/StorageEntry.java
Normal file
@@ -0,0 +1,283 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.storage;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.content.Context;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.os.storage.DiskInfo;
|
||||
import android.os.storage.StorageManager;
|
||||
import android.os.storage.VolumeInfo;
|
||||
import android.os.storage.VolumeRecord;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* This object contains a {@link VolumeInfo} for a mountable storage or a {@link DiskInfo} for an
|
||||
* unsupported disk which is not able to be mounted automatically.
|
||||
*/
|
||||
public class StorageEntry implements Comparable<StorageEntry>, Parcelable {
|
||||
|
||||
private final VolumeInfo mVolumeInfo;
|
||||
private final DiskInfo mUnsupportedDiskInfo;
|
||||
private final VolumeRecord mMissingVolumeRecord;
|
||||
|
||||
private final String mVolumeInfoDescription;
|
||||
|
||||
public StorageEntry(@NonNull Context context, @NonNull VolumeInfo volumeInfo) {
|
||||
mVolumeInfo = volumeInfo;
|
||||
mUnsupportedDiskInfo = null;
|
||||
mMissingVolumeRecord = null;
|
||||
mVolumeInfoDescription = context.getSystemService(StorageManager.class)
|
||||
.getBestVolumeDescription(mVolumeInfo);
|
||||
}
|
||||
|
||||
public StorageEntry(@NonNull DiskInfo diskInfo) {
|
||||
mVolumeInfo = null;
|
||||
mUnsupportedDiskInfo = diskInfo;
|
||||
mMissingVolumeRecord = null;
|
||||
mVolumeInfoDescription = null;
|
||||
}
|
||||
|
||||
public StorageEntry(@NonNull VolumeRecord volumeRecord) {
|
||||
mVolumeInfo = null;
|
||||
mUnsupportedDiskInfo = null;
|
||||
mMissingVolumeRecord = volumeRecord;
|
||||
mVolumeInfoDescription = null;
|
||||
}
|
||||
|
||||
private StorageEntry(Parcel in) {
|
||||
mVolumeInfo = in.readParcelable(VolumeInfo.class.getClassLoader());
|
||||
mUnsupportedDiskInfo = in.readParcelable(DiskInfo.class.getClassLoader());
|
||||
mMissingVolumeRecord = in.readParcelable(VolumeRecord.class.getClassLoader());
|
||||
mVolumeInfoDescription = in.readString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel out, int flags) {
|
||||
out.writeParcelable(mVolumeInfo, 0 /* parcelableFlags */);
|
||||
out.writeParcelable(mUnsupportedDiskInfo, 0 /* parcelableFlags */);
|
||||
out.writeParcelable(mMissingVolumeRecord , 0 /* parcelableFlags */);
|
||||
out.writeString(mVolumeInfoDescription);
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<StorageEntry> CREATOR =
|
||||
new Parcelable.Creator<StorageEntry>() {
|
||||
public StorageEntry createFromParcel(Parcel in) {
|
||||
return new StorageEntry(in);
|
||||
}
|
||||
|
||||
public StorageEntry[] newArray(int size) {
|
||||
return new StorageEntry[size];
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (o == this) {
|
||||
return true;
|
||||
}
|
||||
if (!(o instanceof StorageEntry)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final StorageEntry StorageEntry = (StorageEntry) o;
|
||||
if (isVolumeInfo()) {
|
||||
return mVolumeInfo.equals(StorageEntry.mVolumeInfo);
|
||||
}
|
||||
if (isUnsupportedDiskInfo()) {
|
||||
return mUnsupportedDiskInfo.equals(StorageEntry.mUnsupportedDiskInfo);
|
||||
}
|
||||
return mMissingVolumeRecord.equals(StorageEntry.mMissingVolumeRecord);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
if (isVolumeInfo()) {
|
||||
return mVolumeInfo.hashCode();
|
||||
}
|
||||
if (isUnsupportedDiskInfo()) {
|
||||
return mUnsupportedDiskInfo.hashCode();
|
||||
}
|
||||
return mMissingVolumeRecord.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (isVolumeInfo()) {
|
||||
return mVolumeInfo.toString();
|
||||
}
|
||||
if (isUnsupportedDiskInfo()) {
|
||||
return mUnsupportedDiskInfo.toString();
|
||||
}
|
||||
return mMissingVolumeRecord.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(StorageEntry other) {
|
||||
if (isDefaultInternalStorage() && !other.isDefaultInternalStorage()) {
|
||||
return -1;
|
||||
}
|
||||
if (!isDefaultInternalStorage() && other.isDefaultInternalStorage()) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (isVolumeInfo() && !other.isVolumeInfo()) {
|
||||
return -1;
|
||||
}
|
||||
if (!isVolumeInfo() && other.isVolumeInfo()) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (isPrivate() && !other.isPrivate()) {
|
||||
return -1;
|
||||
}
|
||||
if (!isPrivate() && other.isPrivate()) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (isMounted() && !other.isMounted()) {
|
||||
return -1;
|
||||
}
|
||||
if (!isMounted() && other.isMounted()) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!isMissingVolumeRecord() && other.isMissingVolumeRecord()) {
|
||||
return -1;
|
||||
}
|
||||
if (isMissingVolumeRecord() && !other.isMissingVolumeRecord()) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (getDescription() == null) {
|
||||
return 1;
|
||||
}
|
||||
if (other.getDescription() == null) {
|
||||
return -1;
|
||||
}
|
||||
return getDescription().compareTo(other.getDescription());
|
||||
}
|
||||
|
||||
/** Returns default internal storage. */
|
||||
public static StorageEntry getDefaultInternalStorageEntry(Context context) {
|
||||
return new StorageEntry(context, context.getSystemService(StorageManager.class)
|
||||
.findVolumeById(VolumeInfo.ID_PRIVATE_INTERNAL));
|
||||
}
|
||||
|
||||
/** If it's a VolumeInfo. */
|
||||
public boolean isVolumeInfo() {
|
||||
return mVolumeInfo != null;
|
||||
}
|
||||
|
||||
/** If it's an unsupported DiskInfo. */
|
||||
public boolean isUnsupportedDiskInfo() {
|
||||
return mUnsupportedDiskInfo != null;
|
||||
}
|
||||
|
||||
/** If it's a missing VolumeRecord. */
|
||||
public boolean isMissingVolumeRecord() {
|
||||
return mMissingVolumeRecord != null;
|
||||
}
|
||||
|
||||
/** If it's a default internal storage. */
|
||||
public boolean isDefaultInternalStorage() {
|
||||
if (isVolumeInfo()) {
|
||||
return mVolumeInfo.getType() == VolumeInfo.TYPE_PRIVATE
|
||||
&& TextUtils.equals(mVolumeInfo.getId(), VolumeInfo.ID_PRIVATE_INTERNAL);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/** If it's a mounted storage. */
|
||||
public boolean isMounted() {
|
||||
return mVolumeInfo == null ? false : (mVolumeInfo.getState() == VolumeInfo.STATE_MOUNTED
|
||||
|| mVolumeInfo.getState() == VolumeInfo.STATE_MOUNTED_READ_ONLY);
|
||||
}
|
||||
|
||||
/** If it's an unmountable storage. */
|
||||
public boolean isUnmountable() {
|
||||
return mVolumeInfo == null ? false : mVolumeInfo.getState() == VolumeInfo.STATE_UNMOUNTABLE;
|
||||
}
|
||||
|
||||
/** If it's a private storage. */
|
||||
public boolean isPrivate() {
|
||||
return mVolumeInfo == null ? false : mVolumeInfo.getType() == VolumeInfo.TYPE_PRIVATE;
|
||||
}
|
||||
|
||||
/** Returns description. */
|
||||
public String getDescription() {
|
||||
if (isVolumeInfo()) {
|
||||
return mVolumeInfoDescription;
|
||||
}
|
||||
if (isUnsupportedDiskInfo()) {
|
||||
return mUnsupportedDiskInfo.getDescription();
|
||||
}
|
||||
return mMissingVolumeRecord.getNickname();
|
||||
}
|
||||
|
||||
/** Returns ID. */
|
||||
public String getId() {
|
||||
if (isVolumeInfo()) {
|
||||
return mVolumeInfo.getId();
|
||||
}
|
||||
if (isUnsupportedDiskInfo()) {
|
||||
return mUnsupportedDiskInfo.getId();
|
||||
}
|
||||
return mMissingVolumeRecord.getFsUuid();
|
||||
}
|
||||
|
||||
/** Returns disk ID. */
|
||||
public String getDiskId() {
|
||||
if (isVolumeInfo()) {
|
||||
return mVolumeInfo.getDiskId();
|
||||
}
|
||||
if (isUnsupportedDiskInfo()) {
|
||||
return mUnsupportedDiskInfo.getId();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/** Returns fsUuid. */
|
||||
public String getFsUuid() {
|
||||
if (isVolumeInfo()) {
|
||||
return mVolumeInfo.getFsUuid();
|
||||
}
|
||||
if (isUnsupportedDiskInfo()) {
|
||||
return null;
|
||||
}
|
||||
return mMissingVolumeRecord.getFsUuid();
|
||||
}
|
||||
|
||||
/** Returns root file if it's a VolumeInfo. */
|
||||
public File getPath() {
|
||||
return mVolumeInfo == null ? null : mVolumeInfo.getPath();
|
||||
}
|
||||
|
||||
/** Returns VolumeInfo of the StorageEntry. */
|
||||
public VolumeInfo getVolumeInfo() {
|
||||
return mVolumeInfo;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -158,6 +158,9 @@ public class StorageItemPreferenceController extends AbstractPreferenceControlle
|
||||
intent = getAppsIntent();
|
||||
break;
|
||||
case FILES_KEY:
|
||||
if (mVolume == null) {
|
||||
break;
|
||||
}
|
||||
intent = getFilesIntent();
|
||||
FeatureFactory.getFactory(mContext).getMetricsFeatureProvider().action(
|
||||
mContext, SettingsEnums.STORAGE_FILES);
|
||||
@@ -293,6 +296,17 @@ public class StorageItemPreferenceController extends AbstractPreferenceControlle
|
||||
mTotalSize = totalSizeBytes;
|
||||
}
|
||||
|
||||
/** Set storage size to 0 for each preference. */
|
||||
public void clearStorageSizeDisplay() {
|
||||
mPhotoPreference.setStorageSize(0L, 0L);
|
||||
mAudioPreference.setStorageSize(0L, 0L);
|
||||
mGamePreference.setStorageSize(0L, 0L);
|
||||
mMoviesPreference.setStorageSize(0L, 0L);
|
||||
mAppPreference.setStorageSize(0L, 0L);
|
||||
mFilePreference.setStorageSize(0L, 0L);
|
||||
mSystemPreference.setStorageSize(0L, 0L);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of keys used by this preference controller.
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.storage;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
|
||||
import com.android.settings.core.BasePreferenceController;
|
||||
import com.android.settingslib.widget.SettingsSpinnerPreference;
|
||||
import com.android.settingslib.widget.settingsspinner.SettingsSpinnerAdapter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Shows a spinner for users to select a storage volume.
|
||||
*/
|
||||
public class StorageSelectionPreferenceController extends BasePreferenceController implements
|
||||
AdapterView.OnItemSelectedListener {
|
||||
|
||||
@VisibleForTesting
|
||||
SettingsSpinnerPreference mSpinnerPreference;
|
||||
@VisibleForTesting
|
||||
StorageAdapter mStorageAdapter;
|
||||
|
||||
private final List<StorageEntry> mStorageEntries = new ArrayList<>();
|
||||
|
||||
/** The interface for spinner selection callback. */
|
||||
public interface OnItemSelectedListener {
|
||||
/** Callbacked when the spinner selection is changed. */
|
||||
void onItemSelected(StorageEntry storageEntry);
|
||||
}
|
||||
private OnItemSelectedListener mOnItemSelectedListener;
|
||||
|
||||
public StorageSelectionPreferenceController(Context context, String key) {
|
||||
super(context, key);
|
||||
|
||||
mStorageAdapter = new StorageAdapter(context);
|
||||
}
|
||||
|
||||
public void setOnItemSelectedListener(OnItemSelectedListener listener) {
|
||||
mOnItemSelectedListener = listener;
|
||||
}
|
||||
|
||||
/** Set the storages in the spinner. */
|
||||
public void setStorageEntries(List<StorageEntry> storageEntries) {
|
||||
mStorageAdapter.clear();
|
||||
mStorageEntries.clear();
|
||||
if (storageEntries == null || storageEntries.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
Collections.sort(mStorageEntries);
|
||||
mStorageEntries.addAll(storageEntries);
|
||||
mStorageAdapter.addAll(storageEntries);
|
||||
}
|
||||
|
||||
/** set selected storage in the spinner. */
|
||||
public void setSelectedStorageEntry(StorageEntry selectedStorageEntry) {
|
||||
if (mSpinnerPreference == null || !mStorageEntries.contains(selectedStorageEntry)) {
|
||||
return;
|
||||
}
|
||||
mSpinnerPreference.setSelection(mStorageAdapter.getPosition(selectedStorageEntry));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
return AVAILABLE_UNSEARCHABLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void displayPreference(PreferenceScreen screen) {
|
||||
mSpinnerPreference = screen.findPreference(getPreferenceKey());
|
||||
mSpinnerPreference.setAdapter(mStorageAdapter);
|
||||
mSpinnerPreference.setOnItemSelectedListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemSelected(AdapterView<?> arg0, View arg1, int position, long id) {
|
||||
if (mOnItemSelectedListener == null) {
|
||||
return;
|
||||
}
|
||||
mOnItemSelectedListener.onItemSelected(mStorageAdapter.getItem(position));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNothingSelected(AdapterView<?> arg0) {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
class StorageAdapter extends SettingsSpinnerAdapter<StorageEntry> {
|
||||
|
||||
StorageAdapter(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(int position, View view, ViewGroup parent) {
|
||||
if (view == null) {
|
||||
view = getDefaultView(position, view, parent);
|
||||
}
|
||||
|
||||
TextView textView = null;
|
||||
try {
|
||||
textView = (TextView) view;
|
||||
} catch (ClassCastException e) {
|
||||
throw new IllegalStateException("Default view should be a TextView, ", e);
|
||||
}
|
||||
textView.setText(getItem(position).getDescription());
|
||||
return textView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getDropDownView(int position, View view, ViewGroup parent) {
|
||||
if (view == null) {
|
||||
view = getDefaultDropDownView(position, view, parent);
|
||||
}
|
||||
|
||||
TextView textView = null;
|
||||
try {
|
||||
textView = (TextView) view;
|
||||
} catch (ClassCastException e) {
|
||||
throw new IllegalStateException("Default drop down view should be a TextView, ", e);
|
||||
}
|
||||
textView.setText(getItem(position).getDescription());
|
||||
return textView;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.storage;
|
||||
|
||||
import android.app.usage.StorageStatsManager;
|
||||
import android.content.Context;
|
||||
import android.text.format.Formatter;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
|
||||
import com.android.settings.R;
|
||||
import com.android.settings.core.BasePreferenceController;
|
||||
import com.android.settingslib.utils.ThreadUtils;
|
||||
import com.android.settingslib.widget.UsageProgressBarPreference;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Shows storage summary and progress.
|
||||
*/
|
||||
public class StorageUsageProgressBarPreferenceController extends BasePreferenceController {
|
||||
|
||||
private static final String TAG = "StorageProgressCtrl";
|
||||
|
||||
private final StorageStatsManager mStorageStatsManager;
|
||||
@VisibleForTesting
|
||||
long mUsedBytes;
|
||||
@VisibleForTesting
|
||||
long mTotalBytes;
|
||||
private UsageProgressBarPreference mUsageProgressBarPreference;
|
||||
private StorageEntry mStorageEntry;
|
||||
|
||||
public StorageUsageProgressBarPreferenceController(Context context, String key) {
|
||||
super(context, key);
|
||||
|
||||
mStorageStatsManager = context.getSystemService(StorageStatsManager.class);
|
||||
}
|
||||
|
||||
/** Set StorageEntry to display. */
|
||||
public void setSelectedStorageEntry(StorageEntry storageEntry) {
|
||||
mStorageEntry = storageEntry;
|
||||
getStorageStatsAndUpdateUi();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAvailabilityStatus() {
|
||||
return AVAILABLE_UNSEARCHABLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void displayPreference(PreferenceScreen screen) {
|
||||
mUsageProgressBarPreference = screen.findPreference(getPreferenceKey());
|
||||
getStorageStatsAndUpdateUi();
|
||||
}
|
||||
|
||||
private void getStorageStatsAndUpdateUi() {
|
||||
ThreadUtils.postOnBackgroundThread(() -> {
|
||||
try {
|
||||
if (mStorageEntry == null || !mStorageEntry.isMounted()) {
|
||||
throw new IOException();
|
||||
}
|
||||
|
||||
if (mStorageEntry.isPrivate()) {
|
||||
// StorageStatsManager can only query private storages.
|
||||
mTotalBytes = mStorageStatsManager.getTotalBytes(mStorageEntry.getFsUuid());
|
||||
mUsedBytes = mTotalBytes
|
||||
- mStorageStatsManager.getFreeBytes(mStorageEntry.getFsUuid());
|
||||
} else {
|
||||
final File rootFile = mStorageEntry.getPath();
|
||||
if (rootFile == null) {
|
||||
Log.d(TAG, "Mounted public storage has null root path: " + mStorageEntry);
|
||||
throw new IOException();
|
||||
}
|
||||
mTotalBytes = rootFile.getTotalSpace();
|
||||
mUsedBytes = mTotalBytes - rootFile.getFreeSpace();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
// The storage device isn't present.
|
||||
mTotalBytes = 0;
|
||||
mUsedBytes = 0;
|
||||
}
|
||||
|
||||
if (mUsageProgressBarPreference == null) {
|
||||
return;
|
||||
}
|
||||
ThreadUtils.postOnMainThread(() ->
|
||||
updateState(mUsageProgressBarPreference)
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateState(Preference preference) {
|
||||
mUsageProgressBarPreference.setUsageSummary(
|
||||
getStorageSummary(R.string.storage_usage_summary, mUsedBytes));
|
||||
mUsageProgressBarPreference.setTotalSummary(
|
||||
getStorageSummary(R.string.storage_total_summary, mTotalBytes));
|
||||
mUsageProgressBarPreference.setPercent(mUsedBytes, mTotalBytes);
|
||||
}
|
||||
|
||||
private String getStorageSummary(int resId, long bytes) {
|
||||
final Formatter.BytesResult result = Formatter.formatBytes(mContext.getResources(),
|
||||
bytes, 0);
|
||||
return mContext.getString(resId, result.value, result.units);
|
||||
}
|
||||
}
|
||||
@@ -26,6 +26,7 @@ import com.android.settingslib.deviceinfo.PrivateStorageInfo;
|
||||
import com.android.settingslib.deviceinfo.StorageVolumeProvider;
|
||||
import com.android.settingslib.utils.AsyncLoaderCompat;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
public class VolumeSizesLoader extends AsyncLoaderCompat<PrivateStorageInfo> {
|
||||
@@ -49,6 +50,11 @@ public class VolumeSizesLoader extends AsyncLoaderCompat<PrivateStorageInfo> {
|
||||
|
||||
@Override
|
||||
public PrivateStorageInfo loadInBackground() {
|
||||
if (mVolume == null || (mVolume.getState() != VolumeInfo.STATE_MOUNTED
|
||||
&& mVolume.getState() != VolumeInfo.STATE_MOUNTED_READ_ONLY)) {
|
||||
return new PrivateStorageInfo(0L /* freeBytes */, 0L /* totalBytes */);
|
||||
}
|
||||
|
||||
PrivateStorageInfo volumeSizes;
|
||||
try {
|
||||
volumeSizes = getVolumeSize(mVolumeProvider, mStats, mVolume);
|
||||
@@ -62,8 +68,14 @@ public class VolumeSizesLoader extends AsyncLoaderCompat<PrivateStorageInfo> {
|
||||
static PrivateStorageInfo getVolumeSize(
|
||||
StorageVolumeProvider storageVolumeProvider, StorageStatsManager stats, VolumeInfo info)
|
||||
throws IOException {
|
||||
long privateTotalBytes = storageVolumeProvider.getTotalBytes(stats, info);
|
||||
long privateFreeBytes = storageVolumeProvider.getFreeBytes(stats, info);
|
||||
return new PrivateStorageInfo(privateFreeBytes, privateTotalBytes);
|
||||
if (info.getType() == VolumeInfo.TYPE_PRIVATE) {
|
||||
return new PrivateStorageInfo(storageVolumeProvider.getFreeBytes(stats, info),
|
||||
storageVolumeProvider.getTotalBytes(stats, info));
|
||||
}
|
||||
// TODO(b/174964885): It's confusing to use PrivateStorageInfo for a public storage,
|
||||
// replace it with a new naming or a different object.
|
||||
final File rootFile = info.getPath();
|
||||
return rootFile == null ? new PrivateStorageInfo(0L /* freeBytes */, 0L /* totalBytes */)
|
||||
: new PrivateStorageInfo(rootFile.getFreeSpace(), rootFile.getTotalSpace());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user