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