1d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov/*
2d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov * Copyright (C) 2016 The Android Open Source Project
3d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov *
4d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov * Licensed under the Apache License, Version 2.0 (the "License");
5d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov * you may not use this file except in compliance with the License.
6d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov * You may obtain a copy of the License at
7d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov *
8d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov *      http://www.apache.org/licenses/LICENSE-2.0
9d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov *
10d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov * Unless required by applicable law or agreed to in writing, software
11d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov * distributed under the License is distributed on an "AS IS" BASIS,
12d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov * See the License for the specific language governing permissions and
14d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov * limitations under the License
15d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov */
16d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov
17d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolovpackage com.android.server.am;
18d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov
195c2cf03f5f8e26f715931370004d21ee217edcdeTony Makimport android.app.ActivityManager;
203b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolovimport android.app.IUserSwitchObserver;
21d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolovimport android.content.Context;
22d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolovimport android.content.IIntentReceiver;
23d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolovimport android.content.Intent;
24d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolovimport android.content.pm.UserInfo;
253b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolovimport android.os.Binder;
26d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolovimport android.os.Bundle;
27d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolovimport android.os.Handler;
28d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolovimport android.os.HandlerThread;
293b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolovimport android.os.IRemoteCallback;
303b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolovimport android.os.Looper;
313b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolovimport android.os.Message;
32d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolovimport android.os.RemoteException;
33d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolovimport android.os.UserManagerInternal;
34d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolovimport android.test.AndroidTestCase;
359bc8543d45fc7f2edf857181940d3719e480a597Fyodor Kupolovimport android.test.suitebuilder.annotation.SmallTest;
36d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolovimport android.util.Log;
37d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov
38d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolovimport com.android.server.pm.UserManagerService;
39d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolovimport com.android.server.wm.WindowManagerService;
40d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov
41d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolovimport org.mockito.Mockito;
42d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov
43d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolovimport java.util.ArrayList;
44d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolovimport java.util.Arrays;
453b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolovimport java.util.Collections;
463b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolovimport java.util.HashSet;
473b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolovimport java.util.LinkedHashSet;
48d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolovimport java.util.List;
493b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolovimport java.util.Set;
50d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov
51d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolovimport static android.content.pm.PackageManager.PERMISSION_GRANTED;
523b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolovimport static com.android.server.am.ActivityManagerService.CONTINUE_USER_SWITCH_MSG;
535c2cf03f5f8e26f715931370004d21ee217edcdeTony Makimport static com.android.server.am.ActivityManagerService.REPORT_LOCKED_BOOT_COMPLETE_MSG;
543b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolovimport static com.android.server.am.ActivityManagerService.REPORT_USER_SWITCH_COMPLETE_MSG;
553b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolovimport static com.android.server.am.ActivityManagerService.REPORT_USER_SWITCH_MSG;
563b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolovimport static com.android.server.am.ActivityManagerService.SYSTEM_USER_CURRENT_MSG;
573b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolovimport static com.android.server.am.ActivityManagerService.SYSTEM_USER_START_MSG;
583b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolovimport static com.android.server.am.ActivityManagerService.USER_SWITCH_TIMEOUT_MSG;
595c2cf03f5f8e26f715931370004d21ee217edcdeTony Makimport static org.mockito.ArgumentMatchers.anyString;
605c2cf03f5f8e26f715931370004d21ee217edcdeTony Makimport static org.mockito.ArgumentMatchers.nullable;
613b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolovimport static org.mockito.Matchers.any;
623e0c25bf099e2942ee98b908ee01f82ce5e0bc82Evan Roskyimport static org.mockito.Matchers.anyBoolean;
63d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolovimport static org.mockito.Matchers.anyInt;
64d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolovimport static org.mockito.Matchers.eq;
653b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolovimport static org.mockito.Mockito.doAnswer;
665c2cf03f5f8e26f715931370004d21ee217edcdeTony Makimport static org.mockito.Mockito.doNothing;
67d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolovimport static org.mockito.Mockito.mock;
68d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolovimport static org.mockito.Mockito.never;
693b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolovimport static org.mockito.Mockito.times;
70d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolovimport static org.mockito.Mockito.when;
71d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov
72d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolovpublic class UserControllerTest extends AndroidTestCase {
733b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov    private static final int TEST_USER_ID = 10;
743e0c25bf099e2942ee98b908ee01f82ce5e0bc82Evan Rosky    private static final int NONEXIST_USER_ID = 2;
75d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov    private static String TAG = UserControllerTest.class.getSimpleName();
76d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov    private UserController mUserController;
77d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov    private TestInjector mInjector;
78d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov
795c2cf03f5f8e26f715931370004d21ee217edcdeTony Mak    private static final List<String> START_FOREGROUND_USER_ACTIONS =
805c2cf03f5f8e26f715931370004d21ee217edcdeTony Mak            Arrays.asList(
815c2cf03f5f8e26f715931370004d21ee217edcdeTony Mak                    Intent.ACTION_USER_STARTED,
825c2cf03f5f8e26f715931370004d21ee217edcdeTony Mak                    Intent.ACTION_USER_SWITCHED,
835c2cf03f5f8e26f715931370004d21ee217edcdeTony Mak                    Intent.ACTION_USER_STARTING);
845c2cf03f5f8e26f715931370004d21ee217edcdeTony Mak
855c2cf03f5f8e26f715931370004d21ee217edcdeTony Mak    private static final List<String> START_BACKGROUND_USER_ACTIONS =
865c2cf03f5f8e26f715931370004d21ee217edcdeTony Mak            Arrays.asList(
875c2cf03f5f8e26f715931370004d21ee217edcdeTony Mak                    Intent.ACTION_USER_STARTED,
885c2cf03f5f8e26f715931370004d21ee217edcdeTony Mak                    Intent.ACTION_LOCKED_BOOT_COMPLETED,
895c2cf03f5f8e26f715931370004d21ee217edcdeTony Mak                    Intent.ACTION_USER_STARTING);
905c2cf03f5f8e26f715931370004d21ee217edcdeTony Mak
915c2cf03f5f8e26f715931370004d21ee217edcdeTony Mak    private static final Set<Integer> START_FOREGROUND_USER_MESSAGE_CODES =
925c2cf03f5f8e26f715931370004d21ee217edcdeTony Mak            new HashSet<>(Arrays.asList(REPORT_USER_SWITCH_MSG, USER_SWITCH_TIMEOUT_MSG,
935c2cf03f5f8e26f715931370004d21ee217edcdeTony Mak                    SYSTEM_USER_START_MSG, SYSTEM_USER_CURRENT_MSG));
945c2cf03f5f8e26f715931370004d21ee217edcdeTony Mak
955c2cf03f5f8e26f715931370004d21ee217edcdeTony Mak    private static final Set<Integer> START_BACKGROUND_USER_MESSAGE_CODES =
965c2cf03f5f8e26f715931370004d21ee217edcdeTony Mak            new HashSet<>(Arrays.asList(SYSTEM_USER_START_MSG, REPORT_LOCKED_BOOT_COMPLETE_MSG));
975c2cf03f5f8e26f715931370004d21ee217edcdeTony Mak
98d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov    @Override
99d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov    public void setUp() throws Exception {
100d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov        super.setUp();
1015c2cf03f5f8e26f715931370004d21ee217edcdeTony Mak        System.setProperty("dexmaker.share_classloader", "true");
102d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov        mInjector = new TestInjector(getContext());
103d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov        mUserController = new UserController(mInjector);
1043b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov        setUpUser(TEST_USER_ID, 0);
105d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov    }
106d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov
107d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov    @Override
108d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov    protected void tearDown() throws Exception {
109d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov        super.tearDown();
110d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov        mInjector.handlerThread.quit();
111d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov    }
112d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov
1139bc8543d45fc7f2edf857181940d3719e480a597Fyodor Kupolov    @SmallTest
1145c2cf03f5f8e26f715931370004d21ee217edcdeTony Mak    public void testStartUser_foreground() throws RemoteException {
1155c2cf03f5f8e26f715931370004d21ee217edcdeTony Mak        mUserController.startUser(TEST_USER_ID, true /* foreground */);
116d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov        Mockito.verify(mInjector.getWindowManager()).startFreezingScreen(anyInt(), anyInt());
117d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov        Mockito.verify(mInjector.getWindowManager(), never()).stopFreezingScreen();
1183e0c25bf099e2942ee98b908ee01f82ce5e0bc82Evan Rosky        Mockito.verify(mInjector.getWindowManager(), times(1)).setSwitchingUser(anyBoolean());
1193e0c25bf099e2942ee98b908ee01f82ce5e0bc82Evan Rosky        Mockito.verify(mInjector.getWindowManager()).setSwitchingUser(true);
1205c2cf03f5f8e26f715931370004d21ee217edcdeTony Mak        Mockito.verify(mInjector.getActivityStackSupervisor()).setLockTaskModeLocked(
1215c2cf03f5f8e26f715931370004d21ee217edcdeTony Mak                nullable(TaskRecord.class),
1225c2cf03f5f8e26f715931370004d21ee217edcdeTony Mak                eq(ActivityManager.LOCK_TASK_MODE_NONE),
1235c2cf03f5f8e26f715931370004d21ee217edcdeTony Mak                anyString(),
1245c2cf03f5f8e26f715931370004d21ee217edcdeTony Mak                anyBoolean());
1255c2cf03f5f8e26f715931370004d21ee217edcdeTony Mak        startForegroundUserAssertions();
1265c2cf03f5f8e26f715931370004d21ee217edcdeTony Mak    }
1275c2cf03f5f8e26f715931370004d21ee217edcdeTony Mak
1285c2cf03f5f8e26f715931370004d21ee217edcdeTony Mak    @SmallTest
1295c2cf03f5f8e26f715931370004d21ee217edcdeTony Mak    public void testStartUser_background() throws RemoteException {
1305c2cf03f5f8e26f715931370004d21ee217edcdeTony Mak        mUserController.startUser(TEST_USER_ID, false /* foreground */);
1315c2cf03f5f8e26f715931370004d21ee217edcdeTony Mak        Mockito.verify(
1325c2cf03f5f8e26f715931370004d21ee217edcdeTony Mak                mInjector.getWindowManager(), never()).startFreezingScreen(anyInt(), anyInt());
1335c2cf03f5f8e26f715931370004d21ee217edcdeTony Mak        Mockito.verify(mInjector.getWindowManager(), never()).setSwitchingUser(anyBoolean());
1345c2cf03f5f8e26f715931370004d21ee217edcdeTony Mak        Mockito.verify(mInjector.getActivityStackSupervisor(), never()).setLockTaskModeLocked(
1355c2cf03f5f8e26f715931370004d21ee217edcdeTony Mak                nullable(TaskRecord.class),
1365c2cf03f5f8e26f715931370004d21ee217edcdeTony Mak                eq(ActivityManager.LOCK_TASK_MODE_NONE),
1375c2cf03f5f8e26f715931370004d21ee217edcdeTony Mak                anyString(),
1385c2cf03f5f8e26f715931370004d21ee217edcdeTony Mak                anyBoolean());
1395c2cf03f5f8e26f715931370004d21ee217edcdeTony Mak        startBackgroundUserAssertions();
1403e0c25bf099e2942ee98b908ee01f82ce5e0bc82Evan Rosky    }
1413e0c25bf099e2942ee98b908ee01f82ce5e0bc82Evan Rosky
1423e0c25bf099e2942ee98b908ee01f82ce5e0bc82Evan Rosky    @SmallTest
1433e0c25bf099e2942ee98b908ee01f82ce5e0bc82Evan Rosky    public void testStartUserUIDisabled() throws RemoteException {
1443e0c25bf099e2942ee98b908ee01f82ce5e0bc82Evan Rosky        mUserController.mUserSwitchUiEnabled = false;
1455c2cf03f5f8e26f715931370004d21ee217edcdeTony Mak        mUserController.startUser(TEST_USER_ID, true /* foreground */);
1463e0c25bf099e2942ee98b908ee01f82ce5e0bc82Evan Rosky        Mockito.verify(mInjector.getWindowManager(), never())
1473e0c25bf099e2942ee98b908ee01f82ce5e0bc82Evan Rosky                .startFreezingScreen(anyInt(), anyInt());
1483e0c25bf099e2942ee98b908ee01f82ce5e0bc82Evan Rosky        Mockito.verify(mInjector.getWindowManager(), never()).stopFreezingScreen();
1493e0c25bf099e2942ee98b908ee01f82ce5e0bc82Evan Rosky        Mockito.verify(mInjector.getWindowManager(), never()).setSwitchingUser(anyBoolean());
1505c2cf03f5f8e26f715931370004d21ee217edcdeTony Mak        startForegroundUserAssertions();
1513e0c25bf099e2942ee98b908ee01f82ce5e0bc82Evan Rosky    }
1523e0c25bf099e2942ee98b908ee01f82ce5e0bc82Evan Rosky
1535c2cf03f5f8e26f715931370004d21ee217edcdeTony Mak    private void startUserAssertions(
1545c2cf03f5f8e26f715931370004d21ee217edcdeTony Mak            List<String> expectedActions, Set<Integer> expectedMessageCodes)
1555c2cf03f5f8e26f715931370004d21ee217edcdeTony Mak            throws RemoteException {
156d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov        assertEquals(expectedActions, getActions(mInjector.sentIntents));
1573b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov        Set<Integer> actualCodes = mInjector.handler.getMessageCodes();
1585c2cf03f5f8e26f715931370004d21ee217edcdeTony Mak        assertEquals("Unexpected message sent", expectedMessageCodes, actualCodes);
1595c2cf03f5f8e26f715931370004d21ee217edcdeTony Mak    }
1605c2cf03f5f8e26f715931370004d21ee217edcdeTony Mak
1615c2cf03f5f8e26f715931370004d21ee217edcdeTony Mak    private void startBackgroundUserAssertions() throws RemoteException {
1625c2cf03f5f8e26f715931370004d21ee217edcdeTony Mak        startUserAssertions(START_BACKGROUND_USER_ACTIONS, START_BACKGROUND_USER_MESSAGE_CODES);
1635c2cf03f5f8e26f715931370004d21ee217edcdeTony Mak    }
1645c2cf03f5f8e26f715931370004d21ee217edcdeTony Mak
1655c2cf03f5f8e26f715931370004d21ee217edcdeTony Mak    private void startForegroundUserAssertions() throws RemoteException {
1665c2cf03f5f8e26f715931370004d21ee217edcdeTony Mak        startUserAssertions(START_FOREGROUND_USER_ACTIONS, START_FOREGROUND_USER_MESSAGE_CODES);
1673b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov        Message reportMsg = mInjector.handler.getMessageForCode(REPORT_USER_SWITCH_MSG);
1683b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov        assertNotNull(reportMsg);
1693b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov        UserState userState = (UserState) reportMsg.obj;
1703b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov        assertNotNull(userState);
1713b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov        assertEquals(TEST_USER_ID, userState.mHandle.getIdentifier());
1723b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov        assertEquals("User must be in STATE_BOOTING", UserState.STATE_BOOTING, userState.state);
1733b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov        assertEquals("Unexpected old user id", 0, reportMsg.arg1);
1743b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov        assertEquals("Unexpected new user id", TEST_USER_ID, reportMsg.arg2);
1753b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov    }
1763b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov
1779bc8543d45fc7f2edf857181940d3719e480a597Fyodor Kupolov    @SmallTest
1783e0c25bf099e2942ee98b908ee01f82ce5e0bc82Evan Rosky    public void testFailedStartUserInForeground() throws RemoteException {
1793e0c25bf099e2942ee98b908ee01f82ce5e0bc82Evan Rosky        mUserController.mUserSwitchUiEnabled = false;
1803e0c25bf099e2942ee98b908ee01f82ce5e0bc82Evan Rosky        mUserController.startUserInForeground(NONEXIST_USER_ID);
1813e0c25bf099e2942ee98b908ee01f82ce5e0bc82Evan Rosky        Mockito.verify(mInjector.getWindowManager(), times(1)).setSwitchingUser(anyBoolean());
1823e0c25bf099e2942ee98b908ee01f82ce5e0bc82Evan Rosky        Mockito.verify(mInjector.getWindowManager()).setSwitchingUser(false);
1833e0c25bf099e2942ee98b908ee01f82ce5e0bc82Evan Rosky    }
1843e0c25bf099e2942ee98b908ee01f82ce5e0bc82Evan Rosky
1853e0c25bf099e2942ee98b908ee01f82ce5e0bc82Evan Rosky    @SmallTest
1863b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov    public void testDispatchUserSwitch() throws RemoteException {
1873b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov        // Prepare mock observer and register it
1883b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov        IUserSwitchObserver observer = mock(IUserSwitchObserver.class);
1893b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov        when(observer.asBinder()).thenReturn(new Binder());
1903b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov        doAnswer(invocation -> {
1913b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov            IRemoteCallback callback = (IRemoteCallback) invocation.getArguments()[1];
1923b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov            callback.sendResult(null);
1933b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov            return null;
1943b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov        }).when(observer).onUserSwitching(anyInt(), any());
1953b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov        mUserController.registerUserSwitchObserver(observer, "mock");
1963b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov        // Start user -- this will update state of mUserController
1973b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov        mUserController.startUser(TEST_USER_ID, true);
1983b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov        Message reportMsg = mInjector.handler.getMessageForCode(REPORT_USER_SWITCH_MSG);
1993b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov        assertNotNull(reportMsg);
2003b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov        UserState userState = (UserState) reportMsg.obj;
2013b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov        int oldUserId = reportMsg.arg1;
2023b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov        int newUserId = reportMsg.arg2;
2033b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov        // Call dispatchUserSwitch and verify that observer was called only once
2043b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov        mInjector.handler.clearAllRecordedMessages();
2053b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov        mUserController.dispatchUserSwitch(userState, oldUserId, newUserId);
2063b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov        Mockito.verify(observer, times(1)).onUserSwitching(eq(TEST_USER_ID), any());
2073b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov        Set<Integer> expectedCodes = Collections.singleton(CONTINUE_USER_SWITCH_MSG);
2083b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov        Set<Integer> actualCodes = mInjector.handler.getMessageCodes();
2093b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov        assertEquals("Unexpected message sent", expectedCodes, actualCodes);
2103b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov        Message conMsg = mInjector.handler.getMessageForCode(CONTINUE_USER_SWITCH_MSG);
2113b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov        assertNotNull(conMsg);
2123b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov        userState = (UserState) conMsg.obj;
2133b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov        assertNotNull(userState);
2143b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov        assertEquals(TEST_USER_ID, userState.mHandle.getIdentifier());
2153b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov        assertEquals("User must be in STATE_BOOTING", UserState.STATE_BOOTING, userState.state);
2163b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov        assertEquals("Unexpected old user id", 0, conMsg.arg1);
2173b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov        assertEquals("Unexpected new user id", TEST_USER_ID, conMsg.arg2);
2183b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov    }
2193b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov
2209bc8543d45fc7f2edf857181940d3719e480a597Fyodor Kupolov    @SmallTest
2213b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov    public void testDispatchUserSwitchBadReceiver() throws RemoteException {
2223b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov        // Prepare mock observer which doesn't notify the callback and register it
2233b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov        IUserSwitchObserver observer = mock(IUserSwitchObserver.class);
2243b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov        when(observer.asBinder()).thenReturn(new Binder());
2253b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov        mUserController.registerUserSwitchObserver(observer, "mock");
2263b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov        // Start user -- this will update state of mUserController
2273b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov        mUserController.startUser(TEST_USER_ID, true);
2283b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov        Message reportMsg = mInjector.handler.getMessageForCode(REPORT_USER_SWITCH_MSG);
2293b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov        assertNotNull(reportMsg);
2303b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov        UserState userState = (UserState) reportMsg.obj;
2313b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov        int oldUserId = reportMsg.arg1;
2323b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov        int newUserId = reportMsg.arg2;
2333b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov        // Call dispatchUserSwitch and verify that observer was called only once
2343b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov        mInjector.handler.clearAllRecordedMessages();
2353b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov        mUserController.dispatchUserSwitch(userState, oldUserId, newUserId);
2363b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov        Mockito.verify(observer, times(1)).onUserSwitching(eq(TEST_USER_ID), any());
2373b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov        // Verify that CONTINUE_USER_SWITCH_MSG is not sent (triggers timeout)
2383b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov        Set<Integer> actualCodes = mInjector.handler.getMessageCodes();
2393b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov        assertTrue("No messages should be sent", actualCodes.isEmpty());
2403b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov    }
2413b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov
2429bc8543d45fc7f2edf857181940d3719e480a597Fyodor Kupolov    @SmallTest
2433b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov    public void testContinueUserSwitch() throws RemoteException {
2443b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov        // Start user -- this will update state of mUserController
2453b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov        mUserController.startUser(TEST_USER_ID, true);
2463b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov        Message reportMsg = mInjector.handler.getMessageForCode(REPORT_USER_SWITCH_MSG);
2473b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov        assertNotNull(reportMsg);
2483b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov        UserState userState = (UserState) reportMsg.obj;
2493b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov        int oldUserId = reportMsg.arg1;
2503b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov        int newUserId = reportMsg.arg2;
2513b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov        mInjector.handler.clearAllRecordedMessages();
2523b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov        // Verify that continueUserSwitch worked as expected
2533b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov        mUserController.continueUserSwitch(userState, oldUserId, newUserId);
2543b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov        Mockito.verify(mInjector.getWindowManager(), times(1)).stopFreezingScreen();
2553e0c25bf099e2942ee98b908ee01f82ce5e0bc82Evan Rosky        continueUserSwitchAssertions();
2563e0c25bf099e2942ee98b908ee01f82ce5e0bc82Evan Rosky    }
2573e0c25bf099e2942ee98b908ee01f82ce5e0bc82Evan Rosky
2583e0c25bf099e2942ee98b908ee01f82ce5e0bc82Evan Rosky    @SmallTest
2593e0c25bf099e2942ee98b908ee01f82ce5e0bc82Evan Rosky    public void testContinueUserSwitchUIDisabled() throws RemoteException {
2603e0c25bf099e2942ee98b908ee01f82ce5e0bc82Evan Rosky        mUserController.mUserSwitchUiEnabled = false;
2613e0c25bf099e2942ee98b908ee01f82ce5e0bc82Evan Rosky        // Start user -- this will update state of mUserController
2623e0c25bf099e2942ee98b908ee01f82ce5e0bc82Evan Rosky        mUserController.startUser(TEST_USER_ID, true);
2633e0c25bf099e2942ee98b908ee01f82ce5e0bc82Evan Rosky        Message reportMsg = mInjector.handler.getMessageForCode(REPORT_USER_SWITCH_MSG);
2643e0c25bf099e2942ee98b908ee01f82ce5e0bc82Evan Rosky        assertNotNull(reportMsg);
2653e0c25bf099e2942ee98b908ee01f82ce5e0bc82Evan Rosky        UserState userState = (UserState) reportMsg.obj;
2663e0c25bf099e2942ee98b908ee01f82ce5e0bc82Evan Rosky        int oldUserId = reportMsg.arg1;
2673e0c25bf099e2942ee98b908ee01f82ce5e0bc82Evan Rosky        int newUserId = reportMsg.arg2;
2683e0c25bf099e2942ee98b908ee01f82ce5e0bc82Evan Rosky        mInjector.handler.clearAllRecordedMessages();
2693e0c25bf099e2942ee98b908ee01f82ce5e0bc82Evan Rosky        // Verify that continueUserSwitch worked as expected
2703e0c25bf099e2942ee98b908ee01f82ce5e0bc82Evan Rosky        mUserController.continueUserSwitch(userState, oldUserId, newUserId);
2713e0c25bf099e2942ee98b908ee01f82ce5e0bc82Evan Rosky        Mockito.verify(mInjector.getWindowManager(), never()).stopFreezingScreen();
2723e0c25bf099e2942ee98b908ee01f82ce5e0bc82Evan Rosky        continueUserSwitchAssertions();
2733e0c25bf099e2942ee98b908ee01f82ce5e0bc82Evan Rosky    }
2743e0c25bf099e2942ee98b908ee01f82ce5e0bc82Evan Rosky
2753e0c25bf099e2942ee98b908ee01f82ce5e0bc82Evan Rosky    private void continueUserSwitchAssertions() throws RemoteException {
2763b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov        Set<Integer> expectedCodes = Collections.singleton(REPORT_USER_SWITCH_COMPLETE_MSG);
2773b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov        Set<Integer> actualCodes = mInjector.handler.getMessageCodes();
2783b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov        assertEquals("Unexpected message sent", expectedCodes, actualCodes);
2793b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov        Message msg = mInjector.handler.getMessageForCode(REPORT_USER_SWITCH_COMPLETE_MSG);
2803b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov        assertNotNull(msg);
2813b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov        assertEquals("Unexpected userId", TEST_USER_ID, msg.arg1);
282d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov    }
283d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov
2843e0c25bf099e2942ee98b908ee01f82ce5e0bc82Evan Rosky    @SmallTest
2853e0c25bf099e2942ee98b908ee01f82ce5e0bc82Evan Rosky    public void testDispatchUserSwitchComplete() throws RemoteException {
2863e0c25bf099e2942ee98b908ee01f82ce5e0bc82Evan Rosky        // Prepare mock observer and register it
2873e0c25bf099e2942ee98b908ee01f82ce5e0bc82Evan Rosky        IUserSwitchObserver observer = mock(IUserSwitchObserver.class);
2883e0c25bf099e2942ee98b908ee01f82ce5e0bc82Evan Rosky        when(observer.asBinder()).thenReturn(new Binder());
2893e0c25bf099e2942ee98b908ee01f82ce5e0bc82Evan Rosky        mUserController.registerUserSwitchObserver(observer, "mock");
2903e0c25bf099e2942ee98b908ee01f82ce5e0bc82Evan Rosky        // Start user -- this will update state of mUserController
2913e0c25bf099e2942ee98b908ee01f82ce5e0bc82Evan Rosky        mUserController.startUser(TEST_USER_ID, true);
2923e0c25bf099e2942ee98b908ee01f82ce5e0bc82Evan Rosky        Message reportMsg = mInjector.handler.getMessageForCode(REPORT_USER_SWITCH_MSG);
2933e0c25bf099e2942ee98b908ee01f82ce5e0bc82Evan Rosky        assertNotNull(reportMsg);
2943e0c25bf099e2942ee98b908ee01f82ce5e0bc82Evan Rosky        int newUserId = reportMsg.arg2;
2953e0c25bf099e2942ee98b908ee01f82ce5e0bc82Evan Rosky        mInjector.handler.clearAllRecordedMessages();
2963e0c25bf099e2942ee98b908ee01f82ce5e0bc82Evan Rosky        // Mockito can't reset only interactions, so just verify that this hasn't been
2973e0c25bf099e2942ee98b908ee01f82ce5e0bc82Evan Rosky        // called with 'false' until after dispatchUserSwitchComplete.
2983e0c25bf099e2942ee98b908ee01f82ce5e0bc82Evan Rosky        Mockito.verify(mInjector.getWindowManager(), never()).setSwitchingUser(false);
2993e0c25bf099e2942ee98b908ee01f82ce5e0bc82Evan Rosky        // Call dispatchUserSwitchComplete
3003e0c25bf099e2942ee98b908ee01f82ce5e0bc82Evan Rosky        mUserController.dispatchUserSwitchComplete(newUserId);
3013e0c25bf099e2942ee98b908ee01f82ce5e0bc82Evan Rosky        Mockito.verify(observer, times(1)).onUserSwitchComplete(anyInt());
3023e0c25bf099e2942ee98b908ee01f82ce5e0bc82Evan Rosky        Mockito.verify(observer).onUserSwitchComplete(TEST_USER_ID);
3033e0c25bf099e2942ee98b908ee01f82ce5e0bc82Evan Rosky        Mockito.verify(mInjector.getWindowManager(), times(1)).setSwitchingUser(false);
3043e0c25bf099e2942ee98b908ee01f82ce5e0bc82Evan Rosky    }
3053e0c25bf099e2942ee98b908ee01f82ce5e0bc82Evan Rosky
306d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov    private void setUpUser(int userId, int flags) {
307d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov        UserInfo userInfo = new UserInfo(userId, "User" + userId, flags);
308d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov        when(mInjector.userManagerMock.getUserInfo(eq(userId))).thenReturn(userInfo);
309d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov    }
310d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov
311d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov    private static List<String> getActions(List<Intent> intents) {
312d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov        List<String> result = new ArrayList<>();
313d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov        for (Intent intent : intents) {
314d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov            result.add(intent.getAction());
315d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov        }
316d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov        return result;
317d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov    }
318d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov
319d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov    private static class TestInjector extends UserController.Injector {
320d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov        final Object lock = new Object();
3213b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov        TestHandler handler;
322d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov        HandlerThread handlerThread;
323d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov        UserManagerService userManagerMock;
324d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov        UserManagerInternal userManagerInternalMock;
325d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov        WindowManagerService windowManagerMock;
3265c2cf03f5f8e26f715931370004d21ee217edcdeTony Mak        ActivityStackSupervisor activityStackSupervisor;
327d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov        private Context mCtx;
328d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov        List<Intent> sentIntents = new ArrayList<>();
329d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov
330d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov        TestInjector(Context ctx) {
331d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov            super(null);
332d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov            mCtx = ctx;
333d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov            handlerThread = new HandlerThread(TAG);
334d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov            handlerThread.start();
3353b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov            handler = new TestHandler(handlerThread.getLooper());
336d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov            userManagerMock = mock(UserManagerService.class);
337d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov            userManagerInternalMock = mock(UserManagerInternal.class);
338d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov            windowManagerMock = mock(WindowManagerService.class);
3395c2cf03f5f8e26f715931370004d21ee217edcdeTony Mak            activityStackSupervisor = mock(ActivityStackSupervisor.class);
340d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov        }
341d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov
342d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov        @Override
343d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov        protected Object getLock() {
344d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov            return lock;
345d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov        }
346d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov
347d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov        @Override
348d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov        protected Handler getHandler() {
349d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov            return handler;
350d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov        }
351d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov
352d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov        @Override
353d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov        protected UserManagerService getUserManager() {
354d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov            return userManagerMock;
355d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov        }
356d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov
357d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov        @Override
358d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov        UserManagerInternal getUserManagerInternal() {
359d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov            return userManagerInternalMock;
360d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov        }
361d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov
362d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov        @Override
363d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov        protected Context getContext() {
364d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov            return mCtx;
365d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov        }
366d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov
367d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov        @Override
368d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov        int checkCallingPermission(String permission) {
369d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov            Log.i(TAG, "checkCallingPermission " + permission);
370d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov            return PERMISSION_GRANTED;
371d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov        }
372d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov
373d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov        @Override
374d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov        WindowManagerService getWindowManager() {
375d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov            return windowManagerMock;
376d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov        }
377d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov
378d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov        @Override
379d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov        void updateUserConfigurationLocked() {
380d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov            Log.i(TAG, "updateUserConfigurationLocked");
381d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov        }
382d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov
383d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov        @Override
384d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov        protected int broadcastIntentLocked(Intent intent, String resolvedType,
385d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov                IIntentReceiver resultTo, int resultCode, String resultData, Bundle resultExtras,
386d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov                String[] requiredPermissions, int appOp, Bundle bOptions, boolean ordered,
387d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov                boolean sticky, int callingPid, int callingUid, int userId) {
388d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov            Log.i(TAG, "broadcastIntentLocked " + intent);
389d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov            sentIntents.add(intent);
390d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov            return 0;
391d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov        }
392d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov
393d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov        @Override
3945c2cf03f5f8e26f715931370004d21ee217edcdeTony Mak        void startHomeActivityLocked(int userId, String reason) {
3955c2cf03f5f8e26f715931370004d21ee217edcdeTony Mak            Log.i(TAG, "startHomeActivityLocked " + userId);
396d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov        }
397d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov
398d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov        @Override
3995c2cf03f5f8e26f715931370004d21ee217edcdeTony Mak        ActivityStackSupervisor getActivityStackSupervisor() {
4005c2cf03f5f8e26f715931370004d21ee217edcdeTony Mak            return activityStackSupervisor;
401d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov        }
4025c2cf03f5f8e26f715931370004d21ee217edcdeTony Mak    }
4033b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov
4043b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov    private static class TestHandler extends Handler {
4053b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov        private final List<Message> mMessages = new ArrayList<>();
4063b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov
4073b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov        TestHandler(Looper looper) {
4083b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov            super(looper);
4093b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov        }
4103b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov
4113b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov        Set<Integer> getMessageCodes() {
4123b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov            Set<Integer> result = new LinkedHashSet<>();
4133b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov            for (Message msg : mMessages) {
4143b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov                result.add(msg.what);
4153b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov            }
4163b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov            return result;
4173b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov        }
4183b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov
4193b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov        Message getMessageForCode(int what) {
4203b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov            for (Message msg : mMessages) {
4213b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov                if (msg.what == what) {
4223b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov                    return msg;
4233b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov                }
4243b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov            }
4253b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov            return null;
4263b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov        }
4273b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov
4283b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov        void clearAllRecordedMessages() {
4293b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov            mMessages.clear();
4303b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov        }
4313b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov
4323b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov        @Override
4333b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov        public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
4343b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov            Message copy = new Message();
4353b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov            copy.copyFrom(msg);
4363b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov            mMessages.add(copy);
4373b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov            return super.sendMessageAtTime(msg, uptimeMillis);
4383b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov        }
4393b24e5b9d06be5740383e132c02929ff9bfe8715Fyodor Kupolov    }
440d6038db83d06524daa4f411081fbe48e595e7a2cFyodor Kupolov}