diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java index e9285cc7931d3..bf3c08870c630 100644 --- a/core/java/android/service/wallpaper/WallpaperService.java +++ b/core/java/android/service/wallpaper/WallpaperService.java @@ -49,7 +49,6 @@ import android.util.Log; import android.util.MergedConfiguration; import android.view.Display; import android.view.DisplayCutout; -import android.view.DisplayInfo; import android.view.Gravity; import android.view.IWindowSession; import android.view.InputChannel; @@ -833,22 +832,8 @@ public abstract class WallpaperService extends Service { mLayout.x = 0; mLayout.y = 0; - if (!fixedSize) { - mLayout.width = myWidth; - mLayout.height = myHeight; - } else { - // Force the wallpaper to cover the screen in both dimensions - // only internal implementations like ImageWallpaper - DisplayInfo displayInfo = new DisplayInfo(); - mDisplay.getDisplayInfo(displayInfo); - final float layoutScale = Math.max( - (float) displayInfo.logicalHeight / (float) myHeight, - (float) displayInfo.logicalWidth / (float) myWidth); - mLayout.height = (int) (myHeight * layoutScale); - mLayout.width = (int) (myWidth * layoutScale); - mWindowFlags |= WindowManager.LayoutParams.FLAG_SCALED; - } - + mLayout.width = myWidth; + mLayout.height = myHeight; mLayout.format = mFormat; mCurWindowFlags = mWindowFlags; diff --git a/services/core/java/com/android/server/wm/WallpaperWindowToken.java b/services/core/java/com/android/server/wm/WallpaperWindowToken.java index 294dd040e2a58..e29580beca50b 100644 --- a/services/core/java/com/android/server/wm/WallpaperWindowToken.java +++ b/services/core/java/com/android/server/wm/WallpaperWindowToken.java @@ -28,6 +28,8 @@ import android.os.IBinder; import android.os.RemoteException; import android.util.Slog; import android.view.DisplayInfo; +import android.view.ViewGroup; +import android.view.WindowManager; import android.view.animation.Animation; import java.util.function.Consumer; @@ -166,6 +168,23 @@ class WallpaperWindowToken extends WindowToken { } } + @Override + void adjustWindowParams(WindowState win, WindowManager.LayoutParams attrs) { + if (attrs.height == ViewGroup.LayoutParams.MATCH_PARENT + || attrs.width == ViewGroup.LayoutParams.MATCH_PARENT) { + return; + } + + final DisplayInfo displayInfo = win.getDisplayInfo(); + + final float layoutScale = Math.max( + (float) displayInfo.logicalHeight / (float) attrs.height, + (float) displayInfo.logicalWidth / (float) attrs.width); + attrs.height = (int) (attrs.height * layoutScale); + attrs.width = (int) (attrs.width * layoutScale); + attrs.flags |= WindowManager.LayoutParams.FLAG_SCALED; + } + boolean hasVisibleNotDrawnWallpaper() { for (int j = mChildren.size() - 1; j >= 0; --j) { final WindowState wallpaper = mChildren.get(j); diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 673e7e0d241ed..3f4f629b52924 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -2122,6 +2122,7 @@ public class WindowManagerService extends IWindowManager.Stub int privateFlagChanges = 0; if (attrs != null) { displayPolicy.adjustWindowParamsLw(win, attrs, pid, uid); + win.mToken.adjustWindowParams(win, attrs); // if they don't have the permission, mask out the status bar bits if (seq == win.mSeq) { int systemUiVisibility = attrs.systemUiVisibility diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java index 3b7b7c65a1145..98d9c8fcab5a2 100644 --- a/services/core/java/com/android/server/wm/WindowToken.java +++ b/services/core/java/com/android/server/wm/WindowToken.java @@ -48,6 +48,7 @@ import android.util.proto.ProtoOutputStream; import android.view.DisplayInfo; import android.view.InsetsState; import android.view.SurfaceControl; +import android.view.WindowManager; import com.android.server.policy.WindowManagerPolicy; import com.android.server.protolog.common.ProtoLog; @@ -519,6 +520,14 @@ class WindowToken extends WindowContainer { rotator.unrotateInsets(outSurfaceInsets); } + /** + * Gives a chance to this {@link WindowToken} to adjust the {@link + * android.view.WindowManager.LayoutParams} of its windows. + */ + void adjustWindowParams(WindowState win, WindowManager.LayoutParams attrs) { + } + + @CallSuper @Override public void dumpDebug(ProtoOutputStream proto, long fieldId, 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 14d8a9ddab67a..aa665241c50b4 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java @@ -16,19 +16,30 @@ package com.android.server.wm; +import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS; import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; import static com.android.dx.mockito.inline.extended.ExtendedMockito.when; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import android.content.pm.ActivityInfo; +import android.content.res.Configuration; +import android.graphics.Rect; import android.os.IBinder; import android.platform.test.annotations.Presubmit; +import android.view.DisplayInfo; +import android.view.Gravity; +import android.view.Surface; +import android.view.WindowManager; import androidx.test.filters.SmallTest; +import com.android.server.wm.utils.WmDisplayCutout; + import org.junit.Test; import org.junit.runner.RunWith; @@ -72,4 +83,60 @@ public class WallpaperControllerTests extends WindowTestsBase { wallpaperWindow.mWinAnimator.mLastAlpha = 1; assertTrue(dc.mWallpaperController.canScreenshotWallpaper()); } + + @Test + public void testWallpaperSizeWithFixedTransform() { + // No wallpaper + final DisplayContent dc = createNewDisplay(); + dc.mWmService.mIsFixedRotationTransformEnabled = true; + + // No wallpaper WSA Surface + WindowToken wallpaperWindowToken = new WallpaperWindowToken(mWm, mock(IBinder.class), + true, dc, true /* ownerCanManageAppTokens */); + WindowState wallpaperWindow = createWindow(null /* parent */, TYPE_WALLPAPER, + wallpaperWindowToken, "wallpaperWindow"); + + WindowManager.LayoutParams attrs = wallpaperWindow.getAttrs(); + Rect bounds = dc.getBounds(); + int displayHeight = dc.getBounds().height(); + + // Use a wallpaper with a different ratio than the display + int wallpaperWidth = bounds.width() * 2; + int wallpaperHeight = (int) (bounds.height() * 1.10); + + // Simulate what would be done on the client's side + attrs.width = wallpaperWidth; + attrs.height = wallpaperHeight; + attrs.flags |= FLAG_LAYOUT_NO_LIMITS; + attrs.gravity = Gravity.TOP | Gravity.LEFT; + wallpaperWindow.getWindowFrames().mParentFrame.set(dc.getBounds()); + + // Calling layoutWindowLw a first time, so adjustWindowParams gets the correct data + dc.getDisplayPolicy().layoutWindowLw(wallpaperWindow, null, dc.mDisplayFrames); + + wallpaperWindowToken.adjustWindowParams(wallpaperWindow, attrs); + dc.getDisplayPolicy().layoutWindowLw(wallpaperWindow, null, dc.mDisplayFrames); + + assertEquals(Configuration.ORIENTATION_PORTRAIT, dc.getConfiguration().orientation); + int expectedWidth = (int) (wallpaperWidth * (displayHeight / (double) wallpaperHeight)); + + // Check that the wallpaper is correctly scaled + assertEquals(new Rect(0, 0, expectedWidth, displayHeight), wallpaperWindow.getFrameLw()); + Rect portraitFrame = wallpaperWindow.getFrameLw(); + + // Rotate the display + dc.getDisplayRotation().updateOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE, true); + dc.sendNewConfiguration(); + + // Apply the fixed transform + Configuration config = new Configuration(); + final DisplayInfo info = dc.computeScreenConfiguration(config, Surface.ROTATION_0); + final WmDisplayCutout cutout = dc.calculateDisplayCutoutForRotation(Surface.ROTATION_0); + final DisplayFrames displayFrames = new DisplayFrames(dc.getDisplayId(), info, cutout); + wallpaperWindowToken.applyFixedRotationTransform(info, displayFrames, config); + + // Check that the wallpaper has the same frame in landscape than in portrait + assertEquals(Configuration.ORIENTATION_LANDSCAPE, dc.getConfiguration().orientation); + assertEquals(portraitFrame, wallpaperWindow.getFrameLw()); + } }