1 /* 2 * Copyright (C) 2024 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.WINDOWING_MODE_FREEFORM; 20 import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW; 21 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; 22 import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE; 23 import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE; 24 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; 25 26 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; 27 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; 28 29 import static org.mockito.ArgumentMatchers.any; 30 import static org.mockito.ArgumentMatchers.anyBoolean; 31 import static org.mockito.ArgumentMatchers.eq; 32 import static org.mockito.Mockito.verify; 33 34 import android.app.WindowConfiguration.WindowingMode; 35 import android.content.ComponentName; 36 import android.content.pm.ActivityInfo; 37 import android.content.pm.PackageManager.UserMinAspectRatio; 38 import android.content.res.Configuration; 39 import android.graphics.Rect; 40 import android.view.Surface; 41 42 import androidx.annotation.CallSuper; 43 import androidx.annotation.NonNull; 44 import androidx.annotation.Nullable; 45 46 import com.android.server.wm.utils.TestComponentStack; 47 48 import org.junit.Assert; 49 50 import java.util.function.Consumer; 51 import java.util.function.Function; 52 import java.util.function.Predicate; 53 54 /** 55 * Robot implementation for {@link ActivityRecord}. 56 */ 57 class AppCompatActivityRobot { 58 59 private static final int DEFAULT_DISPLAY_WIDTH = 1000; 60 private static final int DEFAULT_DISPLAY_HEIGHT = 2000; 61 62 private static final float DELTA_ASPECT_RATIO_TOLERANCE = 0.0001f; 63 private static final float COMPAT_SCALE_TOLERANCE = 0.0001f; 64 65 private static final String TEST_COMPONENT_NAME = AppCompatActivityRobot.class.getName(); 66 67 @NonNull 68 private final ActivityTaskManagerService mAtm; 69 @NonNull 70 private final ActivityTaskSupervisor mSupervisor; 71 @NonNull 72 private final TestComponentStack<ActivityRecord> mActivityStack; 73 @NonNull 74 private final TestComponentStack<Task> mTaskStack; 75 76 private final int mDisplayWidth; 77 private final int mDisplayHeight; 78 private DisplayContent mDisplayContent; 79 80 @Nullable 81 private Consumer<ActivityRecord> mOnPostActivityCreation; 82 83 @Nullable 84 private Consumer<DisplayContent> mOnPostDisplayContentCreation; 85 AppCompatActivityRobot(@onNull WindowManagerService wm, @NonNull ActivityTaskManagerService atm, @NonNull ActivityTaskSupervisor supervisor, int displayWidth, int displayHeight, @Nullable Consumer<ActivityRecord> onPostActivityCreation, @Nullable Consumer<DisplayContent> onPostDisplayContentCreation)86 AppCompatActivityRobot(@NonNull WindowManagerService wm, 87 @NonNull ActivityTaskManagerService atm, @NonNull ActivityTaskSupervisor supervisor, 88 int displayWidth, int displayHeight, 89 @Nullable Consumer<ActivityRecord> onPostActivityCreation, 90 @Nullable Consumer<DisplayContent> onPostDisplayContentCreation) { 91 mAtm = atm; 92 mSupervisor = supervisor; 93 mDisplayWidth = displayWidth; 94 mDisplayHeight = displayHeight; 95 mActivityStack = new TestComponentStack<>(); 96 mTaskStack = new TestComponentStack<>(); 97 mOnPostActivityCreation = onPostActivityCreation; 98 mOnPostDisplayContentCreation = onPostDisplayContentCreation; 99 createNewDisplay(); 100 } 101 AppCompatActivityRobot(@onNull WindowManagerService wm, @NonNull ActivityTaskManagerService atm, @NonNull ActivityTaskSupervisor supervisor, int displayWidth, int displayHeight)102 AppCompatActivityRobot(@NonNull WindowManagerService wm, 103 @NonNull ActivityTaskManagerService atm, @NonNull ActivityTaskSupervisor supervisor, 104 int displayWidth, int displayHeight) { 105 this(wm, atm, supervisor, displayWidth, displayHeight, /* onPostActivityCreation */ null, 106 /* onPostDisplayContentCreation */ null); 107 } 108 AppCompatActivityRobot(@onNull WindowManagerService wm, @NonNull ActivityTaskManagerService atm, @NonNull ActivityTaskSupervisor supervisor)109 AppCompatActivityRobot(@NonNull WindowManagerService wm, 110 @NonNull ActivityTaskManagerService atm, @NonNull ActivityTaskSupervisor supervisor) { 111 this(wm, atm, supervisor, DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT); 112 } 113 createActivityWithComponent()114 void createActivityWithComponent() { 115 createActivityWithComponentInNewTask(/* inNewTask */ mTaskStack.isEmpty(), 116 /* inNewDisplay */ false); 117 } 118 createActivityWithComponentWithoutTask()119 void createActivityWithComponentWithoutTask() { 120 createActivityWithComponentInNewTask(/* inNewTask */ false, /* inNewDisplay */ false); 121 } 122 createActivityWithComponentInNewTask()123 void createActivityWithComponentInNewTask() { 124 createActivityWithComponentInNewTask(/* inNewTask */ true, /* inNewDisplay */ false); 125 } 126 createActivityWithComponentInNewTaskAndDisplay()127 void createActivityWithComponentInNewTaskAndDisplay() { 128 createActivityWithComponentInNewTask(/* inNewTask */ true, /* inNewDisplay */ true); 129 } 130 configureTopActivity(float minAspect, float maxAspect, int screenOrientation, boolean isUnresizable)131 void configureTopActivity(float minAspect, float maxAspect, int screenOrientation, 132 boolean isUnresizable) { 133 prepareLimitedBounds(mActivityStack.top(), minAspect, maxAspect, screenOrientation, 134 isUnresizable); 135 } 136 configureUnresizableTopActivity(@ctivityInfo.ScreenOrientation int screenOrientation)137 void configureUnresizableTopActivity(@ActivityInfo.ScreenOrientation int screenOrientation) { 138 configureTopActivity(/* minAspect */ -1, /* maxAspect */ -1, screenOrientation, 139 /* isUnresizable */ true); 140 } 141 setDisplayNaturalOrientation(@onfiguration.Orientation int naturalOrientation)142 void setDisplayNaturalOrientation(@Configuration.Orientation int naturalOrientation) { 143 doReturn(naturalOrientation).when(mDisplayContent).getNaturalOrientation(); 144 } 145 setDisplayIgnoreActivitySizeRestrictions(boolean enabled)146 void setDisplayIgnoreActivitySizeRestrictions(boolean enabled) { 147 doReturn(enabled).when(mDisplayContent).isDisplayIgnoreActivitySizeRestrictions(); 148 } 149 configureTaskBounds(@onNull Rect taskBounds)150 void configureTaskBounds(@NonNull Rect taskBounds) { 151 doReturn(taskBounds).when(mTaskStack.top()).getBounds(); 152 } 153 configureTaskAppBounds(@onNull Rect appBounds)154 void configureTaskAppBounds(@NonNull Rect appBounds) { 155 mTaskStack.top().getWindowConfiguration().setAppBounds(appBounds); 156 } 157 configureTopActivityBounds(@onNull Rect activityBounds)158 void configureTopActivityBounds(@NonNull Rect activityBounds) { 159 doReturn(activityBounds).when(mActivityStack.top()).getBounds(); 160 } 161 162 @NonNull top()163 ActivityRecord top() { 164 return mActivityStack.top(); 165 } 166 167 @NonNull displayContent()168 DisplayContent displayContent() { 169 return mDisplayContent; 170 } 171 172 @NonNull getFromTop(int fromTop)173 ActivityRecord getFromTop(int fromTop) { 174 return mActivityStack.getFromTop(fromTop); 175 } 176 setTaskWindowingMode(@indowingMode int windowingMode)177 void setTaskWindowingMode(@WindowingMode int windowingMode) { 178 mTaskStack.top().setWindowingMode(windowingMode); 179 } 180 setTaskDisplayAreaWindowingMode(@indowingMode int windowingMode)181 void setTaskDisplayAreaWindowingMode(@WindowingMode int windowingMode) { 182 mTaskStack.top().getDisplayArea().setWindowingMode(windowingMode); 183 } 184 setLetterboxedForFixedOrientationAndAspectRatio(boolean enabled)185 void setLetterboxedForFixedOrientationAndAspectRatio(boolean enabled) { 186 doReturn(enabled).when(mActivityStack.top().mAppCompatController 187 .getAspectRatioPolicy()).isLetterboxedForFixedOrientationAndAspectRatio(); 188 } 189 enableFullscreenCameraCompatTreatmentForTopActivity(boolean enabled)190 void enableFullscreenCameraCompatTreatmentForTopActivity(boolean enabled) { 191 if (mDisplayContent.mAppCompatCameraPolicy.hasDisplayRotationCompatPolicy()) { 192 doReturn(enabled).when( 193 mDisplayContent.mAppCompatCameraPolicy.mDisplayRotationCompatPolicy) 194 .isTreatmentEnabledForActivity(eq(mActivityStack.top())); 195 } 196 } 197 setIsCameraRunningAndWindowingModeEligibleFullscreen(boolean enabled)198 void setIsCameraRunningAndWindowingModeEligibleFullscreen(boolean enabled) { 199 doReturn(enabled).when(getTopDisplayRotationCompatPolicy()) 200 .isCameraRunningAndWindowingModeEligible(eq(mActivityStack.top()), 201 /* mustBeFullscreen= */ eq(true)); 202 } 203 setIsCameraRunningAndWindowingModeEligibleFreeform(boolean enabled)204 void setIsCameraRunningAndWindowingModeEligibleFreeform(boolean enabled) { 205 doReturn(enabled).when(getTopCameraCompatFreeformPolicy()) 206 .isCameraRunningAndWindowingModeEligible(eq(mActivityStack.top())); 207 } 208 setTopActivityEligibleForOrientationOverride(boolean enabled)209 void setTopActivityEligibleForOrientationOverride(boolean enabled) { 210 doReturn(enabled).when(getTopDisplayRotationCompatPolicy()) 211 .isActivityEligibleForOrientationOverride(eq(mActivityStack.top())); 212 } 213 setTopActivityInTransition(boolean inTransition)214 void setTopActivityInTransition(boolean inTransition) { 215 doReturn(inTransition).when(mActivityStack.top()).isInTransition(); 216 } 217 setShouldApplyUserMinAspectRatioOverride(boolean enabled)218 void setShouldApplyUserMinAspectRatioOverride(boolean enabled) { 219 doReturn(enabled).when(mActivityStack.top().mAppCompatController 220 .getAspectRatioOverrides()).shouldApplyUserMinAspectRatioOverride(); 221 } 222 setShouldCreateCompatDisplayInsets(boolean enabled)223 void setShouldCreateCompatDisplayInsets(boolean enabled) { 224 doReturn(enabled).when(mActivityStack.top()).shouldCreateAppCompatDisplayInsets(); 225 } 226 setTopActivityInSizeCompatMode(boolean inScm)227 void setTopActivityInSizeCompatMode(boolean inScm) { 228 doReturn(inScm).when(mActivityStack.top()).inSizeCompatMode(); 229 } 230 setShouldApplyUserFullscreenOverride(boolean enabled)231 void setShouldApplyUserFullscreenOverride(boolean enabled) { 232 doReturn(enabled).when(mActivityStack.top().mAppCompatController 233 .getAspectRatioOverrides()).shouldApplyUserFullscreenOverride(); 234 } 235 setGetUserMinAspectRatioOverrideCode(@serMinAspectRatio int overrideCode)236 void setGetUserMinAspectRatioOverrideCode(@UserMinAspectRatio int overrideCode) { 237 doReturn(overrideCode).when(mActivityStack.top().mAppCompatController 238 .getAspectRatioOverrides()).getUserMinAspectRatioOverrideCode(); 239 } 240 setGetUserMinAspectRatioOverrideValue(float overrideValue)241 void setGetUserMinAspectRatioOverrideValue(float overrideValue) { 242 doReturn(overrideValue).when(mActivityStack.top().mAppCompatController 243 .getAspectRatioOverrides()).getUserMinAspectRatio(); 244 } 245 setShouldRefreshActivityForCameraCompat(boolean enabled)246 void setShouldRefreshActivityForCameraCompat(boolean enabled) { 247 doReturn(enabled).when(mActivityStack.top().mAppCompatController.getCameraOverrides()) 248 .shouldRefreshActivityForCameraCompat(); 249 } 250 setIgnoreOrientationRequest(boolean enabled)251 void setIgnoreOrientationRequest(boolean enabled) { 252 mDisplayContent.setIgnoreOrientationRequest(enabled); 253 } 254 setTopActivityOrganizedTask()255 void setTopActivityOrganizedTask() { 256 doReturn(mTaskStack.top()).when(mActivityStack.top()).getOrganizedTask(); 257 } 258 setTopTaskInMultiWindowMode(boolean inMultiWindowMode)259 void setTopTaskInMultiWindowMode(boolean inMultiWindowMode) { 260 doReturn(inMultiWindowMode).when(mTaskStack.top()).inMultiWindowMode(); 261 } 262 setTopActivityAsEmbedded(boolean embedded)263 void setTopActivityAsEmbedded(boolean embedded) { 264 doReturn(embedded).when(mActivityStack.top()).isEmbedded(); 265 } 266 setTopActivityHasLetterboxedBounds(boolean letterboxed)267 void setTopActivityHasLetterboxedBounds(boolean letterboxed) { 268 doReturn(letterboxed).when(mActivityStack.top()).areBoundsLetterboxed(); 269 } 270 setTopActivityVisible(boolean isVisible)271 void setTopActivityVisible(boolean isVisible) { 272 doReturn(isVisible).when(mActivityStack.top()).isVisible(); 273 } 274 setTopActivityVisibleRequested(boolean isVisibleRequested)275 void setTopActivityVisibleRequested(boolean isVisibleRequested) { 276 doReturn(isVisibleRequested).when(mActivityStack.top()).isVisibleRequested(); 277 } 278 setTopActivityFillsParent(boolean fillsParent)279 void setTopActivityFillsParent(boolean fillsParent) { 280 doReturn(fillsParent).when(mActivityStack.top()).fillsParent(); 281 } 282 setTopActivityInMultiWindowMode(boolean multiWindowMode)283 void setTopActivityInMultiWindowMode(boolean multiWindowMode) { 284 doReturn(multiWindowMode).when(mActivityStack.top()).inMultiWindowMode(); 285 if (multiWindowMode) { 286 doReturn(WINDOWING_MODE_MULTI_WINDOW).when(mActivityStack.top()).getWindowingMode(); 287 } 288 } 289 setTopActivityInPinnedWindowingMode(boolean pinnedWindowingMode)290 void setTopActivityInPinnedWindowingMode(boolean pinnedWindowingMode) { 291 doReturn(pinnedWindowingMode).when(mActivityStack.top()).inPinnedWindowingMode(); 292 if (pinnedWindowingMode) { 293 doReturn(WINDOWING_MODE_PINNED).when(mActivityStack.top()).getWindowingMode(); 294 } 295 } 296 setTopActivityInFreeformWindowingMode(boolean freeformWindowingMode)297 void setTopActivityInFreeformWindowingMode(boolean freeformWindowingMode) { 298 doReturn(freeformWindowingMode).when(mActivityStack.top()).inFreeformWindowingMode(); 299 if (freeformWindowingMode) { 300 doReturn(WINDOWING_MODE_FREEFORM).when(mActivityStack.top()).getWindowingMode(); 301 } 302 } 303 setFixedRotationTransformDisplayBounds(@ullable Rect bounds)304 void setFixedRotationTransformDisplayBounds(@Nullable Rect bounds) { 305 doReturn(bounds).when(mActivityStack.top()).getFixedRotationTransformDisplayBounds(); 306 } 307 destroyTopActivity()308 void destroyTopActivity() { 309 mActivityStack.top().removeImmediately(); 310 } 311 destroyActivity(int fromTop)312 void destroyActivity(int fromTop) { 313 mActivityStack.applyTo(/* fromTop */ fromTop, ActivityRecord::removeImmediately); 314 } 315 createNewDisplay()316 void createNewDisplay() { 317 mDisplayContent = new TestDisplayContent.Builder(mAtm, mDisplayWidth, mDisplayHeight) 318 .build(); 319 onPostDisplayContentCreation(mDisplayContent); 320 } 321 createNewTask()322 void createNewTask() { 323 final Task newTask = new WindowTestsBase.TaskBuilder(mSupervisor) 324 .setDisplay(mDisplayContent).build(); 325 mTaskStack.push(newTask); 326 } 327 createNewTaskWithBaseActivity()328 void createNewTaskWithBaseActivity() { 329 final Task newTask = new WindowTestsBase.TaskBuilder(mSupervisor) 330 .setCreateActivity(true) 331 // Respect "@ChangeId" according to test package's target sdk. 332 .setPackage(mAtm.mContext.getPackageName()) 333 .setDisplay(mDisplayContent).build(); 334 mTaskStack.push(newTask); 335 pushActivity(newTask.getTopNonFinishingActivity()); 336 } 337 attachTopActivityToTask()338 void attachTopActivityToTask() { 339 mTaskStack.top().addChild(mActivityStack.top()); 340 } 341 applyToTopActivity(Consumer<ActivityRecord> consumer)342 void applyToTopActivity(Consumer<ActivityRecord> consumer) { 343 consumer.accept(mActivityStack.top()); 344 } 345 applyToActivity(int fromTop, @NonNull Consumer<ActivityRecord> consumer)346 void applyToActivity(int fromTop, @NonNull Consumer<ActivityRecord> consumer) { 347 mActivityStack.applyTo(fromTop, consumer); 348 } 349 applyToAllActivities(@onNull Consumer<ActivityRecord> consumer)350 void applyToAllActivities(@NonNull Consumer<ActivityRecord> consumer) { 351 mActivityStack.applyToAll(consumer); 352 } 353 rotateDisplayForTopActivity(@urface.Rotation int rotation)354 void rotateDisplayForTopActivity(@Surface.Rotation int rotation) { 355 rotateDisplay(mActivityStack.top().mDisplayContent, rotation); 356 } 357 configureTopActivityFoldablePosture(boolean isHalfFolded, boolean isTabletop)358 void configureTopActivityFoldablePosture(boolean isHalfFolded, boolean isTabletop) { 359 mActivityStack.applyToTop((topActivity) -> { 360 final DisplayRotation r = topActivity.mDisplayContent.getDisplayRotation(); 361 doReturn(isHalfFolded).when(r).isDisplaySeparatingHinge(); 362 doReturn(false).when(r) 363 .isDeviceInPosture(any(DeviceStateController.DeviceState.class), 364 anyBoolean()); 365 if (isHalfFolded) { 366 doReturn(true).when(r) 367 .isDeviceInPosture(DeviceStateController.DeviceState.HALF_FOLDED, 368 isTabletop); 369 } 370 topActivity.recomputeConfiguration(); 371 }); 372 } 373 rotateDisplay(@urface.Rotation DisplayContent display, int rotation)374 private static void rotateDisplay(@Surface.Rotation DisplayContent display, int rotation) { 375 final Configuration c = new Configuration(); 376 display.getDisplayRotation().setRotation(rotation); 377 display.computeScreenConfiguration(c); 378 display.onRequestedOverrideConfigurationChanged(c); 379 } 380 assertTrueOnActivity(int fromTop, Predicate<ActivityRecord> predicate)381 void assertTrueOnActivity(int fromTop, Predicate<ActivityRecord> predicate) { 382 mActivityStack.applyTo(fromTop, (activity) -> { 383 Assert.assertTrue(predicate.test(activity)); 384 }); 385 } 386 assertFalseOnTopActivity(Predicate<ActivityRecord> predicate)387 void assertFalseOnTopActivity(Predicate<ActivityRecord> predicate) { 388 Assert.assertFalse(predicate.test(mActivityStack.top())); 389 } 390 assertFalseOnActivity(int fromTop, Predicate<ActivityRecord> predicate)391 void assertFalseOnActivity(int fromTop, Predicate<ActivityRecord> predicate) { 392 mActivityStack.applyTo(fromTop, (activity) -> { 393 Assert.assertFalse(predicate.test(activity)); 394 }); 395 } 396 assertNotNullOnTopActivity(Function<ActivityRecord, Object> getter)397 void assertNotNullOnTopActivity(Function<ActivityRecord, Object> getter) { 398 Assert.assertNotNull(getter.apply(mActivityStack.top())); 399 } 400 assertNullOnTopActivity(Function<ActivityRecord, Object> getter)401 void assertNullOnTopActivity(Function<ActivityRecord, Object> getter) { 402 Assert.assertNull(getter.apply(mActivityStack.top())); 403 } 404 checkTopActivityRecomputedConfiguration()405 void checkTopActivityRecomputedConfiguration() { 406 verify(mActivityStack.top()).recomputeConfiguration(); 407 } 408 checkTopActivityConfigOrientation(@onfiguration.Orientation int orientation)409 void checkTopActivityConfigOrientation(@Configuration.Orientation int orientation) { 410 Assert.assertEquals(orientation, mActivityStack.top() 411 .getRequestedConfigurationOrientation()); 412 } 413 checkTopActivityAspectRatios(float minAspectRatio, float maxAspectRatio)414 void checkTopActivityAspectRatios(float minAspectRatio, float maxAspectRatio) { 415 final ActivityRecord topActivity = mActivityStack.top(); 416 Assert.assertEquals(minAspectRatio, topActivity.getMinAspectRatio(), 417 DELTA_ASPECT_RATIO_TOLERANCE); 418 Assert.assertEquals(maxAspectRatio, topActivity.getMaxAspectRatio(), 419 DELTA_ASPECT_RATIO_TOLERANCE); 420 } 421 checkTopActivityInSizeCompatMode(boolean inScm)422 void checkTopActivityInSizeCompatMode(boolean inScm) { 423 final ActivityRecord topActivity = mActivityStack.top(); 424 Assert.assertEquals(inScm, topActivity.inSizeCompatMode()); 425 Assert.assertNotEquals(1f, topActivity.getCompatScale(), COMPAT_SCALE_TOLERANCE); 426 } 427 launchActivity(float minAspectRatio, float maxAspectRatio, @ActivityInfo.ScreenOrientation int orientation, boolean transparent, boolean withComponent, boolean addToTask)428 void launchActivity(float minAspectRatio, float maxAspectRatio, 429 @ActivityInfo.ScreenOrientation int orientation, boolean transparent, 430 boolean withComponent, boolean addToTask) { 431 final WindowTestsBase.ActivityBuilder 432 activityBuilder = new WindowTestsBase.ActivityBuilder(mAtm) 433 .setScreenOrientation(orientation) 434 .setLaunchedFromUid(0); 435 if (transparent) { 436 activityBuilder.setActivityTheme(android.R.style.Theme_Translucent); 437 } 438 if (withComponent) { 439 // Set the component to be that of the test class in order 440 // to enable compat changes 441 activityBuilder.setComponent(ComponentName.createRelative(mAtm.mContext, 442 TEST_COMPONENT_NAME)); 443 } 444 if (minAspectRatio >= 0) { 445 activityBuilder.setMinAspectRatio(minAspectRatio); 446 } 447 if (maxAspectRatio >= 0) { 448 activityBuilder.setMaxAspectRatio(maxAspectRatio); 449 } 450 final ActivityRecord newActivity = activityBuilder.build(); 451 if (addToTask) { 452 if (mTaskStack.isEmpty()) { 453 createNewTask(); 454 } 455 mTaskStack.top().addChild(newActivity); 456 } 457 pushActivity(newActivity); 458 } 459 460 /** 461 * Specific Robots can override this method to add operation to run on a newly created 462 * {@link ActivityRecord}. Common case is to invoke spyOn(). 463 * 464 * @param activity The newly created {@link ActivityRecord}. 465 */ 466 @CallSuper onPostActivityCreation(@onNull ActivityRecord activity)467 void onPostActivityCreation(@NonNull ActivityRecord activity) { 468 if (mOnPostActivityCreation != null) { 469 mOnPostActivityCreation.accept(activity); 470 } 471 } 472 473 /** 474 * Specific Robots can override this method to add operation to run on a newly created 475 * {@link DisplayContent}. Common case is to invoke spyOn(). 476 * 477 * @param displayContent The newly created {@link DisplayContent}. 478 */ 479 @CallSuper onPostDisplayContentCreation(@onNull DisplayContent displayContent)480 void onPostDisplayContentCreation(@NonNull DisplayContent displayContent) { 481 spyOn(mDisplayContent); 482 if (mOnPostDisplayContentCreation != null) { 483 mOnPostDisplayContentCreation.accept(mDisplayContent); 484 } 485 } 486 createActivityWithComponentInNewTask(boolean inNewTask, boolean inNewDisplay)487 private void createActivityWithComponentInNewTask(boolean inNewTask, boolean inNewDisplay) { 488 if (inNewDisplay) { 489 createNewDisplay(); 490 } 491 if (inNewTask) { 492 createNewTask(); 493 } 494 final WindowTestsBase.ActivityBuilder activityBuilder = 495 new WindowTestsBase.ActivityBuilder(mAtm).setOnTop(true) 496 // Set the component to be that of the test class in order 497 // to enable compat changes 498 .setComponent(ComponentName.createRelative(mAtm.mContext, TEST_COMPONENT_NAME)); 499 if (!mTaskStack.isEmpty()) { 500 // We put the Activity in the current task if any. 501 activityBuilder.setTask(mTaskStack.top()); 502 } 503 pushActivity(activityBuilder.build()); 504 } 505 506 /** 507 * Setups activity with restriction on its bounds, such as maxAspect, minAspect, 508 * fixed orientation, and/or whether it is resizable. 509 */ prepareLimitedBounds(ActivityRecord activity, float minAspect, float maxAspect, @ActivityInfo.ScreenOrientation int screenOrientation, boolean isUnresizable)510 private void prepareLimitedBounds(ActivityRecord activity, float minAspect, float maxAspect, 511 @ActivityInfo.ScreenOrientation int screenOrientation, boolean isUnresizable) { 512 activity.info.resizeMode = isUnresizable 513 ? RESIZE_MODE_UNRESIZEABLE 514 : RESIZE_MODE_RESIZEABLE; 515 final Task task = activity.getTask(); 516 if (task != null) { 517 // Update the Task resize value as activity will follow the task. 518 task.mResizeMode = activity.info.resizeMode; 519 task.getRootActivity().info.resizeMode = activity.info.resizeMode; 520 } 521 activity.setVisibleRequested(true); 522 if (maxAspect >= 0) { 523 activity.info.setMaxAspectRatio(maxAspect); 524 } 525 if (minAspect >= 0) { 526 activity.info.setMinAspectRatio(minAspect); 527 } 528 if (screenOrientation != SCREEN_ORIENTATION_UNSPECIFIED) { 529 activity.info.screenOrientation = screenOrientation; 530 activity.setRequestedOrientation(screenOrientation); 531 } 532 // Make sure to use the provided configuration to construct the size compat fields. 533 activity.mAppCompatController.getSizeCompatModePolicy().clearSizeCompatMode(); 534 activity.ensureActivityConfiguration(); 535 // Make sure the display configuration reflects the change of activity. 536 if (activity.mDisplayContent.updateOrientation()) { 537 activity.mDisplayContent.sendNewConfiguration(); 538 } 539 } 540 getTopDisplayRotationCompatPolicy()541 private DisplayRotationCompatPolicy getTopDisplayRotationCompatPolicy() { 542 return mActivityStack.top().mDisplayContent.mAppCompatCameraPolicy 543 .mDisplayRotationCompatPolicy; 544 } 545 getTopCameraCompatFreeformPolicy()546 private CameraCompatFreeformPolicy getTopCameraCompatFreeformPolicy() { 547 return mActivityStack.top().mDisplayContent.mAppCompatCameraPolicy 548 .mCameraCompatFreeformPolicy; 549 } 550 551 // We add the activity to the stack and spyOn() on its properties. pushActivity(@onNull ActivityRecord activity)552 private void pushActivity(@NonNull ActivityRecord activity) { 553 mActivityStack.push(activity); 554 onPostActivityCreation(activity); 555 } 556 } 557