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.server.am;
18 
19 import static android.app.ActivityManager.START_DELIVERED_TO_TOP;
20 import static android.app.ActivityManager.START_TASK_TO_FRONT;
21 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
22 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
23 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY;
24 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
25 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
26 import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE;
27 import static android.content.pm.ActivityInfo.FLAG_SHOW_WHEN_LOCKED;
28 
29 import static com.android.server.am.ActivityStack.REMOVE_TASK_MODE_DESTROYING;
30 import static com.android.server.am.ActivityStackSupervisor
31         .MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE;
32 
33 import static org.junit.Assert.assertEquals;
34 import static org.junit.Assert.assertFalse;
35 import static org.junit.Assert.assertNull;
36 import static org.junit.Assert.assertTrue;
37 import static org.mockito.ArgumentMatchers.any;
38 import static org.mockito.Matchers.anyInt;
39 import static org.mockito.Mockito.doAnswer;
40 import static org.mockito.Mockito.doReturn;
41 import static org.mockito.Mockito.mock;
42 import static org.mockito.Mockito.reset;
43 import static org.mockito.Mockito.times;
44 import static org.mockito.Mockito.verify;
45 
46 import android.app.ActivityOptions;
47 import android.app.WaitResult;
48 import android.graphics.Rect;
49 import android.platform.test.annotations.Presubmit;
50 import android.support.test.filters.MediumTest;
51 import android.support.test.runner.AndroidJUnit4;
52 import android.util.SparseIntArray;
53 
54 import org.junit.Before;
55 import org.junit.Test;
56 import org.junit.runner.RunWith;
57 import org.mockito.invocation.InvocationOnMock;
58 
59 import java.util.ArrayList;
60 
61 /**
62  * Tests for the {@link ActivityStackSupervisor} class.
63  *
64  * Build/Install/Run:
65  *  atest FrameworksServicesTests:com.android.server.am.ActivityStackSupervisorTests
66  */
67 @MediumTest
68 @Presubmit
69 @RunWith(AndroidJUnit4.class)
70 public class ActivityStackSupervisorTests extends ActivityTestsBase {
71     private ActivityManagerService mService;
72     private ActivityStackSupervisor mSupervisor;
73     private ActivityStack mFullscreenStack;
74 
75     @Before
76     @Override
setUp()77     public void setUp() throws Exception {
78         super.setUp();
79 
80         mService = createActivityManagerService();
81         mSupervisor = mService.mStackSupervisor;
82         mFullscreenStack = mService.mStackSupervisor.getDefaultDisplay().createStack(
83                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
84     }
85 
86     /**
87      * This test ensures that we do not try to restore a task based off an invalid task id. The
88      * stack supervisor is a test version so there will be no tasks present. We should expect
89      * {@code null} to be returned in this case.
90      */
91     @Test
testRestoringInvalidTask()92     public void testRestoringInvalidTask() throws Exception {
93         TaskRecord task = mSupervisor.anyTaskForIdLocked(0 /*taskId*/,
94                 MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE, null, false /* onTop */);
95         assertNull(task);
96     }
97 
98     /**
99      * This test ensures that an existing task in the pinned stack is moved to the fullscreen
100      * activity stack when a new task is added.
101      */
102     @Test
testReplacingTaskInPinnedStack()103     public void testReplacingTaskInPinnedStack() throws Exception {
104         final ActivityRecord firstActivity = new ActivityBuilder(mService).setCreateTask(true)
105                 .setStack(mFullscreenStack).build();
106         final TaskRecord firstTask = firstActivity.getTask();
107 
108         final ActivityRecord secondActivity = new ActivityBuilder(mService).setCreateTask(true)
109                 .setStack(mFullscreenStack).build();
110         final TaskRecord secondTask = secondActivity.getTask();
111 
112         mSupervisor.setFocusStackUnchecked("testReplacingTaskInPinnedStack", mFullscreenStack);
113 
114         // Ensure full screen stack has both tasks.
115         ensureStackPlacement(mFullscreenStack, firstTask, secondTask);
116 
117         // Move first activity to pinned stack.
118         final Rect sourceBounds = new Rect();
119         mSupervisor.moveActivityToPinnedStackLocked(firstActivity, sourceBounds,
120                 0f /*aspectRatio*/, "initialMove");
121 
122         final ActivityDisplay display = mFullscreenStack.getDisplay();
123         ActivityStack pinnedStack = display.getPinnedStack();
124         // Ensure a task has moved over.
125         ensureStackPlacement(pinnedStack, firstTask);
126         ensureStackPlacement(mFullscreenStack, secondTask);
127 
128         // Move second activity to pinned stack.
129         mSupervisor.moveActivityToPinnedStackLocked(secondActivity, sourceBounds,
130                 0f /*aspectRatio*/, "secondMove");
131 
132         // Need to get stacks again as a new instance might have been created.
133         pinnedStack = display.getPinnedStack();
134         mFullscreenStack = display.getStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
135         // Ensure stacks have swapped tasks.
136         ensureStackPlacement(pinnedStack, secondTask);
137         ensureStackPlacement(mFullscreenStack, firstTask);
138     }
139 
ensureStackPlacement(ActivityStack stack, TaskRecord... tasks)140     private static void ensureStackPlacement(ActivityStack stack, TaskRecord... tasks) {
141         final ArrayList<TaskRecord> stackTasks = stack.getAllTasks();
142         assertEquals(stackTasks.size(), tasks != null ? tasks.length : 0);
143 
144         if (tasks == null) {
145             return;
146         }
147 
148         for (TaskRecord task : tasks) {
149             assertTrue(stackTasks.contains(task));
150         }
151     }
152 
153     /**
154      * Ensures that an activity is removed from the stopping activities list once it is resumed.
155      */
156     @Test
testStoppingActivityRemovedWhenResumed()157     public void testStoppingActivityRemovedWhenResumed() throws Exception {
158         final ActivityRecord firstActivity = new ActivityBuilder(mService).setCreateTask(true)
159                 .setStack(mFullscreenStack).build();
160         mSupervisor.mStoppingActivities.add(firstActivity);
161 
162         firstActivity.completeResumeLocked();
163 
164         assertFalse(mSupervisor.mStoppingActivities.contains(firstActivity));
165     }
166 
167     /**
168      * Ensures that waiting results are notified of launches.
169      */
170     @Test
testReportWaitingActivityLaunchedIfNeeded()171     public void testReportWaitingActivityLaunchedIfNeeded() throws Exception {
172         final ActivityRecord firstActivity = new ActivityBuilder(mService).setCreateTask(true)
173                 .setStack(mFullscreenStack).build();
174 
175         // #notifyAll will be called on the ActivityManagerService. we must hold the object lock
176         // when this happens.
177         synchronized (mSupervisor.mService) {
178             final WaitResult taskToFrontWait = new WaitResult();
179             mSupervisor.mWaitingActivityLaunched.add(taskToFrontWait);
180             mSupervisor.reportWaitingActivityLaunchedIfNeeded(firstActivity, START_TASK_TO_FRONT);
181 
182             assertTrue(mSupervisor.mWaitingActivityLaunched.isEmpty());
183             assertEquals(taskToFrontWait.result, START_TASK_TO_FRONT);
184             assertEquals(taskToFrontWait.who, null);
185 
186             final WaitResult deliverToTopWait = new WaitResult();
187             mSupervisor.mWaitingActivityLaunched.add(deliverToTopWait);
188             mSupervisor.reportWaitingActivityLaunchedIfNeeded(firstActivity,
189                     START_DELIVERED_TO_TOP);
190 
191             assertTrue(mSupervisor.mWaitingActivityLaunched.isEmpty());
192             assertEquals(deliverToTopWait.result, START_DELIVERED_TO_TOP);
193             assertEquals(deliverToTopWait.who, firstActivity.realActivity);
194         }
195     }
196 
197     @Test
testApplySleepTokensLocked()198     public void testApplySleepTokensLocked() throws Exception {
199         final ActivityDisplay display = mSupervisor.getDefaultDisplay();
200         final KeyguardController keyguard = mSupervisor.getKeyguardController();
201         final ActivityStack stack = mock(ActivityStack.class);
202         display.addChild(stack, 0 /* position */);
203 
204         // Make sure we wake and resume in the case the display is turning on and the keyguard is
205         // not showing.
206         verifySleepTokenBehavior(display, keyguard, stack, true /*displaySleeping*/,
207                 false /* displayShouldSleep */, true /* isFocusedStack */,
208                 false /* keyguardShowing */, true /* expectWakeFromSleep */,
209                 true /* expectResumeTopActivity */);
210 
211         // Make sure we wake and don't resume when the display is turning on and the keyguard is
212         // showing.
213         verifySleepTokenBehavior(display, keyguard, stack, true /*displaySleeping*/,
214                 false /* displayShouldSleep */, true /* isFocusedStack */,
215                 true /* keyguardShowing */, true /* expectWakeFromSleep */,
216                 false /* expectResumeTopActivity */);
217 
218         // Make sure we wake and don't resume when the display is turning on and the keyguard is
219         // not showing as unfocused.
220         verifySleepTokenBehavior(display, keyguard, stack, true /*displaySleeping*/,
221                 false /* displayShouldSleep */, false /* isFocusedStack */,
222                 false /* keyguardShowing */, true /* expectWakeFromSleep */,
223                 false /* expectResumeTopActivity */);
224 
225         // Should not do anything if the display state hasn't changed.
226         verifySleepTokenBehavior(display, keyguard, stack, false /*displaySleeping*/,
227                 false /* displayShouldSleep */, true /* isFocusedStack */,
228                 false /* keyguardShowing */, false /* expectWakeFromSleep */,
229                 false /* expectResumeTopActivity */);
230     }
231 
verifySleepTokenBehavior(ActivityDisplay display, KeyguardController keyguard, ActivityStack stack, boolean displaySleeping, boolean displayShouldSleep, boolean isFocusedStack, boolean keyguardShowing, boolean expectWakeFromSleep, boolean expectResumeTopActivity)232     private void verifySleepTokenBehavior(ActivityDisplay display, KeyguardController keyguard,
233             ActivityStack stack, boolean displaySleeping, boolean displayShouldSleep,
234             boolean isFocusedStack, boolean keyguardShowing, boolean expectWakeFromSleep,
235             boolean expectResumeTopActivity) {
236         reset(stack);
237 
238         doReturn(displayShouldSleep).when(display).shouldSleep();
239         doReturn(displaySleeping).when(display).isSleeping();
240         doReturn(keyguardShowing).when(keyguard).isKeyguardOrAodShowing(anyInt());
241 
242         mSupervisor.mFocusedStack = isFocusedStack ? stack : null;
243         mSupervisor.applySleepTokensLocked(true);
244         verify(stack, times(expectWakeFromSleep ? 1 : 0)).awakeFromSleepingLocked();
245         verify(stack, times(expectResumeTopActivity ? 1 : 0)).resumeTopActivityUncheckedLocked(
246                 null /* target */, null /* targetOptions */);
247     }
248 
249     @Test
testTopRunningActivityLockedWithNonExistentDisplay()250     public void testTopRunningActivityLockedWithNonExistentDisplay() throws Exception {
251         // Create display that ActivityManagerService does not know about
252         final int unknownDisplayId = 100;
253 
254         doAnswer((InvocationOnMock invocationOnMock) -> {
255             final SparseIntArray displayIds = invocationOnMock.<SparseIntArray>getArgument(0);
256             displayIds.put(0, unknownDisplayId);
257             return null;
258         }).when(mSupervisor.mWindowManager).getDisplaysInFocusOrder(any());
259 
260         mSupervisor.mFocusedStack = mock(ActivityStack.class);
261 
262         // Supervisor should skip over the non-existent display.
263         assertEquals(null, mSupervisor.topRunningActivityLocked());
264     }
265 
266     /**
267      * Verifies that removal of activity with task and stack is done correctly.
268      */
269     @Test
testRemovingStackOnAppCrash()270     public void testRemovingStackOnAppCrash() throws Exception {
271         final ActivityDisplay defaultDisplay = mService.mStackSupervisor.getDefaultDisplay();
272         final int originalStackCount = defaultDisplay.getChildCount();
273         final ActivityStack stack = mService.mStackSupervisor.getDefaultDisplay().createStack(
274                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */);
275         final ActivityRecord firstActivity = new ActivityBuilder(mService).setCreateTask(true)
276                 .setStack(stack).build();
277 
278         assertEquals(originalStackCount + 1, defaultDisplay.getChildCount());
279 
280         // Let's pretend that the app has crashed.
281         firstActivity.app.thread = null;
282         mService.mStackSupervisor.finishTopCrashedActivitiesLocked(firstActivity.app, "test");
283 
284         // Verify that the stack was removed.
285         assertEquals(originalStackCount, defaultDisplay.getChildCount());
286     }
287 
288     @Test
testFocusability()289     public void testFocusability() throws Exception {
290         final ActivityStack stack = mService.mStackSupervisor.getDefaultDisplay().createStack(
291                 WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD, true /* onTop */);
292         final ActivityRecord activity = new ActivityBuilder(mService).setCreateTask(true)
293                 .setStack(stack).build();
294 
295         // Under split screen primary we should be focusable when not minimized
296         mService.mStackSupervisor.setDockedStackMinimized(false);
297         assertTrue(stack.isFocusable());
298         assertTrue(activity.isFocusable());
299 
300         // Under split screen primary we should not be focusable when minimized
301         mService.mStackSupervisor.setDockedStackMinimized(true);
302         assertFalse(stack.isFocusable());
303         assertFalse(activity.isFocusable());
304 
305         final ActivityStack pinnedStack = mService.mStackSupervisor.getDefaultDisplay().createStack(
306                 WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, true /* onTop */);
307         final ActivityRecord pinnedActivity = new ActivityBuilder(mService).setCreateTask(true)
308                 .setStack(pinnedStack).build();
309 
310         // We should not be focusable when in pinned mode
311         assertFalse(pinnedStack.isFocusable());
312         assertFalse(pinnedActivity.isFocusable());
313 
314         // Add flag forcing focusability.
315         pinnedActivity.info.flags |= FLAG_ALWAYS_FOCUSABLE;
316 
317         // We should not be focusable when in pinned mode
318         assertTrue(pinnedStack.isFocusable());
319         assertTrue(pinnedActivity.isFocusable());
320 
321         // Without the overridding activity, stack should not be focusable.
322         pinnedStack.removeTask(pinnedActivity.getTask(), "testFocusability",
323                 REMOVE_TASK_MODE_DESTROYING);
324         assertFalse(pinnedStack.isFocusable());
325     }
326 
327     /**
328      * Verifies the correct activity is returned when querying the top running activity.
329      */
330     @Test
testTopRunningActivity()331     public void testTopRunningActivity() throws Exception {
332         // Create stack to hold focus
333         final ActivityStack emptyStack = mService.mStackSupervisor.getDefaultDisplay()
334                 .createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
335 
336         final KeyguardController keyguard = mSupervisor.getKeyguardController();
337         final ActivityStack stack = mService.mStackSupervisor.getDefaultDisplay().createStack(
338                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
339         final ActivityRecord activity = new ActivityBuilder(mService).setCreateTask(true)
340                 .setStack(stack).build();
341 
342         mSupervisor.mFocusedStack = emptyStack;
343 
344         doAnswer((InvocationOnMock invocationOnMock) -> {
345             final SparseIntArray displayIds = invocationOnMock.<SparseIntArray>getArgument(0);
346             displayIds.put(0, mSupervisor.getDefaultDisplay().mDisplayId);
347             return null;
348         }).when(mSupervisor.mWindowManager).getDisplaysInFocusOrder(any());
349 
350         // Make sure the top running activity is not affected when keyguard is not locked
351         assertEquals(activity, mService.mStackSupervisor.topRunningActivityLocked());
352         assertEquals(activity, mService.mStackSupervisor.topRunningActivityLocked(
353                 true /* considerKeyguardState */));
354 
355         // Check to make sure activity not reported when it cannot show on lock and lock is on.
356         doReturn(true).when(keyguard).isKeyguardLocked();
357         assertEquals(activity, mService.mStackSupervisor.topRunningActivityLocked());
358         assertEquals(null, mService.mStackSupervisor.topRunningActivityLocked(
359                 true /* considerKeyguardState */));
360 
361         // Change focus to stack with activity.
362         mSupervisor.mFocusedStack = stack;
363         assertEquals(activity, mService.mStackSupervisor.topRunningActivityLocked());
364         assertEquals(null, mService.mStackSupervisor.topRunningActivityLocked(
365                 true /* considerKeyguardState */));
366 
367         // Add activity that should be shown on the keyguard.
368         final ActivityRecord showWhenLockedActivity = new ActivityBuilder(mService)
369                 .setCreateTask(true)
370                 .setStack(stack)
371                 .setActivityFlags(FLAG_SHOW_WHEN_LOCKED)
372                 .build();
373 
374         // Ensure the show when locked activity is returned.
375         assertEquals(showWhenLockedActivity, mService.mStackSupervisor.topRunningActivityLocked());
376         assertEquals(showWhenLockedActivity, mService.mStackSupervisor.topRunningActivityLocked(
377                 true /* considerKeyguardState */));
378 
379         // Change focus back to empty stack
380         mSupervisor.mFocusedStack = emptyStack;
381         // Ensure the show when locked activity is returned when not the focused stack
382         assertEquals(showWhenLockedActivity, mService.mStackSupervisor.topRunningActivityLocked());
383         assertEquals(showWhenLockedActivity, mService.mStackSupervisor.topRunningActivityLocked(
384                 true /* considerKeyguardState */));
385     }
386 
387     /**
388      * Verify that split-screen primary stack will be chosen if activity is launched that targets
389      * split-screen secondary, but a matching existing instance is found on top of split-screen
390      * primary stack.
391      */
392     @Test
testSplitScreenPrimaryChosenWhenTopActivityLaunchedToSecondary()393     public void testSplitScreenPrimaryChosenWhenTopActivityLaunchedToSecondary() throws Exception {
394         // Create primary split-screen stack with a task and an activity.
395         final ActivityStack primaryStack = mService.mStackSupervisor.getDefaultDisplay()
396                 .createStack(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, ACTIVITY_TYPE_STANDARD,
397                         true /* onTop */);
398         final TaskRecord task = new TaskBuilder(mSupervisor).setStack(primaryStack).build();
399         final ActivityRecord r = new ActivityBuilder(mService).setTask(task).build();
400 
401         // Find a launch stack for the top activity in split-screen primary, while requesting
402         // split-screen secondary.
403         final ActivityOptions options = ActivityOptions.makeBasic();
404         options.setLaunchWindowingMode(WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY);
405         final ActivityStack result = mSupervisor.getLaunchStack(r, options, task, true /* onTop */);
406 
407         // Assert that the primary stack is returned.
408         assertEquals(primaryStack, result);
409     }
410 }
411