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