diff options
8 files changed, 281 insertions, 24 deletions
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index e7cae76c60fc..0f66586881c4 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -5066,6 +5066,10 @@ <!-- If true, the wallpaper will scale regardless of the value of shouldZoomOutWallpaper() --> <bool name="config_alwaysScaleWallpaper">false</bool> + <!-- Set to true to offset the wallpaper when using multiple displays so that it's centered + at the same position as in the largest display.--> + <bool name="config_offsetWallpaperToCenterOfLargestDisplay">false</bool> + <!-- Package name that will receive an explicit manifest broadcast for android.os.action.POWER_SAVE_MODE_CHANGED. --> <string name="config_powerSaveModeChangedListenerPackage" translatable="false"></string> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index aa0bae656da6..3f81169005a4 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -4373,6 +4373,10 @@ <!-- The max scale for the wallpaper when it's zoomed in --> <java-symbol type="dimen" name="config_wallpaperMaxScale"/> + <!-- Set to true to offset the wallpaper when using multiple displays so that it's centered + at the same position than in the largest display. --> + <java-symbol type="bool" name="config_offsetWallpaperToCenterOfLargestDisplay" /> + <!-- Set to true to enable the user switcher on the keyguard. --> <java-symbol type="bool" name="config_keyguardUserSwitcher" /> diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 6ee018606d71..39904f94f47f 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -1038,6 +1038,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp mCurrentUniqueDisplayId = display.getUniqueId(); mOffTokenAcquirer = mRootWindowContainer.mDisplayOffTokenAcquirer; mWallpaperController = new WallpaperController(mWmService, this); + mWallpaperController.resetLargestDisplay(display); display.getDisplayInfo(mDisplayInfo); display.getMetrics(mDisplayMetrics); mSystemGestureExclusionLimit = mWmService.mConstants.mSystemGestureExclusionLimitDp @@ -3199,6 +3200,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp mWmService.mAccessibilityController.onDisplayRemoved(mDisplayId); mRootWindowContainer.mTaskSupervisor .getKeyguardController().onDisplayRemoved(mDisplayId); + mWallpaperController.resetLargestDisplay(mDisplay); } finally { mDisplayReady = false; } @@ -5769,6 +5771,8 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp updateRecording(); } } + // Notify wallpaper controller of any size changes. + mWallpaperController.resetLargestDisplay(mDisplay); // Dispatch pending Configuration to WindowContext if the associated display changes to // un-suspended state from suspended. if (isSuspendedState(lastDisplayState) diff --git a/services/core/java/com/android/server/wm/PossibleDisplayInfoMapper.java b/services/core/java/com/android/server/wm/PossibleDisplayInfoMapper.java index 3f6fb622481f..e3a2065838d1 100644 --- a/services/core/java/com/android/server/wm/PossibleDisplayInfoMapper.java +++ b/services/core/java/com/android/server/wm/PossibleDisplayInfoMapper.java @@ -22,6 +22,8 @@ import android.util.Slog; import android.util.SparseArray; import android.view.DisplayInfo; +import java.util.ArrayList; +import java.util.List; import java.util.Set; /** @@ -52,19 +54,21 @@ public class PossibleDisplayInfoMapper { /** - * Returns, for the given displayId, a set of display infos. Set contains each supported device - * state. + * Returns, for the given displayId, a list of unique display infos. List contains each + * supported device state. + * <p>List contents are guaranteed to be unique, but returned as a list rather than a set to + * minimize copies needed to make an iteraable data structure. */ - public Set<DisplayInfo> getPossibleDisplayInfos(int displayId) { + public List<DisplayInfo> getPossibleDisplayInfos(int displayId) { // Update display infos before returning, since any cached values would have been removed // in response to any display event. This model avoids re-computing the cache for every // display change event (which occurs extremely frequently in the normal usage of the // device). updatePossibleDisplayInfos(displayId); if (!mDisplayInfos.contains(displayId)) { - return new ArraySet<>(); + return new ArrayList<>(); } - return Set.copyOf(mDisplayInfos.get(displayId)); + return List.copyOf(mDisplayInfos.get(displayId)); } /** diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java index 6245005606d7..d652b8e0ab32 100644 --- a/services/core/java/com/android/server/wm/WallpaperController.java +++ b/services/core/java/com/android/server/wm/WallpaperController.java @@ -19,6 +19,7 @@ package com.android.server.wm; import static android.app.WallpaperManager.COMMAND_FREEZE; import static android.app.WallpaperManager.COMMAND_UNFREEZE; import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; +import static android.view.Display.DEFAULT_DISPLAY; import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED; import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; @@ -35,7 +36,9 @@ import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; import static com.android.server.wm.WindowManagerService.H.WALLPAPER_DRAW_PENDING_TIMEOUT; +import android.annotation.Nullable; import android.graphics.Bitmap; +import android.graphics.Point; import android.graphics.Rect; import android.os.Bundle; import android.os.Debug; @@ -45,6 +48,8 @@ import android.os.SystemClock; import android.util.ArraySet; import android.util.MathUtils; import android.util.Slog; +import android.view.Display; +import android.view.DisplayInfo; import android.view.SurfaceControl; import android.view.WindowManager; import android.view.animation.Animation; @@ -56,6 +61,7 @@ import com.android.internal.util.ToBooleanFunction; import java.io.PrintWriter; import java.util.ArrayList; +import java.util.List; import java.util.function.Consumer; /** @@ -113,8 +119,12 @@ class WallpaperController { */ private WindowState mTmpTopWallpaper; + @Nullable private Point mLargestDisplaySize = null; + private final FindWallpaperTargetResult mFindResults = new FindWallpaperTargetResult(); + private boolean mShouldOffsetWallpaperCenter; + private final ToBooleanFunction<WindowState> mFindWallpaperTargetFunction = w -> { if ((w.mAttrs.type == TYPE_WALLPAPER)) { if (mFindResults.topWallpaper == null || mFindResults.resetTopWallpaper) { @@ -241,6 +251,38 @@ class WallpaperController { mDisplayContent = displayContent; mMaxWallpaperScale = service.mContext.getResources() .getFloat(com.android.internal.R.dimen.config_wallpaperMaxScale); + mShouldOffsetWallpaperCenter = service.mContext.getResources() + .getBoolean( + com.android.internal.R.bool.config_offsetWallpaperToCenterOfLargestDisplay); + } + + void resetLargestDisplay(Display display) { + if (display != null && display.getType() == Display.TYPE_INTERNAL) { + mLargestDisplaySize = null; + } + } + + @VisibleForTesting void setShouldOffsetWallpaperCenter(boolean shouldOffset) { + mShouldOffsetWallpaperCenter = shouldOffset; + } + + @Nullable private Point findLargestDisplaySize() { + if (!mShouldOffsetWallpaperCenter) { + return null; + } + Point largestDisplaySize = new Point(); + List<DisplayInfo> possibleDisplayInfo = + mService.getPossibleDisplayInfoLocked(DEFAULT_DISPLAY); + for (int i = 0; i < possibleDisplayInfo.size(); i++) { + DisplayInfo displayInfo = possibleDisplayInfo.get(i); + if (displayInfo.type == Display.TYPE_INTERNAL + && Math.max(displayInfo.logicalWidth, displayInfo.logicalHeight) + > Math.max(largestDisplaySize.x, largestDisplaySize.y)) { + largestDisplaySize.set(displayInfo.logicalWidth, + displayInfo.logicalHeight); + } + } + return largestDisplaySize; } WindowState getWallpaperTarget() { @@ -327,24 +369,44 @@ class WallpaperController { } boolean updateWallpaperOffset(WindowState wallpaperWin, boolean sync) { - final Rect bounds = wallpaperWin.getLastReportedBounds(); - final int dw = bounds.width(); - final int dh = bounds.height(); - - int xOffset = 0; - int yOffset = 0; + // Size of the display the wallpaper is rendered on. + final Rect lastWallpaperBounds = wallpaperWin.getLastReportedBounds(); + // Full size of the wallpaper (usually larger than bounds above to parallax scroll when + // swiping through Launcher pages). + final Rect wallpaperFrame = wallpaperWin.getFrame(); + + int newXOffset = 0; + int newYOffset = 0; boolean rawChanged = false; // Set the default wallpaper x-offset to either edge of the screen (depending on RTL), to // match the behavior of most Launchers float defaultWallpaperX = wallpaperWin.isRtl() ? 1f : 0f; + // "Wallpaper X" is the previous x-offset of the wallpaper (in a 0 to 1 scale). + // The 0 to 1 scale is because the "length" varies depending on how many home screens you + // have, so 0 is the left of the first home screen, and 1 is the right of the last one (for + // LTR, and the opposite for RTL). float wpx = mLastWallpaperX >= 0 ? mLastWallpaperX : defaultWallpaperX; + // "Wallpaper X step size" is how much of that 0-1 is one "page" of the home screen + // when scrolling. float wpxs = mLastWallpaperXStep >= 0 ? mLastWallpaperXStep : -1.0f; - int availw = wallpaperWin.getFrame().right - wallpaperWin.getFrame().left - dw; + // Difference between width of wallpaper image, and the last size of the wallpaper. + // This is the horizontal surplus from the prior configuration. + int availw = wallpaperFrame.width() - lastWallpaperBounds.width(); + + int displayOffset = getDisplayWidthOffset(availw, lastWallpaperBounds, + wallpaperWin.isRtl()); + availw -= displayOffset; int offset = availw > 0 ? -(int)(availw * wpx + .5f) : 0; if (mLastWallpaperDisplayOffsetX != Integer.MIN_VALUE) { + // if device is LTR, then offset wallpaper to the left (the wallpaper is drawn + // always starting from the left of the screen). offset += mLastWallpaperDisplayOffsetX; + } else if (!wallpaperWin.isRtl()) { + // In RTL the offset is calculated so that the wallpaper ends up right aligned (see + // offset above). + offset -= displayOffset; } - xOffset = offset; + newXOffset = offset; if (wallpaperWin.mWallpaperX != wpx || wallpaperWin.mWallpaperXStep != wpxs) { wallpaperWin.mWallpaperX = wpx; @@ -354,12 +416,13 @@ class WallpaperController { float wpy = mLastWallpaperY >= 0 ? mLastWallpaperY : 0.5f; float wpys = mLastWallpaperYStep >= 0 ? mLastWallpaperYStep : -1.0f; - int availh = wallpaperWin.getFrame().bottom - wallpaperWin.getFrame().top - dh; + int availh = wallpaperWin.getFrame().bottom - wallpaperWin.getFrame().top + - lastWallpaperBounds.height(); offset = availh > 0 ? -(int)(availh * wpy + .5f) : 0; if (mLastWallpaperDisplayOffsetY != Integer.MIN_VALUE) { offset += mLastWallpaperDisplayOffsetY; } - yOffset = offset; + newYOffset = offset; if (wallpaperWin.mWallpaperY != wpy || wallpaperWin.mWallpaperYStep != wpys) { wallpaperWin.mWallpaperY = wpy; @@ -372,7 +435,7 @@ class WallpaperController { rawChanged = true; } - boolean changed = wallpaperWin.setWallpaperOffset(xOffset, yOffset, + boolean changed = wallpaperWin.setWallpaperOffset(newXOffset, newYOffset, wallpaperWin.mShouldScaleWallpaper ? zoomOutToScale(wallpaperWin.mWallpaperZoomOut) : 1); @@ -419,6 +482,52 @@ class WallpaperController { return changed; } + /** + * Get an extra offset if needed ({@link #mShouldOffsetWallpaperCenter} = true, typically on + * multiple display devices) so that the wallpaper in a smaller display ends up centered at the + * same position as in the largest display of the device. + * + * Note that the wallpaper has already been cropped when set by the user, so these calculations + * apply to the image size for the display the wallpaper was set for. + * + * @param availWidth width available for the wallpaper offset in the current display + * @param displayFrame size of the "display" (parent frame) + * @param isRtl whether we're in an RTL configuration + * @return an offset to apply to the width, or 0 if the current configuration doesn't require + * any adjustment (either @link #mShouldOffsetWallpaperCenter} is false or we're on the largest + * display). + */ + private int getDisplayWidthOffset(int availWidth, Rect displayFrame, boolean isRtl) { + if (!mShouldOffsetWallpaperCenter) { + return 0; + } + if (mLargestDisplaySize == null) { + mLargestDisplaySize = findLargestDisplaySize(); + } + if (mLargestDisplaySize == null) { + return 0; + } + // Page width is the width of a Launcher "page", for pagination when swiping right. + int pageWidth = displayFrame.width(); + // Only need offset if the current size is different from the largest display, and we're + // in a portrait configuration + if (mLargestDisplaySize.x != pageWidth && displayFrame.width() < displayFrame.height()) { + // The wallpaper will be scaled to fit the height of the wallpaper, so if the height + // of the displays are different, we need to account for that scaling when calculating + // the offset to the center + float sizeRatio = (float) displayFrame.height() / mLargestDisplaySize.y; + // Scale the width of the largest display to match the scale of the wallpaper size in + // the current display + int adjustedLargestWidth = Math.round(mLargestDisplaySize.x * sizeRatio); + // Finally, find the difference between the centers, taking into account that the + // size of the wallpaper frame could be smaller than the screen + return isRtl + ? adjustedLargestWidth - (adjustedLargestWidth + pageWidth) / 2 + : Math.min(adjustedLargestWidth - pageWidth, availWidth) / 2; + } + return 0; + } + void setWindowWallpaperPosition( WindowState window, float x, float y, float xStep, float yStep) { if (window.mWallpaperX != x || window.mWallpaperY != y) { diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 8025cb296b32..b8a1c96807cd 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -8916,13 +8916,19 @@ public class WindowManagerService extends IWindowManager.Stub } // Retrieve the DisplayInfo across all possible display layouts. - return List.copyOf(mPossibleDisplayInfoMapper.getPossibleDisplayInfos(displayId)); + return mPossibleDisplayInfoMapper.getPossibleDisplayInfos(displayId); } } finally { Binder.restoreCallingIdentity(origId); } } + List<DisplayInfo> getPossibleDisplayInfoLocked(int displayId) { + // Retrieve the DisplayInfo for all possible rotations across all possible display + // layouts. + return mPossibleDisplayInfoMapper.getPossibleDisplayInfos(displayId); + } + /** * Returns {@code true} when the calling package is the recents component. */ diff --git a/services/tests/wmtests/src/com/android/server/wm/PossibleDisplayInfoMapperTests.java b/services/tests/wmtests/src/com/android/server/wm/PossibleDisplayInfoMapperTests.java index 8b0a54050c3c..58b0e16eefe8 100644 --- a/services/tests/wmtests/src/com/android/server/wm/PossibleDisplayInfoMapperTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/PossibleDisplayInfoMapperTests.java @@ -36,6 +36,8 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import java.util.ArrayList; +import java.util.List; import java.util.Set; @@ -88,7 +90,8 @@ public class PossibleDisplayInfoMapperTests extends WindowTestsBase { mPossibleDisplayInfo.add(mDefaultDisplayInfo); mDisplayInfoMapper.updatePossibleDisplayInfos(DEFAULT_DISPLAY); - Set<DisplayInfo> displayInfos = mDisplayInfoMapper.getPossibleDisplayInfos(DEFAULT_DISPLAY); + List<DisplayInfo> displayInfos = mDisplayInfoMapper.getPossibleDisplayInfos( + DEFAULT_DISPLAY); // An entry for rotation 0, for a display that can be in a single state. assertThat(displayInfos.size()).isEqualTo(1); assertPossibleDisplayInfoEntries(displayInfos, mDefaultDisplayInfo); @@ -105,9 +108,10 @@ public class PossibleDisplayInfoMapperTests extends WindowTestsBase { mPossibleDisplayInfo.add(mSecondDisplayInfo); mDisplayInfoMapper.updatePossibleDisplayInfos(DEFAULT_DISPLAY); - Set<DisplayInfo> displayInfos = mDisplayInfoMapper.getPossibleDisplayInfos(DEFAULT_DISPLAY); - Set<DisplayInfo> defaultDisplayInfos = new ArraySet<>(); - Set<DisplayInfo> secondDisplayInfos = new ArraySet<>(); + List<DisplayInfo> displayInfos = mDisplayInfoMapper.getPossibleDisplayInfos( + DEFAULT_DISPLAY); + List<DisplayInfo> defaultDisplayInfos = new ArrayList<>(); + List<DisplayInfo> secondDisplayInfos = new ArrayList<>(); for (DisplayInfo di : displayInfos) { if ((di.flags & FLAG_PRESENTATION) != 0) { secondDisplayInfos.add(di); @@ -137,12 +141,13 @@ public class PossibleDisplayInfoMapperTests extends WindowTestsBase { mPossibleDisplayInfo.add(mSecondDisplayInfo); mDisplayInfoMapper.updatePossibleDisplayInfos(mSecondDisplayInfo.displayId); - Set<DisplayInfo> displayInfos = mDisplayInfoMapper.getPossibleDisplayInfos(DEFAULT_DISPLAY); + List<DisplayInfo> displayInfos = mDisplayInfoMapper.getPossibleDisplayInfos( + DEFAULT_DISPLAY); // An entry for rotation 0, for the default display. assertThat(displayInfos).hasSize(1); assertPossibleDisplayInfoEntries(displayInfos, mDefaultDisplayInfo); - Set<DisplayInfo> secondStateEntries = + List<DisplayInfo> secondStateEntries = mDisplayInfoMapper.getPossibleDisplayInfos(mSecondDisplayInfo.displayId); // An entry for rotation 0, for the second display. assertThat(secondStateEntries).hasSize(1); @@ -157,7 +162,7 @@ public class PossibleDisplayInfoMapperTests extends WindowTestsBase { outDisplayInfo.logicalHeight = logicalBounds.height(); } - private static void assertPossibleDisplayInfoEntries(Set<DisplayInfo> displayInfos, + private static void assertPossibleDisplayInfoEntries(List<DisplayInfo> displayInfos, DisplayInfo expectedDisplayInfo) { for (DisplayInfo displayInfo : displayInfos) { assertThat(displayInfo.displayId).isEqualTo(expectedDisplayInfo.displayId); diff --git a/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java index fba4ff1f1c25..82887135c73d 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java @@ -33,17 +33,21 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.when; +import static com.google.common.truth.Truth.assertThat; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyFloat; +import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.verify; import android.content.pm.ActivityInfo; import android.content.res.Configuration; +import android.content.res.Resources; import android.graphics.Rect; import android.os.IBinder; import android.os.RemoteException; @@ -61,9 +65,12 @@ import androidx.test.filters.SmallTest; import com.android.server.wm.utils.WmDisplayCutout; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import java.util.List; + /** * Tests for the {@link WallpaperController} class. * @@ -74,6 +81,18 @@ import org.junit.runner.RunWith; @Presubmit @RunWith(WindowTestRunner.class) public class WallpaperControllerTests extends WindowTestsBase { + private static final int INITIAL_WIDTH = 600; + private static final int INITIAL_HEIGHT = 900; + private static final int SECOND_WIDTH = 300; + + @Before + public void setup() { + Resources resources = mWm.mContext.getResources(); + spyOn(resources); + doReturn(false).when(resources).getBoolean( + com.android.internal.R.bool.config_offsetWallpaperToCenterOfLargestDisplay); + } + @Test public void testWallpaperScreenshot() { WindowSurfaceController windowSurfaceController = mock(WindowSurfaceController.class); @@ -365,6 +384,108 @@ public class WallpaperControllerTests extends WindowTestsBase { assertTrue(token.isVisible()); } + private static void prepareSmallerSecondDisplay(DisplayContent dc, int width, int height) { + spyOn(dc.mWmService); + DisplayInfo firstDisplay = dc.getDisplayInfo(); + DisplayInfo secondDisplay = new DisplayInfo(firstDisplay); + // Second display is narrower than first display. + secondDisplay.logicalWidth = width; + secondDisplay.logicalHeight = height; + doReturn(List.of(firstDisplay, secondDisplay)).when( + dc.mWmService).getPossibleDisplayInfoLocked(anyInt()); + } + + private static void resizeDisplayAndWallpaper(DisplayContent dc, WindowState wallpaperWindow, + int width, int height) { + dc.setBounds(0, 0, width, height); + dc.updateOrientation(); + dc.sendNewConfiguration(); + spyOn(wallpaperWindow); + doReturn(new Rect(0, 0, width, height)).when(wallpaperWindow).getLastReportedBounds(); + } + + @Test + public void testUpdateWallpaperOffset_initial_shouldCenterDisabled() { + final DisplayContent dc = new TestDisplayContent.Builder(mAtm, INITIAL_WIDTH, + INITIAL_HEIGHT).build(); + dc.mWallpaperController.setShouldOffsetWallpaperCenter(false); + prepareSmallerSecondDisplay(dc, SECOND_WIDTH, INITIAL_HEIGHT); + final WindowState wallpaperWindow = createWallpaperWindow(dc, INITIAL_WIDTH, + INITIAL_HEIGHT); + + dc.mWallpaperController.updateWallpaperOffset(wallpaperWindow, false); + + // Wallpaper centering is disabled, so no offset. + assertThat(wallpaperWindow.mXOffset).isEqualTo(0); + assertThat(wallpaperWindow.mYOffset).isEqualTo(0); + } + + @Test + public void testUpdateWallpaperOffset_initial_shouldCenterEnabled() { + final DisplayContent dc = new TestDisplayContent.Builder(mAtm, INITIAL_WIDTH, + INITIAL_HEIGHT).build(); + dc.mWallpaperController.setShouldOffsetWallpaperCenter(true); + prepareSmallerSecondDisplay(dc, SECOND_WIDTH, INITIAL_HEIGHT); + final WindowState wallpaperWindow = createWallpaperWindow(dc, INITIAL_WIDTH, + INITIAL_HEIGHT); + + dc.mWallpaperController.updateWallpaperOffset(wallpaperWindow, false); + + // Wallpaper matches first display, so has no offset. + assertThat(wallpaperWindow.mXOffset).isEqualTo(0); + assertThat(wallpaperWindow.mYOffset).isEqualTo(0); + } + + @Test + public void testUpdateWallpaperOffset_resize_shouldCenterEnabled() { + final DisplayContent dc = new TestDisplayContent.Builder(mAtm, INITIAL_WIDTH, + INITIAL_HEIGHT).build(); + dc.mWallpaperController.setShouldOffsetWallpaperCenter(true); + prepareSmallerSecondDisplay(dc, SECOND_WIDTH, INITIAL_HEIGHT); + final WindowState wallpaperWindow = createWallpaperWindow(dc, INITIAL_WIDTH, + INITIAL_HEIGHT); + + dc.mWallpaperController.updateWallpaperOffset(wallpaperWindow, false); + + // Resize display to match second display bounds. + resizeDisplayAndWallpaper(dc, wallpaperWindow, SECOND_WIDTH, INITIAL_HEIGHT); + + dc.mWallpaperController.updateWallpaperOffset(wallpaperWindow, false); + + // Wallpaper is 300 wider than second display. + assertThat(wallpaperWindow.mXOffset).isEqualTo(-Math.abs(INITIAL_WIDTH - SECOND_WIDTH) / 2); + assertThat(wallpaperWindow.mYOffset).isEqualTo(0); + } + + @Test + public void testUpdateWallpaperOffset_resize_shouldCenterDisabled() { + final DisplayContent dc = new TestDisplayContent.Builder(mAtm, INITIAL_WIDTH, + INITIAL_HEIGHT).build(); + dc.mWallpaperController.setShouldOffsetWallpaperCenter(false); + prepareSmallerSecondDisplay(dc, SECOND_WIDTH, INITIAL_HEIGHT); + final WindowState wallpaperWindow = createWallpaperWindow(dc, INITIAL_WIDTH, + INITIAL_HEIGHT); + + dc.mWallpaperController.updateWallpaperOffset(wallpaperWindow, false); + + // Resize display to match second display bounds. + resizeDisplayAndWallpaper(dc, wallpaperWindow, SECOND_WIDTH, INITIAL_HEIGHT); + + dc.mWallpaperController.updateWallpaperOffset(wallpaperWindow, false); + + // Wallpaper is 300 wider than second display, but offset disabled. + assertThat(wallpaperWindow.mXOffset).isEqualTo(0); + assertThat(wallpaperWindow.mYOffset).isEqualTo(0); + } + + private WindowState createWallpaperWindow(DisplayContent dc, int width, int height) { + final WindowState wallpaperWindow = createWallpaperWindow(dc); + // Wallpaper is cropped to match first display. + wallpaperWindow.getWindowFrames().mParentFrame.set(new Rect(0, 0, width, height)); + wallpaperWindow.getWindowFrames().mFrame.set(0, 0, width, height); + return wallpaperWindow; + } + private WindowState createWallpaperWindow(DisplayContent dc) { final WindowToken wallpaperWindowToken = new WallpaperWindowToken(mWm, mock(IBinder.class), true /* explicit */, dc, true /* ownerCanManageAppTokens */); |