From f4329ada0026b9048591caf0dc8cff373621e2ff Mon Sep 17 00:00:00 2001 From: alukin Date: Tue, 12 Mar 2024 16:30:24 +0000 Subject: [PATCH] Split System category Splitting System category in Settings > Storage into "Android 14" and "Temporary system files". Android 14 is calculated as StorageStatsManager#getTotalBytes - (size of /data partition). Basically it's the size of all partitions except for the userdata. It also includes the storage rounding which we do to display a nice round storage size (128GB, 256GB, etc). Temporary System Files serves as "Everything else" category that represents all the used storage that didn't fall under any other category. It's the same as how currently "System" category works. Bug: 309801699 Test: atest StorageItemPreferenceControllerTest Test: atest StorageCacheHelperTest Change-Id: Ifae5819bf1d7a1a675df1fa67bd6dcdfa074b584 --- res/drawable/ic_android_vd_theme_24.xml | 26 +++++++++++++ res/drawable/ic_database_vd_theme_24.xml | 25 ++++++++++++ res/xml/storage_category_fragment.xml | 28 +++++++++---- res/xml/storage_dashboard_fragment.xml | 28 +++++++++---- .../storage/StorageAsyncLoader.java | 14 +++++++ .../storage/StorageCacheHelper.java | 4 ++ .../StorageItemPreferenceController.java | 39 +++++++++++++++++-- .../deviceinfo/storage/StorageUtils.java | 33 ++++++++++++++-- .../storage/StorageCacheHelperTest.java | 3 ++ .../StorageItemPreferenceControllerTest.java | 26 ++++++++++++- 10 files changed, 201 insertions(+), 25 deletions(-) create mode 100644 res/drawable/ic_android_vd_theme_24.xml create mode 100644 res/drawable/ic_database_vd_theme_24.xml diff --git a/res/drawable/ic_android_vd_theme_24.xml b/res/drawable/ic_android_vd_theme_24.xml new file mode 100644 index 00000000000..65812090007 --- /dev/null +++ b/res/drawable/ic_android_vd_theme_24.xml @@ -0,0 +1,26 @@ + + + + + diff --git a/res/drawable/ic_database_vd_theme_24.xml b/res/drawable/ic_database_vd_theme_24.xml new file mode 100644 index 00000000000..713a65e9c57 --- /dev/null +++ b/res/drawable/ic_database_vd_theme_24.xml @@ -0,0 +1,25 @@ + + + + diff --git a/res/xml/storage_category_fragment.xml b/res/xml/storage_category_fragment.xml index 2c9588938a2..58bd89138df 100644 --- a/res/xml/storage_category_fragment.xml +++ b/res/xml/storage_category_fragment.xml @@ -61,19 +61,31 @@ android:title="@string/storage_documents_and_other" android:icon="@drawable/ic_folder_vd_theme_24" android:order="106"/> - - + android:order="107"/> + + + + + + android:order="204" /> diff --git a/res/xml/storage_dashboard_fragment.xml b/res/xml/storage_dashboard_fragment.xml index 7c0f3a6d195..fd866ad8604 100644 --- a/res/xml/storage_dashboard_fragment.xml +++ b/res/xml/storage_dashboard_fragment.xml @@ -80,19 +80,31 @@ android:title="@string/storage_documents_and_other" android:icon="@drawable/ic_folder_vd_theme_24" android:order="106"/> - - + android:order="107"/> + + + + + + android:order="204" /> diff --git a/src/com/android/settings/deviceinfo/storage/StorageAsyncLoader.java b/src/com/android/settings/deviceinfo/storage/StorageAsyncLoader.java index 54935ecf4de..4906cf2d8d8 100644 --- a/src/com/android/settings/deviceinfo/storage/StorageAsyncLoader.java +++ b/src/com/android/settings/deviceinfo/storage/StorageAsyncLoader.java @@ -30,8 +30,10 @@ import android.content.pm.UserInfo; import android.database.Cursor; import android.net.Uri; import android.os.Bundle; +import android.os.Environment; import android.os.UserHandle; import android.os.UserManager; +import android.os.storage.StorageManager; import android.provider.MediaStore; import android.provider.MediaStore.Files.FileColumns; import android.provider.MediaStore.MediaColumns; @@ -94,6 +96,7 @@ public class StorageAsyncLoader media /* queryArgs */); result.audioSize = getFilesSize(info.id, MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, media /* queryArgs */); + result.systemSize = getSystemSize(); final Bundle documentsAndOtherQueryArgs = new Bundle(); documentsAndOtherQueryArgs.putString(ContentResolver.QUERY_ARG_SQL_SELECTION, @@ -140,6 +143,16 @@ public class StorageAsyncLoader } } + private long getSystemSize() { + try { + return mStatsManager.getTotalBytes(StorageManager.UUID_DEFAULT) + - Environment.getDataDirectory().getTotalSpace(); + } catch (IOException e) { + Log.e(TAG, "Exception in calculating System category size", e); + return 0; + } + } + private StorageResult getAppsAndGamesSize(int userId) { Log.d(TAG, "Loading apps"); final List applicationInfos = @@ -225,6 +238,7 @@ public class StorageAsyncLoader public long videosSize; public long documentsAndOtherSize; public long trashSize; + public long systemSize; public long cacheSize; public long duplicateCodeSize; diff --git a/src/com/android/settings/deviceinfo/storage/StorageCacheHelper.java b/src/com/android/settings/deviceinfo/storage/StorageCacheHelper.java index e6da454f2f1..50690cb0791 100644 --- a/src/com/android/settings/deviceinfo/storage/StorageCacheHelper.java +++ b/src/com/android/settings/deviceinfo/storage/StorageCacheHelper.java @@ -35,6 +35,7 @@ public class StorageCacheHelper { private static final String DOCUMENTS_AND_OTHER_SIZE_KEY = "documents_and_other_size_key"; private static final String TRASH_SIZE_KEY = "trash_size_key"; private static final String SYSTEM_SIZE_KEY = "system_size_key"; + private static final String TEMPORARY_FILES_SIZE_KEY = "temporary_files_size_key"; private static final String USED_SIZE_KEY = "used_size_key"; private final SharedPreferences mSharedPreferences; @@ -66,6 +67,7 @@ public class StorageCacheHelper { .putLong(DOCUMENTS_AND_OTHER_SIZE_KEY, data.documentsAndOtherSize) .putLong(TRASH_SIZE_KEY, data.trashSize) .putLong(SYSTEM_SIZE_KEY, data.systemSize) + .putLong(TEMPORARY_FILES_SIZE_KEY, data.temporaryFilesSize) .apply(); } @@ -109,6 +111,7 @@ public class StorageCacheHelper { result.documentsAndOtherSize = mSharedPreferences.getLong(DOCUMENTS_AND_OTHER_SIZE_KEY, 0); result.trashSize = mSharedPreferences.getLong(TRASH_SIZE_KEY, 0); result.systemSize = mSharedPreferences.getLong(SYSTEM_SIZE_KEY, 0); + result.temporaryFilesSize = mSharedPreferences.getLong(TEMPORARY_FILES_SIZE_KEY, 0); return result; } @@ -126,5 +129,6 @@ public class StorageCacheHelper { public long documentsAndOtherSize; public long trashSize; public long systemSize; + public long temporaryFilesSize; } } diff --git a/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceController.java b/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceController.java index fd424178f0c..62422ca1ea5 100644 --- a/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceController.java +++ b/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceController.java @@ -27,6 +27,7 @@ import android.content.pm.UserInfo; import android.content.res.TypedArray; import android.graphics.drawable.Drawable; import android.net.Uri; +import android.os.Build; import android.os.Bundle; import android.os.UserHandle; import android.os.UserManager; @@ -40,6 +41,7 @@ import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import androidx.fragment.app.Fragment; import androidx.preference.Preference; +import androidx.preference.PreferenceCategory; import androidx.preference.PreferenceScreen; import com.android.settings.R; @@ -52,6 +54,7 @@ import com.android.settings.core.SubSettingLauncher; import com.android.settings.dashboard.profileselector.ProfileSelectFragment; import com.android.settings.deviceinfo.StorageItemPreference; import com.android.settings.deviceinfo.storage.StorageUtils.SystemInfoFragment; +import com.android.settings.deviceinfo.storage.StorageUtils.TemporaryFilesInfoFragment; import com.android.settings.overlay.FeatureFactory; import com.android.settingslib.core.AbstractPreferenceController; import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; @@ -74,6 +77,7 @@ public class StorageItemPreferenceController extends AbstractPreferenceControlle private static final String TAG = "StorageItemPreference"; private static final String SYSTEM_FRAGMENT_TAG = "SystemInfo"; + private static final String TEMPORARY_FILES_FRAGMENT_TAG = "TemporaryFilesInfo"; @VisibleForTesting static final String PUBLIC_STORAGE_KEY = "pref_public_storage"; @@ -92,6 +96,10 @@ public class StorageItemPreferenceController extends AbstractPreferenceControlle @VisibleForTesting static final String SYSTEM_KEY = "pref_system"; @VisibleForTesting + static final String TEMPORARY_FILES_KEY = "temporary_files"; + @VisibleForTesting + static final String CATEGORY_SPLITTER = "storage_category_splitter"; + @VisibleForTesting static final String TRASH_KEY = "pref_trash"; @VisibleForTesting @@ -133,9 +141,13 @@ public class StorageItemPreferenceController extends AbstractPreferenceControlle @VisibleForTesting @Nullable StorageItemPreference mDocumentsAndOtherPreference; @VisibleForTesting + @Nullable StorageItemPreference mTrashPreference; + @VisibleForTesting @Nullable StorageItemPreference mSystemPreference; @VisibleForTesting - @Nullable StorageItemPreference mTrashPreference; + @Nullable StorageItemPreference mTemporaryFilesPreference; + @VisibleForTesting + @Nullable PreferenceCategory mCategorySplitterPreferenceCategory; private final int mProfileType; @@ -220,6 +232,13 @@ public class StorageItemPreferenceController extends AbstractPreferenceControlle dialog.setTargetFragment(mFragment, 0); dialog.show(mFragment.getFragmentManager(), SYSTEM_FRAGMENT_TAG); return true; + case TEMPORARY_FILES_KEY: + final TemporaryFilesInfoFragment temporaryFilesDialog = + new TemporaryFilesInfoFragment(); + temporaryFilesDialog.setTargetFragment(mFragment, 0); + temporaryFilesDialog.show(mFragment.getFragmentManager(), + TEMPORARY_FILES_FRAGMENT_TAG); + return true; case TRASH_KEY: launchTrashIntent(); return true; @@ -285,6 +304,8 @@ public class StorageItemPreferenceController extends AbstractPreferenceControlle mAppsPreference.setVisible(visible); mGamesPreference.setVisible(visible); mSystemPreference.setVisible(visible); + mTemporaryFilesPreference.setVisible(visible); + mCategorySplitterPreferenceCategory.setVisible(visible); mTrashPreference.setVisible(visible); // If we don't have a shared volume for our internal storage (or the shared volume isn't @@ -315,7 +336,6 @@ public class StorageItemPreferenceController extends AbstractPreferenceControlle mPrivateStorageItemPreferences.add(mAppsPreference); mPrivateStorageItemPreferences.add(mGamesPreference); mPrivateStorageItemPreferences.add(mDocumentsAndOtherPreference); - mPrivateStorageItemPreferences.add(mSystemPreference); mPrivateStorageItemPreferences.add(mTrashPreference); } mScreen.removePreference(mImagesPreference); @@ -324,7 +344,6 @@ public class StorageItemPreferenceController extends AbstractPreferenceControlle mScreen.removePreference(mAppsPreference); mScreen.removePreference(mGamesPreference); mScreen.removePreference(mDocumentsAndOtherPreference); - mScreen.removePreference(mSystemPreference); mScreen.removePreference(mTrashPreference); // Sort display order by size. @@ -361,6 +380,7 @@ public class StorageItemPreferenceController extends AbstractPreferenceControlle tintPreference(mGamesPreference); tintPreference(mDocumentsAndOtherPreference); tintPreference(mSystemPreference); + tintPreference(mTemporaryFilesPreference); tintPreference(mTrashPreference); } @@ -389,7 +409,9 @@ public class StorageItemPreferenceController extends AbstractPreferenceControlle mAppsPreference = screen.findPreference(APPS_KEY); mGamesPreference = screen.findPreference(GAMES_KEY); mDocumentsAndOtherPreference = screen.findPreference(DOCUMENTS_AND_OTHER_KEY); + mCategorySplitterPreferenceCategory = screen.findPreference(CATEGORY_SPLITTER); mSystemPreference = screen.findPreference(SYSTEM_KEY); + mTemporaryFilesPreference = screen.findPreference(TEMPORARY_FILES_KEY); mTrashPreference = screen.findPreference(TRASH_KEY); } @@ -417,6 +439,12 @@ public class StorageItemPreferenceController extends AbstractPreferenceControlle mTrashPreference.setStorageSize(storageCache.trashSize, mTotalSize, animate); if (mSystemPreference != null) { mSystemPreference.setStorageSize(storageCache.systemSize, mTotalSize, animate); + mSystemPreference.setTitle(mContext.getString(R.string.storage_os_name, + Build.VERSION.RELEASE)); + } + if (mTemporaryFilesPreference != null) { + mTemporaryFilesPreference.setStorageSize(storageCache.temporaryFilesSize, mTotalSize, + animate); } // Cache the size info if (result != null) { @@ -445,6 +473,7 @@ public class StorageItemPreferenceController extends AbstractPreferenceControlle storageCache.gamesSize = data.gamesSize; storageCache.documentsAndOtherSize = data.documentsAndOtherSize; storageCache.trashSize = data.trashSize; + storageCache.systemSize = data.systemSize; // Everything else that hasn't already been attributed is tracked as // belonging to system. long attributedSize = 0; @@ -460,7 +489,9 @@ public class StorageItemPreferenceController extends AbstractPreferenceControlle + otherData.allAppsExceptGamesSize; attributedSize -= otherData.duplicateCodeSize; } - storageCache.systemSize = Math.max(DataUnit.GIBIBYTES.toBytes(1), + // System size is equal for each user and should be added only once + attributedSize += data.systemSize; + storageCache.temporaryFilesSize = Math.max(DataUnit.GIBIBYTES.toBytes(1), mUsedBytes - attributedSize); return storageCache; } diff --git a/src/com/android/settings/deviceinfo/storage/StorageUtils.java b/src/com/android/settings/deviceinfo/storage/StorageUtils.java index 4b6a2c40fd8..5c4a4b40f2a 100644 --- a/src/com/android/settings/deviceinfo/storage/StorageUtils.java +++ b/src/com/android/settings/deviceinfo/storage/StorageUtils.java @@ -23,7 +23,6 @@ import android.content.Intent; import android.content.pm.ResolveInfo; import android.graphics.drawable.Drawable; import android.os.AsyncTask; -import android.os.Build; import android.os.Bundle; import android.os.storage.DiskInfo; import android.os.storage.StorageManager; @@ -34,6 +33,7 @@ import android.text.format.Formatter; import android.util.Log; import android.widget.Toast; +import androidx.annotation.NonNull; import androidx.appcompat.app.AlertDialog; import androidx.fragment.app.Fragment; @@ -206,7 +206,7 @@ public class StorageUtils { /** Shows information about system storage. */ public static class SystemInfoFragment extends InstrumentedDialogFragment { /** Shows the fragment. */ - public static void show(Fragment parent) { + public static void show(@NonNull Fragment parent) { if (!parent.isAdded()) return; final SystemInfoFragment dialog = new SystemInfoFragment(); @@ -222,8 +222,33 @@ public class StorageUtils { @Override public Dialog onCreateDialog(Bundle savedInstanceState) { return new AlertDialog.Builder(getActivity()) - .setMessage(getContext().getString(R.string.storage_detail_dialog_system, - Build.VERSION.RELEASE_OR_PREVIEW_DISPLAY)) + .setMessage(getContext().getString(R.string.storage_os_detail_dialog_system)) + .setPositiveButton(android.R.string.ok, null) + .create(); + } + } + + /** Shows information about temporary system files. */ + public static class TemporaryFilesInfoFragment extends InstrumentedDialogFragment { + /** Shows the fragment. */ + public static void show(@NonNull Fragment parent) { + if (!parent.isAdded()) return; + + final TemporaryFilesInfoFragment dialog = new TemporaryFilesInfoFragment(); + dialog.setTargetFragment(parent, 0); + dialog.show(parent.getFragmentManager(), "temporaryFilesInfo"); + } + + @Override + public int getMetricsCategory() { + return SettingsEnums.DIALOG_TEMPORARY_FILES_INFO; + } + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + return new AlertDialog.Builder(getActivity()) + .setMessage(getContext().getString( + R.string.storage_other_files_detail_dialog_system)) .setPositiveButton(android.R.string.ok, null) .create(); } diff --git a/tests/robotests/src/com/android/settings/deviceinfo/storage/StorageCacheHelperTest.java b/tests/robotests/src/com/android/settings/deviceinfo/storage/StorageCacheHelperTest.java index 9e20e78c03a..a26ea1dfca2 100644 --- a/tests/robotests/src/com/android/settings/deviceinfo/storage/StorageCacheHelperTest.java +++ b/tests/robotests/src/com/android/settings/deviceinfo/storage/StorageCacheHelperTest.java @@ -41,6 +41,7 @@ public class StorageCacheHelperTest { private static final long FAKE_TOTAL_SIZE = 256000L; private static final long FAKE_TOTAL_USED_SIZE = 50000L; private static final long FAKE_USED_SIZE = 6500L; + private static final long FAKE_TEMPORARY_FILES_SIZE = 2500L; private Context mContext; private StorageCacheHelper mHelper; @@ -70,6 +71,7 @@ public class StorageCacheHelperTest { StorageCacheHelper.StorageCache storageCache = mHelper.retrieveCachedSize(); assertThat(storageCache.imagesSize).isEqualTo(FAKE_IMAGES_SIZE); + assertThat(storageCache.temporaryFilesSize).isEqualTo(FAKE_TEMPORARY_FILES_SIZE); assertThat(storageCache.totalSize).isEqualTo(0); } @@ -100,6 +102,7 @@ public class StorageCacheHelperTest { result.gamesSize = FAKE_GAMES_SIZE; result.videosSize = FAKE_VIDEOS_SIZE; result.allAppsExceptGamesSize = FAKE_APPS_SIZE; + result.temporaryFilesSize = FAKE_TEMPORARY_FILES_SIZE; return result; } } diff --git a/tests/robotests/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceControllerTest.java index b61f5ab4ef4..2590f52340f 100644 --- a/tests/robotests/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceControllerTest.java @@ -45,6 +45,7 @@ import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentActivity; import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentTransaction; +import androidx.preference.PreferenceCategory; import androidx.preference.PreferenceScreen; import com.android.settings.R; @@ -126,7 +127,10 @@ public class StorageItemPreferenceControllerTest { final StorageItemPreference documentsAndOther = spy(new StorageItemPreference(mContext)); documentsAndOther.setIcon(R.drawable.ic_folder_vd_theme_24); final StorageItemPreference system = spy(new StorageItemPreference(mContext)); - system.setIcon(com.android.settingslib.R.drawable.ic_system_update); + system.setIcon(R.drawable.ic_android_vd_theme_24); + final StorageItemPreference temporaryFiles = spy(new StorageItemPreference(mContext)); + temporaryFiles.setIcon(R.drawable.ic_database_vd_theme_24); + final PreferenceCategory categorySplitter = spy(new PreferenceCategory(mContext)); final StorageItemPreference trash = spy(new StorageItemPreference(mContext)); trash.setIcon(R.drawable.ic_trash_can); @@ -147,6 +151,10 @@ public class StorageItemPreferenceControllerTest { .thenReturn(documentsAndOther); when(screen.findPreference(eq(StorageItemPreferenceController.SYSTEM_KEY))) .thenReturn(system); + when(screen.findPreference(eq(StorageItemPreferenceController.TEMPORARY_FILES_KEY))) + .thenReturn(temporaryFiles); + when(screen.findPreference(eq(StorageItemPreferenceController.CATEGORY_SPLITTER))) + .thenReturn(categorySplitter); when(screen.findPreference(eq(StorageItemPreferenceController.TRASH_KEY))) .thenReturn(trash); @@ -219,6 +227,7 @@ public class StorageItemPreferenceControllerTest { assertThat(mController.mGamesPreference.isVisible()).isFalse(); assertThat(mController.mDocumentsAndOtherPreference.isVisible()).isFalse(); assertThat(mController.mSystemPreference.isVisible()).isFalse(); + assertThat(mController.mTemporaryFilesPreference.isVisible()).isFalse(); assertThat(mController.mTrashPreference.isVisible()).isFalse(); } @@ -329,6 +338,16 @@ public class StorageItemPreferenceControllerTest { .add(nullable(StorageUtils.SystemInfoFragment.class), nullable(String.class)); } + @Test + public void testClickTemporaryFiles() { + mPreference.setKey(StorageItemPreferenceController.TEMPORARY_FILES_KEY); + assertThat(mController.handlePreferenceTreeClick(mPreference)).isTrue(); + + verify(mFragment.getFragmentManager().beginTransaction()) + .add(nullable(StorageUtils.TemporaryFilesInfoFragment.class), + nullable(String.class)); + } + @Test @Config(shadows = ShadowUserManager.class) public void testMeasurementCompletedUpdatesPreferences() { @@ -343,6 +362,7 @@ public class StorageItemPreferenceControllerTest { result.documentsAndOtherSize = MEGABYTE_IN_BYTES * 50; result.trashSize = KILOBYTE_IN_BYTES * 100; result.allAppsExceptGamesSize = MEGABYTE_IN_BYTES * 90; + result.systemSize = MEGABYTE_IN_BYTES * 60; final SparseArray results = new SparseArray<>(); results.put(0, result); @@ -356,6 +376,8 @@ public class StorageItemPreferenceControllerTest { assertThat(mController.mDocumentsAndOtherPreference.getSummary().toString()) .isEqualTo("50 MB"); assertThat(mController.mTrashPreference.getSummary().toString()).isEqualTo("100 kB"); + assertThat(mController.mSystemPreference.getSummary().toString()) + .isEqualTo("60 MB"); } @Test @@ -373,6 +395,7 @@ public class StorageItemPreferenceControllerTest { verify(mController.mDocumentsAndOtherPreference, times(2)) .setIcon(nullable(Drawable.class)); verify(mController.mSystemPreference, times(2)).setIcon(nullable(Drawable.class)); + verify(mController.mTemporaryFilesPreference, times(2)).setIcon(nullable(Drawable.class)); verify(mController.mTrashPreference, times(2)).setIcon(nullable(Drawable.class)); } @@ -437,6 +460,7 @@ public class StorageItemPreferenceControllerTest { assertThat(mController.mGamesPreference.isVisible()).isFalse(); assertThat(mController.mDocumentsAndOtherPreference.isVisible()).isFalse(); assertThat(mController.mSystemPreference.isVisible()).isFalse(); + assertThat(mController.mTemporaryFilesPreference.isVisible()).isFalse(); assertThat(mController.mTrashPreference.isVisible()).isFalse(); }