diff --git a/src/com/android/settings/Utils.java b/src/com/android/settings/Utils.java index 4c8fb2d3414..d04ae8d0de9 100644 --- a/src/com/android/settings/Utils.java +++ b/src/com/android/settings/Utils.java @@ -73,7 +73,6 @@ import android.provider.ContactsContract.Data; import android.provider.ContactsContract.Profile; import android.provider.ContactsContract.RawContacts; import android.provider.Settings; -import android.service.persistentdata.PersistentDataBlockManager; import android.support.annotation.StringRes; import android.support.v7.preference.Preference; import android.support.v7.preference.PreferenceGroup; diff --git a/src/com/android/settings/applications/UserManagerWrapper.java b/src/com/android/settings/applications/UserManagerWrapper.java index daefb844d91..5b4ed2aa05f 100644 --- a/src/com/android/settings/applications/UserManagerWrapper.java +++ b/src/com/android/settings/applications/UserManagerWrapper.java @@ -17,6 +17,7 @@ package com.android.settings.applications; import android.content.pm.UserInfo; + import java.util.List; /** diff --git a/src/com/android/settings/deviceinfo/StorageDashboardFragment.java b/src/com/android/settings/deviceinfo/StorageDashboardFragment.java index 75c0e753b05..602e65f802f 100644 --- a/src/com/android/settings/deviceinfo/StorageDashboardFragment.java +++ b/src/com/android/settings/deviceinfo/StorageDashboardFragment.java @@ -20,6 +20,7 @@ import android.app.LoaderManager; import android.content.Context; import android.content.Intent; import android.content.Loader; +import android.graphics.drawable.Drawable; import android.os.Bundle; import android.os.UserHandle; import android.os.UserManager; @@ -47,6 +48,7 @@ import com.android.settings.deviceinfo.storage.SecondaryUserController; import com.android.settings.deviceinfo.storage.StorageAsyncLoader; import com.android.settings.deviceinfo.storage.StorageItemPreferenceController; import com.android.settings.deviceinfo.storage.StorageSummaryDonutPreferenceController; +import com.android.settings.deviceinfo.storage.UserIconLoader; import com.android.settings.search.BaseSearchIndexProvider; import com.android.settings.search.Indexable; import com.android.settingslib.applications.StorageStatsSource; @@ -61,6 +63,7 @@ public class StorageDashboardFragment extends DashboardFragment implements LoaderManager.LoaderCallbacks> { private static final String TAG = "StorageDashboardFrag"; private static final int STORAGE_JOB_ID = 0; + private static final int ICON_JOB_ID = 1; private static final int OPTIONS_MENU_MIGRATE_DATA = 100; private VolumeInfo mVolume; @@ -70,34 +73,6 @@ public class StorageDashboardFragment extends DashboardFragment private PrivateVolumeOptionMenuController mOptionMenuController; private List mSecondaryUsers; - @Override - public void onResume() { - super.onResume(); - getLoaderManager().initLoader(STORAGE_JOB_ID, Bundle.EMPTY, this); - } - - @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 data) { - mPreferenceController.onLoadFinished(data.get(UserHandle.myUserId())); - updateSecondaryUserControllers(mSecondaryUsers, data); - } - - @Override - public void onLoaderReset(Loader> loader) { - } - @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); @@ -139,6 +114,13 @@ public class StorageDashboardFragment extends DashboardFragment } } + @Override + public void onResume() { + super.onResume(); + getLoaderManager().initLoader(STORAGE_JOB_ID, Bundle.EMPTY, this); + getLoaderManager().initLoader(ICON_JOB_ID, Bundle.EMPTY, new IconLoaderCallbacks()); + } + @Override public int getMetricsCategory() { return MetricsProto.MetricsEvent.SETTINGS_STORAGE_CATEGORY; @@ -227,4 +209,55 @@ public class StorageDashboardFragment extends DashboardFragment } }; + + @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 data) { + mPreferenceController.onLoadFinished(data.get(UserHandle.myUserId())); + updateSecondaryUserControllers(mSecondaryUsers, data); + } + + @Override + public void onLoaderReset(Loader> loader) { + } + + /** + * IconLoaderCallbacks exists because StorageDashboardFragment already implements + * LoaderCallbacks for a different type. + */ + public final class IconLoaderCallbacks + implements LoaderManager.LoaderCallbacks> { + @Override + public Loader> onCreateLoader(int id, Bundle args) { + return new UserIconLoader( + getContext(), + () -> UserIconLoader.loadUserIconsWithContext(getContext())); + } + + @Override + public void onLoadFinished( + Loader> loader, SparseArray data) { + mSecondaryUsers + .stream() + .filter(controller -> controller instanceof UserIconLoader.UserIconHandler) + .forEach( + controller -> + ((UserIconLoader.UserIconHandler) controller) + .handleUserIcons(data)); + } + + @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 b3e89c65b9e..62e946d2690 100644 --- a/src/com/android/settings/deviceinfo/storage/SecondaryUserController.java +++ b/src/com/android/settings/deviceinfo/storage/SecondaryUserController.java @@ -18,6 +18,7 @@ package com.android.settings.deviceinfo.storage; import android.content.Context; import android.content.pm.UserInfo; +import android.graphics.drawable.Drawable; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.annotation.VisibleForTesting; @@ -37,8 +38,8 @@ import java.util.List; * SecondaryUserController controls the preferences on the Storage screen which had to do with * secondary users. */ -public class SecondaryUserController extends PreferenceController implements - StorageAsyncLoader.ResultHandler { +public class SecondaryUserController extends PreferenceController + implements StorageAsyncLoader.ResultHandler, UserIconLoader.UserIconHandler { // 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_"; @@ -69,8 +70,9 @@ public class SecondaryUserController extends PreferenceController implements } if (info == null || Utils.isProfileOf(primaryUser, info)) { - controllers.add(new UserProfileController(context, info, - USER_PROFILE_INSERTION_LOCATION)); + controllers.add( + new UserProfileController( + context, info, userManager, USER_PROFILE_INSERTION_LOCATION)); continue; } @@ -109,8 +111,6 @@ public class SecondaryUserController extends PreferenceController implements mStoragePreference.setStorageSize(mSize, mTotalSizeBytes); } - // TODO(b/36252572): Set the user icon appropriately here. - group.setVisible(true); group.addPreference(mStoragePreference); } @@ -161,6 +161,14 @@ public class SecondaryUserController extends PreferenceController implements } } + @Override + public void handleUserIcons(SparseArray fetchedIcons) { + Drawable userIcon = fetchedIcons.get(mUser.id); + if (userIcon != null) { + mStoragePreference.setIcon(userIcon); + } + } + private static class NoSecondaryUserController extends PreferenceController { public NoSecondaryUserController(Context context) { super(context); diff --git a/src/com/android/settings/deviceinfo/storage/UserIconLoader.java b/src/com/android/settings/deviceinfo/storage/UserIconLoader.java new file mode 100644 index 00000000000..4f00c3c5496 --- /dev/null +++ b/src/com/android/settings/deviceinfo/storage/UserIconLoader.java @@ -0,0 +1,75 @@ +/* + * 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.pm.UserInfo; +import android.graphics.drawable.Drawable; +import android.os.UserManager; +import android.util.Log; +import android.util.SparseArray; + +import com.android.internal.util.Preconditions; +import com.android.settings.Utils; +import com.android.settings.utils.AsyncLoader; + +/** + * Fetches a user icon as a loader using a given icon loading lambda. + */ +public class UserIconLoader extends AsyncLoader> { + private FetchUserIconTask mTask; + + /** + * Task to load all user icons. + */ + public interface FetchUserIconTask { + SparseArray getUserIcons(); + } + + /** + * Handle the output of this task. + */ + public interface UserIconHandler { + void handleUserIcons(SparseArray fetchedIcons); + } + + public UserIconLoader(Context context, FetchUserIconTask task) { + super(context); + mTask = Preconditions.checkNotNull(task); + } + + @Override + public SparseArray loadInBackground() { + return mTask.getUserIcons(); + } + + @Override + protected void onDiscardResult(SparseArray result) {} + + /** + * Loads the user icons using a given context. This returns a {@link SparseArray} which maps + * user ids to their user icons. + */ + public static SparseArray loadUserIconsWithContext(Context context) { + SparseArray value = new SparseArray<>(); + UserManager um = context.getSystemService(UserManager.class); + for (UserInfo userInfo : um.getUsers()) { + value.put(userInfo.id, Utils.getUserIcon(context, um, userInfo)); + } + return value; + } +} diff --git a/src/com/android/settings/deviceinfo/storage/UserProfileController.java b/src/com/android/settings/deviceinfo/storage/UserProfileController.java index 0e197400e68..18fa7b7df0d 100644 --- a/src/com/android/settings/deviceinfo/storage/UserProfileController.java +++ b/src/com/android/settings/deviceinfo/storage/UserProfileController.java @@ -19,6 +19,7 @@ package com.android.settings.deviceinfo.storage; import android.content.Context; import android.content.Intent; import android.content.pm.UserInfo; +import android.graphics.drawable.Drawable; import android.os.Bundle; import android.os.storage.VolumeInfo; import android.support.v7.preference.Preference; @@ -28,25 +29,27 @@ 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.applications.UserManagerWrapper; import com.android.settings.core.PreferenceController; import com.android.settings.deviceinfo.StorageItemPreference; 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 { +/** Defines a {@link PreferenceController} which handles a single profile of the primary user. */ +public class UserProfileController extends PreferenceController + implements StorageAsyncLoader.ResultHandler, UserIconLoader.UserIconHandler { private static final String PREFERENCE_KEY_BASE = "pref_profile_"; private StorageItemPreference mStoragePreference; + private UserManagerWrapper mUserManager; private UserInfo mUser; private long mTotalSizeBytes; private final int mPreferenceOrder; - public UserProfileController(Context context, UserInfo info, int preferenceOrder) { + public UserProfileController( + Context context, UserInfo info, UserManagerWrapper userManager, int preferenceOrder) { super(context); mUser = Preconditions.checkNotNull(info); + mUserManager = userManager; mPreferenceOrder = preferenceOrder; } @@ -66,7 +69,6 @@ public class UserProfileController extends PreferenceController implements mStoragePreference.setOrder(mPreferenceOrder); mStoragePreference.setKey(PREFERENCE_KEY_BASE + mUser.id); mStoragePreference.setTitle(mUser.name); - // TODO(b/36252572): Set user icon here. screen.addPreference(mStoragePreference); } @@ -110,4 +112,12 @@ public class UserProfileController extends PreferenceController implements public void setTotalSize(long totalSize) { mTotalSizeBytes = totalSize; } + + @Override + public void handleUserIcons(SparseArray fetchedIcons) { + Drawable userIcon = fetchedIcons.get(mUser.id); + if (userIcon != null) { + mStoragePreference.setIcon(userIcon); + } + } } 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 16bf1aef827..c55ba36052c 100644 --- a/tests/robotests/src/com/android/settings/deviceinfo/storage/SecondaryUserControllerTest.java +++ b/tests/robotests/src/com/android/settings/deviceinfo/storage/SecondaryUserControllerTest.java @@ -19,12 +19,14 @@ package com.android.settings.deviceinfo.storage; import static com.google.common.truth.Truth.assertThat; import static org.mockito.Matchers.anyString; -import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.content.Context; import android.content.pm.UserInfo; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.drawable.Drawable; import android.support.v7.preference.Preference; import android.support.v7.preference.PreferenceGroup; import android.support.v7.preference.PreferenceScreen; @@ -34,7 +36,9 @@ 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.R; import com.android.settingslib.applications.StorageStatsSource; +import com.android.settingslib.drawable.UserIconDrawable; import org.junit.Before; import org.junit.Test; @@ -187,4 +191,24 @@ public class SecondaryUserControllerTest { // We should have the NoSecondaryUserController. assertThat(controllers.get(0) instanceof SecondaryUserController).isFalse(); } + + @Test + public void iconCallbackChangesPreferenceIcon() throws Exception { + SparseArray icons = new SparseArray<>(); + Bitmap userBitmap = + BitmapFactory.decodeResource( + RuntimeEnvironment.application.getResources(), R.drawable.home); + UserIconDrawable drawable = new UserIconDrawable(100 /* size */).setIcon(userBitmap).bake(); + icons.put(10, drawable); + mPrimaryUser.name = TEST_NAME; + mPrimaryUser.id = 10; + mController.displayPreference(mScreen); + + mController.handleUserIcons(icons); + + final ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(Preference.class); + verify(mGroup).addPreference(argumentCaptor.capture()); + Preference preference = argumentCaptor.getValue(); + assertThat(preference.getIcon()).isEqualTo(drawable); + } } diff --git a/tests/robotests/src/com/android/settings/deviceinfo/storage/UserProfileControllerTest.java b/tests/robotests/src/com/android/settings/deviceinfo/storage/UserProfileControllerTest.java index ed49da48027..0c3fc47216c 100644 --- a/tests/robotests/src/com/android/settings/deviceinfo/storage/UserProfileControllerTest.java +++ b/tests/robotests/src/com/android/settings/deviceinfo/storage/UserProfileControllerTest.java @@ -18,7 +18,6 @@ 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 static org.mockito.Mockito.when; @@ -26,6 +25,9 @@ import static org.mockito.Mockito.when; import android.content.Context; import android.content.Intent; import android.content.pm.UserInfo; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.drawable.Drawable; import android.support.v7.preference.Preference; import android.support.v7.preference.PreferenceScreen; import android.util.SparseArray; @@ -36,7 +38,9 @@ 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.R; import com.android.settingslib.applications.StorageStatsSource; +import com.android.settingslib.drawable.UserIconDrawable; import org.junit.Before; import org.junit.Test; @@ -66,16 +70,15 @@ public class UserProfileControllerTest { MockitoAnnotations.initMocks(this); mContext = spy(RuntimeEnvironment.application); mPrimaryProfile = new UserInfo(); - mController = new UserProfileController(mContext, mPrimaryProfile, 0); + mController = new UserProfileController(mContext, mPrimaryProfile, mUserManager, 0); when(mScreen.getContext()).thenReturn(mContext); + mPrimaryProfile.name = TEST_NAME; + mPrimaryProfile.id = 10; + mController.displayPreference(mScreen); } @Test public void controllerAddsPrimaryProfilePreference() throws Exception { - mPrimaryProfile.name = TEST_NAME; - mPrimaryProfile.id = 10; - mController.displayPreference(mScreen); - final ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(Preference.class); verify(mScreen).addPreference(argumentCaptor.capture()); Preference preference = argumentCaptor.getValue(); @@ -86,9 +89,6 @@ public class UserProfileControllerTest { @Test public void tappingProfilePreferenceSendsToStorageProfileFragment() throws Exception { - mPrimaryProfile.name = TEST_NAME; - mPrimaryProfile.id = 10; - mController.displayPreference(mScreen); final ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(Preference.class); verify(mScreen).addPreference(argumentCaptor.capture()); @@ -105,9 +105,6 @@ public class UserProfileControllerTest { @Test public void acceptingResultUpdatesPreferenceSize() throws Exception { - mPrimaryProfile.name = TEST_NAME; - mPrimaryProfile.id = 10; - mController.displayPreference(mScreen); SparseArray result = new SparseArray<>(); StorageAsyncLoader.AppsStorageResult userResult = new StorageAsyncLoader.AppsStorageResult(); @@ -121,4 +118,21 @@ public class UserProfileControllerTest { assertThat(preference.getSummary()).isEqualTo("99.00B"); } + + @Test + public void iconCallbackChangesPreferenceIcon() throws Exception { + SparseArray icons = new SparseArray<>(); + Bitmap userBitmap = + BitmapFactory.decodeResource( + RuntimeEnvironment.application.getResources(), R.drawable.home); + UserIconDrawable drawable = new UserIconDrawable(100 /* size */).setIcon(userBitmap).bake(); + icons.put(10, drawable); + + mController.handleUserIcons(icons); + + final ArgumentCaptor argumentCaptor = ArgumentCaptor.forClass(Preference.class); + verify(mScreen).addPreference(argumentCaptor.capture()); + Preference preference = argumentCaptor.getValue(); + assertThat(preference.getIcon()).isEqualTo(drawable); + } } \ No newline at end of file