• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.android.settings.accounts;
17 
18 import android.accounts.Account;
19 import android.accounts.AccountManager;
20 import android.accounts.AuthenticatorDescription;
21 import android.content.Context;
22 import android.content.pm.UserInfo;
23 import android.os.UserHandle;
24 import android.os.UserManager;
25 import android.support.v7.preference.Preference;
26 import android.support.v7.preference.PreferenceGroup;
27 import android.support.v7.preference.PreferenceManager;
28 import android.support.v7.preference.PreferenceScreen;
29 import android.text.TextUtils;
30 
31 import com.android.settings.AccessiblePreferenceCategory;
32 import com.android.settings.R;
33 import com.android.settings.SettingsPreferenceFragment;
34 import com.android.settings.SettingsRobolectricTestRunner;
35 import com.android.settings.TestConfig;
36 import com.android.settings.search.SearchIndexableRaw;
37 import com.android.settings.testutils.shadow.ShadowAccountManager;
38 import com.android.settings.testutils.shadow.ShadowContentResolver;
39 
40 import org.junit.Before;
41 import org.junit.Test;
42 import org.junit.runner.RunWith;
43 import org.mockito.ArgumentMatcher;
44 import org.mockito.Mock;
45 import org.mockito.MockitoAnnotations;
46 import org.robolectric.annotation.Config;
47 import org.robolectric.shadows.ShadowApplication;
48 
49 import java.util.ArrayList;
50 import java.util.List;
51 
52 import static com.google.common.truth.Truth.assertThat;
53 import static org.mockito.Answers.RETURNS_DEEP_STUBS;
54 import static org.mockito.Matchers.any;
55 import static org.mockito.Matchers.anyInt;
56 import static org.mockito.Matchers.argThat;
57 import static org.mockito.Matchers.eq;
58 import static org.mockito.Mockito.mock;
59 import static org.mockito.Mockito.never;
60 import static org.mockito.Mockito.reset;
61 import static org.mockito.Mockito.times;
62 import static org.mockito.Mockito.verify;
63 import static org.mockito.Mockito.when;
64 
65 @RunWith(SettingsRobolectricTestRunner.class)
66 @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION,
67         shadows = {ShadowAccountManager.class, ShadowContentResolver.class})
68 public class AccountPreferenceControllerTest {
69 
70     @Mock(answer = RETURNS_DEEP_STUBS)
71     private PreferenceScreen mScreen;
72     @Mock(answer = RETURNS_DEEP_STUBS)
73     private UserManager mUserManager;
74     @Mock(answer = RETURNS_DEEP_STUBS)
75     private SettingsPreferenceFragment mFragment;
76     @Mock(answer = RETURNS_DEEP_STUBS)
77     private AccountManager mAccountManager;
78     @Mock(answer = RETURNS_DEEP_STUBS)
79     private AccountRestrictionHelper mAccountHelper;
80 
81     private Context mContext;
82     private AccountPreferenceController mController;
83 
84     @Before
setUp()85     public void setUp() {
86         MockitoAnnotations.initMocks(this);
87         ShadowApplication shadowContext = ShadowApplication.getInstance();
88         shadowContext.setSystemService(Context.USER_SERVICE, mUserManager);
89         shadowContext.setSystemService(Context.ACCOUNT_SERVICE, mAccountManager);
90         mContext = shadowContext.getApplicationContext();
91 
92         when(mFragment.getPreferenceScreen()).thenReturn(mScreen);
93         when(mFragment.getPreferenceManager().getContext()).thenReturn(mContext);
94         when(mAccountManager.getAuthenticatorTypesAsUser(anyInt())).thenReturn(
95                 new AuthenticatorDescription[0]);
96         when(mAccountManager.getAccountsAsUser(anyInt())).thenReturn(new Account[0]);
97         mController = new AccountPreferenceController(mContext, mFragment, null, mAccountHelper);
98     }
99 
100     @Test
onResume_managedProfile_shouldNotAddAccountCategory()101     public void onResume_managedProfile_shouldNotAddAccountCategory() {
102         when(mUserManager.isManagedProfile()).thenReturn(true);
103         mController.onResume();
104 
105         verify(mScreen, never()).addPreference(any(Preference.class));
106     }
107 
108     @Test
109     @Config(shadows = {ShadowAccountManager.class, ShadowContentResolver.class})
onResume_linkedUser_shouldAddOneAccountCategory()110     public void onResume_linkedUser_shouldAddOneAccountCategory() {
111         final UserInfo info = new UserInfo(1, "user 1", 0);
112         when(mUserManager.isManagedProfile()).thenReturn(false);
113         when(mUserManager.isLinkedUser()).thenReturn(true);
114         when(mUserManager.getUserInfo(anyInt())).thenReturn(info);
115 
116         mController.onResume();
117 
118         verify(mScreen, times(1)).addPreference(any(PreferenceGroup.class));
119     }
120 
121     @Test
122     @Config(shadows = {ShadowAccountManager.class, ShadowContentResolver.class})
onResume_oneProfile_shouldAddOneAccountCategory()123     public void onResume_oneProfile_shouldAddOneAccountCategory() {
124         final List<UserInfo> infos = new ArrayList<>();
125         infos.add(new UserInfo(1, "user 1", 0));
126         when(mUserManager.isManagedProfile()).thenReturn(false);
127         when(mUserManager.isLinkedUser()).thenReturn(false);
128         when(mUserManager.getProfiles(anyInt())).thenReturn(infos);
129 
130         mController.onResume();
131 
132         verify(mScreen, times(1)).addPreference(any(PreferenceGroup.class));
133     }
134 
135     @Test
136     @Config(shadows = {ShadowAccountManager.class, ShadowContentResolver.class})
onResume_twoProfiles_shouldAddTwoAccountCategory()137     public void onResume_twoProfiles_shouldAddTwoAccountCategory() {
138         final List<UserInfo> infos = new ArrayList<>();
139         infos.add(new UserInfo(1, "user 1", 0));
140         infos.add(new UserInfo(2, "user 2", UserInfo.FLAG_MANAGED_PROFILE));
141         when(mUserManager.isManagedProfile()).thenReturn(false);
142         when(mUserManager.isLinkedUser()).thenReturn(false);
143         when(mUserManager.getProfiles(anyInt())).thenReturn(infos);
144 
145         mController.onResume();
146 
147         verify(mScreen, times(2)).addPreference(any(PreferenceGroup.class));
148     }
149 
150     @Test
151     @Config(shadows = {ShadowAccountManager.class, ShadowContentResolver.class})
onResume_noProfileChange_shouldNotAddOrRemoveAccountCategory()152     public void onResume_noProfileChange_shouldNotAddOrRemoveAccountCategory() {
153         final List<UserInfo> infos = new ArrayList<>();
154         infos.add(new UserInfo(1, "user 1", 0));
155         infos.add(new UserInfo(2, "user 2", UserInfo.FLAG_MANAGED_PROFILE));
156         when(mUserManager.isManagedProfile()).thenReturn(false);
157         when(mUserManager.isLinkedUser()).thenReturn(false);
158         when(mUserManager.getProfiles(anyInt())).thenReturn(infos);
159         // First time resume will build the UI
160         mController.onResume();
161         reset(mScreen);
162 
163         mController.onResume();
164         verify(mScreen, never()).addPreference(any(PreferenceGroup.class));
165         verify(mScreen, never()).removePreference(any(PreferenceGroup.class));
166     }
167 
168     @Test
169     @Config(shadows = {ShadowAccountManager.class, ShadowContentResolver.class})
onResume_oneNewProfile_shouldAddOneAccountCategory()170     public void onResume_oneNewProfile_shouldAddOneAccountCategory() {
171         final List<UserInfo> infos = new ArrayList<>();
172         infos.add(new UserInfo(1, "user 1", 0));
173         when(mUserManager.isManagedProfile()).thenReturn(false);
174         when(mUserManager.isLinkedUser()).thenReturn(false);
175         when(mUserManager.getProfiles(anyInt())).thenReturn(infos);
176         // First time resume will build the UI
177         mController.onResume();
178         // add a new profile
179         infos.add(new UserInfo(2, "user 2", UserInfo.FLAG_MANAGED_PROFILE));
180         reset(mScreen);
181 
182         mController.onResume();
183         verify(mScreen, times(1)).addPreference(any(PreferenceGroup.class));
184     }
185 
186     @Test
187     @Config(shadows = {ShadowAccountManager.class, ShadowContentResolver.class})
onResume_oneProfileRemoved_shouldRemoveOneAccountCategory()188     public void onResume_oneProfileRemoved_shouldRemoveOneAccountCategory() {
189         final List<UserInfo> infos = new ArrayList<>();
190         infos.add(new UserInfo(1, "user 1", 0));
191         infos.add(new UserInfo(2, "user 2", UserInfo.FLAG_MANAGED_PROFILE));
192         when(mUserManager.isManagedProfile()).thenReturn(false);
193         when(mUserManager.isLinkedUser()).thenReturn(false);
194         when(mUserManager.getProfiles(anyInt())).thenReturn(infos);
195         // First time resume will build the UI
196         mController.onResume();
197         // remove a profile
198         infos.remove(1);
199 
200         mController.onResume();
201         verify(mScreen, times(1)).removePreference(any(PreferenceGroup.class));
202     }
203 
204     @Test
205     @Config(shadows = {ShadowAccountManager.class, ShadowContentResolver.class})
onResume_oneProfile_shouldSetAccountTitleWithUserName()206     public void onResume_oneProfile_shouldSetAccountTitleWithUserName() {
207         final List<UserInfo> infos = new ArrayList<>();
208         infos.add(new UserInfo(1, "user 1", UserInfo.FLAG_MANAGED_PROFILE));
209         when(mUserManager.isManagedProfile()).thenReturn(false);
210         when(mUserManager.isLinkedUser()).thenReturn(false);
211         when(mUserManager.getProfiles(anyInt())).thenReturn(infos);
212         AccessiblePreferenceCategory preferenceGroup = mock(AccessiblePreferenceCategory.class);
213         when(mAccountHelper.createAccessiblePreferenceCategory(any(Context.class))).thenReturn(
214             preferenceGroup);
215 
216         mController.onResume();
217 
218         verify(preferenceGroup).setTitle(
219             mContext.getString(R.string.account_for_section_header, "user 1"));
220 
221     }
222 
223     @Test
224     @Config(shadows = {ShadowAccountManager.class, ShadowContentResolver.class})
onResume_noPreferenceScreen_shouldNotCrash()225     public void onResume_noPreferenceScreen_shouldNotCrash() {
226         final List<UserInfo> infos = new ArrayList<>();
227         infos.add(new UserInfo(1, "user 1", 0));
228         when(mUserManager.isManagedProfile()).thenReturn(false);
229         when(mUserManager.isLinkedUser()).thenReturn(false);
230         when(mUserManager.getProfiles(anyInt())).thenReturn(infos);
231 
232         AccessiblePreferenceCategory preferenceGroup = mock(AccessiblePreferenceCategory.class);
233         when(mAccountHelper.createAccessiblePreferenceCategory(any(Context.class))).thenReturn(
234                 preferenceGroup);
235 
236         mController.onResume();
237 
238         // Should not crash
239     }
240 
241     @Test
242     @Config(shadows = {ShadowAccountManager.class, ShadowContentResolver.class})
onResume_noPreferenceManager_shouldNotCrash()243     public void onResume_noPreferenceManager_shouldNotCrash() {
244         when(mFragment.getPreferenceManager()).thenReturn(null);
245         final List<UserInfo> infos = new ArrayList<>();
246         infos.add(new UserInfo(1, "user 1", 0));
247         when(mUserManager.isManagedProfile()).thenReturn(false);
248         when(mUserManager.isLinkedUser()).thenReturn(false);
249         when(mUserManager.getProfiles(anyInt())).thenReturn(infos);
250         mController.onResume();
251 
252         // Should not crash
253     }
254 
255     @Test
updateRawDataToIndex_ManagedProfile_shouldNotUpdate()256     public void updateRawDataToIndex_ManagedProfile_shouldNotUpdate() {
257         final List<SearchIndexableRaw> data = new ArrayList<>();
258         when(mUserManager.isManagedProfile()).thenReturn(true);
259 
260         mController.updateRawDataToIndex(data);
261 
262         assertThat(data).isEmpty();
263     }
264 
265     @Test
updateRawDataToIndex_DisabledUser_shouldNotUpdate()266     public void updateRawDataToIndex_DisabledUser_shouldNotUpdate() {
267         final List<SearchIndexableRaw> data = new ArrayList<>();
268         final List<UserInfo> infos = new ArrayList<>();
269         infos.add(new UserInfo(1, "user 1", UserInfo.FLAG_DISABLED));
270         when(mUserManager.isManagedProfile()).thenReturn(false);
271         when(mUserManager.getProfiles(anyInt())).thenReturn(infos);
272         mController.updateRawDataToIndex(data);
273 
274         assertThat(data).isEmpty();
275     }
276 
277     @Test
updateRawDataToIndex_EnabledUser_shouldAddOne()278     public void updateRawDataToIndex_EnabledUser_shouldAddOne() {
279         final List<SearchIndexableRaw> data = new ArrayList<>();
280         final List<UserInfo> infos = new ArrayList<>();
281         infos.add(new UserInfo(1, "user 1", 0));
282         when(mUserManager.isManagedProfile()).thenReturn(false);
283         when(mUserManager.getProfiles(anyInt())).thenReturn(infos);
284 
285         mController.updateRawDataToIndex(data);
286 
287         assertThat(data.size()).isEqualTo(1);
288     }
289 
290     @Test
updateRawDataToIndex_ManagedUser_shouldAddThree()291     public void updateRawDataToIndex_ManagedUser_shouldAddThree() {
292         final List<SearchIndexableRaw> data = new ArrayList<>();
293         final List<UserInfo> infos = new ArrayList<>();
294         infos.add(new UserInfo(1, "user 1", UserInfo.FLAG_MANAGED_PROFILE));
295         when(mUserManager.isManagedProfile()).thenReturn(false);
296         when(mUserManager.getProfiles(anyInt())).thenReturn(infos);
297 
298         mController.updateRawDataToIndex(data);
299 
300         assertThat(data.size()).isEqualTo(3);
301     }
302 
303     @Test
updateRawDataToIndex_DisallowRemove_shouldAddTwo()304     public void updateRawDataToIndex_DisallowRemove_shouldAddTwo() {
305         final List<SearchIndexableRaw> data = new ArrayList<>();
306         final List<UserInfo> infos = new ArrayList<>();
307         infos.add(new UserInfo(1, "user 1", UserInfo.FLAG_MANAGED_PROFILE));
308         when(mUserManager.isManagedProfile()).thenReturn(false);
309         when(mUserManager.getProfiles(anyInt())).thenReturn(infos);
310         when(mAccountHelper.hasBaseUserRestriction(
311                 eq(UserManager.DISALLOW_REMOVE_MANAGED_PROFILE), anyInt()))
312             .thenReturn(true);
313 
314         mController.updateRawDataToIndex(data);
315 
316         assertThat(data.size()).isEqualTo(2);
317     }
318 
319     @Test
updateRawDataToIndex_DisallowModify_shouldAddTwo()320     public void updateRawDataToIndex_DisallowModify_shouldAddTwo() {
321         final List<SearchIndexableRaw> data = new ArrayList<>();
322         final List<UserInfo> infos = new ArrayList<>();
323         infos.add(new UserInfo(1, "user 1", UserInfo.FLAG_MANAGED_PROFILE));
324         when(mUserManager.isManagedProfile()).thenReturn(false);
325         when(mUserManager.getProfiles(anyInt())).thenReturn(infos);
326         when(mAccountHelper.hasBaseUserRestriction(
327             eq(UserManager.DISALLOW_MODIFY_ACCOUNTS), anyInt())).thenReturn(true);
328 
329         mController.updateRawDataToIndex(data);
330 
331         assertThat(data.size()).isEqualTo(2);
332     }
333 
334     @Test
335     @Config(shadows = {ShadowAccountManager.class, ShadowContentResolver.class})
onResume_twoAccountsOfSameType_shouldAddThreePreferences()336     public void onResume_twoAccountsOfSameType_shouldAddThreePreferences() {
337         final List<UserInfo> infos = new ArrayList<>();
338         infos.add(new UserInfo(1, "user 1", 0));
339         when(mUserManager.isManagedProfile()).thenReturn(false);
340         when(mUserManager.isLinkedUser()).thenReturn(false);
341         when(mUserManager.getProfiles(anyInt())).thenReturn(infos);
342         Account[] accounts = {new Account("Account1", "com.acct1")};
343         when(mAccountManager.getAccountsAsUser(anyInt())).thenReturn(accounts);
344 
345         Account[] accountType1 = new Account[2];
346         accountType1[0] = new Account("Account11", "com.acct1");
347         accountType1[1] = new Account("Account12", "com.acct1");
348         when(mAccountManager.getAccountsByTypeAsUser(eq("com.acct1"), any(UserHandle.class)))
349             .thenReturn(accountType1);
350 
351         AuthenticatorDescription[] authDescs = {
352             new AuthenticatorDescription("com.acct1", "com.android.settings",
353                 R.string.account_settings_title, 0, 0, 0, false)
354         };
355         when(mAccountManager.getAuthenticatorTypesAsUser(anyInt())).thenReturn(authDescs);
356 
357         AccessiblePreferenceCategory preferenceGroup = mock(AccessiblePreferenceCategory.class);
358         when(preferenceGroup.getPreferenceManager()).thenReturn(mock(PreferenceManager.class));
359         when(mAccountHelper.createAccessiblePreferenceCategory(any(Context.class))).thenReturn(
360             preferenceGroup);
361 
362         mController.onResume();
363 
364         // should add 2 individual account and the Add account preference
365         verify(preferenceGroup, times(3)).addPreference(any(Preference.class));
366     }
367 
368     @Test
369     @Config(shadows = {ShadowAccountManager.class, ShadowContentResolver.class})
onResume_twoAccountsOfSameName_shouldAddFivePreferences()370     public void onResume_twoAccountsOfSameName_shouldAddFivePreferences() {
371         final List<UserInfo> infos = new ArrayList<>();
372         infos.add(new UserInfo(1, "user 1", 0));
373         when(mUserManager.isManagedProfile()).thenReturn(false);
374         when(mUserManager.isLinkedUser()).thenReturn(false);
375         when(mUserManager.getProfiles(anyInt())).thenReturn(infos);
376 
377         final Account[] accountType1 = new Account[2];
378         accountType1[0] = new Account("Account1", "com.acct1");
379         accountType1[1] = new Account("Account2", "com.acct1");
380         final Account[] accountType2 = new Account[2];
381         accountType2[0] = new Account("Account1", "com.acct2");
382         accountType2[1] = new Account("Account2", "com.acct2");
383         final Account[] allAccounts = new Account[4];
384         allAccounts[0] = accountType1[0];
385         allAccounts[1] = accountType1[1];
386         allAccounts[2] = accountType2[0];
387         allAccounts[3] = accountType2[1];
388         final AuthenticatorDescription[] authDescs = {
389                 new AuthenticatorDescription("com.acct1", "com.android.settings",
390                         R.string.account_settings_title, 0, 0, 0, false),
391                 new AuthenticatorDescription("com.acct2", "com.android.settings",
392                         R.string.account_settings_title, 0, 0, 0, false)
393         };
394 
395         when(mAccountManager.getAccountsAsUser(anyInt())).thenReturn(allAccounts);
396         when(mAccountManager.getAccountsByTypeAsUser(eq("com.acct1"), any(UserHandle.class)))
397                 .thenReturn(accountType1);
398         when(mAccountManager.getAccountsByTypeAsUser(eq("com.acct2"), any(UserHandle.class)))
399                 .thenReturn(accountType2);
400         when(mAccountManager.getAuthenticatorTypesAsUser(anyInt())).thenReturn(authDescs);
401 
402         AccessiblePreferenceCategory preferenceGroup = mock(AccessiblePreferenceCategory.class);
403         when(preferenceGroup.getPreferenceManager()).thenReturn(mock(PreferenceManager.class));
404         when(mAccountHelper.createAccessiblePreferenceCategory(any(Context.class))).thenReturn(
405                 preferenceGroup);
406 
407         mController.onResume();
408 
409         // should add 4 individual account and the Add account preference
410         verify(preferenceGroup, times(5)).addPreference(any(Preference.class));
411     }
412 
413     @Test
414     @Config(shadows = {ShadowAccountManager.class, ShadowContentResolver.class})
onResume_noAccountChange_shouldNotAddAccountPreference()415     public void onResume_noAccountChange_shouldNotAddAccountPreference() {
416         final List<UserInfo> infos = new ArrayList<>();
417         infos.add(new UserInfo(1, "user 1", 0));
418         when(mUserManager.isManagedProfile()).thenReturn(false);
419         when(mUserManager.isLinkedUser()).thenReturn(false);
420         when(mUserManager.getProfiles(anyInt())).thenReturn(infos);
421         Account[] accounts = {new Account("Acct1", "com.acct1")};
422         when(mAccountManager.getAccountsAsUser(anyInt())).thenReturn(accounts);
423 
424         Account[] accountType1 = new Account[2];
425         accountType1[0] = new Account("Acct11", "com.acct1");
426         accountType1[1] = new Account("Acct12", "com.acct1");
427         when(mAccountManager.getAccountsByTypeAsUser(eq("com.acct1"), any(UserHandle.class)))
428             .thenReturn(accountType1);
429 
430         AuthenticatorDescription[] authDescs = {
431             new AuthenticatorDescription("com.acct1", "com.android.settings",
432                 R.string.account_settings_title, 0, 0, 0, false)
433         };
434         when(mAccountManager.getAuthenticatorTypesAsUser(anyInt())).thenReturn(authDescs);
435 
436         AccessiblePreferenceCategory preferenceGroup = mock(AccessiblePreferenceCategory.class);
437         when(preferenceGroup.getPreferenceManager()).thenReturn(mock(PreferenceManager.class));
438         when(mAccountHelper.createAccessiblePreferenceCategory(any(Context.class))).thenReturn(
439             preferenceGroup);
440         mController.onResume();
441 
442         mController.onResume();
443 
444         // each account should be added only once
445         verify(preferenceGroup).addPreference(argThat(new PreferenceMatcher("Acct11")));
446         verify(preferenceGroup).addPreference(argThat(new PreferenceMatcher("Acct12")));
447     }
448 
449     @Test
onResume_oneNewAccount_shouldAddOneAccountPreference()450     public void onResume_oneNewAccount_shouldAddOneAccountPreference() {
451         final List<UserInfo> infos = new ArrayList<>();
452         infos.add(new UserInfo(1, "user 1", 0));
453         when(mUserManager.isManagedProfile()).thenReturn(false);
454         when(mUserManager.isLinkedUser()).thenReturn(false);
455         when(mUserManager.getProfiles(anyInt())).thenReturn(infos);
456         Account[] accounts = {new Account("Acct1", "com.acct1")};
457         when(mAccountManager.getAccountsAsUser(anyInt())).thenReturn(accounts);
458 
459         Account[] accountType1 = new Account[2];
460         accountType1[0] = new Account("Acct11", "com.acct1");
461         accountType1[1] = new Account("Acct12", "com.acct1");
462         when(mAccountManager.getAccountsByTypeAsUser(eq("com.acct1"), any(UserHandle.class)))
463             .thenReturn(accountType1);
464 
465         AuthenticatorDescription[] authDescs = {
466             new AuthenticatorDescription("com.acct1", "com.android.settings",
467                 R.string.account_settings_title, 0, 0, 0, false)
468         };
469         when(mAccountManager.getAuthenticatorTypesAsUser(anyInt())).thenReturn(authDescs);
470 
471         AccessiblePreferenceCategory preferenceGroup = mock(AccessiblePreferenceCategory.class);
472         when(preferenceGroup.getPreferenceManager()).thenReturn(mock(PreferenceManager.class));
473         when(mAccountHelper.createAccessiblePreferenceCategory(any(Context.class))).thenReturn(
474             preferenceGroup);
475 
476         mController.onResume();
477 
478         // add a new account
479         accountType1 = new Account[3];
480         accountType1[0] = new Account("Acct11", "com.acct1");
481         accountType1[1] = new Account("Acct12", "com.acct1");
482         accountType1[2] = new Account("Acct13", "com.acct1");
483         when(mAccountManager.getAccountsByTypeAsUser(eq("com.acct1"), any(UserHandle.class)))
484             .thenReturn(accountType1);
485 
486         mController.onResume();
487 
488         // each account should be added only once
489         verify(preferenceGroup, times(1)).addPreference(argThat(new PreferenceMatcher("Acct11")));
490         verify(preferenceGroup, times(1)).addPreference(argThat(new PreferenceMatcher("Acct12")));
491         verify(preferenceGroup, times(1)).addPreference(argThat(new PreferenceMatcher("Acct13")));
492     }
493 
494     @Test
495     @Config(shadows = {ShadowAccountManager.class, ShadowContentResolver.class})
onResume_oneNewAccountType_shouldAddOneAccountPreference()496     public void onResume_oneNewAccountType_shouldAddOneAccountPreference() {
497         final List<UserInfo> infos = new ArrayList<>();
498         infos.add(new UserInfo(1, "user 1", 0));
499         infos.add(new UserInfo(2, "user 2", UserInfo.FLAG_MANAGED_PROFILE));
500         when(mUserManager.isManagedProfile()).thenReturn(false);
501         when(mUserManager.isLinkedUser()).thenReturn(false);
502         when(mUserManager.getProfiles(anyInt())).thenReturn(infos);
503 
504         AccessiblePreferenceCategory preferenceGroup = mock(AccessiblePreferenceCategory.class);
505         when(preferenceGroup.getPreferenceManager()).thenReturn(mock(PreferenceManager.class));
506         when(mAccountHelper.createAccessiblePreferenceCategory(any(Context.class))).thenReturn(
507             preferenceGroup);
508 
509         // First time resume will build the UI with no account
510         mController.onResume();
511 
512         // Add new account
513         Account[] accounts = {new Account("Acct1", "com.acct1")};
514         when(mAccountManager.getAccountsAsUser(2)).thenReturn(accounts);
515         when(mAccountManager.getAccountsByTypeAsUser(eq("com.acct1"), any(UserHandle.class)))
516             .thenReturn(accounts);
517 
518         AuthenticatorDescription[] authDescs = {
519             new AuthenticatorDescription("com.acct1", "com.android.settings",
520                 R.string.account_settings_title, 0, 0, 0, false)
521         };
522         when(mAccountManager.getAuthenticatorTypesAsUser(anyInt())).thenReturn(authDescs);
523 
524         // Resume should show the newly added account
525         mController.onResume();
526 
527         verify(preferenceGroup).addPreference(argThat(new PreferenceMatcher("Acct1")));
528     }
529 
530     @Test
531     @Config(shadows = {ShadowAccountManager.class, ShadowContentResolver.class})
onResume_oneAccountRemoved_shouldRemoveOneAccountPreference()532     public void onResume_oneAccountRemoved_shouldRemoveOneAccountPreference() {
533         final List<UserInfo> infos = new ArrayList<>();
534         infos.add(new UserInfo(1, "user 1", 0));
535         when(mUserManager.isManagedProfile()).thenReturn(false);
536         when(mUserManager.isLinkedUser()).thenReturn(false);
537         when(mUserManager.getProfiles(anyInt())).thenReturn(infos);
538         Account[] accounts = {new Account("Acct1", "com.acct1")};
539         when(mAccountManager.getAccountsAsUser(anyInt())).thenReturn(accounts);
540 
541         Account[] accountType1 = new Account[2];
542         accountType1[0] = new Account("Acct11", "com.acct1");
543         accountType1[1] = new Account("Acct12", "com.acct1");
544         when(mAccountManager.getAccountsByTypeAsUser(eq("com.acct1"), any(UserHandle.class)))
545             .thenReturn(accountType1);
546 
547         AuthenticatorDescription[] authDescs = {
548             new AuthenticatorDescription("com.acct1", "com.android.settings",
549                 R.string.account_settings_title, 0, 0, 0, false)
550         };
551         when(mAccountManager.getAuthenticatorTypesAsUser(anyInt())).thenReturn(authDescs);
552 
553         AccessiblePreferenceCategory preferenceGroup = mock(AccessiblePreferenceCategory.class);
554         when(preferenceGroup.getPreferenceManager()).thenReturn(mock(PreferenceManager.class));
555         when(mAccountHelper.createAccessiblePreferenceCategory(any(Context.class))).thenReturn(
556             preferenceGroup);
557 
558         mController.onResume();
559 
560         // remove an account
561         accountType1 = new Account[1];
562         accountType1[0] = new Account("Acct11", "com.acct1");
563         when(mAccountManager.getAccountsByTypeAsUser(eq("com.acct1"), any(UserHandle.class)))
564             .thenReturn(accountType1);
565 
566         mController.onResume();
567 
568         verify(preferenceGroup, times(1)).addPreference(argThat(new PreferenceMatcher("Acct11")));
569         verify(preferenceGroup, times(1)).addPreference(argThat(new PreferenceMatcher("Acct12")));
570         verify(preferenceGroup, times(1)).removePreference(
571             argThat(new PreferenceMatcher("Acct12")));
572     }
573 
574     private static class PreferenceMatcher extends ArgumentMatcher<Preference> {
575 
576         private final String mExpectedTitle;
577 
PreferenceMatcher(String title)578         public PreferenceMatcher(String title) {
579             mExpectedTitle = title;
580         }
581 
582         @Override
matches(Object arg)583         public boolean matches(Object arg) {
584             final Preference preference = (Preference) arg;
585             return TextUtils.equals(mExpectedTitle, preference.getTitle());
586         }
587     }
588 
589 }
590