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 17package com.android.server.am; 18 19import static android.app.ActivityManager.START_DELIVERED_TO_TOP; 20import static android.app.ActivityManager.START_TASK_TO_FRONT; 21import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; 22import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; 23import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY; 24import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; 25import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; 26import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE; 27import static android.content.pm.ActivityInfo.FLAG_SHOW_WHEN_LOCKED; 28 29import static com.android.server.am.ActivityStack.REMOVE_TASK_MODE_DESTROYING; 30import static com.android.server.am.ActivityStackSupervisor 31 .MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE; 32 33import static org.junit.Assert.assertEquals; 34import static org.junit.Assert.assertFalse; 35import static org.junit.Assert.assertNull; 36import static org.junit.Assert.assertTrue; 37import static org.mockito.ArgumentMatchers.any; 38import static org.mockito.Matchers.anyInt; 39import static org.mockito.Mockito.doAnswer; 40import static org.mockito.Mockito.doReturn; 41import static org.mockito.Mockito.mock; 42import static org.mockito.Mockito.reset; 43import static org.mockito.Mockito.times; 44import static org.mockito.Mockito.verify; 45 46import android.app.ActivityOptions; 47import android.app.WaitResult; 48import android.graphics.Rect; 49import android.platform.test.annotations.Presubmit; 50import android.support.test.filters.MediumTest; 51import android.support.test.runner.AndroidJUnit4; 52import android.util.SparseIntArray; 53 54import org.junit.Before; 55import org.junit.Test; 56import org.junit.runner.RunWith; 57import org.mockito.invocation.InvocationOnMock; 58 59import 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) 70public class ActivityStackSupervisorTests extends ActivityTestsBase { 71 private ActivityManagerService mService; 72 private ActivityStackSupervisor mSupervisor; 73 private ActivityStack mFullscreenStack; 74 75 @Before 76 @Override 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 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 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 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 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 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 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 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 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 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 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 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 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