diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java index bf1ab8fab7d04..0ab96d63b1b85 100644 --- a/services/core/java/com/android/server/wm/WindowStateAnimator.java +++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java @@ -115,6 +115,7 @@ class WindowStateAnimator { Rect mClipRect = new Rect(); Rect mTmpClipRect = new Rect(); Rect mLastClipRect = new Rect(); + Rect mTmpStackBounds = new Rect(); // Used to save animation distances between the time they are calculated and when they are // used. @@ -168,6 +169,11 @@ class WindowStateAnimator { /** Set when the window has been shown in the screen the first time. */ static final int HAS_DRAWN = 4; + // Surface flinger doesn't support crop rectangles where width or height is non-positive. + // However, we need to somehow handle the situation where the cropping would completely hide + // the window. We achieve this by explicitly hiding the surface and not letting it be shown. + private boolean mHiddenForCrop; + String drawStateToString() { switch (mDrawState) { case NO_SURFACE: return "NO_SURFACE"; @@ -1331,12 +1337,20 @@ class WindowStateAnimator { // so we need to translate to match the actual surface coordinates. clipRect.offset(attrs.surfaceInsets.left, attrs.surfaceInsets.top); + adjustCropToStackBounds(w, clipRect); + if (!clipRect.equals(mLastClipRect)) { mLastClipRect.set(clipRect); try { if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(w, "CROP " + clipRect.toShortString(), null); - mSurfaceControl.setWindowCrop(clipRect); + if (clipRect.width() > 0 && clipRect.height() > 0) { + mSurfaceControl.setWindowCrop(clipRect); + mHiddenForCrop = false; + } else { + hide(); + mHiddenForCrop = true; + } } catch (RuntimeException e) { Slog.w(TAG, "Error setting crop surface of " + w + " crop=" + clipRect.toShortString(), e); @@ -1347,6 +1361,25 @@ class WindowStateAnimator { } } + private void adjustCropToStackBounds(WindowState w, Rect clipRect) { + if (w.getAttrs().type == LayoutParams.TYPE_BASE_APPLICATION) { + TaskStack stack = w.getTask().mStack; + stack.getBounds(mTmpStackBounds); + final int surfaceX = (int) mSurfaceX; + final int surfaceY = (int) mSurfaceY; + // We need to do some acrobatics with surface position, because their clip region is + // relative to the inside of the surface, but the stack bounds aren't. + clipRect.left = Math.max(0, + Math.max(mTmpStackBounds.left, surfaceX + clipRect.left) - surfaceX); + clipRect.top = Math.max(0, + Math.max(mTmpStackBounds.top, surfaceY + clipRect.top) - surfaceY); + clipRect.right = Math.max(0, + Math.min(mTmpStackBounds.right, surfaceX + clipRect.right) - surfaceX); + clipRect.bottom = Math.max(0, + Math.min(mTmpStackBounds.bottom, surfaceY + clipRect.bottom) - surfaceY); + } + } + void setSurfaceBoundariesLocked(final boolean recoveringMemory) { final WindowState w = mWin; @@ -1517,7 +1550,7 @@ class WindowStateAnimator { mDsDx * w.mHScale, mDtDx * w.mVScale, mDsDy * w.mHScale, mDtDy * w.mVScale); - if (mLastHidden && mDrawState == HAS_DRAWN) { + if (mLastHidden && mDrawState == HAS_DRAWN && !mHiddenForCrop) { if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(w, "SHOW (performLayout)", null); if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(TAG, "Showing " + w