Merge "Add user icon to the other user preferences." into oc-dev

This commit is contained in:
Daniel Nishi
2017-04-10 17:27:24 +00:00
committed by Android (Google) Code Review
8 changed files with 219 additions and 55 deletions

View File

@@ -73,7 +73,6 @@ import android.provider.ContactsContract.Data;
import android.provider.ContactsContract.Profile; import android.provider.ContactsContract.Profile;
import android.provider.ContactsContract.RawContacts; import android.provider.ContactsContract.RawContacts;
import android.provider.Settings; import android.provider.Settings;
import android.service.persistentdata.PersistentDataBlockManager;
import android.support.annotation.StringRes; import android.support.annotation.StringRes;
import android.support.v7.preference.Preference; import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceGroup; import android.support.v7.preference.PreferenceGroup;

View File

@@ -17,6 +17,7 @@
package com.android.settings.applications; package com.android.settings.applications;
import android.content.pm.UserInfo; import android.content.pm.UserInfo;
import java.util.List; import java.util.List;
/** /**

View File

@@ -20,6 +20,7 @@ import android.app.LoaderManager;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.Loader; import android.content.Loader;
import android.graphics.drawable.Drawable;
import android.os.Bundle; import android.os.Bundle;
import android.os.UserHandle; import android.os.UserHandle;
import android.os.UserManager; 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.StorageAsyncLoader;
import com.android.settings.deviceinfo.storage.StorageItemPreferenceController; import com.android.settings.deviceinfo.storage.StorageItemPreferenceController;
import com.android.settings.deviceinfo.storage.StorageSummaryDonutPreferenceController; 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.BaseSearchIndexProvider;
import com.android.settings.search.Indexable; import com.android.settings.search.Indexable;
import com.android.settingslib.applications.StorageStatsSource; import com.android.settingslib.applications.StorageStatsSource;
@@ -61,6 +63,7 @@ public class StorageDashboardFragment extends DashboardFragment
implements LoaderManager.LoaderCallbacks<SparseArray<StorageAsyncLoader.AppsStorageResult>> { implements LoaderManager.LoaderCallbacks<SparseArray<StorageAsyncLoader.AppsStorageResult>> {
private static final String TAG = "StorageDashboardFrag"; private static final String TAG = "StorageDashboardFrag";
private static final int STORAGE_JOB_ID = 0; 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 static final int OPTIONS_MENU_MIGRATE_DATA = 100;
private VolumeInfo mVolume; private VolumeInfo mVolume;
@@ -70,34 +73,6 @@ public class StorageDashboardFragment extends DashboardFragment
private PrivateVolumeOptionMenuController mOptionMenuController; private PrivateVolumeOptionMenuController mOptionMenuController;
private List<PreferenceController> mSecondaryUsers; private List<PreferenceController> mSecondaryUsers;
@Override
public void onResume() {
super.onResume();
getLoaderManager().initLoader(STORAGE_JOB_ID, Bundle.EMPTY, this);
}
@Override
public Loader<SparseArray<StorageAsyncLoader.AppsStorageResult>> 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<SparseArray<StorageAsyncLoader.AppsStorageResult>> loader,
SparseArray<StorageAsyncLoader.AppsStorageResult> data) {
mPreferenceController.onLoadFinished(data.get(UserHandle.myUserId()));
updateSecondaryUserControllers(mSecondaryUsers, data);
}
@Override
public void onLoaderReset(Loader<SparseArray<StorageAsyncLoader.AppsStorageResult>> loader) {
}
@Override @Override
public void onCreate(Bundle icicle) { public void onCreate(Bundle icicle) {
super.onCreate(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 @Override
public int getMetricsCategory() { public int getMetricsCategory() {
return MetricsProto.MetricsEvent.SETTINGS_STORAGE_CATEGORY; return MetricsProto.MetricsEvent.SETTINGS_STORAGE_CATEGORY;
@@ -227,4 +209,55 @@ public class StorageDashboardFragment extends DashboardFragment
} }
}; };
@Override
public Loader<SparseArray<StorageAsyncLoader.AppsStorageResult>> 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<SparseArray<StorageAsyncLoader.AppsStorageResult>> loader,
SparseArray<StorageAsyncLoader.AppsStorageResult> data) {
mPreferenceController.onLoadFinished(data.get(UserHandle.myUserId()));
updateSecondaryUserControllers(mSecondaryUsers, data);
}
@Override
public void onLoaderReset(Loader<SparseArray<StorageAsyncLoader.AppsStorageResult>> loader) {
}
/**
* IconLoaderCallbacks exists because StorageDashboardFragment already implements
* LoaderCallbacks for a different type.
*/
public final class IconLoaderCallbacks
implements LoaderManager.LoaderCallbacks<SparseArray<Drawable>> {
@Override
public Loader<SparseArray<Drawable>> onCreateLoader(int id, Bundle args) {
return new UserIconLoader(
getContext(),
() -> UserIconLoader.loadUserIconsWithContext(getContext()));
}
@Override
public void onLoadFinished(
Loader<SparseArray<Drawable>> loader, SparseArray<Drawable> data) {
mSecondaryUsers
.stream()
.filter(controller -> controller instanceof UserIconLoader.UserIconHandler)
.forEach(
controller ->
((UserIconLoader.UserIconHandler) controller)
.handleUserIcons(data));
}
@Override
public void onLoaderReset(Loader<SparseArray<Drawable>> loader) {}
}
} }

View File

@@ -18,6 +18,7 @@ package com.android.settings.deviceinfo.storage;
import android.content.Context; import android.content.Context;
import android.content.pm.UserInfo; import android.content.pm.UserInfo;
import android.graphics.drawable.Drawable;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.support.annotation.VisibleForTesting; 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 * SecondaryUserController controls the preferences on the Storage screen which had to do with
* secondary users. * secondary users.
*/ */
public class SecondaryUserController extends PreferenceController implements public class SecondaryUserController extends PreferenceController
StorageAsyncLoader.ResultHandler { implements StorageAsyncLoader.ResultHandler, UserIconLoader.UserIconHandler {
// PreferenceGroupKey to try to add our preference onto. // PreferenceGroupKey to try to add our preference onto.
private static final String TARGET_PREFERENCE_GROUP_KEY = "pref_secondary_users"; private static final String TARGET_PREFERENCE_GROUP_KEY = "pref_secondary_users";
private static final String PREFERENCE_KEY_BASE = "pref_user_"; 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)) { if (info == null || Utils.isProfileOf(primaryUser, info)) {
controllers.add(new UserProfileController(context, info, controllers.add(
USER_PROFILE_INSERTION_LOCATION)); new UserProfileController(
context, info, userManager, USER_PROFILE_INSERTION_LOCATION));
continue; continue;
} }
@@ -109,8 +111,6 @@ public class SecondaryUserController extends PreferenceController implements
mStoragePreference.setStorageSize(mSize, mTotalSizeBytes); mStoragePreference.setStorageSize(mSize, mTotalSizeBytes);
} }
// TODO(b/36252572): Set the user icon appropriately here.
group.setVisible(true); group.setVisible(true);
group.addPreference(mStoragePreference); group.addPreference(mStoragePreference);
} }
@@ -161,6 +161,14 @@ public class SecondaryUserController extends PreferenceController implements
} }
} }
@Override
public void handleUserIcons(SparseArray<Drawable> fetchedIcons) {
Drawable userIcon = fetchedIcons.get(mUser.id);
if (userIcon != null) {
mStoragePreference.setIcon(userIcon);
}
}
private static class NoSecondaryUserController extends PreferenceController { private static class NoSecondaryUserController extends PreferenceController {
public NoSecondaryUserController(Context context) { public NoSecondaryUserController(Context context) {
super(context); super(context);

View File

@@ -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<SparseArray<Drawable>> {
private FetchUserIconTask mTask;
/**
* Task to load all user icons.
*/
public interface FetchUserIconTask {
SparseArray<Drawable> getUserIcons();
}
/**
* Handle the output of this task.
*/
public interface UserIconHandler {
void handleUserIcons(SparseArray<Drawable> fetchedIcons);
}
public UserIconLoader(Context context, FetchUserIconTask task) {
super(context);
mTask = Preconditions.checkNotNull(task);
}
@Override
public SparseArray<Drawable> loadInBackground() {
return mTask.getUserIcons();
}
@Override
protected void onDiscardResult(SparseArray<Drawable> 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<Drawable> loadUserIconsWithContext(Context context) {
SparseArray<Drawable> 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;
}
}

View File

@@ -19,6 +19,7 @@ package com.android.settings.deviceinfo.storage;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.pm.UserInfo; import android.content.pm.UserInfo;
import android.graphics.drawable.Drawable;
import android.os.Bundle; import android.os.Bundle;
import android.os.storage.VolumeInfo; import android.os.storage.VolumeInfo;
import android.support.v7.preference.Preference; 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.logging.nano.MetricsProto;
import com.android.internal.util.Preconditions; import com.android.internal.util.Preconditions;
import com.android.settings.Utils; import com.android.settings.Utils;
import com.android.settings.applications.UserManagerWrapper;
import com.android.settings.core.PreferenceController; import com.android.settings.core.PreferenceController;
import com.android.settings.deviceinfo.StorageItemPreference; import com.android.settings.deviceinfo.StorageItemPreference;
import com.android.settings.deviceinfo.StorageProfileFragment; import com.android.settings.deviceinfo.StorageProfileFragment;
import com.android.settingslib.drawer.SettingsDrawerActivity; import com.android.settingslib.drawer.SettingsDrawerActivity;
/** /** Defines a {@link PreferenceController} which handles a single profile of the primary user. */
* Defines a {@link PreferenceController} which handles a single profile of the primary user. public class UserProfileController extends PreferenceController
*/ implements StorageAsyncLoader.ResultHandler, UserIconLoader.UserIconHandler {
public class UserProfileController extends PreferenceController implements
StorageAsyncLoader.ResultHandler {
private static final String PREFERENCE_KEY_BASE = "pref_profile_"; private static final String PREFERENCE_KEY_BASE = "pref_profile_";
private StorageItemPreference mStoragePreference; private StorageItemPreference mStoragePreference;
private UserManagerWrapper mUserManager;
private UserInfo mUser; private UserInfo mUser;
private long mTotalSizeBytes; private long mTotalSizeBytes;
private final int mPreferenceOrder; private final int mPreferenceOrder;
public UserProfileController(Context context, UserInfo info, int preferenceOrder) { public UserProfileController(
Context context, UserInfo info, UserManagerWrapper userManager, int preferenceOrder) {
super(context); super(context);
mUser = Preconditions.checkNotNull(info); mUser = Preconditions.checkNotNull(info);
mUserManager = userManager;
mPreferenceOrder = preferenceOrder; mPreferenceOrder = preferenceOrder;
} }
@@ -66,7 +69,6 @@ public class UserProfileController extends PreferenceController implements
mStoragePreference.setOrder(mPreferenceOrder); mStoragePreference.setOrder(mPreferenceOrder);
mStoragePreference.setKey(PREFERENCE_KEY_BASE + mUser.id); mStoragePreference.setKey(PREFERENCE_KEY_BASE + mUser.id);
mStoragePreference.setTitle(mUser.name); mStoragePreference.setTitle(mUser.name);
// TODO(b/36252572): Set user icon here.
screen.addPreference(mStoragePreference); screen.addPreference(mStoragePreference);
} }
@@ -110,4 +112,12 @@ public class UserProfileController extends PreferenceController implements
public void setTotalSize(long totalSize) { public void setTotalSize(long totalSize) {
mTotalSizeBytes = totalSize; mTotalSizeBytes = totalSize;
} }
@Override
public void handleUserIcons(SparseArray<Drawable> fetchedIcons) {
Drawable userIcon = fetchedIcons.get(mUser.id);
if (userIcon != null) {
mStoragePreference.setIcon(userIcon);
}
}
} }

View File

@@ -19,12 +19,14 @@ package com.android.settings.deviceinfo.storage;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import android.content.Context; import android.content.Context;
import android.content.pm.UserInfo; 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.Preference;
import android.support.v7.preference.PreferenceGroup; import android.support.v7.preference.PreferenceGroup;
import android.support.v7.preference.PreferenceScreen; import android.support.v7.preference.PreferenceScreen;
@@ -34,7 +36,9 @@ import com.android.settings.SettingsRobolectricTestRunner;
import com.android.settings.TestConfig; import com.android.settings.TestConfig;
import com.android.settings.applications.UserManagerWrapper; import com.android.settings.applications.UserManagerWrapper;
import com.android.settings.core.PreferenceController; import com.android.settings.core.PreferenceController;
import com.android.settingslib.R;
import com.android.settingslib.applications.StorageStatsSource; import com.android.settingslib.applications.StorageStatsSource;
import com.android.settingslib.drawable.UserIconDrawable;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
@@ -187,4 +191,24 @@ public class SecondaryUserControllerTest {
// We should have the NoSecondaryUserController. // We should have the NoSecondaryUserController.
assertThat(controllers.get(0) instanceof SecondaryUserController).isFalse(); assertThat(controllers.get(0) instanceof SecondaryUserController).isFalse();
} }
@Test
public void iconCallbackChangesPreferenceIcon() throws Exception {
SparseArray<Drawable> 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<Preference> argumentCaptor = ArgumentCaptor.forClass(Preference.class);
verify(mGroup).addPreference(argumentCaptor.capture());
Preference preference = argumentCaptor.getValue();
assertThat(preference.getIcon()).isEqualTo(drawable);
}
} }

View File

@@ -18,7 +18,6 @@ package com.android.settings.deviceinfo.storage;
import static com.google.common.truth.Truth.assertThat; 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.spy;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
@@ -26,6 +25,9 @@ import static org.mockito.Mockito.when;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.pm.UserInfo; 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.Preference;
import android.support.v7.preference.PreferenceScreen; import android.support.v7.preference.PreferenceScreen;
import android.util.SparseArray; import android.util.SparseArray;
@@ -36,7 +38,9 @@ import com.android.settings.SubSettings;
import com.android.settings.TestConfig; import com.android.settings.TestConfig;
import com.android.settings.applications.UserManagerWrapper; import com.android.settings.applications.UserManagerWrapper;
import com.android.settings.deviceinfo.StorageProfileFragment; import com.android.settings.deviceinfo.StorageProfileFragment;
import com.android.settingslib.R;
import com.android.settingslib.applications.StorageStatsSource; import com.android.settingslib.applications.StorageStatsSource;
import com.android.settingslib.drawable.UserIconDrawable;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
@@ -66,16 +70,15 @@ public class UserProfileControllerTest {
MockitoAnnotations.initMocks(this); MockitoAnnotations.initMocks(this);
mContext = spy(RuntimeEnvironment.application); mContext = spy(RuntimeEnvironment.application);
mPrimaryProfile = new UserInfo(); mPrimaryProfile = new UserInfo();
mController = new UserProfileController(mContext, mPrimaryProfile, 0); mController = new UserProfileController(mContext, mPrimaryProfile, mUserManager, 0);
when(mScreen.getContext()).thenReturn(mContext); when(mScreen.getContext()).thenReturn(mContext);
mPrimaryProfile.name = TEST_NAME;
mPrimaryProfile.id = 10;
mController.displayPreference(mScreen);
} }
@Test @Test
public void controllerAddsPrimaryProfilePreference() throws Exception { public void controllerAddsPrimaryProfilePreference() throws Exception {
mPrimaryProfile.name = TEST_NAME;
mPrimaryProfile.id = 10;
mController.displayPreference(mScreen);
final ArgumentCaptor<Preference> argumentCaptor = ArgumentCaptor.forClass(Preference.class); final ArgumentCaptor<Preference> argumentCaptor = ArgumentCaptor.forClass(Preference.class);
verify(mScreen).addPreference(argumentCaptor.capture()); verify(mScreen).addPreference(argumentCaptor.capture());
Preference preference = argumentCaptor.getValue(); Preference preference = argumentCaptor.getValue();
@@ -86,9 +89,6 @@ public class UserProfileControllerTest {
@Test @Test
public void tappingProfilePreferenceSendsToStorageProfileFragment() throws Exception { public void tappingProfilePreferenceSendsToStorageProfileFragment() throws Exception {
mPrimaryProfile.name = TEST_NAME;
mPrimaryProfile.id = 10;
mController.displayPreference(mScreen);
final ArgumentCaptor<Preference> argumentCaptor = ArgumentCaptor.forClass(Preference.class); final ArgumentCaptor<Preference> argumentCaptor = ArgumentCaptor.forClass(Preference.class);
verify(mScreen).addPreference(argumentCaptor.capture()); verify(mScreen).addPreference(argumentCaptor.capture());
@@ -105,9 +105,6 @@ public class UserProfileControllerTest {
@Test @Test
public void acceptingResultUpdatesPreferenceSize() throws Exception { public void acceptingResultUpdatesPreferenceSize() throws Exception {
mPrimaryProfile.name = TEST_NAME;
mPrimaryProfile.id = 10;
mController.displayPreference(mScreen);
SparseArray<StorageAsyncLoader.AppsStorageResult> result = new SparseArray<>(); SparseArray<StorageAsyncLoader.AppsStorageResult> result = new SparseArray<>();
StorageAsyncLoader.AppsStorageResult userResult = StorageAsyncLoader.AppsStorageResult userResult =
new StorageAsyncLoader.AppsStorageResult(); new StorageAsyncLoader.AppsStorageResult();
@@ -121,4 +118,21 @@ public class UserProfileControllerTest {
assertThat(preference.getSummary()).isEqualTo("99.00B"); assertThat(preference.getSummary()).isEqualTo("99.00B");
} }
@Test
public void iconCallbackChangesPreferenceIcon() throws Exception {
SparseArray<Drawable> 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<Preference> argumentCaptor = ArgumentCaptor.forClass(Preference.class);
verify(mScreen).addPreference(argumentCaptor.capture());
Preference preference = argumentCaptor.getValue();
assertThat(preference.getIcon()).isEqualTo(drawable);
}
} }