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