Merge "Also update the account preferences in displayPreference()." into oc-dev am: cf162d5354

am: 2a23542e68

Change-Id: Ifa0d367e40647ce825e90985658dc6a042edc2bd
This commit is contained in:
Doris Ling
2017-05-11 01:04:40 +00:00
committed by android-build-merger
3 changed files with 242 additions and 46 deletions

View File

@@ -2369,8 +2369,6 @@
</intent-filter> </intent-filter>
<meta-data android:name="com.android.settings.category" <meta-data android:name="com.android.settings.category"
android:value="com.android.settings.category.ia.accounts" /> android:value="com.android.settings.category.ia.accounts" />
<meta-data android:name="com.android.settings.summary"
android:resource="@string/summary_empty"/>
<meta-data android:name="com.android.settings.FRAGMENT_CLASS" <meta-data android:name="com.android.settings.FRAGMENT_CLASS"
android:value="com.android.settings.users.UserSettings" /> android:value="com.android.settings.users.UserSettings" />
<meta-data android:name="com.android.settings.PRIMARY_PROFILE_CONTROLLED" <meta-data android:name="com.android.settings.PRIMARY_PROFILE_CONTROLLED"

View File

@@ -34,6 +34,7 @@ import android.support.v7.preference.Preference;
import android.support.v7.preference.Preference.OnPreferenceClickListener; import android.support.v7.preference.Preference.OnPreferenceClickListener;
import android.support.v7.preference.PreferenceGroup; import android.support.v7.preference.PreferenceGroup;
import android.support.v7.preference.PreferenceScreen; import android.support.v7.preference.PreferenceScreen;
import android.util.ArrayMap;
import android.util.Log; import android.util.Log;
import android.util.SparseArray; import android.util.SparseArray;
@@ -117,6 +118,14 @@ public class AccountPreferenceController extends PreferenceController
* The {@link UserInfo} of the profile. * The {@link UserInfo} of the profile.
*/ */
public UserInfo userInfo; public UserInfo userInfo;
/**
* The {@link UserInfo} of the profile.
*/
public boolean pendingRemoval;
/**
* The map from account name to account preference
*/
public ArrayMap<CharSequence, AccountTypePreference> accountPreferences = new ArrayMap<>();
} }
public AccountPreferenceController(Context context, SettingsPreferenceFragment parent, public AccountPreferenceController(Context context, SettingsPreferenceFragment parent,
@@ -149,6 +158,12 @@ public class AccountPreferenceController extends PreferenceController
return null; return null;
} }
@Override
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
updateUi();
}
@Override @Override
public void updateRawDataToIndex(List<SearchIndexableRaw> rawData) { public void updateRawDataToIndex(List<SearchIndexableRaw> rawData) {
if (!isAvailable()) { if (!isAvailable()) {
@@ -189,7 +204,6 @@ public class AccountPreferenceController extends PreferenceController
@Override @Override
public void onResume() { public void onResume() {
cleanUpPreferences();
updateUi(); updateUi();
mManagedProfileBroadcastReceiver.register(mContext); mManagedProfileBroadcastReceiver.register(mContext);
listenToAccountUpdates(); listenToAccountUpdates();
@@ -253,6 +267,9 @@ public class AccountPreferenceController extends PreferenceController
return; return;
} }
for (int i = 0, size = mProfiles.size(); i < size; i++) {
mProfiles.valueAt(i).pendingRemoval = true;
}
if (mUm.isLinkedUser()) { if (mUm.isLinkedUser()) {
// Restricted user or similar // Restricted user or similar
UserInfo userInfo = mUm.getUserInfo(UserHandle.myUserId()); UserInfo userInfo = mUm.getUserInfo(UserHandle.myUserId());
@@ -264,6 +281,7 @@ public class AccountPreferenceController extends PreferenceController
updateProfileUi(profiles.get(i)); updateProfileUi(profiles.get(i));
} }
} }
cleanUpPreferences();
// Add all preferences, starting with one for the primary profile. // Add all preferences, starting with one for the primary profile.
// Note that we're relying on the ordering given by the SparseArray keys, and on the // Note that we're relying on the ordering given by the SparseArray keys, and on the
@@ -278,6 +296,11 @@ public class AccountPreferenceController extends PreferenceController
if (mParent.getPreferenceManager() == null) { if (mParent.getPreferenceManager() == null) {
return; return;
} }
final ProfileData data = mProfiles.get(userInfo.id);
if (data != null) {
data.pendingRemoval = false;
return;
}
final Context context = mContext; final Context context = mContext;
final ProfileData profileData = new ProfileData(); final ProfileData profileData = new ProfileData();
profileData.userInfo = userInfo; profileData.userInfo = userInfo;
@@ -366,12 +389,14 @@ public class AccountPreferenceController extends PreferenceController
if (screen == null) { if (screen == null) {
return; return;
} }
for (int i = 0; i < mProfiles.size(); i++) { final int count = mProfiles.size();
final PreferenceGroup preferenceGroup = mProfiles.valueAt(i).preferenceGroup; for (int i = count-1; i >= 0; i--) {
screen.removePreference(preferenceGroup); final ProfileData data = mProfiles.valueAt(i);
if (data.pendingRemoval) {
screen.removePreference(data.preferenceGroup);
mProfiles.removeAt(i);
}
} }
mProfiles.clear();
mAccountProfileOrder = ORDER_ACCOUNT_PROFILES;
} }
private void listenToAccountUpdates() { private void listenToAccountUpdates() {
@@ -400,18 +425,31 @@ public class AccountPreferenceController extends PreferenceController
// This could happen if activity is finishing // This could happen if activity is finishing
return; return;
} }
profileData.preferenceGroup.removeAll();
if (profileData.userInfo.isEnabled()) { if (profileData.userInfo.isEnabled()) {
final ArrayMap<CharSequence, AccountTypePreference> preferenceToRemove =
new ArrayMap<>(profileData.accountPreferences);
final ArrayList<AccountTypePreference> preferences = getAccountTypePreferences( final ArrayList<AccountTypePreference> preferences = getAccountTypePreferences(
profileData.authenticatorHelper, profileData.userInfo.getUserHandle()); profileData.authenticatorHelper, profileData.userInfo.getUserHandle(),
preferenceToRemove);
final int count = preferences.size(); final int count = preferences.size();
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
profileData.preferenceGroup.addPreference(preferences.get(i)); final AccountTypePreference preference = preferences.get(i);
preference.setOrder(i);
if (!profileData.accountPreferences.containsValue(preference)) {
profileData.preferenceGroup.addPreference(preferences.get(i));
profileData.accountPreferences.put(preference.getTitle(), preference);
}
} }
if (profileData.addAccountPreference != null) { if (profileData.addAccountPreference != null) {
profileData.preferenceGroup.addPreference(profileData.addAccountPreference); profileData.preferenceGroup.addPreference(profileData.addAccountPreference);
} }
for (CharSequence name : preferenceToRemove.keySet()) {
profileData.preferenceGroup.removePreference(
profileData.accountPreferences.get(name));
profileData.accountPreferences.remove(name);
}
} else { } else {
profileData.preferenceGroup.removeAll();
// Put a label instead of the accounts list // Put a label instead of the accounts list
if (mProfileNotAvailablePreference == null) { if (mProfileNotAvailablePreference == null) {
mProfileNotAvailablePreference = mProfileNotAvailablePreference =
@@ -433,7 +471,8 @@ public class AccountPreferenceController extends PreferenceController
} }
private ArrayList<AccountTypePreference> getAccountTypePreferences(AuthenticatorHelper helper, private ArrayList<AccountTypePreference> getAccountTypePreferences(AuthenticatorHelper helper,
UserHandle userHandle) { UserHandle userHandle,
ArrayMap<CharSequence, AccountTypePreference> preferenceToRemove) {
final String[] accountTypes = helper.getEnabledAccountTypes(); final String[] accountTypes = helper.getEnabledAccountTypes();
final ArrayList<AccountTypePreference> accountTypePreferences = final ArrayList<AccountTypePreference> accountTypePreferences =
new ArrayList<>(accountTypes.length); new ArrayList<>(accountTypes.length);
@@ -453,13 +492,16 @@ public class AccountPreferenceController extends PreferenceController
final Account[] accounts = AccountManager.get(mContext) final Account[] accounts = AccountManager.get(mContext)
.getAccountsByTypeAsUser(accountType, userHandle); .getAccountsByTypeAsUser(accountType, userHandle);
final boolean skipToAccount = accounts.length == 1
&& !helper.hasAccountPreferences(accountType);
final Drawable icon = helper.getDrawableForType(mContext, accountType); final Drawable icon = helper.getDrawableForType(mContext, accountType);
final Context prefContext = mParent.getPreferenceManager().getContext(); final Context prefContext = mParent.getPreferenceManager().getContext();
// Add a preference row for each individual account // Add a preference row for each individual account
for (Account account : accounts) { for (Account account : accounts) {
final AccountTypePreference preference = preferenceToRemove.remove(account.name);
if (preference != null) {
accountTypePreferences.add(preference);
continue;
}
final ArrayList<String> auths = final ArrayList<String> auths =
helper.getAuthoritiesForAccountType(account.type); helper.getAuthoritiesForAccountType(account.type);
if (!AccountRestrictionHelper.showAccount(mAuthorities, auths)) { if (!AccountRestrictionHelper.showAccount(mAuthorities, auths)) {
@@ -531,7 +573,6 @@ public class AccountPreferenceController extends PreferenceController
|| action.equals(Intent.ACTION_MANAGED_PROFILE_ADDED)) { || action.equals(Intent.ACTION_MANAGED_PROFILE_ADDED)) {
// Clean old state // Clean old state
stopListeningToAccountUpdates(); stopListeningToAccountUpdates();
cleanUpPreferences();
// Build new state // Build new state
updateUi(); updateUi();
listenToAccountUpdates(); listenToAccountUpdates();

View File

@@ -27,6 +27,7 @@ import android.support.v7.preference.PreferenceGroup;
import android.support.v7.preference.PreferenceManager; import android.support.v7.preference.PreferenceManager;
import android.support.v7.preference.PreferenceScreen; import android.support.v7.preference.PreferenceScreen;
import android.text.TextUtils;
import com.android.settings.AccessiblePreferenceCategory; import com.android.settings.AccessiblePreferenceCategory;
import com.android.settings.R; import com.android.settings.R;
import com.android.settings.SettingsPreferenceFragment; import com.android.settings.SettingsPreferenceFragment;
@@ -39,6 +40,7 @@ import com.android.settings.testutils.shadow.ShadowContentResolver;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.mockito.ArgumentMatcher;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.MockitoAnnotations; import org.mockito.MockitoAnnotations;
import org.robolectric.annotation.Config; import org.robolectric.annotation.Config;
@@ -51,20 +53,22 @@ import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Answers.RETURNS_DEEP_STUBS; import static org.mockito.Answers.RETURNS_DEEP_STUBS;
import static org.mockito.Matchers.any; import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.argThat;
import static org.mockito.Matchers.eq; import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never; import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times; import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
@RunWith(SettingsRobolectricTestRunner.class) @RunWith(SettingsRobolectricTestRunner.class)
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION) @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION,
shadows = {ShadowAccountManager.class, ShadowContentResolver.class})
public class AccountPreferenceControllerTest { public class AccountPreferenceControllerTest {
@Mock(answer = RETURNS_DEEP_STUBS) @Mock(answer = RETURNS_DEEP_STUBS)
private PreferenceScreen mScreen; private PreferenceScreen mScreen;
@Mock(answer = RETURNS_DEEP_STUBS) @Mock(answer = RETURNS_DEEP_STUBS)
private UserManager mUserManager; private UserManager mUserManager;
@Mock(answer = RETURNS_DEEP_STUBS) @Mock(answer = RETURNS_DEEP_STUBS)
@@ -145,43 +149,56 @@ public class AccountPreferenceControllerTest {
@Test @Test
@Config(shadows = {ShadowAccountManager.class, ShadowContentResolver.class}) @Config(shadows = {ShadowAccountManager.class, ShadowContentResolver.class})
public void onResume_oneProfiles_shouldRemoveOneAccountCategory() { public void onResume_noProfileChange_shouldNotAddOrRemoveAccountCategory() {
final List<UserInfo> infos = new ArrayList<>();
infos.add(new UserInfo(1, "user 1", UserInfo.FLAG_MANAGED_PROFILE));
when(mUserManager.isManagedProfile()).thenReturn(false);
when(mUserManager.isLinkedUser()).thenReturn(false);
when(mUserManager.getProfiles(anyInt())).thenReturn(infos);
AccessiblePreferenceCategory preferenceGroup = mock(AccessiblePreferenceCategory.class);
when(mAccountHelper.createAccessiblePreferenceCategory(any(Context.class))).thenReturn(
preferenceGroup);
// First time resume will build the UI, 2nd time will refresh the UI
mController.onResume();
mController.onResume();
verify(mScreen, times(1)).removePreference(any(PreferenceGroup.class));
verify(mScreen).removePreference(preferenceGroup);
}
@Test
@Config(shadows = {ShadowAccountManager.class, ShadowContentResolver.class})
public void onResume_twoProfiles_shouldRemoveTwoAccountCategory() {
final List<UserInfo> infos = new ArrayList<>(); final List<UserInfo> infos = new ArrayList<>();
infos.add(new UserInfo(1, "user 1", 0)); infos.add(new UserInfo(1, "user 1", 0));
infos.add(new UserInfo(2, "user 2", UserInfo.FLAG_MANAGED_PROFILE)); infos.add(new UserInfo(2, "user 2", UserInfo.FLAG_MANAGED_PROFILE));
when(mUserManager.isManagedProfile()).thenReturn(false); when(mUserManager.isManagedProfile()).thenReturn(false);
when(mUserManager.isLinkedUser()).thenReturn(false); when(mUserManager.isLinkedUser()).thenReturn(false);
when(mUserManager.getProfiles(anyInt())).thenReturn(infos); when(mUserManager.getProfiles(anyInt())).thenReturn(infos);
AccessiblePreferenceCategory preferenceGroup = mock(AccessiblePreferenceCategory.class); // First time resume will build the UI
when(mAccountHelper.createAccessiblePreferenceCategory(any(Context.class))).thenReturn(
preferenceGroup);
// First time resume will build the UI, 2nd time will refresh the UI
mController.onResume();
mController.onResume(); mController.onResume();
reset(mScreen);
verify(mScreen, times(2)).removePreference(any(PreferenceGroup.class)); mController.onResume();
verify(mScreen, times(2)).removePreference(preferenceGroup); verify(mScreen, never()).addPreference(any(PreferenceGroup.class));
verify(mScreen, never()).removePreference(any(PreferenceGroup.class));
}
@Test
@Config(shadows = {ShadowAccountManager.class, ShadowContentResolver.class})
public void onResume_oneNewProfile_shouldAddOneAccountCategory() {
final List<UserInfo> infos = new ArrayList<>();
infos.add(new UserInfo(1, "user 1", 0));
when(mUserManager.isManagedProfile()).thenReturn(false);
when(mUserManager.isLinkedUser()).thenReturn(false);
when(mUserManager.getProfiles(anyInt())).thenReturn(infos);
// First time resume will build the UI
mController.onResume();
// add a new profile
infos.add(new UserInfo(2, "user 2", UserInfo.FLAG_MANAGED_PROFILE));
reset(mScreen);
mController.onResume();
verify(mScreen, times(1)).addPreference(any(PreferenceGroup.class));
}
@Test
@Config(shadows = {ShadowAccountManager.class, ShadowContentResolver.class})
public void onResume_oneProfileRemoved_shouldRemoveOneAccountCategory() {
final List<UserInfo> infos = new ArrayList<>();
infos.add(new UserInfo(1, "user 1", 0));
infos.add(new UserInfo(2, "user 2", UserInfo.FLAG_MANAGED_PROFILE));
when(mUserManager.isManagedProfile()).thenReturn(false);
when(mUserManager.isLinkedUser()).thenReturn(false);
when(mUserManager.getProfiles(anyInt())).thenReturn(infos);
// First time resume will build the UI
mController.onResume();
// remove a profile
infos.remove(1);
mController.onResume();
verify(mScreen, times(1)).removePreference(any(PreferenceGroup.class));
} }
@Test @Test
@@ -348,4 +365,144 @@ public class AccountPreferenceControllerTest {
verify(preferenceGroup, times(3)).addPreference(any(Preference.class)); verify(preferenceGroup, times(3)).addPreference(any(Preference.class));
} }
@Test
@Config(shadows = {ShadowAccountManager.class, ShadowContentResolver.class})
public void onResume_noAccountChange_shouldNotAddAccountPreference() {
final List<UserInfo> infos = new ArrayList<>();
infos.add(new UserInfo(1, "user 1", 0));
when(mUserManager.isManagedProfile()).thenReturn(false);
when(mUserManager.isLinkedUser()).thenReturn(false);
when(mUserManager.getProfiles(anyInt())).thenReturn(infos);
Account[] accounts = {new Account("Acct1", "com.acct1")};
when(mAccountManager.getAccountsAsUser(anyInt())).thenReturn(accounts);
Account[] accountType1 = new Account[2];
accountType1[0] = new Account("Acct11", "com.acct1");
accountType1[1] = new Account("Acct12", "com.acct1");
when(mAccountManager.getAccountsByTypeAsUser(eq("com.acct1"), any(UserHandle.class)))
.thenReturn(accountType1);
AuthenticatorDescription[] authDescs = {
new AuthenticatorDescription("com.acct1", "com.android.settings",
R.string.account_settings_title, 0, 0, 0, false)
};
when(mAccountManager.getAuthenticatorTypesAsUser(anyInt())).thenReturn(authDescs);
AccessiblePreferenceCategory preferenceGroup = mock(AccessiblePreferenceCategory.class);
when(preferenceGroup.getPreferenceManager()).thenReturn(mock(PreferenceManager.class));
when(mAccountHelper.createAccessiblePreferenceCategory(any(Context.class))).thenReturn(
preferenceGroup);
mController.onResume();
mController.onResume();
// each account should be added only once
verify(preferenceGroup).addPreference(argThat(new PreferenceMatcher("Acct11")));
verify(preferenceGroup).addPreference(argThat(new PreferenceMatcher("Acct12")));
}
@Test
public void onResume_oneNewAccount_shouldAddOneAccountPreference() {
final List<UserInfo> infos = new ArrayList<>();
infos.add(new UserInfo(1, "user 1", 0));
when(mUserManager.isManagedProfile()).thenReturn(false);
when(mUserManager.isLinkedUser()).thenReturn(false);
when(mUserManager.getProfiles(anyInt())).thenReturn(infos);
Account[] accounts = {new Account("Acct1", "com.acct1")};
when(mAccountManager.getAccountsAsUser(anyInt())).thenReturn(accounts);
Account[] accountType1 = new Account[2];
accountType1[0] = new Account("Acct11", "com.acct1");
accountType1[1] = new Account("Acct12", "com.acct1");
when(mAccountManager.getAccountsByTypeAsUser(eq("com.acct1"), any(UserHandle.class)))
.thenReturn(accountType1);
AuthenticatorDescription[] authDescs = {
new AuthenticatorDescription("com.acct1", "com.android.settings",
R.string.account_settings_title, 0, 0, 0, false)
};
when(mAccountManager.getAuthenticatorTypesAsUser(anyInt())).thenReturn(authDescs);
AccessiblePreferenceCategory preferenceGroup = mock(AccessiblePreferenceCategory.class);
when(preferenceGroup.getPreferenceManager()).thenReturn(mock(PreferenceManager.class));
when(mAccountHelper.createAccessiblePreferenceCategory(any(Context.class))).thenReturn(
preferenceGroup);
mController.onResume();
// add a new account
accountType1 = new Account[3];
accountType1[0] = new Account("Acct11", "com.acct1");
accountType1[1] = new Account("Acct12", "com.acct1");
accountType1[2] = new Account("Acct13", "com.acct1");
when(mAccountManager.getAccountsByTypeAsUser(eq("com.acct1"), any(UserHandle.class)))
.thenReturn(accountType1);
mController.onResume();
// each account should be added only once
verify(preferenceGroup, times(1)).addPreference(argThat(new PreferenceMatcher("Acct11")));
verify(preferenceGroup, times(1)).addPreference(argThat(new PreferenceMatcher("Acct12")));
verify(preferenceGroup, times(1)).addPreference(argThat(new PreferenceMatcher("Acct13")));
}
@Test
@Config(shadows = {ShadowAccountManager.class, ShadowContentResolver.class})
public void onResume_oneAccountRemoved_shouldRemoveOneAccountPreference() {
final List<UserInfo> infos = new ArrayList<>();
infos.add(new UserInfo(1, "user 1", 0));
when(mUserManager.isManagedProfile()).thenReturn(false);
when(mUserManager.isLinkedUser()).thenReturn(false);
when(mUserManager.getProfiles(anyInt())).thenReturn(infos);
Account[] accounts = {new Account("Acct1", "com.acct1")};
when(mAccountManager.getAccountsAsUser(anyInt())).thenReturn(accounts);
Account[] accountType1 = new Account[2];
accountType1[0] = new Account("Acct11", "com.acct1");
accountType1[1] = new Account("Acct12", "com.acct1");
when(mAccountManager.getAccountsByTypeAsUser(eq("com.acct1"), any(UserHandle.class)))
.thenReturn(accountType1);
AuthenticatorDescription[] authDescs = {
new AuthenticatorDescription("com.acct1", "com.android.settings",
R.string.account_settings_title, 0, 0, 0, false)
};
when(mAccountManager.getAuthenticatorTypesAsUser(anyInt())).thenReturn(authDescs);
AccessiblePreferenceCategory preferenceGroup = mock(AccessiblePreferenceCategory.class);
when(preferenceGroup.getPreferenceManager()).thenReturn(mock(PreferenceManager.class));
when(mAccountHelper.createAccessiblePreferenceCategory(any(Context.class))).thenReturn(
preferenceGroup);
mController.onResume();
// remove an account
accountType1 = new Account[1];
accountType1[0] = new Account("Acct11", "com.acct1");
when(mAccountManager.getAccountsByTypeAsUser(eq("com.acct1"), any(UserHandle.class)))
.thenReturn(accountType1);
mController.onResume();
verify(preferenceGroup, times(1)).addPreference(argThat(new PreferenceMatcher("Acct11")));
verify(preferenceGroup, times(1)).addPreference(argThat(new PreferenceMatcher("Acct12")));
verify(preferenceGroup, times(1)).removePreference(
argThat(new PreferenceMatcher("Acct12")));
}
private static class PreferenceMatcher extends ArgumentMatcher<Preference> {
private final String mExpectedTitle;
public PreferenceMatcher(String title) {
mExpectedTitle = title;
}
@Override
public boolean matches(Object arg) {
final Preference preference = (Preference) arg;
return TextUtils.equals(mExpectedTitle, preference.getTitle());
}
}
} }