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