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.WINDOWING_MODE_FREEFORM; 20 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN; 21 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED; 22 import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS; 23 import static android.view.WindowManager.LayoutParams.FLAG_SCALED; 24 import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER; 25 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; 26 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; 27 import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; 28 import static android.view.WindowManager.TRANSIT_CLOSE; 29 import static android.view.WindowManager.TRANSIT_OPEN; 30 31 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; 32 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; 33 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; 34 import static com.android.dx.mockito.inline.extended.ExtendedMockito.when; 35 36 import static com.google.common.truth.Truth.assertThat; 37 38 import static org.junit.Assert.assertEquals; 39 import static org.junit.Assert.assertFalse; 40 import static org.junit.Assert.assertNotEquals; 41 import static org.junit.Assert.assertTrue; 42 import static org.mockito.ArgumentMatchers.anyBoolean; 43 import static org.mockito.ArgumentMatchers.anyFloat; 44 import static org.mockito.ArgumentMatchers.anyInt; 45 import static org.mockito.ArgumentMatchers.eq; 46 import static org.mockito.Mockito.verify; 47 48 import android.content.pm.ActivityInfo; 49 import android.content.res.Configuration; 50 import android.content.res.Resources; 51 import android.graphics.Rect; 52 import android.os.IBinder; 53 import android.os.RemoteException; 54 import android.platform.test.annotations.Presubmit; 55 import android.view.DisplayCutout; 56 import android.view.DisplayInfo; 57 import android.view.DisplayShape; 58 import android.view.Gravity; 59 import android.view.InsetsState; 60 import android.view.PrivacyIndicatorBounds; 61 import android.view.RoundedCorners; 62 import android.view.Surface; 63 import android.view.SurfaceControl; 64 import android.view.WindowManager; 65 66 import androidx.test.filters.SmallTest; 67 68 import org.junit.Before; 69 import org.junit.Test; 70 import org.junit.runner.RunWith; 71 72 import java.util.List; 73 74 /** 75 * Tests for the {@link WallpaperController} class. 76 * 77 * Build/Install/Run: 78 * atest WmTests:WallpaperControllerTests 79 */ 80 @SmallTest 81 @Presubmit 82 @RunWith(WindowTestRunner.class) 83 public class WallpaperControllerTests extends WindowTestsBase { 84 private static final int INITIAL_WIDTH = 600; 85 private static final int INITIAL_HEIGHT = 900; 86 private static final int SECOND_WIDTH = 300; 87 88 @Before setup()89 public void setup() { 90 Resources resources = mWm.mContext.getResources(); 91 spyOn(resources); 92 doReturn(false).when(resources).getBoolean( 93 com.android.internal.R.bool.config_offsetWallpaperToCenterOfLargestDisplay); 94 } 95 96 @Test testWallpaperScreenshot()97 public void testWallpaperScreenshot() { 98 WindowSurfaceController windowSurfaceController = mock(WindowSurfaceController.class); 99 100 // No wallpaper 101 final DisplayContent dc = createNewDisplay(); 102 assertFalse(dc.mWallpaperController.canScreenshotWallpaper()); 103 104 // No wallpaper WSA Surface 105 final WindowState wallpaperWindow = createWallpaperWindow(dc); 106 assertFalse(dc.mWallpaperController.canScreenshotWallpaper()); 107 108 // Wallpaper with not visible WSA surface. 109 wallpaperWindow.mWinAnimator.mSurfaceController = windowSurfaceController; 110 wallpaperWindow.mWinAnimator.mLastAlpha = 1; 111 assertFalse(dc.mWallpaperController.canScreenshotWallpaper()); 112 113 when(windowSurfaceController.getShown()).thenReturn(true); 114 115 // Wallpaper with WSA alpha set to 0. 116 wallpaperWindow.mWinAnimator.mLastAlpha = 0; 117 assertFalse(dc.mWallpaperController.canScreenshotWallpaper()); 118 119 // Wallpaper window with WSA Surface 120 wallpaperWindow.mWinAnimator.mLastAlpha = 1; 121 assertTrue(dc.mWallpaperController.canScreenshotWallpaper()); 122 } 123 124 @Test testWallpaperSizeWithFixedTransform()125 public void testWallpaperSizeWithFixedTransform() { 126 // No wallpaper 127 final DisplayContent dc = mDisplayContent; 128 if (dc.mBaseDisplayHeight == dc.mBaseDisplayWidth) { 129 // Make sure the size is different when changing orientation. 130 resizeDisplay(dc, 500, 1000); 131 } 132 133 // No wallpaper WSA Surface 134 final WindowState wallpaperWindow = createWallpaperWindow(dc); 135 136 WindowManager.LayoutParams attrs = wallpaperWindow.getAttrs(); 137 Rect bounds = dc.getBounds(); 138 int displayWidth = dc.getBounds().width(); 139 int displayHeight = dc.getBounds().height(); 140 141 // Use a wallpaper with a different ratio than the display 142 int wallpaperWidth = bounds.width() * 2; 143 int wallpaperHeight = (int) (bounds.height() * 1.10); 144 145 // Simulate what would be done on the client's side 146 final float layoutScale = Math.max( 147 displayWidth / (float) wallpaperWidth, displayHeight / (float) wallpaperHeight); 148 attrs.width = (int) (wallpaperWidth * layoutScale + .5f); 149 attrs.height = (int) (wallpaperHeight * layoutScale + .5f); 150 attrs.flags |= FLAG_LAYOUT_NO_LIMITS | FLAG_SCALED; 151 attrs.gravity = Gravity.TOP | Gravity.LEFT; 152 wallpaperWindow.getWindowFrames().mParentFrame.set(dc.getBounds()); 153 154 dc.getDisplayPolicy().layoutWindowLw(wallpaperWindow, null, dc.mDisplayFrames); 155 156 assertEquals(Configuration.ORIENTATION_PORTRAIT, dc.getConfiguration().orientation); 157 int expectedWidth = (int) (wallpaperWidth * layoutScale + .5f); 158 159 // Check that the wallpaper is correctly scaled 160 assertEquals(expectedWidth, wallpaperWindow.getFrame().width()); 161 assertEquals(displayHeight, wallpaperWindow.getFrame().height()); 162 Rect portraitFrame = wallpaperWindow.getFrame(); 163 164 // Rotate the display 165 dc.getDisplayRotation().updateOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE, true); 166 dc.sendNewConfiguration(); 167 168 // Apply the fixed transform 169 Configuration config = new Configuration(); 170 final DisplayInfo info = dc.computeScreenConfiguration(config, Surface.ROTATION_0); 171 final DisplayCutout cutout = dc.calculateDisplayCutoutForRotation(Surface.ROTATION_0); 172 final DisplayFrames displayFrames = new DisplayFrames(new InsetsState(), 173 info, cutout, RoundedCorners.NO_ROUNDED_CORNERS, new PrivacyIndicatorBounds(), 174 DisplayShape.NONE); 175 wallpaperWindow.mToken.applyFixedRotationTransform(info, displayFrames, config); 176 177 // Check that the wallpaper has the same frame in landscape than in portrait 178 assertEquals(Configuration.ORIENTATION_LANDSCAPE, dc.getConfiguration().orientation); 179 assertEquals(portraitFrame, wallpaperWindow.getFrame()); 180 } 181 182 @Test testWallpaperZoom()183 public void testWallpaperZoom() throws RemoteException { 184 final DisplayContent dc = mWm.mRoot.getDefaultDisplay(); 185 final WindowState wallpaperWindow = createWallpaperWindow(dc); 186 wallpaperWindow.getAttrs().privateFlags |= 187 WindowManager.LayoutParams.PRIVATE_FLAG_WANTS_OFFSET_NOTIFICATIONS; 188 189 final WindowState homeWindow = createWallpaperTargetWindow(dc); 190 191 spyOn(dc.mWallpaperController); 192 doReturn(true).when(dc.mWallpaperController).isWallpaperVisible(); 193 194 dc.mWallpaperController.adjustWallpaperWindows(); 195 196 spyOn(wallpaperWindow.mClient); 197 198 float zoom = .5f; 199 dc.mWallpaperController.setWallpaperZoomOut(homeWindow, zoom); 200 assertEquals(zoom, wallpaperWindow.mWallpaperZoomOut, .01f); 201 verify(wallpaperWindow.mClient).dispatchWallpaperOffsets(anyFloat(), anyFloat(), anyFloat(), 202 anyFloat(), eq(zoom), anyBoolean()); 203 } 204 205 @Test testWallpaperZoom_shouldNotScaleWallpaper()206 public void testWallpaperZoom_shouldNotScaleWallpaper() throws RemoteException { 207 final DisplayContent dc = mWm.mRoot.getDefaultDisplay(); 208 final WindowState wallpaperWindow = createWallpaperWindow(dc); 209 wallpaperWindow.getAttrs().privateFlags |= 210 WindowManager.LayoutParams.PRIVATE_FLAG_WANTS_OFFSET_NOTIFICATIONS; 211 212 final WindowState homeWindow = createWallpaperTargetWindow(dc); 213 214 spyOn(dc.mWallpaperController); 215 doReturn(true).when(dc.mWallpaperController).isWallpaperVisible(); 216 217 dc.mWallpaperController.adjustWallpaperWindows(); 218 219 spyOn(wallpaperWindow.mClient); 220 221 float newZoom = .5f; 222 wallpaperWindow.mShouldScaleWallpaper = false; 223 // Set zoom, and make sure the window animator scale didn't actually change, but the zoom 224 // value did, and we do dispatch the zoom to the wallpaper service 225 dc.mWallpaperController.setWallpaperZoomOut(homeWindow, newZoom); 226 assertEquals(newZoom, wallpaperWindow.mWallpaperZoomOut, .01f); 227 assertEquals(1f, wallpaperWindow.mWallpaperScale, .01f); 228 verify(wallpaperWindow.mClient).dispatchWallpaperOffsets(anyFloat(), anyFloat(), anyFloat(), 229 anyFloat(), eq(newZoom), anyBoolean()); 230 } 231 232 @Test testWallpaperZoom_multipleCallers()233 public void testWallpaperZoom_multipleCallers() { 234 final DisplayContent dc = mWm.mRoot.getDefaultDisplay(); 235 final WindowState wallpaperWindow = createWallpaperWindow(dc); 236 wallpaperWindow.getAttrs().privateFlags |= 237 WindowManager.LayoutParams.PRIVATE_FLAG_WANTS_OFFSET_NOTIFICATIONS; 238 239 240 spyOn(dc.mWallpaperController); 241 doReturn(true).when(dc.mWallpaperController).isWallpaperVisible(); 242 243 final WindowState homeWindow = createWallpaperTargetWindow(dc); 244 245 WindowState otherWindow = createWindow(null /* parent */, TYPE_APPLICATION, dc, 246 "otherWindow"); 247 248 dc.mWallpaperController.adjustWallpaperWindows(); 249 250 spyOn(wallpaperWindow.mClient); 251 252 // Set zoom from 2 windows 253 float homeWindowInitialZoom = .5f; 254 float otherWindowInitialZoom = .7f; 255 dc.mWallpaperController.setWallpaperZoomOut(homeWindow, homeWindowInitialZoom); 256 dc.mWallpaperController.setWallpaperZoomOut(otherWindow, otherWindowInitialZoom); 257 // Make sure the largest one wins 258 assertEquals(otherWindowInitialZoom, wallpaperWindow.mWallpaperZoomOut, .01f); 259 260 // Change zoom to a larger zoom from homeWindow 261 float homeWindowZoom2 = .8f; 262 dc.mWallpaperController.setWallpaperZoomOut(homeWindow, homeWindowZoom2); 263 // New zoom should be current 264 assertEquals(homeWindowZoom2, wallpaperWindow.mWallpaperZoomOut, .01f); 265 266 // Set homeWindow zoom to a lower zoom, but keep the one from otherWindow 267 dc.mWallpaperController.setWallpaperZoomOut(homeWindow, homeWindowInitialZoom); 268 269 // Zoom from otherWindow should be the current. 270 assertEquals(otherWindowInitialZoom, wallpaperWindow.mWallpaperZoomOut, .01f); 271 } 272 273 @Test testUpdateWallpaperTarget()274 public void testUpdateWallpaperTarget() { 275 final DisplayContent dc = mDisplayContent; 276 final WindowState homeWin = createWallpaperTargetWindow(dc); 277 final WindowState appWin = createWindow(null, TYPE_BASE_APPLICATION, "app"); 278 final RecentsAnimationController recentsController = mock(RecentsAnimationController.class); 279 doReturn(true).when(recentsController).isWallpaperVisible(eq(appWin)); 280 mWm.setRecentsAnimationController(recentsController); 281 282 dc.mWallpaperController.adjustWallpaperWindows(); 283 assertEquals(appWin, dc.mWallpaperController.getWallpaperTarget()); 284 // The wallpaper target is gone, so it should adjust to the next target. 285 appWin.removeImmediately(); 286 assertEquals(homeWin, dc.mWallpaperController.getWallpaperTarget()); 287 } 288 289 @Test testShowWhenLockedWallpaperTarget()290 public void testShowWhenLockedWallpaperTarget() { 291 final WindowState wallpaperWindow = createWallpaperWindow(mDisplayContent); 292 wallpaperWindow.mToken.asWallpaperToken().setShowWhenLocked(true); 293 final WindowState behind = createWindow(null, TYPE_BASE_APPLICATION, "behind"); 294 final WindowState topTranslucent = createWindow(null, TYPE_BASE_APPLICATION, 295 "topTranslucent"); 296 behind.mAttrs.width = behind.mAttrs.height = topTranslucent.mAttrs.width = 297 topTranslucent.mAttrs.height = WindowManager.LayoutParams.MATCH_PARENT; 298 topTranslucent.mAttrs.flags |= WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED; 299 doReturn(true).when(behind.mActivityRecord).fillsParent(); 300 doReturn(false).when(topTranslucent.mActivityRecord).fillsParent(); 301 302 spyOn(mWm.mPolicy); 303 doReturn(true).when(mWm.mPolicy).isKeyguardLocked(); 304 doReturn(true).when(mWm.mPolicy).isKeyguardOccluded(); 305 mDisplayContent.mWallpaperController.adjustWallpaperWindows(); 306 // Wallpaper is visible because the show-when-locked activity is translucent. 307 assertTrue(mDisplayContent.mWallpaperController.isWallpaperTarget(wallpaperWindow)); 308 309 behind.mActivityRecord.setShowWhenLocked(true); 310 mDisplayContent.mWallpaperController.adjustWallpaperWindows(); 311 // Wallpaper is invisible because the lowest show-when-locked activity is opaque. 312 assertTrue(mDisplayContent.mWallpaperController.isWallpaperTarget(null)); 313 } 314 315 /** 316 * Tests that the windowing mode of the wallpaper window must always be fullscreen. 317 */ 318 @Test testWallpaperTokenWindowingMode()319 public void testWallpaperTokenWindowingMode() { 320 final DisplayContent dc = mWm.mRoot.getDefaultDisplay(); 321 final WallpaperWindowToken token = new WallpaperWindowToken(mWm, mock(IBinder.class), 322 true, dc, true /* ownerCanManageAppTokens */); 323 324 // The wallpaper should have requested override fullscreen windowing mode, so the 325 // configuration (windowing mode) propagation from display won't change it. 326 dc.setWindowingMode(WINDOWING_MODE_FREEFORM); 327 assertEquals(WINDOWING_MODE_FULLSCREEN, token.getWindowingMode()); 328 dc.setWindowingMode(WINDOWING_MODE_UNDEFINED); 329 assertEquals(WINDOWING_MODE_FULLSCREEN, token.getWindowingMode()); 330 } 331 332 @Test testFixedRotationRecentsAnimatingTask()333 public void testFixedRotationRecentsAnimatingTask() { 334 final WindowState wallpaperWindow = createWallpaperWindow(mDisplayContent); 335 final WallpaperWindowToken wallpaperToken = wallpaperWindow.mToken.asWallpaperToken(); 336 final WindowState appWin = createWindow(null, TYPE_BASE_APPLICATION, "app"); 337 makeWindowVisible(appWin); 338 final ActivityRecord r = appWin.mActivityRecord; 339 final RecentsAnimationController recentsController = mock(RecentsAnimationController.class); 340 doReturn(true).when(recentsController).isWallpaperVisible(eq(appWin)); 341 mWm.setRecentsAnimationController(recentsController); 342 343 r.applyFixedRotationTransform(mDisplayContent.getDisplayInfo(), 344 mDisplayContent.mDisplayFrames, mDisplayContent.getConfiguration()); 345 // Invisible requested activity should not share its rotation transform. 346 r.setVisibleRequested(false); 347 mDisplayContent.mWallpaperController.adjustWallpaperWindows(); 348 assertFalse(wallpaperToken.hasFixedRotationTransform()); 349 350 // Wallpaper should link the transform of its target. 351 r.setVisibleRequested(true); 352 mDisplayContent.mWallpaperController.adjustWallpaperWindows(); 353 assertEquals(appWin, mDisplayContent.mWallpaperController.getWallpaperTarget()); 354 assertTrue(r.hasFixedRotationTransform()); 355 assertTrue(wallpaperToken.hasFixedRotationTransform()); 356 357 // The case with shell transition. 358 registerTestTransitionPlayer(); 359 final Transition t = r.mTransitionController.createTransition(TRANSIT_OPEN); 360 final ActivityRecord recents = mock(ActivityRecord.class); 361 t.collect(r.getTask()); 362 r.mTransitionController.setTransientLaunch(recents, r.getTask()); 363 // The activity in restore-below task should not be the target if keyguard is not locked. 364 mDisplayContent.mWallpaperController.adjustWallpaperWindows(); 365 assertNotEquals(appWin, mDisplayContent.mWallpaperController.getWallpaperTarget()); 366 // The activity in restore-below task should be the target if keyguard is occluded. 367 doReturn(true).when(mDisplayContent).isKeyguardLocked(); 368 mDisplayContent.mWallpaperController.adjustWallpaperWindows(); 369 assertEquals(appWin, mDisplayContent.mWallpaperController.getWallpaperTarget()); 370 } 371 372 @Test testWallpaperReportConfigChange()373 public void testWallpaperReportConfigChange() { 374 final WindowState wallpaperWindow = createWallpaperWindow(mDisplayContent); 375 createWallpaperTargetWindow(mDisplayContent); 376 final WallpaperWindowToken wallpaperToken = wallpaperWindow.mToken.asWallpaperToken(); 377 makeWindowVisible(wallpaperWindow); 378 wallpaperWindow.mLayoutSeq = mDisplayContent.mLayoutSeq; 379 // Assume the token was invisible and the latest config was reported. 380 wallpaperToken.commitVisibility(false); 381 makeLastConfigReportedToClient(wallpaperWindow, false /* visible */); 382 assertTrue(wallpaperWindow.isLastConfigReportedToClient()); 383 384 final Rect bounds = wallpaperToken.getBounds(); 385 wallpaperToken.setBounds(new Rect(0, 0, bounds.width() / 2, bounds.height() / 2)); 386 assertFalse(wallpaperWindow.isLastConfigReportedToClient()); 387 // If there is a pending config change when changing to visible, it should tell the client 388 // to redraw by WindowState#reportResized. 389 wallpaperToken.commitVisibility(true); 390 waitUntilHandlersIdle(); 391 assertTrue(wallpaperWindow.isLastConfigReportedToClient()); 392 } 393 394 @Test testWallpaperTokenVisibility()395 public void testWallpaperTokenVisibility() { 396 final DisplayContent dc = mWm.mRoot.getDefaultDisplay(); 397 final WindowState wallpaperWindow = createWallpaperWindow(dc); 398 final WallpaperWindowToken token = wallpaperWindow.mToken.asWallpaperToken(); 399 wallpaperWindow.setHasSurface(true); 400 401 // Set-up mock shell transitions 402 registerTestTransitionPlayer(); 403 404 Transition transit = 405 mWm.mAtmService.getTransitionController().createTransition(TRANSIT_OPEN); 406 407 // wallpaper windows are immediately visible when set to visible even during a transition 408 token.setVisibility(true); 409 assertTrue(wallpaperWindow.isVisible()); 410 assertTrue(token.isVisibleRequested()); 411 assertTrue(token.isVisible()); 412 transit.abort(); 413 414 // In a transition, setting invisible should ONLY set requestedVisible false; otherwise 415 // wallpaper should remain "visible" until transition is over. 416 transit = mWm.mAtmService.getTransitionController().createTransition(TRANSIT_CLOSE); 417 transit.start(); 418 token.setVisibility(false); 419 assertTrue(wallpaperWindow.isVisible()); 420 assertFalse(token.isVisibleRequested()); 421 assertTrue(token.isVisible()); 422 423 final SurfaceControl.Transaction t = mock(SurfaceControl.Transaction.class); 424 token.finishSync(t, token.getSyncGroup(), false /* cancel */); 425 transit.onTransactionReady(transit.getSyncId(), t); 426 dc.mTransitionController.finishTransition(transit); 427 assertFalse(wallpaperWindow.isVisible()); 428 assertFalse(token.isVisible()); 429 } 430 prepareSmallerSecondDisplay(DisplayContent dc, int width, int height)431 private static void prepareSmallerSecondDisplay(DisplayContent dc, int width, int height) { 432 spyOn(dc.mWmService); 433 DisplayInfo firstDisplay = dc.getDisplayInfo(); 434 DisplayInfo secondDisplay = new DisplayInfo(firstDisplay); 435 // Second display is narrower than first display. 436 secondDisplay.logicalWidth = width; 437 secondDisplay.logicalHeight = height; 438 doReturn(List.of(firstDisplay, secondDisplay)).when( 439 dc.mWmService).getPossibleDisplayInfoLocked(anyInt()); 440 } 441 resizeDisplayAndWallpaper(DisplayContent dc, WindowState wallpaperWindow, int width, int height)442 private static void resizeDisplayAndWallpaper(DisplayContent dc, WindowState wallpaperWindow, 443 int width, int height) { 444 dc.setBounds(0, 0, width, height); 445 dc.updateOrientation(); 446 dc.sendNewConfiguration(); 447 spyOn(wallpaperWindow); 448 doReturn(new Rect(0, 0, width, height)).when(wallpaperWindow).getParentFrame(); 449 } 450 451 @Test testUpdateWallpaperOffset_initial_shouldCenterDisabled()452 public void testUpdateWallpaperOffset_initial_shouldCenterDisabled() { 453 final DisplayContent dc = new TestDisplayContent.Builder(mAtm, INITIAL_WIDTH, 454 INITIAL_HEIGHT).build(); 455 dc.mWallpaperController.setShouldOffsetWallpaperCenter(false); 456 prepareSmallerSecondDisplay(dc, SECOND_WIDTH, INITIAL_HEIGHT); 457 final WindowState wallpaperWindow = createWallpaperWindow(dc, INITIAL_WIDTH, 458 INITIAL_HEIGHT); 459 460 dc.mWallpaperController.updateWallpaperOffset(wallpaperWindow, false); 461 462 // Wallpaper centering is disabled, so no offset. 463 assertThat(wallpaperWindow.mXOffset).isEqualTo(0); 464 assertThat(wallpaperWindow.mYOffset).isEqualTo(0); 465 } 466 467 @Test testUpdateWallpaperOffset_initial_shouldCenterEnabled()468 public void testUpdateWallpaperOffset_initial_shouldCenterEnabled() { 469 final DisplayContent dc = new TestDisplayContent.Builder(mAtm, INITIAL_WIDTH, 470 INITIAL_HEIGHT).build(); 471 dc.mWallpaperController.setShouldOffsetWallpaperCenter(true); 472 prepareSmallerSecondDisplay(dc, SECOND_WIDTH, INITIAL_HEIGHT); 473 final WindowState wallpaperWindow = createWallpaperWindow(dc, INITIAL_WIDTH, 474 INITIAL_HEIGHT); 475 476 dc.mWallpaperController.updateWallpaperOffset(wallpaperWindow, false); 477 478 // Wallpaper matches first display, so has no offset. 479 assertThat(wallpaperWindow.mXOffset).isEqualTo(0); 480 assertThat(wallpaperWindow.mYOffset).isEqualTo(0); 481 } 482 483 @Test testUpdateWallpaperOffset_resize_shouldCenterEnabled()484 public void testUpdateWallpaperOffset_resize_shouldCenterEnabled() { 485 final DisplayContent dc = new TestDisplayContent.Builder(mAtm, INITIAL_WIDTH, 486 INITIAL_HEIGHT).build(); 487 dc.mWallpaperController.setShouldOffsetWallpaperCenter(true); 488 prepareSmallerSecondDisplay(dc, SECOND_WIDTH, INITIAL_HEIGHT); 489 final WindowState wallpaperWindow = createWallpaperWindow(dc, INITIAL_WIDTH, 490 INITIAL_HEIGHT); 491 492 dc.mWallpaperController.updateWallpaperOffset(wallpaperWindow, false); 493 494 // Resize display to match second display bounds. 495 resizeDisplayAndWallpaper(dc, wallpaperWindow, SECOND_WIDTH, INITIAL_HEIGHT); 496 497 dc.mWallpaperController.updateWallpaperOffset(wallpaperWindow, false); 498 499 // Wallpaper is 300 wider than second display. 500 assertThat(wallpaperWindow.mXOffset).isEqualTo(-Math.abs(INITIAL_WIDTH - SECOND_WIDTH) / 2); 501 assertThat(wallpaperWindow.mYOffset).isEqualTo(0); 502 } 503 504 @Test testUpdateWallpaperOffset_resize_shouldCenterDisabled()505 public void testUpdateWallpaperOffset_resize_shouldCenterDisabled() { 506 final DisplayContent dc = new TestDisplayContent.Builder(mAtm, INITIAL_WIDTH, 507 INITIAL_HEIGHT).build(); 508 dc.mWallpaperController.setShouldOffsetWallpaperCenter(false); 509 prepareSmallerSecondDisplay(dc, SECOND_WIDTH, INITIAL_HEIGHT); 510 final WindowState wallpaperWindow = createWallpaperWindow(dc, INITIAL_WIDTH, 511 INITIAL_HEIGHT); 512 513 dc.mWallpaperController.updateWallpaperOffset(wallpaperWindow, false); 514 515 // Resize display to match second display bounds. 516 resizeDisplayAndWallpaper(dc, wallpaperWindow, SECOND_WIDTH, INITIAL_HEIGHT); 517 518 dc.mWallpaperController.updateWallpaperOffset(wallpaperWindow, false); 519 520 // Wallpaper is 300 wider than second display, but offset disabled. 521 assertThat(wallpaperWindow.mXOffset).isEqualTo(0); 522 assertThat(wallpaperWindow.mYOffset).isEqualTo(0); 523 } 524 createWallpaperWindow(DisplayContent dc, int width, int height)525 private WindowState createWallpaperWindow(DisplayContent dc, int width, int height) { 526 final WindowState wallpaperWindow = createWallpaperWindow(dc); 527 // Wallpaper is cropped to match first display. 528 wallpaperWindow.getWindowFrames().mParentFrame.set(new Rect(0, 0, width, height)); 529 wallpaperWindow.getWindowFrames().mFrame.set(0, 0, width, height); 530 return wallpaperWindow; 531 } 532 createWallpaperWindow(DisplayContent dc)533 private WindowState createWallpaperWindow(DisplayContent dc) { 534 final WindowToken wallpaperWindowToken = new WallpaperWindowToken(mWm, mock(IBinder.class), 535 true /* explicit */, dc, true /* ownerCanManageAppTokens */); 536 return createWindow(null /* parent */, TYPE_WALLPAPER, wallpaperWindowToken, 537 "wallpaperWindow"); 538 } 539 createWallpaperTargetWindow(DisplayContent dc)540 private WindowState createWallpaperTargetWindow(DisplayContent dc) { 541 final ActivityRecord homeActivity = new ActivityBuilder(mWm.mAtmService) 542 .setTask(dc.getDefaultTaskDisplayArea().getRootHomeTask()) 543 .build(); 544 homeActivity.setVisibility(true); 545 546 WindowState appWindow = createWindow(null /* parent */, TYPE_BASE_APPLICATION, 547 homeActivity, "wallpaperTargetWindow"); 548 appWindow.getAttrs().flags |= FLAG_SHOW_WALLPAPER; 549 appWindow.mHasSurface = true; 550 spyOn(appWindow); 551 doReturn(true).when(appWindow).isDrawFinishedLw(); 552 553 homeActivity.addWindow(appWindow); 554 return appWindow; 555 } 556 } 557