diff --git a/res/xml/storage_dashboard_fragment.xml b/res/xml/storage_dashboard_fragment.xml index 271d31bd859..fedc77fe4ce 100644 --- a/res/xml/storage_dashboard_fragment.xml +++ b/res/xml/storage_dashboard_fragment.xml @@ -16,40 +16,50 @@ + android:title="@string/storage_settings" + android:orderingFromXml="false"> + android:key="pref_summary" + android:order="0" /> + android:title="@string/storage_photos_videos" + android:order="1" > + android:title="@string/storage_music_audio" + android:order="2" > + android:title="@string/storage_games" + android:order="3" > + android:title="@string/storage_other_apps" + android:order="4" > + android:title="@string/storage_files" + android:order="5" > + android:title="@string/storage_detail_system" + android:order="100" > + android:title="@string/storage_other_users" + android:order="200" /> + android:fragment="com.android.settings.deletionhelper.AutomaticStorageManagerSettings" + android:order="300" > \ No newline at end of file diff --git a/res/xml/storage_profile_fragment.xml b/res/xml/storage_profile_fragment.xml new file mode 100644 index 00000000000..d0c5c3ac271 --- /dev/null +++ b/res/xml/storage_profile_fragment.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + diff --git a/src/com/android/settings/Utils.java b/src/com/android/settings/Utils.java index 124c44192d3..350ab9ce869 100644 --- a/src/com/android/settings/Utils.java +++ b/src/com/android/settings/Utils.java @@ -65,6 +65,7 @@ import android.os.ServiceManager; import android.os.UserHandle; import android.os.UserManager; import android.os.storage.StorageManager; +import android.os.storage.VolumeInfo; import android.preference.PreferenceFrameLayout; import android.provider.ContactsContract.CommonDataKinds; import android.provider.ContactsContract.Contacts; @@ -1258,4 +1259,21 @@ public final class Utils extends com.android.settingslib.Utils { (user.profileGroupId != UserInfo.NO_PROFILE_GROUP_ID && user.profileGroupId == profile.profileGroupId); } + + /** + * Tries to initalize a volume with the given bundle. If it is a valid, private, and readable + * {@link VolumeInfo}, it is returned. If it is not valid, null is returned. + */ + @Nullable + public static VolumeInfo maybeInitializeVolume(StorageManager sm, Bundle bundle) { + final String volumeId = bundle.getString(VolumeInfo.EXTRA_VOLUME_ID, + VolumeInfo.ID_PRIVATE_INTERNAL); + VolumeInfo volume = sm.findVolumeById(volumeId); + return isVolumeValid(volume) ? volume : null; + } + + private static boolean isVolumeValid(VolumeInfo volume) { + return (volume != null) && (volume.getType() == VolumeInfo.TYPE_PRIVATE) + && volume.isMountedReadable(); + } } diff --git a/src/com/android/settings/deviceinfo/StorageDashboardFragment.java b/src/com/android/settings/deviceinfo/StorageDashboardFragment.java index d65eb750bf7..72e1493409c 100644 --- a/src/com/android/settings/deviceinfo/StorageDashboardFragment.java +++ b/src/com/android/settings/deviceinfo/StorageDashboardFragment.java @@ -25,11 +25,11 @@ import android.os.UserManager; import android.os.storage.StorageManager; import android.os.storage.VolumeInfo; import android.provider.SearchIndexableResource; -import android.support.annotation.VisibleForTesting; import android.util.SparseArray; import com.android.internal.logging.nano.MetricsProto; import com.android.settings.R; +import com.android.settings.Utils; import com.android.settings.applications.PackageManagerWrapperImpl; import com.android.settings.applications.UserManagerWrapper; import com.android.settings.applications.UserManagerWrapperImpl; @@ -48,7 +48,6 @@ import com.android.settingslib.deviceinfo.StorageManagerVolumeProvider; import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import java.util.Map; public class StorageDashboardFragment extends DashboardFragment implements LoaderManager.LoaderCallbacks> { @@ -61,11 +60,6 @@ public class StorageDashboardFragment extends DashboardFragment private StorageItemPreferenceController mPreferenceController; private List mSecondaryUsers; - private boolean isVolumeValid() { - return (mVolume != null) && (mVolume.getType() == VolumeInfo.TYPE_PRIVATE) - && mVolume.isMountedReadable(); - } - @Override public void onResume() { super.onResume(); @@ -101,7 +95,8 @@ public class StorageDashboardFragment extends DashboardFragment // Initialize the storage sizes that we can quickly calc. final Context context = getActivity(); StorageManager sm = context.getSystemService(StorageManager.class); - if (!initializeVolume(sm, getArguments())) { + mVolume = Utils.maybeInitializeVolume(sm, getArguments()); + if (mVolume == null) { getActivity().finish(); return; } @@ -156,17 +151,6 @@ public class StorageDashboardFragment extends DashboardFragment return controllers; } - /** - * Initializes the volume with a given bundle and returns if the volume is valid. - */ - @VisibleForTesting - boolean initializeVolume(StorageManager sm, Bundle bundle) { - String volumeId = bundle.getString(VolumeInfo.EXTRA_VOLUME_ID, - VolumeInfo.ID_PRIVATE_INTERNAL); - mVolume = sm.findVolumeById(volumeId); - return isVolumeValid(); - } - /** * Updates the secondary user controller sizes. */ @@ -174,13 +158,10 @@ public class StorageDashboardFragment extends DashboardFragment SparseArray stats) { for (int i = 0, size = controllers.size(); i < size; i++) { PreferenceController controller = controllers.get(i); - if (controller instanceof SecondaryUserController) { - SecondaryUserController userController = (SecondaryUserController) controller; - int userId = userController.getUser().id; - StorageAsyncLoader.AppsStorageResult result = stats.get(userId); - if (result != null) { - userController.setSize(result.externalStats.totalBytes); - } + if (controller instanceof StorageAsyncLoader.ResultHandler) { + StorageAsyncLoader.ResultHandler userController = + (StorageAsyncLoader.ResultHandler) controller; + userController.handleResult(stats); } } } diff --git a/src/com/android/settings/deviceinfo/StorageProfileFragment.java b/src/com/android/settings/deviceinfo/StorageProfileFragment.java new file mode 100644 index 00000000000..6ae03daef47 --- /dev/null +++ b/src/com/android/settings/deviceinfo/StorageProfileFragment.java @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.deviceinfo; + +import android.app.LoaderManager; +import android.content.Context; +import android.content.Loader; +import android.os.Bundle; +import android.os.UserHandle; +import android.os.UserManager; +import android.os.storage.StorageManager; +import android.os.storage.VolumeInfo; +import android.util.SparseArray; + +import com.android.internal.logging.nano.MetricsProto; +import com.android.settings.R; +import com.android.settings.Utils; +import com.android.settings.applications.PackageManagerWrapperImpl; +import com.android.settings.applications.UserManagerWrapperImpl; +import com.android.settings.core.PreferenceController; +import com.android.settings.dashboard.DashboardFragment; +import com.android.settings.deviceinfo.storage.StorageAsyncLoader; +import com.android.settings.deviceinfo.storage.StorageAsyncLoader.AppsStorageResult; +import com.android.settings.deviceinfo.storage.StorageItemPreferenceController; +import com.android.settingslib.applications.StorageStatsSource; +import com.android.settingslib.deviceinfo.StorageManagerVolumeProvider; + +import java.util.ArrayList; +import java.util.List; + +/** + * StorageProfileFragment is a fragment which shows the storage results for a profile of the + * primary user. + */ +public class StorageProfileFragment extends DashboardFragment + implements LoaderManager.LoaderCallbacks> { + private static final String TAG = "StorageProfileFragment"; + public static final String USER_ID_EXTRA = "userId"; + private static final int APPS_JOB_ID = 0; + + private VolumeInfo mVolume; + private int mUserId; + private StorageItemPreferenceController mPreferenceController; + + @Override + public void onCreate(Bundle icicle) { + super.onCreate(icicle); + final Bundle args = getArguments(); + + // Initialize the storage sizes that we can quickly calc. + final Context context = getActivity(); + final StorageManager sm = context.getSystemService(StorageManager.class); + mVolume = Utils.maybeInitializeVolume(sm, args); + if (mVolume == null) { + getActivity().finish(); + return; + } + + mPreferenceController.setVolume(mVolume); + mUserId = args.getInt(USER_ID_EXTRA, UserHandle.myUserId()); + mPreferenceController.setUserId(mUserId); + } + + @Override + public void onResume() { + super.onResume(); + getLoaderManager().initLoader(APPS_JOB_ID, Bundle.EMPTY, this); + } + + @Override + public int getMetricsCategory() { + return MetricsProto.MetricsEvent.SETTINGS_STORAGE_PROFILE; + } + + @Override + protected String getLogTag() { + return TAG; + } + + @Override + protected int getPreferenceScreenResId() { + return R.xml.storage_profile_fragment; + } + + @Override + protected List getPreferenceControllers(Context context) { + final List controllers = new ArrayList<>(); + final StorageManager sm = context.getSystemService(StorageManager.class); + mPreferenceController = new StorageItemPreferenceController(context, this, + mVolume, new StorageManagerVolumeProvider(sm)); + controllers.add(mPreferenceController); + return controllers; + } + + @Override + public Loader> onCreateLoader(int id, Bundle args) { + Context context = getContext(); + return new StorageAsyncLoader(context, + new UserManagerWrapperImpl(context.getSystemService(UserManager.class)), + mVolume.fsUuid, + new StorageStatsSource(context), + new PackageManagerWrapperImpl(context.getPackageManager())); + } + + @Override + public void onLoadFinished(Loader> loader, + SparseArray result) { + mPreferenceController.onLoadFinished(result.get(mUserId)); + } + + @Override + public void onLoaderReset(Loader> loader) { + } +} diff --git a/src/com/android/settings/deviceinfo/storage/SecondaryUserController.java b/src/com/android/settings/deviceinfo/storage/SecondaryUserController.java index d45c6e394cd..a5e83732ef2 100644 --- a/src/com/android/settings/deviceinfo/storage/SecondaryUserController.java +++ b/src/com/android/settings/deviceinfo/storage/SecondaryUserController.java @@ -23,6 +23,7 @@ import android.support.annotation.Nullable; import android.support.annotation.VisibleForTesting; import android.support.v7.preference.PreferenceGroup; import android.support.v7.preference.PreferenceScreen; +import android.util.SparseArray; import com.android.settings.Utils; import com.android.settings.applications.UserManagerWrapper; @@ -35,10 +36,12 @@ import java.util.List; * SecondaryUserController controls the preferences on the Storage screen which had to do with * secondary users. */ -public class SecondaryUserController extends PreferenceController { +public class SecondaryUserController extends PreferenceController implements + StorageAsyncLoader.ResultHandler { // PreferenceGroupKey to try to add our preference onto. private static final String TARGET_PREFERENCE_GROUP_KEY = "pref_secondary_users"; private static final String PREFERENCE_KEY_BASE = "pref_user_"; + private static final int USER_PROFILE_INSERTION_LOCATION = 6; private static final int SIZE_NOT_SET = -1; private @NonNull UserInfo mUser; @@ -59,7 +62,13 @@ public class SecondaryUserController extends PreferenceController { List infos = userManager.getUsers(); for (int i = 0, size = infos.size(); i < size; i++) { UserInfo info = infos.get(i); + if (info.equals(primaryUser)) { + continue; + } + if (info == null || Utils.isProfileOf(primaryUser, info)) { + controllers.add(new UserProfileController(context, info, + USER_PROFILE_INSERTION_LOCATION)); continue; } @@ -131,6 +140,14 @@ public class SecondaryUserController extends PreferenceController { } } + public void handleResult(SparseArray stats) { + int userId = getUser().id; + StorageAsyncLoader.AppsStorageResult result = stats.get(userId); + if (result != null) { + setSize(result.externalStats.totalBytes); + } + } + private static class NoSecondaryUserController extends PreferenceController { public NoSecondaryUserController(Context context) { super(context); diff --git a/src/com/android/settings/deviceinfo/storage/StorageAsyncLoader.java b/src/com/android/settings/deviceinfo/storage/StorageAsyncLoader.java index a60831ba9db..d5d96a5f080 100644 --- a/src/com/android/settings/deviceinfo/storage/StorageAsyncLoader.java +++ b/src/com/android/settings/deviceinfo/storage/StorageAsyncLoader.java @@ -23,10 +23,9 @@ import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.UserInfo; import android.os.UserHandle; -import android.util.ArrayMap; import android.util.ArraySet; -import android.util.SparseArray; import android.util.Log; +import android.util.SparseArray; import com.android.settings.applications.PackageManagerWrapper; import com.android.settings.applications.UserManagerWrapper; @@ -34,7 +33,6 @@ import com.android.settings.utils.AsyncLoader; import com.android.settingslib.applications.StorageStatsSource; import java.util.List; -import java.util.Map; /** * StorageAsyncLoader is a Loader which loads categorized app information and external stats for all @@ -118,4 +116,12 @@ public class StorageAsyncLoader public long otherAppsSize; public StorageStatsSource.ExternalStorageStats externalStats; } + + /** + * ResultHandler defines a destination of data which can handle a result from + * {@link StorageAsyncLoader}. + */ + public interface ResultHandler { + void handleResult(SparseArray result); + } } diff --git a/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceController.java b/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceController.java index 88ba152e255..e31d968c2b2 100644 --- a/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceController.java +++ b/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceController.java @@ -22,7 +22,6 @@ 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.support.annotation.VisibleForTesting; import android.support.v7.preference.Preference; @@ -36,12 +35,12 @@ import com.android.settings.Utils; import com.android.settings.applications.ManageApplications; import com.android.settings.core.PreferenceController; import com.android.settings.core.instrumentation.MetricsFeatureProvider; - import com.android.settings.overlay.FeatureFactory; import com.android.settingslib.deviceinfo.StorageMeasurement; import com.android.settingslib.deviceinfo.StorageVolumeProvider; -import com.android.settingslib.applications.StorageStatsSource; +import java.util.ArrayList; +import java.util.List; import java.util.Map; /** @@ -70,7 +69,7 @@ public class StorageItemPreferenceController extends PreferenceController { private final MetricsFeatureProvider mMetricsFeatureProvider; private final StorageVolumeProvider mSvp; private VolumeInfo mVolume; - private final int mUserId; + private int mUserId; private long mSystemSize; private StorageItemPreferenceAlternate mPhotoPreference; @@ -89,8 +88,7 @@ public class StorageItemPreferenceController extends PreferenceController { mVolume = volume; mSvp = svp; mMetricsFeatureProvider = FeatureFactory.getFactory(context).getMetricsFeatureProvider(); - UserManager um = mContext.getSystemService(UserManager.class); - mUserId = um.getUserHandle(); + mUserId = UserHandle.myUserId(); } @Override @@ -157,6 +155,13 @@ public class StorageItemPreferenceController extends PreferenceController { mVolume = volume; } + /** + * Sets the user id for which this preference controller is handling. + */ + public void setUserId(int userId) { + mUserId = userId; + } + @Override public void displayPreference(PreferenceScreen screen) { mPhotoPreference = (StorageItemPreferenceAlternate) screen.findPreference(PHOTO_KEY); @@ -173,7 +178,9 @@ public class StorageItemPreferenceController extends PreferenceController { mAudioPreference.setStorageSize(data.musicAppsSize + data.externalStats.audioBytes); mGamePreference.setStorageSize(data.gamesSize); mAppPreference.setStorageSize(data.otherAppsSize); - mSystemPreference.setStorageSize(mSystemSize); + if (mSystemPreference != null) { + mSystemPreference.setStorageSize(mSystemSize); + } long unattributedBytes = data.externalStats.totalBytes - data.externalStats.audioBytes - data.externalStats.videoBytes - data.externalStats.imageBytes; @@ -188,6 +195,20 @@ public class StorageItemPreferenceController extends PreferenceController { mSystemSize = systemSize; } + /** + * Returns a list of keys used by this preference controller. + */ + public static List getUsedKeys() { + List list = new ArrayList<>(); + list.add(PHOTO_KEY); + list.add(AUDIO_KEY); + list.add(GAME_KEY); + list.add(OTHER_APPS_KEY); + list.add(SYSTEM_KEY); + list.add(FILES_KEY); + return list; + } + private Intent getPhotosIntent() { Intent intent = new Intent(); intent.setAction(android.content.Intent.ACTION_VIEW); diff --git a/src/com/android/settings/deviceinfo/storage/UserProfileController.java b/src/com/android/settings/deviceinfo/storage/UserProfileController.java new file mode 100644 index 00000000000..5da9fec89ec --- /dev/null +++ b/src/com/android/settings/deviceinfo/storage/UserProfileController.java @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.deviceinfo.storage; + +import android.content.Context; +import android.content.Intent; +import android.content.pm.UserInfo; +import android.os.Bundle; +import android.os.storage.VolumeInfo; +import android.support.v7.preference.Preference; +import android.support.v7.preference.PreferenceScreen; +import android.util.SparseArray; + +import com.android.internal.logging.nano.MetricsProto; +import com.android.internal.util.Preconditions; +import com.android.settings.Utils; +import com.android.settings.core.PreferenceController; +import com.android.settings.deviceinfo.StorageProfileFragment; +import com.android.settingslib.drawer.SettingsDrawerActivity; + +/** + * Defines a {@link PreferenceController} which handles a single profile of the primary user. + */ +public class UserProfileController extends PreferenceController implements + StorageAsyncLoader.ResultHandler { + private static final String PREFERENCE_KEY_BASE = "pref_profile_"; + private StorageItemPreferenceAlternate mStoragePreference; + private UserInfo mUser; + private final int mPreferenceOrder; + + public UserProfileController(Context context, UserInfo info, int preferenceOrder) { + super(context); + mUser = Preconditions.checkNotNull(info); + mPreferenceOrder = preferenceOrder; + } + + @Override + public boolean isAvailable() { + return true; + } + + @Override + public String getPreferenceKey() { + return PREFERENCE_KEY_BASE + mUser.id; + } + + @Override + public void displayPreference(PreferenceScreen screen) { + mStoragePreference = new StorageItemPreferenceAlternate(mContext); + mStoragePreference.setOrder(mPreferenceOrder); + mStoragePreference.setKey(PREFERENCE_KEY_BASE + mUser.id); + mStoragePreference.setTitle(mUser.name); + screen.addPreference(mStoragePreference); + } + + @Override + public boolean handlePreferenceTreeClick(Preference preference) { + if (preference != null && mStoragePreference == preference) { + Bundle args = new Bundle(2); + args.putInt(StorageProfileFragment.USER_ID_EXTRA, mUser.id); + args.putString(VolumeInfo.EXTRA_VOLUME_ID, VolumeInfo.ID_PRIVATE_INTERNAL); + Intent intent = Utils.onBuildStartFragmentIntent(mContext, + StorageProfileFragment.class.getName(), args, null, 0, + mUser.name, false, MetricsProto.MetricsEvent.DEVICEINFO_STORAGE); + intent.putExtra(SettingsDrawerActivity.EXTRA_SHOW_MENU, true); + mContext.startActivity(intent); + return true; + } + + return false; + } + + @Override + public void handleResult(SparseArray stats) { + Preconditions.checkNotNull(stats); + + int userId = mUser.id; + StorageAsyncLoader.AppsStorageResult result = stats.get(userId); + if (result != null) { + setSize(result.externalStats.totalBytes); + } + } + + /** + * Sets the size for the preference using a byte count. + */ + public void setSize(long size) { + if (mStoragePreference != null) { + mStoragePreference.setStorageSize(size); + } + } +} diff --git a/src/com/android/settings/search/SearchIndexableResources.java b/src/com/android/settings/search/SearchIndexableResources.java index 07e1459805e..956ac0b950c 100644 --- a/src/com/android/settings/search/SearchIndexableResources.java +++ b/src/com/android/settings/search/SearchIndexableResources.java @@ -45,6 +45,7 @@ import com.android.settings.connecteddevice.ConnectedDeviceDashboardFragment; import com.android.settings.datausage.DataUsageMeteredSettings; import com.android.settings.datausage.DataUsageSummary; import com.android.settings.deviceinfo.StorageDashboardFragment; +import com.android.settings.deviceinfo.StorageProfileFragment; import com.android.settings.deviceinfo.StorageSettings; import com.android.settings.display.ScreenZoomSettings; import com.android.settings.enterprise.EnterprisePrivacySettings; diff --git a/tests/robotests/assets/grandfather_not_implementing_index_provider b/tests/robotests/assets/grandfather_not_implementing_index_provider index 5e134bfe386..76d1013d61b 100644 --- a/tests/robotests/assets/grandfather_not_implementing_index_provider +++ b/tests/robotests/assets/grandfather_not_implementing_index_provider @@ -4,4 +4,5 @@ com.android.settings.notification.ZenModePrioritySettings com.android.settings.inputmethod.InputAndGestureSettings com.android.settings.accounts.AccountDetailDashboardFragment com.android.settings.gestures.GestureSettings -com.android.settings.fuelgauge.PowerUsageDetail \ No newline at end of file +com.android.settings.fuelgauge.PowerUsageDetail +com.android.settings.deviceinfo.StorageProfileFragment diff --git a/tests/robotests/src/com/android/settings/UtilsTest.java b/tests/robotests/src/com/android/settings/UtilsTest.java index 90a6e05c34b..324e75104b5 100644 --- a/tests/robotests/src/com/android/settings/UtilsTest.java +++ b/tests/robotests/src/com/android/settings/UtilsTest.java @@ -1,13 +1,25 @@ package com.android.settings; +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.RETURNS_DEEP_STUBS; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; + import android.content.Context; import android.net.ConnectivityManager; import android.net.LinkAddress; import android.net.LinkProperties; import android.net.Network; import android.net.wifi.WifiManager; +import android.os.Bundle; +import android.os.storage.DiskInfo; +import android.os.storage.StorageManager; +import android.os.storage.VolumeInfo; import android.text.format.DateUtils; -import java.net.InetAddress; + import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -16,9 +28,7 @@ import org.mockito.MockitoAnnotations; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; -import static com.google.common.truth.Truth.assertThat; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.when; +import java.net.InetAddress; @RunWith(SettingsRobolectricTestRunner.class) @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) @@ -97,4 +107,13 @@ public class UtilsTest { assertThat(Utils.formatElapsedTime(mContext, testMillis, false)).isEqualTo(expectedTime); } + + @Test + public void testInitializeVolumeDoesntBreakOnNullVolume() { + VolumeInfo info = new VolumeInfo("id", 0, new DiskInfo("id", 0), ""); + StorageManager storageManager = mock(StorageManager.class, RETURNS_DEEP_STUBS); + when(storageManager.findVolumeById(anyString())).thenReturn(info); + + Utils.maybeInitializeVolume(storageManager, new Bundle()); + } } diff --git a/tests/robotests/src/com/android/settings/deviceinfo/StorageDashboardFragmentTest.java b/tests/robotests/src/com/android/settings/deviceinfo/StorageDashboardFragmentTest.java index f16304ecdfc..e2a46de04c2 100644 --- a/tests/robotests/src/com/android/settings/deviceinfo/StorageDashboardFragmentTest.java +++ b/tests/robotests/src/com/android/settings/deviceinfo/StorageDashboardFragmentTest.java @@ -79,11 +79,4 @@ public class StorageDashboardFragmentTest { assertThat(indexRes).isNotNull(); assertThat(indexRes.get(0).xmlResId).isEqualTo(mFragment.getPreferenceScreenResId()); } - - @Test - public void testInitializeVolumeDoesntBreakOnNullVolume() { - VolumeInfo info = new VolumeInfo("id", 0, new DiskInfo("id", 0), ""); - when(mStorageManager.findVolumeById(anyString())).thenReturn(info); - mFragment.initializeVolume(mStorageManager, new Bundle()); - } } \ No newline at end of file diff --git a/tests/robotests/src/com/android/settings/deviceinfo/storage/SecondaryUserControllerTest.java b/tests/robotests/src/com/android/settings/deviceinfo/storage/SecondaryUserControllerTest.java index b11132de19e..7222f535553 100644 --- a/tests/robotests/src/com/android/settings/deviceinfo/storage/SecondaryUserControllerTest.java +++ b/tests/robotests/src/com/android/settings/deviceinfo/storage/SecondaryUserControllerTest.java @@ -28,11 +28,13 @@ import android.content.pm.UserInfo; import android.support.v7.preference.Preference; import android.support.v7.preference.PreferenceGroup; import android.support.v7.preference.PreferenceScreen; +import android.util.SparseArray; import com.android.settings.SettingsRobolectricTestRunner; import com.android.settings.TestConfig; import com.android.settings.applications.UserManagerWrapper; import com.android.settings.core.PreferenceController; +import com.android.settingslib.applications.StorageStatsSource; import org.junit.Before; import org.junit.Test; @@ -130,7 +132,7 @@ public class SecondaryUserControllerTest { } @Test - public void profilesOfPrimaryUserAreIgnored() throws Exception { + public void profilesOfPrimaryUserAreNotIgnored() throws Exception { ArrayList userInfos = new ArrayList<>(); UserInfo secondaryUser = new UserInfo(); secondaryUser.id = mPrimaryUser.id; @@ -142,7 +144,31 @@ public class SecondaryUserControllerTest { List controllers = SecondaryUserController.getSecondaryUserControllers(mContext, mUserManager); - assertThat(controllers).hasSize(1); - assertThat(controllers.get(0) instanceof SecondaryUserController).isFalse(); + assertThat(controllers).hasSize(2); + assertThat(controllers.get(0) instanceof UserProfileController).isTrue(); + assertThat(controllers.get(1) instanceof SecondaryUserController).isFalse(); + } + + @Test + public void controllerUpdatesPreferenceOnAcceptingResult() throws Exception { + mPrimaryUser.name = TEST_NAME; + mPrimaryUser.id = 10; + PreferenceScreen screen = mock(PreferenceScreen.class); + PreferenceGroup group = mock(PreferenceGroup.class); + when(screen.findPreference(anyString())).thenReturn(group); + when(group.getKey()).thenReturn(TARGET_PREFERENCE_GROUP_KEY); + mController.displayPreference(screen); + StorageAsyncLoader.AppsStorageResult userResult = + new StorageAsyncLoader.AppsStorageResult(); + SparseArray result = new SparseArray<>(); + userResult.externalStats = new StorageStatsSource.ExternalStorageStats(99, 33, 33, 33); + result.put(10, userResult); + + mController.handleResult(result); + final ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(Preference.class); + verify(group).addPreference(argumentCaptor.capture()); + Preference preference = argumentCaptor.getValue(); + + assertThat(preference.getSummary()).isEqualTo("99.00B"); } } diff --git a/tests/robotests/src/com/android/settings/deviceinfo/storage/UserProfileControllerTest.java b/tests/robotests/src/com/android/settings/deviceinfo/storage/UserProfileControllerTest.java new file mode 100644 index 00000000000..2cd4f760118 --- /dev/null +++ b/tests/robotests/src/com/android/settings/deviceinfo/storage/UserProfileControllerTest.java @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.deviceinfo.storage; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; + +import android.content.Context; +import android.content.Intent; +import android.content.pm.UserInfo; +import android.support.v7.preference.Preference; +import android.support.v7.preference.PreferenceScreen; +import android.util.SparseArray; + +import com.android.settings.SettingsActivity; +import com.android.settings.SettingsRobolectricTestRunner; +import com.android.settings.SubSettings; +import com.android.settings.TestConfig; +import com.android.settings.applications.UserManagerWrapper; +import com.android.settings.deviceinfo.StorageProfileFragment; +import com.android.settingslib.applications.StorageStatsSource; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +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 UserProfileControllerTest { + private static final String TEST_NAME = "Fred"; + + @Mock + private UserManagerWrapper mUserManager; + + private Context mContext; + private UserProfileController mController; + private UserInfo mPrimaryProfile; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + mContext = spy(RuntimeEnvironment.application); + mPrimaryProfile = new UserInfo(); + mController = new UserProfileController(mContext, mPrimaryProfile, 0); + } + + @Test + public void controllerAddsPrimaryProfilePreference() throws Exception { + mPrimaryProfile.name = TEST_NAME; + mPrimaryProfile.id = 10; + PreferenceScreen screen = mock(PreferenceScreen.class); + mController.displayPreference(screen); + + final ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(Preference.class); + verify(screen).addPreference(argumentCaptor.capture()); + Preference preference = argumentCaptor.getValue(); + + assertThat(preference.getTitle()).isEqualTo(TEST_NAME); + assertThat(preference.getKey()).isEqualTo("pref_profile_10"); + } + + @Test + public void tappingProfilePreferenceSendsToStorageProfileFragment() throws Exception { + mPrimaryProfile.name = TEST_NAME; + mPrimaryProfile.id = 10; + PreferenceScreen screen = mock(PreferenceScreen.class); + mController.displayPreference(screen); + + final ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(Preference.class); + verify(screen).addPreference(argumentCaptor.capture()); + Preference preference = argumentCaptor.getValue(); + assertThat(mController.handlePreferenceTreeClick(preference)).isTrue(); + final ArgumentCaptor intentCaptor = ArgumentCaptor.forClass(Intent.class); + verify(mContext).startActivity(intentCaptor.capture()); + + Intent intent = intentCaptor.getValue(); + assertThat(intent.getComponent().getClassName()).isEqualTo(SubSettings.class.getName()); + assertThat(intent.getStringExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT)).isEqualTo( + StorageProfileFragment.class.getName()); + } + + @Test + public void acceptingResultUpdatesPreferenceSize() throws Exception { + mPrimaryProfile.name = TEST_NAME; + mPrimaryProfile.id = 10; + PreferenceScreen screen = mock(PreferenceScreen.class); + mController.displayPreference(screen); + SparseArray result = new SparseArray<>(); + StorageAsyncLoader.AppsStorageResult userResult = + new StorageAsyncLoader.AppsStorageResult(); + userResult.externalStats = new StorageStatsSource.ExternalStorageStats(99, 33, 33, 33); + result.put(10, userResult); + + mController.handleResult(result); + final ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(Preference.class); + verify(screen).addPreference(argumentCaptor.capture()); + Preference preference = argumentCaptor.getValue(); + + assertThat(preference.getSummary()).isEqualTo("99.00B"); + } +} \ No newline at end of file