Show "Files" category for public storage in Storage Settings
Users can click this preference to see public storage files
in external file browsers.
Bug: 170918505
Test: make RunSettingsRoboTests ROBOTEST_FILTER=StorageItemPreferenceControllerTest
manual
Select private storage and public storage and observe UI
Change-Id: If3f0d59b2ebf941d70e81e60c4c2015b80e7cf33
diff --git a/res/xml/storage_dashboard_fragment.xml b/res/xml/storage_dashboard_fragment.xml
index 076405f..83972e3 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"/>
<!-- Preference order 100~200 are 'ONLY' for storage category preferences below. -->
+ <Preference
+ android:key="pref_public_storage"
+ android:title="@string/storage_files"
+ android:icon="@drawable/ic_folder_vd_theme_24"
+ android:order="100"/>
<com.android.settings.deviceinfo.StorageItemPreference
android:key="pref_images"
android:title="@string/storage_images"
- android:icon="@drawable/ic_photo_library"/>
+ android:icon="@drawable/ic_photo_library"
+ android:order="101"/>
<com.android.settings.deviceinfo.StorageItemPreference
android:key="pref_videos"
android:title="@string/storage_videos"
- android:icon="@drawable/ic_local_movies"/>
+ android:icon="@drawable/ic_local_movies"
+ android:order="102"/>
<com.android.settings.deviceinfo.StorageItemPreference
android:key="pref_audios"
android:title="@string/storage_audios"
- android:icon="@drawable/ic_media_stream"/>
+ android:icon="@drawable/ic_media_stream"
+ android:order="103"/>
<com.android.settings.deviceinfo.StorageItemPreference
android:key="pref_apps"
android:title="@string/storage_apps"
- android:icon="@drawable/ic_storage_apps"/>
+ android:icon="@drawable/ic_storage_apps"
+ android:order="104"/>
<com.android.settings.deviceinfo.StorageItemPreference
android:key="pref_games"
android:title="@string/storage_games"
- android:icon="@drawable/ic_videogame_vd_theme_24"/>
+ android:icon="@drawable/ic_videogame_vd_theme_24"
+ android:order="105"/>
<com.android.settings.deviceinfo.StorageItemPreference
android:key="pref_documents_and_other"
android:title="@string/storage_documents_and_other"
- android:icon="@drawable/ic_folder_vd_theme_24"/>
+ android:icon="@drawable/ic_folder_vd_theme_24"
+ android:order="106"/>
<com.android.settings.deviceinfo.StorageItemPreference
android:key="pref_system"
android:title="@string/storage_system"
- android:icon="@drawable/ic_system_update"/>
+ android:icon="@drawable/ic_system_update"
+ android:order="107"/>
<com.android.settings.deviceinfo.StorageItemPreference
android:key="pref_trash"
android:title="@string/storage_trash"
- android:icon="@drawable/ic_trash_can"/>
+ android:icon="@drawable/ic_trash_can"
+ android:order="108"/>
<!-- Preference order 100~200 are 'ONLY' for storage category preferences above. -->
<PreferenceCategory
android:key="pref_secondary_users"
diff --git a/src/com/android/settings/deviceinfo/StorageDashboardFragment.java b/src/com/android/settings/deviceinfo/StorageDashboardFragment.java
index b8c4e28..03a7b97 100644
--- a/src/com/android/settings/deviceinfo/StorageDashboardFragment.java
+++ b/src/com/android/settings/deviceinfo/StorageDashboardFragment.java
@@ -248,15 +248,19 @@
mPreferenceController.setVolume(mSelectedStorageEntry.getVolumeInfo());
- if (mSelectedStorageEntry.isPrivate() && mSelectedStorageEntry.isMounted()) {
+ if (!mSelectedStorageEntry.isMounted()) {
+ // Set null volume to hide category stats.
+ mPreferenceController.setVolume(null);
+ return;
+ }
+ if (mSelectedStorageEntry.isPrivate()) {
// Stats data is only available on private volumes.
getLoaderManager().restartLoader(STORAGE_JOB_ID, Bundle.EMPTY, this);
getLoaderManager()
.restartLoader(VOLUME_SIZE_JOB_ID, Bundle.EMPTY, new VolumeSizeCallbacks());
getLoaderManager().restartLoader(ICON_JOB_ID, Bundle.EMPTY, new IconLoaderCallbacks());
} else {
- // Set null volume to hide category stats.
- mPreferenceController.setVolume(null);
+ mPreferenceController.setVolume(mSelectedStorageEntry.getVolumeInfo());
}
}
diff --git a/src/com/android/settings/deviceinfo/storage/StorageEntry.java b/src/com/android/settings/deviceinfo/storage/StorageEntry.java
index f718116..9ea0292 100644
--- a/src/com/android/settings/deviceinfo/storage/StorageEntry.java
+++ b/src/com/android/settings/deviceinfo/storage/StorageEntry.java
@@ -236,6 +236,14 @@
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 7d77687..e5259f9 100644
--- a/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceController.java
+++ b/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceController.java
@@ -70,6 +70,8 @@
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
static final String VIDEOS_KEY = "pref_videos";
@@ -103,9 +105,11 @@
private long mUsedBytes;
private long mTotalSize;
- private List<StorageItemPreference> mStorageItemPreferences;
+ private List<StorageItemPreference> mPrivateStorageItemPreferences;
private PreferenceScreen mScreen;
@VisibleForTesting
+ Preference mPublicStoragePreference;
+ @VisibleForTesting
StorageItemPreference mImagesPreference;
@VisibleForTesting
StorageItemPreference mVideosPreference;
@@ -167,6 +171,9 @@
return false;
}
switch (preference.getKey()) {
+ case PUBLIC_STORAGE_KEY:
+ launchPublicStorageIntent();
+ return true;
case IMAGES_KEY:
launchImagesIntent();
return true;
@@ -210,37 +217,45 @@
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 @@
}
}
- 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 @@
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 void setUserId(UserHandle userHandle) {
mUserId = userHandle.getIdentifier();
+ tintPreference(mPublicStoragePreference);
tintPreference(mImagesPreference);
tintPreference(mVideosPreference);
tintPreference(mAudiosPreference);
@@ -320,6 +336,7 @@
@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 @@
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<StorageAsyncLoader.AppsStorageResult> result,
@@ -371,7 +385,7 @@
mSystemPreference.setStorageSize(systemSize, mTotalSize);
}
- updateCategoryPreferencesOrder();
+ updatePrivateStorageCategoryPreferencesOrder();
}
public void setUsedSize(long usedSizeBytes) {
@@ -382,6 +396,13 @@
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 6f9c451..b7bf7f5 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 @@
}
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 @@
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)))
@@ -149,6 +153,24 @@
}
@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<Intent> 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);
mController.handlePreferenceTreeClick(mPreference);
@@ -191,6 +213,7 @@
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 @@
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 @@
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 cf1b6b2..3cd3539 100644
--- a/tests/unit/src/com/android/settings/deviceinfo/storage/StorageEntryTest.java
+++ b/tests/unit/src/com/android/settings/deviceinfo/storage/StorageEntryTest.java
@@ -209,6 +209,24 @@
}
@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);
final StorageEntry diskStorage = new StorageEntry(diskInfo);