From 4cd89bb082ba2c8f6f38aeda35085b6cb862b087 Mon Sep 17 00:00:00 2001 From: Arc Wang Date: Wed, 28 Apr 2021 19:54:37 +0800 Subject: [PATCH] Storage Settings Apps category shows image/video/audio APPs There is AOSP built in file browser for image/video/audio file category, all APPs except games should be included in Apps category. - Shows image/video/audio APPs in APPs category. - Count Image/Video/Audio APPs storage size to Apps storage size. - Remove APP size & cache size for Images/Videos/Audios category. Bug: 170918505 Test: atest StorageAsyncLoaderTest.java Change-Id: I07e0a3a66a13f36b9e0cbde289d8ba90df4ae295 --- .../ManageApplications.java | 2 +- .../storage/StorageAsyncLoader.java | 23 +++++++++++++ .../storage/StorageAsyncLoaderTest.java | 32 ++++++++++++++++--- 3 files changed, 51 insertions(+), 6 deletions(-) diff --git a/src/com/android/settings/applications/manageapplications/ManageApplications.java b/src/com/android/settings/applications/manageapplications/ManageApplications.java index a92f5394da4..a08c5406535 100644 --- a/src/com/android/settings/applications/manageapplications/ManageApplications.java +++ b/src/com/android/settings/applications/manageapplications/ManageApplications.java @@ -511,7 +511,7 @@ public class ManageApplications extends InstrumentedFragment if (storageType == STORAGE_TYPE_MUSIC) { filter = new CompoundFilter(ApplicationsState.FILTER_AUDIO, filter); } else if (storageType == STORAGE_TYPE_DEFAULT) { - filter = new CompoundFilter(ApplicationsState.FILTER_OTHER_APPS, filter); + filter = new CompoundFilter(ApplicationsState.FILTER_APPS_EXCEPT_GAMES, filter); } return filter; } diff --git a/src/com/android/settings/deviceinfo/storage/StorageAsyncLoader.java b/src/com/android/settings/deviceinfo/storage/StorageAsyncLoader.java index 9d10a1daf0e..f53b68fd1af 100644 --- a/src/com/android/settings/deviceinfo/storage/StorageAsyncLoader.java +++ b/src/com/android/settings/deviceinfo/storage/StorageAsyncLoader.java @@ -120,7 +120,9 @@ public class StorageAsyncLoader // This isn't quite right because it slams the first user by user id with the whole code // size, but this ensures that we count all apps seen once. + boolean isAddCodeBytesForFirstUserId = false; if (!mSeenPackages.contains(app.packageName)) { + isAddCodeBytesForFirstUserId = true; blamedSize += stats.getCodeBytes(); mSeenPackages.add(app.packageName); } @@ -130,13 +132,34 @@ public class StorageAsyncLoader result.gamesSize += blamedSize; break; case CATEGORY_AUDIO: + // TODO(b/170918505): Should revamp audio size calculation with the data + // from media provider. result.musicAppsSize += blamedSize; + if (isAddCodeBytesForFirstUserId) { + result.musicAppsSize -= stats.getCodeBytes(); + } + + result.otherAppsSize += blamedSize; break; case CATEGORY_VIDEO: + // TODO(b/170918505): Should revamp video size calculation with the data + // from media provider. result.videoAppsSize += blamedSize; + if (isAddCodeBytesForFirstUserId) { + result.videoAppsSize -= stats.getCodeBytes(); + } + + result.otherAppsSize += blamedSize; break; case CATEGORY_IMAGE: + // TODO(b/170918505): Should revamp image size calculation with the data + // from media provider. result.photosAppsSize += blamedSize; + if (isAddCodeBytesForFirstUserId) { + result.photosAppsSize -= stats.getCodeBytes(); + } + + result.otherAppsSize += blamedSize; break; default: // The deprecated game flag does not set the category. diff --git a/tests/unit/src/com/android/settings/deviceinfo/storage/StorageAsyncLoaderTest.java b/tests/unit/src/com/android/settings/deviceinfo/storage/StorageAsyncLoaderTest.java index f2349bbf831..a271e9b9e99 100644 --- a/tests/unit/src/com/android/settings/deviceinfo/storage/StorageAsyncLoaderTest.java +++ b/tests/unit/src/com/android/settings/deviceinfo/storage/StorageAsyncLoaderTest.java @@ -22,7 +22,9 @@ import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; import android.content.Context; @@ -30,20 +32,22 @@ import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.UserInfo; +import android.content.res.Resources; import android.net.TrafficStats; import android.os.UserHandle; import android.os.UserManager; import android.util.SparseArray; +import androidx.test.core.app.ApplicationProvider; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; +import com.android.settings.R; import com.android.settingslib.applications.StorageStatsSource; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.Answers; import org.mockito.Mock; import org.mockito.MockitoAnnotations; @@ -57,11 +61,11 @@ public class StorageAsyncLoaderTest { private static final int SECONDARY_USER_ID = 10; private static final String PACKAGE_NAME_1 = "com.blah.test"; private static final String PACKAGE_NAME_2 = "com.blah.test2"; + private static final String PACKAGE_NAME_3 = "com.blah.test3"; private static final long DEFAULT_QUOTA = 64 * TrafficStats.MB_IN_BYTES; @Mock private StorageStatsSource mSource; - @Mock(answer = Answers.RETURNS_DEEP_STUBS) private Context mContext; @Mock private PackageManager mPackageManager; @@ -76,6 +80,7 @@ public class StorageAsyncLoaderTest { @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); + mContext = spy(ApplicationProvider.getApplicationContext()); mInfo = new ArrayList<>(); mLoader = new StorageAsyncLoader(mContext, mUserManager, "id", mSource, mPackageManager); when(mPackageManager.getInstalledApplicationsAsUser(eq(PRIMARY_USER_ID), anyInt())) @@ -85,6 +90,10 @@ public class StorageAsyncLoaderTest { mUsers.add(info); when(mUserManager.getUsers()).thenReturn(mUsers); when(mSource.getCacheQuotaBytes(anyString(), anyInt())).thenReturn(DEFAULT_QUOTA); + final Resources resources = spy(mContext.getResources()); + when(mContext.getResources()).thenReturn(resources); + doReturn("content://com.android.providers.media.documents/root/videos_root") + .when(resources).getString(R.string.config_videos_storage_category_uri); } @Test @@ -169,8 +178,8 @@ public class StorageAsyncLoaderTest { SparseArray result = mLoader.loadInBackground(); assertThat(result.size()).isEqualTo(1); - assertThat(result.get(PRIMARY_USER_ID).videoAppsSize).isEqualTo(11L); - assertThat(result.get(PRIMARY_USER_ID).otherAppsSize).isEqualTo(0); + // Code size is not included for file based video category. + assertThat(result.get(PRIMARY_USER_ID).videoAppsSize).isEqualTo(10L); } @Test @@ -206,7 +215,8 @@ public class StorageAsyncLoaderTest { SparseArray result = mLoader.loadInBackground(); assertThat(result.size()).isEqualTo(2); - assertThat(result.get(PRIMARY_USER_ID).videoAppsSize).isEqualTo(11L); + // Code size is not included for file based video category. + assertThat(result.get(PRIMARY_USER_ID).videoAppsSize).isEqualTo(10L); // No code size for the second user. assertThat(result.get(SECONDARY_USER_ID).videoAppsSize).isEqualTo(10L); } @@ -221,6 +231,18 @@ public class StorageAsyncLoaderTest { assertThat(result.get(PRIMARY_USER_ID).otherAppsSize).isEqualTo(DEFAULT_QUOTA + 11); } + @Test + public void testAppsAreFiltered() throws Exception { + addPackage(PACKAGE_NAME_1, 0, 1, 10, ApplicationInfo.CATEGORY_IMAGE); + addPackage(PACKAGE_NAME_2, 0, 1, 10, ApplicationInfo.CATEGORY_VIDEO); + addPackage(PACKAGE_NAME_3, 0, 1, 10, ApplicationInfo.CATEGORY_AUDIO); + + SparseArray result = mLoader.loadInBackground(); + + assertThat(result.size()).isEqualTo(1); + assertThat(result.get(PRIMARY_USER_ID).otherAppsSize).isEqualTo(33L); + } + private ApplicationInfo addPackage(String packageName, long cacheSize, long codeSize, long dataSize, int category) throws Exception { StorageStatsSource.AppStorageStats storageStats =