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 final ActivityRecord activity = createActivityWithTask(); 1183 // Put an activity on top of test activity to make it invisible and prevent us from 1184 // accidentally resuming the topmost one again. 1185 new ActivityBuilder(mAtm).build(); 1186 activity.setVisibleRequested(false); 1187 activity.setState(STOPPED, "test"); 1188 1189 activity.finishIfPossible("test", false /* oomAdj */); 1190 1191 verify(activity.mDisplayContent, never()).prepareAppTransition(eq(TRANSIT_CLOSE)); 1192 assertFalse(activity.inTransition()); 1193 } 1194 1195 /** 1196 * Verify that finish request for the last activity in a task will request a shell transition 1197 * with that task as a trigger. 1198 */ 1199 @Test testFinishActivityIfPossible_lastInTaskRequestsTransitionWithTrigger()1200 public void testFinishActivityIfPossible_lastInTaskRequestsTransitionWithTrigger() { 1201 final TestTransitionPlayer testPlayer = registerTestTransitionPlayer(); 1202 final ActivityRecord activity = createActivityWithTask(); 1203 activity.finishing = false; 1204 activity.setVisibleRequested(true); 1205 activity.setState(RESUMED, "test"); 1206 activity.finishIfPossible("test", false /* oomAdj */); 1207 1208 verify(activity).setVisibility(eq(false)); 1209 assertEquals(activity.getTask().mTaskId, testPlayer.mLastRequest.getTriggerTask().taskId); 1210 } 1211 1212 /** 1213 * Verify that when collecting activity to the existing close transition, it should not affect 1214 * ready state. 1215 */ 1216 @Test testFinishActivityIfPossible_collectToExistingTransition()1217 public void testFinishActivityIfPossible_collectToExistingTransition() { 1218 final TestTransitionPlayer testPlayer = registerTestTransitionPlayer(); 1219 final ActivityRecord activity = createActivityWithTask(); 1220 activity.setState(PAUSED, "test"); 1221 activity.finishIfPossible("test", false /* oomAdj */); 1222 final Transition lastTransition = testPlayer.mLastTransit; 1223 assertTrue(lastTransition.allReady()); 1224 assertTrue(activity.inTransition()); 1225 1226 // Collect another activity to the existing transition without changing ready state. 1227 final ActivityRecord activity2 = createActivityRecord(activity.getTask()); 1228 activity2.setState(PAUSING, "test"); 1229 activity2.finishIfPossible("test", false /* oomAdj */); 1230 assertTrue(activity2.inTransition()); 1231 assertEquals(lastTransition, testPlayer.mLastTransit); 1232 assertTrue(lastTransition.allReady()); 1233 } 1234 1235 @Test testFinishActivityIfPossible_sendResultImmediately()1236 public void testFinishActivityIfPossible_sendResultImmediately() { 1237 // Create activity representing the source of the activity result. 1238 final ComponentName sourceComponent = ComponentName.createRelative( 1239 DEFAULT_COMPONENT_PACKAGE_NAME, ".SourceActivity"); 1240 final ComponentName targetComponent = ComponentName.createRelative( 1241 sourceComponent.getPackageName(), ".TargetActivity"); 1242 1243 final ActivityRecord sourceActivity = new ActivityBuilder(mWm.mAtmService) 1244 .setComponent(sourceComponent) 1245 .setLaunchMode(ActivityInfo.LAUNCH_SINGLE_INSTANCE) 1246 .setCreateTask(true) 1247 .build(); 1248 sourceActivity.finishing = false; 1249 sourceActivity.setState(STOPPED, "test"); 1250 1251 final ActivityRecord targetActivity = new ActivityBuilder(mWm.mAtmService) 1252 .setComponent(targetComponent) 1253 .setTargetActivity(sourceComponent.getClassName()) 1254 .setLaunchMode(ActivityInfo.LAUNCH_SINGLE_INSTANCE) 1255 .setCreateTask(true) 1256 .setOnTop(true) 1257 .build(); 1258 targetActivity.finishing = false; 1259 targetActivity.setState(RESUMED, "test"); 1260 targetActivity.resultTo = sourceActivity; 1261 targetActivity.setForceSendResultForMediaProjection(); 1262 1263 clearInvocations(mAtm.getLifecycleManager()); 1264 1265 targetActivity.finishIfPossible(0, new Intent(), null, "test", false /* oomAdj */); 1266 1267 try { 1268 verify(mAtm.getLifecycleManager(), atLeastOnce()).scheduleTransaction( 1269 any(ClientTransaction.class)); 1270 } catch (RemoteException ignored) { 1271 } 1272 1273 assertNull(targetActivity.results); 1274 } 1275 1276 @Test testFinishActivityIfPossible_sendResultImmediatelyIfResumed()1277 public void testFinishActivityIfPossible_sendResultImmediatelyIfResumed() { 1278 final Task task = new TaskBuilder(mSupervisor).build(); 1279 final TaskFragment taskFragment1 = createTaskFragmentWithActivity(task); 1280 final TaskFragment taskFragment2 = createTaskFragmentWithActivity(task); 1281 final ActivityRecord resultToActivity = taskFragment1.getTopMostActivity(); 1282 final ActivityRecord targetActivity = taskFragment2.getTopMostActivity(); 1283 resultToActivity.setState(RESUMED, "test"); 1284 targetActivity.setState(RESUMED, "test"); 1285 targetActivity.resultTo = resultToActivity; 1286 1287 clearInvocations(mAtm.getLifecycleManager()); 1288 targetActivity.finishIfPossible(0, new Intent(), null, "test", false /* oomAdj */); 1289 waitUntilHandlersIdle(); 1290 1291 verify(resultToActivity).sendResult(anyInt(), eq(null), anyInt(), anyInt(), any(), eq(null), 1292 anyBoolean()); 1293 } 1294 1295 /** 1296 * Verify that complete finish request for non-finishing activity is invalid. 1297 */ 1298 @Test(expected = IllegalArgumentException.class) testCompleteFinishing_failNotFinishing()1299 public void testCompleteFinishing_failNotFinishing() { 1300 final ActivityRecord activity = createActivityWithTask(); 1301 activity.finishing = false; 1302 activity.completeFinishing("test"); 1303 } 1304 1305 /** 1306 * Verify that complete finish request for resumed activity is invalid. 1307 */ 1308 @Test(expected = IllegalArgumentException.class) testCompleteFinishing_failResumed()1309 public void testCompleteFinishing_failResumed() { 1310 final ActivityRecord activity = createActivityWithTask(); 1311 activity.setState(RESUMED, "test"); 1312 activity.completeFinishing("test"); 1313 } 1314 1315 /** 1316 * Verify that finish request for pausing activity must be a no-op - activity will finish 1317 * once it completes pausing. 1318 */ 1319 @Test testCompleteFinishing_pausing()1320 public void testCompleteFinishing_pausing() { 1321 final ActivityRecord activity = createActivityWithTask(); 1322 activity.setState(PAUSING, "test"); 1323 activity.finishing = true; 1324 1325 assertEquals("Activity must not be removed immediately - waiting for paused", 1326 activity, activity.completeFinishing("test")); 1327 assertEquals(PAUSING, activity.getState()); 1328 verify(activity, never()).destroyIfPossible(anyString()); 1329 } 1330 1331 /** 1332 * Verify that finish request won't change the state of next top activity if the current 1333 * finishing activity doesn't need to be destroyed immediately. The case is usually like 1334 * from {@link Task#completePause(boolean, ActivityRecord)} to 1335 * {@link ActivityRecord#completeFinishing(String)}, so the complete-pause should take the 1336 * responsibility to resume the next activity with updating the state. 1337 */ 1338 @Test testCompleteFinishing_keepStateOfNextInvisible()1339 public void testCompleteFinishing_keepStateOfNextInvisible() { 1340 final ActivityRecord currentTop = createActivityWithTask(); 1341 final Task task = currentTop.getTask(); 1342 1343 currentTop.setVisibleRequested(currentTop.nowVisible = true); 1344 1345 // Simulates that {@code currentTop} starts an existing activity from background (so its 1346 // state is stopped) and the starting flow just goes to place it at top. 1347 final Task nextStack = new TaskBuilder(mSupervisor).setCreateActivity(true).build(); 1348 final ActivityRecord nextTop = nextStack.getTopNonFinishingActivity(); 1349 nextTop.setState(STOPPED, "test"); 1350 1351 task.setPausingActivity(currentTop); 1352 currentTop.finishing = true; 1353 currentTop.setState(PAUSED, "test"); 1354 currentTop.completeFinishing(false /* updateVisibility */, "completePause"); 1355 1356 // Current top becomes stopping because it is visible and the next is invisible. 1357 assertEquals(STOPPING, currentTop.getState()); 1358 // The state of next activity shouldn't be changed. 1359 assertEquals(STOPPED, nextTop.getState()); 1360 } 1361 1362 /** 1363 * Verify that finish bottom activity from a task won't boost it to top. 1364 */ 1365 @Test testFinishBottomActivityIfPossible_noZBoost()1366 public void testFinishBottomActivityIfPossible_noZBoost() { 1367 final ActivityRecord bottomActivity = createActivityWithTask(); 1368 final ActivityRecord topActivity = new ActivityBuilder(mAtm) 1369 .setTask(bottomActivity.getTask()).build(); 1370 topActivity.setVisibleRequested(true); 1371 // simulating bottomActivity as a trampoline activity. 1372 bottomActivity.setState(RESUMED, "test"); 1373 bottomActivity.finishIfPossible("test", false); 1374 assertFalse(bottomActivity.mNeedsZBoost); 1375 } 1376 1377 /** 1378 * Verify that complete finish request for visible activity must be delayed before the next one 1379 * becomes visible. 1380 */ 1381 @Test testCompleteFinishing_waitForNextVisible()1382 public void testCompleteFinishing_waitForNextVisible() { 1383 final ActivityRecord activity = createActivityWithTask(); 1384 final ActivityRecord topActivity = new ActivityBuilder(mAtm) 1385 .setTask(activity.getTask()).build(); 1386 topActivity.setVisibleRequested(true); 1387 topActivity.nowVisible = true; 1388 topActivity.finishing = true; 1389 topActivity.setState(PAUSED, "true"); 1390 // Mark the bottom activity as not visible, so that we will wait for it before removing 1391 // the top one. 1392 activity.setVisibleRequested(false); 1393 activity.nowVisible = false; 1394 activity.setState(STOPPED, "test"); 1395 1396 assertEquals("Activity must not be removed immediately - waiting for next visible", 1397 topActivity, topActivity.completeFinishing("test")); 1398 assertEquals("Activity must be stopped to make next one visible", STOPPING, 1399 topActivity.getState()); 1400 assertTrue("Activity must be stopped to make next one visible", 1401 topActivity.mTaskSupervisor.mStoppingActivities.contains(topActivity)); 1402 verify(topActivity, never()).destroyIfPossible(anyString()); 1403 } 1404 1405 /** 1406 * Verify that complete finish request for top invisible activity must not be delayed while 1407 * sleeping, but next invisible activity must be resumed (and paused/stopped) 1408 */ 1409 @Test testCompleteFinishing_noWaitForNextVisible_sleeping()1410 public void testCompleteFinishing_noWaitForNextVisible_sleeping() { 1411 final ActivityRecord activity = createActivityWithTask(); 1412 // Create a top activity on a new task 1413 final ActivityRecord topActivity = createActivityWithTask(); 1414 mDisplayContent.setIsSleeping(true); 1415 doReturn(true).when(activity).shouldBeVisible(); 1416 topActivity.setVisibleRequested(false); 1417 topActivity.nowVisible = false; 1418 topActivity.finishing = true; 1419 topActivity.setState(STOPPED, "true"); 1420 1421 // Mark the activity behind (on a separate task) as not visible 1422 activity.setVisibleRequested(false); 1423 activity.nowVisible = false; 1424 activity.setState(STOPPED, "test"); 1425 1426 clearInvocations(activity); 1427 topActivity.completeFinishing("test"); 1428 verify(activity).setState(eq(RESUMED), any()); 1429 verify(topActivity).destroyIfPossible(anyString()); 1430 } 1431 1432 /** 1433 * Verify that complete finish request for invisible activity must not be delayed. 1434 */ 1435 @Test testCompleteFinishing_noWaitForNextVisible_alreadyInvisible()1436 public void testCompleteFinishing_noWaitForNextVisible_alreadyInvisible() { 1437 final ActivityRecord activity = createActivityWithTask(); 1438 final ActivityRecord topActivity = new ActivityBuilder(mAtm) 1439 .setTask(activity.getTask()).build(); 1440 topActivity.setVisibleRequested(false); 1441 topActivity.nowVisible = false; 1442 topActivity.finishing = true; 1443 topActivity.setState(STOPPED, "true"); 1444 // Mark the bottom activity as not visible, so that we would wait for it before removing 1445 // the top one. 1446 activity.setVisibleRequested(false); 1447 activity.nowVisible = false; 1448 activity.setState(STOPPED, "test"); 1449 1450 topActivity.completeFinishing("test"); 1451 1452 verify(topActivity).destroyIfPossible(anyString()); 1453 } 1454 1455 /** 1456 * Verify that paused finishing activity will be added to finishing list and wait for next one 1457 * to idle. 1458 */ 1459 @Test testCompleteFinishing_waitForIdle()1460 public void testCompleteFinishing_waitForIdle() { 1461 final ActivityRecord activity = createActivityWithTask(); 1462 final ActivityRecord topActivity = new ActivityBuilder(mAtm) 1463 .setTask(activity.getTask()).build(); 1464 topActivity.setVisibleRequested(true); 1465 topActivity.nowVisible = true; 1466 topActivity.finishing = true; 1467 topActivity.setState(PAUSED, "true"); 1468 // Mark the bottom activity as already visible, so that there is no need to wait for it. 1469 activity.setVisibleRequested(true); 1470 activity.nowVisible = true; 1471 activity.setState(RESUMED, "test"); 1472 1473 topActivity.completeFinishing("test"); 1474 1475 verify(topActivity).addToFinishingAndWaitForIdle(); 1476 } 1477 1478 /** 1479 * Verify that complete finish request for visible activity must not be delayed if the next one 1480 * is already visible and it's not the focused stack. 1481 */ 1482 @Test testCompleteFinishing_noWaitForNextVisible_stopped()1483 public void testCompleteFinishing_noWaitForNextVisible_stopped() { 1484 final ActivityRecord activity = createActivityWithTask(); 1485 final ActivityRecord topActivity = new ActivityBuilder(mAtm) 1486 .setTask(activity.getTask()).build(); 1487 topActivity.setVisibleRequested(false); 1488 topActivity.nowVisible = false; 1489 topActivity.finishing = true; 1490 topActivity.setState(STOPPED, "true"); 1491 // Mark the bottom activity as already visible, so that there is no need to wait for it. 1492 activity.setVisibleRequested(true); 1493 activity.nowVisible = true; 1494 activity.setState(RESUMED, "test"); 1495 1496 topActivity.completeFinishing("test"); 1497 1498 verify(topActivity).destroyIfPossible(anyString()); 1499 } 1500 1501 /** 1502 * Verify that complete finish request for visible activity must not be delayed if the next one 1503 * is already visible and it's not the focused stack. 1504 */ 1505 @Test testCompleteFinishing_noWaitForNextVisible_nonFocusedStack()1506 public void testCompleteFinishing_noWaitForNextVisible_nonFocusedStack() { 1507 final ActivityRecord activity = createActivityWithTask(); 1508 final ActivityRecord topActivity = new ActivityBuilder(mAtm) 1509 .setTask(activity.getTask()).build(); 1510 topActivity.setVisibleRequested(true); 1511 topActivity.nowVisible = true; 1512 topActivity.finishing = true; 1513 topActivity.setState(PAUSED, "true"); 1514 // Mark the bottom activity as already visible, so that there is no need to wait for it. 1515 activity.setVisibleRequested(true); 1516 activity.nowVisible = true; 1517 activity.setState(RESUMED, "test"); 1518 1519 // Add another stack to become focused and make the activity there visible. This way it 1520 // simulates finishing in non-focused stack in split-screen. 1521 final Task stack = new TaskBuilder(mSupervisor).setCreateActivity(true).build(); 1522 final ActivityRecord focusedActivity = stack.getTopMostActivity(); 1523 focusedActivity.nowVisible = true; 1524 focusedActivity.setVisibleRequested(true); 1525 focusedActivity.setState(RESUMED, "test"); 1526 stack.setResumedActivity(focusedActivity, "test"); 1527 1528 topActivity.completeFinishing("test"); 1529 1530 verify(topActivity).destroyIfPossible(anyString()); 1531 } 1532 1533 /** 1534 * Verify that complete finish request for a show-when-locked activity must ensure the 1535 * keyguard occluded state being updated. 1536 */ 1537 @Test testCompleteFinishing_showWhenLocked()1538 public void testCompleteFinishing_showWhenLocked() { 1539 final ActivityRecord activity = createActivityWithTask(); 1540 final Task task = activity.getTask(); 1541 // Make keyguard locked and set the top activity show-when-locked. 1542 KeyguardController keyguardController = activity.mTaskSupervisor.getKeyguardController(); 1543 int displayId = activity.getDisplayId(); 1544 doReturn(true).when(keyguardController).isKeyguardLocked(eq(displayId)); 1545 final ActivityRecord topActivity = new ActivityBuilder(mAtm).setTask(task).build(); 1546 topActivity.setVisibleRequested(true); 1547 topActivity.nowVisible = true; 1548 topActivity.setState(RESUMED, "true"); 1549 doCallRealMethod().when(mRootWindowContainer).ensureActivitiesVisible( 1550 any() /* starting */, anyInt() /* configChanges */, 1551 anyBoolean() /* preserveWindows */, anyBoolean() /* notifyClients */); 1552 topActivity.setShowWhenLocked(true); 1553 1554 // Verify the stack-top activity is occluded keyguard. 1555 assertEquals(topActivity, task.topRunningActivity()); 1556 assertTrue(keyguardController.isDisplayOccluded(DEFAULT_DISPLAY)); 1557 1558 // Finish the top activity 1559 topActivity.setState(PAUSED, "true"); 1560 topActivity.finishing = true; 1561 topActivity.completeFinishing("test"); 1562 1563 // Verify new top activity does not occlude keyguard. 1564 assertEquals(activity, task.topRunningActivity()); 1565 assertFalse(keyguardController.isDisplayOccluded(DEFAULT_DISPLAY)); 1566 } 1567 1568 /** 1569 * Verify that complete finish request for an activity which the resume activity is translucent 1570 * must ensure the visibilities of activities being updated. 1571 */ 1572 @Test testCompleteFinishing_ensureActivitiesVisible_withConditions()1573 public void testCompleteFinishing_ensureActivitiesVisible_withConditions() { 1574 testCompleteFinishing_ensureActivitiesVisible(false, PAUSED); 1575 testCompleteFinishing_ensureActivitiesVisible(false, STARTED); 1576 testCompleteFinishing_ensureActivitiesVisible(true, PAUSED); 1577 testCompleteFinishing_ensureActivitiesVisible(true, STARTED); 1578 } 1579 testCompleteFinishing_ensureActivitiesVisible(boolean diffTask, State secondActivityState)1580 private void testCompleteFinishing_ensureActivitiesVisible(boolean diffTask, 1581 State secondActivityState) { 1582 final ActivityRecord activity = createActivityWithTask(); 1583 final Task task = activity.getTask(); 1584 final ActivityRecord firstActivity = new ActivityBuilder(mAtm).setTask(task).build(); 1585 firstActivity.setVisibleRequested(false); 1586 firstActivity.nowVisible = false; 1587 firstActivity.setState(STOPPED, "test"); 1588 1589 final ActivityRecord secondActivity = new ActivityBuilder(mAtm).setTask(task).build(); 1590 secondActivity.setVisibleRequested(true); 1591 secondActivity.nowVisible = true; 1592 secondActivity.setState(secondActivityState, "test"); 1593 1594 ActivityRecord translucentActivity; 1595 if (diffTask) { 1596 translucentActivity = new ActivityBuilder(mAtm).setCreateTask(true).build(); 1597 } else { 1598 translucentActivity = new ActivityBuilder(mAtm).setTask(task).build(); 1599 } 1600 translucentActivity.setVisibleRequested(true); 1601 translucentActivity.nowVisible = true; 1602 translucentActivity.setState(RESUMED, "test"); 1603 1604 doReturn(true).when(firstActivity).occludesParent(true); 1605 doReturn(true).when(secondActivity).occludesParent(true); 1606 1607 // Finish the second activity 1608 secondActivity.finishing = true; 1609 secondActivity.completeFinishing("test"); 1610 verify(secondActivity.mDisplayContent).ensureActivitiesVisible(null /* starting */, 1611 0 /* configChanges */ , false /* preserveWindows */, 1612 true /* notifyClients */); 1613 1614 // Finish the first activity 1615 firstActivity.finishing = true; 1616 firstActivity.setVisibleRequested(true); 1617 firstActivity.completeFinishing("test"); 1618 verify(firstActivity.mDisplayContent, times(2)).ensureActivitiesVisible(null /* starting */, 1619 0 /* configChanges */ , false /* preserveWindows */, 1620 true /* notifyClients */); 1621 1622 // Remove the translucent activity and clear invocations for next test 1623 translucentActivity.getTask().removeImmediately("test"); 1624 clearInvocations(mDefaultDisplay); 1625 } 1626 1627 /** 1628 * Verify destroy activity request completes successfully. 1629 */ 1630 @Test testDestroyIfPossible()1631 public void testDestroyIfPossible() { 1632 final ActivityRecord activity = createActivityWithTask(); 1633 doReturn(false).when(mRootWindowContainer) 1634 .resumeFocusedTasksTopActivities(); 1635 activity.destroyIfPossible("test"); 1636 1637 assertEquals(DESTROYING, activity.getState()); 1638 assertTrue(activity.finishing); 1639 verify(activity).destroyImmediately(anyString()); 1640 } 1641 1642 /** 1643 * Verify that complete finish request for visible activity must not destroy it immediately if 1644 * it is the last running activity on a display with a home stack. We must wait for home 1645 * activity to come up to avoid a black flash in this case. 1646 */ 1647 @Test testDestroyIfPossible_lastActivityAboveEmptyHomeStack()1648 public void testDestroyIfPossible_lastActivityAboveEmptyHomeStack() { 1649 final ActivityRecord activity = createActivityWithTask(); 1650 // Empty the home stack. 1651 final Task homeStack = activity.getDisplayArea().getRootHomeTask(); 1652 homeStack.forAllLeafTasks((t) -> { 1653 homeStack.removeChild(t, "test"); 1654 }, true /* traverseTopToBottom */); 1655 activity.finishing = true; 1656 doReturn(false).when(mRootWindowContainer) 1657 .resumeFocusedTasksTopActivities(); 1658 1659 // Try to destroy the last activity above the home stack. 1660 activity.destroyIfPossible("test"); 1661 1662 // Verify that the activity was not actually destroyed, but waits for next one to come up 1663 // instead. 1664 verify(activity, never()).destroyImmediately(anyString()); 1665 assertEquals(FINISHING, activity.getState()); 1666 assertTrue(activity.mTaskSupervisor.mFinishingActivities.contains(activity)); 1667 } 1668 1669 /** 1670 * Verify that complete finish request for visible activity must resume next home stack before 1671 * destroying it immediately if it is the last running activity on a display with a home stack. 1672 * We must wait for home activity to come up to avoid a black flash in this case. 1673 */ 1674 @Test testCompleteFinishing_lastActivityAboveEmptyHomeStack()1675 public void testCompleteFinishing_lastActivityAboveEmptyHomeStack() { 1676 final ActivityRecord activity = createActivityWithTask(); 1677 // Empty the home root task. 1678 final Task homeRootTask = activity.getDisplayArea().getRootHomeTask(); 1679 homeRootTask.forAllLeafTasks((t) -> { 1680 homeRootTask.removeChild(t, "test"); 1681 }, true /* traverseTopToBottom */); 1682 activity.setState(STARTED, "test"); 1683 activity.finishing = true; 1684 activity.setVisibleRequested(true); 1685 1686 // Try to finish the last activity above the home stack. 1687 activity.completeFinishing("test"); 1688 1689 // Verify that the activity is not destroyed immediately, but waits for next one to come up. 1690 verify(activity, never()).destroyImmediately(anyString()); 1691 assertEquals(FINISHING, activity.getState()); 1692 assertTrue(activity.mTaskSupervisor.mFinishingActivities.contains(activity)); 1693 } 1694 1695 /** 1696 * Test that the activity will be moved to destroying state and the message to destroy will be 1697 * sent to the client. 1698 */ 1699 @Test testDestroyImmediately_hadApp_finishing()1700 public void testDestroyImmediately_hadApp_finishing() { 1701 final ActivityRecord activity = createActivityWithTask(); 1702 activity.finishing = true; 1703 activity.destroyImmediately("test"); 1704 1705 assertEquals(DESTROYING, activity.getState()); 1706 } 1707 1708 /** 1709 * Test that the activity will be moved to destroyed state immediately if it was not marked as 1710 * finishing before {@link ActivityRecord#destroyImmediately(String)}. 1711 */ 1712 @Test testDestroyImmediately_hadApp_notFinishing()1713 public void testDestroyImmediately_hadApp_notFinishing() { 1714 final ActivityRecord activity = createActivityWithTask(); 1715 activity.finishing = false; 1716 activity.destroyImmediately("test"); 1717 1718 assertEquals(DESTROYED, activity.getState()); 1719 } 1720 1721 /** 1722 * Test that an activity with no process attached and that is marked as finishing will be 1723 * removed from task when {@link ActivityRecord#destroyImmediately(String)} is called. 1724 */ 1725 @Test testDestroyImmediately_noApp_finishing()1726 public void testDestroyImmediately_noApp_finishing() { 1727 final ActivityRecord activity = createActivityWithTask(); 1728 activity.app = null; 1729 activity.finishing = true; 1730 final Task task = activity.getTask(); 1731 1732 activity.destroyImmediately("test"); 1733 1734 assertEquals(DESTROYED, activity.getState()); 1735 assertNull(activity.getTask()); 1736 assertEquals(0, task.getChildCount()); 1737 } 1738 1739 /** 1740 * Test that an activity with no process attached and that is not marked as finishing will be 1741 * marked as DESTROYED but not removed from task. 1742 */ 1743 @Test testDestroyImmediately_noApp_notFinishing()1744 public void testDestroyImmediately_noApp_notFinishing() { 1745 final ActivityRecord activity = createActivityWithTask(); 1746 activity.app = null; 1747 activity.finishing = false; 1748 final Task task = activity.getTask(); 1749 1750 activity.destroyImmediately("test"); 1751 1752 assertEquals(DESTROYED, activity.getState()); 1753 assertEquals(task, activity.getTask()); 1754 assertEquals(1, task.getChildCount()); 1755 } 1756 1757 /** 1758 * Test that an activity will not be destroyed if it is marked as non-destroyable. 1759 */ 1760 @Test testSafelyDestroy_nonDestroyable()1761 public void testSafelyDestroy_nonDestroyable() { 1762 final ActivityRecord activity = createActivityWithTask(); 1763 doReturn(false).when(activity).isDestroyable(); 1764 1765 activity.safelyDestroy("test"); 1766 1767 verify(activity, never()).destroyImmediately(anyString()); 1768 } 1769 1770 /** 1771 * Test that an activity will not be destroyed if it is marked as non-destroyable. 1772 */ 1773 @Test testSafelyDestroy_destroyable()1774 public void testSafelyDestroy_destroyable() { 1775 final ActivityRecord activity = createActivityWithTask(); 1776 doReturn(true).when(activity).isDestroyable(); 1777 1778 activity.safelyDestroy("test"); 1779 1780 verify(activity).destroyImmediately(anyString()); 1781 } 1782 1783 @Test testRemoveImmediately()1784 public void testRemoveImmediately() { 1785 final Consumer<Consumer<ActivityRecord>> test = setup -> { 1786 final ActivityRecord activity = createActivityWithTask(); 1787 final WindowProcessController wpc = activity.app; 1788 setup.accept(activity); 1789 activity.getTask().removeImmediately("test"); 1790 try { 1791 verify(mAtm.getLifecycleManager()).scheduleTransaction(any(), eq(activity.token), 1792 isA(DestroyActivityItem.class)); 1793 } catch (RemoteException ignored) { 1794 } 1795 assertNull(activity.app); 1796 assertEquals(DESTROYED, activity.getState()); 1797 assertFalse(wpc.hasActivities()); 1798 }; 1799 test.accept(activity -> activity.setState(RESUMED, "test")); 1800 test.accept(activity -> activity.finishing = true); 1801 } 1802 1803 @Test testRemoveFromHistory()1804 public void testRemoveFromHistory() { 1805 final ActivityRecord activity = createActivityWithTask(); 1806 final Task rootTask = activity.getRootTask(); 1807 final Task task = activity.getTask(); 1808 final WindowProcessController wpc = activity.app; 1809 assertTrue(wpc.hasActivities()); 1810 1811 activity.removeFromHistory("test"); 1812 1813 assertEquals(DESTROYED, activity.getState()); 1814 assertNull(activity.app); 1815 assertNull(activity.getTask()); 1816 assertFalse(wpc.hasActivities()); 1817 assertEquals(0, task.getChildCount()); 1818 assertEquals(task.getRootTask(), task); 1819 assertEquals(0, rootTask.getChildCount()); 1820 } 1821 1822 /** 1823 * Test that it's not allowed to call {@link ActivityRecord#destroyed(String)} if activity is 1824 * not in destroying or destroyed state. 1825 */ 1826 @Test(expected = IllegalStateException.class) testDestroyed_notDestroying()1827 public void testDestroyed_notDestroying() { 1828 final ActivityRecord activity = createActivityWithTask(); 1829 activity.setState(STOPPED, "test"); 1830 activity.destroyed("test"); 1831 } 1832 1833 /** 1834 * Test that {@link ActivityRecord#destroyed(String)} can be called if an activity is destroying 1835 */ 1836 @Test testDestroyed_destroying()1837 public void testDestroyed_destroying() { 1838 final ActivityRecord activity = createActivityWithTask(); 1839 activity.setState(DESTROYING, "test"); 1840 activity.destroyed("test"); 1841 1842 verify(activity).removeFromHistory(anyString()); 1843 } 1844 1845 /** 1846 * Test that {@link ActivityRecord#destroyed(String)} can be called if an activity is destroyed. 1847 */ 1848 @Test testDestroyed_destroyed()1849 public void testDestroyed_destroyed() { 1850 final ActivityRecord activity = createActivityWithTask(); 1851 activity.setState(DESTROYED, "test"); 1852 activity.destroyed("test"); 1853 1854 verify(activity).removeFromHistory(anyString()); 1855 } 1856 1857 @Test testActivityOverridesProcessConfig()1858 public void testActivityOverridesProcessConfig() { 1859 final ActivityRecord activity = createActivityWithTask(); 1860 final WindowProcessController wpc = activity.app; 1861 assertTrue(wpc.registeredForActivityConfigChanges()); 1862 assertFalse(wpc.registeredForDisplayAreaConfigChanges()); 1863 1864 final ActivityRecord secondaryDisplayActivity = 1865 createActivityOnDisplay(false /* defaultDisplay */, null /* process */); 1866 1867 assertTrue(wpc.registeredForActivityConfigChanges()); 1868 assertEquals(0, activity.getMergedOverrideConfiguration() 1869 .diff(wpc.getRequestedOverrideConfiguration())); 1870 assertNotEquals(activity.getConfiguration(), 1871 secondaryDisplayActivity.getConfiguration()); 1872 } 1873 1874 @Test testActivityOverridesProcessConfig_TwoActivities()1875 public void testActivityOverridesProcessConfig_TwoActivities() { 1876 final ActivityRecord activity = createActivityWithTask(); 1877 final WindowProcessController wpc = activity.app; 1878 assertTrue(wpc.registeredForActivityConfigChanges()); 1879 1880 final Task firstTaskRecord = activity.getTask(); 1881 final ActivityRecord secondActivityRecord = 1882 new ActivityBuilder(mAtm).setTask(firstTaskRecord).setUseProcess(wpc).build(); 1883 1884 assertTrue(wpc.registeredForActivityConfigChanges()); 1885 assertEquals(0, secondActivityRecord.getMergedOverrideConfiguration() 1886 .diff(wpc.getRequestedOverrideConfiguration())); 1887 } 1888 1889 @Test testActivityOverridesProcessConfig_TwoActivities_SecondaryDisplay()1890 public void testActivityOverridesProcessConfig_TwoActivities_SecondaryDisplay() { 1891 final ActivityRecord activity = createActivityWithTask(); 1892 final WindowProcessController wpc = activity.app; 1893 assertTrue(wpc.registeredForActivityConfigChanges()); 1894 1895 final ActivityRecord secondActivityRecord = 1896 new ActivityBuilder(mAtm).setTask(activity.getTask()).setUseProcess(wpc).build(); 1897 1898 assertTrue(wpc.registeredForActivityConfigChanges()); 1899 assertEquals(0, secondActivityRecord.getMergedOverrideConfiguration() 1900 .diff(wpc.getRequestedOverrideConfiguration())); 1901 } 1902 1903 @Test testActivityOverridesProcessConfig_TwoActivities_DifferentTasks()1904 public void testActivityOverridesProcessConfig_TwoActivities_DifferentTasks() { 1905 final ActivityRecord activity = createActivityWithTask(); 1906 final WindowProcessController wpc = activity.app; 1907 assertTrue(wpc.registeredForActivityConfigChanges()); 1908 1909 final ActivityRecord secondActivityRecord = 1910 createActivityOnDisplay(true /* defaultDisplay */, wpc); 1911 1912 assertTrue(wpc.registeredForActivityConfigChanges()); 1913 assertEquals(0, secondActivityRecord.getMergedOverrideConfiguration() 1914 .diff(wpc.getRequestedOverrideConfiguration())); 1915 } 1916 1917 @Test testActivityOnCancelFixedRotationTransform()1918 public void testActivityOnCancelFixedRotationTransform() { 1919 final ActivityRecord activity = createActivityWithTask(); 1920 final DisplayRotation displayRotation = activity.mDisplayContent.getDisplayRotation(); 1921 final RemoteDisplayChangeController remoteDisplayChangeController = activity 1922 .mDisplayContent.mRemoteDisplayChangeController; 1923 spyOn(displayRotation); 1924 spyOn(remoteDisplayChangeController); 1925 1926 final DisplayContent display = activity.mDisplayContent; 1927 final int originalRotation = display.getRotation(); 1928 1929 // Make {@link DisplayContent#sendNewConfiguration} not apply rotation immediately. 1930 doReturn(true).when(remoteDisplayChangeController).isWaitingForRemoteDisplayChange(); 1931 doReturn((originalRotation + 1) % 4).when(displayRotation).rotationForOrientation( 1932 anyInt() /* orientation */, anyInt() /* lastRotation */); 1933 // Set to visible so the activity can freeze the screen. 1934 activity.setVisibility(true); 1935 1936 display.rotateInDifferentOrientationIfNeeded(activity); 1937 display.setFixedRotationLaunchingAppUnchecked(activity); 1938 displayRotation.updateRotationUnchecked(true /* forceUpdate */); 1939 1940 assertTrue(displayRotation.isRotatingSeamlessly()); 1941 1942 // The launching rotated app should not be cleared when waiting for remote rotation. 1943 display.continueUpdateOrientationForDiffOrienLaunchingApp(); 1944 assertTrue(display.isFixedRotationLaunchingApp(activity)); 1945 1946 // Simulate the rotation has been updated to previous one, e.g. sensor updates before the 1947 // remote rotation is completed. 1948 doReturn(originalRotation).when(displayRotation).rotationForOrientation( 1949 anyInt() /* orientation */, anyInt() /* lastRotation */); 1950 display.updateOrientation(); 1951 1952 final DisplayInfo rotatedInfo = activity.getFixedRotationTransformDisplayInfo(); 1953 activity.finishFixedRotationTransform(); 1954 final ScreenRotationAnimation rotationAnim = display.getRotationAnimation(); 1955 assertNotNull(rotationAnim); 1956 rotationAnim.setRotation(display.getPendingTransaction(), originalRotation); 1957 1958 // Because the display doesn't rotate, the rotated activity needs to cancel the fixed 1959 // rotation. There should be a rotation animation to cover the change of activity. 1960 verify(activity).onCancelFixedRotationTransform(rotatedInfo.rotation); 1961 assertTrue(activity.isFreezingScreen()); 1962 assertFalse(displayRotation.isRotatingSeamlessly()); 1963 assertTrue(rotationAnim.isRotating()); 1964 1965 // Simulate the remote rotation has completed and the configuration doesn't change, then 1966 // the rotated activity should also be restored by clearing the transform. 1967 displayRotation.updateRotationUnchecked(true /* forceUpdate */); 1968 doReturn(false).when(remoteDisplayChangeController).isWaitingForRemoteDisplayChange(); 1969 clearInvocations(activity); 1970 display.setFixedRotationLaunchingAppUnchecked(activity); 1971 display.sendNewConfiguration(); 1972 1973 assertFalse(display.hasTopFixedRotationLaunchingApp()); 1974 assertFalse(activity.hasFixedRotationTransform()); 1975 1976 // Simulate that the activity requests the same orientation as display. 1977 activity.setOrientation(display.getConfiguration().orientation); 1978 // Skip the real freezing. 1979 activity.setVisibleRequested(false); 1980 clearInvocations(activity); 1981 activity.onCancelFixedRotationTransform(originalRotation); 1982 // The implementation of cancellation must be executed. 1983 verify(activity).startFreezingScreen(originalRotation); 1984 } 1985 1986 @Test testIsSnapshotCompatible()1987 public void testIsSnapshotCompatible() { 1988 final ActivityRecord activity = createActivityWithTask(); 1989 final Task task = activity.getTask(); 1990 final Rect taskBounds = task.getBounds(); 1991 final TaskSnapshot snapshot = new TaskSnapshotPersisterTestBase.TaskSnapshotBuilder() 1992 .setTopActivityComponent(activity.mActivityComponent) 1993 .setRotation(activity.getWindowConfiguration().getRotation()) 1994 .setTaskSize(taskBounds.width(), taskBounds.height()) 1995 .build(); 1996 1997 assertTrue(activity.isSnapshotCompatible(snapshot)); 1998 1999 doReturn(task.getWindowConfiguration().getRotation() + 1).when(mDisplayContent) 2000 .rotationForActivityInDifferentOrientation(activity); 2001 2002 assertFalse(activity.isSnapshotCompatible(snapshot)); 2003 } 2004 2005 /** 2006 * Test that the snapshot should be obsoleted if the top activity changed. 2007 */ 2008 @Test testIsSnapshotCompatibleTopActivityChanged()2009 public void testIsSnapshotCompatibleTopActivityChanged() { 2010 final ActivityRecord activity = createActivityWithTask(); 2011 final ActivityRecord secondActivity = new ActivityBuilder(mAtm) 2012 .setTask(activity.getTask()) 2013 .setOnTop(true) 2014 .build(); 2015 final Task task = secondActivity.getTask(); 2016 final Rect taskBounds = task.getBounds(); 2017 final TaskSnapshot snapshot = new TaskSnapshotPersisterTestBase.TaskSnapshotBuilder() 2018 .setTopActivityComponent(secondActivity.mActivityComponent) 2019 .setTaskSize(taskBounds.width(), taskBounds.height()) 2020 .build(); 2021 2022 assertTrue(secondActivity.isSnapshotCompatible(snapshot)); 2023 2024 // Emulate the top activity changed. 2025 assertFalse(activity.isSnapshotCompatible(snapshot)); 2026 } 2027 2028 /** 2029 * Test that the snapshot should be obsoleted if the task size changed. 2030 */ 2031 @Test testIsSnapshotCompatibleTaskSizeChanged()2032 public void testIsSnapshotCompatibleTaskSizeChanged() { 2033 final ActivityRecord activity = createActivityWithTask(); 2034 final Task task = activity.getTask(); 2035 final Rect taskBounds = task.getBounds(); 2036 final int currentRotation = mDisplayContent.getRotation(); 2037 final int w = taskBounds.width(); 2038 final int h = taskBounds.height(); 2039 final TaskSnapshot snapshot = new TaskSnapshotPersisterTestBase.TaskSnapshotBuilder() 2040 .setTopActivityComponent(activity.mActivityComponent) 2041 .setRotation(currentRotation) 2042 .setTaskSize(w, h) 2043 .build(); 2044 2045 assertTrue(activity.isSnapshotCompatible(snapshot)); 2046 2047 taskBounds.right = taskBounds.width() * 2; 2048 task.getWindowConfiguration().setBounds(taskBounds); 2049 activity.getWindowConfiguration().setBounds(taskBounds); 2050 2051 assertFalse(activity.isSnapshotCompatible(snapshot)); 2052 2053 // Flipped size should be accepted if the activity will show with 90 degree rotation. 2054 final int targetRotation = currentRotation + 1; 2055 doReturn(targetRotation).when(mDisplayContent) 2056 .rotationForActivityInDifferentOrientation(any()); 2057 final TaskSnapshot rotatedSnapshot = new TaskSnapshotPersisterTestBase.TaskSnapshotBuilder() 2058 .setTopActivityComponent(activity.mActivityComponent) 2059 .setRotation(targetRotation) 2060 .setTaskSize(h, w) 2061 .build(); 2062 task.getWindowConfiguration().getBounds().set(0, 0, w, h); 2063 assertTrue(activity.isSnapshotCompatible(rotatedSnapshot)); 2064 } 2065 2066 @Test testFixedRotationSnapshotStartingWindow()2067 public void testFixedRotationSnapshotStartingWindow() { 2068 final ActivityRecord activity = createActivityWithTask(); 2069 // TaskSnapshotSurface requires a fullscreen opaque window. 2070 final WindowManager.LayoutParams params = new WindowManager.LayoutParams( 2071 WindowManager.LayoutParams.TYPE_APPLICATION_STARTING); 2072 params.width = params.height = WindowManager.LayoutParams.MATCH_PARENT; 2073 final TestWindowState w = new TestWindowState( 2074 mAtm.mWindowManager, mock(Session.class), new TestIWindow(), params, activity); 2075 activity.addWindow(w); 2076 2077 // Assume the activity is launching in different rotation, and there was an available 2078 // snapshot accepted by {@link Activity#isSnapshotCompatible}. 2079 final TaskSnapshot snapshot = new TaskSnapshotPersisterTestBase.TaskSnapshotBuilder() 2080 .setRotation((activity.getWindowConfiguration().getRotation() + 1) % 4) 2081 .build(); 2082 setRotatedScreenOrientationSilently(activity); 2083 activity.setVisible(false); 2084 2085 final IWindowSession session = WindowManagerGlobal.getWindowSession(); 2086 spyOn(session); 2087 try { 2088 // Return error to skip unnecessary operation. 2089 doReturn(WindowManagerGlobal.ADD_STARTING_NOT_NEEDED).when(session).addToDisplay( 2090 any() /* window */, any() /* attrs */, 2091 anyInt() /* viewVisibility */, anyInt() /* displayId */, 2092 anyInt() /* requestedVisibleTypes */, any() /* outInputChannel */, 2093 any() /* outInsetsState */, any() /* outActiveControls */, 2094 any() /* outAttachedFrame */, any() /* outSizeCompatScale */); 2095 mAtm.mWindowManager.mStartingSurfaceController 2096 .createTaskSnapshotSurface(activity, snapshot); 2097 } catch (RemoteException ignored) { 2098 } finally { 2099 reset(session); 2100 } 2101 2102 // Because the rotation of snapshot and the corresponding top activity are different, fixed 2103 // rotation should be applied when creating snapshot surface if the display rotation may be 2104 // changed according to the activity orientation. 2105 assertTrue(activity.hasFixedRotationTransform()); 2106 assertTrue(activity.mDisplayContent.isFixedRotationLaunchingApp(activity)); 2107 } 2108 2109 /** 2110 * Sets orientation without notifying the parent to simulate that the display has not applied 2111 * the requested orientation yet. 2112 */ setRotatedScreenOrientationSilently(ActivityRecord r)2113 static void setRotatedScreenOrientationSilently(ActivityRecord r) { 2114 final int rotatedOrentation = r.getConfiguration().orientation == ORIENTATION_PORTRAIT 2115 ? SCREEN_ORIENTATION_LANDSCAPE 2116 : SCREEN_ORIENTATION_PORTRAIT; 2117 doReturn(false).when(r).onDescendantOrientationChanged(any()); 2118 r.setOrientation(rotatedOrentation); 2119 } 2120 2121 @Test testActivityOnDifferentDisplayUpdatesProcessOverride()2122 public void testActivityOnDifferentDisplayUpdatesProcessOverride() { 2123 final ActivityRecord secondaryDisplayActivity = 2124 createActivityOnDisplay(false /* defaultDisplay */, null /* process */); 2125 final WindowProcessController wpc = secondaryDisplayActivity.app; 2126 assertTrue(wpc.registeredForActivityConfigChanges()); 2127 2128 final ActivityRecord secondActivityRecord = 2129 createActivityOnDisplay(true /* defaultDisplay */, wpc); 2130 2131 assertTrue(wpc.registeredForActivityConfigChanges()); 2132 assertEquals(0, secondActivityRecord.getMergedOverrideConfiguration() 2133 .diff(wpc.getRequestedOverrideConfiguration())); 2134 assertFalse(wpc.registeredForDisplayAreaConfigChanges()); 2135 } 2136 2137 @Test testActivityReparentChangesProcessOverride()2138 public void testActivityReparentChangesProcessOverride() { 2139 final ActivityRecord activity = createActivityWithTask(); 2140 final WindowProcessController wpc = activity.app; 2141 final Task initialTask = activity.getTask(); 2142 final Configuration initialConf = 2143 new Configuration(activity.getMergedOverrideConfiguration()); 2144 assertEquals(0, activity.getMergedOverrideConfiguration() 2145 .diff(wpc.getRequestedOverrideConfiguration())); 2146 assertTrue(wpc.registeredForActivityConfigChanges()); 2147 2148 // Create a new task with custom config to reparent the activity to. 2149 final Task newTask = new TaskBuilder(mSupervisor).build(); 2150 final Configuration newConfig = newTask.getConfiguration(); 2151 newConfig.densityDpi += 100; 2152 newTask.onRequestedOverrideConfigurationChanged(newConfig); 2153 assertEquals(newTask.getConfiguration().densityDpi, newConfig.densityDpi); 2154 2155 // Reparent the activity and verify that config override changed. 2156 activity.reparent(newTask, 0 /* top */, "test"); 2157 assertEquals(activity.getConfiguration().densityDpi, newConfig.densityDpi); 2158 assertEquals(activity.getMergedOverrideConfiguration().densityDpi, newConfig.densityDpi); 2159 2160 assertTrue(wpc.registeredForActivityConfigChanges()); 2161 assertNotEquals(initialConf, wpc.getRequestedOverrideConfiguration()); 2162 assertEquals(0, activity.getMergedOverrideConfiguration() 2163 .diff(wpc.getRequestedOverrideConfiguration())); 2164 } 2165 2166 @Test testActivityReparentDoesntClearProcessOverride_TwoActivities()2167 public void testActivityReparentDoesntClearProcessOverride_TwoActivities() { 2168 final ActivityRecord activity = createActivityWithTask(); 2169 final WindowProcessController wpc = activity.app; 2170 final Configuration initialConf = 2171 new Configuration(activity.getMergedOverrideConfiguration()); 2172 final Task initialTask = activity.getTask(); 2173 final ActivityRecord secondActivity = new ActivityBuilder(mAtm).setTask(initialTask) 2174 .setUseProcess(wpc).build(); 2175 2176 assertTrue(wpc.registeredForActivityConfigChanges()); 2177 assertEquals(0, secondActivity.getMergedOverrideConfiguration() 2178 .diff(wpc.getRequestedOverrideConfiguration())); 2179 2180 // Create a new task with custom config to reparent the second activity to. 2181 final Task newTask = new TaskBuilder(mSupervisor).build(); 2182 final Configuration newConfig = newTask.getConfiguration(); 2183 newConfig.densityDpi += 100; 2184 newTask.onRequestedOverrideConfigurationChanged(newConfig); 2185 2186 // Reparent the activity and verify that config override changed. 2187 secondActivity.reparent(newTask, 0 /* top */, "test"); 2188 2189 assertTrue(wpc.registeredForActivityConfigChanges()); 2190 assertEquals(0, secondActivity.getMergedOverrideConfiguration() 2191 .diff(wpc.getRequestedOverrideConfiguration())); 2192 assertNotEquals(initialConf, wpc.getRequestedOverrideConfiguration()); 2193 2194 // Reparent the first activity and verify that config override didn't change. 2195 activity.reparent(newTask, 1 /* top */, "test"); 2196 assertTrue(wpc.registeredForActivityConfigChanges()); 2197 assertEquals(0, secondActivity.getMergedOverrideConfiguration() 2198 .diff(wpc.getRequestedOverrideConfiguration())); 2199 assertNotEquals(initialConf, wpc.getRequestedOverrideConfiguration()); 2200 } 2201 2202 @Test testActivityDestroyDoesntChangeProcessOverride()2203 public void testActivityDestroyDoesntChangeProcessOverride() { 2204 final ActivityRecord firstActivity = 2205 createActivityOnDisplay(true /* defaultDisplay */, null /* process */); 2206 final WindowProcessController wpc = firstActivity.app; 2207 assertTrue(wpc.registeredForActivityConfigChanges()); 2208 assertEquals(0, firstActivity.getMergedOverrideConfiguration() 2209 .diff(wpc.getRequestedOverrideConfiguration())); 2210 2211 final ActivityRecord secondActivity = 2212 createActivityOnDisplay(false /* defaultDisplay */, wpc); 2213 assertTrue(wpc.registeredForActivityConfigChanges()); 2214 assertEquals(0, secondActivity.getMergedOverrideConfiguration() 2215 .diff(wpc.getRequestedOverrideConfiguration())); 2216 2217 final ActivityRecord thirdActivity = 2218 createActivityOnDisplay(false /* defaultDisplay */, wpc); 2219 assertTrue(wpc.registeredForActivityConfigChanges()); 2220 assertEquals(0, thirdActivity.getMergedOverrideConfiguration() 2221 .diff(wpc.getRequestedOverrideConfiguration())); 2222 2223 secondActivity.destroyImmediately(""); 2224 2225 assertTrue(wpc.registeredForActivityConfigChanges()); 2226 assertEquals(0, thirdActivity.getMergedOverrideConfiguration() 2227 .diff(wpc.getRequestedOverrideConfiguration())); 2228 2229 firstActivity.destroyImmediately(""); 2230 2231 assertTrue(wpc.registeredForActivityConfigChanges()); 2232 assertEquals(0, thirdActivity.getMergedOverrideConfiguration() 2233 .diff(wpc.getRequestedOverrideConfiguration())); 2234 } 2235 2236 @Test testFullscreenWindowCanTurnScreenOn()2237 public void testFullscreenWindowCanTurnScreenOn() { 2238 final ActivityRecord activity = createActivityWithTask(); 2239 final Task task = activity.getTask(); 2240 task.setWindowingMode(WINDOWING_MODE_FULLSCREEN); 2241 doReturn(true).when(activity).getTurnScreenOnFlag(); 2242 2243 assertTrue(activity.canTurnScreenOn()); 2244 } 2245 2246 @Test testFreeformWindowCanTurnScreenOn()2247 public void testFreeformWindowCanTurnScreenOn() { 2248 final ActivityRecord activity = createActivityWithTask(); 2249 final Task task = activity.getTask(); 2250 task.setWindowingMode(WINDOWING_MODE_FREEFORM); 2251 doReturn(true).when(activity).getTurnScreenOnFlag(); 2252 2253 assertTrue(activity.canTurnScreenOn()); 2254 } 2255 2256 @Test testGetLockTaskLaunchMode()2257 public void testGetLockTaskLaunchMode() { 2258 final ActivityRecord activity = createActivityWithTask(); 2259 final ActivityOptions options = ActivityOptions.makeBasic().setLockTaskEnabled(true); 2260 activity.info.lockTaskLaunchMode = LOCK_TASK_LAUNCH_MODE_DEFAULT; 2261 assertEquals(LOCK_TASK_LAUNCH_MODE_IF_ALLOWLISTED, 2262 ActivityRecord.getLockTaskLaunchMode(activity.info, options)); 2263 2264 activity.info.lockTaskLaunchMode = LOCK_TASK_LAUNCH_MODE_ALWAYS; 2265 assertEquals(LOCK_TASK_LAUNCH_MODE_DEFAULT, 2266 ActivityRecord.getLockTaskLaunchMode(activity.info, null /*options*/)); 2267 2268 activity.info.lockTaskLaunchMode = LOCK_TASK_LAUNCH_MODE_NEVER; 2269 assertEquals(LOCK_TASK_LAUNCH_MODE_DEFAULT, 2270 ActivityRecord.getLockTaskLaunchMode(activity.info, null /*options*/)); 2271 2272 activity.info.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_PRIVILEGED; 2273 activity.info.lockTaskLaunchMode = LOCK_TASK_LAUNCH_MODE_ALWAYS; 2274 assertEquals(LOCK_TASK_LAUNCH_MODE_ALWAYS, 2275 ActivityRecord.getLockTaskLaunchMode(activity.info, null /*options*/)); 2276 2277 activity.info.lockTaskLaunchMode = LOCK_TASK_LAUNCH_MODE_NEVER; 2278 assertEquals(LOCK_TASK_LAUNCH_MODE_NEVER, 2279 ActivityRecord.getLockTaskLaunchMode(activity.info, null /*options*/)); 2280 2281 } 2282 2283 @Test testProcessInfoUpdateWhenSetState()2284 public void testProcessInfoUpdateWhenSetState() { 2285 final ActivityRecord activity = createActivityWithTask(); 2286 activity.setState(INITIALIZING, "test"); 2287 spyOn(activity.app); 2288 verifyProcessInfoUpdate(activity, RESUMED, 2289 true /* shouldUpdate */, true /* activityChange */); 2290 verifyProcessInfoUpdate(activity, PAUSED, 2291 false /* shouldUpdate */, false /* activityChange */); 2292 verifyProcessInfoUpdate(activity, STOPPED, 2293 false /* shouldUpdate */, false /* activityChange */); 2294 verifyProcessInfoUpdate(activity, STARTED, 2295 true /* shouldUpdate */, true /* activityChange */); 2296 2297 activity.app.removeActivity(activity, true /* keepAssociation */); 2298 verifyProcessInfoUpdate(activity, DESTROYING, 2299 true /* shouldUpdate */, false /* activityChange */); 2300 verifyProcessInfoUpdate(activity, DESTROYED, 2301 true /* shouldUpdate */, false /* activityChange */); 2302 } 2303 2304 @Test testSupportsFreeform()2305 public void testSupportsFreeform() { 2306 final ActivityRecord activity = new ActivityBuilder(mAtm) 2307 .setCreateTask(true) 2308 .setResizeMode(ActivityInfo.RESIZE_MODE_UNRESIZEABLE) 2309 .setScreenOrientation(SCREEN_ORIENTATION_LANDSCAPE) 2310 .build(); 2311 2312 // Not allow non-resizable 2313 mAtm.mForceResizableActivities = false; 2314 mAtm.mSupportsNonResizableMultiWindow = -1; 2315 mAtm.mDevEnableNonResizableMultiWindow = false; 2316 assertFalse(activity.supportsFreeform()); 2317 2318 // Force resizable 2319 mAtm.mForceResizableActivities = true; 2320 mAtm.mSupportsNonResizableMultiWindow = -1; 2321 mAtm.mDevEnableNonResizableMultiWindow = false; 2322 assertTrue(activity.supportsFreeform()); 2323 2324 // Use development option to allow non-resizable 2325 mAtm.mForceResizableActivities = false; 2326 mAtm.mSupportsNonResizableMultiWindow = -1; 2327 mAtm.mDevEnableNonResizableMultiWindow = true; 2328 assertTrue(activity.supportsFreeform()); 2329 2330 // Always allow non-resizable 2331 mAtm.mForceResizableActivities = false; 2332 mAtm.mSupportsNonResizableMultiWindow = 1; 2333 mAtm.mDevEnableNonResizableMultiWindow = false; 2334 assertTrue(activity.supportsFreeform()); 2335 } 2336 2337 @Test testSupportsPictureInPicture()2338 public void testSupportsPictureInPicture() { 2339 final ActivityRecord activity = new ActivityBuilder(mAtm) 2340 .setCreateTask(true) 2341 .setResizeMode(ActivityInfo.RESIZE_MODE_UNRESIZEABLE) 2342 .setActivityFlags(FLAG_SUPPORTS_PICTURE_IN_PICTURE) 2343 .build(); 2344 2345 // Device not supports PIP 2346 mAtm.mSupportsPictureInPicture = false; 2347 assertFalse(activity.supportsPictureInPicture()); 2348 2349 // Device and app support PIP 2350 mAtm.mSupportsPictureInPicture = true; 2351 assertTrue(activity.supportsPictureInPicture()); 2352 2353 // Activity not supports PIP 2354 activity.info.flags &= ~FLAG_SUPPORTS_PICTURE_IN_PICTURE; 2355 assertFalse(activity.supportsPictureInPicture()); 2356 } 2357 2358 @Test testCheckEnterPictureInPictureState_displayNotSupportedPip()2359 public void testCheckEnterPictureInPictureState_displayNotSupportedPip() { 2360 final Task task = new TaskBuilder(mSupervisor) 2361 .setDisplay(mDisplayContent).build(); 2362 final ActivityRecord activity = new ActivityBuilder(mAtm) 2363 .setTask(task) 2364 .setResizeMode(ActivityInfo.RESIZE_MODE_UNRESIZEABLE) 2365 .setActivityFlags(FLAG_SUPPORTS_PICTURE_IN_PICTURE) 2366 .build(); 2367 mAtm.mSupportsPictureInPicture = true; 2368 AppOpsManager appOpsManager = mAtm.getAppOpsManager(); 2369 doReturn(MODE_ALLOWED).when(appOpsManager).checkOpNoThrow(eq(OP_PICTURE_IN_PICTURE), 2370 anyInt(), any()); 2371 doReturn(false).when(mAtm).shouldDisableNonVrUiLocked(); 2372 2373 spyOn(mDisplayContent.mDwpcHelper); 2374 doReturn(false).when(mDisplayContent.mDwpcHelper).isEnteringPipAllowed(anyInt()); 2375 2376 assertFalse(activity.checkEnterPictureInPictureState("TEST", false /* beforeStopping */)); 2377 } 2378 2379 @Test testLaunchIntoPip()2380 public void testLaunchIntoPip() { 2381 final PictureInPictureParams params = new PictureInPictureParams.Builder() 2382 .build(); 2383 final ActivityOptions opts = ActivityOptions.makeLaunchIntoPip(params); 2384 final ActivityRecord activity = new ActivityBuilder(mAtm) 2385 .setActivityOptions(opts) 2386 .build(); 2387 2388 // Verify the pictureInPictureArgs is set on the new Activity 2389 assertNotNull(activity.pictureInPictureArgs); 2390 assertTrue(activity.pictureInPictureArgs.isLaunchIntoPip()); 2391 } 2392 2393 @Test testActivityServiceConnectionsHolder()2394 public void testActivityServiceConnectionsHolder() { 2395 final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build(); 2396 final ActivityServiceConnectionsHolder<Object> holder = 2397 mAtm.mInternal.getServiceConnectionsHolder(activity.token); 2398 assertNotNull(holder); 2399 final Object connection = new Object(); 2400 holder.addConnection(connection); 2401 assertTrue(holder.isActivityVisible()); 2402 final int[] count = new int[1]; 2403 final Consumer<Object> c = conn -> { 2404 count[0]++; 2405 assertFalse(Thread.holdsLock(activity)); 2406 }; 2407 holder.forEachConnection(c); 2408 assertEquals(1, count[0]); 2409 2410 holder.removeConnection(connection); 2411 holder.forEachConnection(c); 2412 assertEquals(1, count[0]); 2413 2414 activity.setVisibleRequested(false); 2415 activity.setState(STOPPED, "test"); 2416 assertFalse(holder.isActivityVisible()); 2417 2418 activity.removeImmediately(); 2419 assertNull(mAtm.mInternal.getServiceConnectionsHolder(activity.token)); 2420 } 2421 2422 @Test testTransferLaunchCookieWhenFinishing()2423 public void testTransferLaunchCookieWhenFinishing() { 2424 final ActivityRecord activity1 = createActivityWithTask(); 2425 final Binder launchCookie = new Binder(); 2426 activity1.mLaunchCookie = launchCookie; 2427 final ActivityRecord activity2 = createActivityRecord(activity1.getTask()); 2428 activity1.setState(PAUSED, "test"); 2429 activity1.makeFinishingLocked(); 2430 2431 assertEquals(launchCookie, activity2.mLaunchCookie); 2432 assertNull(activity1.mLaunchCookie); 2433 activity2.makeFinishingLocked(); 2434 assertTrue(activity1.getTask().getTaskInfo().launchCookies.contains(launchCookie)); 2435 } 2436 2437 @Test testOrientationForScreenOrientationBehind()2438 public void testOrientationForScreenOrientationBehind() { 2439 final Task task = createTask(mDisplayContent); 2440 // Activity below 2441 new ActivityBuilder(mAtm) 2442 .setTask(task) 2443 .setScreenOrientation(SCREEN_ORIENTATION_PORTRAIT) 2444 .build(); 2445 final ActivityRecord activityTop = new ActivityBuilder(mAtm) 2446 .setTask(task) 2447 .setScreenOrientation(SCREEN_ORIENTATION_BEHIND) 2448 .build(); 2449 final int topOrientation = activityTop.getRequestedConfigurationOrientation(); 2450 assertEquals(ORIENTATION_PORTRAIT, topOrientation); 2451 } 2452 verifyProcessInfoUpdate(ActivityRecord activity, State state, boolean shouldUpdate, boolean activityChange)2453 private void verifyProcessInfoUpdate(ActivityRecord activity, State state, 2454 boolean shouldUpdate, boolean activityChange) { 2455 reset(activity.app); 2456 activity.setState(state, "test"); 2457 verify(activity.app, times(shouldUpdate ? 1 : 0)).updateProcessInfo(anyBoolean(), 2458 eq(activityChange), anyBoolean(), anyBoolean()); 2459 } 2460 createActivityWithTask()2461 private ActivityRecord createActivityWithTask() { 2462 return new ActivityBuilder(mAtm).setCreateTask(true).setOnTop(true).build(); 2463 } 2464 createActivityWith2LevelTask()2465 private ActivityRecord createActivityWith2LevelTask() { 2466 final Task task = new TaskBuilder(mSupervisor) 2467 .setCreateParentTask(true).setCreateActivity(true).build(); 2468 return task.getTopNonFinishingActivity(); 2469 } 2470 2471 /** 2472 * Creates an activity on display. For non-default display request it will also create a new 2473 * display with custom DisplayInfo. 2474 */ createActivityOnDisplay(boolean defaultDisplay, WindowProcessController process)2475 private ActivityRecord createActivityOnDisplay(boolean defaultDisplay, 2476 WindowProcessController process) { 2477 final DisplayContent display; 2478 if (defaultDisplay) { 2479 display = mRootWindowContainer.getDefaultDisplay(); 2480 } else { 2481 display = new TestDisplayContent.Builder(mAtm, 2000, 1000).setDensityDpi(300) 2482 .setPosition(DisplayContent.POSITION_TOP).build(); 2483 } 2484 final Task task = new TaskBuilder(mSupervisor).setDisplay(display).build(); 2485 return new ActivityBuilder(mAtm).setTask(task).setUseProcess(process).build(); 2486 } 2487 2488 @Test 2489 @Presubmit testAddWindow_Order()2490 public void testAddWindow_Order() { 2491 final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build(); 2492 assertEquals(0, activity.getChildCount()); 2493 2494 final WindowState win1 = createWindow(null, TYPE_APPLICATION, activity, "win1"); 2495 final WindowState startingWin = createWindow(null, TYPE_APPLICATION_STARTING, activity, 2496 "startingWin"); 2497 final WindowState baseWin = createWindow(null, TYPE_BASE_APPLICATION, activity, "baseWin"); 2498 final WindowState win4 = createWindow(null, TYPE_APPLICATION, activity, "win4"); 2499 2500 // Should not contain the windows that were added above. 2501 assertEquals(4, activity.getChildCount()); 2502 assertTrue(activity.mChildren.contains(win1)); 2503 assertTrue(activity.mChildren.contains(startingWin)); 2504 assertTrue(activity.mChildren.contains(baseWin)); 2505 assertTrue(activity.mChildren.contains(win4)); 2506 2507 // The starting window should be on-top of all other windows. 2508 assertEquals(startingWin, activity.mChildren.peekLast()); 2509 2510 // The base application window should be below all other windows. 2511 assertEquals(baseWin, activity.mChildren.peekFirst()); 2512 activity.removeImmediately(); 2513 } 2514 2515 @Test 2516 @Presubmit testFindMainWindow()2517 public void testFindMainWindow() { 2518 final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build(); 2519 assertNull(activity.findMainWindow()); 2520 2521 final WindowState window1 = createWindow(null, TYPE_BASE_APPLICATION, activity, "window1"); 2522 final WindowState window11 = createWindow(window1, FIRST_SUB_WINDOW, activity, "window11"); 2523 final WindowState window12 = createWindow(window1, FIRST_SUB_WINDOW, activity, "window12"); 2524 assertEquals(window1, activity.findMainWindow()); 2525 window1.mAnimatingExit = true; 2526 assertEquals(window1, activity.findMainWindow()); 2527 final WindowState window2 = createWindow(null, TYPE_APPLICATION_STARTING, activity, 2528 "window2"); 2529 assertEquals(window2, activity.findMainWindow()); 2530 activity.removeImmediately(); 2531 } 2532 2533 @Test 2534 @Presubmit testGetTopFullscreenOpaqueWindow()2535 public void testGetTopFullscreenOpaqueWindow() { 2536 final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build(); 2537 assertNull(activity.getTopFullscreenOpaqueWindow()); 2538 2539 final WindowState window1 = createWindow(null, TYPE_BASE_APPLICATION, activity, "window1"); 2540 final WindowState window11 = createWindow(null, TYPE_APPLICATION, activity, "window11"); 2541 final WindowState window12 = createWindow(null, TYPE_APPLICATION, activity, "window12"); 2542 assertEquals(window12, activity.getTopFullscreenOpaqueWindow()); 2543 window12.mAttrs.width = 500; 2544 assertEquals(window11, activity.getTopFullscreenOpaqueWindow()); 2545 window11.mAttrs.width = 500; 2546 assertEquals(window1, activity.getTopFullscreenOpaqueWindow()); 2547 window1.mAttrs.alpha = 0f; 2548 assertNull(activity.getTopFullscreenOpaqueWindow()); 2549 activity.removeImmediately(); 2550 } 2551 2552 @SetupWindows(addWindows = W_ACTIVITY) 2553 @Test testLandscapeSeascapeRotationByApp()2554 public void testLandscapeSeascapeRotationByApp() { 2555 final Task task = new TaskBuilder(mSupervisor) 2556 .setDisplay(mDisplayContent).setCreateActivity(true).build(); 2557 final ActivityRecord activity = task.getTopNonFinishingActivity(); 2558 final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams( 2559 TYPE_BASE_APPLICATION); 2560 attrs.setTitle("AppWindow"); 2561 final TestWindowState appWindow = createWindowState(attrs, activity); 2562 activity.addWindow(appWindow); 2563 spyOn(appWindow); 2564 doNothing().when(appWindow).onStartFreezingScreen(); 2565 2566 // Set initial orientation and update. 2567 activity.setOrientation(SCREEN_ORIENTATION_LANDSCAPE); 2568 mDisplayContent.updateOrientation(null /* freezeThisOneIfNeeded */, 2569 false /* forceUpdate */); 2570 assertEquals(SCREEN_ORIENTATION_LANDSCAPE, mDisplayContent.getLastOrientation()); 2571 appWindow.mResizeReported = false; 2572 2573 // Update the orientation to perform 180 degree rotation and check that resize was reported. 2574 activity.setOrientation(SCREEN_ORIENTATION_REVERSE_LANDSCAPE); 2575 mDisplayContent.updateOrientation(null /* freezeThisOneIfNeeded */, 2576 false /* forceUpdate */); 2577 // In this test, DC will not get config update. Set the waiting flag to false. 2578 mDisplayContent.mWaitingForConfig = false; 2579 mWm.mRoot.performSurfacePlacement(); 2580 assertEquals(SCREEN_ORIENTATION_REVERSE_LANDSCAPE, mDisplayContent.getLastOrientation()); 2581 assertTrue(appWindow.mResizeReported); 2582 appWindow.removeImmediately(); 2583 } 2584 2585 @SetupWindows(addWindows = W_ACTIVITY) 2586 @Test testLandscapeSeascapeRotationByPolicy()2587 public void testLandscapeSeascapeRotationByPolicy() { 2588 final Task task = new TaskBuilder(mSupervisor) 2589 .setDisplay(mDisplayContent).setCreateActivity(true).build(); 2590 final ActivityRecord activity = task.getTopNonFinishingActivity(); 2591 final DisplayRotation displayRotation = mDisplayContent.getDisplayRotation(); 2592 spyOn(displayRotation); 2593 2594 final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams( 2595 TYPE_BASE_APPLICATION); 2596 attrs.setTitle("RotationByPolicy"); 2597 final TestWindowState appWindow = createWindowState(attrs, activity); 2598 activity.addWindow(appWindow); 2599 spyOn(appWindow); 2600 doNothing().when(appWindow).onStartFreezingScreen(); 2601 doNothing().when(mWm).startFreezingDisplay(anyInt(), anyInt(), any(), anyInt()); 2602 2603 // Set initial orientation and update. 2604 performRotation(displayRotation, Surface.ROTATION_90); 2605 appWindow.mResizeReported = false; 2606 2607 // Update the rotation to perform 180 degree rotation and check that resize was reported. 2608 performRotation(displayRotation, Surface.ROTATION_270); 2609 assertTrue(appWindow.mResizeReported); 2610 } 2611 performRotation(DisplayRotation spiedRotation, int rotationToReport)2612 private void performRotation(DisplayRotation spiedRotation, int rotationToReport) { 2613 doReturn(rotationToReport).when(spiedRotation).rotationForOrientation(anyInt(), anyInt()); 2614 mWm.updateRotation(false, false); 2615 } 2616 2617 @Test 2618 @Presubmit testGetOrientation()2619 public void testGetOrientation() { 2620 // ActivityBuilder will resume top activities and cause the activity been added into 2621 // opening apps list. Since this test is focus on the effect of visible on getting 2622 // orientation, we skip app transition to avoid interference. 2623 doNothing().when(mDisplayContent).prepareAppTransition(anyInt()); 2624 final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build(); 2625 activity.setVisible(true); 2626 2627 activity.setOrientation(SCREEN_ORIENTATION_LANDSCAPE); 2628 2629 activity.setOccludesParent(false); 2630 // Can specify orientation if app doesn't occludes parent. 2631 assertEquals(SCREEN_ORIENTATION_LANDSCAPE, activity.getOrientation()); 2632 2633 doReturn(true).when(activity).shouldIgnoreOrientationRequests(); 2634 assertEquals(SCREEN_ORIENTATION_UNSET, activity.getOrientation()); 2635 2636 doReturn(false).when(activity).shouldIgnoreOrientationRequests(); 2637 activity.setOccludesParent(true); 2638 activity.setVisible(false); 2639 activity.setVisibleRequested(false); 2640 // Can not specify orientation if app isn't visible even though it occludes parent. 2641 assertEquals(SCREEN_ORIENTATION_UNSET, activity.getOrientation()); 2642 // Can specify orientation if the current orientation candidate is orientation behind. 2643 assertEquals(SCREEN_ORIENTATION_LANDSCAPE, 2644 activity.getOrientation(SCREEN_ORIENTATION_BEHIND)); 2645 } 2646 2647 @Test 2648 @Presubmit testKeyguardFlagsDuringRelaunch()2649 public void testKeyguardFlagsDuringRelaunch() { 2650 final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build(); 2651 final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams( 2652 TYPE_BASE_APPLICATION); 2653 attrs.flags |= FLAG_SHOW_WHEN_LOCKED | FLAG_DISMISS_KEYGUARD; 2654 attrs.setTitle("AppWindow"); 2655 final TestWindowState appWindow = createWindowState(attrs, activity); 2656 2657 // Add window with show when locked flag 2658 activity.addWindow(appWindow); 2659 assertTrue(activity.containsShowWhenLockedWindow() 2660 && activity.containsDismissKeyguardWindow()); 2661 2662 // Start relaunching 2663 activity.startRelaunching(); 2664 assertTrue(activity.containsShowWhenLockedWindow() 2665 && activity.containsDismissKeyguardWindow()); 2666 2667 // Remove window and make sure that we still report back flag 2668 activity.removeChild(appWindow); 2669 assertTrue(activity.containsShowWhenLockedWindow() 2670 && activity.containsDismissKeyguardWindow()); 2671 2672 // Finish relaunching and ensure flag is now not reported 2673 activity.finishRelaunching(); 2674 assertFalse(activity.containsShowWhenLockedWindow() 2675 || activity.containsDismissKeyguardWindow()); 2676 } 2677 2678 @Test testStuckExitingWindow()2679 public void testStuckExitingWindow() { 2680 final WindowState closingWindow = createWindow(null, FIRST_APPLICATION_WINDOW, 2681 "closingWindow"); 2682 closingWindow.mAnimatingExit = true; 2683 closingWindow.mRemoveOnExit = true; 2684 closingWindow.mActivityRecord.commitVisibility( 2685 false /* visible */, true /* performLayout */); 2686 2687 // We pretended that we were running an exit animation, but that should have been cleared up 2688 // by changing visibility of ActivityRecord 2689 closingWindow.removeIfPossible(); 2690 assertTrue(closingWindow.mRemoved); 2691 } 2692 2693 @Test testSetOrientation()2694 public void testSetOrientation() { 2695 final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build(); 2696 activity.setVisible(true); 2697 2698 // Assert orientation is unspecified to start. 2699 assertEquals(SCREEN_ORIENTATION_UNSPECIFIED, activity.getOrientation()); 2700 2701 activity.setOrientation(SCREEN_ORIENTATION_LANDSCAPE); 2702 assertEquals(SCREEN_ORIENTATION_LANDSCAPE, activity.getOrientation()); 2703 2704 mDisplayContent.removeAppToken(activity.token); 2705 // Assert orientation is unset to after container is removed. 2706 assertEquals(SCREEN_ORIENTATION_UNSET, activity.getOrientation()); 2707 2708 // Reset display frozen state 2709 mWm.mDisplayFrozen = false; 2710 } 2711 2712 @Test testRespectTopFullscreenOrientation()2713 public void testRespectTopFullscreenOrientation() { 2714 final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build(); 2715 final Configuration displayConfig = activity.mDisplayContent.getConfiguration(); 2716 final Configuration activityConfig = activity.getConfiguration(); 2717 activity.setOrientation(SCREEN_ORIENTATION_PORTRAIT); 2718 2719 assertEquals(Configuration.ORIENTATION_PORTRAIT, displayConfig.orientation); 2720 assertEquals(Configuration.ORIENTATION_PORTRAIT, activityConfig.orientation); 2721 2722 final ActivityRecord topActivity = createActivityRecord(activity.getTask()); 2723 topActivity.setOrientation(SCREEN_ORIENTATION_LANDSCAPE); 2724 2725 assertEquals(Configuration.ORIENTATION_LANDSCAPE, displayConfig.orientation); 2726 // Although the activity requested portrait, it is not the top activity that determines 2727 // the display orientation. So it should be able to inherit the orientation from parent. 2728 // Otherwise its configuration will be inconsistent that its orientation is portrait but 2729 // other screen configurations are in landscape, e.g. screenWidthDp, screenHeightDp, and 2730 // window configuration. 2731 assertEquals(Configuration.ORIENTATION_LANDSCAPE, activityConfig.orientation); 2732 } 2733 2734 @Test testReportOrientationChange()2735 public void testReportOrientationChange() { 2736 final Task task = new TaskBuilder(mSupervisor) 2737 .setDisplay(mDisplayContent).setCreateActivity(true).build(); 2738 final ActivityRecord activity = task.getTopNonFinishingActivity(); 2739 activity.setOrientation(SCREEN_ORIENTATION_LANDSCAPE); 2740 2741 mDisplayContent.getDisplayRotation().setFixedToUserRotation( 2742 IWindowManager.FIXED_TO_USER_ROTATION_ENABLED); 2743 reset(task); 2744 activity.reportDescendantOrientationChangeIfNeeded(); 2745 verify(task, atLeast(1)).onConfigurationChanged(any(Configuration.class)); 2746 } 2747 2748 @Test testCreateRemoveStartingWindow()2749 public void testCreateRemoveStartingWindow() { 2750 registerTestStartingWindowOrganizer(); 2751 final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build(); 2752 activity.addStartingWindow(mPackageName, android.R.style.Theme, null, true, true, false, 2753 true, false, false, false); 2754 waitUntilHandlersIdle(); 2755 assertHasStartingWindow(activity); 2756 activity.removeStartingWindow(); 2757 waitUntilHandlersIdle(); 2758 assertNoStartingWindow(activity); 2759 } 2760 testLegacySplashScreen(int targetSdk, int verifyType)2761 private void testLegacySplashScreen(int targetSdk, int verifyType) { 2762 final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build(); 2763 activity.mTargetSdk = targetSdk; 2764 activity.addStartingWindow(mPackageName, android.R.style.Theme, null, true, true, false, 2765 true, false, false, false); 2766 waitUntilHandlersIdle(); 2767 assertHasStartingWindow(activity); 2768 assertEquals(activity.mStartingData.mTypeParams & TYPE_PARAMETER_LEGACY_SPLASH_SCREEN, 2769 verifyType); 2770 activity.removeStartingWindow(); 2771 waitUntilHandlersIdle(); 2772 assertNoStartingWindow(activity); 2773 } 2774 2775 @Test testCreateRemoveLegacySplashScreenWindow()2776 public void testCreateRemoveLegacySplashScreenWindow() { 2777 registerTestStartingWindowOrganizer(); 2778 DeviceConfig.Properties properties = DeviceConfig.getProperties( 2779 DeviceConfig.NAMESPACE_WINDOW_MANAGER); 2780 try { 2781 DeviceConfig.setProperty(DeviceConfig.NAMESPACE_WINDOW_MANAGER, 2782 "splash_screen_exception_list", DEFAULT_COMPONENT_PACKAGE_NAME, false); 2783 testLegacySplashScreen(Build.VERSION_CODES.R, TYPE_PARAMETER_LEGACY_SPLASH_SCREEN); 2784 testLegacySplashScreen(Build.VERSION_CODES.S, TYPE_PARAMETER_LEGACY_SPLASH_SCREEN); 2785 testLegacySplashScreen(Build.VERSION_CODES.TIRAMISU, 2786 TYPE_PARAMETER_LEGACY_SPLASH_SCREEN); 2787 testLegacySplashScreen(Build.VERSION_CODES.UPSIDE_DOWN_CAKE, 2788 TYPE_PARAMETER_LEGACY_SPLASH_SCREEN); 2789 testLegacySplashScreen(Build.VERSION_CODES.UPSIDE_DOWN_CAKE + 1, 2790 TYPE_PARAMETER_LEGACY_SPLASH_SCREEN); 2791 // Above V 2792 testLegacySplashScreen(Build.VERSION_CODES.UPSIDE_DOWN_CAKE + 2, 0); 2793 } finally { 2794 try { 2795 DeviceConfig.setProperties(properties); 2796 } catch (DeviceConfig.BadConfigException e) { 2797 Assert.fail(e.getMessage()); 2798 } 2799 } 2800 } 2801 2802 @Test testTransferStartingWindow()2803 public void testTransferStartingWindow() { 2804 registerTestStartingWindowOrganizer(); 2805 final ActivityRecord activity1 = new ActivityBuilder(mAtm).setCreateTask(true) 2806 .setVisible(false).build(); 2807 final ActivityRecord activity2 = new ActivityBuilder(mAtm).setCreateTask(true) 2808 .setVisible(false).build(); 2809 activity1.addStartingWindow(mPackageName, android.R.style.Theme, null, true, true, false, 2810 true, false, false, false); 2811 waitUntilHandlersIdle(); 2812 activity2.addStartingWindow(mPackageName, android.R.style.Theme, activity1, true, true, 2813 false, true, false, false, false); 2814 waitUntilHandlersIdle(); 2815 assertFalse(mDisplayContent.mSkipAppTransitionAnimation); 2816 assertNoStartingWindow(activity1); 2817 assertHasStartingWindow(activity2); 2818 } 2819 2820 @Test testTransferStartingWindowWhileCreating()2821 public void testTransferStartingWindowWhileCreating() { 2822 final TestStartingWindowOrganizer organizer = registerTestStartingWindowOrganizer(); 2823 final ActivityRecord activity1 = new ActivityBuilder(mAtm).setCreateTask(true).build(); 2824 final ActivityRecord activity2 = new ActivityBuilder(mAtm).setCreateTask(true).build(); 2825 organizer.setRunnableWhenAddingSplashScreen( 2826 () -> { 2827 // Surprise, ...! Transfer window in the middle of the creation flow. 2828 activity2.addStartingWindow(mPackageName, android.R.style.Theme, activity1, 2829 true, true, false, true, false, false, false); 2830 }); 2831 activity1.addStartingWindow(mPackageName, android.R.style.Theme, null, true, true, false, 2832 true, false, false, false); 2833 waitUntilHandlersIdle(); 2834 assertNoStartingWindow(activity1); 2835 assertHasStartingWindow(activity2); 2836 } 2837 2838 @Test testTransferStartingWindowCanAnimate()2839 public void testTransferStartingWindowCanAnimate() { 2840 registerTestStartingWindowOrganizer(); 2841 final ActivityRecord activity1 = new ActivityBuilder(mAtm).setCreateTask(true).build(); 2842 final ActivityRecord activity2 = new ActivityBuilder(mAtm).setCreateTask(true).build(); 2843 activity1.addStartingWindow(mPackageName, android.R.style.Theme, null, true, true, false, 2844 true, false, false, false); 2845 waitUntilHandlersIdle(); 2846 activity2.addStartingWindow(mPackageName, android.R.style.Theme, activity1, true, true, 2847 false, true, false, false, false); 2848 waitUntilHandlersIdle(); 2849 assertNoStartingWindow(activity1); 2850 assertHasStartingWindow(activity2); 2851 2852 // Assert that bottom activity is allowed to do animation. 2853 ArrayList<WindowContainer> sources = new ArrayList<>(); 2854 sources.add(activity2); 2855 doReturn(true).when(activity2).okToAnimate(); 2856 doReturn(true).when(activity2).isAnimating(); 2857 assertTrue(activity2.applyAnimation(null, TRANSIT_OLD_ACTIVITY_OPEN, true, false, sources)); 2858 } 2859 @Test testTrackingStartingWindowThroughTrampoline()2860 public void testTrackingStartingWindowThroughTrampoline() { 2861 final ActivityRecord sourceRecord = new ActivityBuilder(mAtm) 2862 .setCreateTask(true).setLaunchedFromUid(Process.SYSTEM_UID).build(); 2863 sourceRecord.showStartingWindow(null /* prev */, true /* newTask */, false, 2864 true /* startActivity */, null); 2865 2866 final ActivityRecord secondRecord = new ActivityBuilder(mAtm) 2867 .setTask(sourceRecord.getTask()).build(); 2868 secondRecord.showStartingWindow(null /* prev */, true /* newTask */, false, 2869 true /* startActivity */, sourceRecord); 2870 assertFalse(secondRecord.mSplashScreenStyleSolidColor); 2871 secondRecord.onStartingWindowDrawn(); 2872 2873 final ActivityRecord finalRecord = new ActivityBuilder(mAtm) 2874 .setTask(sourceRecord.getTask()).build(); 2875 finalRecord.showStartingWindow(null /* prev */, true /* newTask */, false, 2876 true /* startActivity */, secondRecord); 2877 assertTrue(finalRecord.mSplashScreenStyleSolidColor); 2878 } 2879 2880 @Test testTransferStartingWindowFromFinishingActivity()2881 public void testTransferStartingWindowFromFinishingActivity() { 2882 registerTestStartingWindowOrganizer(); 2883 final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build(); 2884 final Task task = activity.getTask(); 2885 activity.addStartingWindow(mPackageName, android.R.style.Theme, null /* transferFrom */, 2886 true /* newTask */, true /* taskSwitch */, false /* processRunning */, 2887 false /* allowTaskSnapshot */, false /* activityCreate */, false /* suggestEmpty 2888 */, false /* activityAllDrawn */); 2889 waitUntilHandlersIdle(); 2890 assertHasStartingWindow(activity); 2891 2892 doCallRealMethod().when(task).startActivityLocked( 2893 any(), any(), anyBoolean(), anyBoolean(), any(), any()); 2894 // In normal case, resumeFocusedTasksTopActivities() should be called after 2895 // startActivityLocked(). So skip resumeFocusedTasksTopActivities() in ActivityBuilder. 2896 doReturn(false).when(mRootWindowContainer) 2897 .resumeFocusedTasksTopActivities(); 2898 // Make mVisibleSetFromTransferredStartingWindow true. 2899 final ActivityRecord middle = new ActivityBuilder(mAtm).setTask(task).build(); 2900 task.startActivityLocked(middle, null /* topTask */, 2901 false /* newTask */, false /* isTaskSwitch */, null /* options */, 2902 null /* sourceRecord */); 2903 middle.makeFinishingLocked(); 2904 2905 assertNull(activity.mStartingWindow); 2906 assertHasStartingWindow(middle); 2907 2908 final ActivityRecord top = new ActivityBuilder(mAtm).setTask(task).build(); 2909 // Expect the visibility should be updated to true when transferring starting window from 2910 // a visible activity. 2911 top.setVisible(false); 2912 // The finishing middle should be able to transfer starting window to top. 2913 task.startActivityLocked(top, null /* topTask */, 2914 false /* newTask */, false /* isTaskSwitch */, null /* options */, 2915 null /* sourceRecord */); 2916 2917 assertTrue(mDisplayContent.mSkipAppTransitionAnimation); 2918 assertNull(middle.mStartingWindow); 2919 assertHasStartingWindow(top); 2920 assertTrue(top.isVisible()); 2921 // The activity was visible by mVisibleSetFromTransferredStartingWindow, so after its 2922 // starting window is transferred, it should restore to invisible. 2923 assertFalse(middle.isVisible()); 2924 } 2925 2926 @Test testTransferStartingWindowSetFixedRotation()2927 public void testTransferStartingWindowSetFixedRotation() { 2928 registerTestStartingWindowOrganizer(); 2929 final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build(); 2930 final Task task = activity.getTask(); 2931 final ActivityRecord topActivity = new ActivityBuilder(mAtm).setTask(task).build(); 2932 topActivity.setVisible(false); 2933 task.positionChildAt(POSITION_TOP, topActivity, false /* includeParents */); 2934 activity.addStartingWindow(mPackageName, android.R.style.Theme, null, true, true, false, 2935 true, false, false, false); 2936 waitUntilHandlersIdle(); 2937 2938 // Make activities to have different rotation from it display and set fixed rotation 2939 // transform to activity1. 2940 int rotation = (mDisplayContent.getRotation() + 1) % 4; 2941 mDisplayContent.setFixedRotationLaunchingApp(activity, rotation); 2942 // The configuration with rotation change should not trigger task-association. 2943 assertNotNull(activity.mStartingData); 2944 assertNull(activity.mStartingData.mAssociatedTask); 2945 doReturn(rotation).when(mDisplayContent) 2946 .rotationForActivityInDifferentOrientation(topActivity); 2947 2948 // The transform will be finished because there is no running animation. Keep activity in 2949 // animating state to avoid the transform being finished. 2950 doReturn(true).when(activity).isAnimating(anyInt()); 2951 // Make sure the fixed rotation transform linked to activity2 when adding starting window 2952 // on activity2. 2953 topActivity.addStartingWindow(mPackageName, android.R.style.Theme, activity, false, false, 2954 false, true, false, false, false); 2955 waitUntilHandlersIdle(); 2956 assertTrue(topActivity.hasFixedRotationTransform()); 2957 } 2958 2959 @Test testTryTransferStartingWindowFromHiddenAboveToken()2960 public void testTryTransferStartingWindowFromHiddenAboveToken() { 2961 registerTestStartingWindowOrganizer(); 2962 // Add two tasks on top of each other. 2963 final ActivityRecord activityTop = new ActivityBuilder(mAtm).setCreateTask(true).build(); 2964 final ActivityRecord activityBottom = new ActivityBuilder(mAtm).build(); 2965 activityTop.getTask().addChild(activityBottom, 0); 2966 2967 // Add a starting window. 2968 activityTop.addStartingWindow(mPackageName, android.R.style.Theme, null, true, true, false, 2969 true, false, false, false); 2970 waitUntilHandlersIdle(); 2971 2972 final WindowState startingWindow = activityTop.mStartingWindow; 2973 assertNotNull(startingWindow); 2974 2975 // Make the top one invisible, and try transferring the starting window from the top to the 2976 // bottom one. 2977 activityTop.setVisibility(false); 2978 activityBottom.transferStartingWindowFromHiddenAboveTokenIfNeeded(); 2979 waitUntilHandlersIdle(); 2980 2981 // Expect getFrozenInsetsState will be null when transferring the starting window. 2982 assertNull(startingWindow.getFrozenInsetsState()); 2983 2984 // Assert that the bottom window now has the starting window. 2985 assertNoStartingWindow(activityTop); 2986 assertHasStartingWindow(activityBottom); 2987 } 2988 2989 @Test testStartingWindowInTaskFragment()2990 public void testStartingWindowInTaskFragment() { 2991 final ActivityRecord activity1 = new ActivityBuilder(mAtm).setCreateTask(true).build(); 2992 final WindowState startingWindow = createWindowState( 2993 new WindowManager.LayoutParams(TYPE_APPLICATION_STARTING), activity1); 2994 activity1.addWindow(startingWindow); 2995 activity1.mStartingData = mock(StartingData.class); 2996 activity1.attachStartingWindow(startingWindow); 2997 final Task task = activity1.getTask(); 2998 final Rect taskBounds = task.getBounds(); 2999 final int width = taskBounds.width(); 3000 final int height = taskBounds.height(); 3001 final BiConsumer<TaskFragment, Rect> fragmentSetup = (fragment, bounds) -> { 3002 final Configuration config = fragment.getRequestedOverrideConfiguration(); 3003 config.windowConfiguration.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW); 3004 config.windowConfiguration.setBounds(bounds); 3005 fragment.onRequestedOverrideConfigurationChanged(config); 3006 }; 3007 3008 final TaskFragment taskFragment1 = new TaskFragment( 3009 mAtm, null /* fragmentToken */, false /* createdByOrganizer */); 3010 fragmentSetup.accept(taskFragment1, new Rect(0, 0, width / 2, height)); 3011 task.addChild(taskFragment1, POSITION_TOP); 3012 assertEquals(task, activity1.mStartingData.mAssociatedTask); 3013 assertEquals(activity1.mStartingData, task.mSharedStartingData); 3014 3015 final TaskFragment taskFragment2 = new TaskFragment( 3016 mAtm, null /* fragmentToken */, false /* createdByOrganizer */); 3017 fragmentSetup.accept(taskFragment2, new Rect(width / 2, 0, width, height)); 3018 task.addChild(taskFragment2, POSITION_TOP); 3019 final ActivityRecord activity2 = new ActivityBuilder(mAtm) 3020 .setResizeMode(ActivityInfo.RESIZE_MODE_UNRESIZEABLE).build(); 3021 activity2.setVisibleRequested(true); 3022 taskFragment2.addChild(activity2); 3023 assertTrue(activity2.isResizeable()); 3024 activity1.reparent(taskFragment1, POSITION_TOP); 3025 3026 // Adds an Activity which doesn't have shared starting data, and verify if it blocks 3027 // starting window removal. 3028 final ActivityRecord activity3 = new ActivityBuilder(mAtm).build(); 3029 taskFragment2.addChild(activity3, POSITION_TOP); 3030 3031 verify(activity1.getSyncTransaction()).reparent(eq(startingWindow.mSurfaceControl), 3032 eq(task.mSurfaceControl)); 3033 assertEquals(task.mSurfaceControl, startingWindow.getAnimationLeashParent()); 3034 assertEquals(taskFragment1.getBounds(), activity1.getBounds()); 3035 // The activity was resized by task fragment, but starting window must still cover the task. 3036 assertEquals(taskBounds, activity1.mStartingWindow.getBounds()); 3037 3038 // The starting window is only removed when all embedded activities are drawn. 3039 final WindowState activityWindow = mock(WindowState.class); 3040 activity1.onFirstWindowDrawn(activityWindow); 3041 activity2.onFirstWindowDrawn(activityWindow); 3042 assertNull(activity1.mStartingWindow); 3043 assertNull(task.mSharedStartingData); 3044 } 3045 3046 @Test testTransitionAnimationBounds()3047 public void testTransitionAnimationBounds() { 3048 removeGlobalMinSizeRestriction(); 3049 final Task task = new TaskBuilder(mSupervisor) 3050 .setCreateParentTask(true).setCreateActivity(true).build(); 3051 final Task rootTask = task.getRootTask(); 3052 final ActivityRecord activity = task.getTopNonFinishingActivity(); 3053 final Rect stackBounds = new Rect(0, 0, 1000, 600); 3054 final Rect taskBounds = new Rect(100, 400, 600, 800); 3055 // Set the bounds and windowing mode to window configuration directly, otherwise the 3056 // testing setups may be discarded by configuration resolving. 3057 rootTask.getWindowConfiguration().setBounds(stackBounds); 3058 task.getWindowConfiguration().setBounds(taskBounds); 3059 activity.getWindowConfiguration().setBounds(taskBounds); 3060 3061 // Check that anim bounds for freeform window match task bounds 3062 task.getWindowConfiguration().setWindowingMode(WINDOWING_MODE_FREEFORM); 3063 assertEquals(task.getBounds(), activity.getAnimationBounds(ROOT_TASK_CLIP_NONE)); 3064 3065 // ROOT_TASK_CLIP_AFTER_ANIM should use task bounds since they will be clipped by 3066 // bounds animation layer. 3067 task.getWindowConfiguration().setWindowingMode(WINDOWING_MODE_FULLSCREEN); 3068 assertEquals(task.getBounds(), activity.getAnimationBounds(ROOT_TASK_CLIP_AFTER_ANIM)); 3069 3070 // Even the activity is smaller than task and it is not aligned to the top-left corner of 3071 // task, the animation bounds the same as task and position should be zero because in real 3072 // case the letterbox will fill the remaining area in task. 3073 final Rect halfBounds = new Rect(taskBounds); 3074 halfBounds.scale(0.5f); 3075 activity.getWindowConfiguration().setBounds(halfBounds); 3076 final Point animationPosition = new Point(); 3077 activity.getAnimationPosition(animationPosition); 3078 3079 assertEquals(taskBounds, activity.getAnimationBounds(ROOT_TASK_CLIP_AFTER_ANIM)); 3080 assertEquals(new Point(0, 0), animationPosition); 3081 } 3082 3083 @Test testTransitionAnimationBounds_returnTaskFragment()3084 public void testTransitionAnimationBounds_returnTaskFragment() { 3085 removeGlobalMinSizeRestriction(); 3086 final Task task = new TaskBuilder(mSupervisor).setCreateParentTask(true).build(); 3087 final Task rootTask = task.getRootTask(); 3088 final TaskFragment taskFragment = createTaskFragmentWithActivity(task); 3089 final ActivityRecord activity = taskFragment.getTopNonFinishingActivity(); 3090 final Rect stackBounds = new Rect(0, 0, 1000, 600); 3091 final Rect taskBounds = new Rect(100, 400, 600, 800); 3092 final Rect taskFragmentBounds = new Rect(100, 400, 300, 800); 3093 final Rect activityBounds = new Rect(100, 400, 300, 600); 3094 // Set the bounds and windowing mode to window configuration directly, otherwise the 3095 // testing setups may be discarded by configuration resolving. 3096 rootTask.getWindowConfiguration().setBounds(stackBounds); 3097 task.getWindowConfiguration().setBounds(taskBounds); 3098 taskFragment.getWindowConfiguration().setBounds(taskFragmentBounds); 3099 activity.getWindowConfiguration().setBounds(activityBounds); 3100 3101 // Check that anim bounds for freeform window match task fragment bounds 3102 task.getWindowConfiguration().setWindowingMode(WINDOWING_MODE_FREEFORM); 3103 assertEquals(taskFragment.getBounds(), activity.getAnimationBounds(ROOT_TASK_CLIP_NONE)); 3104 3105 // ROOT_TASK_CLIP_AFTER_ANIM should use task fragment bounds since they will be clipped by 3106 // bounds animation layer. 3107 task.getWindowConfiguration().setWindowingMode(WINDOWING_MODE_FULLSCREEN); 3108 assertEquals(taskFragment.getBounds(), 3109 activity.getAnimationBounds(ROOT_TASK_CLIP_AFTER_ANIM)); 3110 } 3111 3112 @Test testHasStartingWindow()3113 public void testHasStartingWindow() { 3114 final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true).build(); 3115 final WindowManager.LayoutParams attrs = 3116 new WindowManager.LayoutParams(TYPE_APPLICATION_STARTING); 3117 final TestWindowState startingWindow = createWindowState(attrs, activity); 3118 activity.mStartingData = mock(StartingData.class); 3119 activity.addWindow(startingWindow); 3120 assertTrue("Starting window should be present", activity.hasStartingWindow()); 3121 activity.mStartingData = null; 3122 assertTrue("Starting window should be present", activity.hasStartingWindow()); 3123 3124 activity.removeChild(startingWindow); 3125 assertFalse("Starting window should not be present", activity.hasStartingWindow()); 3126 } 3127 3128 @Test testCloseToSquareFixedOrientation()3129 public void testCloseToSquareFixedOrientation() { 3130 // create a square display 3131 final DisplayContent squareDisplay = new TestDisplayContent.Builder(mAtm, 2000, 2000) 3132 .setSystemDecorations(true).build(); 3133 // Add a decor insets provider window. 3134 final WindowState navbar = createNavBarWithProvidedInsets(squareDisplay); 3135 assertTrue(navbar.providesDisplayDecorInsets() 3136 && squareDisplay.getDisplayPolicy().updateDecorInsetsInfo()); 3137 squareDisplay.sendNewConfiguration(); 3138 final Task task = new TaskBuilder(mSupervisor).setDisplay(squareDisplay).build(); 3139 3140 // create a fixed portrait activity 3141 ActivityRecord activity = new ActivityBuilder(mAtm).setTask(task) 3142 .setScreenOrientation(SCREEN_ORIENTATION_PORTRAIT).build(); 3143 3144 // The available space could be landscape because of decor insets, but the configuration 3145 // should still respect the requested portrait orientation. 3146 assertEquals(ORIENTATION_PORTRAIT, activity.getConfiguration().orientation); 3147 assertTrue(activity.getConfiguration().windowConfiguration.getAppBounds().width() 3148 <= activity.getConfiguration().windowConfiguration.getAppBounds().height()); 3149 3150 // create a fixed landscape activity 3151 activity = new ActivityBuilder(mAtm).setTask(task) 3152 .setScreenOrientation(SCREEN_ORIENTATION_LANDSCAPE).build(); 3153 3154 // check that both the configuration and app bounds are landscape 3155 assertEquals(ORIENTATION_LANDSCAPE, activity.getConfiguration().orientation); 3156 assertTrue(activity.getConfiguration().windowConfiguration.getAppBounds().width() 3157 > activity.getConfiguration().windowConfiguration.getAppBounds().height()); 3158 } 3159 3160 @Test testSetVisibility_visibleToVisible()3161 public void testSetVisibility_visibleToVisible() { 3162 final ActivityRecord activity = new ActivityBuilder(mAtm) 3163 .setCreateTask(true).build(); 3164 // By default, activity is visible. 3165 assertTrue(activity.isVisible()); 3166 assertTrue(activity.isVisibleRequested()); 3167 assertTrue(activity.mDisplayContent.mOpeningApps.contains(activity)); 3168 assertFalse(activity.mDisplayContent.mClosingApps.contains(activity)); 3169 3170 // Request the activity to be visible. Although the activity is already visible, app 3171 // transition animation should be applied on this activity. This might be unnecessary, but 3172 // until we verify no logic relies on this behavior, we'll keep this as is. 3173 activity.setVisibility(true); 3174 assertTrue(activity.isVisible()); 3175 assertTrue(activity.isVisibleRequested()); 3176 assertTrue(activity.mDisplayContent.mOpeningApps.contains(activity)); 3177 assertFalse(activity.mDisplayContent.mClosingApps.contains(activity)); 3178 } 3179 3180 @Test testSetVisibility_visibleToInvisible()3181 public void testSetVisibility_visibleToInvisible() { 3182 final ActivityRecord activity = new ActivityBuilder(mAtm) 3183 .setCreateTask(true).build(); 3184 // By default, activity is visible. 3185 assertTrue(activity.isVisible()); 3186 assertTrue(activity.isVisibleRequested()); 3187 assertTrue(activity.mDisplayContent.mOpeningApps.contains(activity)); 3188 assertFalse(activity.mDisplayContent.mClosingApps.contains(activity)); 3189 3190 // Request the activity to be invisible. Since the visibility changes, app transition 3191 // animation should be applied on this activity. 3192 activity.setVisibility(false); 3193 assertTrue(activity.isVisible()); 3194 assertFalse(activity.isVisibleRequested()); 3195 assertFalse(activity.mDisplayContent.mOpeningApps.contains(activity)); 3196 assertTrue(activity.mDisplayContent.mClosingApps.contains(activity)); 3197 } 3198 3199 @Test testSetVisibility_invisibleToVisible()3200 public void testSetVisibility_invisibleToVisible() { 3201 final ActivityRecord activity = new ActivityBuilder(mAtm) 3202 .setCreateTask(true).setVisible(false).build(); 3203 // Activiby is invisible. However ATMS requests it to become visible, since this is a top 3204 // activity. 3205 assertFalse(activity.isVisible()); 3206 assertTrue(activity.isVisibleRequested()); 3207 assertTrue(activity.mDisplayContent.mOpeningApps.contains(activity)); 3208 assertFalse(activity.mDisplayContent.mClosingApps.contains(activity)); 3209 3210 // Request the activity to be visible. Since the visibility changes, app transition 3211 // animation should be applied on this activity. 3212 activity.setVisibility(true); 3213 assertFalse(activity.isVisible()); 3214 assertTrue(activity.isVisibleRequested()); 3215 assertTrue(activity.mDisplayContent.mOpeningApps.contains(activity)); 3216 assertFalse(activity.mDisplayContent.mClosingApps.contains(activity)); 3217 3218 // There should still be animation (add to opening) if keyguard is going away while the 3219 // screen is off because it will be visible after screen is turned on by unlocking. 3220 mDisplayContent.mOpeningApps.remove(activity); 3221 mDisplayContent.mClosingApps.remove(activity); 3222 activity.commitVisibility(false /* visible */, false /* performLayout */); 3223 mDisplayContent.getDisplayPolicy().screenTurnedOff(); 3224 final KeyguardController controller = mSupervisor.getKeyguardController(); 3225 doReturn(true).when(controller).isKeyguardGoingAway(anyInt()); 3226 activity.setVisibility(true); 3227 assertTrue(mDisplayContent.mOpeningApps.contains(activity)); 3228 } 3229 3230 @Test testSetVisibility_invisibleToInvisible()3231 public void testSetVisibility_invisibleToInvisible() { 3232 final ActivityRecord activity = new ActivityBuilder(mAtm) 3233 .setCreateTask(true).setVisible(false).build(); 3234 // Activiby is invisible. However ATMS requests it to become visible, since this is a top 3235 // activity. 3236 assertFalse(activity.isVisible()); 3237 assertTrue(activity.isVisibleRequested()); 3238 assertTrue(activity.mDisplayContent.mOpeningApps.contains(activity)); 3239 assertFalse(activity.mDisplayContent.mClosingApps.contains(activity)); 3240 3241 // Request the activity to be invisible. Since the activity is already invisible, no app 3242 // transition should be applied on this activity. 3243 activity.setVisibility(false); 3244 assertFalse(activity.isVisible()); 3245 assertFalse(activity.isVisibleRequested()); 3246 assertFalse(activity.mDisplayContent.mOpeningApps.contains(activity)); 3247 assertFalse(activity.mDisplayContent.mClosingApps.contains(activity)); 3248 } 3249 3250 @SetupWindows(addWindows = W_INPUT_METHOD) 3251 @Test testImeInsetsFrozenFlag_resetWhenNoImeFocusableInActivity()3252 public void testImeInsetsFrozenFlag_resetWhenNoImeFocusableInActivity() { 3253 final WindowState app = createWindow(null, TYPE_APPLICATION, "app"); 3254 makeWindowVisibleAndDrawn(app, mImeWindow); 3255 mDisplayContent.setImeLayeringTarget(app); 3256 mDisplayContent.setImeInputTarget(app); 3257 3258 // Simulate app is closing and expect the last IME is shown and IME insets is frozen. 3259 mDisplayContent.mOpeningApps.clear(); 3260 app.mActivityRecord.commitVisibility(false, false); 3261 app.mActivityRecord.onWindowsGone(); 3262 3263 assertTrue(app.mActivityRecord.mLastImeShown); 3264 assertTrue(app.mActivityRecord.mImeInsetsFrozenUntilStartInput); 3265 3266 // Expect IME insets frozen state will reset when the activity has no IME focusable window. 3267 app.mActivityRecord.forAllWindows(w -> { 3268 w.mAttrs.flags |= FLAG_ALT_FOCUSABLE_IM; 3269 return true; 3270 }, true); 3271 3272 app.mActivityRecord.commitVisibility(true, false); 3273 app.mActivityRecord.onWindowsVisible(); 3274 3275 assertFalse(app.mActivityRecord.mImeInsetsFrozenUntilStartInput); 3276 } 3277 3278 @SetupWindows(addWindows = W_INPUT_METHOD) 3279 @Test testImeInsetsFrozenFlag_resetWhenReportedToBeImeInputTarget()3280 public void testImeInsetsFrozenFlag_resetWhenReportedToBeImeInputTarget() { 3281 final WindowState app = createWindow(null, TYPE_APPLICATION, "app"); 3282 3283 mDisplayContent.getInsetsStateController().getImeSourceProvider().setWindowContainer( 3284 mImeWindow, null, null); 3285 mImeWindow.getControllableInsetProvider().setServerVisible(true); 3286 3287 InsetsSource imeSource = new InsetsSource(ID_IME, ime()); 3288 app.mAboveInsetsState.addSource(imeSource); 3289 mDisplayContent.setImeLayeringTarget(app); 3290 mDisplayContent.updateImeInputAndControlTarget(app); 3291 3292 InsetsState state = app.getInsetsState(); 3293 assertFalse(state.getOrCreateSource(imeSource.getId(), ime()).isVisible()); 3294 assertTrue(state.getOrCreateSource(imeSource.getId(), ime()).getFrame().isEmpty()); 3295 3296 // Simulate app is closing and expect IME insets is frozen. 3297 mDisplayContent.mOpeningApps.clear(); 3298 app.mActivityRecord.commitVisibility(false, false); 3299 app.mActivityRecord.onWindowsGone(); 3300 assertTrue(app.mActivityRecord.mImeInsetsFrozenUntilStartInput); 3301 3302 // Simulate app re-start input or turning screen off/on then unlocked by un-secure 3303 // keyguard to back to the app, expect IME insets is not frozen 3304 app.mActivityRecord.commitVisibility(true, false); 3305 mDisplayContent.updateImeInputAndControlTarget(app); 3306 mDisplayContent.mWmService.mRoot.performSurfacePlacement(); 3307 3308 assertFalse(app.mActivityRecord.mImeInsetsFrozenUntilStartInput); 3309 3310 imeSource.setVisible(true); 3311 imeSource.setFrame(new Rect(100, 400, 500, 500)); 3312 app.mAboveInsetsState.addSource(imeSource); 3313 3314 // Verify when IME is visible and the app can receive the right IME insets from policy. 3315 makeWindowVisibleAndDrawn(app, mImeWindow); 3316 state = app.getInsetsState(); 3317 assertTrue(state.peekSource(ID_IME).isVisible()); 3318 assertEquals(state.peekSource(ID_IME).getFrame(), imeSource.getFrame()); 3319 } 3320 3321 @SetupWindows(addWindows = { W_ACTIVITY, W_INPUT_METHOD }) 3322 @Test testImeInsetsFrozenFlag_noDispatchVisibleInsetsWhenAppNotRequest()3323 public void testImeInsetsFrozenFlag_noDispatchVisibleInsetsWhenAppNotRequest() 3324 throws RemoteException { 3325 final WindowState app1 = createWindow(null, TYPE_APPLICATION, "app1"); 3326 final WindowState app2 = createWindow(null, TYPE_APPLICATION, "app2"); 3327 3328 mDisplayContent.getInsetsStateController().getImeSourceProvider().setWindowContainer( 3329 mImeWindow, null, null); 3330 mImeWindow.getControllableInsetProvider().setServerVisible(true); 3331 3332 // Simulate app2 is closing and let app1 is visible to be IME targets. 3333 makeWindowVisibleAndDrawn(app1, mImeWindow); 3334 mDisplayContent.setImeLayeringTarget(app1); 3335 mDisplayContent.updateImeInputAndControlTarget(app1); 3336 app2.mActivityRecord.commitVisibility(false, false); 3337 3338 // app1 requests IME visible. 3339 app1.setRequestedVisibleTypes(ime(), ime()); 3340 mDisplayContent.getInsetsStateController().onRequestedVisibleTypesChanged(app1); 3341 3342 // Verify app1's IME insets is visible and app2's IME insets frozen flag set. 3343 assertTrue(app1.getInsetsState().peekSource(ID_IME).isVisible()); 3344 assertTrue(app2.mActivityRecord.mImeInsetsFrozenUntilStartInput); 3345 3346 // Simulate switching to app2 to make it visible to be IME targets. 3347 spyOn(app2); 3348 spyOn(app2.mClient); 3349 ArgumentCaptor<InsetsState> insetsStateCaptor = ArgumentCaptor.forClass(InsetsState.class); 3350 doReturn(true).when(app2).isReadyToDispatchInsetsState(); 3351 mDisplayContent.setImeLayeringTarget(app2); 3352 app2.mActivityRecord.commitVisibility(true, false); 3353 mDisplayContent.updateImeInputAndControlTarget(app2); 3354 mDisplayContent.mWmService.mRoot.performSurfacePlacement(); 3355 3356 // Verify after unfreezing app2's IME insets state, we won't dispatch visible IME insets 3357 // to client if the app didn't request IME visible. 3358 assertFalse(app2.mActivityRecord.mImeInsetsFrozenUntilStartInput); 3359 verify(app2.mClient, atLeastOnce()).resized(any(), anyBoolean(), any(), 3360 insetsStateCaptor.capture(), anyBoolean(), anyBoolean(), anyInt(), anyInt(), 3361 anyBoolean()); 3362 assertFalse(app2.getInsetsState().isSourceOrDefaultVisible(ID_IME, ime())); 3363 } 3364 3365 @Test testImeInsetsFrozenFlag_multiWindowActivities()3366 public void testImeInsetsFrozenFlag_multiWindowActivities() { 3367 final WindowToken imeToken = createTestWindowToken(TYPE_INPUT_METHOD, mDisplayContent); 3368 final WindowState ime = createWindow(null, TYPE_INPUT_METHOD, imeToken, "ime"); 3369 makeWindowVisibleAndDrawn(ime); 3370 3371 // Create a split-screen root task with activity1 and activity 2. 3372 final Task task = new TaskBuilder(mSupervisor) 3373 .setCreateParentTask(true).setCreateActivity(true).build(); 3374 task.getRootTask().setWindowingMode(WINDOWING_MODE_MULTI_WINDOW); 3375 final ActivityRecord activity1 = task.getTopNonFinishingActivity(); 3376 activity1.getTask().setResumedActivity(activity1, "testApp1"); 3377 3378 final ActivityRecord activity2 = new TaskBuilder(mSupervisor) 3379 .setWindowingMode(WINDOWING_MODE_MULTI_WINDOW) 3380 .setCreateActivity(true).build().getTopMostActivity(); 3381 activity2.getTask().setResumedActivity(activity2, "testApp2"); 3382 activity2.getTask().setParent(task.getRootTask()); 3383 3384 // Simulate activity1 and activity2 both have set mImeInsetsFrozenUntilStartInput when 3385 // invisible to user. 3386 activity1.mImeInsetsFrozenUntilStartInput = true; 3387 activity2.mImeInsetsFrozenUntilStartInput = true; 3388 3389 final WindowState app1 = createWindow(null, TYPE_APPLICATION, activity1, "app1"); 3390 final WindowState app2 = createWindow(null, TYPE_APPLICATION, activity2, "app2"); 3391 makeWindowVisibleAndDrawn(app1, app2); 3392 3393 final InsetsStateController controller = mDisplayContent.getInsetsStateController(); 3394 controller.getImeSourceProvider().setWindowContainer( 3395 ime, null, null); 3396 ime.getControllableInsetProvider().setServerVisible(true); 3397 3398 // app1 starts input and expect IME insets for all activities in split-screen will be 3399 // frozen until the input started. 3400 mDisplayContent.setImeLayeringTarget(app1); 3401 mDisplayContent.updateImeInputAndControlTarget(app1); 3402 mDisplayContent.mWmService.mRoot.performSurfacePlacement(); 3403 3404 assertEquals(app1, mDisplayContent.getImeInputTarget()); 3405 assertFalse(activity1.mImeInsetsFrozenUntilStartInput); 3406 assertFalse(activity2.mImeInsetsFrozenUntilStartInput); 3407 3408 app1.setRequestedVisibleTypes(ime()); 3409 controller.onRequestedVisibleTypesChanged(app1); 3410 3411 // Expect all activities in split-screen will get IME insets visible state 3412 assertTrue(app1.getInsetsState().peekSource(ID_IME).isVisible()); 3413 assertTrue(app2.getInsetsState().peekSource(ID_IME).isVisible()); 3414 } 3415 3416 @Test testInClosingAnimation_visibilityNotCommitted_doNotHideSurface()3417 public void testInClosingAnimation_visibilityNotCommitted_doNotHideSurface() { 3418 final WindowState app = createWindow(null, TYPE_APPLICATION, "app"); 3419 makeWindowVisibleAndDrawn(app); 3420 3421 // Put the activity in close transition. 3422 mDisplayContent.mOpeningApps.clear(); 3423 mDisplayContent.mClosingApps.add(app.mActivityRecord); 3424 mDisplayContent.prepareAppTransition(TRANSIT_CLOSE); 3425 3426 // Remove window during transition, so it is requested to hide, but won't be committed until 3427 // the transition is finished. 3428 app.mActivityRecord.onRemovedFromDisplay(); 3429 3430 assertTrue(mDisplayContent.mClosingApps.contains(app.mActivityRecord)); 3431 assertFalse(app.mActivityRecord.isVisibleRequested()); 3432 assertTrue(app.mActivityRecord.isVisible()); 3433 assertTrue(app.mActivityRecord.isSurfaceShowing()); 3434 3435 // Start transition. 3436 app.mActivityRecord.prepareSurfaces(); 3437 3438 // Because the app is waiting for transition, it should not hide the surface. 3439 assertTrue(app.mActivityRecord.isSurfaceShowing()); 3440 } 3441 3442 @Test testInClosingAnimation_visibilityCommitted_hideSurface()3443 public void testInClosingAnimation_visibilityCommitted_hideSurface() { 3444 final WindowState app = createWindow(null, TYPE_APPLICATION, "app"); 3445 makeWindowVisibleAndDrawn(app); 3446 3447 // Put the activity in close transition. 3448 mDisplayContent.mOpeningApps.clear(); 3449 mDisplayContent.mClosingApps.add(app.mActivityRecord); 3450 mDisplayContent.prepareAppTransition(TRANSIT_CLOSE); 3451 3452 // Commit visibility before start transition. 3453 app.mActivityRecord.commitVisibility(false, false); 3454 3455 assertFalse(app.mActivityRecord.isVisibleRequested()); 3456 assertFalse(app.mActivityRecord.isVisible()); 3457 assertTrue(app.mActivityRecord.isSurfaceShowing()); 3458 3459 // Start transition. 3460 app.mActivityRecord.prepareSurfaces(); 3461 3462 // Because the app visibility has been committed before the transition start, it should hide 3463 // the surface. 3464 assertFalse(app.mActivityRecord.isSurfaceShowing()); 3465 } 3466 3467 @Test testUpdateCameraCompatState_flagIsEnabled_controlStateIsUpdated()3468 public void testUpdateCameraCompatState_flagIsEnabled_controlStateIsUpdated() { 3469 final ActivityRecord activity = createActivityWithTask(); 3470 // Mock a flag being enabled. 3471 doReturn(true).when(activity).isCameraCompatControlEnabled(); 3472 3473 activity.updateCameraCompatState(/* showControl */ true, 3474 /* transformationApplied */ false, /* callback */ null); 3475 3476 assertEquals(activity.getCameraCompatControlState(), 3477 CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED); 3478 3479 activity.updateCameraCompatState(/* showControl */ true, 3480 /* transformationApplied */ true, /* callback */ null); 3481 3482 assertEquals(activity.getCameraCompatControlState(), 3483 CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED); 3484 3485 activity.updateCameraCompatState(/* showControl */ false, 3486 /* transformationApplied */ false, /* callback */ null); 3487 3488 assertEquals(activity.getCameraCompatControlState(), CAMERA_COMPAT_CONTROL_HIDDEN); 3489 3490 activity.updateCameraCompatState(/* showControl */ false, 3491 /* transformationApplied */ true, /* callback */ null); 3492 3493 assertEquals(activity.getCameraCompatControlState(), CAMERA_COMPAT_CONTROL_HIDDEN); 3494 } 3495 3496 @Test testUpdateCameraCompatState_flagIsDisabled_controlStateIsHidden()3497 public void testUpdateCameraCompatState_flagIsDisabled_controlStateIsHidden() { 3498 final ActivityRecord activity = createActivityWithTask(); 3499 // Mock a flag being disabled. 3500 doReturn(false).when(activity).isCameraCompatControlEnabled(); 3501 3502 activity.updateCameraCompatState(/* showControl */ true, 3503 /* transformationApplied */ false, /* callback */ null); 3504 3505 assertEquals(activity.getCameraCompatControlState(), CAMERA_COMPAT_CONTROL_HIDDEN); 3506 3507 activity.updateCameraCompatState(/* showControl */ true, 3508 /* transformationApplied */ true, /* callback */ null); 3509 3510 assertEquals(activity.getCameraCompatControlState(), CAMERA_COMPAT_CONTROL_HIDDEN); 3511 } 3512 3513 @Test testUpdateCameraCompatStateFromUser_clickedOnDismiss()3514 public void testUpdateCameraCompatStateFromUser_clickedOnDismiss() throws RemoteException { 3515 final ActivityRecord activity = createActivityWithTask(); 3516 // Mock a flag being enabled. 3517 doReturn(true).when(activity).isCameraCompatControlEnabled(); 3518 3519 ICompatCameraControlCallback callback = getCompatCameraControlCallback(); 3520 spyOn(callback); 3521 activity.updateCameraCompatState(/* showControl */ true, 3522 /* transformationApplied */ false, callback); 3523 3524 assertEquals(activity.getCameraCompatControlState(), 3525 CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED); 3526 3527 // Clicking on the button. 3528 activity.updateCameraCompatStateFromUser(CAMERA_COMPAT_CONTROL_DISMISSED); 3529 3530 verify(callback, never()).revertCameraCompatTreatment(); 3531 verify(callback, never()).applyCameraCompatTreatment(); 3532 assertEquals(activity.getCameraCompatControlState(), CAMERA_COMPAT_CONTROL_DISMISSED); 3533 3534 // All following updates are ignored. 3535 activity.updateCameraCompatState(/* showControl */ true, 3536 /* transformationApplied */ false, /* callback */ null); 3537 3538 assertEquals(activity.getCameraCompatControlState(), CAMERA_COMPAT_CONTROL_DISMISSED); 3539 3540 activity.updateCameraCompatState(/* showControl */ true, 3541 /* transformationApplied */ true, /* callback */ null); 3542 3543 assertEquals(activity.getCameraCompatControlState(), CAMERA_COMPAT_CONTROL_DISMISSED); 3544 3545 activity.updateCameraCompatState(/* showControl */ false, 3546 /* transformationApplied */ true, /* callback */ null); 3547 3548 assertEquals(activity.getCameraCompatControlState(), CAMERA_COMPAT_CONTROL_DISMISSED); 3549 } 3550 3551 @Test testUpdateCameraCompatStateFromUser_clickedOnApplyTreatment()3552 public void testUpdateCameraCompatStateFromUser_clickedOnApplyTreatment() 3553 throws RemoteException { 3554 final ActivityRecord activity = createActivityWithTask(); 3555 // Mock a flag being enabled. 3556 doReturn(true).when(activity).isCameraCompatControlEnabled(); 3557 3558 ICompatCameraControlCallback callback = getCompatCameraControlCallback(); 3559 spyOn(callback); 3560 activity.updateCameraCompatState(/* showControl */ true, 3561 /* transformationApplied */ false, callback); 3562 3563 assertEquals(activity.getCameraCompatControlState(), 3564 CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED); 3565 3566 // Clicking on the button. 3567 activity.updateCameraCompatStateFromUser(CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED); 3568 3569 verify(callback, never()).revertCameraCompatTreatment(); 3570 verify(callback).applyCameraCompatTreatment(); 3571 assertEquals(activity.getCameraCompatControlState(), 3572 CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED); 3573 3574 // Request from the client to show the control are ignored respecting the user choice. 3575 activity.updateCameraCompatState(/* showControl */ true, 3576 /* transformationApplied */ false, /* callback */ null); 3577 3578 assertEquals(activity.getCameraCompatControlState(), 3579 CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED); 3580 3581 // Request from the client to hide the control is respected. 3582 activity.updateCameraCompatState(/* showControl */ false, 3583 /* transformationApplied */ true, /* callback */ null); 3584 3585 assertEquals(activity.getCameraCompatControlState(), CAMERA_COMPAT_CONTROL_HIDDEN); 3586 3587 // Request from the client to show the control again is respected. 3588 activity.updateCameraCompatState(/* showControl */ true, 3589 /* transformationApplied */ false, /* callback */ null); 3590 3591 assertEquals(activity.getCameraCompatControlState(), 3592 CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED); 3593 } 3594 3595 @Test testUpdateCameraCompatStateFromUser_clickedOnRevertTreatment()3596 public void testUpdateCameraCompatStateFromUser_clickedOnRevertTreatment() 3597 throws RemoteException { 3598 final ActivityRecord activity = createActivityWithTask(); 3599 // Mock a flag being enabled. 3600 doReturn(true).when(activity).isCameraCompatControlEnabled(); 3601 3602 ICompatCameraControlCallback callback = getCompatCameraControlCallback(); 3603 spyOn(callback); 3604 activity.updateCameraCompatState(/* showControl */ true, 3605 /* transformationApplied */ true, callback); 3606 3607 assertEquals(activity.getCameraCompatControlState(), 3608 CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED); 3609 3610 // Clicking on the button. 3611 activity.updateCameraCompatStateFromUser(CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED); 3612 3613 verify(callback).revertCameraCompatTreatment(); 3614 verify(callback, never()).applyCameraCompatTreatment(); 3615 assertEquals(activity.getCameraCompatControlState(), 3616 CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED); 3617 3618 // Request from the client to show the control are ignored respecting the user choice. 3619 activity.updateCameraCompatState(/* showControl */ true, 3620 /* transformationApplied */ true, /* callback */ null); 3621 3622 assertEquals(activity.getCameraCompatControlState(), 3623 CAMERA_COMPAT_CONTROL_TREATMENT_SUGGESTED); 3624 3625 // Request from the client to hide the control is respected. 3626 activity.updateCameraCompatState(/* showControl */ false, 3627 /* transformationApplied */ true, /* callback */ null); 3628 3629 assertEquals(activity.getCameraCompatControlState(), CAMERA_COMPAT_CONTROL_HIDDEN); 3630 3631 // Request from the client to show the control again is respected. 3632 activity.updateCameraCompatState(/* showControl */ true, 3633 /* transformationApplied */ true, /* callback */ null); 3634 3635 assertEquals(activity.getCameraCompatControlState(), 3636 CAMERA_COMPAT_CONTROL_TREATMENT_APPLIED); 3637 } 3638 3639 @Test // b/162542125 testInputDispatchTimeout()3640 public void testInputDispatchTimeout() throws RemoteException { 3641 final ActivityRecord activity = createActivityWithTask(); 3642 final WindowProcessController wpc = activity.app; 3643 spyOn(wpc); 3644 doReturn(true).when(wpc).isInstrumenting(); 3645 final ActivityRecord instrumentingActivity = createActivityOnDisplay( 3646 true /* defaultDisplay */, wpc); 3647 assertEquals(INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT_MILLIS, 3648 instrumentingActivity.mInputDispatchingTimeoutMillis); 3649 3650 doReturn(false).when(wpc).isInstrumenting(); 3651 final ActivityRecord nonInstrumentingActivity = createActivityOnDisplay( 3652 true /* defaultDisplay */, wpc); 3653 assertEquals(DEFAULT_DISPATCHING_TIMEOUT_MILLIS, 3654 nonInstrumentingActivity.mInputDispatchingTimeoutMillis); 3655 3656 final ActivityRecord noProcActivity = createActivityOnDisplay(true /* defaultDisplay */, 3657 null); 3658 assertEquals(DEFAULT_DISPATCHING_TIMEOUT_MILLIS, 3659 noProcActivity.mInputDispatchingTimeoutMillis); 3660 } 3661 3662 @Test testEnsureActivitiesVisibleAnotherUserTasks()3663 public void testEnsureActivitiesVisibleAnotherUserTasks() { 3664 // Create an activity with hierarchy: 3665 // RootTask 3666 // - TaskFragment 3667 // - Activity 3668 DisplayContent display = createNewDisplay(); 3669 Task rootTask = createTask(display); 3670 ActivityRecord activity = createActivityRecord(rootTask); 3671 final TaskFragment taskFragment = new TaskFragment(mAtm, new Binder(), 3672 true /* createdByOrganizer */, true /* isEmbedded */); 3673 activity.getTask().addChild(taskFragment, POSITION_TOP); 3674 activity.reparent(taskFragment, POSITION_TOP); 3675 3676 // Ensure the activity visibility is updated even it is not shown to current user. 3677 activity.setVisibleRequested(true); 3678 doReturn(false).when(activity).showToCurrentUser(); 3679 spyOn(taskFragment); 3680 doReturn(false).when(taskFragment).shouldBeVisible(any()); 3681 display.ensureActivitiesVisible(null, 0, false, false); 3682 assertFalse(activity.isVisibleRequested()); 3683 } 3684 3685 @Test testShellTransitionTaskWindowingModeChange()3686 public void testShellTransitionTaskWindowingModeChange() { 3687 final ActivityRecord activity = createActivityWithTask(); 3688 final Task task = activity.getTask(); 3689 task.setWindowingMode(WINDOWING_MODE_FULLSCREEN); 3690 3691 assertTrue(activity.isVisible()); 3692 assertTrue(activity.isVisibleRequested()); 3693 assertEquals(WINDOWING_MODE_FULLSCREEN, activity.getWindowingMode()); 3694 3695 registerTestTransitionPlayer(); 3696 task.mTransitionController.requestTransitionIfNeeded(TRANSIT_PIP, task); 3697 task.setWindowingMode(WINDOWING_MODE_PINNED); 3698 3699 // Collect activity in the transition if the Task windowing mode is going to change. 3700 assertTrue(activity.inTransition()); 3701 } 3702 3703 /** 3704 * Verifies the task is moved to back when back pressed if the root activity was originally 3705 * started from Launcher. 3706 */ 3707 @Test testMoveTaskToBackWhenStartedFromLauncher()3708 public void testMoveTaskToBackWhenStartedFromLauncher() { 3709 final Task task = createTask(mDisplayContent); 3710 final ActivityRecord ar = createActivityRecord(task); 3711 task.realActivity = ar.mActivityComponent; 3712 ar.intent.setAction(Intent.ACTION_MAIN); 3713 ar.intent.addCategory(Intent.CATEGORY_LAUNCHER); 3714 doReturn(true).when(ar).isLaunchSourceType(eq(LAUNCH_SOURCE_TYPE_HOME)); 3715 3716 mAtm.mActivityClientController.onBackPressed(ar.token, null /* callback */); 3717 verify(task).moveTaskToBack(any()); 3718 } 3719 getCompatCameraControlCallback()3720 private ICompatCameraControlCallback getCompatCameraControlCallback() { 3721 return new ICompatCameraControlCallback.Stub() { 3722 @Override 3723 public void applyCameraCompatTreatment() {} 3724 3725 @Override 3726 public void revertCameraCompatTreatment() {} 3727 }; 3728 } 3729 assertHasStartingWindow(ActivityRecord atoken)3730 private void assertHasStartingWindow(ActivityRecord atoken) { 3731 assertNotNull(atoken.mStartingSurface); 3732 assertNotNull(atoken.mStartingData); 3733 assertNotNull(atoken.mStartingWindow); 3734 } 3735 assertNoStartingWindow(ActivityRecord atoken)3736 private void assertNoStartingWindow(ActivityRecord atoken) { 3737 assertNull(atoken.mStartingSurface); 3738 assertNull(atoken.mStartingWindow); 3739 assertNull(atoken.mStartingData); 3740 atoken.forAllWindows(windowState -> { 3741 assertFalse(windowState.getBaseType() == TYPE_APPLICATION_STARTING); 3742 }, true); 3743 } 3744 } 3745