1 /* 2 * Copyright (C) 2018 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.wm; 18 19 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; 20 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; 21 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY; 22 import static android.content.pm.ActivityInfo.CONFIG_ORIENTATION; 23 import static android.content.pm.ActivityInfo.CONFIG_SCREEN_LAYOUT; 24 import static android.content.pm.ActivityInfo.FLAG_SUPPORTS_PICTURE_IN_PICTURE; 25 import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_ALWAYS; 26 import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_DEFAULT; 27 import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_IF_ALLOWLISTED; 28 import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_NEVER; 29 import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE; 30 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND; 31 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; 32 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; 33 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE; 34 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET; 35 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; 36 import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; 37 import static android.content.res.Configuration.ORIENTATION_PORTRAIT; 38 import static android.os.Process.NOBODY_UID; 39 import static android.view.Display.DEFAULT_DISPLAY; 40 import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW; 41 import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW; 42 import static android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD; 43 import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED; 44 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; 45 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; 46 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; 47 import static android.view.WindowManager.TRANSIT_CLOSE; 48 import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_OPEN; 49 import static android.window.StartingWindowInfo.TYPE_PARAMETER_LEGACY_SPLASH_SCREEN; 50 51 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; 52 53 import static com.android.dx.mockito.inline.extended.ExtendedMockito.any; 54 import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyBoolean; 55 import static com.android.dx.mockito.inline.extended.ExtendedMockito.atLeast; 56 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer; 57 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doCallRealMethod; 58 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing; 59 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; 60 import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq; 61 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; 62 import static com.android.dx.mockito.inline.extended.ExtendedMockito.reset; 63 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; 64 import static com.android.dx.mockito.inline.extended.ExtendedMockito.times; 65 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; 66 import static com.android.server.wm.ActivityRecord.FINISH_RESULT_CANCELLED; 67 import static com.android.server.wm.ActivityRecord.FINISH_RESULT_REMOVED; 68 import static com.android.server.wm.ActivityRecord.FINISH_RESULT_REQUESTED; 69 import static com.android.server.wm.Task.ActivityState.DESTROYED; 70 import static com.android.server.wm.Task.ActivityState.DESTROYING; 71 import static com.android.server.wm.Task.ActivityState.FINISHING; 72 import static com.android.server.wm.Task.ActivityState.INITIALIZING; 73 import static com.android.server.wm.Task.ActivityState.PAUSED; 74 import static com.android.server.wm.Task.ActivityState.PAUSING; 75 import static com.android.server.wm.Task.ActivityState.RESUMED; 76 import static com.android.server.wm.Task.ActivityState.STARTED; 77 import static com.android.server.wm.Task.ActivityState.STOPPED; 78 import static com.android.server.wm.Task.ActivityState.STOPPING; 79 import static com.android.server.wm.Task.TASK_VISIBILITY_INVISIBLE; 80 import static com.android.server.wm.Task.TASK_VISIBILITY_VISIBLE; 81 import static com.android.server.wm.Task.TASK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT; 82 import static com.android.server.wm.WindowContainer.POSITION_TOP; 83 import static com.android.server.wm.WindowStateAnimator.ROOT_TASK_CLIP_AFTER_ANIM; 84 import static com.android.server.wm.WindowStateAnimator.ROOT_TASK_CLIP_BEFORE_ANIM; 85 import static com.android.server.wm.WindowStateAnimator.ROOT_TASK_CLIP_NONE; 86 87 import static com.google.common.truth.Truth.assertThat; 88 89 import static org.junit.Assert.assertEquals; 90 import static org.junit.Assert.assertFalse; 91 import static org.junit.Assert.assertNotEquals; 92 import static org.junit.Assert.assertNotNull; 93 import static org.junit.Assert.assertNull; 94 import static org.junit.Assert.assertTrue; 95 import static org.mockito.ArgumentMatchers.anyInt; 96 import static org.mockito.ArgumentMatchers.anyString; 97 import static org.mockito.ArgumentMatchers.isA; 98 import static org.mockito.Mockito.clearInvocations; 99 import static org.mockito.Mockito.never; 100 101 import android.app.ActivityOptions; 102 import android.app.WindowConfiguration; 103 import android.app.servertransaction.ActivityConfigurationChangeItem; 104 import android.app.servertransaction.ClientTransaction; 105 import android.app.servertransaction.DestroyActivityItem; 106 import android.app.servertransaction.PauseActivityItem; 107 import android.content.ComponentName; 108 import android.content.Intent; 109 import android.content.pm.ActivityInfo; 110 import android.content.pm.ApplicationInfo; 111 import android.content.res.Configuration; 112 import android.content.res.Resources; 113 import android.graphics.Point; 114 import android.graphics.Rect; 115 import android.os.Build; 116 import android.os.Bundle; 117 import android.os.PersistableBundle; 118 import android.os.Process; 119 import android.os.RemoteException; 120 import android.platform.test.annotations.Presubmit; 121 import android.provider.DeviceConfig; 122 import android.util.MergedConfiguration; 123 import android.util.MutableBoolean; 124 import android.view.DisplayInfo; 125 import android.view.IRemoteAnimationFinishedCallback; 126 import android.view.IRemoteAnimationRunner.Stub; 127 import android.view.IWindowManager; 128 import android.view.IWindowSession; 129 import android.view.RemoteAnimationAdapter; 130 import android.view.RemoteAnimationTarget; 131 import android.view.Surface; 132 import android.view.WindowManager; 133 import android.view.WindowManagerGlobal; 134 import android.window.TaskSnapshot; 135 136 import androidx.test.filters.MediumTest; 137 138 import com.android.internal.R; 139 import com.android.server.wm.Task.ActivityState; 140 141 import org.junit.Assert; 142 import org.junit.Before; 143 import org.junit.Test; 144 import org.junit.runner.RunWith; 145 import org.mockito.invocation.InvocationOnMock; 146 147 import java.util.ArrayList; 148 149 150 /** 151 * Tests for the {@link ActivityRecord} class. 152 * 153 * Build/Install/Run: 154 * atest WmTests:ActivityRecordTests 155 */ 156 @MediumTest 157 @Presubmit 158 @RunWith(WindowTestRunner.class) 159 public class ActivityRecordTests extends WindowTestsBase { 160 161 private final String mPackageName = getInstrumentation().getTargetContext().getPackageName(); 162 163 @Before setUp()164 public void setUp() throws Exception { 165 setBooted(mAtm); 166 } 167 registerTestStartingWindowOrganizer()168 private TestStartingWindowOrganizer registerTestStartingWindowOrganizer() { 169 return new TestStartingWindowOrganizer(mAtm, 170 mSystemServicesTestRule.getPowerManagerWrapper()); 171 } 172 173 @Test testStackCleanupOnClearingTask()174 public void testStackCleanupOnClearingTask() { 175 final ActivityRecord activity = createActivityWith2LevelTask(); 176 final Task task = activity.getTask(); 177 final Task rootTask = activity.getRootTask(); 178 activity.onParentChanged(null /*newParent*/, task); 179 verify(rootTask, times(1)).cleanUpActivityReferences(any()); 180 } 181 182 @Test testStackCleanupOnActivityRemoval()183 public void testStackCleanupOnActivityRemoval() { 184 final ActivityRecord activity = createActivityWith2LevelTask(); 185 final Task task = activity.getTask(); 186 final Task rootTask = activity.getRootTask(); 187 task.removeChild(activity); 188 verify(rootTask, times(1)).cleanUpActivityReferences(any()); 189 } 190 191 @Test testStackCleanupOnTaskRemoval()192 public void testStackCleanupOnTaskRemoval() { 193 final ActivityRecord activity = createActivityWith2LevelTask(); 194 final Task task = activity.getTask(); 195 final Task rootTask = activity.getRootTask(); 196 rootTask.removeChild(task, null /*reason*/); 197 // parentTask should be gone on task removal. 198 assertNull(mAtm.mRootWindowContainer.getRootTask(rootTask.mTaskId)); 199 } 200 201 @Test testRemoveChildWithOverlayActivity()202 public void testRemoveChildWithOverlayActivity() { 203 final ActivityRecord activity = createActivityWithTask(); 204 final Task task = activity.getTask(); 205 final ActivityRecord overlayActivity = new ActivityBuilder(mAtm).setTask(task).build(); 206 overlayActivity.setTaskOverlay(true); 207 final ActivityRecord overlayActivity2 = new ActivityBuilder(mAtm).setTask(task).build(); 208 overlayActivity2.setTaskOverlay(true); 209 210 task.removeChild(overlayActivity2, "test"); 211 verify(mSupervisor, never()).removeTask(any(), anyBoolean(), anyBoolean(), any()); 212 } 213 214 @Test testNoCleanupMovingActivityInSameStack()215 public void testNoCleanupMovingActivityInSameStack() { 216 final ActivityRecord activity = createActivityWith2LevelTask(); 217 final Task rootTask = activity.getRootTask(); 218 final Task newTask = new TaskBuilder(mAtm.mTaskSupervisor).setParentTask(rootTask).build(); 219 activity.reparent(newTask, 0, null /*reason*/); 220 verify(rootTask, times(0)).cleanUpActivityReferences(any()); 221 } 222 223 @Test testPausingWhenVisibleFromStopped()224 public void testPausingWhenVisibleFromStopped() throws Exception { 225 final ActivityRecord activity = createActivityWithTask(); 226 final MutableBoolean pauseFound = new MutableBoolean(false); 227 doAnswer((InvocationOnMock invocationOnMock) -> { 228 final ClientTransaction transaction = invocationOnMock.getArgument(0); 229 if (transaction.getLifecycleStateRequest() instanceof PauseActivityItem) { 230 pauseFound.value = true; 231 } 232 return null; 233 }).when(activity.app.getThread()).scheduleTransaction(any()); 234 235 activity.setState(STOPPED, "testPausingWhenVisibleFromStopped"); 236 237 // The activity is in the focused stack so it should be resumed. 238 activity.makeVisibleIfNeeded(null /* starting */, true /* reportToClient */); 239 assertTrue(activity.isState(RESUMED)); 240 assertFalse(pauseFound.value); 241 242 // Make the activity non focusable 243 activity.setState(STOPPED, "testPausingWhenVisibleFromStopped"); 244 doReturn(false).when(activity).isFocusable(); 245 246 // If the activity is not focusable, it should move to paused. 247 activity.makeVisibleIfNeeded(null /* starting */, true /* reportToClient */); 248 assertTrue(activity.isState(PAUSING)); 249 assertTrue(pauseFound.value); 250 251 // Make sure that the state does not change for current non-stopping states. 252 activity.setState(INITIALIZING, "testPausingWhenVisibleFromStopped"); 253 doReturn(true).when(activity).isFocusable(); 254 255 activity.makeVisibleIfNeeded(null /* starting */, true /* reportToClient */); 256 257 assertTrue(activity.isState(INITIALIZING)); 258 259 // Make sure the state does not change if we are not the current top activity. 260 activity.setState(STOPPED, "testPausingWhenVisibleFromStopped behind"); 261 262 final Task task = activity.getTask(); 263 final ActivityRecord topActivity = new ActivityBuilder(mAtm).setTask(task).build(); 264 task.mTranslucentActivityWaiting = topActivity; 265 activity.makeVisibleIfNeeded(null /* starting */, true /* reportToClient */); 266 assertTrue(activity.isState(STARTED)); 267 268 task.mTranslucentActivityWaiting = null; 269 topActivity.setOccludesParent(false); 270 activity.setState(STOPPED, "testPausingWhenVisibleFromStopped behind non-opaque"); 271 activity.makeVisibleIfNeeded(null /* starting */, true /* reportToClient */); 272 assertTrue(activity.isState(STARTED)); 273 } 274 ensureActivityConfiguration(ActivityRecord activity)275 private void ensureActivityConfiguration(ActivityRecord activity) { 276 activity.ensureActivityConfiguration(0 /* globalChanges */, false /* preserveWindow */); 277 } 278 279 @Test testCanBeLaunchedOnDisplay()280 public void testCanBeLaunchedOnDisplay() { 281 mAtm.mSupportsMultiWindow = true; 282 final ActivityRecord activity = new ActivityBuilder(mAtm).build(); 283 284 // An activity can be launched on default display. 285 assertTrue(activity.canBeLaunchedOnDisplay(DEFAULT_DISPLAY)); 286 // An activity cannot be launched on a non-existent display. 287 assertFalse(activity.canBeLaunchedOnDisplay(Integer.MAX_VALUE)); 288 } 289 290 @Test testsApplyOptionsLocked()291 public void testsApplyOptionsLocked() { 292 final ActivityRecord activity = createActivityWithTask(); 293 ActivityOptions activityOptions = ActivityOptions.makeBasic(); 294 295 // Set and apply options for ActivityRecord. Pending options should be cleared 296 activity.updateOptionsLocked(activityOptions); 297 activity.applyOptionsAnimation(); 298 assertNull(activity.getOptions()); 299 300 // Set options for two ActivityRecords in same Task. Apply one ActivityRecord options. 301 // Pending options should be cleared for both ActivityRecords 302 ActivityRecord activity2 = new ActivityBuilder(mAtm).setTask(activity.getTask()).build(); 303 activity2.updateOptionsLocked(activityOptions); 304 activity.updateOptionsLocked(activityOptions); 305 activity.applyOptionsAnimation(); 306 assertNull(activity.getOptions()); 307 assertNull(activity2.getOptions()); 308 309 // Set options for two ActivityRecords in separate Tasks. Apply one ActivityRecord options. 310 // Pending options should be cleared for only ActivityRecord that was applied 311 activity2 = new ActivityBuilder(mAtm).setCreateTask(true).build(); 312 activity2.updateOptionsLocked(activityOptions); 313 activity.updateOptionsLocked(activityOptions); 314 activity.applyOptionsAnimation(); 315 assertNull(activity.getOptions()); 316 assertNotNull(activity2.getOptions()); 317 } 318 319 @Test testNewOverrideConfigurationIncrementsSeq()320 public void testNewOverrideConfigurationIncrementsSeq() { 321 final ActivityRecord activity = createActivityWithTask(); 322 final Configuration newConfig = new Configuration(); 323 324 final int prevSeq = activity.getMergedOverrideConfiguration().seq; 325 activity.onRequestedOverrideConfigurationChanged(newConfig); 326 assertEquals(prevSeq + 1, activity.getMergedOverrideConfiguration().seq); 327 } 328 329 @Test testNewParentConfigurationIncrementsSeq()330 public void testNewParentConfigurationIncrementsSeq() { 331 final ActivityRecord activity = createActivityWithTask(); 332 final Task task = activity.getTask(); 333 final Configuration newConfig = new Configuration( 334 task.getRequestedOverrideConfiguration()); 335 newConfig.orientation = newConfig.orientation == ORIENTATION_PORTRAIT 336 ? ORIENTATION_LANDSCAPE : ORIENTATION_PORTRAIT; 337 338 final int prevSeq = activity.getMergedOverrideConfiguration().seq; 339 task.onRequestedOverrideConfigurationChanged(newConfig); 340 assertEquals(prevSeq + 1, activity.getMergedOverrideConfiguration().seq); 341 } 342 343 @Test testSetsRelaunchReason_NotDragResizing()344 public void testSetsRelaunchReason_NotDragResizing() { 345 final ActivityRecord activity = createActivityWithTask(); 346 final Task task = activity.getTask(); 347 activity.setState(Task.ActivityState.RESUMED, "Testing"); 348 349 task.onRequestedOverrideConfigurationChanged(task.getConfiguration()); 350 activity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(), 351 activity.getConfiguration())); 352 353 activity.info.configChanges &= ~CONFIG_ORIENTATION; 354 final Configuration newConfig = new Configuration(task.getConfiguration()); 355 newConfig.orientation = newConfig.orientation == ORIENTATION_PORTRAIT 356 ? ORIENTATION_LANDSCAPE 357 : ORIENTATION_PORTRAIT; 358 task.onRequestedOverrideConfigurationChanged(newConfig); 359 360 activity.mRelaunchReason = ActivityTaskManagerService.RELAUNCH_REASON_NONE; 361 362 ensureActivityConfiguration(activity); 363 364 assertEquals(ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE, 365 activity.mRelaunchReason); 366 } 367 368 @Test testSetsRelaunchReason_DragResizing()369 public void testSetsRelaunchReason_DragResizing() { 370 final ActivityRecord activity = createActivityWithTask(); 371 final Task task = activity.getTask(); 372 activity.setState(Task.ActivityState.RESUMED, "Testing"); 373 374 task.onRequestedOverrideConfigurationChanged(task.getConfiguration()); 375 activity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(), 376 activity.getConfiguration())); 377 378 activity.info.configChanges &= ~CONFIG_ORIENTATION; 379 final Configuration newConfig = new Configuration(task.getConfiguration()); 380 newConfig.orientation = newConfig.orientation == ORIENTATION_PORTRAIT 381 ? ORIENTATION_LANDSCAPE 382 : ORIENTATION_PORTRAIT; 383 task.onRequestedOverrideConfigurationChanged(newConfig); 384 385 doReturn(true).when(task).isDragResizing(); 386 387 activity.mRelaunchReason = ActivityTaskManagerService.RELAUNCH_REASON_NONE; 388 389 ensureActivityConfiguration(activity); 390 391 assertEquals(ActivityTaskManagerService.RELAUNCH_REASON_FREE_RESIZE, 392 activity.mRelaunchReason); 393 } 394 395 @Test testRelaunchClearTopWaitingTranslucent()396 public void testRelaunchClearTopWaitingTranslucent() { 397 final ActivityRecord activity = createActivityWithTask(); 398 final Task task = activity.getTask(); 399 activity.setState(Task.ActivityState.RESUMED, "Testing"); 400 401 task.onRequestedOverrideConfigurationChanged(task.getConfiguration()); 402 activity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(), 403 activity.getConfiguration())); 404 405 activity.info.configChanges &= ~CONFIG_ORIENTATION; 406 final Configuration newConfig = new Configuration(task.getConfiguration()); 407 newConfig.orientation = newConfig.orientation == ORIENTATION_PORTRAIT 408 ? ORIENTATION_LANDSCAPE 409 : ORIENTATION_PORTRAIT; 410 task.onRequestedOverrideConfigurationChanged(newConfig); 411 task.mTranslucentActivityWaiting = activity; 412 ensureActivityConfiguration(activity); 413 assertNull(task.mTranslucentActivityWaiting); 414 } 415 416 @Test testSetsRelaunchReason_NonResizeConfigChanges()417 public void testSetsRelaunchReason_NonResizeConfigChanges() { 418 final ActivityRecord activity = createActivityWithTask(); 419 final Task task = activity.getTask(); 420 activity.setState(Task.ActivityState.RESUMED, "Testing"); 421 422 task.onRequestedOverrideConfigurationChanged(task.getConfiguration()); 423 activity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(), 424 activity.getConfiguration())); 425 426 activity.info.configChanges &= ~ActivityInfo.CONFIG_FONT_SCALE; 427 final Configuration newConfig = new Configuration(task.getConfiguration()); 428 newConfig.fontScale = 5; 429 task.onRequestedOverrideConfigurationChanged(newConfig); 430 431 activity.mRelaunchReason = 432 ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE; 433 434 ensureActivityConfiguration(activity); 435 436 assertEquals(ActivityTaskManagerService.RELAUNCH_REASON_NONE, 437 activity.mRelaunchReason); 438 } 439 440 @Test testDestroyedActivityNotScheduleConfigChanged()441 public void testDestroyedActivityNotScheduleConfigChanged() throws RemoteException { 442 final ActivityRecord activity = new ActivityBuilder(mAtm) 443 .setCreateTask(true) 444 .setConfigChanges(CONFIG_ORIENTATION) 445 .build(); 446 final Task task = activity.getTask(); 447 activity.setState(DESTROYED, "Testing"); 448 clearInvocations(mAtm.getLifecycleManager()); 449 450 final Configuration newConfig = new Configuration(task.getConfiguration()); 451 newConfig.orientation = newConfig.orientation == ORIENTATION_PORTRAIT 452 ? ORIENTATION_LANDSCAPE 453 : ORIENTATION_PORTRAIT; 454 task.onRequestedOverrideConfigurationChanged(newConfig); 455 456 ensureActivityConfiguration(activity); 457 458 verify(mAtm.getLifecycleManager(), never()) 459 .scheduleTransaction(any(), any(), isA(ActivityConfigurationChangeItem.class)); 460 } 461 462 @Test testSetRequestedOrientationUpdatesConfiguration()463 public void testSetRequestedOrientationUpdatesConfiguration() throws Exception { 464 final ActivityRecord activity = new ActivityBuilder(mAtm) 465 .setCreateTask(true) 466 .setConfigChanges(CONFIG_ORIENTATION | CONFIG_SCREEN_LAYOUT) 467 .build(); 468 activity.setState(Task.ActivityState.RESUMED, "Testing"); 469 470 activity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(), 471 activity.getConfiguration())); 472 473 clearInvocations(mAtm.getLifecycleManager()); 474 final Configuration newConfig = new Configuration(activity.getConfiguration()); 475 final int shortSide = Math.min(newConfig.screenWidthDp, newConfig.screenHeightDp); 476 final int longSide = Math.max(newConfig.screenWidthDp, newConfig.screenHeightDp); 477 if (newConfig.orientation == ORIENTATION_PORTRAIT) { 478 newConfig.orientation = ORIENTATION_LANDSCAPE; 479 newConfig.screenWidthDp = longSide; 480 newConfig.screenHeightDp = shortSide; 481 } else { 482 newConfig.orientation = ORIENTATION_PORTRAIT; 483 newConfig.screenWidthDp = shortSide; 484 newConfig.screenHeightDp = longSide; 485 } 486 487 // Mimic the behavior that display doesn't handle app's requested orientation. 488 final DisplayContent dc = activity.getTask().getDisplayContent(); 489 doReturn(false).when(dc).onDescendantOrientationChanged(any()); 490 doReturn(false).when(dc).handlesOrientationChangeFromDescendant(); 491 492 final int requestedOrientation; 493 switch (newConfig.orientation) { 494 case ORIENTATION_LANDSCAPE: 495 requestedOrientation = SCREEN_ORIENTATION_LANDSCAPE; 496 break; 497 case ORIENTATION_PORTRAIT: 498 requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; 499 break; 500 default: 501 throw new IllegalStateException("Orientation in new config should be either" 502 + "landscape or portrait."); 503 } 504 activity.setRequestedOrientation(requestedOrientation); 505 506 final ActivityConfigurationChangeItem expected = 507 ActivityConfigurationChangeItem.obtain(newConfig); 508 verify(mAtm.getLifecycleManager()).scheduleTransaction(eq(activity.app.getThread()), 509 eq(activity.appToken), eq(expected)); 510 } 511 512 @Test ignoreRequestedOrientationInFreeformWindows()513 public void ignoreRequestedOrientationInFreeformWindows() { 514 final ActivityRecord activity = createActivityWithTask(); 515 final Task task = activity.getTask(); 516 task.setWindowingMode(WINDOWING_MODE_FREEFORM); 517 final Rect stableRect = new Rect(); 518 task.mDisplayContent.getStableRect(stableRect); 519 520 // Carve out non-decor insets from stableRect 521 final Rect insets = new Rect(); 522 final DisplayInfo displayInfo = task.mDisplayContent.getDisplayInfo(); 523 final DisplayPolicy policy = task.mDisplayContent.getDisplayPolicy(); 524 policy.getNonDecorInsetsLw(displayInfo.rotation, displayInfo.logicalWidth, 525 displayInfo.logicalHeight, displayInfo.displayCutout, insets); 526 policy.convertNonDecorInsetsToStableInsets(insets, displayInfo.rotation); 527 Task.intersectWithInsetsIfFits(stableRect, stableRect, insets); 528 529 final boolean isScreenPortrait = stableRect.width() <= stableRect.height(); 530 final Rect bounds = new Rect(stableRect); 531 if (isScreenPortrait) { 532 // Landscape bounds 533 final int newHeight = stableRect.width() - 10; 534 bounds.top = stableRect.top + (stableRect.height() - newHeight) / 2; 535 bounds.bottom = bounds.top + newHeight; 536 } else { 537 // Portrait bounds 538 final int newWidth = stableRect.height() - 10; 539 bounds.left = stableRect.left + (stableRect.width() - newWidth) / 2; 540 bounds.right = bounds.left + newWidth; 541 } 542 task.setBounds(bounds); 543 544 // Requests orientation that's different from its bounds. 545 activity.setRequestedOrientation( 546 isScreenPortrait ? SCREEN_ORIENTATION_PORTRAIT : SCREEN_ORIENTATION_LANDSCAPE); 547 548 // Asserts it has orientation derived from bounds. 549 assertEquals(isScreenPortrait ? ORIENTATION_LANDSCAPE : ORIENTATION_PORTRAIT, 550 activity.getConfiguration().orientation); 551 } 552 553 @Test ignoreRequestedOrientationForResizableInSplitWindows()554 public void ignoreRequestedOrientationForResizableInSplitWindows() { 555 final ActivityRecord activity = createActivityWith2LevelTask(); 556 final Task task = activity.getTask(); 557 final Task rootTask = activity.getRootTask(); 558 rootTask.setWindowingMode(WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY); 559 final Rect stableRect = new Rect(); 560 rootTask.mDisplayContent.getStableRect(stableRect); 561 562 // Carve out non-decor insets from stableRect 563 final Rect insets = new Rect(); 564 final DisplayInfo displayInfo = rootTask.mDisplayContent.getDisplayInfo(); 565 final DisplayPolicy policy = rootTask.mDisplayContent.getDisplayPolicy(); 566 policy.getNonDecorInsetsLw(displayInfo.rotation, displayInfo.logicalWidth, 567 displayInfo.logicalHeight, displayInfo.displayCutout, insets); 568 policy.convertNonDecorInsetsToStableInsets(insets, displayInfo.rotation); 569 Task.intersectWithInsetsIfFits(stableRect, stableRect, insets); 570 571 final boolean isScreenPortrait = stableRect.width() <= stableRect.height(); 572 final Rect bounds = new Rect(stableRect); 573 if (isScreenPortrait) { 574 // Landscape bounds 575 final int newHeight = stableRect.width() - 10; 576 bounds.top = stableRect.top + (stableRect.height() - newHeight) / 2; 577 bounds.bottom = bounds.top + newHeight; 578 } else { 579 // Portrait bounds 580 final int newWidth = stableRect.height() - 10; 581 bounds.left = stableRect.left + (stableRect.width() - newWidth) / 2; 582 bounds.right = bounds.left + newWidth; 583 } 584 task.setBounds(bounds); 585 586 final int activityCurOrientation = activity.getConfiguration().orientation; 587 588 // Requests orientation that's different from its bounds. 589 activity.setRequestedOrientation(activityCurOrientation == ORIENTATION_LANDSCAPE 590 ? SCREEN_ORIENTATION_PORTRAIT : SCREEN_ORIENTATION_LANDSCAPE); 591 592 // Asserts fixed orientation request is ignored, and the orientation is not changed 593 // (fill Task). 594 assertEquals(activityCurOrientation, activity.getConfiguration().orientation); 595 assertFalse(activity.isLetterboxedForFixedOrientationAndAspectRatio()); 596 } 597 598 @Test respectRequestedOrientationForNonResizableInSplitWindows()599 public void respectRequestedOrientationForNonResizableInSplitWindows() { 600 final Task task = new TaskBuilder(mSupervisor) 601 .setCreateParentTask(true).setCreateActivity(true).build(); 602 final Task rootTask = task.getRootTask(); 603 final ActivityRecord activity = new ActivityBuilder(mAtm) 604 .setParentTask(task) 605 .setOnTop(true) 606 .setResizeMode(RESIZE_MODE_UNRESIZEABLE) 607 .setScreenOrientation(SCREEN_ORIENTATION_PORTRAIT) 608 .build(); 609 610 // Task in landscape. 611 rootTask.setWindowingMode(WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY); 612 task.setBounds(0, 0, 1000, 500); 613 assertEquals(ORIENTATION_LANDSCAPE, task.getConfiguration().orientation); 614 615 // Asserts fixed orientation request is respected, and the orientation is not changed. 616 assertEquals(ORIENTATION_PORTRAIT, activity.getConfiguration().orientation); 617 618 // Clear size compat. 619 activity.clearSizeCompatMode(); 620 activity.ensureActivityConfiguration(0 /* globalChanges */, false /* preserveWindow */); 621 activity.mDisplayContent.sendNewConfiguration(); 622 623 // Relaunching the app should still respect the orientation request. 624 assertEquals(ORIENTATION_PORTRAIT, activity.getConfiguration().orientation); 625 assertTrue(activity.isLetterboxedForFixedOrientationAndAspectRatio()); 626 } 627 628 @Test testShouldMakeActive_deferredResume()629 public void testShouldMakeActive_deferredResume() { 630 final ActivityRecord activity = createActivityWithTask(); 631 activity.setState(Task.ActivityState.STOPPED, "Testing"); 632 633 mSupervisor.beginDeferResume(); 634 assertEquals(false, activity.shouldMakeActive(null /* activeActivity */)); 635 636 mSupervisor.endDeferResume(); 637 assertEquals(true, activity.shouldMakeActive(null /* activeActivity */)); 638 } 639 640 @Test testShouldMakeActive_nonTopVisible()641 public void testShouldMakeActive_nonTopVisible() { 642 final ActivityRecord activity = createActivityWithTask(); 643 final Task task = activity.getTask(); 644 ActivityRecord finishingActivity = new ActivityBuilder(mAtm).setTask(task).build(); 645 finishingActivity.finishing = true; 646 ActivityRecord topActivity = new ActivityBuilder(mAtm).setTask(task).build(); 647 activity.setState(Task.ActivityState.STOPPED, "Testing"); 648 649 assertEquals(false, activity.shouldMakeActive(null /* activeActivity */)); 650 } 651 652 @Test testShouldResume_stackVisibility()653 public void testShouldResume_stackVisibility() { 654 final ActivityRecord activity = createActivityWithTask(); 655 final Task task = activity.getTask(); 656 activity.setState(Task.ActivityState.STOPPED, "Testing"); 657 658 doReturn(TASK_VISIBILITY_VISIBLE).when(task).getVisibility(null); 659 assertEquals(true, activity.shouldResumeActivity(null /* activeActivity */)); 660 661 doReturn(TASK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT).when(task).getVisibility(null); 662 assertEquals(false, activity.shouldResumeActivity(null /* activeActivity */)); 663 664 doReturn(TASK_VISIBILITY_INVISIBLE).when(task).getVisibility(null); 665 assertEquals(false, activity.shouldResumeActivity(null /* activeActivity */)); 666 } 667 668 @Test testShouldResumeOrPauseWithResults()669 public void testShouldResumeOrPauseWithResults() { 670 final ActivityRecord activity = createActivityWithTask(); 671 final Task task = activity.getTask(); 672 activity.setState(Task.ActivityState.STOPPED, "Testing"); 673 674 ActivityRecord topActivity = new ActivityBuilder(mAtm).setTask(task).build(); 675 activity.addResultLocked(topActivity, "resultWho", 0, 0, new Intent()); 676 topActivity.finishing = true; 677 678 doReturn(TASK_VISIBILITY_VISIBLE).when(task).getVisibility(null); 679 assertEquals(true, activity.shouldResumeActivity(null /* activeActivity */)); 680 assertEquals(false, activity.shouldPauseActivity(null /*activeActivity */)); 681 } 682 683 @Test testPushConfigurationWhenLaunchTaskBehind()684 public void testPushConfigurationWhenLaunchTaskBehind() throws Exception { 685 final ActivityRecord activity = new ActivityBuilder(mAtm) 686 .setCreateTask(true) 687 .setLaunchTaskBehind(true) 688 .setConfigChanges(CONFIG_ORIENTATION | CONFIG_SCREEN_LAYOUT) 689 .build(); 690 final Task task = activity.getTask(); 691 activity.setState(Task.ActivityState.STOPPED, "Testing"); 692 693 final Task stack = new TaskBuilder(mSupervisor).setCreateActivity(true).build(); 694 try { 695 clearInvocations(mAtm.getLifecycleManager()); 696 doReturn(false).when(stack).isTranslucent(any()); 697 assertTrue(task.shouldBeVisible(null /* starting */)); 698 699 activity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(), 700 activity.getConfiguration())); 701 702 final Configuration newConfig = new Configuration(activity.getConfiguration()); 703 final int shortSide = Math.min(newConfig.screenWidthDp, newConfig.screenHeightDp); 704 final int longSide = Math.max(newConfig.screenWidthDp, newConfig.screenHeightDp); 705 if (newConfig.orientation == ORIENTATION_PORTRAIT) { 706 newConfig.orientation = ORIENTATION_LANDSCAPE; 707 newConfig.screenWidthDp = longSide; 708 newConfig.screenHeightDp = shortSide; 709 } else { 710 newConfig.orientation = ORIENTATION_PORTRAIT; 711 newConfig.screenWidthDp = shortSide; 712 newConfig.screenHeightDp = longSide; 713 } 714 715 task.onConfigurationChanged(newConfig); 716 717 activity.ensureActivityConfiguration(0 /* globalChanges */, 718 false /* preserveWindow */, true /* ignoreStopState */); 719 720 final ActivityConfigurationChangeItem expected = 721 ActivityConfigurationChangeItem.obtain(newConfig); 722 verify(mAtm.getLifecycleManager()).scheduleTransaction( 723 eq(activity.app.getThread()), eq(activity.appToken), eq(expected)); 724 } finally { 725 stack.getDisplayArea().removeChild(stack); 726 } 727 } 728 729 @Test testShouldStartWhenMakeClientActive()730 public void testShouldStartWhenMakeClientActive() { 731 final ActivityRecord activity = createActivityWithTask(); 732 ActivityRecord topActivity = new ActivityBuilder(mAtm).setTask(activity.getTask()).build(); 733 topActivity.setOccludesParent(false); 734 activity.setState(Task.ActivityState.STOPPED, "Testing"); 735 activity.setVisibility(true); 736 activity.makeActiveIfNeeded(null /* activeActivity */); 737 assertEquals(STARTED, activity.getState()); 738 } 739 740 @Test testTakeOptions()741 public void testTakeOptions() { 742 final ActivityRecord activity = createActivityWithTask(); 743 ActivityOptions opts = ActivityOptions.makeRemoteAnimation( 744 new RemoteAnimationAdapter(new Stub() { 745 746 @Override 747 public void onAnimationStart(@WindowManager.TransitionOldType int transit, 748 RemoteAnimationTarget[] apps, 749 RemoteAnimationTarget[] wallpapers, 750 RemoteAnimationTarget[] nonApps, 751 IRemoteAnimationFinishedCallback finishedCallback) { 752 } 753 754 @Override 755 public void onAnimationCancelled() { 756 } 757 }, 0, 0)); 758 activity.updateOptionsLocked(opts); 759 assertNotNull(activity.takeOptions()); 760 assertNull(activity.getOptions()); 761 762 final AppTransition appTransition = activity.mDisplayContent.mAppTransition; 763 spyOn(appTransition); 764 activity.applyOptionsAnimation(); 765 766 verify(appTransition).overridePendingAppTransitionRemote(any()); 767 } 768 769 @Test testCanLaunchHomeActivityFromChooser()770 public void testCanLaunchHomeActivityFromChooser() { 771 ComponentName chooserComponent = ComponentName.unflattenFromString( 772 Resources.getSystem().getString(R.string.config_chooserActivity)); 773 ActivityRecord chooserActivity = new ActivityBuilder(mAtm).setComponent( 774 chooserComponent).build(); 775 assertThat(chooserActivity.canLaunchHomeActivity(NOBODY_UID, chooserActivity)).isTrue(); 776 } 777 778 /** 779 * Verify that an {@link ActivityRecord} reports that it has saved state after creation, and 780 * that it is cleared after activity is resumed. 781 */ 782 @Test testHasSavedState()783 public void testHasSavedState() { 784 final ActivityRecord activity = createActivityWithTask(); 785 assertTrue(activity.hasSavedState()); 786 787 ActivityRecord.activityResumedLocked(activity.appToken, false /* handleSplashScreenExit */); 788 assertFalse(activity.hasSavedState()); 789 assertNull(activity.getSavedState()); 790 } 791 792 /** Verify the behavior of {@link ActivityRecord#setSavedState(Bundle)}. */ 793 @Test testUpdateSavedState()794 public void testUpdateSavedState() { 795 final ActivityRecord activity = createActivityWithTask(); 796 activity.setSavedState(null /* savedState */); 797 assertFalse(activity.hasSavedState()); 798 assertNull(activity.getSavedState()); 799 800 final Bundle savedState = new Bundle(); 801 savedState.putString("test", "string"); 802 activity.setSavedState(savedState); 803 assertTrue(activity.hasSavedState()); 804 assertEquals(savedState, activity.getSavedState()); 805 } 806 807 /** Verify the correct updates of saved state when activity client reports stop. */ 808 @Test testUpdateSavedState_activityStopped()809 public void testUpdateSavedState_activityStopped() { 810 final ActivityRecord activity = createActivityWithTask(); 811 final Bundle savedState = new Bundle(); 812 savedState.putString("test", "string"); 813 final PersistableBundle persistentSavedState = new PersistableBundle(); 814 persistentSavedState.putString("persist", "string"); 815 816 // Set state to STOPPING, or ActivityRecord#activityStoppedLocked() call will be ignored. 817 activity.setState(STOPPING, "test"); 818 activity.activityStopped(savedState, persistentSavedState, "desc"); 819 assertTrue(activity.hasSavedState()); 820 assertEquals(savedState, activity.getSavedState()); 821 assertEquals(persistentSavedState, activity.getPersistentSavedState()); 822 823 // Sending 'null' for saved state can only happen due to timeout, so previously stored saved 824 // states should not be overridden. 825 activity.setState(STOPPING, "test"); 826 activity.activityStopped(null /* savedState */, null /* persistentSavedState */, "desc"); 827 assertTrue(activity.hasSavedState()); 828 assertEquals(savedState, activity.getSavedState()); 829 assertEquals(persistentSavedState, activity.getPersistentSavedState()); 830 } 831 832 /** 833 * Verify that activity finish request is not performed if activity is finishing or is in 834 * incorrect state. 835 */ 836 @Test testFinishActivityIfPossible_cancelled()837 public void testFinishActivityIfPossible_cancelled() { 838 final ActivityRecord activity = createActivityWithTask(); 839 // Mark activity as finishing 840 activity.finishing = true; 841 assertEquals("Duplicate finish request must be ignored", FINISH_RESULT_CANCELLED, 842 activity.finishIfPossible("test", false /* oomAdj */)); 843 assertTrue(activity.finishing); 844 assertTrue(activity.isInRootTaskLocked()); 845 846 // Remove activity from task 847 activity.finishing = false; 848 activity.onParentChanged(null /*newParent*/, activity.getTask()); 849 assertEquals("Activity outside of task/stack cannot be finished", FINISH_RESULT_CANCELLED, 850 activity.finishIfPossible("test", false /* oomAdj */)); 851 assertFalse(activity.finishing); 852 } 853 854 /** 855 * Verify that activity finish request is placed, but not executed immediately if activity is 856 * not ready yet. 857 */ 858 @Test testFinishActivityIfPossible_requested()859 public void testFinishActivityIfPossible_requested() { 860 final ActivityRecord activity = createActivityWithTask(); 861 activity.finishing = false; 862 assertEquals("Currently resumed activity must be prepared removal", FINISH_RESULT_REQUESTED, 863 activity.finishIfPossible("test", false /* oomAdj */)); 864 assertTrue(activity.finishing); 865 assertTrue(activity.isInRootTaskLocked()); 866 867 // First request to finish activity must schedule a "destroy" request to the client. 868 // Activity must be removed from history after the client reports back or after timeout. 869 activity.finishing = false; 870 activity.setState(STOPPED, "test"); 871 assertEquals("Activity outside of task/stack cannot be finished", FINISH_RESULT_REQUESTED, 872 activity.finishIfPossible("test", false /* oomAdj */)); 873 assertTrue(activity.finishing); 874 assertTrue(activity.isInRootTaskLocked()); 875 } 876 877 /** 878 * Verify that activity finish request removes activity immediately if it's ready. 879 */ 880 @Test testFinishActivityIfPossible_removed()881 public void testFinishActivityIfPossible_removed() { 882 final ActivityRecord activity = createActivityWithTask(); 883 // Prepare the activity record to be ready for immediate removal. It should be invisible and 884 // have no process. Otherwise, request to finish it will send a message to client first. 885 activity.setState(STOPPED, "test"); 886 activity.mVisibleRequested = false; 887 activity.nowVisible = false; 888 // Set process to 'null' to allow immediate removal, but don't call mActivity.setProcess() - 889 // this will cause NPE when updating task's process. 890 activity.app = null; 891 892 // Put a visible activity on top, so the finishing activity doesn't have to wait until the 893 // next activity reports idle to destroy it. 894 final ActivityRecord topActivity = new ActivityBuilder(mAtm) 895 .setTask(activity.getTask()).build(); 896 topActivity.mVisibleRequested = true; 897 topActivity.nowVisible = true; 898 topActivity.setState(RESUMED, "test"); 899 900 assertEquals("Activity outside of task/rootTask cannot be finished", FINISH_RESULT_REMOVED, 901 activity.finishIfPossible("test", false /* oomAdj */)); 902 assertTrue(activity.finishing); 903 assertFalse(activity.isInRootTaskLocked()); 904 } 905 906 /** 907 * Verify that when finishing the top focused activity on top display, the root task order 908 * will be changed by adjusting focus. 909 */ 910 @Test testFinishActivityIfPossible_adjustStackOrder()911 public void testFinishActivityIfPossible_adjustStackOrder() { 912 final ActivityRecord activity = createActivityWithTask(); 913 final Task task = activity.getTask(); 914 // Prepare the tasks with order (top to bottom): task, task1, task2. 915 final Task task1 = new TaskBuilder(mSupervisor).setCreateActivity(true).build(); 916 task.moveToFront("test"); 917 // The task2 is needed here for moving back to simulate the 918 // {@link DisplayContent#mPreferredTopFocusableStack} is cleared, so 919 // {@link DisplayContent#getFocusedStack} will rely on the order of focusable-and-visible 920 // tasks. Then when mActivity is finishing, its task will be invisible (no running 921 // activities in the task) that is the key condition to verify. 922 final Task task2 = new TaskBuilder(mSupervisor).setCreateActivity(true).build(); 923 task2.moveToBack("test", task2.getBottomMostTask()); 924 925 assertTrue(task.isTopRootTaskInDisplayArea()); 926 927 activity.setState(RESUMED, "test"); 928 activity.finishIfPossible(0 /* resultCode */, null /* resultData */, 929 null /* resultGrants */, "test", false /* oomAdj */); 930 931 assertTrue(task1.isTopRootTaskInDisplayArea()); 932 } 933 934 /** 935 * Verify that when finishing the top focused activity while root task was created by organizer, 936 * the stack order will be changed by adjusting focus. 937 */ 938 @Test testFinishActivityIfPossible_adjustStackOrderOrganizedRoot()939 public void testFinishActivityIfPossible_adjustStackOrderOrganizedRoot() { 940 // Make mStack be a the root task that created by task organizer 941 final Task rootableTask = new TaskBuilder(mSupervisor) 942 .setCreateParentTask(true).setCreateActivity(true).build(); 943 final Task rootTask = rootableTask.getRootTask(); 944 rootTask.mCreatedByOrganizer = true; 945 946 // Have two tasks (topRootableTask and rootableTask) as the children of rootTask. 947 ActivityRecord topActivity = new ActivityBuilder(mAtm) 948 .setCreateTask(true) 949 .setParentTask(rootTask) 950 .build(); 951 Task topRootableTask = topActivity.getTask(); 952 topRootableTask.moveToFront("test"); 953 assertTrue(rootTask.isTopRootTaskInDisplayArea()); 954 955 // Finish top activity and verify the next focusable rootable task has adjusted to top. 956 topActivity.setState(RESUMED, "test"); 957 topActivity.finishIfPossible(0 /* resultCode */, null /* resultData */, 958 null /* resultGrants */, "test", false /* oomAdj */); 959 assertEquals(rootableTask, rootTask.getTopMostTask()); 960 } 961 962 /** 963 * Verify that when top focused activity is on secondary display, when finishing the top focused 964 * activity on default display, the preferred top stack on default display should be changed by 965 * adjusting focus. 966 */ 967 @Test testFinishActivityIfPossible_PreferredTopStackChanged()968 public void testFinishActivityIfPossible_PreferredTopStackChanged() { 969 final ActivityRecord activity = createActivityWithTask(); 970 final Task task = activity.getTask(); 971 final ActivityRecord topActivityOnNonTopDisplay = 972 createActivityOnDisplay(true /* defaultDisplay */, null /* process */); 973 Task topRootableTask = topActivityOnNonTopDisplay.getRootTask(); 974 topRootableTask.moveToFront("test"); 975 assertTrue(topRootableTask.isTopRootTaskInDisplayArea()); 976 assertEquals(topRootableTask, topActivityOnNonTopDisplay.getDisplayArea() 977 .mPreferredTopFocusableRootTask); 978 979 final ActivityRecord secondaryDisplayActivity = 980 createActivityOnDisplay(false /* defaultDisplay */, null /* process */); 981 topRootableTask = secondaryDisplayActivity.getRootTask(); 982 topRootableTask.moveToFront("test"); 983 assertTrue(topRootableTask.isTopRootTaskInDisplayArea()); 984 assertEquals(topRootableTask, 985 secondaryDisplayActivity.getDisplayArea().mPreferredTopFocusableRootTask); 986 987 // The global top focus activity is on secondary display now. 988 // Finish top activity on default display and verify the next preferred top focusable stack 989 // on default display has changed. 990 topActivityOnNonTopDisplay.setState(RESUMED, "test"); 991 topActivityOnNonTopDisplay.finishIfPossible(0 /* resultCode */, null /* resultData */, 992 null /* resultGrants */, "test", false /* oomAdj */); 993 assertEquals(task, task.getTopMostTask()); 994 assertEquals(task, activity.getDisplayArea().mPreferredTopFocusableRootTask); 995 } 996 997 /** 998 * Verify that resumed activity is paused due to finish request. 999 */ 1000 @Test testFinishActivityIfPossible_resumedStartsPausing()1001 public void testFinishActivityIfPossible_resumedStartsPausing() { 1002 final ActivityRecord activity = createActivityWithTask(); 1003 activity.finishing = false; 1004 activity.setState(RESUMED, "test"); 1005 assertEquals("Currently resumed activity must be paused before removal", 1006 FINISH_RESULT_REQUESTED, activity.finishIfPossible("test", false /* oomAdj */)); 1007 assertEquals(PAUSING, activity.getState()); 1008 verify(activity).setVisibility(eq(false)); 1009 verify(activity.mDisplayContent).prepareAppTransition(eq(TRANSIT_CLOSE)); 1010 } 1011 1012 /** 1013 * Verify that finish request will be completed immediately for non-resumed activity. 1014 */ 1015 @Test testFinishActivityIfPossible_nonResumedFinishCompletesImmediately()1016 public void testFinishActivityIfPossible_nonResumedFinishCompletesImmediately() { 1017 final ActivityRecord activity = createActivityWithTask(); 1018 final ActivityState[] states = {INITIALIZING, STARTED, PAUSED, STOPPING, STOPPED}; 1019 for (ActivityState state : states) { 1020 activity.finishing = false; 1021 activity.setState(state, "test"); 1022 reset(activity); 1023 assertEquals("Finish must be requested", FINISH_RESULT_REQUESTED, 1024 activity.finishIfPossible("test", false /* oomAdj */)); 1025 verify(activity).completeFinishing(anyString()); 1026 } 1027 } 1028 1029 /** 1030 * Verify that finishing will not be completed in PAUSING state. 1031 */ 1032 @Test testFinishActivityIfPossible_pausing()1033 public void testFinishActivityIfPossible_pausing() { 1034 final ActivityRecord activity = createActivityWithTask(); 1035 activity.finishing = false; 1036 activity.setState(PAUSING, "test"); 1037 assertEquals("Finish must be requested", FINISH_RESULT_REQUESTED, 1038 activity.finishIfPossible("test", false /* oomAdj */)); 1039 verify(activity, never()).completeFinishing(anyString()); 1040 } 1041 1042 /** 1043 * Verify that finish request for resumed activity will prepare an app transition but not 1044 * execute it immediately. 1045 */ 1046 @Test testFinishActivityIfPossible_visibleResumedPreparesAppTransition()1047 public void testFinishActivityIfPossible_visibleResumedPreparesAppTransition() { 1048 final ActivityRecord activity = createActivityWithTask(); 1049 clearInvocations(activity.mDisplayContent); 1050 activity.finishing = false; 1051 activity.mVisibleRequested = true; 1052 activity.setState(RESUMED, "test"); 1053 activity.finishIfPossible("test", false /* oomAdj */); 1054 1055 verify(activity).setVisibility(eq(false)); 1056 verify(activity.mDisplayContent).prepareAppTransition(eq(TRANSIT_CLOSE)); 1057 verify(activity.mDisplayContent, never()).executeAppTransition(); 1058 } 1059 1060 /** 1061 * Verify that finish request for paused activity will prepare and execute an app transition. 1062 */ 1063 @Test testFinishActivityIfPossible_visibleNotResumedExecutesAppTransition()1064 public void testFinishActivityIfPossible_visibleNotResumedExecutesAppTransition() { 1065 final ActivityRecord activity = createActivityWithTask(); 1066 clearInvocations(activity.mDisplayContent); 1067 activity.finishing = false; 1068 activity.mVisibleRequested = true; 1069 activity.setState(PAUSED, "test"); 1070 activity.finishIfPossible("test", false /* oomAdj */); 1071 1072 verify(activity, atLeast(1)).setVisibility(eq(false)); 1073 verify(activity.mDisplayContent).prepareAppTransition(eq(TRANSIT_CLOSE)); 1074 verify(activity.mDisplayContent).executeAppTransition(); 1075 } 1076 1077 /** 1078 * Verify that finish request for non-visible activity will not prepare any transitions. 1079 */ 1080 @Test testFinishActivityIfPossible_nonVisibleNoAppTransition()1081 public void testFinishActivityIfPossible_nonVisibleNoAppTransition() { 1082 final ActivityRecord activity = createActivityWithTask(); 1083 // Put an activity on top of test activity to make it invisible and prevent us from 1084 // accidentally resuming the topmost one again. 1085 new ActivityBuilder(mAtm).build(); 1086 activity.mVisibleRequested = false; 1087 activity.setState(STOPPED, "test"); 1088 1089 activity.finishIfPossible("test", false /* oomAdj */); 1090 1091 verify(activity.mDisplayContent, never()).prepareAppTransition(eq(TRANSIT_CLOSE)); 1092 } 1093 1094 /** 1095 * Verify that finish request for the last activity in a task will request a shell transition 1096 * with that task as a trigger. 1097 */ 1098 @Test testFinishActivityIfPossible_lastInTaskRequestsTransitionWithTrigger()1099 public void testFinishActivityIfPossible_lastInTaskRequestsTransitionWithTrigger() { 1100 // Set-up mock shell transitions 1101 final TestTransitionPlayer testPlayer = new TestTransitionPlayer( 1102 mAtm.getTransitionController(), mAtm.mWindowOrganizerController); 1103 mAtm.getTransitionController().registerTransitionPlayer(testPlayer); 1104 1105 final ActivityRecord activity = createActivityWithTask(); 1106 activity.finishing = false; 1107 activity.mVisibleRequested = true; 1108 activity.setState(RESUMED, "test"); 1109 activity.finishIfPossible("test", false /* oomAdj */); 1110 1111 verify(activity).setVisibility(eq(false)); 1112 assertEquals(activity.getTask().mTaskId, testPlayer.mLastRequest.getTriggerTask().taskId); 1113 } 1114 1115 /** 1116 * Verify that complete finish request for non-finishing activity is invalid. 1117 */ 1118 @Test(expected = IllegalArgumentException.class) testCompleteFinishing_failNotFinishing()1119 public void testCompleteFinishing_failNotFinishing() { 1120 final ActivityRecord activity = createActivityWithTask(); 1121 activity.finishing = false; 1122 activity.completeFinishing("test"); 1123 } 1124 1125 /** 1126 * Verify that complete finish request for resumed activity is invalid. 1127 */ 1128 @Test(expected = IllegalArgumentException.class) testCompleteFinishing_failResumed()1129 public void testCompleteFinishing_failResumed() { 1130 final ActivityRecord activity = createActivityWithTask(); 1131 activity.setState(RESUMED, "test"); 1132 activity.completeFinishing("test"); 1133 } 1134 1135 /** 1136 * Verify that finish request for pausing activity must be a no-op - activity will finish 1137 * once it completes pausing. 1138 */ 1139 @Test testCompleteFinishing_pausing()1140 public void testCompleteFinishing_pausing() { 1141 final ActivityRecord activity = createActivityWithTask(); 1142 activity.setState(PAUSING, "test"); 1143 activity.finishing = true; 1144 1145 assertEquals("Activity must not be removed immediately - waiting for paused", 1146 activity, activity.completeFinishing("test")); 1147 assertEquals(PAUSING, activity.getState()); 1148 verify(activity, never()).destroyIfPossible(anyString()); 1149 } 1150 1151 /** 1152 * Verify that finish request won't change the state of next top activity if the current 1153 * finishing activity doesn't need to be destroyed immediately. The case is usually like 1154 * from {@link ActivityStack#completePauseLocked(boolean, ActivityRecord)} to 1155 * {@link ActivityRecord#completeFinishing(String)}, so the complete-pause should take the 1156 * responsibility to resume the next activity with updating the state. 1157 */ 1158 @Test testCompleteFinishing_keepStateOfNextInvisible()1159 public void testCompleteFinishing_keepStateOfNextInvisible() { 1160 final ActivityRecord currentTop = createActivityWithTask(); 1161 final Task task = currentTop.getTask(); 1162 1163 currentTop.mVisibleRequested = currentTop.nowVisible = true; 1164 1165 // Simulates that {@code currentTop} starts an existing activity from background (so its 1166 // state is stopped) and the starting flow just goes to place it at top. 1167 final Task nextStack = new TaskBuilder(mSupervisor).setCreateActivity(true).build(); 1168 final ActivityRecord nextTop = nextStack.getTopNonFinishingActivity(); 1169 nextTop.setState(STOPPED, "test"); 1170 1171 task.setPausingActivity(currentTop); 1172 currentTop.finishing = true; 1173 currentTop.setState(PAUSED, "test"); 1174 currentTop.completeFinishing("completePauseLocked"); 1175 1176 // Current top becomes stopping because it is visible and the next is invisible. 1177 assertEquals(STOPPING, currentTop.getState()); 1178 // The state of next activity shouldn't be changed. 1179 assertEquals(STOPPED, nextTop.getState()); 1180 } 1181 1182 /** 1183 * Verify that finish bottom activity from a task won't boost it to top. 1184 */ 1185 @Test testFinishBottomActivityIfPossible_noZBoost()1186 public void testFinishBottomActivityIfPossible_noZBoost() { 1187 final ActivityRecord bottomActivity = createActivityWithTask(); 1188 final ActivityRecord topActivity = new ActivityBuilder(mAtm) 1189 .setTask(bottomActivity.getTask()).build(); 1190 topActivity.mVisibleRequested = true; 1191 // simulating bottomActivity as a trampoline activity. 1192 bottomActivity.setState(RESUMED, "test"); 1193 bottomActivity.finishIfPossible("test", false); 1194 assertFalse(bottomActivity.mNeedsZBoost); 1195 } 1196 1197 /** 1198 * Verify that complete finish request for visible activity must be delayed before the next one 1199 * becomes visible. 1200 */ 1201 @Test testCompleteFinishing_waitForNextVisible()1202 public void testCompleteFinishing_waitForNextVisible() { 1203 final ActivityRecord activity = createActivityWithTask(); 1204 final ActivityRecord topActivity = new ActivityBuilder(mAtm) 1205 .setTask(activity.getTask()).build(); 1206 topActivity.mVisibleRequested = true; 1207 topActivity.nowVisible = true; 1208 topActivity.finishing = true; 1209 topActivity.setState(PAUSED, "true"); 1210 // Mark the bottom activity as not visible, so that we will wait for it before removing 1211 // the top one. 1212 activity.mVisibleRequested = false; 1213 activity.nowVisible = false; 1214 activity.setState(STOPPED, "test"); 1215 1216 assertEquals("Activity must not be removed immediately - waiting for next visible", 1217 topActivity, topActivity.completeFinishing("test")); 1218 assertEquals("Activity must be stopped to make next one visible", STOPPING, 1219 topActivity.getState()); 1220 assertTrue("Activity must be stopped to make next one visible", 1221 topActivity.mTaskSupervisor.mStoppingActivities.contains(topActivity)); 1222 verify(topActivity, never()).destroyIfPossible(anyString()); 1223 } 1224 1225 /** 1226 * Verify that complete finish request for top invisible activity must not be delayed while 1227 * sleeping, but next invisible activity must be resumed (and paused/stopped) 1228 */ 1229 @Test testCompleteFinishing_noWaitForNextVisible_sleeping()1230 public void testCompleteFinishing_noWaitForNextVisible_sleeping() { 1231 final ActivityRecord activity = createActivityWithTask(); 1232 // Create a top activity on a new task 1233 final ActivityRecord topActivity = createActivityWithTask(); 1234 mDisplayContent.setIsSleeping(true); 1235 doReturn(true).when(activity).shouldBeVisible(); 1236 topActivity.mVisibleRequested = false; 1237 topActivity.nowVisible = false; 1238 topActivity.finishing = true; 1239 topActivity.setState(STOPPED, "true"); 1240 1241 // Mark the activity behind (on a separate task) as not visible 1242 activity.mVisibleRequested = false; 1243 activity.nowVisible = false; 1244 activity.setState(STOPPED, "test"); 1245 1246 clearInvocations(activity); 1247 topActivity.completeFinishing("test"); 1248 verify(activity).setState(eq(RESUMED), any()); 1249 verify(topActivity).destroyIfPossible(anyString()); 1250 } 1251 1252 /** 1253 * Verify that complete finish request for invisible activity must not be delayed. 1254 */ 1255 @Test testCompleteFinishing_noWaitForNextVisible_alreadyInvisible()1256 public void testCompleteFinishing_noWaitForNextVisible_alreadyInvisible() { 1257 final ActivityRecord activity = createActivityWithTask(); 1258 final ActivityRecord topActivity = new ActivityBuilder(mAtm) 1259 .setTask(activity.getTask()).build(); 1260 topActivity.mVisibleRequested = false; 1261 topActivity.nowVisible = false; 1262 topActivity.finishing = true; 1263 topActivity.setState(STOPPED, "true"); 1264 // Mark the bottom activity as not visible, so that we would wait for it before removing 1265 // the top one. 1266 activity.mVisibleRequested = false; 1267 activity.nowVisible = false; 1268 activity.setState(STOPPED, "test"); 1269 1270 topActivity.completeFinishing("test"); 1271 1272 verify(topActivity).destroyIfPossible(anyString()); 1273 } 1274 1275 /** 1276 * Verify that paused finishing activity will be added to finishing list and wait for next one 1277 * to idle. 1278 */ 1279 @Test testCompleteFinishing_waitForIdle()1280 public void testCompleteFinishing_waitForIdle() { 1281 final ActivityRecord activity = createActivityWithTask(); 1282 final ActivityRecord topActivity = new ActivityBuilder(mAtm) 1283 .setTask(activity.getTask()).build(); 1284 topActivity.mVisibleRequested = true; 1285 topActivity.nowVisible = true; 1286 topActivity.finishing = true; 1287 topActivity.setState(PAUSED, "true"); 1288 // Mark the bottom activity as already visible, so that there is no need to wait for it. 1289 activity.mVisibleRequested = true; 1290 activity.nowVisible = true; 1291 activity.setState(RESUMED, "test"); 1292 1293 topActivity.completeFinishing("test"); 1294 1295 verify(topActivity).addToFinishingAndWaitForIdle(); 1296 } 1297 1298 /** 1299 * Verify that complete finish request for visible activity must not be delayed if the next one 1300 * is already visible and it's not the focused stack. 1301 */ 1302 @Test testCompleteFinishing_noWaitForNextVisible_stopped()1303 public void testCompleteFinishing_noWaitForNextVisible_stopped() { 1304 final ActivityRecord activity = createActivityWithTask(); 1305 final ActivityRecord topActivity = new ActivityBuilder(mAtm) 1306 .setTask(activity.getTask()).build(); 1307 topActivity.mVisibleRequested = false; 1308 topActivity.nowVisible = false; 1309 topActivity.finishing = true; 1310 topActivity.setState(STOPPED, "true"); 1311 // Mark the bottom activity as already visible, so that there is no need to wait for it. 1312 activity.mVisibleRequested = true; 1313 activity.nowVisible = true; 1314 activity.setState(RESUMED, "test"); 1315 1316 topActivity.completeFinishing("test"); 1317 1318 verify(topActivity).destroyIfPossible(anyString()); 1319 } 1320 1321 /** 1322 * Verify that complete finish request for visible activity must not be delayed if the next one 1323 * is already visible and it's not the focused stack. 1324 */ 1325 @Test testCompleteFinishing_noWaitForNextVisible_nonFocusedStack()1326 public void testCompleteFinishing_noWaitForNextVisible_nonFocusedStack() { 1327 final ActivityRecord activity = createActivityWithTask(); 1328 final ActivityRecord topActivity = new ActivityBuilder(mAtm) 1329 .setTask(activity.getTask()).build(); 1330 topActivity.mVisibleRequested = true; 1331 topActivity.nowVisible = true; 1332 topActivity.finishing = true; 1333 topActivity.setState(PAUSED, "true"); 1334 // Mark the bottom activity as already visible, so that there is no need to wait for it. 1335 activity.mVisibleRequested = true; 1336 activity.nowVisible = true; 1337 activity.setState(RESUMED, "test"); 1338 1339 // Add another stack to become focused and make the activity there visible. This way it 1340 // simulates finishing in non-focused stack in split-screen. 1341 final Task stack = new TaskBuilder(mSupervisor).setCreateActivity(true).build(); 1342 final ActivityRecord focusedActivity = stack.getTopMostActivity(); 1343 focusedActivity.nowVisible = true; 1344 focusedActivity.mVisibleRequested = true; 1345 focusedActivity.setState(RESUMED, "test"); 1346 stack.setResumedActivity(focusedActivity, "test"); 1347 1348 topActivity.completeFinishing("test"); 1349 1350 verify(topActivity).destroyIfPossible(anyString()); 1351 } 1352 1353 /** 1354 * Verify that complete finish request for a show-when-locked activity must ensure the 1355 * keyguard occluded state being updated. 1356 */ 1357 @Test testCompleteFinishing_showWhenLocked()1358 public void testCompleteFinishing_showWhenLocked() { 1359 final ActivityRecord activity = createActivityWithTask(); 1360 final Task task = activity.getTask(); 1361 // Make keyguard locked and set the top activity show-when-locked. 1362 KeyguardController keyguardController = activity.mTaskSupervisor.getKeyguardController(); 1363 doReturn(true).when(keyguardController).isKeyguardLocked(); 1364 final ActivityRecord topActivity = new ActivityBuilder(mAtm).setTask(task).build(); 1365 topActivity.mVisibleRequested = true; 1366 topActivity.nowVisible = true; 1367 topActivity.setState(RESUMED, "true"); 1368 doCallRealMethod().when(mRootWindowContainer).ensureActivitiesVisible( 1369 any() /* starting */, anyInt() /* configChanges */, 1370 anyBoolean() /* preserveWindows */, anyBoolean() /* notifyClients */); 1371 topActivity.setShowWhenLocked(true); 1372 1373 // Verify the stack-top activity is occluded keyguard. 1374 assertEquals(topActivity, task.topRunningActivity()); 1375 assertTrue(keyguardController.isDisplayOccluded(DEFAULT_DISPLAY)); 1376 1377 // Finish the top activity 1378 topActivity.setState(PAUSED, "true"); 1379 topActivity.finishing = true; 1380 topActivity.completeFinishing("test"); 1381 1382 // Verify new top activity does not occlude keyguard. 1383 assertEquals(activity, task.topRunningActivity()); 1384 assertFalse(keyguardController.isDisplayOccluded(DEFAULT_DISPLAY)); 1385 } 1386 1387 /** 1388 * Verify that complete finish request for an activity which the resume activity is translucent 1389 * must ensure the visibilities of activities being updated. 1390 */ 1391 @Test testCompleteFinishing_ensureActivitiesVisible_withConditions()1392 public void testCompleteFinishing_ensureActivitiesVisible_withConditions() { 1393 testCompleteFinishing_ensureActivitiesVisible(false, PAUSED); 1394 testCompleteFinishing_ensureActivitiesVisible(false, STARTED); 1395 testCompleteFinishing_ensureActivitiesVisible(true, PAUSED); 1396 testCompleteFinishing_ensureActivitiesVisible(true, STARTED); 1397 } 1398 testCompleteFinishing_ensureActivitiesVisible(boolean diffTask, ActivityState secondActivityState)1399 private void testCompleteFinishing_ensureActivitiesVisible(boolean diffTask, 1400 ActivityState secondActivityState) { 1401 final ActivityRecord activity = createActivityWithTask(); 1402 final Task task = activity.getTask(); 1403 final ActivityRecord firstActivity = new ActivityBuilder(mAtm).setTask(task).build(); 1404 firstActivity.mVisibleRequested = false; 1405 firstActivity.nowVisible = false; 1406 firstActivity.setState(STOPPED, "test"); 1407 1408 final ActivityRecord secondActivity = new ActivityBuilder(mAtm).setTask(task).build(); 1409 secondActivity.mVisibleRequested = true; 1410 secondActivity.nowVisible = true; 1411 secondActivity.setState(secondActivityState, "test"); 1412 1413 ActivityRecord translucentActivity; 1414 if (diffTask) { 1415 translucentActivity = new ActivityBuilder(mAtm).setCreateTask(true).build(); 1416 } else { 1417 translucentActivity = new ActivityBuilder(mAtm).setTask(task).build(); 1418 } 1419 translucentActivity.mVisibleRequested = true; 1420 translucentActivity.nowVisible = true; 1421 translucentActivity.setState(RESUMED, "test"); 1422 1423 doReturn(true).when(firstActivity).occludesParent(true); 1424 doReturn(true).when(secondActivity).occludesParent(true); 1425 1426 // Finish the second activity 1427 secondActivity.finishing = true; 1428 secondActivity.completeFinishing("test"); 1429 verify(secondActivity.mDisplayContent).ensureActivitiesVisible(null /* starting */, 1430 0 /* configChanges */ , false /* preserveWindows */, 1431 true /* notifyClients */); 1432 1433 // Finish the first activity 1434 firstActivity.finishing = true; 1435 firstActivity.mVisibleRequested = true; 1436 firstActivity.completeFinishing("test"); 1437 verify(firstActivity.mDisplayContent, times(2)).ensureActivitiesVisible(null /* starting */, 1438 0 /* configChanges */ , false /* preserveWindows */, 1439 true /* notifyClients */); 1440 1441 // Remove the translucent activity and clear invocations for next test 1442 translucentActivity.getTask().removeImmediately("test"); 1443 clearInvocations(mDefaultDisplay); 1444 } 1445 1446 /** 1447 * Verify destroy activity request completes successfully. 1448 */ 1449 @Test testDestroyIfPossible()1450 public void testDestroyIfPossible() { 1451 final ActivityRecord activity = createActivityWithTask(); 1452 doReturn(false).when(mRootWindowContainer).resumeFocusedTasksTopActivities(); 1453 activity.destroyIfPossible("test"); 1454 1455 assertEquals(DESTROYING, activity.getState()); 1456 assertTrue(activity.finishing); 1457 verify(activity).destroyImmediately(anyString()); 1458 } 1459 1460 /** 1461 * Verify that complete finish request for visible activity must not destroy it immediately if 1462 * it is the last running activity on a display with a home stack. We must wait for home 1463 * activity to come up to avoid a black flash in this case. 1464 */ 1465 @Test testDestroyIfPossible_lastActivityAboveEmptyHomeStack()1466 public void testDestroyIfPossible_lastActivityAboveEmptyHomeStack() { 1467 final ActivityRecord activity = createActivityWithTask(); 1468 // Empty the home stack. 1469 final Task homeStack = activity.getDisplayArea().getRootHomeTask(); 1470 homeStack.forAllLeafTasks((t) -> { 1471 homeStack.removeChild(t, "test"); 1472 }, true /* traverseTopToBottom */); 1473 activity.finishing = true; 1474 doReturn(false).when(mRootWindowContainer).resumeFocusedTasksTopActivities(); 1475 1476 // Try to destroy the last activity above the home stack. 1477 activity.destroyIfPossible("test"); 1478 1479 // Verify that the activity was not actually destroyed, but waits for next one to come up 1480 // instead. 1481 verify(activity, never()).destroyImmediately(anyString()); 1482 assertEquals(FINISHING, activity.getState()); 1483 assertTrue(activity.mTaskSupervisor.mFinishingActivities.contains(activity)); 1484 } 1485 1486 /** 1487 * Verify that complete finish request for visible activity must resume next home stack before 1488 * destroying it immediately if it is the last running activity on a display with a home stack. 1489 * We must wait for home activity to come up to avoid a black flash in this case. 1490 */ 1491 @Test testCompleteFinishing_lastActivityAboveEmptyHomeStack()1492 public void testCompleteFinishing_lastActivityAboveEmptyHomeStack() { 1493 final ActivityRecord activity = createActivityWithTask(); 1494 // Empty the home root task. 1495 final Task homeRootTask = activity.getDisplayArea().getRootHomeTask(); 1496 homeRootTask.forAllLeafTasks((t) -> { 1497 homeRootTask.removeChild(t, "test"); 1498 }, true /* traverseTopToBottom */); 1499 activity.setState(STARTED, "test"); 1500 activity.finishing = true; 1501 activity.mVisibleRequested = true; 1502 1503 // Try to finish the last activity above the home stack. 1504 activity.completeFinishing("test"); 1505 1506 // Verify that the activity is not destroyed immediately, but waits for next one to come up. 1507 verify(activity, never()).destroyImmediately(anyString()); 1508 assertEquals(FINISHING, activity.getState()); 1509 assertTrue(activity.mTaskSupervisor.mFinishingActivities.contains(activity)); 1510 } 1511 1512 /** 1513 * Test that the activity will be moved to destroying state and the message to destroy will be 1514 * sent to the client. 1515 */ 1516 @Test testDestroyImmediately_hadApp_finishing()1517 public void testDestroyImmediately_hadApp_finishing() { 1518 final ActivityRecord activity = createActivityWithTask(); 1519 activity.finishing = true; 1520 activity.destroyImmediately("test"); 1521 1522 assertEquals(DESTROYING, activity.getState()); 1523 } 1524 1525 /** 1526 * Test that the activity will be moved to destroyed state immediately if it was not marked as 1527 * finishing before {@link ActivityRecord#destroyImmediately(String)}. 1528 */ 1529 @Test testDestroyImmediately_hadApp_notFinishing()1530 public void testDestroyImmediately_hadApp_notFinishing() { 1531 final ActivityRecord activity = createActivityWithTask(); 1532 activity.finishing = false; 1533 activity.destroyImmediately("test"); 1534 1535 assertEquals(DESTROYED, activity.getState()); 1536 } 1537 1538 /** 1539 * Test that an activity with no process attached and that is marked as finishing will be 1540 * removed from task when {@link ActivityRecord#destroyImmediately(String)} is called. 1541 */ 1542 @Test testDestroyImmediately_noApp_finishing()1543 public void testDestroyImmediately_noApp_finishing() { 1544 final ActivityRecord activity = createActivityWithTask(); 1545 activity.app = null; 1546 activity.finishing = true; 1547 final Task task = activity.getTask(); 1548 1549 activity.destroyImmediately("test"); 1550 1551 assertEquals(DESTROYED, activity.getState()); 1552 assertNull(activity.getTask()); 1553 assertEquals(0, task.getChildCount()); 1554 } 1555 1556 /** 1557 * Test that an activity with no process attached and that is not marked as finishing will be 1558 * marked as DESTROYED but not removed from task. 1559 */ 1560 @Test testDestroyImmediately_noApp_notFinishing()1561 public void testDestroyImmediately_noApp_notFinishing() { 1562 final ActivityRecord activity = createActivityWithTask(); 1563 activity.app = null; 1564 activity.finishing = false; 1565 final Task task = activity.getTask(); 1566 1567 activity.destroyImmediately("test"); 1568 1569 assertEquals(DESTROYED, activity.getState()); 1570 assertEquals(task, activity.getTask()); 1571 assertEquals(1, task.getChildCount()); 1572 } 1573 1574 /** 1575 * Test that an activity will not be destroyed if it is marked as non-destroyable. 1576 */ 1577 @Test testSafelyDestroy_nonDestroyable()1578 public void testSafelyDestroy_nonDestroyable() { 1579 final ActivityRecord activity = createActivityWithTask(); 1580 doReturn(false).when(activity).isDestroyable(); 1581 1582 activity.safelyDestroy("test"); 1583 1584 verify(activity, never()).destroyImmediately(anyString()); 1585 } 1586 1587 /** 1588 * Test that an activity will not be destroyed if it is marked as non-destroyable. 1589 */ 1590 @Test testSafelyDestroy_destroyable()1591 public void testSafelyDestroy_destroyable() { 1592 final ActivityRecord activity = createActivityWithTask(); 1593 doReturn(true).when(activity).isDestroyable(); 1594 1595 activity.safelyDestroy("test"); 1596 1597 verify(activity).destroyImmediately(anyString()); 1598 } 1599 1600 @Test testRemoveImmediately()1601 public void testRemoveImmediately() throws RemoteException { 1602 final ActivityRecord activity = createActivityWithTask(); 1603 final WindowProcessController wpc = activity.app; 1604 activity.getTask().removeImmediately("test"); 1605 1606 verify(mAtm.getLifecycleManager()).scheduleTransaction(any(), eq(activity.appToken), 1607 isA(DestroyActivityItem.class)); 1608 assertNull(activity.app); 1609 assertEquals(DESTROYED, activity.getState()); 1610 assertFalse(wpc.hasActivities()); 1611 } 1612 1613 @Test testRemoveFromHistory()1614 public void testRemoveFromHistory() { 1615 final ActivityRecord activity = createActivityWithTask(); 1616 final Task rootTask = activity.getRootTask(); 1617 final Task task = activity.getTask(); 1618 final WindowProcessController wpc = activity.app; 1619 assertTrue(wpc.hasActivities()); 1620 1621 activity.removeFromHistory("test"); 1622 1623 assertEquals(DESTROYED, activity.getState()); 1624 assertNull(activity.app); 1625 assertNull(activity.getTask()); 1626 assertFalse(wpc.hasActivities()); 1627 assertEquals(0, task.getChildCount()); 1628 assertEquals(task.getRootTask(), task); 1629 assertEquals(0, rootTask.getChildCount()); 1630 } 1631 1632 /** 1633 * Test that it's not allowed to call {@link ActivityRecord#destroyed(String)} if activity is 1634 * not in destroying or destroyed state. 1635 */ 1636 @Test(expected = IllegalStateException.class) testDestroyed_notDestroying()1637 public void testDestroyed_notDestroying() { 1638 final ActivityRecord activity = createActivityWithTask(); 1639 activity.setState(STOPPED, "test"); 1640 activity.destroyed("test"); 1641 } 1642 1643 /** 1644 * Test that {@link ActivityRecord#destroyed(String)} can be called if an activity is destroying 1645 */ 1646 @Test testDestroyed_destroying()1647 public void testDestroyed_destroying() { 1648 final ActivityRecord activity = createActivityWithTask(); 1649 activity.setState(DESTROYING, "test"); 1650 activity.destroyed("test"); 1651 1652 verify(activity).removeFromHistory(anyString()); 1653 } 1654 1655 /** 1656 * Test that {@link ActivityRecord#destroyed(String)} can be called if an activity is destroyed. 1657 */ 1658 @Test testDestroyed_destroyed()1659 public void testDestroyed_destroyed() { 1660 final ActivityRecord activity = createActivityWithTask(); 1661 activity.setState(DESTROYED, "test"); 1662 activity.destroyed("test"); 1663 1664 verify(activity).removeFromHistory(anyString()); 1665 } 1666 1667 @Test testActivityOverridesProcessConfig()1668 public void testActivityOverridesProcessConfig() { 1669 final ActivityRecord activity = createActivityWithTask(); 1670 final WindowProcessController wpc = activity.app; 1671 assertTrue(wpc.registeredForActivityConfigChanges()); 1672 assertFalse(wpc.registeredForDisplayAreaConfigChanges()); 1673 1674 final ActivityRecord secondaryDisplayActivity = 1675 createActivityOnDisplay(false /* defaultDisplay */, null /* process */); 1676 1677 assertTrue(wpc.registeredForActivityConfigChanges()); 1678 assertEquals(0, activity.getMergedOverrideConfiguration() 1679 .diff(wpc.getRequestedOverrideConfiguration())); 1680 assertNotEquals(activity.getConfiguration(), 1681 secondaryDisplayActivity.getConfiguration()); 1682 } 1683 1684 @Test testActivityOverridesProcessConfig_TwoActivities()1685 public void testActivityOverridesProcessConfig_TwoActivities() { 1686 final ActivityRecord activity = createActivityWithTask(); 1687 final WindowProcessController wpc = activity.app; 1688 assertTrue(wpc.registeredForActivityConfigChanges()); 1689 1690 final Task firstTaskRecord = activity.getTask(); 1691 final ActivityRecord secondActivityRecord = 1692 new ActivityBuilder(mAtm).setTask(firstTaskRecord).setUseProcess(wpc).build(); 1693 1694 assertTrue(wpc.registeredForActivityConfigChanges()); 1695 assertEquals(0, secondActivityRecord.getMergedOverrideConfiguration() 1696 .diff(wpc.getRequestedOverrideConfiguration())); 1697 } 1698 1699 @Test testActivityOverridesProcessConfig_TwoActivities_SecondaryDisplay()1700 public void testActivityOverridesProcessConfig_TwoActivities_SecondaryDisplay() { 1701 final ActivityRecord activity = createActivityWithTask(); 1702 final WindowProcessController wpc = activity.app; 1703 assertTrue(wpc.registeredForActivityConfigChanges()); 1704 1705 final ActivityRecord secondActivityRecord = 1706 new ActivityBuilder(mAtm).setTask(activity.getTask()).setUseProcess(wpc).build(); 1707 1708 assertTrue(wpc.registeredForActivityConfigChanges()); 1709 assertEquals(0, secondActivityRecord.getMergedOverrideConfiguration() 1710 .diff(wpc.getRequestedOverrideConfiguration())); 1711 } 1712 1713 @Test testActivityOverridesProcessConfig_TwoActivities_DifferentTasks()1714 public void testActivityOverridesProcessConfig_TwoActivities_DifferentTasks() { 1715 final ActivityRecord activity = createActivityWithTask(); 1716 final WindowProcessController wpc = activity.app; 1717 assertTrue(wpc.registeredForActivityConfigChanges()); 1718 1719 final ActivityRecord secondActivityRecord = 1720 createActivityOnDisplay(true /* defaultDisplay */, wpc); 1721 1722 assertTrue(wpc.registeredForActivityConfigChanges()); 1723 assertEquals(0, secondActivityRecord.getMergedOverrideConfiguration() 1724 .diff(wpc.getRequestedOverrideConfiguration())); 1725 } 1726 1727 @Test testActivityOnCancelFixedRotationTransform()1728 public void testActivityOnCancelFixedRotationTransform() { 1729 final ActivityRecord activity = createActivityWithTask(); 1730 final DisplayRotation displayRotation = activity.mDisplayContent.getDisplayRotation(); 1731 spyOn(displayRotation); 1732 1733 final DisplayContent display = activity.mDisplayContent; 1734 final int originalRotation = display.getRotation(); 1735 1736 // Make {@link DisplayContent#sendNewConfiguration} not apply rotation immediately. 1737 doReturn(true).when(displayRotation).isWaitingForRemoteRotation(); 1738 doReturn((originalRotation + 1) % 4).when(displayRotation).rotationForOrientation( 1739 anyInt() /* orientation */, anyInt() /* lastRotation */); 1740 // Set to visible so the activity can freeze the screen. 1741 activity.setVisibility(true); 1742 1743 display.rotateInDifferentOrientationIfNeeded(activity); 1744 display.setFixedRotationLaunchingAppUnchecked(activity); 1745 displayRotation.updateRotationUnchecked(true /* forceUpdate */); 1746 1747 assertTrue(displayRotation.isRotatingSeamlessly()); 1748 1749 // The launching rotated app should not be cleared when waiting for remote rotation. 1750 display.continueUpdateOrientationForDiffOrienLaunchingApp(); 1751 assertTrue(display.isFixedRotationLaunchingApp(activity)); 1752 1753 // Simulate the rotation has been updated to previous one, e.g. sensor updates before the 1754 // remote rotation is completed. 1755 doReturn(originalRotation).when(displayRotation).rotationForOrientation( 1756 anyInt() /* orientation */, anyInt() /* lastRotation */); 1757 display.updateOrientation(); 1758 1759 final DisplayInfo rotatedInfo = activity.getFixedRotationTransformDisplayInfo(); 1760 activity.finishFixedRotationTransform(); 1761 final ScreenRotationAnimation rotationAnim = display.getRotationAnimation(); 1762 assertNotNull(rotationAnim); 1763 rotationAnim.setRotation(display.getPendingTransaction(), originalRotation); 1764 1765 // Because the display doesn't rotate, the rotated activity needs to cancel the fixed 1766 // rotation. There should be a rotation animation to cover the change of activity. 1767 verify(activity).onCancelFixedRotationTransform(rotatedInfo.rotation); 1768 assertTrue(activity.isFreezingScreen()); 1769 assertFalse(displayRotation.isRotatingSeamlessly()); 1770 assertTrue(rotationAnim.isRotating()); 1771 1772 // Simulate the remote rotation has completed and the configuration doesn't change, then 1773 // the rotated activity should also be restored by clearing the transform. 1774 displayRotation.updateRotationUnchecked(true /* forceUpdate */); 1775 doReturn(false).when(displayRotation).isWaitingForRemoteRotation(); 1776 clearInvocations(activity); 1777 display.setFixedRotationLaunchingAppUnchecked(activity); 1778 display.sendNewConfiguration(); 1779 1780 assertFalse(display.hasTopFixedRotationLaunchingApp()); 1781 assertFalse(activity.hasFixedRotationTransform()); 1782 1783 // Simulate that the activity requests the same orientation as display. 1784 activity.setOrientation(display.getConfiguration().orientation); 1785 // Skip the real freezing. 1786 activity.mVisibleRequested = false; 1787 clearInvocations(activity); 1788 activity.onCancelFixedRotationTransform(originalRotation); 1789 // The implementation of cancellation must be executed. 1790 verify(activity).startFreezingScreen(originalRotation); 1791 } 1792 1793 @Test testIsSnapshotCompatible()1794 public void testIsSnapshotCompatible() { 1795 final ActivityRecord activity = createActivityWithTask(); 1796 final TaskSnapshot snapshot = new TaskSnapshotPersisterTestBase.TaskSnapshotBuilder() 1797 .setTopActivityComponent(activity.mActivityComponent) 1798 .setRotation(activity.getWindowConfiguration().getRotation()) 1799 .build(); 1800 1801 assertTrue(activity.isSnapshotCompatible(snapshot)); 1802 1803 setRotatedScreenOrientationSilently(activity); 1804 1805 assertFalse(activity.isSnapshotCompatible(snapshot)); 1806 } 1807 1808 /** 1809 * Test that the snapshot should be obsoleted if the top activity changed. 1810 */ 1811 @Test testIsSnapshotCompatibleTopActivityChanged()1812 public void testIsSnapshotCompatibleTopActivityChanged() { 1813 final ActivityRecord activity = createActivityWithTask(); 1814 final ActivityRecord secondActivity = new ActivityBuilder(mAtm) 1815 .setTask(activity.getTask()) 1816 .setOnTop(true) 1817 .build(); 1818 final TaskSnapshot snapshot = new TaskSnapshotPersisterTestBase.TaskSnapshotBuilder() 1819 .setTopActivityComponent(secondActivity.mActivityComponent) 1820 .build(); 1821 1822 assertTrue(secondActivity.isSnapshotCompatible(snapshot)); 1823 1824 // Emulate the top activity changed. 1825 assertFalse(activity.isSnapshotCompatible(snapshot)); 1826 } 1827 1828 @Test testFixedRotationSnapshotStartingWindow()1829 public void testFixedRotationSnapshotStartingWindow() { 1830 final ActivityRecord activity = createActivityWithTask(); 1831 // TaskSnapshotSurface requires a fullscreen opaque window. 1832 final WindowManager.LayoutParams params = new WindowManager.LayoutParams( 1833 WindowManager.LayoutParams.TYPE_APPLICATION_STARTING); 1834 params.width = params.height = WindowManager.LayoutParams.MATCH_PARENT; 1835 final TestWindowState w = new TestWindowState( 1836 mAtm.mWindowManager, mock(Session.class), new TestIWindow(), params, activity); 1837 activity.addWindow(w); 1838 1839 // Assume the activity is launching in different rotation, and there was an available 1840 // snapshot accepted by {@link Activity#isSnapshotCompatible}. 1841 final TaskSnapshot snapshot = new TaskSnapshotPersisterTestBase.TaskSnapshotBuilder() 1842 .setRotation((activity.getWindowConfiguration().getRotation() + 1) % 4) 1843 .build(); 1844 setRotatedScreenOrientationSilently(activity); 1845 activity.setVisible(false); 1846 1847 final IWindowSession session = WindowManagerGlobal.getWindowSession(); 1848 spyOn(session); 1849 try { 1850 // Return error to skip unnecessary operation. 1851 doReturn(WindowManagerGlobal.ADD_STARTING_NOT_NEEDED).when(session).addToDisplay( 1852 any() /* window */, any() /* attrs */, 1853 anyInt() /* viewVisibility */, anyInt() /* displayId */, 1854 any() /* requestedVisibility */, any() /* outInputChannel */, 1855 any() /* outInsetsState */, any() /* outActiveControls */); 1856 mAtm.mWindowManager.mStartingSurfaceController 1857 .createTaskSnapshotSurface(activity, snapshot); 1858 } catch (RemoteException ignored) { 1859 } finally { 1860 reset(session); 1861 } 1862 1863 // Because the rotation of snapshot and the corresponding top activity are different, fixed 1864 // rotation should be applied when creating snapshot surface if the display rotation may be 1865 // changed according to the activity orientation. 1866 assertTrue(activity.hasFixedRotationTransform()); 1867 assertTrue(activity.mDisplayContent.isFixedRotationLaunchingApp(activity)); 1868 } 1869 1870 /** 1871 * Sets orientation without notifying the parent to simulate that the display has not applied 1872 * the requested orientation yet. 1873 */ setRotatedScreenOrientationSilently(ActivityRecord r)1874 static void setRotatedScreenOrientationSilently(ActivityRecord r) { 1875 final int rotatedOrentation = r.getConfiguration().orientation == ORIENTATION_PORTRAIT 1876 ? SCREEN_ORIENTATION_LANDSCAPE 1877 : SCREEN_ORIENTATION_PORTRAIT; 1878 doReturn(false).when(r).onDescendantOrientationChanged(any()); 1879 r.setOrientation(rotatedOrentation); 1880 } 1881 1882 @Test testActivityOnDifferentDisplayUpdatesProcessOverride()1883 public void testActivityOnDifferentDisplayUpdatesProcessOverride() { 1884 final ActivityRecord secondaryDisplayActivity = 1885 createActivityOnDisplay(false /* defaultDisplay */, null /* process */); 1886 final WindowProcessController wpc = secondaryDisplayActivity.app; 1887 assertTrue(wpc.registeredForActivityConfigChanges()); 1888 1889 final ActivityRecord secondActivityRecord = 1890 createActivityOnDisplay(true /* defaultDisplay */, wpc); 1891 1892 assertTrue(wpc.registeredForActivityConfigChanges()); 1893 assertEquals(0, secondActivityRecord.getMergedOverrideConfiguration() 1894 .diff(wpc.getRequestedOverrideConfiguration())); 1895 assertFalse(wpc.registeredForDisplayAreaConfigChanges()); 1896 } 1897 1898 @Test testActivityReparentChangesProcessOverride()1899 public void testActivityReparentChangesProcessOverride() { 1900 final ActivityRecord activity = createActivityWithTask(); 1901 final WindowProcessController wpc = activity.app; 1902 final Task initialTask = activity.getTask(); 1903 final Configuration initialConf = 1904 new Configuration(activity.getMergedOverrideConfiguration()); 1905 assertEquals(0, activity.getMergedOverrideConfiguration() 1906 .diff(wpc.getRequestedOverrideConfiguration())); 1907 assertTrue(wpc.registeredForActivityConfigChanges()); 1908 1909 // Create a new task with custom config to reparent the activity to. 1910 final Task newTask = 1911 new TaskBuilder(mSupervisor).setParentTask(initialTask.getRootTask()).build(); 1912 final Configuration newConfig = newTask.getConfiguration(); 1913 newConfig.densityDpi += 100; 1914 newTask.onRequestedOverrideConfigurationChanged(newConfig); 1915 assertEquals(newTask.getConfiguration().densityDpi, newConfig.densityDpi); 1916 1917 // Reparent the activity and verify that config override changed. 1918 activity.reparent(newTask, 0 /* top */, "test"); 1919 assertEquals(activity.getConfiguration().densityDpi, newConfig.densityDpi); 1920 assertEquals(activity.getMergedOverrideConfiguration().densityDpi, newConfig.densityDpi); 1921 1922 assertTrue(wpc.registeredForActivityConfigChanges()); 1923 assertNotEquals(initialConf, wpc.getRequestedOverrideConfiguration()); 1924 assertEquals(0, activity.getMergedOverrideConfiguration() 1925 .diff(wpc.getRequestedOverrideConfiguration())); 1926 } 1927 1928 @Test testActivityReparentDoesntClearProcessOverride_TwoActivities()1929 public void testActivityReparentDoesntClearProcessOverride_TwoActivities() { 1930 final ActivityRecord activity = createActivityWithTask(); 1931 final WindowProcessController wpc = activity.app; 1932 final Configuration initialConf = 1933 new Configuration(activity.getMergedOverrideConfiguration()); 1934 final Task initialTask = activity.getTask(); 1935 final ActivityRecord secondActivity = new ActivityBuilder(mAtm).setTask(initialTask) 1936 .setUseProcess(wpc).build(); 1937 1938 assertTrue(wpc.registeredForActivityConfigChanges()); 1939 assertEquals(0, secondActivity.getMergedOverrideConfiguration() 1940 .diff(wpc.getRequestedOverrideConfiguration())); 1941 1942 // Create a new task with custom config to reparent the second activity to. 1943 final Task newTask = 1944 new TaskBuilder(mSupervisor).setParentTask(initialTask.getRootTask()).build(); 1945 final Configuration newConfig = newTask.getConfiguration(); 1946 newConfig.densityDpi += 100; 1947 newTask.onRequestedOverrideConfigurationChanged(newConfig); 1948 1949 // Reparent the activity and verify that config override changed. 1950 secondActivity.reparent(newTask, 0 /* top */, "test"); 1951 1952 assertTrue(wpc.registeredForActivityConfigChanges()); 1953 assertEquals(0, secondActivity.getMergedOverrideConfiguration() 1954 .diff(wpc.getRequestedOverrideConfiguration())); 1955 assertNotEquals(initialConf, wpc.getRequestedOverrideConfiguration()); 1956 1957 // Reparent the first activity and verify that config override didn't change. 1958 activity.reparent(newTask, 1 /* top */, "test"); 1959 assertTrue(wpc.registeredForActivityConfigChanges()); 1960 assertEquals(0, secondActivity.getMergedOverrideConfiguration() 1961 .diff(wpc.getRequestedOverrideConfiguration())); 1962 assertNotEquals(initialConf, wpc.getRequestedOverrideConfiguration()); 1963 } 1964 1965 @Test testActivityDestroyDoesntChangeProcessOverride()1966 public void testActivityDestroyDoesntChangeProcessOverride() { 1967 final ActivityRecord firstActivity = 1968 createActivityOnDisplay(true /* defaultDisplay */, null /* process */); 1969 final WindowProcessController wpc = firstActivity.app; 1970 assertTrue(wpc.registeredForActivityConfigChanges()); 1971 assertEquals(0, firstActivity.getMergedOverrideConfiguration() 1972 .diff(wpc.getRequestedOverrideConfiguration())); 1973 1974 final ActivityRecord secondActivity = 1975 createActivityOnDisplay(false /* defaultDisplay */, wpc); 1976 assertTrue(wpc.registeredForActivityConfigChanges()); 1977 assertEquals(0, secondActivity.getMergedOverrideConfiguration() 1978 .diff(wpc.getRequestedOverrideConfiguration())); 1979 1980 final ActivityRecord thirdActivity = 1981 createActivityOnDisplay(false /* defaultDisplay */, wpc); 1982 assertTrue(wpc.registeredForActivityConfigChanges()); 1983 assertEquals(0, thirdActivity.getMergedOverrideConfiguration() 1984 .diff(wpc.getRequestedOverrideConfiguration())); 1985 1986 secondActivity.destroyImmediately(""); 1987 1988 assertTrue(wpc.registeredForActivityConfigChanges()); 1989 assertEquals(0, thirdActivity.getMergedOverrideConfiguration() 1990 .diff(wpc.getRequestedOverrideConfiguration())); 1991 1992 firstActivity.destroyImmediately(""); 1993 1994 assertTrue(wpc.registeredForActivityConfigChanges()); 1995 assertEquals(0, thirdActivity.getMergedOverrideConfiguration() 1996 .diff(wpc.getRequestedOverrideConfiguration())); 1997 } 1998 1999 @Test testFullscreenWindowCanTurnScreenOn()2000 public void testFullscreenWindowCanTurnScreenOn() { 2001 final ActivityRecord activity = createActivityWithTask(); 2002 final Task task = activity.getTask(); 2003 task.setWindowingMode(WINDOWING_MODE_FULLSCREEN); 2004 doReturn(true).when(activity).getTurnScreenOnFlag(); 2005 2006 assertTrue(activity.canTurnScreenOn()); 2007 } 2008 2009 @Test testFreeformWindowCanTurnScreenOn()2010 public void testFreeformWindowCanTurnScreenOn() { 2011 final ActivityRecord activity = createActivityWithTask(); 2012 final Task task = activity.getTask(); 2013 task.setWindowingMode(WINDOWING_MODE_FREEFORM); 2014 doReturn(true).when(activity).getTurnScreenOnFlag(); 2015 2016 assertTrue(activity.canTurnScreenOn()); 2017 } 2018 2019 @Test testGetLockTaskLaunchMode()2020 public void testGetLockTaskLaunchMode() { 2021 final ActivityRecord activity = createActivityWithTask(); 2022 final ActivityOptions options = ActivityOptions.makeBasic().setLockTaskEnabled(true); 2023 activity.info.lockTaskLaunchMode = LOCK_TASK_LAUNCH_MODE_DEFAULT; 2024 assertEquals(LOCK_TASK_LAUNCH_MODE_IF_ALLOWLISTED, 2025 ActivityRecord.getLockTaskLaunchMode(activity.info, options)); 2026 2027 activity.info.lockTaskLaunchMode = LOCK_TASK_LAUNCH_MODE_ALWAYS; 2028 assertEquals(LOCK_TASK_LAUNCH_MODE_DEFAULT, 2029 ActivityRecord.getLockTaskLaunchMode(activity.info, null /*options*/)); 2030 2031 activity.info.lockTaskLaunchMode = LOCK_TASK_LAUNCH_MODE_NEVER; 2032 assertEquals(LOCK_TASK_LAUNCH_MODE_DEFAULT, 2033 ActivityRecord.getLockTaskLaunchMode(activity.info, null /*options*/)); 2034 2035 activity.info.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_PRIVILEGED; 2036 activity.info.lockTaskLaunchMode = LOCK_TASK_LAUNCH_MODE_ALWAYS; 2037 assertEquals(LOCK_TASK_LAUNCH_MODE_ALWAYS, 2038 ActivityRecord.getLockTaskLaunchMode(activity.info, null /*options*/)); 2039 2040 activity.info.lockTaskLaunchMode = LOCK_TASK_LAUNCH_MODE_NEVER; 2041 assertEquals(LOCK_TASK_LAUNCH_MODE_NEVER, 2042 ActivityRecord.getLockTaskLaunchMode(activity.info, null /*options*/)); 2043 2044 } 2045 2046 @Test testProcessInfoUpdateWhenSetState()2047 public void testProcessInfoUpdateWhenSetState() { 2048 final ActivityRecord activity = createActivityWithTask(); 2049 activity.setState(INITIALIZING, "test"); 2050 spyOn(activity.app); 2051 verifyProcessInfoUpdate(activity, RESUMED, 2052 true /* shouldUpdate */, true /* activityChange */); 2053 verifyProcessInfoUpdate(activity, PAUSED, 2054 false /* shouldUpdate */, false /* activityChange */); 2055 verifyProcessInfoUpdate(activity, STOPPED, 2056 false /* shouldUpdate */, false /* activityChange */); 2057 verifyProcessInfoUpdate(activity, STARTED, 2058 true /* shouldUpdate */, true /* activityChange */); 2059 2060 activity.app.removeActivity(activity, true /* keepAssociation */); 2061 verifyProcessInfoUpdate(activity, DESTROYING, 2062 true /* shouldUpdate */, false /* activityChange */); 2063 verifyProcessInfoUpdate(activity, DESTROYED, 2064 true /* shouldUpdate */, false /* activityChange */); 2065 } 2066 2067 @Test testSupportsSplitScreenWindowingMode()2068 public void testSupportsSplitScreenWindowingMode() { 2069 final ActivityRecord activity = new ActivityBuilder(mAtm) 2070 .setCreateTask(true) 2071 .setResizeMode(ActivityInfo.RESIZE_MODE_UNRESIZEABLE) 2072 .setScreenOrientation(SCREEN_ORIENTATION_LANDSCAPE) 2073 .build(); 2074 2075 // Not allow non-resizable 2076 mAtm.mForceResizableActivities = false; 2077 mAtm.mSupportsNonResizableMultiWindow = -1; 2078 mAtm.mDevEnableNonResizableMultiWindow = false; 2079 assertFalse(activity.supportsSplitScreenWindowingMode()); 2080 2081 // Force resizable 2082 mAtm.mForceResizableActivities = true; 2083 mAtm.mSupportsNonResizableMultiWindow = -1; 2084 mAtm.mDevEnableNonResizableMultiWindow = false; 2085 assertTrue(activity.supportsSplitScreenWindowingMode()); 2086 2087 // Use development option to allow non-resizable 2088 mAtm.mForceResizableActivities = false; 2089 mAtm.mSupportsNonResizableMultiWindow = -1; 2090 mAtm.mDevEnableNonResizableMultiWindow = true; 2091 assertTrue(activity.supportsSplitScreenWindowingMode()); 2092 2093 // Always allow non-resizable 2094 mAtm.mForceResizableActivities = false; 2095 mAtm.mSupportsNonResizableMultiWindow = 1; 2096 mAtm.mDevEnableNonResizableMultiWindow = false; 2097 assertTrue(activity.supportsSplitScreenWindowingMode()); 2098 } 2099 2100 @Test testSupportsFreeform()2101 public void testSupportsFreeform() { 2102 final ActivityRecord activity = new ActivityBuilder(mAtm) 2103 .setCreateTask(true) 2104 .setResizeMode(ActivityInfo.RESIZE_MODE_UNRESIZEABLE) 2105 .setScreenOrientation(SCREEN_ORIENTATION_LANDSCAPE) 2106 .build(); 2107 2108 // Not allow non-resizable 2109 mAtm.mForceResizableActivities = false; 2110 mAtm.mSupportsNonResizableMultiWindow = -1; 2111 mAtm.mDevEnableNonResizableMultiWindow = false; 2112 assertFalse(activity.supportsFreeform()); 2113 2114 // Force resizable 2115 mAtm.mForceResizableActivities = true; 2116 mAtm.mSupportsNonResizableMultiWindow = -1; 2117 mAtm.mDevEnableNonResizableMultiWindow = false; 2118 assertTrue(activity.supportsFreeform()); 2119 2120 // Use development option to allow non-resizable 2121 mAtm.mForceResizableActivities = false; 2122 mAtm.mSupportsNonResizableMultiWindow = -1; 2123 mAtm.mDevEnableNonResizableMultiWindow = true; 2124 assertTrue(activity.supportsFreeform()); 2125 2126 // Always allow non-resizable 2127 mAtm.mForceResizableActivities = false; 2128 mAtm.mSupportsNonResizableMultiWindow = 1; 2129 mAtm.mDevEnableNonResizableMultiWindow = false; 2130 assertTrue(activity.supportsFreeform()); 2131 } 2132 2133 @Test testSupportsPictureInPicture()2134 public void testSupportsPictureInPicture() { 2135 final ActivityRecord activity = new ActivityBuilder(mAtm) 2136 .setCreateTask(true) 2137 .setResizeMode(ActivityInfo.RESIZE_MODE_UNRESIZEABLE) 2138 .setActivityFlags(FLAG_SUPPORTS_PICTURE_IN_PICTURE) 2139 .build(); 2140 2141 // Device not supports PIP 2142 mAtm.mSupportsPictureInPicture = false; 2143 assertFalse(activity.supportsPictureInPicture()); 2144 2145 // Device and app support PIP 2146 mAtm.mSupportsPictureInPicture = true; 2147 assertTrue(activity.supportsPictureInPicture()); 2148 2149 // Activity not supports PIP 2150 activity.info.flags &= ~FLAG_SUPPORTS_PICTURE_IN_PICTURE; 2151 assertFalse(activity.supportsPictureInPicture()); 2152 } 2153 verifyProcessInfoUpdate(ActivityRecord activity, ActivityState state, boolean shouldUpdate, boolean activityChange)2154 private void verifyProcessInfoUpdate(ActivityRecord activity, ActivityState state, 2155 boolean shouldUpdate, boolean activityChange) { 2156 reset(activity.app); 2157 activity.setState(state, "test"); 2158 verify(activity.app, times(shouldUpdate ? 1 : 0)).updateProcessInfo(anyBoolean(), 2159 eq(activityChange), anyBoolean(), anyBoolean()); 2160 } 2161 createActivityWithTask()2162 private ActivityRecord createActivityWithTask() { 2163 return new ActivityBuilder(mAtm).setCreateTask(true).setOnTop(true).build(); 2164 } 2165 createActivityWith2LevelTask()2166 private ActivityRecord createActivityWith2LevelTask() { 2167 final Task task = new TaskBuilder(mSupervisor) 2168 .setCreateParentTask(true).setCreateActivity(true).build(); 2169 return task.getTopNonFinishingActivity(); 2170 } 2171 2172 /** 2173 * Creates an activity on display. For non-default display request it will also create a new 2174 * display with custom DisplayInfo. 2175 */ createActivityOnDisplay(boolean defaultDisplay, WindowProcessController process)2176 private ActivityRecord createActivityOnDisplay(boolean defaultDisplay, 2177 WindowProcessController process) { 2178 final DisplayContent display; 2179 if (defaultDisplay) { 2180 display = mRootWindowContainer.getDefaultDisplay(); 2181 } else { 2182 display = new TestDisplayContent.Builder(mAtm, 2000, 1000).setDensityDpi(300) 2183 .setPosition(DisplayContent.POSITION_TOP).build(); 2184 } 2185 final Task task = new TaskBuilder(mSupervisor).setDisplay(display).build(); 2186 return new ActivityBuilder(mAtm).setTask(task).setUseProcess(process).build(); 2187 } 2188 2189 @Test 2190 @Presubmit testAddWindow_Order()2191 public void testAddWindow_Order() { 2192 final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build(); 2193 assertEquals(0, activity.getChildCount()); 2194 2195 final WindowState win1 = createWindow(null, TYPE_APPLICATION, activity, "win1"); 2196 final WindowState startingWin = createWindow(null, TYPE_APPLICATION_STARTING, activity, 2197 "startingWin"); 2198 final WindowState baseWin = createWindow(null, TYPE_BASE_APPLICATION, activity, "baseWin"); 2199 final WindowState win4 = createWindow(null, TYPE_APPLICATION, activity, "win4"); 2200 2201 // Should not contain the windows that were added above. 2202 assertEquals(4, activity.getChildCount()); 2203 assertTrue(activity.mChildren.contains(win1)); 2204 assertTrue(activity.mChildren.contains(startingWin)); 2205 assertTrue(activity.mChildren.contains(baseWin)); 2206 assertTrue(activity.mChildren.contains(win4)); 2207 2208 // The starting window should be on-top of all other windows. 2209 assertEquals(startingWin, activity.mChildren.peekLast()); 2210 2211 // The base application window should be below all other windows. 2212 assertEquals(baseWin, activity.mChildren.peekFirst()); 2213 activity.removeImmediately(); 2214 } 2215 2216 @Test 2217 @Presubmit testFindMainWindow()2218 public void testFindMainWindow() { 2219 final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build(); 2220 assertNull(activity.findMainWindow()); 2221 2222 final WindowState window1 = createWindow(null, TYPE_BASE_APPLICATION, activity, "window1"); 2223 final WindowState window11 = createWindow(window1, FIRST_SUB_WINDOW, activity, "window11"); 2224 final WindowState window12 = createWindow(window1, FIRST_SUB_WINDOW, activity, "window12"); 2225 assertEquals(window1, activity.findMainWindow()); 2226 window1.mAnimatingExit = true; 2227 assertEquals(window1, activity.findMainWindow()); 2228 final WindowState window2 = createWindow(null, TYPE_APPLICATION_STARTING, activity, 2229 "window2"); 2230 assertEquals(window2, activity.findMainWindow()); 2231 activity.removeImmediately(); 2232 } 2233 2234 @Test 2235 @Presubmit testGetTopFullscreenOpaqueWindow()2236 public void testGetTopFullscreenOpaqueWindow() { 2237 final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build(); 2238 assertNull(activity.getTopFullscreenOpaqueWindow()); 2239 2240 final WindowState window1 = createWindow(null, TYPE_BASE_APPLICATION, activity, "window1"); 2241 final WindowState window11 = createWindow(null, TYPE_APPLICATION, activity, "window11"); 2242 final WindowState window12 = createWindow(null, TYPE_APPLICATION, activity, "window12"); 2243 assertEquals(window12, activity.getTopFullscreenOpaqueWindow()); 2244 window12.mAttrs.width = 500; 2245 assertEquals(window11, activity.getTopFullscreenOpaqueWindow()); 2246 window11.mAttrs.width = 500; 2247 assertEquals(window1, activity.getTopFullscreenOpaqueWindow()); 2248 window1.mAttrs.alpha = 0f; 2249 assertNull(activity.getTopFullscreenOpaqueWindow()); 2250 activity.removeImmediately(); 2251 } 2252 2253 @UseTestDisplay(addWindows = W_ACTIVITY) 2254 @Test testLandscapeSeascapeRotationByApp()2255 public void testLandscapeSeascapeRotationByApp() { 2256 final Task task = new TaskBuilder(mSupervisor) 2257 .setDisplay(mDisplayContent).setCreateActivity(true).build(); 2258 final ActivityRecord activity = task.getTopNonFinishingActivity(); 2259 final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams( 2260 TYPE_BASE_APPLICATION); 2261 attrs.setTitle("AppWindow"); 2262 final TestWindowState appWindow = createWindowState(attrs, activity); 2263 activity.addWindow(appWindow); 2264 spyOn(appWindow); 2265 doNothing().when(appWindow).onStartFreezingScreen(); 2266 2267 // Set initial orientation and update. 2268 activity.setOrientation(SCREEN_ORIENTATION_LANDSCAPE); 2269 mDisplayContent.updateOrientation( 2270 mDisplayContent.getRequestedOverrideConfiguration(), 2271 null /* freezeThisOneIfNeeded */, false /* forceUpdate */); 2272 assertEquals(SCREEN_ORIENTATION_LANDSCAPE, mDisplayContent.getLastOrientation()); 2273 appWindow.mResizeReported = false; 2274 2275 // Update the orientation to perform 180 degree rotation and check that resize was reported. 2276 activity.setOrientation(SCREEN_ORIENTATION_REVERSE_LANDSCAPE); 2277 mDisplayContent.updateOrientation( 2278 mDisplayContent.getRequestedOverrideConfiguration(), 2279 null /* freezeThisOneIfNeeded */, false /* forceUpdate */); 2280 // In this test, DC will not get config update. Set the waiting flag to false. 2281 mDisplayContent.mWaitingForConfig = false; 2282 mWm.mRoot.performSurfacePlacement(); 2283 assertEquals(SCREEN_ORIENTATION_REVERSE_LANDSCAPE, mDisplayContent.getLastOrientation()); 2284 assertTrue(appWindow.mResizeReported); 2285 appWindow.removeImmediately(); 2286 } 2287 2288 @UseTestDisplay(addWindows = W_ACTIVITY) 2289 @Test testLandscapeSeascapeRotationByPolicy()2290 public void testLandscapeSeascapeRotationByPolicy() { 2291 final Task task = new TaskBuilder(mSupervisor) 2292 .setDisplay(mDisplayContent).setCreateActivity(true).build(); 2293 final ActivityRecord activity = task.getTopNonFinishingActivity(); 2294 // This instance has been spied in {@link TestDisplayContent}. 2295 final DisplayRotation displayRotation = mDisplayContent.getDisplayRotation(); 2296 2297 final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams( 2298 TYPE_BASE_APPLICATION); 2299 attrs.setTitle("RotationByPolicy"); 2300 final TestWindowState appWindow = createWindowState(attrs, activity); 2301 activity.addWindow(appWindow); 2302 spyOn(appWindow); 2303 doNothing().when(appWindow).onStartFreezingScreen(); 2304 2305 // Set initial orientation and update. 2306 performRotation(displayRotation, Surface.ROTATION_90); 2307 appWindow.mResizeReported = false; 2308 2309 // Update the rotation to perform 180 degree rotation and check that resize was reported. 2310 performRotation(displayRotation, Surface.ROTATION_270); 2311 assertTrue(appWindow.mResizeReported); 2312 2313 appWindow.removeImmediately(); 2314 } 2315 performRotation(DisplayRotation spiedRotation, int rotationToReport)2316 private void performRotation(DisplayRotation spiedRotation, int rotationToReport) { 2317 doReturn(rotationToReport).when(spiedRotation).rotationForOrientation(anyInt(), anyInt()); 2318 mWm.updateRotation(false, false); 2319 } 2320 2321 @Test 2322 @Presubmit testGetOrientation()2323 public void testGetOrientation() { 2324 // ActivityBuilder will resume top activities and cause the activity been added into 2325 // opening apps list. Since this test is focus on the effect of visible on getting 2326 // orientation, we skip app transition to avoid interference. 2327 doNothing().when(mDisplayContent).prepareAppTransition(anyInt()); 2328 final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build(); 2329 activity.setVisible(true); 2330 2331 activity.setOrientation(SCREEN_ORIENTATION_LANDSCAPE); 2332 2333 activity.setOccludesParent(false); 2334 // Can specify orientation if app doesn't occludes parent. 2335 assertEquals(SCREEN_ORIENTATION_LANDSCAPE, activity.getOrientation()); 2336 2337 activity.setOccludesParent(true); 2338 activity.setVisible(false); 2339 activity.mVisibleRequested = false; 2340 // Can not specify orientation if app isn't visible even though it occludes parent. 2341 assertEquals(SCREEN_ORIENTATION_UNSET, activity.getOrientation()); 2342 // Can specify orientation if the current orientation candidate is orientation behind. 2343 assertEquals(SCREEN_ORIENTATION_LANDSCAPE, 2344 activity.getOrientation(SCREEN_ORIENTATION_BEHIND)); 2345 } 2346 2347 @Test 2348 @Presubmit testKeyguardFlagsDuringRelaunch()2349 public void testKeyguardFlagsDuringRelaunch() { 2350 final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build(); 2351 final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams( 2352 TYPE_BASE_APPLICATION); 2353 attrs.flags |= FLAG_SHOW_WHEN_LOCKED | FLAG_DISMISS_KEYGUARD; 2354 attrs.setTitle("AppWindow"); 2355 final TestWindowState appWindow = createWindowState(attrs, activity); 2356 2357 // Add window with show when locked flag 2358 activity.addWindow(appWindow); 2359 assertTrue(activity.containsShowWhenLockedWindow() 2360 && activity.containsDismissKeyguardWindow()); 2361 2362 // Start relaunching 2363 activity.startRelaunching(); 2364 assertTrue(activity.containsShowWhenLockedWindow() 2365 && activity.containsDismissKeyguardWindow()); 2366 2367 // Remove window and make sure that we still report back flag 2368 activity.removeChild(appWindow); 2369 assertTrue(activity.containsShowWhenLockedWindow() 2370 && activity.containsDismissKeyguardWindow()); 2371 2372 // Finish relaunching and ensure flag is now not reported 2373 activity.finishRelaunching(); 2374 assertFalse(activity.containsShowWhenLockedWindow() 2375 || activity.containsDismissKeyguardWindow()); 2376 } 2377 2378 @Test testStuckExitingWindow()2379 public void testStuckExitingWindow() { 2380 final WindowState closingWindow = createWindow(null, FIRST_APPLICATION_WINDOW, 2381 "closingWindow"); 2382 closingWindow.mAnimatingExit = true; 2383 closingWindow.mRemoveOnExit = true; 2384 closingWindow.mActivityRecord.commitVisibility( 2385 false /* visible */, true /* performLayout */); 2386 2387 // We pretended that we were running an exit animation, but that should have been cleared up 2388 // by changing visibility of ActivityRecord 2389 closingWindow.removeIfPossible(); 2390 assertTrue(closingWindow.mRemoved); 2391 } 2392 2393 @Test testSetOrientation()2394 public void testSetOrientation() { 2395 final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build(); 2396 activity.setVisible(true); 2397 2398 // Assert orientation is unspecified to start. 2399 assertEquals(SCREEN_ORIENTATION_UNSPECIFIED, activity.getOrientation()); 2400 2401 activity.setOrientation(SCREEN_ORIENTATION_LANDSCAPE); 2402 assertEquals(SCREEN_ORIENTATION_LANDSCAPE, activity.getOrientation()); 2403 2404 mDisplayContent.removeAppToken(activity.token); 2405 // Assert orientation is unset to after container is removed. 2406 assertEquals(SCREEN_ORIENTATION_UNSET, activity.getOrientation()); 2407 2408 // Reset display frozen state 2409 mWm.mDisplayFrozen = false; 2410 } 2411 2412 @UseTestDisplay 2413 @Test testRespectTopFullscreenOrientation()2414 public void testRespectTopFullscreenOrientation() { 2415 final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build(); 2416 final Configuration displayConfig = activity.mDisplayContent.getConfiguration(); 2417 final Configuration activityConfig = activity.getConfiguration(); 2418 activity.setOrientation(SCREEN_ORIENTATION_PORTRAIT); 2419 2420 assertEquals(Configuration.ORIENTATION_PORTRAIT, displayConfig.orientation); 2421 assertEquals(Configuration.ORIENTATION_PORTRAIT, activityConfig.orientation); 2422 2423 final ActivityRecord topActivity = createActivityRecord(activity.getTask()); 2424 topActivity.setOrientation(SCREEN_ORIENTATION_LANDSCAPE); 2425 2426 assertEquals(Configuration.ORIENTATION_LANDSCAPE, displayConfig.orientation); 2427 // Although the activity requested portrait, it is not the top activity that determines 2428 // the display orientation. So it should be able to inherit the orientation from parent. 2429 // Otherwise its configuration will be inconsistent that its orientation is portrait but 2430 // other screen configurations are in landscape, e.g. screenWidthDp, screenHeightDp, and 2431 // window configuration. 2432 assertEquals(Configuration.ORIENTATION_LANDSCAPE, activityConfig.orientation); 2433 } 2434 2435 @UseTestDisplay 2436 @Test testReportOrientationChange()2437 public void testReportOrientationChange() { 2438 final Task task = new TaskBuilder(mSupervisor) 2439 .setDisplay(mDisplayContent).setCreateActivity(true).build(); 2440 final ActivityRecord activity = task.getTopNonFinishingActivity(); 2441 activity.setOrientation(SCREEN_ORIENTATION_LANDSCAPE); 2442 2443 mDisplayContent.getDisplayRotation().setFixedToUserRotation( 2444 IWindowManager.FIXED_TO_USER_ROTATION_ENABLED); 2445 reset(task); 2446 activity.reportDescendantOrientationChangeIfNeeded(); 2447 verify(task, atLeast(1)).onConfigurationChanged(any(Configuration.class)); 2448 } 2449 2450 @Test testCreateRemoveStartingWindow()2451 public void testCreateRemoveStartingWindow() { 2452 registerTestStartingWindowOrganizer(); 2453 final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build(); 2454 activity.addStartingWindow(mPackageName, 2455 android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true, 2456 false, false); 2457 waitUntilHandlersIdle(); 2458 assertHasStartingWindow(activity); 2459 activity.removeStartingWindow(); 2460 waitUntilHandlersIdle(); 2461 assertNoStartingWindow(activity); 2462 } 2463 testLegacySplashScreen(int targetSdk, int verifyType)2464 private void testLegacySplashScreen(int targetSdk, int verifyType) { 2465 final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build(); 2466 activity.mTargetSdk = targetSdk; 2467 activity.addStartingWindow(mPackageName, 2468 android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true, 2469 false, false); 2470 waitUntilHandlersIdle(); 2471 assertHasStartingWindow(activity); 2472 assertEquals(activity.mStartingData.mTypeParams & TYPE_PARAMETER_LEGACY_SPLASH_SCREEN, 2473 verifyType); 2474 activity.removeStartingWindow(); 2475 waitUntilHandlersIdle(); 2476 assertNoStartingWindow(activity); 2477 } 2478 2479 @Test testCreateRemoveLegacySplashScreenWindow()2480 public void testCreateRemoveLegacySplashScreenWindow() { 2481 registerTestStartingWindowOrganizer(); 2482 DeviceConfig.Properties properties = DeviceConfig.getProperties( 2483 DeviceConfig.NAMESPACE_WINDOW_MANAGER); 2484 try { 2485 DeviceConfig.setProperty(DeviceConfig.NAMESPACE_WINDOW_MANAGER, 2486 "splash_screen_exception_list", DEFAULT_COMPONENT_PACKAGE_NAME, false); 2487 testLegacySplashScreen(Build.VERSION_CODES.R, TYPE_PARAMETER_LEGACY_SPLASH_SCREEN); 2488 testLegacySplashScreen(Build.VERSION_CODES.S, 0); 2489 } finally { 2490 try { 2491 DeviceConfig.setProperties(properties); 2492 } catch (DeviceConfig.BadConfigException e) { 2493 Assert.fail(e.getMessage()); 2494 } 2495 } 2496 } 2497 2498 @Test testTransferStartingWindow()2499 public void testTransferStartingWindow() { 2500 registerTestStartingWindowOrganizer(); 2501 final ActivityRecord activity1 = new ActivityBuilder(mAtm).setCreateTask(true).build(); 2502 final ActivityRecord activity2 = new ActivityBuilder(mAtm).setCreateTask(true).build(); 2503 activity1.addStartingWindow(mPackageName, 2504 android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true, 2505 false, false); 2506 waitUntilHandlersIdle(); 2507 activity2.addStartingWindow(mPackageName, 2508 android.R.style.Theme, null, "Test", 0, 0, 0, 0, activity1.appToken.asBinder(), 2509 true, true, false, true, false, false); 2510 waitUntilHandlersIdle(); 2511 assertNoStartingWindow(activity1); 2512 assertHasStartingWindow(activity2); 2513 } 2514 2515 @Test testTransferStartingWindowWhileCreating()2516 public void testTransferStartingWindowWhileCreating() { 2517 final TestStartingWindowOrganizer organizer = registerTestStartingWindowOrganizer(); 2518 final ActivityRecord activity1 = new ActivityBuilder(mAtm).setCreateTask(true).build(); 2519 final ActivityRecord activity2 = new ActivityBuilder(mAtm).setCreateTask(true).build(); 2520 organizer.setRunnableWhenAddingSplashScreen( 2521 () -> { 2522 // Surprise, ...! Transfer window in the middle of the creation flow. 2523 activity2.addStartingWindow(mPackageName, 2524 android.R.style.Theme, null, "Test", 0, 0, 0, 0, 2525 activity1.appToken.asBinder(), true, true, false, 2526 true, false, false); 2527 }); 2528 activity1.addStartingWindow(mPackageName, 2529 android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true, 2530 false, false); 2531 waitUntilHandlersIdle(); 2532 assertNoStartingWindow(activity1); 2533 assertHasStartingWindow(activity2); 2534 } 2535 2536 @Test testTransferStartingWindowCanAnimate()2537 public void testTransferStartingWindowCanAnimate() { 2538 registerTestStartingWindowOrganizer(); 2539 final ActivityRecord activity1 = new ActivityBuilder(mAtm).setCreateTask(true).build(); 2540 final ActivityRecord activity2 = new ActivityBuilder(mAtm).setCreateTask(true).build(); 2541 activity1.addStartingWindow(mPackageName, 2542 android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true, 2543 false, false); 2544 waitUntilHandlersIdle(); 2545 activity2.addStartingWindow(mPackageName, 2546 android.R.style.Theme, null, "Test", 0, 0, 0, 0, activity1.appToken.asBinder(), 2547 true, true, false, true, false, false); 2548 waitUntilHandlersIdle(); 2549 assertNoStartingWindow(activity1); 2550 assertHasStartingWindow(activity2); 2551 2552 // Assert that bottom activity is allowed to do animation. 2553 ArrayList<WindowContainer> sources = new ArrayList<>(); 2554 sources.add(activity2); 2555 doReturn(true).when(activity2).okToAnimate(); 2556 doReturn(true).when(activity2).isAnimating(); 2557 assertTrue(activity2.applyAnimation(null, TRANSIT_OLD_ACTIVITY_OPEN, true, false, sources)); 2558 } 2559 @Test testTrackingStartingWindowThroughTrampoline()2560 public void testTrackingStartingWindowThroughTrampoline() { 2561 final ActivityRecord sourceRecord = new ActivityBuilder(mAtm) 2562 .setCreateTask(true).setLaunchedFromUid(Process.SYSTEM_UID).build(); 2563 sourceRecord.showStartingWindow(null /* prev */, true /* newTask */, false, 2564 true /* startActivity */, null); 2565 2566 final ActivityRecord secondRecord = new ActivityBuilder(mAtm) 2567 .setTask(sourceRecord.getTask()).build(); 2568 secondRecord.showStartingWindow(null /* prev */, true /* newTask */, false, 2569 true /* startActivity */, sourceRecord); 2570 assertFalse(secondRecord.mSplashScreenStyleEmpty); 2571 secondRecord.onStartingWindowDrawn(); 2572 2573 final ActivityRecord finalRecord = new ActivityBuilder(mAtm) 2574 .setTask(sourceRecord.getTask()).build(); 2575 finalRecord.showStartingWindow(null /* prev */, true /* newTask */, false, 2576 true /* startActivity */, secondRecord); 2577 assertTrue(finalRecord.mSplashScreenStyleEmpty); 2578 } 2579 2580 @Test testTransferStartingWindowFromFinishingActivity()2581 public void testTransferStartingWindowFromFinishingActivity() { 2582 registerTestStartingWindowOrganizer(); 2583 final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build(); 2584 final Task task = activity.getTask(); 2585 activity.addStartingWindow(mPackageName, android.R.style.Theme, null /* compatInfo */, 2586 "Test", 0 /* labelRes */, 0 /* icon */, 0 /* logo */, 0 /* windowFlags */, 2587 null /* transferFrom */, true /* newTask */, true /* taskSwitch */, 2588 false /* processRunning */, false /* allowTaskSnapshot */, 2589 false /* activityCreate */, false /* suggestEmpty */); 2590 waitUntilHandlersIdle(); 2591 assertHasStartingWindow(activity); 2592 activity.mStartingWindowState = ActivityRecord.STARTING_WINDOW_SHOWN; 2593 2594 doCallRealMethod().when(task).startActivityLocked( 2595 any(), any(), anyBoolean(), anyBoolean(), any(), any()); 2596 // In normal case, resumeFocusedTasksTopActivities() should be called after 2597 // startActivityLocked(). So skip resumeFocusedTasksTopActivities() in ActivityBuilder. 2598 doReturn(false).when(mRootWindowContainer).resumeFocusedTasksTopActivities(); 2599 // Make mVisibleSetFromTransferredStartingWindow true. 2600 final ActivityRecord middle = new ActivityBuilder(mAtm).setTask(task).build(); 2601 task.startActivityLocked(middle, null /* focusedTopActivity */, 2602 false /* newTask */, false /* keepCurTransition */, null /* options */, 2603 null /* sourceRecord */); 2604 middle.makeFinishingLocked(); 2605 2606 assertNull(activity.mStartingWindow); 2607 assertHasStartingWindow(middle); 2608 2609 final ActivityRecord top = new ActivityBuilder(mAtm).setTask(task).build(); 2610 // Expect the visibility should be updated to true when transferring starting window from 2611 // a visible activity. 2612 top.setVisible(false); 2613 // The finishing middle should be able to transfer starting window to top. 2614 task.startActivityLocked(top, null /* focusedTopActivity */, 2615 false /* newTask */, false /* keepCurTransition */, null /* options */, 2616 null /* sourceRecord */); 2617 2618 assertNull(middle.mStartingWindow); 2619 assertHasStartingWindow(top); 2620 assertTrue(top.isVisible()); 2621 // The activity was visible by mVisibleSetFromTransferredStartingWindow, so after its 2622 // starting window is transferred, it should restore to invisible. 2623 assertFalse(middle.isVisible()); 2624 } 2625 2626 @Test testTransferStartingWindowSetFixedRotation()2627 public void testTransferStartingWindowSetFixedRotation() { 2628 registerTestStartingWindowOrganizer(); 2629 final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build(); 2630 final Task task = activity.getTask(); 2631 final ActivityRecord topActivity = new ActivityBuilder(mAtm).setTask(task).build(); 2632 topActivity.setVisible(false); 2633 task.positionChildAt(topActivity, POSITION_TOP); 2634 activity.addStartingWindow(mPackageName, 2635 android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true, 2636 false, false); 2637 waitUntilHandlersIdle(); 2638 2639 // Make activities to have different rotation from it display and set fixed rotation 2640 // transform to activity1. 2641 int rotation = (mDisplayContent.getRotation() + 1) % 4; 2642 mDisplayContent.setFixedRotationLaunchingApp(activity, rotation); 2643 doReturn(rotation).when(mDisplayContent) 2644 .rotationForActivityInDifferentOrientation(topActivity); 2645 2646 // The transform will be finished because there is no running animation. Keep activity in 2647 // animating state to avoid the transform being finished. 2648 doReturn(true).when(activity).isAnimating(anyInt()); 2649 // Make sure the fixed rotation transform linked to activity2 when adding starting window 2650 // on activity2. 2651 topActivity.addStartingWindow(mPackageName, 2652 android.R.style.Theme, null, "Test", 0, 0, 0, 0, activity.appToken.asBinder(), 2653 false, false, false, true, false, false); 2654 waitUntilHandlersIdle(); 2655 assertTrue(topActivity.hasFixedRotationTransform()); 2656 } 2657 2658 @Test testTryTransferStartingWindowFromHiddenAboveToken()2659 public void testTryTransferStartingWindowFromHiddenAboveToken() { 2660 registerTestStartingWindowOrganizer(); 2661 // Add two tasks on top of each other. 2662 final ActivityRecord activityTop = new ActivityBuilder(mAtm).setCreateTask(true).build(); 2663 final ActivityRecord activityBottom = new ActivityBuilder(mAtm).build(); 2664 activityTop.getTask().addChild(activityBottom, 0); 2665 2666 // Add a starting window. 2667 activityTop.addStartingWindow(mPackageName, 2668 android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true, 2669 false, false); 2670 waitUntilHandlersIdle(); 2671 2672 // Make the top one invisible, and try transferring the starting window from the top to the 2673 // bottom one. 2674 activityTop.setVisibility(false, false); 2675 activityBottom.transferStartingWindowFromHiddenAboveTokenIfNeeded(); 2676 waitUntilHandlersIdle(); 2677 2678 // Assert that the bottom window now has the starting window. 2679 assertNoStartingWindow(activityTop); 2680 assertHasStartingWindow(activityBottom); 2681 } 2682 2683 @Test testTransitionAnimationBounds()2684 public void testTransitionAnimationBounds() { 2685 removeGlobalMinSizeRestriction(); 2686 final Task task = new TaskBuilder(mSupervisor) 2687 .setCreateParentTask(true).setCreateActivity(true).build(); 2688 final Task rootTask = task.getRootTask(); 2689 final ActivityRecord activity = task.getTopNonFinishingActivity(); 2690 final Rect stackBounds = new Rect(0, 0, 1000, 600); 2691 final Rect taskBounds = new Rect(100, 400, 600, 800); 2692 // Set the bounds and windowing mode to window configuration directly, otherwise the 2693 // testing setups may be discarded by configuration resolving. 2694 rootTask.getWindowConfiguration().setBounds(stackBounds); 2695 task.getWindowConfiguration().setBounds(taskBounds); 2696 activity.getWindowConfiguration().setBounds(taskBounds); 2697 2698 // Check that anim bounds for freeform window match task bounds 2699 task.getWindowConfiguration().setWindowingMode(WINDOWING_MODE_FREEFORM); 2700 assertEquals(task.getBounds(), activity.getAnimationBounds(ROOT_TASK_CLIP_NONE)); 2701 2702 // ROOT_TASK_CLIP_AFTER_ANIM should use task bounds since they will be clipped by 2703 // bounds animation layer. 2704 task.getWindowConfiguration().setWindowingMode(WINDOWING_MODE_FULLSCREEN); 2705 assertEquals(task.getBounds(), activity.getAnimationBounds(ROOT_TASK_CLIP_AFTER_ANIM)); 2706 2707 // Even the activity is smaller than task and it is not aligned to the top-left corner of 2708 // task, the animation bounds the same as task and position should be zero because in real 2709 // case the letterbox will fill the remaining area in task. 2710 final Rect halfBounds = new Rect(taskBounds); 2711 halfBounds.scale(0.5f); 2712 activity.getWindowConfiguration().setBounds(halfBounds); 2713 final Point animationPosition = new Point(); 2714 activity.getAnimationPosition(animationPosition); 2715 2716 assertEquals(taskBounds, activity.getAnimationBounds(ROOT_TASK_CLIP_AFTER_ANIM)); 2717 assertEquals(new Point(0, 0), animationPosition); 2718 2719 // ROOT_TASK_CLIP_BEFORE_ANIM should use stack bounds since it won't be clipped later. 2720 task.getWindowConfiguration().setWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY); 2721 assertEquals(rootTask.getBounds(), activity.getAnimationBounds(ROOT_TASK_CLIP_BEFORE_ANIM)); 2722 } 2723 2724 @Test testHasStartingWindow()2725 public void testHasStartingWindow() { 2726 final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build(); 2727 final WindowManager.LayoutParams attrs = 2728 new WindowManager.LayoutParams(TYPE_APPLICATION_STARTING); 2729 final TestWindowState startingWindow = createWindowState(attrs, activity); 2730 activity.startingDisplayed = true; 2731 activity.addWindow(startingWindow); 2732 assertTrue("Starting window should be present", activity.hasStartingWindow()); 2733 activity.startingDisplayed = false; 2734 assertTrue("Starting window should be present", activity.hasStartingWindow()); 2735 2736 activity.removeChild(startingWindow); 2737 assertFalse("Starting window should not be present", activity.hasStartingWindow()); 2738 } 2739 2740 @Test testSetVisibility_visibleToVisible()2741 public void testSetVisibility_visibleToVisible() { 2742 final ActivityRecord activity = new ActivityBuilder(mAtm) 2743 .setCreateTask(true).build(); 2744 // By default, activity is visible. 2745 assertTrue(activity.isVisible()); 2746 assertTrue(activity.mVisibleRequested); 2747 assertTrue(activity.mDisplayContent.mOpeningApps.contains(activity)); 2748 assertFalse(activity.mDisplayContent.mClosingApps.contains(activity)); 2749 2750 // Request the activity to be visible. Although the activity is already visible, app 2751 // transition animation should be applied on this activity. This might be unnecessary, but 2752 // until we verify no logic relies on this behavior, we'll keep this as is. 2753 activity.setVisibility(true); 2754 assertTrue(activity.isVisible()); 2755 assertTrue(activity.mVisibleRequested); 2756 assertTrue(activity.mDisplayContent.mOpeningApps.contains(activity)); 2757 assertFalse(activity.mDisplayContent.mClosingApps.contains(activity)); 2758 } 2759 2760 @Test testSetVisibility_visibleToInvisible()2761 public void testSetVisibility_visibleToInvisible() { 2762 final ActivityRecord activity = new ActivityBuilder(mAtm) 2763 .setCreateTask(true).build(); 2764 // By default, activity is visible. 2765 assertTrue(activity.isVisible()); 2766 assertTrue(activity.mVisibleRequested); 2767 assertTrue(activity.mDisplayContent.mOpeningApps.contains(activity)); 2768 assertFalse(activity.mDisplayContent.mClosingApps.contains(activity)); 2769 2770 // Request the activity to be invisible. Since the visibility changes, app transition 2771 // animation should be applied on this activity. 2772 activity.setVisibility(false); 2773 assertTrue(activity.isVisible()); 2774 assertFalse(activity.mVisibleRequested); 2775 assertFalse(activity.mDisplayContent.mOpeningApps.contains(activity)); 2776 assertTrue(activity.mDisplayContent.mClosingApps.contains(activity)); 2777 } 2778 2779 @Test testSetVisibility_invisibleToVisible()2780 public void testSetVisibility_invisibleToVisible() { 2781 final ActivityRecord activity = new ActivityBuilder(mAtm) 2782 .setCreateTask(true).setVisible(false).build(); 2783 // Activiby is invisible. However ATMS requests it to become visible, since this is a top 2784 // activity. 2785 assertFalse(activity.isVisible()); 2786 assertTrue(activity.mVisibleRequested); 2787 assertTrue(activity.mDisplayContent.mOpeningApps.contains(activity)); 2788 assertFalse(activity.mDisplayContent.mClosingApps.contains(activity)); 2789 2790 // Request the activity to be visible. Since the visibility changes, app transition 2791 // animation should be applied on this activity. 2792 activity.setVisibility(true); 2793 assertFalse(activity.isVisible()); 2794 assertTrue(activity.mVisibleRequested); 2795 assertTrue(activity.mDisplayContent.mOpeningApps.contains(activity)); 2796 assertFalse(activity.mDisplayContent.mClosingApps.contains(activity)); 2797 } 2798 2799 @Test testSetVisibility_invisibleToInvisible()2800 public void testSetVisibility_invisibleToInvisible() { 2801 final ActivityRecord activity = new ActivityBuilder(mAtm) 2802 .setCreateTask(true).setVisible(false).build(); 2803 // Activiby is invisible. However ATMS requests it to become visible, since this is a top 2804 // activity. 2805 assertFalse(activity.isVisible()); 2806 assertTrue(activity.mVisibleRequested); 2807 assertTrue(activity.mDisplayContent.mOpeningApps.contains(activity)); 2808 assertFalse(activity.mDisplayContent.mClosingApps.contains(activity)); 2809 2810 // Request the activity to be invisible. Since the activity is already invisible, no app 2811 // transition should be applied on this activity. 2812 activity.setVisibility(false); 2813 assertFalse(activity.isVisible()); 2814 assertFalse(activity.mVisibleRequested); 2815 assertFalse(activity.mDisplayContent.mOpeningApps.contains(activity)); 2816 assertFalse(activity.mDisplayContent.mClosingApps.contains(activity)); 2817 } 2818 assertHasStartingWindow(ActivityRecord atoken)2819 private void assertHasStartingWindow(ActivityRecord atoken) { 2820 assertNotNull(atoken.mStartingSurface); 2821 assertNotNull(atoken.mStartingData); 2822 assertNotNull(atoken.mStartingWindow); 2823 } 2824 assertNoStartingWindow(ActivityRecord atoken)2825 private void assertNoStartingWindow(ActivityRecord atoken) { 2826 assertNull(atoken.mStartingSurface); 2827 assertNull(atoken.mStartingWindow); 2828 assertNull(atoken.mStartingData); 2829 atoken.forAllWindows(windowState -> { 2830 assertFalse(windowState.getBaseType() == TYPE_APPLICATION_STARTING); 2831 }, true); 2832 } 2833 } 2834