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