diff --git a/res/xml/storage_dashboard_fragment.xml b/res/xml/storage_dashboard_fragment.xml index 076405fa00e..83972e35b92 100644 --- a/res/xml/storage_dashboard_fragment.xml +++ b/res/xml/storage_dashboard_fragment.xml @@ -44,38 +44,51 @@ android:title="@string/storage_free_up_space_title" android:summary="@string/storage_free_up_space_summary"/> + + android:icon="@drawable/ic_photo_library" + android:order="101"/> + android:icon="@drawable/ic_local_movies" + android:order="102"/> + android:icon="@drawable/ic_media_stream" + android:order="103"/> + android:icon="@drawable/ic_storage_apps" + android:order="104"/> + android:icon="@drawable/ic_videogame_vd_theme_24" + android:order="105"/> + android:icon="@drawable/ic_folder_vd_theme_24" + android:order="106"/> + android:icon="@drawable/ic_system_update" + android:order="107"/> + android:icon="@drawable/ic_trash_can" + android:order="108"/> , Parcelable { return mVolumeInfo == null ? false : mVolumeInfo.getType() == VolumeInfo.TYPE_PUBLIC; } + /** + * Stub volume is a volume that is maintained by external party such as the ChromeOS processes + * in ARC++. + */ + public boolean isStub() { + return mVolumeInfo == null ? false : mVolumeInfo.getType() == VolumeInfo.TYPE_STUB; + } + /** Returns description. */ public String getDescription() { if (isVolumeInfo()) { diff --git a/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceController.java b/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceController.java index 7d7768799d8..e5259f996e3 100644 --- a/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceController.java +++ b/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceController.java @@ -69,6 +69,8 @@ public class StorageItemPreferenceController extends AbstractPreferenceControlle private static final String SYSTEM_FRAGMENT_TAG = "SystemInfo"; + @VisibleForTesting + static final String PUBLIC_STORAGE_KEY = "pref_public_storage"; @VisibleForTesting static final String IMAGES_KEY = "pref_images"; @VisibleForTesting @@ -103,9 +105,11 @@ public class StorageItemPreferenceController extends AbstractPreferenceControlle private long mUsedBytes; private long mTotalSize; - private List mStorageItemPreferences; + private List mPrivateStorageItemPreferences; private PreferenceScreen mScreen; @VisibleForTesting + Preference mPublicStoragePreference; + @VisibleForTesting StorageItemPreference mImagesPreference; @VisibleForTesting StorageItemPreference mVideosPreference; @@ -167,6 +171,9 @@ public class StorageItemPreferenceController extends AbstractPreferenceControlle return false; } switch (preference.getKey()) { + case PUBLIC_STORAGE_KEY: + launchPublicStorageIntent(); + return true; case IMAGES_KEY: launchImagesIntent(); return true; @@ -210,37 +217,45 @@ public class StorageItemPreferenceController extends AbstractPreferenceControlle public void setVolume(VolumeInfo volume) { mVolume = volume; - final boolean isValidVolume = isValidVolume(); - setCategoryPreferencesVisibility(isValidVolume); - if (isValidVolume) { - updateCategoryPreferencesOrder(); - } + updateCategoryPreferencesVisibility(); + updatePrivateStorageCategoryPreferencesOrder(); } // Stats data is only available on private volumes. - private boolean isValidVolume() { + private boolean isValidPrivateVolume() { return mVolume != null && mVolume.getType() == VolumeInfo.TYPE_PRIVATE && (mVolume.getState() == VolumeInfo.STATE_MOUNTED || mVolume.getState() == VolumeInfo.STATE_MOUNTED_READ_ONLY); } - private void setCategoryPreferencesVisibility(boolean visible) { + private boolean isValidPublicVolume() { + return mVolume != null + && (mVolume.getType() == VolumeInfo.TYPE_PUBLIC + || mVolume.getType() == VolumeInfo.TYPE_STUB) + && (mVolume.getState() == VolumeInfo.STATE_MOUNTED + || mVolume.getState() == VolumeInfo.STATE_MOUNTED_READ_ONLY); + } + + private void updateCategoryPreferencesVisibility() { if (mScreen == null) { return; } - mImagesPreference.setVisible(visible); - mVideosPreference.setVisible(visible); - mAudiosPreference.setVisible(visible); - mAppsPreference.setVisible(visible); - mGamesPreference.setVisible(visible); - mDocumentsAndOtherPreference.setVisible(visible); - mSystemPreference.setVisible(visible); + mPublicStoragePreference.setVisible(isValidPublicVolume()); + + final boolean privateStoragePreferencesVisible = isValidPrivateVolume(); + mImagesPreference.setVisible(privateStoragePreferencesVisible); + mVideosPreference.setVisible(privateStoragePreferencesVisible); + mAudiosPreference.setVisible(privateStoragePreferencesVisible); + mAppsPreference.setVisible(privateStoragePreferencesVisible); + mGamesPreference.setVisible(privateStoragePreferencesVisible); + mDocumentsAndOtherPreference.setVisible(privateStoragePreferencesVisible); + mSystemPreference.setVisible(privateStoragePreferencesVisible); // TODO(b/170918505): Shows trash category after trash category feature complete. mTrashPreference.setVisible(false); - if (visible) { + if (privateStoragePreferencesVisible) { final VolumeInfo sharedVolume = mSvp.findEmulatedForPrivate(mVolume); // If we don't have a shared volume for our internal storage (or the shared volume isn't // mounted as readable for whatever reason), we should hide the File preference. @@ -250,22 +265,22 @@ public class StorageItemPreferenceController extends AbstractPreferenceControlle } } - private void updateCategoryPreferencesOrder() { - if (mScreen == null) { + private void updatePrivateStorageCategoryPreferencesOrder() { + if (mScreen == null || !isValidPrivateVolume()) { return; } - if (mStorageItemPreferences == null) { - mStorageItemPreferences = new ArrayList<>(); + if (mPrivateStorageItemPreferences == null) { + mPrivateStorageItemPreferences = new ArrayList<>(); - mStorageItemPreferences.add(mImagesPreference); - mStorageItemPreferences.add(mVideosPreference); - mStorageItemPreferences.add(mAudiosPreference); - mStorageItemPreferences.add(mAppsPreference); - mStorageItemPreferences.add(mGamesPreference); - mStorageItemPreferences.add(mDocumentsAndOtherPreference); - mStorageItemPreferences.add(mSystemPreference); - mStorageItemPreferences.add(mTrashPreference); + mPrivateStorageItemPreferences.add(mImagesPreference); + mPrivateStorageItemPreferences.add(mVideosPreference); + mPrivateStorageItemPreferences.add(mAudiosPreference); + mPrivateStorageItemPreferences.add(mAppsPreference); + mPrivateStorageItemPreferences.add(mGamesPreference); + mPrivateStorageItemPreferences.add(mDocumentsAndOtherPreference); + mPrivateStorageItemPreferences.add(mSystemPreference); + mPrivateStorageItemPreferences.add(mTrashPreference); } mScreen.removePreference(mImagesPreference); mScreen.removePreference(mVideosPreference); @@ -277,10 +292,10 @@ public class StorageItemPreferenceController extends AbstractPreferenceControlle mScreen.removePreference(mTrashPreference); // Sort display order by size. - Collections.sort(mStorageItemPreferences, + Collections.sort(mPrivateStorageItemPreferences, Comparator.comparingLong(StorageItemPreference::getStorageSize)); int orderIndex = LAST_STORAGE_CATEGORY_PREFERENCE_ORDER; - for (StorageItemPreference preference : mStorageItemPreferences) { + for (StorageItemPreference preference : mPrivateStorageItemPreferences) { preference.setOrder(orderIndex--); mScreen.addPreference(preference); } @@ -292,6 +307,7 @@ public class StorageItemPreferenceController extends AbstractPreferenceControlle public void setUserId(UserHandle userHandle) { mUserId = userHandle.getIdentifier(); + tintPreference(mPublicStoragePreference); tintPreference(mImagesPreference); tintPreference(mVideosPreference); tintPreference(mAudiosPreference); @@ -320,6 +336,7 @@ public class StorageItemPreferenceController extends AbstractPreferenceControlle @Override public void displayPreference(PreferenceScreen screen) { mScreen = screen; + mPublicStoragePreference = screen.findPreference(PUBLIC_STORAGE_KEY); mImagesPreference = screen.findPreference(IMAGES_KEY); mVideosPreference = screen.findPreference(VIDEOS_KEY); mAudiosPreference = screen.findPreference(AUDIOS_KEY); @@ -329,11 +346,8 @@ public class StorageItemPreferenceController extends AbstractPreferenceControlle mSystemPreference = screen.findPreference(SYSTEM_KEY); mTrashPreference = screen.findPreference(TRASH_KEY); - final boolean isValidVolume = isValidVolume(); - setCategoryPreferencesVisibility(isValidVolume); - if (isValidVolume) { - updateCategoryPreferencesOrder(); - } + updateCategoryPreferencesVisibility(); + updatePrivateStorageCategoryPreferencesOrder(); } public void onLoadFinished(SparseArray result, @@ -371,7 +385,7 @@ public class StorageItemPreferenceController extends AbstractPreferenceControlle mSystemPreference.setStorageSize(systemSize, mTotalSize); } - updateCategoryPreferencesOrder(); + updatePrivateStorageCategoryPreferencesOrder(); } public void setUsedSize(long usedSizeBytes) { @@ -382,6 +396,13 @@ public class StorageItemPreferenceController extends AbstractPreferenceControlle mTotalSize = totalSizeBytes; } + private void launchPublicStorageIntent() { + final Intent intent = mVolume.buildBrowseIntent(); + if (intent != null) { + mContext.startActivity(intent); + } + } + // TODO(b/183078080): To simplify StorageItemPreferenceController, move launchxxxIntent to a // utility object. private void launchImagesIntent() { 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 6f9c4514c69..b7bf7f56606 100644 --- a/tests/robotests/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceControllerTest.java @@ -104,6 +104,8 @@ public class StorageItemPreferenceControllerTest { } private PreferenceScreen getPreferenceScreen() { + final StorageItemPreference publicStorage = spy(new StorageItemPreference(mContext)); + publicStorage.setIcon(R.drawable.ic_folder_vd_theme_24); final StorageItemPreference images = spy(new StorageItemPreference(mContext)); images.setIcon(R.drawable.ic_photo_library); final StorageItemPreference videos = spy(new StorageItemPreference(mContext)); @@ -122,6 +124,8 @@ public class StorageItemPreferenceControllerTest { trash.setIcon(R.drawable.ic_trash_can); final PreferenceScreen screen = mock(PreferenceScreen.class); + when(screen.findPreference(eq(StorageItemPreferenceController.PUBLIC_STORAGE_KEY))) + .thenReturn(publicStorage); when(screen.findPreference(eq(StorageItemPreferenceController.IMAGES_KEY))) .thenReturn(images); when(screen.findPreference(eq(StorageItemPreferenceController.VIDEOS_KEY))) @@ -148,6 +152,24 @@ public class StorageItemPreferenceControllerTest { .isEqualTo(mContext.getString(R.string.memory_calculating_size)); } + @Test + public void launchPublicStorageIntent_nonNullBrowseIntent_settingsIntent() { + final String fakeBrowseAction = "FAKE_BROWSE_ACTION"; + final Intent fakeBrowseIntent = new Intent(fakeBrowseAction); + // mContext is not the activity, add FLAG_ACTIVITY_NEW_TASK to avoid AndroidRuntimeException + // during this test. + fakeBrowseIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + when(mVolume.buildBrowseIntent()).thenReturn(fakeBrowseIntent); + mPreference.setKey(StorageItemPreferenceController.PUBLIC_STORAGE_KEY); + mController.handlePreferenceTreeClick(mPreference); + + final ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(Intent.class); + verify(mContext).startActivity(argumentCaptor.capture()); + + final Intent intent = argumentCaptor.getValue(); + assertThat(intent.getAction()).isEqualTo(fakeBrowseAction); + } + @Test public void launchImagesIntent_resolveActionViewNull_settingsIntent() { mPreference.setKey(StorageItemPreferenceController.IMAGES_KEY); @@ -191,6 +213,7 @@ public class StorageItemPreferenceControllerTest { mController.setVolume(null); + assertThat(mController.mPublicStoragePreference.isVisible()).isFalse(); assertThat(mController.mImagesPreference.isVisible()).isFalse(); assertThat(mController.mVideosPreference.isVisible()).isFalse(); assertThat(mController.mAudiosPreference.isVisible()).isFalse(); @@ -347,6 +370,7 @@ public class StorageItemPreferenceControllerTest { mController.setUserId(new UserHandle(10)); + verify(mController.mPublicStoragePreference, times(2)).setIcon(nullable(Drawable.class)); verify(mController.mImagesPreference, times(2)).setIcon(nullable(Drawable.class)); verify(mController.mVideosPreference, times(2)).setIcon(nullable(Drawable.class)); verify(mController.mAudiosPreference, times(2)).setIcon(nullable(Drawable.class)); @@ -418,4 +442,26 @@ public class StorageItemPreferenceControllerTest { assertThat(mController.mDocumentsAndOtherPreference.isVisible()).isTrue(); } + + @Test + public void setVolume_publicStorage_showFilePreference() { + // This will hide it initially. + mController.displayPreference(mPreferenceScreen); + when(mVolume.getType()).thenReturn(VolumeInfo.TYPE_PUBLIC); + when(mVolume.getState()).thenReturn(VolumeInfo.STATE_MOUNTED); + when(mVolume.isMountedReadable()).thenReturn(true); + + // And we bring it back. + mController.setVolume(mVolume); + + assertThat(mController.mPublicStoragePreference.isVisible()).isTrue(); + assertThat(mController.mImagesPreference.isVisible()).isFalse(); + assertThat(mController.mVideosPreference.isVisible()).isFalse(); + assertThat(mController.mAudiosPreference.isVisible()).isFalse(); + assertThat(mController.mAppsPreference.isVisible()).isFalse(); + assertThat(mController.mGamesPreference.isVisible()).isFalse(); + assertThat(mController.mDocumentsAndOtherPreference.isVisible()).isFalse(); + assertThat(mController.mSystemPreference.isVisible()).isFalse(); + assertThat(mController.mTrashPreference.isVisible()).isFalse(); + } } diff --git a/tests/unit/src/com/android/settings/deviceinfo/storage/StorageEntryTest.java b/tests/unit/src/com/android/settings/deviceinfo/storage/StorageEntryTest.java index cf1b6b2c8ec..3cd35395e01 100644 --- a/tests/unit/src/com/android/settings/deviceinfo/storage/StorageEntryTest.java +++ b/tests/unit/src/com/android/settings/deviceinfo/storage/StorageEntryTest.java @@ -208,6 +208,24 @@ public class StorageEntryTest { assertThat(privateStorage.isPrivate()).isTrue(); } + @Test + public void isPublic_prublicVolume_shouldReturnTrue() { + final VolumeInfo publicVolumeInfo = mock(VolumeInfo.class); + final StorageEntry publicStorage = new StorageEntry(mContext, publicVolumeInfo); + when(publicVolumeInfo.getType()).thenReturn(VolumeInfo.TYPE_PUBLIC); + + assertThat(publicStorage.isPublic()).isTrue(); + } + + @Test + public void isStub_stubVolume_shouldReturnTrue() { + final VolumeInfo stubVolumeInfo = mock(VolumeInfo.class); + final StorageEntry stubStorage = new StorageEntry(mContext, stubVolumeInfo); + when(stubVolumeInfo.getType()).thenReturn(VolumeInfo.TYPE_STUB); + + assertThat(stubStorage.isStub()).isTrue(); + } + @Test public void isPrivate_nonVolumeInfo_shouldReturnFalse() { final DiskInfo diskInfo = mock(DiskInfo.class);