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(); }