1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License 15 */ 16 17 package com.android.server.wm; 18 19 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD; 20 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; 21 import static android.content.pm.ActivityInfo.CONFIG_ORIENTATION; 22 import static android.content.pm.ActivityInfo.CONFIG_SCREEN_LAYOUT; 23 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; 24 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; 25 import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; 26 import static android.content.res.Configuration.ORIENTATION_PORTRAIT; 27 import static android.os.Process.NOBODY_UID; 28 import static android.view.Display.DEFAULT_DISPLAY; 29 import static android.view.WindowManager.TRANSIT_TASK_CLOSE; 30 31 import static com.android.dx.mockito.inline.extended.ExtendedMockito.any; 32 import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyBoolean; 33 import static com.android.dx.mockito.inline.extended.ExtendedMockito.atLeast; 34 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer; 35 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doCallRealMethod; 36 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; 37 import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq; 38 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; 39 import static com.android.dx.mockito.inline.extended.ExtendedMockito.reset; 40 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; 41 import static com.android.dx.mockito.inline.extended.ExtendedMockito.times; 42 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; 43 import static com.android.server.wm.ActivityRecord.FINISH_RESULT_CANCELLED; 44 import static com.android.server.wm.ActivityRecord.FINISH_RESULT_REMOVED; 45 import static com.android.server.wm.ActivityRecord.FINISH_RESULT_REQUESTED; 46 import static com.android.server.wm.ActivityStack.ActivityState.DESTROYED; 47 import static com.android.server.wm.ActivityStack.ActivityState.DESTROYING; 48 import static com.android.server.wm.ActivityStack.ActivityState.FINISHING; 49 import static com.android.server.wm.ActivityStack.ActivityState.INITIALIZING; 50 import static com.android.server.wm.ActivityStack.ActivityState.PAUSED; 51 import static com.android.server.wm.ActivityStack.ActivityState.PAUSING; 52 import static com.android.server.wm.ActivityStack.ActivityState.RESUMED; 53 import static com.android.server.wm.ActivityStack.ActivityState.STARTED; 54 import static com.android.server.wm.ActivityStack.ActivityState.STOPPED; 55 import static com.android.server.wm.ActivityStack.ActivityState.STOPPING; 56 import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_INVISIBLE; 57 import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE; 58 import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT; 59 60 import static com.google.common.truth.Truth.assertThat; 61 62 import static org.junit.Assert.assertEquals; 63 import static org.junit.Assert.assertFalse; 64 import static org.junit.Assert.assertNotEquals; 65 import static org.junit.Assert.assertNotNull; 66 import static org.junit.Assert.assertNull; 67 import static org.junit.Assert.assertTrue; 68 import static org.mockito.ArgumentMatchers.anyInt; 69 import static org.mockito.ArgumentMatchers.anyString; 70 import static org.mockito.Mockito.clearInvocations; 71 import static org.mockito.Mockito.never; 72 73 import android.app.ActivityManager.TaskSnapshot; 74 import android.app.ActivityOptions; 75 import android.app.WindowConfiguration; 76 import android.app.servertransaction.ActivityConfigurationChangeItem; 77 import android.app.servertransaction.ClientTransaction; 78 import android.app.servertransaction.PauseActivityItem; 79 import android.content.ComponentName; 80 import android.content.Intent; 81 import android.content.pm.ActivityInfo; 82 import android.content.res.Configuration; 83 import android.content.res.Resources; 84 import android.graphics.Rect; 85 import android.os.Bundle; 86 import android.os.PersistableBundle; 87 import android.os.RemoteException; 88 import android.platform.test.annotations.Presubmit; 89 import android.util.MergedConfiguration; 90 import android.util.MutableBoolean; 91 import android.view.DisplayInfo; 92 import android.view.IRemoteAnimationFinishedCallback; 93 import android.view.IRemoteAnimationRunner.Stub; 94 import android.view.IWindowSession; 95 import android.view.RemoteAnimationAdapter; 96 import android.view.RemoteAnimationTarget; 97 import android.view.WindowManager; 98 import android.view.WindowManagerGlobal; 99 100 import androidx.test.filters.MediumTest; 101 102 import com.android.internal.R; 103 import com.android.server.wm.ActivityStack.ActivityState; 104 105 import org.junit.Before; 106 import org.junit.Test; 107 import org.junit.runner.RunWith; 108 import org.mockito.invocation.InvocationOnMock; 109 110 /** 111 * Tests for the {@link ActivityRecord} class. 112 * 113 * Build/Install/Run: 114 * atest WmTests:ActivityRecordTests 115 */ 116 @MediumTest 117 @Presubmit 118 @RunWith(WindowTestRunner.class) 119 public class ActivityRecordTests extends ActivityTestsBase { 120 private ActivityStack mStack; 121 private Task mTask; 122 private ActivityRecord mActivity; 123 124 @Before setUp()125 public void setUp() throws Exception { 126 mStack = new StackBuilder(mRootWindowContainer).build(); 127 mTask = mStack.getBottomMostTask(); 128 mActivity = mTask.getTopNonFinishingActivity(); 129 130 setBooted(mService); 131 } 132 133 @Test testStackCleanupOnClearingTask()134 public void testStackCleanupOnClearingTask() { 135 mActivity.onParentChanged(null /*newParent*/, mActivity.getTask()); 136 verify(mStack, times(1)).cleanUpActivityReferences(any()); 137 } 138 139 @Test testStackCleanupOnActivityRemoval()140 public void testStackCleanupOnActivityRemoval() { 141 mTask.removeChild(mActivity); 142 verify(mStack, times(1)).cleanUpActivityReferences(any()); 143 } 144 145 @Test testStackCleanupOnTaskRemoval()146 public void testStackCleanupOnTaskRemoval() { 147 mStack.removeChild(mTask, null /*reason*/); 148 // Stack should be gone on task removal. 149 assertNull(mService.mRootWindowContainer.getStack(mStack.mTaskId)); 150 } 151 152 @Test testRemoveChildWithOverlayActivity()153 public void testRemoveChildWithOverlayActivity() { 154 final ActivityRecord overlayActivity = 155 new ActivityBuilder(mService).setTask(mTask).build(); 156 overlayActivity.setTaskOverlay(true); 157 final ActivityRecord overlayActivity2 = 158 new ActivityBuilder(mService).setTask(mTask).build(); 159 overlayActivity2.setTaskOverlay(true); 160 161 mTask.removeChild(overlayActivity2, "test"); 162 verify(mSupervisor, never()).removeTask(any(), anyBoolean(), anyBoolean(), any()); 163 } 164 165 @Test testNoCleanupMovingActivityInSameStack()166 public void testNoCleanupMovingActivityInSameStack() { 167 final Task newTask = new TaskBuilder(mService.mStackSupervisor).setStack(mStack).build(); 168 mActivity.reparent(newTask, 0, null /*reason*/); 169 verify(mStack, times(0)).cleanUpActivityReferences(any()); 170 } 171 172 @Test testPausingWhenVisibleFromStopped()173 public void testPausingWhenVisibleFromStopped() throws Exception { 174 final MutableBoolean pauseFound = new MutableBoolean(false); 175 doAnswer((InvocationOnMock invocationOnMock) -> { 176 final ClientTransaction transaction = invocationOnMock.getArgument(0); 177 if (transaction.getLifecycleStateRequest() instanceof PauseActivityItem) { 178 pauseFound.value = true; 179 } 180 return null; 181 }).when(mActivity.app.getThread()).scheduleTransaction(any()); 182 183 mActivity.setState(STOPPED, "testPausingWhenVisibleFromStopped"); 184 185 // The activity is in the focused stack so it should be resumed. 186 mActivity.makeVisibleIfNeeded(null /* starting */, true /* reportToClient */); 187 assertTrue(mActivity.isState(RESUMED)); 188 assertFalse(pauseFound.value); 189 190 // Make the activity non focusable 191 mActivity.setState(STOPPED, "testPausingWhenVisibleFromStopped"); 192 doReturn(false).when(mActivity).isFocusable(); 193 194 // If the activity is not focusable, it should move to paused. 195 mActivity.makeVisibleIfNeeded(null /* starting */, true /* reportToClient */); 196 assertTrue(mActivity.isState(PAUSING)); 197 assertTrue(pauseFound.value); 198 199 // Make sure that the state does not change for current non-stopping states. 200 mActivity.setState(INITIALIZING, "testPausingWhenVisibleFromStopped"); 201 doReturn(true).when(mActivity).isFocusable(); 202 203 mActivity.makeVisibleIfNeeded(null /* starting */, true /* reportToClient */); 204 205 assertTrue(mActivity.isState(INITIALIZING)); 206 207 // Make sure the state does not change if we are not the current top activity. 208 mActivity.setState(STOPPED, "testPausingWhenVisibleFromStopped behind"); 209 210 final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build(); 211 mStack.mTranslucentActivityWaiting = topActivity; 212 mActivity.makeVisibleIfNeeded(null /* starting */, true /* reportToClient */); 213 assertTrue(mActivity.isState(STARTED)); 214 215 mStack.mTranslucentActivityWaiting = null; 216 topActivity.setOccludesParent(false); 217 mActivity.setState(STOPPED, "testPausingWhenVisibleFromStopped behind non-opaque"); 218 mActivity.makeVisibleIfNeeded(null /* starting */, true /* reportToClient */); 219 assertTrue(mActivity.isState(STARTED)); 220 } 221 ensureActivityConfiguration()222 private void ensureActivityConfiguration() { 223 mActivity.ensureActivityConfiguration(0 /* globalChanges */, false /* preserveWindow */); 224 } 225 226 @Test testCanBeLaunchedOnDisplay()227 public void testCanBeLaunchedOnDisplay() { 228 mService.mSupportsMultiWindow = true; 229 final ActivityRecord activity = new ActivityBuilder(mService).build(); 230 231 // An activity can be launched on default display. 232 assertTrue(activity.canBeLaunchedOnDisplay(DEFAULT_DISPLAY)); 233 // An activity cannot be launched on a non-existent display. 234 assertFalse(activity.canBeLaunchedOnDisplay(Integer.MAX_VALUE)); 235 } 236 237 @Test testsApplyOptionsLocked()238 public void testsApplyOptionsLocked() { 239 ActivityOptions activityOptions = ActivityOptions.makeBasic(); 240 241 // Set and apply options for ActivityRecord. Pending options should be cleared 242 mActivity.updateOptionsLocked(activityOptions); 243 mActivity.applyOptionsLocked(); 244 assertNull(mActivity.pendingOptions); 245 246 // Set options for two ActivityRecords in same Task. Apply one ActivityRecord options. 247 // Pending options should be cleared for both ActivityRecords 248 ActivityRecord activity2 = new ActivityBuilder(mService).setTask(mTask).build(); 249 activity2.updateOptionsLocked(activityOptions); 250 mActivity.updateOptionsLocked(activityOptions); 251 mActivity.applyOptionsLocked(); 252 assertNull(mActivity.pendingOptions); 253 assertNull(activity2.pendingOptions); 254 255 // Set options for two ActivityRecords in separate Tasks. Apply one ActivityRecord options. 256 // Pending options should be cleared for only ActivityRecord that was applied 257 Task task2 = new TaskBuilder(mService.mStackSupervisor).setStack(mStack).build(); 258 activity2 = new ActivityBuilder(mService).setTask(task2).build(); 259 activity2.updateOptionsLocked(activityOptions); 260 mActivity.updateOptionsLocked(activityOptions); 261 mActivity.applyOptionsLocked(); 262 assertNull(mActivity.pendingOptions); 263 assertNotNull(activity2.pendingOptions); 264 } 265 266 @Test testNewOverrideConfigurationIncrementsSeq()267 public void testNewOverrideConfigurationIncrementsSeq() { 268 final Configuration newConfig = new Configuration(); 269 270 final int prevSeq = mActivity.getMergedOverrideConfiguration().seq; 271 mActivity.onRequestedOverrideConfigurationChanged(newConfig); 272 assertEquals(prevSeq + 1, mActivity.getMergedOverrideConfiguration().seq); 273 } 274 275 @Test testNewParentConfigurationIncrementsSeq()276 public void testNewParentConfigurationIncrementsSeq() { 277 final Configuration newConfig = new Configuration( 278 mTask.getRequestedOverrideConfiguration()); 279 newConfig.orientation = newConfig.orientation == ORIENTATION_PORTRAIT 280 ? ORIENTATION_LANDSCAPE : ORIENTATION_PORTRAIT; 281 282 final int prevSeq = mActivity.getMergedOverrideConfiguration().seq; 283 mTask.onRequestedOverrideConfigurationChanged(newConfig); 284 assertEquals(prevSeq + 1, mActivity.getMergedOverrideConfiguration().seq); 285 } 286 287 @Test testSetsRelaunchReason_NotDragResizing()288 public void testSetsRelaunchReason_NotDragResizing() { 289 mActivity.setState(ActivityStack.ActivityState.RESUMED, "Testing"); 290 291 mTask.onRequestedOverrideConfigurationChanged(mTask.getConfiguration()); 292 mActivity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(), 293 mActivity.getConfiguration())); 294 295 mActivity.info.configChanges &= ~CONFIG_ORIENTATION; 296 final Configuration newConfig = new Configuration(mTask.getConfiguration()); 297 newConfig.orientation = newConfig.orientation == ORIENTATION_PORTRAIT 298 ? ORIENTATION_LANDSCAPE 299 : ORIENTATION_PORTRAIT; 300 mTask.onRequestedOverrideConfigurationChanged(newConfig); 301 302 mActivity.mRelaunchReason = ActivityTaskManagerService.RELAUNCH_REASON_NONE; 303 304 ensureActivityConfiguration(); 305 306 assertEquals(ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE, 307 mActivity.mRelaunchReason); 308 } 309 310 @Test testSetsRelaunchReason_DragResizing()311 public void testSetsRelaunchReason_DragResizing() { 312 mActivity.setState(ActivityStack.ActivityState.RESUMED, "Testing"); 313 314 mTask.onRequestedOverrideConfigurationChanged(mTask.getConfiguration()); 315 mActivity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(), 316 mActivity.getConfiguration())); 317 318 mActivity.info.configChanges &= ~CONFIG_ORIENTATION; 319 final Configuration newConfig = new Configuration(mTask.getConfiguration()); 320 newConfig.orientation = newConfig.orientation == ORIENTATION_PORTRAIT 321 ? ORIENTATION_LANDSCAPE 322 : ORIENTATION_PORTRAIT; 323 mTask.onRequestedOverrideConfigurationChanged(newConfig); 324 325 doReturn(true).when(mTask).isDragResizing(); 326 327 mActivity.mRelaunchReason = ActivityTaskManagerService.RELAUNCH_REASON_NONE; 328 329 ensureActivityConfiguration(); 330 331 assertEquals(ActivityTaskManagerService.RELAUNCH_REASON_FREE_RESIZE, 332 mActivity.mRelaunchReason); 333 } 334 335 @Test testSetsRelaunchReason_NonResizeConfigChanges()336 public void testSetsRelaunchReason_NonResizeConfigChanges() { 337 mActivity.setState(ActivityStack.ActivityState.RESUMED, "Testing"); 338 339 mTask.onRequestedOverrideConfigurationChanged(mTask.getConfiguration()); 340 mActivity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(), 341 mActivity.getConfiguration())); 342 343 mActivity.info.configChanges &= ~ActivityInfo.CONFIG_FONT_SCALE; 344 final Configuration newConfig = new Configuration(mTask.getConfiguration()); 345 newConfig.fontScale = 5; 346 mTask.onRequestedOverrideConfigurationChanged(newConfig); 347 348 mActivity.mRelaunchReason = 349 ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE; 350 351 ensureActivityConfiguration(); 352 353 assertEquals(ActivityTaskManagerService.RELAUNCH_REASON_NONE, 354 mActivity.mRelaunchReason); 355 } 356 357 @Test testSetRequestedOrientationUpdatesConfiguration()358 public void testSetRequestedOrientationUpdatesConfiguration() throws Exception { 359 mActivity = new ActivityBuilder(mService) 360 .setTask(mTask) 361 .setConfigChanges(CONFIG_ORIENTATION | CONFIG_SCREEN_LAYOUT) 362 .build(); 363 mActivity.setState(ActivityStack.ActivityState.RESUMED, "Testing"); 364 365 mActivity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(), 366 mActivity.getConfiguration())); 367 368 final Configuration newConfig = new Configuration(mActivity.getConfiguration()); 369 final int shortSide = Math.min(newConfig.screenWidthDp, newConfig.screenHeightDp); 370 final int longSide = Math.max(newConfig.screenWidthDp, newConfig.screenHeightDp); 371 if (newConfig.orientation == ORIENTATION_PORTRAIT) { 372 newConfig.orientation = ORIENTATION_LANDSCAPE; 373 newConfig.screenWidthDp = longSide; 374 newConfig.screenHeightDp = shortSide; 375 } else { 376 newConfig.orientation = ORIENTATION_PORTRAIT; 377 newConfig.screenWidthDp = shortSide; 378 newConfig.screenHeightDp = longSide; 379 } 380 381 // Mimic the behavior that display doesn't handle app's requested orientation. 382 final DisplayContent dc = mTask.getDisplayContent(); 383 doReturn(false).when(dc).onDescendantOrientationChanged(any(), any()); 384 doReturn(false).when(dc).handlesOrientationChangeFromDescendant(); 385 386 final int requestedOrientation; 387 switch (newConfig.orientation) { 388 case ORIENTATION_LANDSCAPE: 389 requestedOrientation = SCREEN_ORIENTATION_LANDSCAPE; 390 break; 391 case ORIENTATION_PORTRAIT: 392 requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; 393 break; 394 default: 395 throw new IllegalStateException("Orientation in new config should be either" 396 + "landscape or portrait."); 397 } 398 mActivity.setRequestedOrientation(requestedOrientation); 399 400 final ActivityConfigurationChangeItem expected = 401 ActivityConfigurationChangeItem.obtain(newConfig); 402 verify(mService.getLifecycleManager()).scheduleTransaction(eq(mActivity.app.getThread()), 403 eq(mActivity.appToken), eq(expected)); 404 } 405 406 @Test ignoreRequestedOrientationInFreeformWindows()407 public void ignoreRequestedOrientationInFreeformWindows() { 408 mStack.setWindowingMode(WindowConfiguration.WINDOWING_MODE_FREEFORM); 409 final Rect stableRect = new Rect(); 410 mStack.getDisplay().mDisplayContent.getStableRect(stableRect); 411 412 // Carve out non-decor insets from stableRect 413 final Rect insets = new Rect(); 414 final DisplayInfo displayInfo = mStack.getDisplay().getDisplayInfo(); 415 final DisplayPolicy policy = mStack.getDisplay().getDisplayPolicy(); 416 policy.getNonDecorInsetsLw(displayInfo.rotation, displayInfo.logicalWidth, 417 displayInfo.logicalHeight, displayInfo.displayCutout, insets); 418 policy.convertNonDecorInsetsToStableInsets(insets, displayInfo.rotation); 419 Task.intersectWithInsetsIfFits(stableRect, stableRect, insets); 420 421 final boolean isScreenPortrait = stableRect.width() <= stableRect.height(); 422 final Rect bounds = new Rect(stableRect); 423 if (isScreenPortrait) { 424 // Landscape bounds 425 final int newHeight = stableRect.width() - 10; 426 bounds.top = stableRect.top + (stableRect.height() - newHeight) / 2; 427 bounds.bottom = bounds.top + newHeight; 428 } else { 429 // Portrait bounds 430 final int newWidth = stableRect.height() - 10; 431 bounds.left = stableRect.left + (stableRect.width() - newWidth) / 2; 432 bounds.right = bounds.left + newWidth; 433 } 434 mTask.setBounds(bounds); 435 436 // Requests orientation that's different from its bounds. 437 mActivity.setRequestedOrientation( 438 isScreenPortrait ? SCREEN_ORIENTATION_PORTRAIT : SCREEN_ORIENTATION_LANDSCAPE); 439 440 // Asserts it has orientation derived from bounds. 441 assertEquals(isScreenPortrait ? ORIENTATION_LANDSCAPE : ORIENTATION_PORTRAIT, 442 mActivity.getConfiguration().orientation); 443 } 444 445 @Test ignoreRequestedOrientationInSplitWindows()446 public void ignoreRequestedOrientationInSplitWindows() { 447 mStack.setWindowingMode(WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY); 448 final Rect stableRect = new Rect(); 449 mStack.getDisplay().getStableRect(stableRect); 450 451 // Carve out non-decor insets from stableRect 452 final Rect insets = new Rect(); 453 final DisplayInfo displayInfo = mStack.getDisplay().getDisplayInfo(); 454 final DisplayPolicy policy = mStack.getDisplay().getDisplayPolicy(); 455 policy.getNonDecorInsetsLw(displayInfo.rotation, displayInfo.logicalWidth, 456 displayInfo.logicalHeight, displayInfo.displayCutout, insets); 457 policy.convertNonDecorInsetsToStableInsets(insets, displayInfo.rotation); 458 Task.intersectWithInsetsIfFits(stableRect, stableRect, insets); 459 460 final boolean isScreenPortrait = stableRect.width() <= stableRect.height(); 461 final Rect bounds = new Rect(stableRect); 462 if (isScreenPortrait) { 463 // Landscape bounds 464 final int newHeight = stableRect.width() - 10; 465 bounds.top = stableRect.top + (stableRect.height() - newHeight) / 2; 466 bounds.bottom = bounds.top + newHeight; 467 } else { 468 // Portrait bounds 469 final int newWidth = stableRect.height() - 10; 470 bounds.left = stableRect.left + (stableRect.width() - newWidth) / 2; 471 bounds.right = bounds.left + newWidth; 472 } 473 mTask.setBounds(bounds); 474 475 // Requests orientation that's different from its bounds. 476 mActivity.setRequestedOrientation( 477 isScreenPortrait ? SCREEN_ORIENTATION_PORTRAIT : SCREEN_ORIENTATION_LANDSCAPE); 478 479 // Asserts it has orientation derived from bounds. 480 assertEquals(isScreenPortrait ? ORIENTATION_LANDSCAPE : ORIENTATION_PORTRAIT, 481 mActivity.getConfiguration().orientation); 482 } 483 484 @Test testShouldMakeActive_deferredResume()485 public void testShouldMakeActive_deferredResume() { 486 mActivity.setState(ActivityStack.ActivityState.STOPPED, "Testing"); 487 488 mSupervisor.beginDeferResume(); 489 assertEquals(false, mActivity.shouldMakeActive(null /* activeActivity */)); 490 491 mSupervisor.endDeferResume(); 492 assertEquals(true, mActivity.shouldMakeActive(null /* activeActivity */)); 493 } 494 495 @Test testShouldMakeActive_nonTopVisible()496 public void testShouldMakeActive_nonTopVisible() { 497 ActivityRecord finishingActivity = new ActivityBuilder(mService).setTask(mTask).build(); 498 finishingActivity.finishing = true; 499 ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build(); 500 mActivity.setState(ActivityStack.ActivityState.STOPPED, "Testing"); 501 502 assertEquals(false, mActivity.shouldMakeActive(null /* activeActivity */)); 503 } 504 505 @Test testShouldResume_stackVisibility()506 public void testShouldResume_stackVisibility() { 507 mActivity.setState(ActivityStack.ActivityState.STOPPED, "Testing"); 508 spyOn(mStack); 509 510 doReturn(STACK_VISIBILITY_VISIBLE).when(mStack).getVisibility(null); 511 assertEquals(true, mActivity.shouldResumeActivity(null /* activeActivity */)); 512 513 doReturn(STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT).when(mStack).getVisibility(null); 514 assertEquals(false, mActivity.shouldResumeActivity(null /* activeActivity */)); 515 516 doReturn(STACK_VISIBILITY_INVISIBLE).when(mStack).getVisibility(null); 517 assertEquals(false, mActivity.shouldResumeActivity(null /* activeActivity */)); 518 } 519 520 @Test testShouldResumeOrPauseWithResults()521 public void testShouldResumeOrPauseWithResults() { 522 mActivity.setState(ActivityStack.ActivityState.STOPPED, "Testing"); 523 spyOn(mStack); 524 525 ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build(); 526 mActivity.addResultLocked(topActivity, "resultWho", 0, 0, new Intent()); 527 topActivity.finishing = true; 528 529 doReturn(STACK_VISIBILITY_VISIBLE).when(mStack).getVisibility(null); 530 assertEquals(true, mActivity.shouldResumeActivity(null /* activeActivity */)); 531 assertEquals(false, mActivity.shouldPauseActivity(null /*activeActivity */)); 532 } 533 534 @Test testPushConfigurationWhenLaunchTaskBehind()535 public void testPushConfigurationWhenLaunchTaskBehind() throws Exception { 536 mActivity = new ActivityBuilder(mService) 537 .setTask(mTask) 538 .setLaunchTaskBehind(true) 539 .setConfigChanges(CONFIG_ORIENTATION) 540 .build(); 541 mActivity.setState(ActivityStack.ActivityState.STOPPED, "Testing"); 542 543 final ActivityStack stack = new StackBuilder(mRootWindowContainer).build(); 544 try { 545 doReturn(false).when(stack).isTranslucent(any()); 546 assertFalse(mStack.shouldBeVisible(null /* starting */)); 547 548 mActivity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(), 549 mActivity.getConfiguration())); 550 551 final Configuration newConfig = new Configuration(mActivity.getConfiguration()); 552 final int shortSide = Math.min(newConfig.screenWidthDp, newConfig.screenHeightDp); 553 final int longSide = Math.max(newConfig.screenWidthDp, newConfig.screenHeightDp); 554 if (newConfig.orientation == ORIENTATION_PORTRAIT) { 555 newConfig.orientation = ORIENTATION_LANDSCAPE; 556 newConfig.screenWidthDp = longSide; 557 newConfig.screenHeightDp = shortSide; 558 } else { 559 newConfig.orientation = ORIENTATION_PORTRAIT; 560 newConfig.screenWidthDp = shortSide; 561 newConfig.screenHeightDp = longSide; 562 } 563 564 mTask.onConfigurationChanged(newConfig); 565 566 mActivity.ensureActivityConfiguration(0 /* globalChanges */, 567 false /* preserveWindow */, true /* ignoreStopState */); 568 569 final ActivityConfigurationChangeItem expected = 570 ActivityConfigurationChangeItem.obtain(newConfig); 571 verify(mService.getLifecycleManager()).scheduleTransaction( 572 eq(mActivity.app.getThread()), eq(mActivity.appToken), eq(expected)); 573 } finally { 574 stack.getDisplayArea().removeChild(stack); 575 } 576 } 577 578 @Test testShouldStartWhenMakeClientActive()579 public void testShouldStartWhenMakeClientActive() { 580 ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build(); 581 topActivity.setOccludesParent(false); 582 mActivity.setState(ActivityStack.ActivityState.STOPPED, "Testing"); 583 mActivity.setVisibility(true); 584 mActivity.makeActiveIfNeeded(null /* activeActivity */); 585 assertEquals(STARTED, mActivity.getState()); 586 } 587 588 @Test testTakeOptions()589 public void testTakeOptions() { 590 ActivityOptions opts = ActivityOptions.makeRemoteAnimation( 591 new RemoteAnimationAdapter(new Stub() { 592 593 @Override 594 public void onAnimationStart(RemoteAnimationTarget[] apps, 595 RemoteAnimationTarget[] wallpapers, 596 IRemoteAnimationFinishedCallback finishedCallback) { 597 598 } 599 600 @Override 601 public void onAnimationCancelled() { 602 603 } 604 }, 0, 0)); 605 mActivity.updateOptionsLocked(opts); 606 assertNotNull(mActivity.takeOptionsLocked(true /* fromClient */)); 607 assertNotNull(mActivity.pendingOptions); 608 609 mActivity.updateOptionsLocked(ActivityOptions.makeBasic()); 610 assertNotNull(mActivity.takeOptionsLocked(false /* fromClient */)); 611 assertNull(mActivity.pendingOptions); 612 } 613 614 @Test testCanLaunchHomeActivityFromChooser()615 public void testCanLaunchHomeActivityFromChooser() { 616 ComponentName chooserComponent = ComponentName.unflattenFromString( 617 Resources.getSystem().getString(R.string.config_chooserActivity)); 618 ActivityRecord chooserActivity = new ActivityBuilder(mService).setComponent( 619 chooserComponent).build(); 620 assertThat(mActivity.canLaunchHomeActivity(NOBODY_UID, chooserActivity)).isTrue(); 621 } 622 623 /** 624 * Verify that an {@link ActivityRecord} reports that it has saved state after creation, and 625 * that it is cleared after activity is resumed. 626 */ 627 @Test testHasSavedState()628 public void testHasSavedState() { 629 assertTrue(mActivity.hasSavedState()); 630 631 ActivityRecord.activityResumedLocked(mActivity.appToken); 632 assertFalse(mActivity.hasSavedState()); 633 assertNull(mActivity.getSavedState()); 634 } 635 636 /** Verify the behavior of {@link ActivityRecord#setSavedState(Bundle)}. */ 637 @Test testUpdateSavedState()638 public void testUpdateSavedState() { 639 mActivity.setSavedState(null /* savedState */); 640 assertFalse(mActivity.hasSavedState()); 641 assertNull(mActivity.getSavedState()); 642 643 final Bundle savedState = new Bundle(); 644 savedState.putString("test", "string"); 645 mActivity.setSavedState(savedState); 646 assertTrue(mActivity.hasSavedState()); 647 assertEquals(savedState, mActivity.getSavedState()); 648 } 649 650 /** Verify the correct updates of saved state when activity client reports stop. */ 651 @Test testUpdateSavedState_activityStopped()652 public void testUpdateSavedState_activityStopped() { 653 final Bundle savedState = new Bundle(); 654 savedState.putString("test", "string"); 655 final PersistableBundle persistentSavedState = new PersistableBundle(); 656 persistentSavedState.putString("persist", "string"); 657 658 // Set state to STOPPING, or ActivityRecord#activityStoppedLocked() call will be ignored. 659 mActivity.setState(STOPPING, "test"); 660 mActivity.activityStopped(savedState, persistentSavedState, "desc"); 661 assertTrue(mActivity.hasSavedState()); 662 assertEquals(savedState, mActivity.getSavedState()); 663 assertEquals(persistentSavedState, mActivity.getPersistentSavedState()); 664 665 // Sending 'null' for saved state can only happen due to timeout, so previously stored saved 666 // states should not be overridden. 667 mActivity.setState(STOPPING, "test"); 668 mActivity.activityStopped(null /* savedState */, null /* persistentSavedState */, "desc"); 669 assertTrue(mActivity.hasSavedState()); 670 assertEquals(savedState, mActivity.getSavedState()); 671 assertEquals(persistentSavedState, mActivity.getPersistentSavedState()); 672 } 673 674 /** 675 * Verify that activity finish request is not performed if activity is finishing or is in 676 * incorrect state. 677 */ 678 @Test testFinishActivityIfPossible_cancelled()679 public void testFinishActivityIfPossible_cancelled() { 680 // Mark activity as finishing 681 mActivity.finishing = true; 682 assertEquals("Duplicate finish request must be ignored", FINISH_RESULT_CANCELLED, 683 mActivity.finishIfPossible("test", false /* oomAdj */)); 684 assertTrue(mActivity.finishing); 685 assertTrue(mActivity.isInStackLocked()); 686 687 // Remove activity from task 688 mActivity.finishing = false; 689 mActivity.onParentChanged(null /*newParent*/, mActivity.getTask()); 690 assertEquals("Activity outside of task/stack cannot be finished", FINISH_RESULT_CANCELLED, 691 mActivity.finishIfPossible("test", false /* oomAdj */)); 692 assertFalse(mActivity.finishing); 693 } 694 695 /** 696 * Verify that activity finish request is placed, but not executed immediately if activity is 697 * not ready yet. 698 */ 699 @Test testFinishActivityIfPossible_requested()700 public void testFinishActivityIfPossible_requested() { 701 mActivity.finishing = false; 702 assertEquals("Currently resumed activity must be prepared removal", FINISH_RESULT_REQUESTED, 703 mActivity.finishIfPossible("test", false /* oomAdj */)); 704 assertTrue(mActivity.finishing); 705 assertTrue(mActivity.isInStackLocked()); 706 707 // First request to finish activity must schedule a "destroy" request to the client. 708 // Activity must be removed from history after the client reports back or after timeout. 709 mActivity.finishing = false; 710 mActivity.setState(STOPPED, "test"); 711 assertEquals("Activity outside of task/stack cannot be finished", FINISH_RESULT_REQUESTED, 712 mActivity.finishIfPossible("test", false /* oomAdj */)); 713 assertTrue(mActivity.finishing); 714 assertTrue(mActivity.isInStackLocked()); 715 } 716 717 /** 718 * Verify that activity finish request removes activity immediately if it's ready. 719 */ 720 @Test testFinishActivityIfPossible_removed()721 public void testFinishActivityIfPossible_removed() { 722 // Prepare the activity record to be ready for immediate removal. It should be invisible and 723 // have no process. Otherwise, request to finish it will send a message to client first. 724 mActivity.setState(STOPPED, "test"); 725 mActivity.mVisibleRequested = false; 726 mActivity.nowVisible = false; 727 // Set process to 'null' to allow immediate removal, but don't call mActivity.setProcess() - 728 // this will cause NPE when updating task's process. 729 mActivity.app = null; 730 731 // Put a visible activity on top, so the finishing activity doesn't have to wait until the 732 // next activity reports idle to destroy it. 733 final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build(); 734 topActivity.mVisibleRequested = true; 735 topActivity.nowVisible = true; 736 topActivity.setState(RESUMED, "test"); 737 738 assertEquals("Activity outside of task/stack cannot be finished", FINISH_RESULT_REMOVED, 739 mActivity.finishIfPossible("test", false /* oomAdj */)); 740 assertTrue(mActivity.finishing); 741 assertFalse(mActivity.isInStackLocked()); 742 } 743 744 /** 745 * Verify that when finishing the top focused activity on top display, the stack order will be 746 * changed by adjusting focus. 747 */ 748 @Test testFinishActivityIfPossible_adjustStackOrder()749 public void testFinishActivityIfPossible_adjustStackOrder() { 750 // Prepare the stacks with order (top to bottom): mStack, stack1, stack2. 751 final ActivityStack stack1 = new StackBuilder(mRootWindowContainer).build(); 752 mStack.moveToFront("test"); 753 // The stack2 is needed here for moving back to simulate the 754 // {@link DisplayContent#mPreferredTopFocusableStack} is cleared, so 755 // {@link DisplayContent#getFocusedStack} will rely on the order of focusable-and-visible 756 // stacks. Then when mActivity is finishing, its stack will be invisible (no running 757 // activities in the stack) that is the key condition to verify. 758 final ActivityStack stack2 = new StackBuilder(mRootWindowContainer).build(); 759 stack2.moveToBack("test", stack2.getBottomMostTask()); 760 761 assertTrue(mStack.isTopStackInDisplayArea()); 762 763 mActivity.setState(RESUMED, "test"); 764 mActivity.finishIfPossible(0 /* resultCode */, null /* resultData */, 765 null /* resultGrants */, "test", false /* oomAdj */); 766 767 assertTrue(stack1.isTopStackInDisplayArea()); 768 } 769 770 /** 771 * Verify that when finishing the top focused activity while root task was created by organizer, 772 * the stack order will be changed by adjusting focus. 773 */ 774 @Test testFinishActivityIfPossible_adjustStackOrderOrganizedRoot()775 public void testFinishActivityIfPossible_adjustStackOrderOrganizedRoot() { 776 // Make mStack be a the root task that created by task organizer 777 mStack.mCreatedByOrganizer = true; 778 779 // Have two tasks (topRootableTask and mTask) as the children of mStack. 780 ActivityRecord topActivity = new ActivityBuilder(mActivity.mAtmService) 781 .setCreateTask(true) 782 .setStack(mStack) 783 .build(); 784 ActivityStack topRootableTask = (ActivityStack) topActivity.getTask(); 785 topRootableTask.moveToFront("test"); 786 assertTrue(mStack.isTopStackInDisplayArea()); 787 788 // Finish top activity and verify the next focusable rootable task has adjusted to top. 789 topActivity.setState(RESUMED, "test"); 790 topActivity.finishIfPossible(0 /* resultCode */, null /* resultData */, 791 null /* resultGrants */, "test", false /* oomAdj */); 792 assertEquals(mTask, mStack.getTopMostTask()); 793 } 794 795 /** 796 * Verify that when top focused activity is on secondary display, when finishing the top focused 797 * activity on default display, the preferred top stack on default display should be changed by 798 * adjusting focus. 799 */ 800 @Test testFinishActivityIfPossible_PreferredTopStackChanged()801 public void testFinishActivityIfPossible_PreferredTopStackChanged() { 802 final ActivityRecord topActivityOnNonTopDisplay = 803 createActivityOnDisplay(true /* defaultDisplay */, null /* process */); 804 ActivityStack topRootableTask = topActivityOnNonTopDisplay.getRootTask(); 805 topRootableTask.moveToFront("test"); 806 assertTrue(topRootableTask.isTopStackInDisplayArea()); 807 assertEquals(topRootableTask, topActivityOnNonTopDisplay.getDisplayArea() 808 .mPreferredTopFocusableStack); 809 810 final ActivityRecord secondaryDisplayActivity = 811 createActivityOnDisplay(false /* defaultDisplay */, null /* process */); 812 topRootableTask = secondaryDisplayActivity.getRootTask(); 813 topRootableTask.moveToFront("test"); 814 assertTrue(topRootableTask.isTopStackInDisplayArea()); 815 assertEquals(topRootableTask, 816 secondaryDisplayActivity.getDisplayArea().mPreferredTopFocusableStack); 817 818 // The global top focus activity is on secondary display now. 819 // Finish top activity on default display and verify the next preferred top focusable stack 820 // on default display has changed. 821 topActivityOnNonTopDisplay.setState(RESUMED, "test"); 822 topActivityOnNonTopDisplay.finishIfPossible(0 /* resultCode */, null /* resultData */, 823 null /* resultGrants */, "test", false /* oomAdj */); 824 assertEquals(mTask, mStack.getTopMostTask()); 825 assertEquals(mStack, mActivity.getDisplayArea().mPreferredTopFocusableStack); 826 } 827 828 /** 829 * Verify that resumed activity is paused due to finish request. 830 */ 831 @Test testFinishActivityIfPossible_resumedStartsPausing()832 public void testFinishActivityIfPossible_resumedStartsPausing() { 833 mActivity.finishing = false; 834 mActivity.setState(RESUMED, "test"); 835 assertEquals("Currently resumed activity must be paused before removal", 836 FINISH_RESULT_REQUESTED, mActivity.finishIfPossible("test", false /* oomAdj */)); 837 assertEquals(PAUSING, mActivity.getState()); 838 verify(mActivity).setVisibility(eq(false)); 839 verify(mActivity.getDisplay().mDisplayContent) 840 .prepareAppTransition(eq(TRANSIT_TASK_CLOSE), eq(false) /* alwaysKeepCurrent */); 841 } 842 843 /** 844 * Verify that finish request will be completed immediately for non-resumed activity. 845 */ 846 @Test testFinishActivityIfPossible_nonResumedFinishCompletesImmediately()847 public void testFinishActivityIfPossible_nonResumedFinishCompletesImmediately() { 848 final ActivityState[] states = {INITIALIZING, STARTED, PAUSED, STOPPING, STOPPED}; 849 for (ActivityState state : states) { 850 mActivity.finishing = false; 851 mActivity.setState(state, "test"); 852 reset(mActivity); 853 assertEquals("Finish must be requested", FINISH_RESULT_REQUESTED, 854 mActivity.finishIfPossible("test", false /* oomAdj */)); 855 verify(mActivity).completeFinishing(anyString()); 856 } 857 } 858 859 /** 860 * Verify that finishing will not be completed in PAUSING state. 861 */ 862 @Test testFinishActivityIfPossible_pausing()863 public void testFinishActivityIfPossible_pausing() { 864 mActivity.finishing = false; 865 mActivity.setState(PAUSING, "test"); 866 assertEquals("Finish must be requested", FINISH_RESULT_REQUESTED, 867 mActivity.finishIfPossible("test", false /* oomAdj */)); 868 verify(mActivity, never()).completeFinishing(anyString()); 869 } 870 871 /** 872 * Verify that finish request for resumed activity will prepare an app transition but not 873 * execute it immediately. 874 */ 875 @Test testFinishActivityIfPossible_visibleResumedPreparesAppTransition()876 public void testFinishActivityIfPossible_visibleResumedPreparesAppTransition() { 877 mActivity.finishing = false; 878 mActivity.mVisibleRequested = true; 879 mActivity.setState(RESUMED, "test"); 880 mActivity.finishIfPossible("test", false /* oomAdj */); 881 882 verify(mActivity).setVisibility(eq(false)); 883 verify(mActivity.getDisplay().mDisplayContent) 884 .prepareAppTransition(eq(TRANSIT_TASK_CLOSE), eq(false) /* alwaysKeepCurrent */); 885 verify(mActivity.getDisplay().mDisplayContent, never()).executeAppTransition(); 886 } 887 888 /** 889 * Verify that finish request for paused activity will prepare and execute an app transition. 890 */ 891 @Test testFinishActivityIfPossible_visibleNotResumedExecutesAppTransition()892 public void testFinishActivityIfPossible_visibleNotResumedExecutesAppTransition() { 893 mActivity.finishing = false; 894 mActivity.mVisibleRequested = true; 895 mActivity.setState(PAUSED, "test"); 896 mActivity.finishIfPossible("test", false /* oomAdj */); 897 898 verify(mActivity, atLeast(1)).setVisibility(eq(false)); 899 verify(mActivity.getDisplay().mDisplayContent) 900 .prepareAppTransition(eq(TRANSIT_TASK_CLOSE), eq(false) /* alwaysKeepCurrent */); 901 verify(mActivity.getDisplay().mDisplayContent).executeAppTransition(); 902 } 903 904 /** 905 * Verify that finish request for non-visible activity will not prepare any transitions. 906 */ 907 @Test testFinishActivityIfPossible_nonVisibleNoAppTransition()908 public void testFinishActivityIfPossible_nonVisibleNoAppTransition() { 909 // Put an activity on top of test activity to make it invisible and prevent us from 910 // accidentally resuming the topmost one again. 911 new ActivityBuilder(mService).build(); 912 mActivity.mVisibleRequested = false; 913 mActivity.setState(STOPPED, "test"); 914 915 mActivity.finishIfPossible("test", false /* oomAdj */); 916 917 verify(mActivity.getDisplay().mDisplayContent, never()) 918 .prepareAppTransition(eq(TRANSIT_TASK_CLOSE), eq(false) /* alwaysKeepCurrent */); 919 } 920 921 /** 922 * Verify that complete finish request for non-finishing activity is invalid. 923 */ 924 @Test(expected = IllegalArgumentException.class) testCompleteFinishing_failNotFinishing()925 public void testCompleteFinishing_failNotFinishing() { 926 mActivity.finishing = false; 927 mActivity.completeFinishing("test"); 928 } 929 930 /** 931 * Verify that complete finish request for resumed activity is invalid. 932 */ 933 @Test(expected = IllegalArgumentException.class) testCompleteFinishing_failResumed()934 public void testCompleteFinishing_failResumed() { 935 mActivity.setState(RESUMED, "test"); 936 mActivity.completeFinishing("test"); 937 } 938 939 /** 940 * Verify that finish request for pausing activity must be a no-op - activity will finish 941 * once it completes pausing. 942 */ 943 @Test testCompleteFinishing_pausing()944 public void testCompleteFinishing_pausing() { 945 mActivity.setState(PAUSING, "test"); 946 mActivity.finishing = true; 947 948 assertEquals("Activity must not be removed immediately - waiting for paused", 949 mActivity, mActivity.completeFinishing("test")); 950 assertEquals(PAUSING, mActivity.getState()); 951 verify(mActivity, never()).destroyIfPossible(anyString()); 952 } 953 954 /** 955 * Verify that finish request won't change the state of next top activity if the current 956 * finishing activity doesn't need to be destroyed immediately. The case is usually like 957 * from {@link ActivityStack#completePauseLocked(boolean, ActivityRecord)} to 958 * {@link ActivityRecord#completeFinishing(String)}, so the complete-pause should take the 959 * responsibility to resume the next activity with updating the state. 960 */ 961 @Test testCompleteFinishing_keepStateOfNextInvisible()962 public void testCompleteFinishing_keepStateOfNextInvisible() { 963 final ActivityRecord currentTop = mActivity; 964 currentTop.mVisibleRequested = currentTop.nowVisible = true; 965 966 // Simulates that {@code currentTop} starts an existing activity from background (so its 967 // state is stopped) and the starting flow just goes to place it at top. 968 final ActivityStack nextStack = new StackBuilder(mRootWindowContainer).build(); 969 final ActivityRecord nextTop = nextStack.getTopNonFinishingActivity(); 970 nextTop.setState(STOPPED, "test"); 971 972 mStack.mPausingActivity = currentTop; 973 currentTop.finishing = true; 974 currentTop.setState(PAUSED, "test"); 975 currentTop.completeFinishing("completePauseLocked"); 976 977 // Current top becomes stopping because it is visible and the next is invisible. 978 assertEquals(STOPPING, currentTop.getState()); 979 // The state of next activity shouldn't be changed. 980 assertEquals(STOPPED, nextTop.getState()); 981 } 982 983 /** 984 * Verify that complete finish request for visible activity must be delayed before the next one 985 * becomes visible. 986 */ 987 @Test testCompleteFinishing_waitForNextVisible()988 public void testCompleteFinishing_waitForNextVisible() { 989 final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build(); 990 topActivity.mVisibleRequested = true; 991 topActivity.nowVisible = true; 992 topActivity.finishing = true; 993 topActivity.setState(PAUSED, "true"); 994 // Mark the bottom activity as not visible, so that we will wait for it before removing 995 // the top one. 996 mActivity.mVisibleRequested = false; 997 mActivity.nowVisible = false; 998 mActivity.setState(STOPPED, "test"); 999 1000 assertEquals("Activity must not be removed immediately - waiting for next visible", 1001 topActivity, topActivity.completeFinishing("test")); 1002 assertEquals("Activity must be stopped to make next one visible", STOPPING, 1003 topActivity.getState()); 1004 assertTrue("Activity must be stopped to make next one visible", 1005 topActivity.mStackSupervisor.mStoppingActivities.contains(topActivity)); 1006 verify(topActivity, never()).destroyIfPossible(anyString()); 1007 } 1008 1009 /** 1010 * Verify that complete finish request for invisible activity must not be delayed. 1011 */ 1012 @Test testCompleteFinishing_noWaitForNextVisible_alreadyInvisible()1013 public void testCompleteFinishing_noWaitForNextVisible_alreadyInvisible() { 1014 final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build(); 1015 topActivity.mVisibleRequested = false; 1016 topActivity.nowVisible = false; 1017 topActivity.finishing = true; 1018 topActivity.setState(STOPPED, "true"); 1019 // Mark the bottom activity as not visible, so that we would wait for it before removing 1020 // the top one. 1021 mActivity.mVisibleRequested = false; 1022 mActivity.nowVisible = false; 1023 mActivity.setState(STOPPED, "test"); 1024 1025 topActivity.completeFinishing("test"); 1026 1027 verify(topActivity).destroyIfPossible(anyString()); 1028 } 1029 1030 /** 1031 * Verify that paused finishing activity will be added to finishing list and wait for next one 1032 * to idle. 1033 */ 1034 @Test testCompleteFinishing_waitForIdle()1035 public void testCompleteFinishing_waitForIdle() { 1036 final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build(); 1037 topActivity.mVisibleRequested = true; 1038 topActivity.nowVisible = true; 1039 topActivity.finishing = true; 1040 topActivity.setState(PAUSED, "true"); 1041 // Mark the bottom activity as already visible, so that there is no need to wait for it. 1042 mActivity.mVisibleRequested = true; 1043 mActivity.nowVisible = true; 1044 mActivity.setState(RESUMED, "test"); 1045 1046 topActivity.completeFinishing("test"); 1047 1048 verify(topActivity).addToFinishingAndWaitForIdle(); 1049 } 1050 1051 /** 1052 * Verify that complete finish request for visible activity must not be delayed if the next one 1053 * is already visible and it's not the focused stack. 1054 */ 1055 @Test testCompleteFinishing_noWaitForNextVisible_stopped()1056 public void testCompleteFinishing_noWaitForNextVisible_stopped() { 1057 final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build(); 1058 topActivity.mVisibleRequested = false; 1059 topActivity.nowVisible = false; 1060 topActivity.finishing = true; 1061 topActivity.setState(STOPPED, "true"); 1062 // Mark the bottom activity as already visible, so that there is no need to wait for it. 1063 mActivity.mVisibleRequested = true; 1064 mActivity.nowVisible = true; 1065 mActivity.setState(RESUMED, "test"); 1066 1067 topActivity.completeFinishing("test"); 1068 1069 verify(topActivity).destroyIfPossible(anyString()); 1070 } 1071 1072 /** 1073 * Verify that complete finish request for visible activity must not be delayed if the next one 1074 * is already visible and it's not the focused stack. 1075 */ 1076 @Test testCompleteFinishing_noWaitForNextVisible_nonFocusedStack()1077 public void testCompleteFinishing_noWaitForNextVisible_nonFocusedStack() { 1078 final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build(); 1079 topActivity.mVisibleRequested = true; 1080 topActivity.nowVisible = true; 1081 topActivity.finishing = true; 1082 topActivity.setState(PAUSED, "true"); 1083 // Mark the bottom activity as already visible, so that there is no need to wait for it. 1084 mActivity.mVisibleRequested = true; 1085 mActivity.nowVisible = true; 1086 mActivity.setState(RESUMED, "test"); 1087 1088 // Add another stack to become focused and make the activity there visible. This way it 1089 // simulates finishing in non-focused stack in split-screen. 1090 final ActivityStack stack = new StackBuilder(mRootWindowContainer).build(); 1091 final ActivityRecord focusedActivity = stack.getTopMostActivity(); 1092 focusedActivity.nowVisible = true; 1093 focusedActivity.mVisibleRequested = true; 1094 focusedActivity.setState(RESUMED, "test"); 1095 stack.mResumedActivity = focusedActivity; 1096 1097 topActivity.completeFinishing("test"); 1098 1099 verify(topActivity).destroyIfPossible(anyString()); 1100 } 1101 1102 /** 1103 * Verify that complete finish request for a show-when-locked activity must ensure the 1104 * keyguard occluded state being updated. 1105 */ 1106 @Test testCompleteFinishing_showWhenLocked()1107 public void testCompleteFinishing_showWhenLocked() { 1108 // Make keyguard locked and set the top activity show-when-locked. 1109 KeyguardController keyguardController = mActivity.mStackSupervisor.getKeyguardController(); 1110 doReturn(true).when(keyguardController).isKeyguardLocked(); 1111 final ActivityRecord topActivity = new ActivityBuilder(mService).setTask(mTask).build(); 1112 topActivity.mVisibleRequested = true; 1113 topActivity.nowVisible = true; 1114 topActivity.setState(RESUMED, "true"); 1115 doCallRealMethod().when(mRootWindowContainer).ensureActivitiesVisible( 1116 any() /* starting */, anyInt() /* configChanges */, 1117 anyBoolean() /* preserveWindows */, anyBoolean() /* notifyClients */); 1118 topActivity.setShowWhenLocked(true); 1119 1120 // Verify the stack-top activity is occluded keyguard. 1121 assertEquals(topActivity, mStack.topRunningActivity()); 1122 assertTrue(mStack.topActivityOccludesKeyguard()); 1123 1124 // Finish the top activity 1125 topActivity.setState(PAUSED, "true"); 1126 topActivity.finishing = true; 1127 topActivity.completeFinishing("test"); 1128 1129 // Verify new top activity does not occlude keyguard. 1130 assertEquals(mActivity, mStack.topRunningActivity()); 1131 assertFalse(mStack.topActivityOccludesKeyguard()); 1132 } 1133 1134 /** 1135 * Verify that complete finish request for an activity which the resume activity is translucent 1136 * must ensure the visibilities of activities being updated. 1137 */ 1138 @Test testCompleteFinishing_ensureActivitiesVisible()1139 public void testCompleteFinishing_ensureActivitiesVisible() { 1140 final ActivityRecord firstActivity = new ActivityBuilder(mService).setTask(mTask).build(); 1141 firstActivity.mVisibleRequested = false; 1142 firstActivity.nowVisible = false; 1143 firstActivity.setState(STOPPED, "true"); 1144 1145 final ActivityRecord secondActivity = new ActivityBuilder(mService).setTask(mTask).build(); 1146 secondActivity.mVisibleRequested = true; 1147 secondActivity.nowVisible = true; 1148 secondActivity.setState(PAUSED, "true"); 1149 1150 final ActivityRecord translucentActivity = 1151 new ActivityBuilder(mService).setTask(mTask).build(); 1152 translucentActivity.mVisibleRequested = true; 1153 translucentActivity.nowVisible = true; 1154 translucentActivity.setState(RESUMED, "true"); 1155 1156 doReturn(false).when(translucentActivity).occludesParent(); 1157 1158 // Finish the second activity 1159 secondActivity.finishing = true; 1160 secondActivity.completeFinishing("test"); 1161 verify(secondActivity.getDisplay()).ensureActivitiesVisible(null /* starting */, 1162 0 /* configChanges */ , false /* preserveWindows */, 1163 true /* notifyClients */); 1164 1165 // Finish the first activity 1166 firstActivity.finishing = true; 1167 firstActivity.mVisibleRequested = true; 1168 firstActivity.completeFinishing("test"); 1169 verify(firstActivity.getDisplay(), times(2)).ensureActivitiesVisible(null /* starting */, 1170 0 /* configChanges */ , false /* preserveWindows */, 1171 true /* notifyClients */); 1172 } 1173 1174 /** 1175 * Verify destroy activity request completes successfully. 1176 */ 1177 @Test testDestroyIfPossible()1178 public void testDestroyIfPossible() { 1179 doReturn(false).when(mRootWindowContainer).resumeFocusedStacksTopActivities(); 1180 spyOn(mStack); 1181 mActivity.destroyIfPossible("test"); 1182 1183 assertEquals(DESTROYING, mActivity.getState()); 1184 assertTrue(mActivity.finishing); 1185 verify(mActivity).destroyImmediately(eq(true) /* removeFromApp */, anyString()); 1186 } 1187 1188 /** 1189 * Verify that complete finish request for visible activity must not destroy it immediately if 1190 * it is the last running activity on a display with a home stack. We must wait for home 1191 * activity to come up to avoid a black flash in this case. 1192 */ 1193 @Test testDestroyIfPossible_lastActivityAboveEmptyHomeStack()1194 public void testDestroyIfPossible_lastActivityAboveEmptyHomeStack() { 1195 // Empty the home stack. 1196 final ActivityStack homeStack = mActivity.getDisplayArea().getRootHomeTask(); 1197 homeStack.forAllLeafTasks((t) -> { 1198 homeStack.removeChild(t, "test"); 1199 }, true /* traverseTopToBottom */); 1200 mActivity.finishing = true; 1201 doReturn(false).when(mRootWindowContainer).resumeFocusedStacksTopActivities(); 1202 spyOn(mStack); 1203 1204 // Try to destroy the last activity above the home stack. 1205 mActivity.destroyIfPossible("test"); 1206 1207 // Verify that the activity was not actually destroyed, but waits for next one to come up 1208 // instead. 1209 verify(mActivity, never()).destroyImmediately(eq(true) /* removeFromApp */, anyString()); 1210 assertEquals(FINISHING, mActivity.getState()); 1211 assertTrue(mActivity.mStackSupervisor.mFinishingActivities.contains(mActivity)); 1212 } 1213 1214 /** 1215 * Verify that complete finish request for visible activity must resume next home stack before 1216 * destroying it immediately if it is the last running activity on a display with a home stack. 1217 * We must wait for home activity to come up to avoid a black flash in this case. 1218 */ 1219 @Test testCompleteFinishing_lastActivityAboveEmptyHomeStack()1220 public void testCompleteFinishing_lastActivityAboveEmptyHomeStack() { 1221 // Empty the home stack. 1222 final ActivityStack homeStack = mActivity.getDisplayArea().getRootHomeTask(); 1223 homeStack.forAllLeafTasks((t) -> { 1224 homeStack.removeChild(t, "test"); 1225 }, true /* traverseTopToBottom */); 1226 mActivity.finishing = true; 1227 spyOn(mStack); 1228 1229 // Try to finish the last activity above the home stack. 1230 mActivity.completeFinishing("test"); 1231 1232 // Verify that the activity is not destroyed immediately, but waits for next one to come up. 1233 verify(mActivity, never()).destroyImmediately(eq(true) /* removeFromApp */, anyString()); 1234 assertEquals(FINISHING, mActivity.getState()); 1235 assertTrue(mActivity.mStackSupervisor.mFinishingActivities.contains(mActivity)); 1236 } 1237 1238 /** 1239 * Test that the activity will be moved to destroying state and the message to destroy will be 1240 * sent to the client. 1241 */ 1242 @Test testDestroyImmediately_hadApp_finishing()1243 public void testDestroyImmediately_hadApp_finishing() { 1244 mActivity.finishing = true; 1245 mActivity.destroyImmediately(false /* removeFromApp */, "test"); 1246 1247 assertEquals(DESTROYING, mActivity.getState()); 1248 } 1249 1250 /** 1251 * Test that the activity will be moved to destroyed state immediately if it was not marked as 1252 * finishing before {@link ActivityRecord#destroyImmediately(boolean, String)}. 1253 */ 1254 @Test testDestroyImmediately_hadApp_notFinishing()1255 public void testDestroyImmediately_hadApp_notFinishing() { 1256 mActivity.finishing = false; 1257 mActivity.destroyImmediately(false /* removeFromApp */, "test"); 1258 1259 assertEquals(DESTROYED, mActivity.getState()); 1260 } 1261 1262 /** 1263 * Test that an activity with no process attached and that is marked as finishing will be 1264 * removed from task when {@link ActivityRecord#destroyImmediately(boolean, String)} is called. 1265 */ 1266 @Test testDestroyImmediately_noApp_finishing()1267 public void testDestroyImmediately_noApp_finishing() { 1268 mActivity.app = null; 1269 mActivity.finishing = true; 1270 final Task task = mActivity.getTask(); 1271 1272 mActivity.destroyImmediately(false /* removeFromApp */, "test"); 1273 1274 assertEquals(DESTROYED, mActivity.getState()); 1275 assertNull(mActivity.getTask()); 1276 assertEquals(0, task.getChildCount()); 1277 } 1278 1279 /** 1280 * Test that an activity with no process attached and that is not marked as finishing will be 1281 * marked as DESTROYED but not removed from task. 1282 */ 1283 @Test testDestroyImmediately_noApp_notFinishing()1284 public void testDestroyImmediately_noApp_notFinishing() { 1285 mActivity.app = null; 1286 mActivity.finishing = false; 1287 final Task task = mActivity.getTask(); 1288 1289 mActivity.destroyImmediately(false /* removeFromApp */, "test"); 1290 1291 assertEquals(DESTROYED, mActivity.getState()); 1292 assertEquals(task, mActivity.getTask()); 1293 assertEquals(1, task.getChildCount()); 1294 } 1295 1296 /** 1297 * Test that an activity will not be destroyed if it is marked as non-destroyable. 1298 */ 1299 @Test testSafelyDestroy_nonDestroyable()1300 public void testSafelyDestroy_nonDestroyable() { 1301 doReturn(false).when(mActivity).isDestroyable(); 1302 1303 mActivity.safelyDestroy("test"); 1304 1305 verify(mActivity, never()).destroyImmediately(eq(true) /* removeFromApp */, anyString()); 1306 } 1307 1308 /** 1309 * Test that an activity will not be destroyed if it is marked as non-destroyable. 1310 */ 1311 @Test testSafelyDestroy_destroyable()1312 public void testSafelyDestroy_destroyable() { 1313 doReturn(true).when(mActivity).isDestroyable(); 1314 1315 mActivity.safelyDestroy("test"); 1316 1317 verify(mActivity).destroyImmediately(eq(true) /* removeFromApp */, anyString()); 1318 } 1319 1320 @Test testRemoveFromHistory()1321 public void testRemoveFromHistory() { 1322 final ActivityStack stack = mActivity.getRootTask(); 1323 final Task task = mActivity.getTask(); 1324 1325 mActivity.removeFromHistory("test"); 1326 1327 assertEquals(DESTROYED, mActivity.getState()); 1328 assertNull(mActivity.app); 1329 assertNull(mActivity.getTask()); 1330 assertEquals(0, task.getChildCount()); 1331 assertEquals(task.getStack(), task); 1332 assertEquals(0, stack.getChildCount()); 1333 } 1334 1335 /** 1336 * Test that it's not allowed to call {@link ActivityRecord#destroyed(String)} if activity is 1337 * not in destroying or destroyed state. 1338 */ 1339 @Test(expected = IllegalStateException.class) testDestroyed_notDestroying()1340 public void testDestroyed_notDestroying() { 1341 mActivity.setState(STOPPED, "test"); 1342 mActivity.destroyed("test"); 1343 } 1344 1345 /** 1346 * Test that {@link ActivityRecord#destroyed(String)} can be called if an activity is destroying 1347 */ 1348 @Test testDestroyed_destroying()1349 public void testDestroyed_destroying() { 1350 mActivity.setState(DESTROYING, "test"); 1351 mActivity.destroyed("test"); 1352 1353 verify(mActivity).removeFromHistory(anyString()); 1354 } 1355 1356 /** 1357 * Test that {@link ActivityRecord#destroyed(String)} can be called if an activity is destroyed. 1358 */ 1359 @Test testDestroyed_destroyed()1360 public void testDestroyed_destroyed() { 1361 mActivity.setState(DESTROYED, "test"); 1362 mActivity.destroyed("test"); 1363 1364 verify(mActivity).removeFromHistory(anyString()); 1365 } 1366 1367 @Test testActivityOverridesProcessConfig()1368 public void testActivityOverridesProcessConfig() { 1369 final WindowProcessController wpc = mActivity.app; 1370 assertTrue(wpc.registeredForActivityConfigChanges()); 1371 assertFalse(wpc.registeredForDisplayConfigChanges()); 1372 1373 final ActivityRecord secondaryDisplayActivity = 1374 createActivityOnDisplay(false /* defaultDisplay */, null /* process */); 1375 1376 assertTrue(wpc.registeredForActivityConfigChanges()); 1377 assertEquals(0, mActivity.getMergedOverrideConfiguration() 1378 .diff(wpc.getRequestedOverrideConfiguration())); 1379 assertNotEquals(mActivity.getConfiguration(), 1380 secondaryDisplayActivity.getConfiguration()); 1381 } 1382 1383 @Test testActivityOverridesProcessConfig_TwoActivities()1384 public void testActivityOverridesProcessConfig_TwoActivities() { 1385 final WindowProcessController wpc = mActivity.app; 1386 assertTrue(wpc.registeredForActivityConfigChanges()); 1387 1388 final Task firstTaskRecord = mActivity.getTask(); 1389 final ActivityRecord secondActivityRecord = 1390 new ActivityBuilder(mService).setTask(firstTaskRecord).setUseProcess(wpc).build(); 1391 1392 assertTrue(wpc.registeredForActivityConfigChanges()); 1393 assertEquals(0, secondActivityRecord.getMergedOverrideConfiguration() 1394 .diff(wpc.getRequestedOverrideConfiguration())); 1395 } 1396 1397 @Test testActivityOverridesProcessConfig_TwoActivities_SecondaryDisplay()1398 public void testActivityOverridesProcessConfig_TwoActivities_SecondaryDisplay() { 1399 final WindowProcessController wpc = mActivity.app; 1400 assertTrue(wpc.registeredForActivityConfigChanges()); 1401 1402 final ActivityRecord secondActivityRecord = 1403 new ActivityBuilder(mService).setTask(mTask).setUseProcess(wpc).build(); 1404 1405 assertTrue(wpc.registeredForActivityConfigChanges()); 1406 assertEquals(0, secondActivityRecord.getMergedOverrideConfiguration() 1407 .diff(wpc.getRequestedOverrideConfiguration())); 1408 } 1409 1410 @Test testActivityOverridesProcessConfig_TwoActivities_DifferentTasks()1411 public void testActivityOverridesProcessConfig_TwoActivities_DifferentTasks() { 1412 final WindowProcessController wpc = mActivity.app; 1413 assertTrue(wpc.registeredForActivityConfigChanges()); 1414 1415 final ActivityRecord secondActivityRecord = 1416 createActivityOnDisplay(true /* defaultDisplay */, wpc); 1417 1418 assertTrue(wpc.registeredForActivityConfigChanges()); 1419 assertEquals(0, secondActivityRecord.getMergedOverrideConfiguration() 1420 .diff(wpc.getRequestedOverrideConfiguration())); 1421 } 1422 1423 @Test testActivityOnCancelFixedRotationTransform()1424 public void testActivityOnCancelFixedRotationTransform() { 1425 final DisplayRotation displayRotation = mActivity.mDisplayContent.getDisplayRotation(); 1426 spyOn(displayRotation); 1427 1428 final DisplayContent display = mActivity.mDisplayContent; 1429 final int originalRotation = display.getRotation(); 1430 1431 // Make {@link DisplayContent#sendNewConfiguration} not apply rotation immediately. 1432 doReturn(true).when(displayRotation).isWaitingForRemoteRotation(); 1433 doReturn((originalRotation + 1) % 4).when(displayRotation).rotationForOrientation( 1434 anyInt() /* orientation */, anyInt() /* lastRotation */); 1435 // Set to visible so the activity can freeze the screen. 1436 mActivity.setVisibility(true); 1437 1438 display.rotateInDifferentOrientationIfNeeded(mActivity); 1439 display.setFixedRotationLaunchingAppUnchecked(mActivity); 1440 displayRotation.updateRotationUnchecked(true /* forceUpdate */); 1441 1442 assertTrue(displayRotation.isRotatingSeamlessly()); 1443 1444 // The launching rotated app should not be cleared when waiting for remote rotation. 1445 display.continueUpdateOrientationForDiffOrienLaunchingApp(); 1446 assertTrue(display.isFixedRotationLaunchingApp(mActivity)); 1447 1448 // Simulate the rotation has been updated to previous one, e.g. sensor updates before the 1449 // remote rotation is completed. 1450 doReturn(originalRotation).when(displayRotation).rotationForOrientation( 1451 anyInt() /* orientation */, anyInt() /* lastRotation */); 1452 display.updateOrientation(); 1453 1454 final DisplayInfo rotatedInfo = mActivity.getFixedRotationTransformDisplayInfo(); 1455 mActivity.finishFixedRotationTransform(); 1456 final ScreenRotationAnimation rotationAnim = display.getRotationAnimation(); 1457 assertNotNull(rotationAnim); 1458 rotationAnim.setRotation(display.getPendingTransaction(), originalRotation); 1459 1460 // Because the display doesn't rotate, the rotated activity needs to cancel the fixed 1461 // rotation. There should be a rotation animation to cover the change of activity. 1462 verify(mActivity).onCancelFixedRotationTransform(rotatedInfo.rotation); 1463 assertTrue(mActivity.isFreezingScreen()); 1464 assertFalse(displayRotation.isRotatingSeamlessly()); 1465 assertTrue(rotationAnim.isRotating()); 1466 1467 // Simulate the remote rotation has completed and the configuration doesn't change, then 1468 // the rotated activity should also be restored by clearing the transform. 1469 displayRotation.updateRotationUnchecked(true /* forceUpdate */); 1470 doReturn(false).when(displayRotation).isWaitingForRemoteRotation(); 1471 clearInvocations(mActivity); 1472 display.setFixedRotationLaunchingAppUnchecked(mActivity); 1473 display.sendNewConfiguration(); 1474 1475 assertFalse(display.hasTopFixedRotationLaunchingApp()); 1476 assertFalse(mActivity.hasFixedRotationTransform()); 1477 } 1478 1479 @Test testIsSnapshotCompatible()1480 public void testIsSnapshotCompatible() { 1481 final TaskSnapshot snapshot = new TaskSnapshotPersisterTestBase.TaskSnapshotBuilder() 1482 .setRotation(mActivity.getWindowConfiguration().getRotation()) 1483 .build(); 1484 1485 assertTrue(mActivity.isSnapshotCompatible(snapshot)); 1486 1487 setRotatedScreenOrientationSilently(mActivity); 1488 1489 assertFalse(mActivity.isSnapshotCompatible(snapshot)); 1490 } 1491 1492 @Test testFixedRotationSnapshotStartingWindow()1493 public void testFixedRotationSnapshotStartingWindow() { 1494 // TaskSnapshotSurface requires a fullscreen opaque window. 1495 final WindowManager.LayoutParams params = new WindowManager.LayoutParams( 1496 WindowManager.LayoutParams.TYPE_APPLICATION_STARTING); 1497 params.width = params.height = WindowManager.LayoutParams.MATCH_PARENT; 1498 final WindowTestUtils.TestWindowState w = new WindowTestUtils.TestWindowState( 1499 mService.mWindowManager, mock(Session.class), new TestIWindow(), params, mActivity); 1500 mActivity.addWindow(w); 1501 1502 // Assume the activity is launching in different rotation, and there was an available 1503 // snapshot accepted by {@link Activity#isSnapshotCompatible}. 1504 final TaskSnapshot snapshot = new TaskSnapshotPersisterTestBase.TaskSnapshotBuilder() 1505 .setRotation((mActivity.getWindowConfiguration().getRotation() + 1) % 4) 1506 .build(); 1507 setRotatedScreenOrientationSilently(mActivity); 1508 mActivity.setVisible(false); 1509 1510 final IWindowSession session = WindowManagerGlobal.getWindowSession(); 1511 spyOn(session); 1512 try { 1513 // Return error to skip unnecessary operation. 1514 doReturn(WindowManagerGlobal.ADD_STARTING_NOT_NEEDED).when(session).addToDisplay( 1515 any() /* window */, anyInt() /* seq */, any() /* attrs */, 1516 anyInt() /* viewVisibility */, anyInt() /* displayId */, any() /* outFrame */, 1517 any() /* outContentInsets */, any() /* outStableInsets */, 1518 any() /* outDisplayCutout */, any() /* outInputChannel */, 1519 any() /* outInsetsState */, any() /* outActiveControls */); 1520 TaskSnapshotSurface.create(mService.mWindowManager, mActivity, snapshot); 1521 } catch (RemoteException ignored) { 1522 } finally { 1523 reset(session); 1524 } 1525 1526 // Because the rotation of snapshot and the corresponding top activity are different, fixed 1527 // rotation should be applied when creating snapshot surface if the display rotation may be 1528 // changed according to the activity orientation. 1529 assertTrue(mActivity.hasFixedRotationTransform()); 1530 assertTrue(mActivity.mDisplayContent.isFixedRotationLaunchingApp(mActivity)); 1531 } 1532 1533 /** 1534 * Sets orientation without notifying the parent to simulate that the display has not applied 1535 * the requested orientation yet. 1536 */ setRotatedScreenOrientationSilently(ActivityRecord r)1537 static void setRotatedScreenOrientationSilently(ActivityRecord r) { 1538 final int rotatedOrentation = r.getConfiguration().orientation == ORIENTATION_PORTRAIT 1539 ? SCREEN_ORIENTATION_LANDSCAPE 1540 : SCREEN_ORIENTATION_PORTRAIT; 1541 doReturn(false).when(r).onDescendantOrientationChanged(any(), any()); 1542 r.setOrientation(rotatedOrentation); 1543 } 1544 1545 @Test testActivityOnDifferentDisplayUpdatesProcessOverride()1546 public void testActivityOnDifferentDisplayUpdatesProcessOverride() { 1547 final ActivityRecord secondaryDisplayActivity = 1548 createActivityOnDisplay(false /* defaultDisplay */, null /* process */); 1549 final WindowProcessController wpc = secondaryDisplayActivity.app; 1550 assertTrue(wpc.registeredForActivityConfigChanges()); 1551 1552 final ActivityRecord secondActivityRecord = 1553 createActivityOnDisplay(true /* defaultDisplay */, wpc); 1554 1555 assertTrue(wpc.registeredForActivityConfigChanges()); 1556 assertEquals(0, secondActivityRecord.getMergedOverrideConfiguration() 1557 .diff(wpc.getRequestedOverrideConfiguration())); 1558 assertFalse(wpc.registeredForDisplayConfigChanges()); 1559 } 1560 1561 @Test testActivityReparentChangesProcessOverride()1562 public void testActivityReparentChangesProcessOverride() { 1563 final WindowProcessController wpc = mActivity.app; 1564 final Task initialTask = mActivity.getTask(); 1565 final Configuration initialConf = 1566 new Configuration(mActivity.getMergedOverrideConfiguration()); 1567 assertEquals(0, mActivity.getMergedOverrideConfiguration() 1568 .diff(wpc.getRequestedOverrideConfiguration())); 1569 assertTrue(wpc.registeredForActivityConfigChanges()); 1570 1571 // Create a new task with custom config to reparent the activity to. 1572 final Task newTask = 1573 new TaskBuilder(mSupervisor).setStack(initialTask.getStack()).build(); 1574 final Configuration newConfig = newTask.getConfiguration(); 1575 newConfig.densityDpi += 100; 1576 newTask.onRequestedOverrideConfigurationChanged(newConfig); 1577 assertEquals(newTask.getConfiguration().densityDpi, newConfig.densityDpi); 1578 1579 // Reparent the activity and verify that config override changed. 1580 mActivity.reparent(newTask, 0 /* top */, "test"); 1581 assertEquals(mActivity.getConfiguration().densityDpi, newConfig.densityDpi); 1582 assertEquals(mActivity.getMergedOverrideConfiguration().densityDpi, newConfig.densityDpi); 1583 1584 assertTrue(wpc.registeredForActivityConfigChanges()); 1585 assertNotEquals(initialConf, wpc.getRequestedOverrideConfiguration()); 1586 assertEquals(0, mActivity.getMergedOverrideConfiguration() 1587 .diff(wpc.getRequestedOverrideConfiguration())); 1588 } 1589 1590 @Test testActivityReparentDoesntClearProcessOverride_TwoActivities()1591 public void testActivityReparentDoesntClearProcessOverride_TwoActivities() { 1592 final WindowProcessController wpc = mActivity.app; 1593 final Configuration initialConf = 1594 new Configuration(mActivity.getMergedOverrideConfiguration()); 1595 final Task initialTask = mActivity.getTask(); 1596 final ActivityRecord secondActivity = new ActivityBuilder(mService).setTask(initialTask) 1597 .setUseProcess(wpc).build(); 1598 1599 assertTrue(wpc.registeredForActivityConfigChanges()); 1600 assertEquals(0, secondActivity.getMergedOverrideConfiguration() 1601 .diff(wpc.getRequestedOverrideConfiguration())); 1602 1603 // Create a new task with custom config to reparent the second activity to. 1604 final Task newTask = 1605 new TaskBuilder(mSupervisor).setStack(initialTask.getStack()).build(); 1606 final Configuration newConfig = newTask.getConfiguration(); 1607 newConfig.densityDpi += 100; 1608 newTask.onRequestedOverrideConfigurationChanged(newConfig); 1609 1610 // Reparent the activity and verify that config override changed. 1611 secondActivity.reparent(newTask, 0 /* top */, "test"); 1612 1613 assertTrue(wpc.registeredForActivityConfigChanges()); 1614 assertEquals(0, secondActivity.getMergedOverrideConfiguration() 1615 .diff(wpc.getRequestedOverrideConfiguration())); 1616 assertNotEquals(initialConf, wpc.getRequestedOverrideConfiguration()); 1617 1618 // Reparent the first activity and verify that config override didn't change. 1619 mActivity.reparent(newTask, 1 /* top */, "test"); 1620 assertTrue(wpc.registeredForActivityConfigChanges()); 1621 assertEquals(0, secondActivity.getMergedOverrideConfiguration() 1622 .diff(wpc.getRequestedOverrideConfiguration())); 1623 assertNotEquals(initialConf, wpc.getRequestedOverrideConfiguration()); 1624 } 1625 1626 @Test testActivityDestroyDoesntChangeProcessOverride()1627 public void testActivityDestroyDoesntChangeProcessOverride() { 1628 final ActivityRecord firstActivity = 1629 createActivityOnDisplay(true /* defaultDisplay */, null /* process */); 1630 final WindowProcessController wpc = firstActivity.app; 1631 assertTrue(wpc.registeredForActivityConfigChanges()); 1632 assertEquals(0, firstActivity.getMergedOverrideConfiguration() 1633 .diff(wpc.getRequestedOverrideConfiguration())); 1634 1635 final ActivityRecord secondActivity = 1636 createActivityOnDisplay(false /* defaultDisplay */, wpc); 1637 assertTrue(wpc.registeredForActivityConfigChanges()); 1638 assertEquals(0, secondActivity.getMergedOverrideConfiguration() 1639 .diff(wpc.getRequestedOverrideConfiguration())); 1640 1641 final ActivityRecord thirdActivity = 1642 createActivityOnDisplay(false /* defaultDisplay */, wpc); 1643 assertTrue(wpc.registeredForActivityConfigChanges()); 1644 assertEquals(0, thirdActivity.getMergedOverrideConfiguration() 1645 .diff(wpc.getRequestedOverrideConfiguration())); 1646 1647 secondActivity.destroyImmediately(true, ""); 1648 1649 assertTrue(wpc.registeredForActivityConfigChanges()); 1650 assertEquals(0, thirdActivity.getMergedOverrideConfiguration() 1651 .diff(wpc.getRequestedOverrideConfiguration())); 1652 1653 firstActivity.destroyImmediately(true, ""); 1654 1655 assertTrue(wpc.registeredForActivityConfigChanges()); 1656 assertEquals(0, thirdActivity.getMergedOverrideConfiguration() 1657 .diff(wpc.getRequestedOverrideConfiguration())); 1658 } 1659 1660 /** 1661 * Creates an activity on display. For non-default display request it will also create a new 1662 * display with custom DisplayInfo. 1663 */ createActivityOnDisplay(boolean defaultDisplay, WindowProcessController process)1664 private ActivityRecord createActivityOnDisplay(boolean defaultDisplay, 1665 WindowProcessController process) { 1666 final DisplayContent display; 1667 if (defaultDisplay) { 1668 display = mRootWindowContainer.getDefaultDisplay(); 1669 } else { 1670 display = new TestDisplayContent.Builder(mService, 2000, 1000).setDensityDpi(300) 1671 .setPosition(DisplayContent.POSITION_TOP).build(); 1672 } 1673 final ActivityStack stack = display.getDefaultTaskDisplayArea() 1674 .createStack(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD, true /* onTop */); 1675 final Task task = new TaskBuilder(mSupervisor).setStack(stack).build(); 1676 return new ActivityBuilder(mService).setTask(task).setUseProcess(process).build(); 1677 } 1678 } 1679