diff options
| author | 2022-07-07 20:45:11 +0100 | |
|---|---|---|
| committer | 2022-08-31 18:06:30 +0000 | |
| commit | a95ffcd63bb212545954ec4cac810db286d17c98 (patch) | |
| tree | 25c30f2c2386227bb0d10e6a905d34e382d24291 | |
| parent | 56fe9580ff24fbcea77b93ec345b0860a5e7bf85 (diff) | |
Offset the wallpaper to center in smaller display
If we have more than one physical display, offset the wallpaper
in the smaller displays so that the center corresponds to the
center of the image in the largest display.
This behavior is controlled by a config flag to avoid
affecting the behavior of existing foldable devices.
Bug: 195120817
Test: manual (visually verified with different images)
Test: atest WmTests:WallpaperControllerTests
Change-Id: I57bfeb5ab82f265c991f3be02313abb4289d42dd
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 */); |