1 /*
2  * Copyright (C) 2017 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.systemui.keyguard;
18 
19 import static org.mockito.Matchers.any;
20 import static org.mockito.Matchers.anyInt;
21 import static org.mockito.Matchers.argThat;
22 import static org.mockito.Mockito.doReturn;
23 import static org.mockito.Mockito.eq;
24 import static org.mockito.Mockito.never;
25 import static org.mockito.Mockito.verify;
26 import static org.mockito.Mockito.when;
27 
28 import android.app.ActivityManager;
29 import android.app.ActivityOptions;
30 import android.app.IActivityTaskManager;
31 import android.app.IApplicationThread;
32 import android.app.ProfilerInfo;
33 import android.content.Context;
34 import android.content.Intent;
35 import android.os.Bundle;
36 import android.os.IBinder;
37 
38 import androidx.test.filters.SmallTest;
39 import androidx.test.runner.AndroidJUnit4;
40 
41 import com.android.systemui.SysuiTestCase;
42 import com.android.systemui.settings.UserTracker;
43 import com.android.systemui.shared.system.TaskStackChangeListener;
44 import com.android.systemui.shared.system.TaskStackChangeListeners;
45 
46 import org.junit.Before;
47 import org.junit.Test;
48 import org.junit.runner.RunWith;
49 import org.mockito.ArgumentCaptor;
50 import org.mockito.ArgumentMatcher;
51 import org.mockito.Mock;
52 import org.mockito.MockitoAnnotations;
53 
54 /**
55  * runtest systemui -c com.android.systemui.keyguard.WorkLockActivityControllerTest
56  */
57 @SmallTest
58 @RunWith(AndroidJUnit4.class)
59 public class WorkLockActivityControllerTest extends SysuiTestCase {
60     private static final int TASK_USER_ID = 333;
61     private static final int PROFILE_USER_ID = 555;
62     private static final int TASK_ID = 444;
63     private static final ActivityManager.RunningTaskInfo TASK_INFO =
64             new ActivityManager.RunningTaskInfo();
65 
66     static {
67         TASK_INFO.userId = TASK_USER_ID;
68         TASK_INFO.taskId = TASK_ID;
69     }
70 
71     private @Mock Context mContext;
72     private @Mock TaskStackChangeListeners mTaskStackChangeListeners;
73     private @Mock IActivityTaskManager mIActivityTaskManager;
74     private @Mock UserTracker mUserTracker;
75 
76     private WorkLockActivityController mController;
77     private TaskStackChangeListener mTaskStackListener;
78 
79     @Before
setUp()80     public void setUp() throws Exception {
81         MockitoAnnotations.initMocks(this);
82 
83         // Set a package name to use for checking ComponentName well-formedness in tests.
84         doReturn("com.example.test").when(mContext).getPackageName();
85         when(mUserTracker.getUserId()).thenReturn(ActivityManager.getCurrentUser());
86 
87         // Construct controller. Save the TaskStackListener for injecting events.
88         final ArgumentCaptor<TaskStackChangeListener> listenerCaptor =
89                 ArgumentCaptor.forClass(TaskStackChangeListener.class);
90         mController = new WorkLockActivityController(mContext, mUserTracker,
91                 mTaskStackChangeListeners, mIActivityTaskManager);
92 
93         verify(mTaskStackChangeListeners).registerTaskStackListener(listenerCaptor.capture());
94         mTaskStackListener = listenerCaptor.getValue();
95     }
96 
97     @Test
testOverlayStartedWhenLocked()98     public void testOverlayStartedWhenLocked() throws Exception {
99         // When starting an activity succeeds,
100         setActivityStartCode(TASK_ID, true /*taskOverlay*/, ActivityManager.START_SUCCESS);
101 
102         // And the controller receives a message saying the profile is locked,
103         mTaskStackListener.onTaskProfileLocked(TASK_INFO, PROFILE_USER_ID);
104 
105         // The overlay should start and the task the activity started in should not be removed.
106         verifyStartActivity(TASK_ID, true /*taskOverlay*/, PROFILE_USER_ID);
107         verify(mIActivityTaskManager, never()).removeTask(anyInt() /*taskId*/);
108     }
109 
110     @Test
testRemoveTaskOnFailureToStartOverlay()111     public void testRemoveTaskOnFailureToStartOverlay() throws Exception {
112         // When starting an activity fails,
113         setActivityStartCode(TASK_ID, true /*taskOverlay*/, ActivityManager.START_CLASS_NOT_FOUND);
114 
115         // And the controller receives a message saying the profile is locked,
116         mTaskStackListener.onTaskProfileLocked(TASK_INFO, PROFILE_USER_ID);
117 
118         // The task the activity started in should be removed to prevent the locked task from
119         // being shown.
120         verifyStartActivity(TASK_ID, true /*taskOverlay*/, PROFILE_USER_ID);
121         verify(mIActivityTaskManager).removeTask(TASK_ID);
122     }
123 
124     // End of tests, start of helpers
125     // ------------------------------
126 
setActivityStartCode(int taskId, boolean taskOverlay, int code)127     private void setActivityStartCode(int taskId, boolean taskOverlay, int code) throws Exception {
128         doReturn(code).when(mIActivityTaskManager).startActivityAsUser(
129                 eq((IApplicationThread) null),
130                 eq((String) null),
131                 eq((String) null),
132                 any(Intent.class),
133                 eq((String) null),
134                 eq((IBinder) null),
135                 eq((String) null),
136                 anyInt(),
137                 anyInt(),
138                 eq((ProfilerInfo) null),
139                 argThat(hasOptions(taskId, taskOverlay)),
140                 eq(ActivityManager.getCurrentUser()));
141     }
142 
verifyStartActivity(int taskId, boolean taskOverlay, int profileUserId)143     private void verifyStartActivity(int taskId, boolean taskOverlay, int profileUserId)
144             throws Exception {
145         verify(mIActivityTaskManager).startActivityAsUser(
146                 eq((IApplicationThread) null),
147                 eq((String) null),
148                 eq((String) null),
149                 argThat(hasUserId(profileUserId)),
150                 eq((String) null),
151                 eq((IBinder) null),
152                 eq((String) null),
153                 anyInt(),
154                 anyInt(),
155                 eq((ProfilerInfo) null),
156                 argThat(hasOptions(taskId, taskOverlay)),
157                 eq(ActivityManager.getCurrentUser()));
158     }
159 
hasUserId(int userId)160     private static ArgumentMatcher<Intent> hasUserId(int userId) {
161         return intent -> intent.getIntExtra(Intent.EXTRA_USER_ID, -1) == userId;
162     }
163 
hasOptions(final int taskId, final boolean overlay)164     private static ArgumentMatcher<Bundle> hasOptions(final int taskId, final boolean overlay) {
165         return item -> {
166             final ActivityOptions options = ActivityOptions.fromBundle(item);
167             return (options.getLaunchTaskId() == taskId)
168                     && (options.getTaskOverlay() == overlay);
169         };
170     }
171 }
172