Loading res/drawable/ic_trash_can.xml +2 −1 Original line number Diff line number Diff line Loading @@ -18,7 +18,8 @@ android:width="24dp" android:height="24dp" android:viewportWidth="24" android:viewportHeight="24"> android:viewportHeight="24" android:tint="?android:attr/colorControlNormal"> <path android:pathData="M15,3V4H20V6H19V19C19,20.1 18.1,21 17,21H7C5.9,21 5,20.1 5,19V6H4V4H9V3H15ZM7,19H17V6H7V19ZM9,8H11V17H9V8ZM15,8H13V17H15V8Z" android:fillColor="#5F6368" Loading src/com/android/settings/deviceinfo/StorageItemPreference.java +2 −10 Original line number Diff line number Diff line Loading @@ -17,8 +17,6 @@ package com.android.settings.deviceinfo; import android.content.Context; import android.text.TextUtils; import android.text.format.Formatter; import android.util.AttributeSet; import android.widget.ProgressBar; Loading @@ -26,6 +24,7 @@ import androidx.preference.Preference; import androidx.preference.PreferenceViewHolder; import com.android.settings.R; import com.android.settings.deviceinfo.storage.StorageUtils; public class StorageItemPreference extends Preference { public int userHandle; Loading @@ -49,7 +48,7 @@ public class StorageItemPreference extends Preference { public void setStorageSize(long size, long total) { mStorageSize = size; setSummary(getStorageSummary(size)); setSummary(StorageUtils.getStorageSizeLabel(getContext(), size)); if (total == 0) { mProgressPercent = 0; Loading Loading @@ -77,11 +76,4 @@ public class StorageItemPreference extends Preference { updateProgressBar(); super.onBindViewHolder(view); } private String getStorageSummary(long bytes) { final Formatter.BytesResult result = Formatter.formatBytes(getContext().getResources(), bytes, Formatter.FLAG_SHORTER); return TextUtils.expandTemplate(getContext().getText(R.string.storage_size_large), result.value, result.units).toString(); } } src/com/android/settings/deviceinfo/storage/EmptyTrashFragment.java +65 −8 Original line number Diff line number Diff line Loading @@ -18,25 +18,54 @@ package com.android.settings.deviceinfo.storage; import android.app.Dialog; import android.app.settings.SettingsEnums; import android.content.Context; import android.content.pm.PackageManager.NameNotFoundException; import android.os.Bundle; import android.os.UserHandle; import android.provider.MediaStore; import android.util.Log; import androidx.appcompat.app.AlertDialog; import androidx.fragment.app.Fragment; import com.android.settings.R; import com.android.settings.core.instrumentation.InstrumentedDialogFragment; import com.android.settingslib.utils.ThreadUtils; /** * Dialog asks if users want to empty trash files. * TODO(b/189388449): Shows "Deleting..." and disables Trash category while deleting trash files. */ public class EmptyTrashFragment extends InstrumentedDialogFragment { private static final String TAG = "EmptyTrashFragment"; private static final String TAG_EMPTY_TRASH = "empty_trash"; private final Fragment mParentFragment; private final int mUserId; private final long mTrashSize; private final OnEmptyTrashCompleteListener mOnEmptyTrashCompleteListener; /** The listener to receive empty trash complete callback event. */ public interface OnEmptyTrashCompleteListener { /** The empty trash complete callback. */ void onEmptyTrashComplete(); } public EmptyTrashFragment(Fragment parent, int userId, long trashSize, OnEmptyTrashCompleteListener onEmptyTrashCompleteListener) { super(); mParentFragment = parent; setTargetFragment(mParentFragment, 0 /* requestCode */); mUserId = userId; mTrashSize = trashSize; mOnEmptyTrashCompleteListener = onEmptyTrashCompleteListener; } /** Shows the empty trash dialog. */ public static void show(Fragment parent) { final EmptyTrashFragment dialog = new EmptyTrashFragment(); dialog.setTargetFragment(parent, 0 /* requestCode */); dialog.show(parent.getFragmentManager(), TAG_EMPTY_TRASH); public void show() { show(mParentFragment.getFragmentManager(), TAG_EMPTY_TRASH); } @Override Loading @@ -48,10 +77,38 @@ public class EmptyTrashFragment extends InstrumentedDialogFragment { public Dialog onCreateDialog(Bundle savedInstanceState) { final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); return builder.setTitle(R.string.storage_trash_dialog_title) .setMessage(R.string.storage_trash_dialog_ask_message) .setPositiveButton(R.string.storage_trash_dialog_confirm, (dialog, which) -> { // TODO(170918505): Implement the logic in worker thread. }).setNegativeButton(android.R.string.cancel, null) .setMessage(getActivity().getString(R.string.storage_trash_dialog_ask_message, StorageUtils.getStorageSizeLabel(getActivity(), mTrashSize))) .setPositiveButton(R.string.storage_trash_dialog_confirm, (dialog, which) -> emptyTrashAsync()) .setNegativeButton(android.R.string.cancel, null) .create(); } private void emptyTrashAsync() { final Context context = getActivity(); final Context perUserContext; try { perUserContext = context.createPackageContextAsUser( context.getApplicationContext().getPackageName(), 0 /* flags= */, UserHandle.of(mUserId)); } catch (NameNotFoundException e) { Log.e(TAG, "Not able to get Context for user ID " + mUserId); return; } final Bundle trashQueryArgs = new Bundle(); trashQueryArgs.putInt(MediaStore.QUERY_ARG_MATCH_TRASHED, MediaStore.MATCH_ONLY); ThreadUtils.postOnBackgroundThread(() -> { perUserContext.getContentResolver().delete( MediaStore.Files.getContentUri(MediaStore.VOLUME_EXTERNAL), trashQueryArgs); if (mOnEmptyTrashCompleteListener == null) { return; } ThreadUtils.postOnMainThread( () -> mOnEmptyTrashCompleteListener.onEmptyTrashComplete()); }); } } src/com/android/settings/deviceinfo/storage/StorageItemPreferenceController.java +22 −5 Original line number Diff line number Diff line Loading @@ -32,6 +32,7 @@ import android.os.UserManager; import android.os.storage.VolumeInfo; import android.util.Log; import android.util.SparseArray; import android.widget.Toast; import androidx.annotation.VisibleForTesting; import androidx.fragment.app.Fragment; Loading Loading @@ -64,7 +65,8 @@ import java.util.Map; * categorization breakdown. */ public class StorageItemPreferenceController extends AbstractPreferenceController implements PreferenceControllerMixin { PreferenceControllerMixin, EmptyTrashFragment.OnEmptyTrashCompleteListener { private static final String TAG = "StorageItemPreference"; private static final String SYSTEM_FRAGMENT_TAG = "SystemInfo"; Loading Loading @@ -256,8 +258,7 @@ public class StorageItemPreferenceController extends AbstractPreferenceControlle mGamesPreference.setVisible(privateStoragePreferencesVisible); mDocumentsAndOtherPreference.setVisible(privateStoragePreferencesVisible); mSystemPreference.setVisible(privateStoragePreferencesVisible); // TODO(b/170918505): Shows trash category after trash category feature complete. mTrashPreference.setVisible(false); mTrashPreference.setVisible(privateStoragePreferencesVisible); if (privateStoragePreferencesVisible) { final VolumeInfo sharedVolume = mSvp.findEmulatedForPrivate(mVolume); Loading Loading @@ -460,13 +461,29 @@ public class StorageItemPreferenceController extends AbstractPreferenceControlle private void launchTrashIntent() { final Intent intent = new Intent("android.settings.VIEW_TRASH"); if (intent.resolveActivity(mPackageManager) == null) { EmptyTrashFragment.show(mFragment); if (mPackageManager.resolveActivityAsUser(intent, 0 /* flags */, mUserId) == null) { final long trashSize = mTrashPreference.getStorageSize(); if (trashSize > 0) { new EmptyTrashFragment(mFragment, mUserId, trashSize, this /* onEmptyTrashCompleteListener */).show(); } else { Toast.makeText(mContext, R.string.storage_trash_dialog_empty_message, Toast.LENGTH_SHORT).show(); } } else { mContext.startActivityAsUser(intent, new UserHandle(mUserId)); } } @Override public void onEmptyTrashComplete() { if (mTrashPreference == null) { return; } mTrashPreference.setStorageSize(0, mTotalSize); updatePrivateStorageCategoryPreferencesOrder(); } private static long totalValues(StorageMeasurement.MeasurementDetails details, int userId, String... keys) { long total = 0; Loading src/com/android/settings/deviceinfo/storage/StorageUtils.java +10 −0 Original line number Diff line number Diff line Loading @@ -26,6 +26,8 @@ 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 android.text.format.Formatter; import android.util.Log; import android.widget.Toast; Loading Loading @@ -115,6 +117,14 @@ public class StorageUtils { .launch(); } /** Returns size label of changing units. (e.g., 1kB, 2MB, 3GB) */ public static String getStorageSizeLabel(Context context, long bytes) { final Formatter.BytesResult result = Formatter.formatBytes(context.getResources(), bytes, Formatter.FLAG_SHORTER); return TextUtils.expandTemplate(context.getText(R.string.storage_size_large), result.value, result.units).toString(); } /** An AsyncTask to unmount a specified volume. */ public static class UnmountTask extends AsyncTask<Void, Void, Exception> { private final Context mContext; Loading Loading
res/drawable/ic_trash_can.xml +2 −1 Original line number Diff line number Diff line Loading @@ -18,7 +18,8 @@ android:width="24dp" android:height="24dp" android:viewportWidth="24" android:viewportHeight="24"> android:viewportHeight="24" android:tint="?android:attr/colorControlNormal"> <path android:pathData="M15,3V4H20V6H19V19C19,20.1 18.1,21 17,21H7C5.9,21 5,20.1 5,19V6H4V4H9V3H15ZM7,19H17V6H7V19ZM9,8H11V17H9V8ZM15,8H13V17H15V8Z" android:fillColor="#5F6368" Loading
src/com/android/settings/deviceinfo/StorageItemPreference.java +2 −10 Original line number Diff line number Diff line Loading @@ -17,8 +17,6 @@ package com.android.settings.deviceinfo; import android.content.Context; import android.text.TextUtils; import android.text.format.Formatter; import android.util.AttributeSet; import android.widget.ProgressBar; Loading @@ -26,6 +24,7 @@ import androidx.preference.Preference; import androidx.preference.PreferenceViewHolder; import com.android.settings.R; import com.android.settings.deviceinfo.storage.StorageUtils; public class StorageItemPreference extends Preference { public int userHandle; Loading @@ -49,7 +48,7 @@ public class StorageItemPreference extends Preference { public void setStorageSize(long size, long total) { mStorageSize = size; setSummary(getStorageSummary(size)); setSummary(StorageUtils.getStorageSizeLabel(getContext(), size)); if (total == 0) { mProgressPercent = 0; Loading Loading @@ -77,11 +76,4 @@ public class StorageItemPreference extends Preference { updateProgressBar(); super.onBindViewHolder(view); } private String getStorageSummary(long bytes) { final Formatter.BytesResult result = Formatter.formatBytes(getContext().getResources(), bytes, Formatter.FLAG_SHORTER); return TextUtils.expandTemplate(getContext().getText(R.string.storage_size_large), result.value, result.units).toString(); } }
src/com/android/settings/deviceinfo/storage/EmptyTrashFragment.java +65 −8 Original line number Diff line number Diff line Loading @@ -18,25 +18,54 @@ package com.android.settings.deviceinfo.storage; import android.app.Dialog; import android.app.settings.SettingsEnums; import android.content.Context; import android.content.pm.PackageManager.NameNotFoundException; import android.os.Bundle; import android.os.UserHandle; import android.provider.MediaStore; import android.util.Log; import androidx.appcompat.app.AlertDialog; import androidx.fragment.app.Fragment; import com.android.settings.R; import com.android.settings.core.instrumentation.InstrumentedDialogFragment; import com.android.settingslib.utils.ThreadUtils; /** * Dialog asks if users want to empty trash files. * TODO(b/189388449): Shows "Deleting..." and disables Trash category while deleting trash files. */ public class EmptyTrashFragment extends InstrumentedDialogFragment { private static final String TAG = "EmptyTrashFragment"; private static final String TAG_EMPTY_TRASH = "empty_trash"; private final Fragment mParentFragment; private final int mUserId; private final long mTrashSize; private final OnEmptyTrashCompleteListener mOnEmptyTrashCompleteListener; /** The listener to receive empty trash complete callback event. */ public interface OnEmptyTrashCompleteListener { /** The empty trash complete callback. */ void onEmptyTrashComplete(); } public EmptyTrashFragment(Fragment parent, int userId, long trashSize, OnEmptyTrashCompleteListener onEmptyTrashCompleteListener) { super(); mParentFragment = parent; setTargetFragment(mParentFragment, 0 /* requestCode */); mUserId = userId; mTrashSize = trashSize; mOnEmptyTrashCompleteListener = onEmptyTrashCompleteListener; } /** Shows the empty trash dialog. */ public static void show(Fragment parent) { final EmptyTrashFragment dialog = new EmptyTrashFragment(); dialog.setTargetFragment(parent, 0 /* requestCode */); dialog.show(parent.getFragmentManager(), TAG_EMPTY_TRASH); public void show() { show(mParentFragment.getFragmentManager(), TAG_EMPTY_TRASH); } @Override Loading @@ -48,10 +77,38 @@ public class EmptyTrashFragment extends InstrumentedDialogFragment { public Dialog onCreateDialog(Bundle savedInstanceState) { final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); return builder.setTitle(R.string.storage_trash_dialog_title) .setMessage(R.string.storage_trash_dialog_ask_message) .setPositiveButton(R.string.storage_trash_dialog_confirm, (dialog, which) -> { // TODO(170918505): Implement the logic in worker thread. }).setNegativeButton(android.R.string.cancel, null) .setMessage(getActivity().getString(R.string.storage_trash_dialog_ask_message, StorageUtils.getStorageSizeLabel(getActivity(), mTrashSize))) .setPositiveButton(R.string.storage_trash_dialog_confirm, (dialog, which) -> emptyTrashAsync()) .setNegativeButton(android.R.string.cancel, null) .create(); } private void emptyTrashAsync() { final Context context = getActivity(); final Context perUserContext; try { perUserContext = context.createPackageContextAsUser( context.getApplicationContext().getPackageName(), 0 /* flags= */, UserHandle.of(mUserId)); } catch (NameNotFoundException e) { Log.e(TAG, "Not able to get Context for user ID " + mUserId); return; } final Bundle trashQueryArgs = new Bundle(); trashQueryArgs.putInt(MediaStore.QUERY_ARG_MATCH_TRASHED, MediaStore.MATCH_ONLY); ThreadUtils.postOnBackgroundThread(() -> { perUserContext.getContentResolver().delete( MediaStore.Files.getContentUri(MediaStore.VOLUME_EXTERNAL), trashQueryArgs); if (mOnEmptyTrashCompleteListener == null) { return; } ThreadUtils.postOnMainThread( () -> mOnEmptyTrashCompleteListener.onEmptyTrashComplete()); }); } }
src/com/android/settings/deviceinfo/storage/StorageItemPreferenceController.java +22 −5 Original line number Diff line number Diff line Loading @@ -32,6 +32,7 @@ import android.os.UserManager; import android.os.storage.VolumeInfo; import android.util.Log; import android.util.SparseArray; import android.widget.Toast; import androidx.annotation.VisibleForTesting; import androidx.fragment.app.Fragment; Loading Loading @@ -64,7 +65,8 @@ import java.util.Map; * categorization breakdown. */ public class StorageItemPreferenceController extends AbstractPreferenceController implements PreferenceControllerMixin { PreferenceControllerMixin, EmptyTrashFragment.OnEmptyTrashCompleteListener { private static final String TAG = "StorageItemPreference"; private static final String SYSTEM_FRAGMENT_TAG = "SystemInfo"; Loading Loading @@ -256,8 +258,7 @@ public class StorageItemPreferenceController extends AbstractPreferenceControlle mGamesPreference.setVisible(privateStoragePreferencesVisible); mDocumentsAndOtherPreference.setVisible(privateStoragePreferencesVisible); mSystemPreference.setVisible(privateStoragePreferencesVisible); // TODO(b/170918505): Shows trash category after trash category feature complete. mTrashPreference.setVisible(false); mTrashPreference.setVisible(privateStoragePreferencesVisible); if (privateStoragePreferencesVisible) { final VolumeInfo sharedVolume = mSvp.findEmulatedForPrivate(mVolume); Loading Loading @@ -460,13 +461,29 @@ public class StorageItemPreferenceController extends AbstractPreferenceControlle private void launchTrashIntent() { final Intent intent = new Intent("android.settings.VIEW_TRASH"); if (intent.resolveActivity(mPackageManager) == null) { EmptyTrashFragment.show(mFragment); if (mPackageManager.resolveActivityAsUser(intent, 0 /* flags */, mUserId) == null) { final long trashSize = mTrashPreference.getStorageSize(); if (trashSize > 0) { new EmptyTrashFragment(mFragment, mUserId, trashSize, this /* onEmptyTrashCompleteListener */).show(); } else { Toast.makeText(mContext, R.string.storage_trash_dialog_empty_message, Toast.LENGTH_SHORT).show(); } } else { mContext.startActivityAsUser(intent, new UserHandle(mUserId)); } } @Override public void onEmptyTrashComplete() { if (mTrashPreference == null) { return; } mTrashPreference.setStorageSize(0, mTotalSize); updatePrivateStorageCategoryPreferencesOrder(); } private static long totalValues(StorageMeasurement.MeasurementDetails details, int userId, String... keys) { long total = 0; Loading
src/com/android/settings/deviceinfo/storage/StorageUtils.java +10 −0 Original line number Diff line number Diff line Loading @@ -26,6 +26,8 @@ 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 android.text.format.Formatter; import android.util.Log; import android.widget.Toast; Loading Loading @@ -115,6 +117,14 @@ public class StorageUtils { .launch(); } /** Returns size label of changing units. (e.g., 1kB, 2MB, 3GB) */ public static String getStorageSizeLabel(Context context, long bytes) { final Formatter.BytesResult result = Formatter.formatBytes(context.getResources(), bytes, Formatter.FLAG_SHORTER); return TextUtils.expandTemplate(context.getText(R.string.storage_size_large), result.value, result.units).toString(); } /** An AsyncTask to unmount a specified volume. */ public static class UnmountTask extends AsyncTask<Void, Void, Exception> { private final Context mContext; Loading