1 /* 2 * Copyright (C) 2021 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 17 package com.android.car.settings.system; 18 19 import static com.google.common.truth.Truth.assertThat; 20 21 import static org.mockito.ArgumentMatchers.anyInt; 22 import static org.mockito.Mockito.when; 23 import static org.mockito.Mockito.withSettings; 24 25 import android.accounts.Account; 26 import android.accounts.AccountManager; 27 import android.accounts.AuthenticatorDescription; 28 import android.car.drivingstate.CarUxRestrictions; 29 import android.content.Context; 30 import android.content.pm.UserInfo; 31 import android.os.UserHandle; 32 import android.os.UserManager; 33 34 import androidx.lifecycle.LifecycleOwner; 35 import androidx.preference.PreferenceCategory; 36 import androidx.preference.PreferenceGroup; 37 import androidx.preference.PreferenceManager; 38 import androidx.preference.PreferenceScreen; 39 import androidx.test.annotation.UiThreadTest; 40 import androidx.test.core.app.ApplicationProvider; 41 import androidx.test.ext.junit.runners.AndroidJUnit4; 42 43 import com.android.car.settings.R; 44 import com.android.car.settings.common.FragmentController; 45 import com.android.car.settings.common.PreferenceControllerTestUtil; 46 import com.android.car.settings.testutils.TestLifecycleOwner; 47 import com.android.dx.mockito.inline.extended.ExtendedMockito; 48 49 import org.junit.After; 50 import org.junit.Before; 51 import org.junit.Test; 52 import org.junit.runner.RunWith; 53 import org.mockito.Mock; 54 import org.mockito.MockitoAnnotations; 55 import org.mockito.MockitoSession; 56 import org.mockito.stubbing.Answer; 57 58 import java.util.ArrayList; 59 import java.util.HashMap; 60 import java.util.List; 61 import java.util.Map; 62 63 /** Unit test for {@link FactoryResetAccountsPreferenceController}. */ 64 @RunWith(AndroidJUnit4.class) 65 public class FactoryResetAccountsPreferenceControllerTest { 66 private final int mUserId = UserHandle.myUserId(); 67 68 private Context mContext = ApplicationProvider.getApplicationContext(); 69 private LifecycleOwner mLifecycleOwner; 70 private PreferenceGroup mPreference; 71 private FactoryResetAccountsPreferenceController mPreferenceController; 72 private CarUxRestrictions mCarUxRestrictions; 73 private MockitoSession mSession; 74 75 private Map<Integer, List<AuthenticatorDescription>> mAuthenticatorDescriptionMap; 76 private Map<Integer, List<Account>> mAccountMap; 77 78 @Mock 79 private FragmentController mFragmentController; 80 @Mock 81 private AccountManager mMockAccountManager; 82 @Mock 83 private UserManager mMockUserManager; 84 85 @Before 86 @UiThreadTest setUp()87 public void setUp() { 88 MockitoAnnotations.initMocks(this); 89 mLifecycleOwner = new TestLifecycleOwner(); 90 mCarUxRestrictions = new CarUxRestrictions.Builder(/* reqOpt= */ true, 91 CarUxRestrictions.UX_RESTRICTIONS_BASELINE, /* timestamp= */ 0).build(); 92 93 mAuthenticatorDescriptionMap = new HashMap<>(); 94 mAccountMap = new HashMap<>(); 95 mAuthenticatorDescriptionMap.put(mUserId, new ArrayList<>()); 96 mAccountMap.put(mUserId, new ArrayList<>()); 97 mSession = ExtendedMockito.mockitoSession() 98 .mockStatic(AccountManager.class, withSettings().lenient()) 99 .mockStatic(UserManager.class, withSettings().lenient()) 100 .startMocking(); 101 when(AccountManager.get(mContext)).thenReturn(mMockAccountManager); 102 updateAccountManagerMocks(); 103 when(UserManager.get(mContext)).thenCallRealMethod(); 104 105 PreferenceManager preferenceManager = new PreferenceManager(mContext); 106 PreferenceScreen screen = preferenceManager.createPreferenceScreen(mContext); 107 mPreference = new PreferenceCategory(mContext); 108 screen.addPreference(mPreference); 109 mPreferenceController = new FactoryResetAccountsPreferenceController(mContext, 110 "key", mFragmentController, mCarUxRestrictions); 111 PreferenceControllerTestUtil.assignPreference(mPreferenceController, mPreference); 112 } 113 114 @After 115 @UiThreadTest tearDown()116 public void tearDown() { 117 if (mSession != null) { 118 mSession.finishMocking(); 119 } 120 } 121 122 @Test onCreate_addsTitlePreference()123 public void onCreate_addsTitlePreference() { 124 mPreferenceController.onCreate(mLifecycleOwner); 125 126 assertThat(mPreference.getPreferenceCount()).isEqualTo(1); 127 assertThat(mPreference.getPreference(0).getTitle()).isEqualTo( 128 mContext.getString(R.string.factory_reset_accounts)); 129 } 130 131 @Test refreshUi_accountsPresent_showsGroup()132 public void refreshUi_accountsPresent_showsGroup() { 133 mPreferenceController.onCreate(mLifecycleOwner); 134 mPreferenceController.onStart(mLifecycleOwner); 135 addAccountAndDescription(mUserId, "accountName"); 136 137 mPreferenceController.refreshUi(); 138 139 assertThat(mPreference.isVisible()).isTrue(); 140 } 141 142 @Test refreshUi_noAccountsPresent_hidesGroup()143 public void refreshUi_noAccountsPresent_hidesGroup() { 144 mPreferenceController.onCreate(mLifecycleOwner); 145 mPreferenceController.onStart(mLifecycleOwner); 146 147 mPreferenceController.refreshUi(); 148 149 assertThat(mPreference.isVisible()).isFalse(); 150 } 151 152 @Test refreshUi_multipleProfiles_showsAllAccounts()153 public void refreshUi_multipleProfiles_showsAllAccounts() { 154 int profileId1 = 112; 155 int profileId2 = 113; 156 List<UserInfo> profiles = new ArrayList<>(); 157 profiles.add(new UserInfo(profileId1, String.valueOf(profileId1), 0)); 158 profiles.add(new UserInfo(profileId2, String.valueOf(profileId2), 0)); 159 String accountName1 = "accountName1"; 160 addAccountAndDescription(profileId1, accountName1); 161 String accountName2 = "accountName2"; 162 addAccountAndDescription(profileId2, accountName2); 163 164 when(UserManager.get(mContext)).thenReturn(mMockUserManager); 165 when(mMockUserManager.getProfiles(mUserId)).thenReturn(profiles); 166 167 mPreferenceController.onCreate(mLifecycleOwner); 168 mPreferenceController.onStart(mLifecycleOwner); 169 170 mPreferenceController.refreshUi(); 171 172 // Title + two profiles with one account each. 173 assertThat(mPreference.getPreferenceCount()).isEqualTo(3); 174 assertThat(mPreference.getPreference(1).getTitle()).isEqualTo(accountName1); 175 assertThat(mPreference.getPreference(2).getTitle()).isEqualTo(accountName2); 176 } 177 178 @Test refreshUi_missingAccountDescription_skipsAccount()179 public void refreshUi_missingAccountDescription_skipsAccount() { 180 mPreferenceController.onCreate(mLifecycleOwner); 181 mPreferenceController.onStart(mLifecycleOwner); 182 addAccountAndDescription(mUserId, "account name with desc"); 183 String accountNameNoDesc = "account name no desc"; 184 addAccount(mUserId, accountNameNoDesc); 185 186 mPreferenceController.refreshUi(); 187 188 // Title + one account with valid description. 189 assertThat(mPreference.getPreferenceCount()).isEqualTo(2); 190 assertThat(mPreference.getPreference(1).getTitle()).isNotEqualTo(accountNameNoDesc); 191 } 192 193 @Test refreshUi_accountAdded_addsPreferenceToGroup()194 public void refreshUi_accountAdded_addsPreferenceToGroup() { 195 addAccountAndDescription(mUserId, "accountName"); 196 mPreferenceController.onCreate(mLifecycleOwner); 197 mPreferenceController.onStart(mLifecycleOwner); 198 assertThat(mPreference.getPreferenceCount()).isEqualTo(2); 199 200 String addedAccountName = "added account name"; 201 addAccountAndDescription(mUserId, addedAccountName); 202 mPreferenceController.refreshUi(); 203 204 // Title + one already present account + one newly added account. 205 assertThat(mPreference.getPreferenceCount()).isEqualTo(3); 206 assertThat(mPreference.getPreference(2).getTitle()).isEqualTo(addedAccountName); 207 } 208 209 @Test refreshUi_accountRemoved_removesPreferenceFromGroup()210 public void refreshUi_accountRemoved_removesPreferenceFromGroup() { 211 String accountNameToRemove = "account name to remove"; 212 addAccountAndDescription(mUserId, accountNameToRemove); 213 mPreferenceController.onCreate(mLifecycleOwner); 214 mPreferenceController.onStart(mLifecycleOwner); 215 assertThat(mPreference.getPreferenceCount()).isEqualTo(2); 216 217 clearAllAccounts(); 218 mPreferenceController.refreshUi(); 219 220 // Title only, all accounts removed. 221 assertThat(mPreference.getPreferenceCount()).isEqualTo(1); 222 assertThat(mPreference.getPreference(0).getTitle()).isNotEqualTo(accountNameToRemove); 223 } 224 addAccountAndDescription(int profileId, String accountName)225 private void addAccountAndDescription(int profileId, String accountName) { 226 addDescription(profileId, accountName); 227 addAccount(profileId, accountName); 228 } 229 addAccount(int profileId, String accountName)230 private void addAccount(int profileId, String accountName) { 231 String type = accountName + "_type"; 232 if (!mAccountMap.containsKey(profileId)) { 233 mAccountMap.put(profileId, new ArrayList<>()); 234 } 235 mAccountMap.get(profileId).add(new Account(accountName, type)); 236 updateAccountManagerMocks(); 237 } 238 addDescription(int profileId, String accountName)239 private void addDescription(int profileId, String accountName) { 240 String type = accountName + "_type"; 241 if (!mAuthenticatorDescriptionMap.containsKey(profileId)) { 242 mAuthenticatorDescriptionMap.put(profileId, new ArrayList<>()); 243 } 244 mAuthenticatorDescriptionMap.get(profileId).add( 245 new AuthenticatorDescription(type, "packageName", 246 /* labelId= */ 0, /* iconId= */ 0, /* smallIconId= */ 0, /* prefId= */ 0)); 247 updateAccountManagerMocks(); 248 } 249 clearAllAccounts()250 private void clearAllAccounts() { 251 mAuthenticatorDescriptionMap.clear(); 252 mAccountMap.clear(); 253 updateAccountManagerMocks(); 254 } 255 updateAccountManagerMocks()256 private void updateAccountManagerMocks() { 257 when(mMockAccountManager.getAuthenticatorTypesAsUser(anyInt())).then( 258 (Answer<AuthenticatorDescription[]>) invocation -> { 259 Object[] args = invocation.getArguments(); 260 int profileId = (Integer) args[0]; 261 return mAuthenticatorDescriptionMap.containsKey(profileId) 262 ? mAuthenticatorDescriptionMap.get(profileId).toArray( 263 new AuthenticatorDescription[0]) 264 : new AuthenticatorDescription[0]; 265 }); 266 when(mMockAccountManager.getAccountsAsUser(anyInt())).then( 267 (Answer<Account[]>) invocation -> { 268 Object[] args = invocation.getArguments(); 269 int profileId = (Integer) args[0]; 270 return mAccountMap.containsKey(profileId) 271 ? mAccountMap.get(profileId).toArray(new Account[0]) 272 : new Account[0]; 273 }); 274 } 275 } 276