1 /*
2  * Copyright (C) 2023 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.systemui.car.userpicker;
17 
18 import static android.car.CarOccupantZoneManager.INVALID_USER_ID;
19 import static android.view.Display.INVALID_DISPLAY;
20 
21 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
22 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
23 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
24 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
25 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
26 
27 import static org.mockito.ArgumentMatchers.any;
28 import static org.mockito.ArgumentMatchers.anyBoolean;
29 import static org.mockito.ArgumentMatchers.anyInt;
30 import static org.mockito.ArgumentMatchers.anyString;
31 import static org.mockito.ArgumentMatchers.eq;
32 import static org.mockito.Mockito.after;
33 
34 import android.app.ActivityManager;
35 import android.car.test.mocks.AndroidMockitoHelper;
36 import android.car.user.UserCreationResult;
37 import android.content.pm.UserInfo;
38 import android.testing.AndroidTestingRunner;
39 import android.testing.TestableLooper;
40 import android.view.View;
41 
42 import androidx.test.filters.SmallTest;
43 
44 import com.android.systemui.R;
45 import com.android.systemui.car.CarSystemUiTest;
46 import com.android.systemui.car.userpicker.UserPickerController.Callbacks;
47 import com.android.systemui.settings.DisplayTracker;
48 
49 import com.google.android.material.snackbar.Snackbar;
50 
51 import org.junit.After;
52 import org.junit.Before;
53 import org.junit.Test;
54 import org.junit.runner.RunWith;
55 import org.mockito.Mock;
56 import org.mockito.MockitoSession;
57 import org.mockito.quality.Strictness;
58 
59 import java.util.ArrayList;
60 import java.util.List;
61 
62 @CarSystemUiTest
63 @RunWith(AndroidTestingRunner.class)
64 @TestableLooper.RunWithLooper
65 @SmallTest
66 public class UserPickerControllerTest extends UserPickerTestCase {
67     private UserPickerController mUserPickerController;
68     private SnackbarManager mSnackbarManager;
69     private UserPickerSharedState mUserPickerSharedState;
70 
71     @Mock
72     private DialogManager mMockDialogManager;
73     @Mock
74     private CarServiceMediator mMockCarServiceMediator;
75     @Mock
76     private UserEventManager mMockUserEventManager;
77     @Mock
78     private DisplayTracker mMockDisplayTracker;
79     @Mock
80     private Callbacks mMockCallbacks;
81     @Mock
82     private UserCreationResult mCreateResult;
83 
84     private List<UserInfo> mAliveUsers = new ArrayList<UserInfo>();
85     private List<UserRecord> mUserRecords = null;
86     private MockitoSession mMockingSession;
87 
88     @Before
setUp()89     public void setUp() {
90         mMockingSession = mockitoSession()
91                 .initMocks(this)
92                 .spyStatic(ActivityManager.class)
93                 .spyStatic(Snackbar.class)
94                 .strictness(Strictness.WARN)
95                 .startMocking();
96 
97         mAliveUsers.clear();
98         doReturn(mAliveUsers).when(mMockUserEventManager).getAliveUsers();
99         doReturn(mDriverUserInfo).when(mMockUserEventManager).getCurrentForegroundUserInfo();
100     }
101 
102     @After
tearDown()103     public void tearDown() {
104         if (mMockingSession != null) {
105             mMockingSession.finishMocking();
106         }
107     }
108 
displaySetup(boolean isLogoutState, int displayId)109     void displaySetup(boolean isLogoutState, int displayId) {
110         mAliveUsers.add(mDriverUserInfo);
111         doReturn(true).when(mMockUserEventManager).isUserRunning(USER_ID_DRIVER);
112         doReturn(MAIN_DISPLAY_ID).when(mMockCarServiceMediator).getDisplayIdForUser(USER_ID_DRIVER);
113         doReturn(USER_ID_DRIVER).when(mMockCarServiceMediator).getUserForDisplay(MAIN_DISPLAY_ID);
114 
115         mAliveUsers.add(mFrontUserInfo);
116         if (isLogoutState) {
117             doReturn(INVALID_DISPLAY).when(mMockCarServiceMediator)
118                     .getDisplayIdForUser(USER_ID_FRONT);
119             doReturn(INVALID_USER_ID).when(mMockCarServiceMediator)
120                     .getUserForDisplay(FRONT_PASSENGER_DISPLAY_ID);
121         } else {
122             doReturn(true).when(mMockUserEventManager).isUserRunning(USER_ID_FRONT);
123             doReturn(FRONT_PASSENGER_DISPLAY_ID).when(mMockCarServiceMediator)
124                     .getDisplayIdForUser(USER_ID_FRONT);
125             doReturn(USER_ID_FRONT).when(mMockCarServiceMediator)
126                     .getUserForDisplay(FRONT_PASSENGER_DISPLAY_ID);
127         }
128 
129         mAliveUsers.add(mRearUserInfo);
130         doReturn(INVALID_DISPLAY).when(mMockCarServiceMediator).getDisplayIdForUser(USER_ID_REAR);
131         doReturn(INVALID_USER_ID).when(mMockCarServiceMediator)
132                 .getUserForDisplay(REAR_PASSENGER_DISPLAY_ID);
133 
134         doReturn(displayId).when(mContext).getDisplayId();
135         doReturn(MAIN_DISPLAY_ID).when(mMockDisplayTracker).getDefaultDisplayId();
136 
137         mSnackbarManager = new SnackbarManager();
138         mUserPickerSharedState = new UserPickerSharedState();
139         View rootView = mInflater.inflate(R.layout.test_empty_layout, null);
140         mSnackbarManager.setRootView(rootView, R.id.test_empty_layout_frame);
141 
142         mUserPickerController = new UserPickerController(mContext, mMockUserEventManager,
143                 mMockCarServiceMediator, mMockDialogManager, mSnackbarManager,
144                 mMockDisplayTracker, mUserPickerSharedState);
145         mUserPickerController.init(mMockCallbacks, displayId);
146         mUserPickerController.onConfigurationChanged();
147         AndroidMockitoHelper.mockAmGetCurrentUser(USER_ID_DRIVER);
148         mUserPickerController.updateUsers();
149         mUserRecords = mUserPickerController.createUserRecords();
150     }
151 
getUserRecord(String name)152     UserRecord getUserRecord(String name) {
153         if (name != null) {
154             for (int i = 0; i < mUserRecords.size(); i++) {
155                 if (name.equals(mUserRecords.get(i).mName)) {
156                     return mUserRecords.get(i);
157                 }
158             }
159         }
160         return null;
161     }
162 
163     @Test
loginItself_changeUserState_finishUserPicker()164     public void loginItself_changeUserState_finishUserPicker() {
165         displaySetup(/* isLogoutState= */ false, /* displayId= */ FRONT_PASSENGER_DISPLAY_ID);
166 
167         mUserPickerController.handleUserSelected(getUserRecord(USER_NAME_FRONT));
168 
169         verify(mMockUserEventManager, after(IDLE_TIMEOUT).never())
170                 .startUserForDisplay(anyInt(), anyInt(), anyInt(), anyBoolean());
171         verify(mMockCallbacks, after(IDLE_TIMEOUT)).onFinishRequested();
172     }
173 
174     @Test
checkSnackbar_loginDriverUser_showSnackbar()175     public void checkSnackbar_loginDriverUser_showSnackbar() {
176         Snackbar snackbar = mock(Snackbar.class);
177         doReturn(snackbar).when(() -> Snackbar.make(any(View.class), any(String.class), anyInt()));
178         displaySetup(/* isLogoutState= */ false, /* displayId= */ FRONT_PASSENGER_DISPLAY_ID);
179         spyOn(mSnackbarManager);
180 
181         mUserPickerController.handleUserSelected(getUserRecord(USER_NAME_DRIVER));
182 
183         verify(mMockUserEventManager, after(IDLE_TIMEOUT).never())
184                 .startUserForDisplay(anyInt(), anyInt(), anyInt(), anyBoolean());
185         verify(mSnackbarManager, after(IDLE_TIMEOUT)).showSnackbar(anyString());
186     }
187 
188     @Test
checkSwitchUser_changeUserState_switchUser()189     public void checkSwitchUser_changeUserState_switchUser() {
190         displaySetup(/* isLogoutState= */ false, /* displayId= */ MAIN_DISPLAY_ID);
191 
192         mUserPickerController.handleUserSelected((getUserRecord(USER_NAME_REAR)));
193 
194         verify(mMockUserEventManager, after(IDLE_TIMEOUT).never()).createNewUser();
195         verify(mMockUserEventManager, after(IDLE_TIMEOUT))
196                 .startUserForDisplay(anyInt(), eq(USER_ID_REAR), anyInt(), anyBoolean());
197     }
198 
199     @Test
checkChangeUser_changeUserState_changeUser()200     public void checkChangeUser_changeUserState_changeUser() {
201         doReturn(true).when(mMockUserEventManager).stopUserUnchecked(anyInt(), anyInt());
202         displaySetup(/* isLogoutState= */ false, /* displayId= */ FRONT_PASSENGER_DISPLAY_ID);
203 
204         mUserPickerController.handleUserSelected(getUserRecord(USER_NAME_REAR));
205 
206         verify(mMockUserEventManager, after(IDLE_TIMEOUT).atLeastOnce())
207                 .stopUserUnchecked(USER_ID_FRONT, FRONT_PASSENGER_DISPLAY_ID);
208         verify(mMockUserEventManager, after(IDLE_TIMEOUT))
209                 .startUserForDisplay(anyInt(), eq(USER_ID_REAR), anyInt(), anyBoolean());
210     }
211 
212     @Test
checkLoginUser_logoutState_startUser()213     public void checkLoginUser_logoutState_startUser() {
214         doReturn(true).when(mMockUserEventManager).stopUserUnchecked(anyInt(), anyInt());
215         displaySetup(/* isLogoutState= */ true, /* displayId= */ FRONT_PASSENGER_DISPLAY_ID);
216 
217         mUserPickerController.handleUserSelected(getUserRecord(USER_NAME_REAR));
218 
219         verify(mMockUserEventManager, after(IDLE_TIMEOUT).never())
220                 .stopUserUnchecked(anyInt(), anyInt());
221         verify(mMockUserEventManager, after(IDLE_TIMEOUT))
222                 .startUserForDisplay(anyInt(), eq(USER_ID_REAR), anyInt(), anyBoolean());
223     }
224 
225     @Test
checkCreateGuest_pressGuestIcon_createdGuestUser()226     public void checkCreateGuest_pressGuestIcon_createdGuestUser() {
227         UserInfo guestInfo = new UserInfo(USER_ID_GUEST, "G", UserInfo.FLAG_GUEST);
228         doReturn(true).when(mCreateResult).isSuccess();
229         doReturn(mCreateResult).when(mMockUserEventManager).createGuest();
230         doReturn(guestInfo.getUserHandle()).when(mCreateResult).getUser();
231         doReturn(guestInfo).when(mMockUserEventManager).getUserInfo(USER_ID_GUEST);
232         doReturn(true).when(mMockUserEventManager).stopUserUnchecked(anyInt(), anyInt());
233         displaySetup(/* isLogoutState= */ false, /* displayId= */ FRONT_PASSENGER_DISPLAY_ID);
234 
235         mUserPickerController.handleUserSelected(getUserRecord(mGuestLabel));
236 
237         verify(mMockUserEventManager, after(IDLE_TIMEOUT)).createGuest();
238         verify(mMockUserEventManager, after(IDLE_TIMEOUT).atLeastOnce())
239                 .stopUserUnchecked(USER_ID_FRONT, FRONT_PASSENGER_DISPLAY_ID);
240         verify(mMockUserEventManager, after(IDLE_TIMEOUT))
241                 .startUserForDisplay(anyInt(), eq(USER_ID_GUEST), anyInt(), anyBoolean());
242     }
243 
244     @Test
checkAddNewUser_pressAddUserIcon_createdUser()245     public void checkAddNewUser_pressAddUserIcon_createdUser() {
246         UserInfo newUserInfo = new UserInfo(USER_ID_REAR + 1, "New", UserInfo.FLAG_FULL);
247         doReturn(true).when(mCreateResult).isSuccess();
248         doReturn(mCreateResult).when(mMockUserEventManager).createNewUser();
249         doReturn(true).when(mMockUserEventManager).stopUserUnchecked(anyInt(), anyInt());
250         doReturn(newUserInfo.getUserHandle()).when(mCreateResult).getUser();
251         doReturn(newUserInfo).when(mMockUserEventManager)
252                 .getUserInfo(newUserInfo.getUserHandle().getIdentifier());
253         displaySetup(/* isLogoutState= */ false, /* displayId= */ FRONT_PASSENGER_DISPLAY_ID);
254 
255         mUserPickerController.startAddNewUser();
256 
257         verify(mMockUserEventManager, after(IDLE_TIMEOUT)).createNewUser();
258         verify(mMockUserEventManager, after(IDLE_TIMEOUT).atLeastOnce())
259                 .stopUserUnchecked(USER_ID_FRONT, FRONT_PASSENGER_DISPLAY_ID);
260         verify(mMockUserEventManager, after(IDLE_TIMEOUT))
261                 .startUserForDisplay(anyInt(), eq(USER_ID_REAR + 1), anyInt(), anyBoolean());
262     }
263 
264     @Test
checkDestroyController_callOnDestroy_destroyAll()265     public void checkDestroyController_callOnDestroy_destroyAll() {
266         displaySetup(/* isLogoutState= */ false, /* displayId= */ FRONT_PASSENGER_DISPLAY_ID);
267         spyOn(mUserPickerSharedState);
268 
269         mUserPickerController.onDestroy();
270 
271         verify(mUserPickerSharedState).resetUserLoginStarted(eq(FRONT_PASSENGER_DISPLAY_ID));
272         verify(mMockUserEventManager)
273                 .unregisterOnUpdateUsersListener(eq(FRONT_PASSENGER_DISPLAY_ID));
274     }
275 }
276