1 /*
2  * Copyright (C) 2020 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 android.car.test.mocks;
17 
18 import static android.car.test.mocks.CarArgumentMatchers.isUserHandle;
19 
20 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
21 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doThrow;
22 
23 import static com.google.common.truth.Truth.assertWithMessage;
24 
25 import static org.mockito.ArgumentMatchers.anyString;
26 import static org.mockito.ArgumentMatchers.argThat;
27 import static org.mockito.Mockito.when;
28 
29 import android.annotation.NonNull;
30 import android.annotation.Nullable;
31 import android.annotation.UserIdInt;
32 import android.app.Activity;
33 import android.app.ActivityManager;
34 import android.app.admin.DevicePolicyManager;
35 import android.car.Car;
36 import android.car.CarVersion;
37 import android.car.PlatformVersion;
38 import android.car.builtin.app.ActivityManagerHelper;
39 import android.car.builtin.os.UserManagerHelper;
40 import android.car.test.util.UserTestingHelper;
41 import android.car.test.util.Visitor;
42 import android.content.Context;
43 import android.content.pm.PackageManager;
44 import android.content.pm.PackageManager.PermissionResult;
45 import android.content.pm.UserInfo;
46 import android.content.pm.UserInfo.UserInfoFlag;
47 import android.os.Binder;
48 import android.os.Handler;
49 import android.os.IBinder;
50 import android.os.IInterface;
51 import android.os.Looper;
52 import android.os.NewUserRequest;
53 import android.os.NewUserResponse;
54 import android.os.ServiceManager;
55 import android.os.UserHandle;
56 import android.os.UserManager;
57 import android.os.UserManager.RemoveResult;
58 import android.os.UserManager.UserSwitchabilityResult;
59 import android.util.Log;
60 
61 import org.mockito.ArgumentMatcher;
62 
63 import java.util.Arrays;
64 import java.util.List;
65 import java.util.Objects;
66 import java.util.Set;
67 import java.util.concurrent.Callable;
68 import java.util.concurrent.CountDownLatch;
69 import java.util.concurrent.atomic.AtomicReference;
70 import java.util.stream.Collectors;
71 
72 /**
73  * Provides common Mockito calls for core Android classes.
74  */
75 public final class AndroidMockitoHelper {
76 
77     private static final String TAG = AndroidMockitoHelper.class.getSimpleName();
78 
79     /**
80      * Mocks a call to {@link ActivityManager#getCurrentUser()}.
81      *
82      * <p><b>Note: </b>it must be made inside a
83      * {@link com.android.dx.mockito.inline.extended.StaticMockitoSession} built with
84      * {@code spyStatic(ActivityManager.class)}.
85      *
86      * @param userId result of such call
87      */
mockAmGetCurrentUser(@serIdInt int userId)88     public static void mockAmGetCurrentUser(@UserIdInt int userId) {
89         doReturn(userId).when(() -> ActivityManager.getCurrentUser());
90     }
91 
92     /**
93      * Mocks a call to {@link ActivityManager#switchUser(UserHandle)}.
94      */
mockAmSwitchUser(ActivityManager am, UserHandle user, boolean result)95     public static void mockAmSwitchUser(ActivityManager am, UserHandle user,
96             boolean result) {
97         when(am.switchUser(user)).thenReturn(result);
98     }
99 
100     /**
101      * Mocks a call to {@link ActivityManagerHelper#startUserInBackground(int)}.
102      *
103      * * <p><b>Note: </b>it must be made inside a
104      *      * {@link com.android.dx.mockito.inline.extended.StaticMockitoSession} built with
105      *      * {@code spyStatic(ActivityManagerHelper.class)}.
106      */
mockAmStartUserInBackground(@serIdInt int userId, boolean result)107     public static void mockAmStartUserInBackground(@UserIdInt int userId, boolean result)
108             throws Exception {
109         doReturn(result).when(() -> ActivityManagerHelper.startUserInBackground(userId));
110     }
111 
112     /**
113      * Mocks a call to {@link ActivityManagerHelper#startUserInBackgroundVisibleOnDisplay(int, int)}
114      *
115      * * <p><b>Note: </b>it must be made inside a
116      *      * {@link com.android.dx.mockito.inline.extended.StaticMockitoSession} built with
117      *      * {@code spyStatic(ActivityManagerHelper.class)}.
118      */
mockAmStartUserInBackgroundVisibleOnDisplay( @serIdInt int userId, int displayId, boolean result)119     public static void mockAmStartUserInBackgroundVisibleOnDisplay(
120             @UserIdInt int userId, int displayId, boolean result) throws Exception {
121         doReturn(result).when(()
122                 -> ActivityManagerHelper.startUserInBackgroundVisibleOnDisplay(userId, displayId));
123     }
124 
125     /**
126      * Mocks a call to {@link ActivityManagerHelper#stopUser(int, boolean)}.
127      *
128      * * <p><b>Note: </b>it must be made inside a
129      *      * {@link com.android.dx.mockito.inline.extended.StaticMockitoSession} built with
130      *      * {@code spyStatic(ActivityManagerHelper.class)}.
131      */
mockForceStopUser(@serIdInt int userId, int result)132     public static void mockForceStopUser(@UserIdInt int userId, int result) throws Exception {
133         doReturn(result)
134                 .when(() -> ActivityManagerHelper.stopUser(userId, /* force= */ true));
135     }
136 
137     /**
138      * Mocks a throwing call to {@link ActivityManagerHelper#stopUser(int, boolean)}.
139      *
140      * * <p><b>Note: </b>it must be made inside a
141      *      * {@link com.android.dx.mockito.inline.extended.StaticMockitoSession} built with
142      *      * {@code spyStatic(ActivityManagerHelper.class)}.
143      */
mockForceStopUserThrows(@serIdInt int userId, Throwable throwable)144     public static void mockForceStopUserThrows(@UserIdInt int userId, Throwable throwable)
145             throws Exception {
146         doThrow(throwable).when(() -> ActivityManagerHelper.stopUser(userId, /* force= */ true));
147     }
148 
149     /**
150      * Mocks a call to {@link ActivityManagerHelper#stopUserWithDelayedLocking(int, boolean)}.
151      *
152      * * <p><b>Note: </b>it must be made inside a
153      *      * {@link com.android.dx.mockito.inline.extended.StaticMockitoSession} built with
154      *      * {@code spyStatic(ActivityManagerHelper.class)}.
155      */
mockStopUserWithDelayedLocking(@serIdInt int userId, int result)156     public static void mockStopUserWithDelayedLocking(@UserIdInt int userId, int result)
157             throws Exception {
158         doReturn(result)
159                 .when(() -> ActivityManagerHelper.stopUserWithDelayedLocking(
160                         userId, /* force= */ true));
161     }
162 
163     /**
164      * Mocks a throwing call to
165      *     {@link ActivityManagerHelper#stopUserWithDelayedLocking(int, boolean)}.
166      *
167      * * <p><b>Note: </b>it must be made inside a
168      *      * {@link com.android.dx.mockito.inline.extended.StaticMockitoSession} built with
169      *      * {@code spyStatic(ActivityManagerHelper.class)}.
170      */
mockStopUserWithDelayedLockingThrows(@serIdInt int userId, Throwable throwable)171     public static void mockStopUserWithDelayedLockingThrows(@UserIdInt int userId,
172             Throwable throwable) throws Exception {
173         doThrow(throwable).when(() -> ActivityManagerHelper.stopUserWithDelayedLocking(
174                 userId, /* force= */ true));
175     }
176 
177     /**
178      * Mocks a call to {@link DevicePolicyManager#logoutUser()}.
179      */
mockDpmLogoutUser(DevicePolicyManager dpm, int result)180     public static void mockDpmLogoutUser(DevicePolicyManager dpm, int result) {
181         when(dpm.logoutUser()).thenReturn(result);
182     }
183 
184     /**
185      * Mocks a successful call to {@code UserManager#createUser(NewUserRequest)}
186      */
mockUmCreateUser(UserManager um, @Nullable String name, String userType, @UserInfoFlag int flags, UserHandle user)187     public static void mockUmCreateUser(UserManager um, @Nullable String name, String userType,
188             @UserInfoFlag int flags, UserHandle user) {
189         NewUserResponse response = new NewUserResponse(user, UserManager.USER_OPERATION_SUCCESS);
190         when(um.createUser(isNewUserRequest(name, userType, flags))).thenReturn(response);
191     }
192 
193     /**
194      * Mocks a call to {@code UserManager#createUser(NewUserRequest)} that returns the given
195      * response.
196      */
mockUmCreateUser(UserManager um, @Nullable String name, String userType, @UserInfoFlag int flags, NewUserResponse response)197     public static void mockUmCreateUser(UserManager um, @Nullable String name, String userType,
198             @UserInfoFlag int flags, NewUserResponse response) {
199         when(um.createUser(isNewUserRequest(name, userType, flags))).thenReturn(response);
200     }
201 
202     /**
203      * Mocks a call to {@code UserManager#createUser(NewUserRequest)} that throws the given
204      * runtime exception.
205      */
mockUmCreateUser(UserManager um, @Nullable String name, String userType, @UserInfoFlag int flags, RuntimeException e)206     public static void mockUmCreateUser(UserManager um, @Nullable String name, String userType,
207             @UserInfoFlag int flags, RuntimeException e) {
208         when(um.createUser(isNewUserRequest(name, userType, flags))).thenThrow(e);
209     }
210 
211     /**
212      * Mocks a successful call to {@code UserManager#createUser(NewUserRequest)}
213      */
mockUmCreateGuest(UserManager um, @Nullable String name, @UserIdInt int userId)214     public static void mockUmCreateGuest(UserManager um, @Nullable String name,
215             @UserIdInt int userId) {
216         NewUserResponse response = new NewUserResponse(UserHandle.of(userId),
217                 UserManager.USER_OPERATION_SUCCESS);
218         when(um.createUser(
219                 isNewUserRequest(name, UserManager.USER_TYPE_FULL_GUEST, /* flags= */ 0)))
220                 .thenReturn(response);
221     }
222 
223     @NonNull
isNewUserRequest(@ullable String name, String userType, @UserInfoFlag int flags)224     private static NewUserRequest isNewUserRequest(@Nullable String name,
225             String userType, @UserInfoFlag int flags) {
226         return argThat(new NewUserRequestMatcher(name, userType, flags));
227     }
228 
229     /**
230      * Mocks a call to {@link UserManager#isHeadlessSystemUserMode()}.
231      *
232      * <p><b>Note: </b>it must be made inside a
233      * {@linkcom.android.dx.mockito.inline.extended.StaticMockitoSession} built with
234      * {@code spyStatic(UserManager.class)}.
235      *
236      * @param mode result of such call
237      */
mockUmIsHeadlessSystemUserMode(boolean mode)238     public static void mockUmIsHeadlessSystemUserMode(boolean mode) {
239         doReturn(mode).when(() -> UserManager.isHeadlessSystemUserMode());
240     }
241 
242     /**
243      * Mocks {@code UserManager#getUserInfo(userId)} to return a {@link UserInfo} with the given
244      * {@code flags}.
245      */
246     @NonNull
mockUmGetUserInfo(UserManager um, @UserIdInt int userId, @UserInfoFlag int flags)247     public static UserInfo mockUmGetUserInfo(UserManager um, @UserIdInt int userId,
248             @UserInfoFlag int flags) {
249         Objects.requireNonNull(um);
250         UserInfo user = new UserTestingHelper.UserInfoBuilder(userId).setFlags(flags).build();
251         mockUmGetUserInfo(um, user);
252         return user;
253     }
254 
255     /**
256      * Mocks {@code UserManager.getUserInfo(userId)} to return the given {@link UserInfo}.
257      */
258     @NonNull
mockUmGetUserInfo(UserManager um, UserInfo user)259     public static void mockUmGetUserInfo(UserManager um, UserInfo user) {
260         when(um.getUserInfo(user.id)).thenReturn(user);
261     }
262 
263     /**
264      * Mocks {@code UserManager#getUserInfo(userId)} when the {@code userId} is the system user's.
265      */
266     @NonNull
mockUmGetSystemUser(UserManager um)267     public static void mockUmGetSystemUser(UserManager um) {
268         UserInfo user = new UserTestingHelper.UserInfoBuilder(UserHandle.USER_SYSTEM)
269                 .setFlags(UserInfo.FLAG_SYSTEM).build();
270         when(um.getUserInfo(UserHandle.USER_SYSTEM)).thenReturn(user);
271     }
272 
273     /**
274      * Mocks {@link UserManager#getAliveUsers()} to return the given users.
275      */
mockUmGetAliveUsers(UserManager um, UserInfo... users)276     public static void mockUmGetAliveUsers(UserManager um, UserInfo... users) {
277         Objects.requireNonNull(um);
278         when(um.getAliveUsers()).thenReturn(UserTestingHelper.toList(users));
279     }
280 
281     /**
282      * Mocks {@link UserManager#getAliveUsers()} to return the simple users with the given ids.
283      */
mockUmGetAliveUsers(UserManager um, @UserIdInt int... userIds)284     public static void mockUmGetAliveUsers(UserManager um,
285             @UserIdInt int... userIds) {
286         mockUmGetUserHandles(um, true, userIds);
287         List<UserInfo> users = UserTestingHelper.newUsers(userIds);
288         when(um.getAliveUsers()).thenReturn(users);
289     }
290 
291     /**
292      * Mocks {@link UserManager#getUserHandles(boolean)} to return the given users.
293      */
mockUmGetUserHandles(UserManager um, boolean excludeDying, UserHandle... users)294     public static void mockUmGetUserHandles(UserManager um, boolean excludeDying,
295             UserHandle... users) {
296         Objects.requireNonNull(users);
297         mockUmGetUserHandles(um, excludeDying, UserTestingHelper.toList(users));
298     }
299 
300     /**
301      * Mocks {@link UserManager#getUserHandles(boolean)} to return the given users.
302      */
mockUmGetUserHandles(UserManager um, boolean excludeDying, List<UserHandle> users)303     public static void mockUmGetUserHandles(UserManager um, boolean excludeDying,
304             List<UserHandle> users) {
305         Objects.requireNonNull(um);
306         Objects.requireNonNull(users);
307         when(um.getUserHandles(excludeDying)).thenReturn(users);
308     }
309 
310     /**
311      * Mocks {@link UserManager#getUserHandles(boolean)} to return the given users.
312      */
mockUmGetUserHandles(UserManager um, boolean excludeDying, int... userIds)313     public static void mockUmGetUserHandles(UserManager um, boolean excludeDying,
314             int... userIds) {
315         mockUmGetUserHandles(um, excludeDying, UserTestingHelper.newUserHandles(userIds));
316     }
317 
318     /** Mocks a call to {@link UserManager#getUserHandles(boolean)}. */
mockUmGetAllUsers(UserManager um, UserHandle... users)319     public static void mockUmGetAllUsers(UserManager um, UserHandle... users) {
320         mockUmGetUserHandles(um, /* excludeDying= */ false, users);
321     }
322 
323     /**
324      * Mocks a call to {@code UserManager#isUserRunning(userId)}.
325      */
mockUmIsUserRunning(UserManager um, @UserIdInt int userId, boolean isRunning)326     public static void mockUmIsUserRunning(UserManager um, @UserIdInt int userId,
327             boolean isRunning) {
328         when(um.isUserRunning(userId)).thenReturn(isRunning);
329         when(um.isUserRunning(UserHandle.of(userId))).thenReturn(isRunning);
330     }
331 
332     /**
333      * Mocks a call to {@code UserManager#isUserUnlockingOrUnlocked()}.
334      */
mockUmIsUserUnlockingOrUnlocked(UserManager um, @UserIdInt int userId, boolean value)335     public static void mockUmIsUserUnlockingOrUnlocked(UserManager um, @UserIdInt int userId,
336             boolean value) {
337         when(um.isUserUnlockingOrUnlocked(isUserHandle(userId))).thenReturn(value);
338         when(um.isUserUnlockingOrUnlocked(userId)).thenReturn(value);
339     }
340 
341     /**
342      * Mocks a successful call to {@code UserManager#removeUserWhenPossible(UserHandle, boolean)},
343      * and notifies {@code listener} when it's called.
344      */
mockUmRemoveUserWhenPossible(UserManager um, UserInfo user, boolean overrideDevicePolicy, @RemoveResult int result, @Nullable Visitor<UserInfo> listener)345     public static void mockUmRemoveUserWhenPossible(UserManager um,
346             UserInfo user, boolean overrideDevicePolicy, @RemoveResult int result,
347             @Nullable Visitor<UserInfo> listener) {
348         when(um.removeUserWhenPossible(user.getUserHandle(), overrideDevicePolicy))
349                 .thenAnswer((inv) -> {
350                     if (listener != null) {
351                         Log.v(TAG, "mockUmRemoveUserWhenPossible(" + user + "): notifying "
352                                 + listener);
353                         listener.visit(user);
354                     }
355                     return result;
356                 });
357     }
358 
359     /**
360      * Mocks a successful call to {@code UserManager#removeUserWhenPossible(UserHandle, boolean)},
361      * and notifies {@code listener} when it's called.
362      */
mockUmRemoveUserWhenPossible(UserManager um, UserHandle user, boolean overrideDevicePolicy, @RemoveResult int result, @Nullable Visitor<UserHandle> listener)363     public static void mockUmRemoveUserWhenPossible(UserManager um,
364             UserHandle user, boolean overrideDevicePolicy, @RemoveResult int result,
365             @Nullable Visitor<UserHandle> listener) {
366         when(um.removeUserWhenPossible(user, overrideDevicePolicy)).thenAnswer((inv) -> {
367             if (listener != null) {
368                 Log.v(TAG, "mockUmRemoveUserWhenPossible(" + user + "): notifying " + listener);
369                 listener.visit(user);
370             }
371             return result;
372         });
373     }
374 
375     /**
376      * Mocks a call to {@code UserManager#hasUserRestrictionForUser(String, UserHandle)} that
377      * returns {@code value}.
378      */
mockUmHasUserRestrictionForUser(UserManager um, UserHandle user, String restrictionKey, boolean value)379     public static void mockUmHasUserRestrictionForUser(UserManager um,
380             UserHandle user, String restrictionKey, boolean value) {
381         when(um.hasUserRestrictionForUser(restrictionKey, user)).thenReturn(value);
382     }
383 
384     /**
385      * Mocks a call to {@code UserManager#getUserSwitchability(int)} that
386      * returns {@code result}.
387      */
mockUmGetUserSwitchability(UserManager um, @UserSwitchabilityResult int result)388     public static void mockUmGetUserSwitchability(UserManager um,
389             @UserSwitchabilityResult int result) {
390         when(um.getUserSwitchability()).thenReturn(result);
391     }
392 
393     /**
394      * Mocks a call to {@code UserManager#getVisibleUsers()} that
395      * returns {@link UserHandle UserHandles} with the given {@code userIds}.
396      */
mockUmGetVisibleUsers(UserManager um, @UserIdInt int...userIds)397     public static void mockUmGetVisibleUsers(UserManager um, @UserIdInt int...userIds) {
398         Set<UserHandle> users = Arrays.stream(userIds).mapToObj(u -> UserHandle.of(u))
399                 .collect(Collectors.toSet());
400         Log.v(TAG, "mockUmGetVisibleUsers(" + Arrays.toString(userIds) + ": returning "
401                 + users);
402         when(um.getVisibleUsers()).thenReturn(users);
403     }
404 
405     /**
406      * Mocks a call to {@code UserManager#isUserVisible()} that returns {@code isVisible}.
407      */
mockUmIsUserVisible(UserManager um, boolean isVisible)408     public static void mockUmIsUserVisible(UserManager um, boolean isVisible) {
409         when(um.isUserVisible()).thenReturn(isVisible);
410     }
411 
412     /**
413      * Mocks a call to {@code UserManager#isVisibleBackgroundUsersSupported()} that returns
414      * {@code isVisibleBackgroundUsersSupported}.
415      */
mockUmIsVisibleBackgroundUsersSupported(UserManager um, boolean isVisibleBackgroundUsersSupported)416     public static void mockUmIsVisibleBackgroundUsersSupported(UserManager um,
417             boolean isVisibleBackgroundUsersSupported) {
418         when(um.isVisibleBackgroundUsersSupported()).thenReturn(
419                 isVisibleBackgroundUsersSupported);
420     }
421 
422     /**
423      * Mocks a call to {@code UserManager#isVisibleBackgroundUsersOnDefaultDisplaySupported()} that
424      * returns {@code isVisibleBackgroundUsersOnDefaultDisplaySupported}.
425      */
mockUmIsVisibleBackgroundUsersOnDefaultDisplaySupported(UserManager um, boolean supported)426     public static void mockUmIsVisibleBackgroundUsersOnDefaultDisplaySupported(UserManager um,
427             boolean supported) {
428         when(um.isVisibleBackgroundUsersOnDefaultDisplaySupported()).thenReturn(supported);
429     }
430 
431     /**
432      * Mocks a call to {@link ServiceManager#getService(name)}.
433      *
434      * <p><b>Note: </b>it must be made inside a
435      * {@link com.android.dx.mockito.inline.extended.StaticMockitoSession} built with
436      * {@code spyStatic(ServiceManager.class)}.
437      *
438      * @param name interface name of the service
439      * @param binder result of such call
440      */
mockSmGetService(String name, IBinder binder)441     public static void mockSmGetService(String name, IBinder binder) {
442         doReturn(binder).when(() -> ServiceManager.getService(name));
443     }
444 
445     /**
446      * Returns mocked binder implementation from the given interface name.
447      *
448      * <p><b>Note: </b>it must be made inside a
449      * {@link com.android.dx.mockito.inline.extended.StaticMockitoSession} built with
450      * {@code spyStatic(ServiceManager.class)}.
451      *
452      * @param name interface name of the service
453      * @param binder mocked return of ServiceManager.getService
454      * @param service binder implementation
455      */
mockQueryService(String name, IBinder binder, T service)456     public static <T extends IInterface> void mockQueryService(String name,
457             IBinder binder, T service) {
458         doReturn(binder).when(() -> ServiceManager.getService(name));
459         doReturn(binder).when(() -> ServiceManager.checkService(name));
460         when(binder.queryLocalInterface(anyString())).thenReturn(service);
461     }
462 
463     /**
464      * Mocks a call to {@link Binder#getCallingUserHandle()}.
465      *
466      * <p><b>Note: </b>it must be made inside a
467      * {@link com.android.dx.mockito.inline.extended.StaticMockitoSession} built with
468      * {@code spyStatic(Binder.class)}.
469      *
470      * @param userId identifier of the {@link UserHandle} that will be returned.
471      */
mockBinderGetCallingUserHandle(@serIdInt int userId)472     public static void mockBinderGetCallingUserHandle(@UserIdInt int userId) {
473         doReturn(UserHandle.of(userId)).when(() -> Binder.getCallingUserHandle());
474     }
475 
476     /**
477      * Mocks a call to {@link Car#getCarVersion()}
478      */
mockCarGetCarVersion(CarVersion version)479     public static void mockCarGetCarVersion(CarVersion version) {
480         Log.d(TAG, "mockCarGetCarVersion(): " + version);
481         doReturn(version).when(() -> Car.getCarVersion());
482     }
483 
484     /**
485      * Mocks a call to {@link Car#getPlatformVersion()}
486      */
mockCarGetPlatformVersion(PlatformVersion version)487     public static void mockCarGetPlatformVersion(PlatformVersion version) {
488         Log.d(TAG, "mockCarGetPlatformVersion(): " + version);
489         doReturn(version).when(() -> Car.getPlatformVersion());
490     }
491 
492     /**
493      * Mocks a call to {@link Car#isApiVersionAtLeast()}
494      */
mockCarIsApiVersionAtLeast(int major, int minor, boolean isIt)495     public static void mockCarIsApiVersionAtLeast(int major, int minor, boolean isIt) {
496         Log.d(TAG, "mockCarIsApiVersionAtLeast(" + major + ", " + minor + "): " + isIt);
497         doReturn(isIt).when(() -> Car.isApiVersionAtLeast(major, minor));
498     }
499 
500     /**
501      * Mocks a call to {@link Context#getSystemService(Class)}.
502      */
mockContextGetService(Context context, Class<T> serviceClass, T service)503     public static <T> void mockContextGetService(Context context,
504             Class<T> serviceClass, T service) {
505         when(context.getSystemService(serviceClass)).thenReturn(service);
506         if (serviceClass.equals(PackageManager.class)) {
507             when(context.getPackageManager()).thenReturn(PackageManager.class.cast(service));
508         }
509     }
510 
511     /**
512      * Mocks a call to {@link Context#checkCallingOrSelfPermission(String)}
513      */
mockContextCheckCallingOrSelfPermission(Context context, String permission, @PermissionResult int permissionResults)514     public static void mockContextCheckCallingOrSelfPermission(Context context,
515             String permission, @PermissionResult int permissionResults) {
516         when(context.checkCallingOrSelfPermission(permission)).thenReturn(permissionResults);
517     }
518 
519     /**
520      * Mock a call to {@link Context#createContextAsUser(UserHandle, int)}}
521      */
mockContextCreateContextAsUser(Context context, Context userContext, @UserIdInt int userId)522     public static void mockContextCreateContextAsUser(Context context, Context userContext,
523             @UserIdInt int userId) {
524         when(context.createContextAsUser(UserHandle.of(userId), /* flags= */ 0)).thenReturn(
525                 userContext);
526     }
527 
528     // TODO(b/192307581): add unit tests
529     /**
530      * Returns the result of the giving {@code callable} in the main thread, preparing the
531      * {@link Looper} if needed and using a default timeout.
532      */
syncCallOnMainThread(Callable<T> c)533     public static <T> T syncCallOnMainThread(Callable<T> c) throws Exception {
534         return syncCallOnMainThread(JavaMockitoHelper.ASYNC_TIMEOUT_MS, c);
535     }
536 
537     // TODO(b/192307581): add unit tests
538     /**
539      * Returns the result of the giving {@code callable} in the main thread, preparing the
540      * {@link Looper} if needed.
541      */
syncCallOnMainThread(long timeoutMs, Callable<T> callable)542     public static <T> T syncCallOnMainThread(long timeoutMs, Callable<T> callable)
543             throws Exception {
544         boolean quitLooper = false;
545         Looper looper = Looper.getMainLooper();
546         if (looper == null) {
547             Log.i(TAG, "preparing main looper");
548             Looper.prepareMainLooper();
549             looper = Looper.getMainLooper();
550             assertWithMessage("Looper.getMainLooper()").that(looper).isNotNull();
551             quitLooper = true;
552         }
553         Log.i(TAG, "looper: " + looper);
554         AtomicReference<Exception> exception = new AtomicReference<>();
555         AtomicReference<T> ref = new AtomicReference<>();
556         try {
557             Handler handler = new Handler(looper);
558             CountDownLatch latch = new CountDownLatch(1);
559             handler.post(() -> {
560                 T result = null;
561                 try {
562                     result = callable.call();
563                 } catch (Exception e) {
564                     exception.set(e);
565                 }
566                 ref.set(result);
567                 latch.countDown();
568             });
569             JavaMockitoHelper.await(latch, timeoutMs);
570             Exception e = exception.get();
571             if (e != null) throw e;
572             return ref.get();
573         } finally {
574             if (quitLooper) {
575                 Log.i(TAG, "quitting looper: " + looper);
576                 looper.quitSafely();
577             }
578         }
579     }
580 
581     // TODO(b/192307581): add unit tests
582     /**
583      * Runs the giving {@code runnable} in the activity's UI thread, using a default timeout.
584      */
syncRunOnUiThread(Activity activity, Runnable runnable)585     public static void syncRunOnUiThread(Activity activity, Runnable runnable) throws Exception {
586         syncRunOnUiThread(JavaMockitoHelper.ASYNC_TIMEOUT_MS, activity, runnable);
587     }
588 
589     // TODO(b/192307581): add unit tests
590     /**
591      * Runs the giving {@code runnable} in the activity's UI thread.
592      */
syncRunOnUiThread(long timeoutMs, Activity activity, Runnable runnable)593     public static void syncRunOnUiThread(long timeoutMs, Activity activity, Runnable runnable)
594             throws Exception {
595         CountDownLatch latch = new CountDownLatch(1);
596         activity.runOnUiThread(() -> {
597             runnable.run();
598             latch.countDown();
599         });
600         JavaMockitoHelper.await(latch, timeoutMs);
601     }
602 
AndroidMockitoHelper()603     private AndroidMockitoHelper() {
604         throw new UnsupportedOperationException("contains only static methods");
605     }
606 
607     static final class NewUserRequestMatcher implements
608             ArgumentMatcher<NewUserRequest> {
609 
610         private final String mName;
611         private final String mUserType;
612         private final int mFlags;
613 
NewUserRequestMatcher(String name, String userType, int flags)614         NewUserRequestMatcher(String name, String userType, int flags) {
615             mName = name;
616             mUserType = userType;
617             mFlags = flags;
618         }
619 
620         @Override
matches(NewUserRequest request)621         public boolean matches(NewUserRequest request) {
622             if (request.isAdmin()
623                     && ((mFlags & UserManagerHelper.FLAG_ADMIN) != UserManagerHelper.FLAG_ADMIN)) {
624                 return false;
625             }
626             if (request.isEphemeral() && ((mFlags
627                     & UserManagerHelper.FLAG_EPHEMERAL) != UserManagerHelper.FLAG_EPHEMERAL)) {
628                 return false;
629             }
630 
631             return request.getUserType().equals(mUserType)
632                     && Objects.equals(request.getName(), mName);
633         }
634     }
635 }
636