From 3e52fc25154540faf3c0cb927ff45532cdebdddf Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Tue, 15 May 2012 17:58:02 -0700 Subject: [PATCH] Fix some issues with updating the offsets of a window. - Apply the correct crop rect at this point. - Apply the correct position by taking into account the frame left/top. - Don't directly apply the new values if the window is currently animating, since we need to go through the whole animation step to determine what the correct position is (taking into account any transformations). Change-Id: I15d79354d9779867c49c7c0880faccdead7b021d --- .../server/wm/WindowStateAnimator.java | 126 ++++++++++-------- 1 file changed, 73 insertions(+), 53 deletions(-) diff --git a/services/java/com/android/server/wm/WindowStateAnimator.java b/services/java/com/android/server/wm/WindowStateAnimator.java index cba92f3600319..5516dea82067c 100644 --- a/services/java/com/android/server/wm/WindowStateAnimator.java +++ b/services/java/com/android/server/wm/WindowStateAnimator.java @@ -935,6 +935,59 @@ class WindowStateAnimator { mDtDy = mWin.mGlobalScale; } + void updateSurfaceWindowCrop(final boolean recoveringMemory) { + final WindowState w = mWin; + + // Need to recompute a new system decor rect each time. + if ((w.mAttrs.flags & LayoutParams.FLAG_SCALED) != 0) { + // Currently can't do this cropping for scaled windows. We'll + // just keep the crop rect the same as the source surface. + w.mSystemDecorRect.set(0, 0, w.mRequestedWidth, w.mRequestedHeight); + } else if (w.mLayer >= mService.mSystemDecorLayer) { + // Above the decor layer is easy, just use the entire window. + w.mSystemDecorRect.set(0, 0, w.mCompatFrame.width(), + w.mCompatFrame.height()); + } else { + final Rect decorRect = mService.mSystemDecorRect; + // Compute the offset of the window in relation to the decor rect. + final int offX = w.mXOffset + w.mFrame.left; + final int offY = w.mYOffset + w.mFrame.top; + // Initialize the decor rect to the entire frame. + w.mSystemDecorRect.set(0, 0, w.mFrame.width(), w.mFrame.height()); + // Intersect with the decor rect, offsetted by window position. + w.mSystemDecorRect.intersect(decorRect.left-offX, decorRect.top-offY, + decorRect.right-offX, decorRect.bottom-offY); + // If size compatibility is being applied to the window, the + // surface is scaled relative to the screen. Also apply this + // scaling to the crop rect. We aren't using the standard rect + // scale function because we want to round things to make the crop + // always round to a larger rect to ensure we don't crop too + // much and hide part of the window that should be seen. + if (w.mEnforceSizeCompat && w.mInvGlobalScale != 1.0f) { + final float scale = w.mInvGlobalScale; + w.mSystemDecorRect.left = (int) (w.mSystemDecorRect.left * scale - 0.5f); + w.mSystemDecorRect.top = (int) (w.mSystemDecorRect.top * scale - 0.5f); + w.mSystemDecorRect.right = (int) ((w.mSystemDecorRect.right+1) * scale - 0.5f); + w.mSystemDecorRect.bottom = (int) ((w.mSystemDecorRect.bottom+1) * scale - 0.5f); + } + } + + if (!w.mSystemDecorRect.equals(w.mLastSystemDecorRect)) { + w.mLastSystemDecorRect.set(w.mSystemDecorRect); + try { + if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(w, + "CROP " + w.mSystemDecorRect.toShortString(), null); + mSurface.setWindowCrop(w.mSystemDecorRect); + } catch (RuntimeException e) { + Slog.w(TAG, "Error setting crop surface of " + w + + " crop=" + w.mSystemDecorRect.toShortString(), e); + if (!recoveringMemory) { + mService.reclaimSomeSurfaceMemoryLocked(this, "crop", true); + } + } + } + } + void setSurfaceBoundaries(final boolean recoveringMemory) { final WindowState w = mWin; int width, height; @@ -1003,54 +1056,7 @@ class WindowStateAnimator { } } - // Need to recompute a new system decor rect each time. - if ((w.mAttrs.flags & LayoutParams.FLAG_SCALED) != 0) { - // Currently can't do this cropping for scaled windows. We'll - // just keep the crop rect the same as the source surface. - w.mSystemDecorRect.set(0, 0, w.mRequestedWidth, w.mRequestedHeight); - } else if (w.mLayer >= mService.mSystemDecorLayer) { - // Above the decor layer is easy, just use the entire window. - w.mSystemDecorRect.set(0, 0, w.mCompatFrame.width(), - w.mCompatFrame.height()); - } else { - final Rect decorRect = mService.mSystemDecorRect; - // Compute the offset of the window in relation to the decor rect. - final int offX = w.mXOffset + w.mFrame.left; - final int offY = w.mYOffset + w.mFrame.top; - // Initialize the decor rect to the entire frame. - w.mSystemDecorRect.set(0, 0, w.mFrame.width(), w.mFrame.height()); - // Intersect with the decor rect, offsetted by window position. - w.mSystemDecorRect.intersect(decorRect.left-offX, decorRect.top-offY, - decorRect.right-offX, decorRect.bottom-offY); - // If size compatibility is being applied to the window, the - // surface is scaled relative to the screen. Also apply this - // scaling to the crop rect. We aren't using the standard rect - // scale function because we want to round things to make the crop - // always round to a larger rect to ensure we don't crop too - // much and hide part of the window that should be seen. - if (w.mEnforceSizeCompat && w.mInvGlobalScale != 1.0f) { - final float scale = w.mInvGlobalScale; - w.mSystemDecorRect.left = (int) (w.mSystemDecorRect.left * scale - 0.5f); - w.mSystemDecorRect.top = (int) (w.mSystemDecorRect.top * scale - 0.5f); - w.mSystemDecorRect.right = (int) ((w.mSystemDecorRect.right+1) * scale - 0.5f); - w.mSystemDecorRect.bottom = (int) ((w.mSystemDecorRect.bottom+1) * scale - 0.5f); - } - } - - if (!w.mSystemDecorRect.equals(w.mLastSystemDecorRect)) { - w.mLastSystemDecorRect.set(w.mSystemDecorRect); - try { - if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(w, - "CROP " + w.mSystemDecorRect.toShortString(), null); - mSurface.setWindowCrop(w.mSystemDecorRect); - } catch (RuntimeException e) { - Slog.w(TAG, "Error setting crop surface of " + w - + " crop=" + w.mSystemDecorRect.toShortString(), e); - if (!recoveringMemory) { - mService.reclaimSomeSurfaceMemoryLocked(this, "crop", true); - } - } - } + updateSurfaceWindowCrop(recoveringMemory); } public void prepareSurfaceLocked(final boolean recoveringMemory) { @@ -1181,17 +1187,31 @@ class WindowStateAnimator { } void setWallpaperOffset(int left, int top) { + mSurfaceX = left; + mSurfaceY = top; + if (mAnimating) { + // If this window (or its app token) is animating, then the position + // of the surface will be re-computed on the next animation frame. + // We can't poke it directly here because it depends on whatever + // transformation is being applied by the animation. + return; + } + if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, + ">>> OPEN TRANSACTION setWallpaperOffset"); Surface.openTransaction(); try { - mSurfaceX = left; - mSurfaceY = top; - mSurface.setPosition(left, top); - mSurface.setWindowCrop(null); + if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(mWin, + "POS " + left + ", " + top, null); + mSurface.setPosition(mWin.mFrame.left + left, mWin.mFrame.top + top); + updateSurfaceWindowCrop(false); } catch (RuntimeException e) { Slog.w(TAG, "Error positioning surface of " + mWin + " pos=(" + left + "," + top + ")", e); + } finally { + Surface.closeTransaction(); + if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, + "<<< CLOSE TRANSACTION setWallpaperOffset"); } - Surface.closeTransaction(); } // This must be called while inside a transaction.