diff --git a/res/xml/storage_dashboard_fragment.xml b/res/xml/storage_dashboard_fragment.xml index d5772675aec..50287c39d0e 100644 --- a/res/xml/storage_dashboard_fragment.xml +++ b/res/xml/storage_dashboard_fragment.xml @@ -21,32 +21,26 @@ android:key="pref_summary" /> + android:title="@string/storage_photos_videos"> + android:title="@string/storage_music_audio"> + android:title="@string/storage_games"> + android:title="@string/storage_other_apps"> + android:title="@string/storage_detail_system"> + android:title="@string/storage_files"> \ No newline at end of file diff --git a/src/com/android/settings/deviceinfo/StorageDashboardFragment.java b/src/com/android/settings/deviceinfo/StorageDashboardFragment.java index 5d1ac4a759a..abefce6bb8e 100644 --- a/src/com/android/settings/deviceinfo/StorageDashboardFragment.java +++ b/src/com/android/settings/deviceinfo/StorageDashboardFragment.java @@ -35,6 +35,7 @@ import com.android.settings.overlay.FeatureFactory; import com.android.settings.search.BaseSearchIndexProvider; import com.android.settings.search.Indexable; import com.android.settings.widget.FooterPreference; +import com.android.settingslib.deviceinfo.StorageManagerVolumeProvider; import com.android.settingslib.drawer.CategoryKey; import java.util.ArrayList; @@ -48,6 +49,7 @@ public class StorageDashboardFragment extends DashboardFragment { private long mTotalSize; private StorageSummaryDonutPreferenceController mSummaryController; + private StorageItemPreferenceController mPreferenceController; private boolean isVolumeValid() { return (mVolume != null) && (mVolume.getType() == VolumeInfo.TYPE_PRIVATE) @@ -78,6 +80,7 @@ public class StorageDashboardFragment extends DashboardFragment { final long usedBytes = mTotalSize - mVolume.getPath().getFreeSpace(); mSummaryController.updateBytes(usedBytes, mTotalSize); + mPreferenceController.setVolume(mVolume); // Initialize the footer preference to go to the smart storage management. final FooterPreference pref = mFooterPreferenceMixin.createFooterPreference(); @@ -114,13 +117,12 @@ public class StorageDashboardFragment extends DashboardFragment { final List controllers = new ArrayList<>(); mSummaryController = new StorageSummaryDonutPreferenceController(context); controllers.add(mSummaryController); + + StorageManager sm = context.getSystemService(StorageManager.class); + mPreferenceController = new StorageItemPreferenceController(context, this, mVolume, + new StorageManagerVolumeProvider(sm)); + controllers.add(mPreferenceController); controllers.add(new ManageStoragePreferenceController(context)); - controllers.add(new StorageItemPreferenceController(context, "pref_photos_videos")); - controllers.add(new StorageItemPreferenceController(context, "pref_music_audio")); - controllers.add(new StorageItemPreferenceController(context, "pref_games")); - controllers.add(new StorageItemPreferenceController(context, "pref_other_apps")); - controllers.add(new StorageItemPreferenceController(context, "pref_system")); - controllers.add(new StorageItemPreferenceController(context, "pref_files")); return controllers; } diff --git a/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceController.java b/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceController.java index 6a610721b42..3e802fd5cd4 100644 --- a/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceController.java +++ b/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceController.java @@ -16,23 +16,48 @@ package com.android.settings.deviceinfo.storage; +import android.app.Fragment; +import android.content.ActivityNotFoundException; import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.os.UserHandle; +import android.os.UserManager; +import android.os.storage.VolumeInfo; +import android.provider.DocumentsContract; import android.support.v7.preference.Preference; +import android.util.Log; +import com.android.settings.R; +import com.android.settings.Settings; +import com.android.settings.Utils; +import com.android.settings.applications.ManageApplications; import com.android.settings.core.PreferenceController; +import com.android.settingslib.deviceinfo.StorageVolumeProvider; + /** - * StorageItemPreferenceController handles the updating of a single storage preference line item. + * StorageItemPreferenceController handles the storage line items which summarize the storage + * categorization breakdown. */ public class StorageItemPreferenceController extends PreferenceController { - private static final long NOT_YET_SET = -1; - private final String mKey; - private long mStorageSize; + private static final String TAG = "StorageItemPreference"; + private final Fragment mFragment; + private final StorageVolumeProvider mSvp; + private VolumeInfo mVolume; + private final int mUserId; - public StorageItemPreferenceController(Context context, String key) { + private static final String AUTHORITY_MEDIA = "com.android.providers.media.documents"; + + public StorageItemPreferenceController(Context context, Fragment hostFragment, + VolumeInfo volume, StorageVolumeProvider svp) { super(context); - mKey = key; - mStorageSize = NOT_YET_SET; + mFragment = hostFragment; + mVolume = volume; + mSvp = svp; + + UserManager um = mContext.getSystemService(UserManager.class); + mUserId = um.getUserHandle(); } @Override @@ -42,28 +67,97 @@ public class StorageItemPreferenceController extends PreferenceController { @Override public boolean handlePreferenceTreeClick(Preference preference) { - return false; + if (preference == null) { + return false; + } + + // TODO: Currently, this reflects the existing behavior for these toggles. + // After the intermediate views are built, swap them in. + Intent intent = null; + switch (preference.getKey()) { + case "pref_photos_videos": + intent = getPhotosIntent(); + break; + case "pref_music_audio": + intent = getAudioIntent(); + break; + case "pref_games": + // TODO: Once app categorization is added, make this section. + case "pref_other_apps": + // Because we are likely constructed with a null volume, this is theoretically + // possible. + if (mVolume == null) { + break; + } + intent = getAppsIntent(); + break; + case "pref_files": + intent = getFilesIntent(); + break; + } + + if (intent != null) { + intent.putExtra(Intent.EXTRA_USER_ID, mUserId); + + launchIntent(intent); + return true; + } + + return super.handlePreferenceTreeClick(preference); } @Override public String getPreferenceKey() { - return mKey; - } - - @Override - public void updateState(Preference preference) { - if (preference == null || mStorageSize == NOT_YET_SET) { - return; - } - - StorageItemPreferenceAlternate summary = (StorageItemPreferenceAlternate) preference; - summary.setStorageSize(mStorageSize); + return null; } /** - * Sets the amount of bytes used by this storage item. + * Sets the storage volume to use for when handling taps. */ - public void setStorageSize(long size) { - mStorageSize = size; + public void setVolume(VolumeInfo volume) { + mVolume = volume; + } + + private Intent getPhotosIntent() { + Intent intent = new Intent(DocumentsContract.ACTION_BROWSE); + intent.setData(DocumentsContract.buildRootUri(AUTHORITY_MEDIA, "images_root")); + intent.addCategory(Intent.CATEGORY_DEFAULT); + return intent; + } + + private Intent getAudioIntent() { + Intent intent = new Intent(DocumentsContract.ACTION_BROWSE); + intent.setData(DocumentsContract.buildRootUri(AUTHORITY_MEDIA, "audio_root")); + intent.addCategory(Intent.CATEGORY_DEFAULT); + return intent; + } + + private Intent getAppsIntent() { + Bundle args = new Bundle(); + args.putString(ManageApplications.EXTRA_CLASSNAME, + Settings.StorageUseActivity.class.getName()); + args.putString(ManageApplications.EXTRA_VOLUME_UUID, mVolume.getFsUuid()); + args.putString(ManageApplications.EXTRA_VOLUME_NAME, mVolume.getDescription()); + return Utils.onBuildStartFragmentIntent(mContext, + ManageApplications.class.getName(), args, null, R.string.apps_storage, null, + false); + } + + private Intent getFilesIntent() { + return mSvp.findEmulatedForPrivate(mVolume).buildBrowseIntent(); + } + + private void launchIntent(Intent intent) { + try { + final int userId = intent.getIntExtra(Intent.EXTRA_USER_ID, -1); + + if (userId == -1) { + mFragment.startActivity(intent); + } else { + mFragment.getActivity().startActivityAsUser(intent, new UserHandle(userId)); + } + } catch (ActivityNotFoundException e) { + Log.w(TAG, "No activity found for " + intent); + } } } 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 1862dd09b26..19936c468ff 100644 --- a/tests/robotests/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceControllerTest.java @@ -17,63 +17,129 @@ package com.android.settings.deviceinfo.storage; import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.app.Fragment; import android.content.Context; -import android.support.v7.preference.Preference; -import android.support.v7.preference.PreferenceViewHolder; +import android.content.Intent; +import android.os.UserHandle; +import android.os.storage.VolumeInfo; +import android.provider.DocumentsContract; import android.view.LayoutInflater; -import android.view.View; import android.widget.LinearLayout; +import com.android.settings.R; +import com.android.settings.SettingsActivity; import com.android.settings.SettingsRobolectricTestRunner; +import com.android.settings.SubSettings; import com.android.settings.TestConfig; -import com.android.settings.deviceinfo.StorageItemPreference; +import com.android.settings.applications.ManageApplications; +import com.android.settingslib.deviceinfo.StorageVolumeProvider; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.Mockito; +import org.mockito.Answers; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; @RunWith(SettingsRobolectricTestRunner.class) @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) public class StorageItemPreferenceControllerTest { - private static final String KEY = "pref"; private Context mContext; + private VolumeInfo mVolume; + @Mock(answer = Answers.RETURNS_DEEP_STUBS) + private Fragment mFragment; + @Mock + private StorageVolumeProvider mSvp; private StorageItemPreferenceController mController; - private PreferenceViewHolder mHolder; private StorageItemPreferenceAlternate mPreference; @Before public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + mVolume = new VolumeInfo("id", 0, null, "id"); mContext = RuntimeEnvironment.application; - mController = new StorageItemPreferenceController(mContext, KEY); + mController = new StorageItemPreferenceController(mContext, mFragment, mVolume, mSvp); mPreference = new StorageItemPreferenceAlternate(mContext); // Inflate the preference and the widget. LayoutInflater inflater = LayoutInflater.from(mContext); - final View view = inflater.inflate(mPreference.getLayoutResource(), - new LinearLayout(mContext), false); - - mHolder = new PreferenceViewHolder(view); - } - - @Test - public void testGetKey() { - assertThat(mController.getPreferenceKey()).isEqualTo(KEY); + inflater.inflate(mPreference.getLayoutResource(), new LinearLayout(mContext), false); } @Test public void testUpdateStateWithInitialState() { - mController.updateState(mPreference); - assertThat(mPreference.getSummary().toString()).isEqualTo("Calculating…"); + assertThat(mPreference.getSummary().toString()).isEqualTo( + mContext.getString(R.string.memory_calculating_size)); } @Test - public void testPreferenceShouldUpdateAfterPopulatingData() { - mController.setStorageSize(1024L); - mController.updateState(mPreference); - assertThat(mPreference.getSummary().toString()).isEqualTo("1.00KB"); + public void testClickPhotos() { + mPreference.setKey("pref_photos_videos"); + mController.handlePreferenceTreeClick(mPreference); + final ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(Intent.class); + verify(mFragment.getActivity()).startActivityAsUser(argumentCaptor.capture(), + any(UserHandle.class)); + + Intent intent = argumentCaptor.getValue(); + assertThat(intent.getAction()).isEqualTo(DocumentsContract.ACTION_BROWSE); + assertThat(intent.getData()).isEqualTo(DocumentsContract.buildRootUri( + "com.android.providers.media.documents", + "images_root")); + } + + @Test + public void testClickAudio() { + mPreference.setKey("pref_music_audio"); + mController.handlePreferenceTreeClick(mPreference); + + final ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(Intent.class); + verify(mFragment.getActivity()).startActivityAsUser(argumentCaptor.capture(), + any(UserHandle.class)); + + Intent intent = argumentCaptor.getValue(); + assertThat(intent.getAction()).isEqualTo(DocumentsContract.ACTION_BROWSE); + assertThat(intent.getData()).isEqualTo(DocumentsContract.buildRootUri( + "com.android.providers.media.documents", + "audio_root")); + } + + @Test + public void testClickApps() { + mPreference.setKey("pref_other_apps"); + mController.handlePreferenceTreeClick(mPreference); + + final ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(Intent.class); + verify(mFragment.getActivity()).startActivityAsUser(argumentCaptor.capture(), + any(UserHandle.class)); + + Intent intent = argumentCaptor.getValue(); + assertThat(intent.getAction()).isEqualTo(Intent.ACTION_MAIN); + assertThat(intent.getComponent().getClassName()).isEqualTo(SubSettings.class.getName()); + assertThat(intent.getStringExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT)).isEqualTo( + ManageApplications.class.getName()); + } + + @Test + public void testClickFiles() { + when(mSvp.findEmulatedForPrivate(any(VolumeInfo.class))).thenReturn(mVolume); + mPreference.setKey("pref_files"); + mController.handlePreferenceTreeClick(mPreference); + + final ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(Intent.class); + verify(mFragment.getActivity()).startActivityAsUser(argumentCaptor.capture(), + any(UserHandle.class)); + + Intent intent = argumentCaptor.getValue(); + Intent browseIntent = mVolume.buildBrowseIntent(); + assertThat(intent.getAction()).isEqualTo(browseIntent.getAction()); + assertThat(intent.getData()).isEqualTo(browseIntent.getData()); } } \ No newline at end of file