diff --git a/core/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto index 449e546722074..c11058a221072 100644 --- a/core/proto/android/server/windowmanagerservice.proto +++ b/core/proto/android/server/windowmanagerservice.proto @@ -295,6 +295,7 @@ message WindowStateProto { optional bool animating_exit = 14; repeated WindowStateProto child_windows = 15; optional .android.graphics.RectProto surface_position = 16; + optional .android.graphics.RectProto shown_position = 17; optional int32 requested_width = 18; optional int32 requested_height = 19; optional int32 view_visibility = 20; diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index 177d6af489b34..0502848d698ee 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -5603,7 +5603,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { final int fl = PolicyControl.getWindowFlags(null, mTopFullscreenOpaqueWindowState.getAttrs()); if (localLOGV) { - Slog.d(TAG, "frame: " + mTopFullscreenOpaqueWindowState.getFrameLw()); + Slog.d(TAG, "frame: " + mTopFullscreenOpaqueWindowState.getFrameLw() + + " shown position: " + + mTopFullscreenOpaqueWindowState.getShownPositionLw()); Slog.d(TAG, "attr: " + mTopFullscreenOpaqueWindowState.getAttrs() + " lp.flags=0x" + Integer.toHexString(fl)); } diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java index 3af3fcbbf7a81..e9c4c5c8138f2 100644 --- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java +++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java @@ -231,6 +231,14 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants { */ public Rect getFrameLw(); + /** + * Retrieve the current position of the window that is actually shown. + * Must be called with the window manager lock held. + * + * @return Point The point holding the shown window position. + */ + public Point getShownPositionLw(); + /** * Retrieve the frame of the display that this window was last * laid out in. Must be called with the diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java index da3a035ad8df5..f2ad6fb7a8880 100644 --- a/services/core/java/com/android/server/wm/WallpaperController.java +++ b/services/core/java/com/android/server/wm/WallpaperController.java @@ -272,8 +272,6 @@ class WallpaperController { } boolean updateWallpaperOffset(WindowState wallpaperWin, int dw, int dh, boolean sync) { - int xOffset = 0; - int yOffset = 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 @@ -285,8 +283,11 @@ class WallpaperController { if (mLastWallpaperDisplayOffsetX != Integer.MIN_VALUE) { offset += mLastWallpaperDisplayOffsetX; } - xOffset = offset; - + boolean changed = wallpaperWin.mXOffset != offset; + if (changed) { + if (DEBUG_WALLPAPER) Slog.v(TAG, "Update wallpaper " + wallpaperWin + " x: " + offset); + wallpaperWin.mXOffset = offset; + } if (wallpaperWin.mWallpaperX != wpx || wallpaperWin.mWallpaperXStep != wpxs) { wallpaperWin.mWallpaperX = wpx; wallpaperWin.mWallpaperXStep = wpxs; @@ -300,16 +301,17 @@ class WallpaperController { if (mLastWallpaperDisplayOffsetY != Integer.MIN_VALUE) { offset += mLastWallpaperDisplayOffsetY; } - yOffset = offset; - + if (wallpaperWin.mYOffset != offset) { + if (DEBUG_WALLPAPER) Slog.v(TAG, "Update wallpaper " + wallpaperWin + " y: " + offset); + changed = true; + wallpaperWin.mYOffset = offset; + } if (wallpaperWin.mWallpaperY != wpy || wallpaperWin.mWallpaperYStep != wpys) { wallpaperWin.mWallpaperY = wpy; wallpaperWin.mWallpaperYStep = wpys; rawChanged = true; } - boolean changed = wallpaperWin.mWinAnimator.setWallpaperOffset(xOffset, yOffset); - if (rawChanged && (wallpaperWin.mAttrs.privateFlags & WindowManager.LayoutParams.PRIVATE_FLAG_WANTS_OFFSET_NOTIFICATIONS) != 0) { try { diff --git a/services/core/java/com/android/server/wm/WallpaperWindowToken.java b/services/core/java/com/android/server/wm/WallpaperWindowToken.java index ddda027595da4..2ae5c7bd9c254 100644 --- a/services/core/java/com/android/server/wm/WallpaperWindowToken.java +++ b/services/core/java/com/android/server/wm/WallpaperWindowToken.java @@ -74,6 +74,10 @@ class WallpaperWindowToken extends WindowToken { for (int wallpaperNdx = mChildren.size() - 1; wallpaperNdx >= 0; wallpaperNdx--) { final WindowState wallpaper = mChildren.get(wallpaperNdx); if (wallpaperController.updateWallpaperOffset(wallpaper, dw, dh, sync)) { + final WindowStateAnimator winAnimator = wallpaper.mWinAnimator; + winAnimator.computeShownFrameLocked(); + // No need to lay out the windows - we can just set the wallpaper position directly. + winAnimator.setWallpaperOffset(wallpaper.mShownPosition); // We only want to be synchronous with one wallpaper. sync = false; } diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 48d29e372124e..240e7fd8e9b05 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -137,6 +137,7 @@ import static com.android.server.wm.proto.WindowStateProto.REMOVED; import static com.android.server.wm.proto.WindowStateProto.REMOVE_ON_EXIT; import static com.android.server.wm.proto.WindowStateProto.REQUESTED_HEIGHT; import static com.android.server.wm.proto.WindowStateProto.REQUESTED_WIDTH; +import static com.android.server.wm.proto.WindowStateProto.SHOWN_POSITION; import static com.android.server.wm.proto.WindowStateProto.STABLE_INSETS; import static com.android.server.wm.proto.WindowStateProto.STACK_ID; import static com.android.server.wm.proto.WindowStateProto.SURFACE_INSETS; @@ -295,6 +296,12 @@ class WindowState extends WindowContainer implements WindowManagerP */ private final MergedConfiguration mLastReportedConfiguration = new MergedConfiguration(); + /** + * Actual position of the surface shown on-screen (may be modified by animation). These are + * in the screen's coordinate space (WITH the compatibility scale applied). + */ + final Point mShownPosition = new Point(); + /** * Insets that determine the actually visible area. These are in the application's * coordinate space (without compatibility scale applied). @@ -454,6 +461,10 @@ class WindowState extends WindowContainer implements WindowManagerP int mWallpaperDisplayOffsetX = Integer.MIN_VALUE; int mWallpaperDisplayOffsetY = Integer.MIN_VALUE; + // Wallpaper windows: pixels offset based on above variables. + int mXOffset; + int mYOffset; + /** * This is set after IWindowSession.relayout() has been called at * least once for the window. It allows us to detect the situation @@ -734,6 +745,8 @@ class WindowState extends WindowContainer implements WindowManagerP mRequestedHeight = 0; mLastRequestedWidth = 0; mLastRequestedHeight = 0; + mXOffset = 0; + mYOffset = 0; mLayer = 0; mInputWindowHandle = new InputWindowHandle( mAppToken != null ? mAppToken.mInputApplicationHandle : null, this, c, @@ -1098,6 +1111,11 @@ class WindowState extends WindowContainer implements WindowManagerP return mFrame; } + @Override + public Point getShownPositionLw() { + return mShownPosition; + } + @Override public Rect getDisplayFrameLw() { return mDisplayFrame; @@ -3116,6 +3134,7 @@ class WindowState extends WindowContainer implements WindowManagerP mContentInsets.writeToProto(proto, CONTENT_INSETS); mAttrs.surfaceInsets.writeToProto(proto, SURFACE_INSETS); mSurfacePosition.writeToProto(proto, SURFACE_POSITION); + mShownPosition.writeToProto(proto, SHOWN_POSITION); mWinAnimator.writeToProto(proto, ANIMATOR); proto.write(ANIMATING_EXIT, mAnimatingExit); for (int i = 0; i < mChildren.size(); i++) { @@ -3231,6 +3250,10 @@ class WindowState extends WindowContainer implements WindowManagerP pw.print(prefix); pw.print("mRelayoutCalled="); pw.print(mRelayoutCalled); pw.print(" mLayoutNeeded="); pw.println(mLayoutNeeded); } + if (mXOffset != 0 || mYOffset != 0) { + pw.print(prefix); pw.print("Offsets x="); pw.print(mXOffset); + pw.print(" y="); pw.println(mYOffset); + } if (dumpAll) { pw.print(prefix); pw.print("mGivenContentInsets="); mGivenContentInsets.printShortString(pw); @@ -3249,6 +3272,7 @@ class WindowState extends WindowContainer implements WindowManagerP pw.println(getLastReportedConfiguration()); } pw.print(prefix); pw.print("mHasSurface="); pw.print(mHasSurface); + pw.print(" mShownPosition="); mShownPosition.printShortString(pw); pw.print(" isReadyForDisplay()="); pw.print(isReadyForDisplay()); pw.print(" mWindowRemovalAllowed="); pw.println(mWindowRemovalAllowed); if (dumpAll) { @@ -4171,8 +4195,9 @@ class WindowState extends WindowContainer implements WindowManagerP final int width = mFrame.width(); final int height = mFrame.height(); - final int left = mFrame.left; - final int top = mFrame.top; + // Compute the offset of the window in relation to the decor rect. + final int left = mXOffset + mFrame.left; + final int top = mYOffset + mFrame.top; // Initialize the decor rect to the entire frame. if (isDockedResizing()) { @@ -4367,8 +4392,8 @@ class WindowState extends WindowContainer implements WindowManagerP float9[Matrix.MSKEW_Y] = mWinAnimator.mDtDx; float9[Matrix.MSKEW_X] = mWinAnimator.mDtDy; float9[Matrix.MSCALE_Y] = mWinAnimator.mDsDy; - int x = mSurfacePosition.x; - int y = mSurfacePosition.y; + int x = mSurfacePosition.x + mShownPosition.x; + int y = mSurfacePosition.y + mShownPosition.y; // If changed, also adjust transformFrameToSurfacePosition final WindowContainer parent = getParent(); diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java index 76c1812134c13..dd23b6f256300 100644 --- a/services/core/java/com/android/server/wm/WindowStateAnimator.java +++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java @@ -209,12 +209,6 @@ class WindowStateAnimator { float mExtraHScale = (float) 1.0; float mExtraVScale = (float) 1.0; - // An offset in pixel of the surface contents from the window position. Used for Wallpaper - // to provide the effect of scrolling within a large surface. We just use these values as - // a cache. - int mXOffset = 0; - int mYOffset = 0; - private final Rect mTmpSize = new Rect(); private final SurfaceControl.Transaction mReparentTransaction = new SurfaceControl.Transaction(); @@ -444,7 +438,7 @@ class WindowStateAnimator { flags |= SurfaceControl.SECURE; } - mTmpSize.set(0, 0, 0, 0); + mTmpSize.set(w.mFrame.left + w.mXOffset, w.mFrame.top + w.mYOffset, 0, 0); calculateSurfaceBounds(w, attrs); final int width = mTmpSize.width(); final int height = mTmpSize.height(); @@ -685,8 +679,8 @@ class WindowStateAnimator { // WindowState.prepareSurfaces expands for surface insets (in order they don't get // clipped by the WindowState surface), so we need to go into the other direction here. - tmpMatrix.postTranslate(mWin.mAttrs.surfaceInsets.left, - mWin.mAttrs.surfaceInsets.top); + tmpMatrix.postTranslate(mWin.mXOffset + mWin.mAttrs.surfaceInsets.left, + mWin.mYOffset + mWin.mAttrs.surfaceInsets.top); // "convert" it into SurfaceFlinger's format @@ -701,6 +695,9 @@ class WindowStateAnimator { mDtDx = tmpFloats[Matrix.MSKEW_Y]; mDtDy = tmpFloats[Matrix.MSKEW_X]; mDsDy = tmpFloats[Matrix.MSCALE_Y]; + float x = tmpFloats[Matrix.MTRANS_X]; + float y = tmpFloats[Matrix.MTRANS_Y]; + mWin.mShownPosition.set(Math.round(x), Math.round(y)); // Now set the alpha... but because our current hardware // can't do alpha transformation on a non-opaque surface, @@ -710,7 +707,8 @@ class WindowStateAnimator { mShownAlpha = mAlpha; if (!mService.mLimitedAlphaCompositing || (!PixelFormat.formatHasAlpha(mWin.mAttrs.format) - || (mWin.isIdentityMatrix(mDsDx, mDtDx, mDtDy, mDsDy)))) { + || (mWin.isIdentityMatrix(mDsDx, mDtDx, mDtDy, mDsDy) + && x == frame.left && y == frame.top))) { //Slog.i(TAG_WM, "Applying alpha transform"); if (screenAnimation) { mShownAlpha *= screenRotationAnimation.getEnterTransformation().getAlpha(); @@ -740,6 +738,10 @@ class WindowStateAnimator { TAG, "computeShownFrameLocked: " + this + " not attached, mAlpha=" + mAlpha); + // WindowState.prepareSurfaces expands for surface insets (in order they don't get + // clipped by the WindowState surface), so we need to go into the other direction here. + mWin.mShownPosition.set(mWin.mXOffset + mWin.mAttrs.surfaceInsets.left, + mWin.mYOffset + mWin.mAttrs.surfaceInsets.top); mShownAlpha = mAlpha; mHaveMatrix = false; mDsDx = mWin.mGlobalScale; @@ -790,6 +792,12 @@ class WindowStateAnimator { if (DEBUG_WINDOW_CROP) Slog.d(TAG, "win=" + w + " Initial clip rect: " + clipRect + " fullscreen=" + fullscreen); + if (isFreeformResizing && !w.isChildWindow()) { + // For freeform resizing non child windows, we are using the big surface positioned + // at 0,0. Thus we must express the crop in that coordinate space. + clipRect.offset(w.mShownPosition.x, w.mShownPosition.y); + } + w.expandForSurfaceInsets(clipRect); // The clip rect was generated assuming (0,0) as the window origin, @@ -831,7 +839,7 @@ class WindowStateAnimator { return; } - mTmpSize.set(0, 0, 0, 0); + mTmpSize.set(w.mShownPosition.x, w.mShownPosition.y, 0, 0); calculateSurfaceBounds(w, attrs); mExtraHScale = (float) 1.0; @@ -965,6 +973,11 @@ class WindowStateAnimator { // then take over the scaling until the new buffer arrives, and things // will be seamless. mForceScaleUntilResize = true; + } else { + if (!w.mSeamlesslyRotated) { + mSurfaceController.setPositionInTransaction(mTmpSize.left, mTmpSize.top, + recoveringMemory); + } } // If we are ending the scaling mode. We switch to SCALING_MODE_FREEZE @@ -1156,26 +1169,24 @@ class WindowStateAnimator { mSurfaceController.setTransparentRegionHint(region); } - boolean setWallpaperOffset(int dx, int dy) { - if (mXOffset == dx && mYOffset == dy) { - return false; - } - mXOffset = dx; - mYOffset = dy; + void setWallpaperOffset(Point shownPosition) { + final LayoutParams attrs = mWin.getAttrs(); + final int left = shownPosition.x - attrs.surfaceInsets.left; + final int top = shownPosition.y - attrs.surfaceInsets.top; try { if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, ">>> OPEN TRANSACTION setWallpaperOffset"); mService.openSurfaceTransaction(); - mSurfaceController.setPositionInTransaction(dx, dy, false); + mSurfaceController.setPositionInTransaction(mWin.mFrame.left + left, + mWin.mFrame.top + top, false); applyCrop(null, false); } catch (RuntimeException e) { Slog.w(TAG, "Error positioning surface of " + mWin - + " pos=(" + dx + "," + dy + ")", e); + + " pos=(" + left + "," + top + ")", e); } finally { mService.closeSurfaceTransaction("setWallpaperOffset"); if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, "<<< CLOSE TRANSACTION setWallpaperOffset"); - return true; } } diff --git a/services/tests/servicestests/src/com/android/server/policy/FakeWindowState.java b/services/tests/servicestests/src/com/android/server/policy/FakeWindowState.java index 5de393c7ae2b8..a628b7b70c151 100644 --- a/services/tests/servicestests/src/com/android/server/policy/FakeWindowState.java +++ b/services/tests/servicestests/src/com/android/server/policy/FakeWindowState.java @@ -78,6 +78,11 @@ public class FakeWindowState implements WindowManagerPolicy.WindowState { return parentFrame; } + @Override + public Point getShownPositionLw() { + return new Point(parentFrame.left, parentFrame.top); + } + @Override public Rect getDisplayFrameLw() { return displayFrame;