From f34a04cca9b7f34eff533866ec11233777876ebf Mon Sep 17 00:00:00 2001 From: Filip Gruszczynski Date: Mon, 7 Dec 2015 15:05:49 -0800 Subject: [PATCH] Fix freeform to recents animating window being cuttoff. The window will appear cutoff during the animation if the window was cropped due to stack or decor bounds before the animation started. We need to disable the cropping (both from decor and from stack bounds) for the duration of the animation. Unfortunately, by disabling cropping of a freeform window to the stack bounds, we will make it appear above the docked window during the animation (because the animation will lift the layer). To fix this, we need to treat the docked stack like the pinned stack and assume it's always on top for the layering purposes. CL also includes refactoring of mSystemDecorRect and mLastSystemDecorRect which can be moved from WindowState to WindowStateAnimator and made private there. Bug: 24913782 Change-Id: Idbea99ba04e9449d0563d0c02636f8b4b63087f7 --- core/java/android/app/ActivityManager.java | 8 +++ .../android/server/wm/WindowManagerService.java | 5 +- .../java/com/android/server/wm/WindowState.java | 14 ----- .../com/android/server/wm/WindowStateAnimator.java | 73 +++++++++++++++------- 4 files changed, 61 insertions(+), 39 deletions(-) diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index b11a12f2fd06..81fe23c5aabe 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -559,6 +559,14 @@ public class ActivityManager { public static boolean isAlwaysOnTop(int stackId) { return stackId == PINNED_STACK_ID; } + + /** + * Returns true if the application windows in this stack should be displayed above all + * other application windows, including during the animation. + */ + public static boolean shouldIncreaseApplicationWindowLayer(int stackId) { + return stackId == PINNED_STACK_ID || stackId == DOCKED_STACK_ID; + } } /** diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index fa71cfc5c545..334a4dccde4f 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -8693,9 +8693,8 @@ public class WindowManagerService extends IWindowManager.Stub } if (!force) { final TaskStack stack = w.getStack(); - if (stack != null && (StackId.isAlwaysOnTop(stack.mStackId) - || stack.mStackId == DOCKED_STACK_ID)) { - // If the window's stack is always on top, we want to make it above other windows + if (stack != null && (StackId.shouldIncreaseApplicationWindowLayer(stack.mStackId))) { + // For pinned and docked stack window, we want to make them above other windows // also when these windows are animating. force = true; } diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 4fb3283cc634..0fc714263b78 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -259,13 +259,6 @@ final class WindowState implements WindowManagerPolicy.WindowState { */ int mTouchableInsets = ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME; - /** - * This is rectangle of the window's surface that is not covered by - * system decorations. - */ - final Rect mSystemDecorRect = new Rect(); - final Rect mLastSystemDecorRect = new Rect(); - // Current transformation being applied. float mGlobalScale=1; float mInvGlobalScale=1; @@ -2085,13 +2078,6 @@ final class WindowState implements WindowManagerPolicy.WindowState { pw.print(prefix); pw.print("mFrame="); mFrame.printShortString(pw); pw.print(" last="); mLastFrame.printShortString(pw); pw.println(); - pw.print(prefix); pw.print("mSystemDecorRect="); mSystemDecorRect.printShortString(pw); - pw.print(" last="); mLastSystemDecorRect.printShortString(pw); - if (mWinAnimator.mHasClipRect) { - pw.print(" mLastClipRect="); - mWinAnimator.mLastClipRect.printShortString(pw); - } - pw.println(); } if (mEnforceSizeCompat) { pw.print(prefix); pw.print("mCompatFrame="); mCompatFrame.printShortString(pw); diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java index 77b51430bc69..7cd67d098db8 100644 --- a/services/core/java/com/android/server/wm/WindowStateAnimator.java +++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java @@ -28,6 +28,7 @@ import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WIND import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SURFACE_TRACE; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER; +import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_CROP; import static com.android.server.wm.WindowManagerDebugConfig.HIDE_STACK_CRAWLS; import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS; import static com.android.server.wm.WindowManagerDebugConfig.SHOW_SURFACE_ALLOC; @@ -128,6 +129,13 @@ class WindowStateAnimator { Rect mLastClipRect = new Rect(); Rect mTmpStackBounds = new Rect(); + /** + * This is rectangle of the window's surface that is not covered by + * system decorations. + */ + private final Rect mSystemDecorRect = new Rect(); + private final Rect mLastSystemDecorRect = new Rect(); + // Used to save animation distances between the time they are calculated and when they are used. private int mAnimDx; private int mAnimDy; @@ -599,7 +607,7 @@ class WindowStateAnimator { } // We may abort, so initialize to defaults. - w.mLastSystemDecorRect.set(0, 0, 0, 0); + mLastSystemDecorRect.set(0, 0, 0, 0); mHasClipRect = false; mClipRect.set(0, 0, 0, 0); mLastClipRect.set(0, 0, 0, 0); @@ -1048,8 +1056,9 @@ class WindowStateAnimator { } } - private void applyDecorRect(final Rect decorRect) { + private void calculateSystemDecorRect() { final WindowState w = mWin; + final Rect decorRect = w.mDecorFrame; final int width = w.mFrame.width(); final int height = w.mFrame.height(); @@ -1058,11 +1067,17 @@ class WindowStateAnimator { final int top = w.mYOffset + w.mFrame.top; // Initialize the decor rect to the entire frame. - w.mSystemDecorRect.set(0, 0, width, height); + mSystemDecorRect.set(0, 0, width, height); - // Intersect with the decor rect, offsetted by window position. - w.mSystemDecorRect.intersect(decorRect.left - left, decorRect.top - top, - decorRect.right - left, decorRect.bottom - top); + // If a freeform window is animating from a position where it would be cutoff, it would be + // cutoff during the animation. We don't want that, so for the duration of the animation + // we ignore the decor cropping and depend on layering to position windows correctly. + final boolean cropToDecor = !(w.inFreeformWorkspace() && w.isAnimatingLw()); + if (cropToDecor) { + // Intersect with the decor rect, offsetted by window position. + mSystemDecorRect.intersect(decorRect.left - left, decorRect.top - top, + decorRect.right - left, decorRect.bottom - top); + } // If size compatibility is being applied to the window, the // surface is scaled relative to the screen. Also apply this @@ -1072,10 +1087,10 @@ class WindowStateAnimator { // 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); + mSystemDecorRect.left = (int) (mSystemDecorRect.left * scale - 0.5f); + mSystemDecorRect.top = (int) (mSystemDecorRect.top * scale - 0.5f); + mSystemDecorRect.right = (int) ((mSystemDecorRect.right+1) * scale - 0.5f); + mSystemDecorRect.bottom = (int) ((mSystemDecorRect.bottom+1) * scale - 0.5f); } } @@ -1086,30 +1101,34 @@ class WindowStateAnimator { return; } final DisplayInfo displayInfo = displayContent.getDisplayInfo(); + if (DEBUG_WINDOW_CROP) Slog.d(TAG, "Updating crop for window: " + w + ", " + "mLastCrop=" + + mLastClipRect); // Need to recompute a new system decor rect each time. if (!w.isDefaultDisplay()) { // On a different display there is no system decor. Crop the window // by the screen boundaries. - w.mSystemDecorRect.set(0, 0, w.mCompatFrame.width(), w.mCompatFrame.height()); - w.mSystemDecorRect.intersect(-w.mCompatFrame.left, -w.mCompatFrame.top, + mSystemDecorRect.set(0, 0, w.mCompatFrame.width(), w.mCompatFrame.height()); + mSystemDecorRect.intersect(-w.mCompatFrame.left, -w.mCompatFrame.top, displayInfo.logicalWidth - w.mCompatFrame.left, displayInfo.logicalHeight - w.mCompatFrame.top); } 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()); + mSystemDecorRect.set(0, 0, w.mCompatFrame.width(), w.mCompatFrame.height()); } else if (w.mDecorFrame.isEmpty()) { // Windows without policy decor aren't cropped. - w.mSystemDecorRect.set(0, 0, w.mCompatFrame.width(), w.mCompatFrame.height()); + mSystemDecorRect.set(0, 0, w.mCompatFrame.width(), w.mCompatFrame.height()); } else if (w.mAttrs.type == LayoutParams.TYPE_WALLPAPER && mAnimator.isAnimating()) { // If we're animating, the wallpaper crop should only be updated at the end of the // animation. - mTmpClipRect.set(w.mSystemDecorRect); - applyDecorRect(w.mDecorFrame); - w.mSystemDecorRect.union(mTmpClipRect); + mTmpClipRect.set(mSystemDecorRect); + calculateSystemDecorRect(); + mSystemDecorRect.union(mTmpClipRect); } else { // Crop to the system decor specified by policy. - applyDecorRect(w.mDecorFrame); + calculateSystemDecorRect(); + if (DEBUG_WINDOW_CROP) Slog.d(TAG, "Applying decor to crop for " + w + ", mDecorFrame=" + + w.mDecorFrame + ", mSystemDecorRect=" + mSystemDecorRect); } final boolean fullscreen = w.isFrameFullscreen(displayInfo); @@ -1123,7 +1142,9 @@ class WindowStateAnimator { } else { // We use the clip rect as provided by the tranformation for non-fullscreen windows to // avoid premature clipping with the system decor rect. - clipRect.set((mHasClipRect && !fullscreen) ? mClipRect : w.mSystemDecorRect); + clipRect.set((mHasClipRect && !fullscreen) ? mClipRect : mSystemDecorRect); + if (DEBUG_WINDOW_CROP) Slog.d(TAG, "Initial clip rect: " + clipRect + ", mHasClipRect=" + + mHasClipRect + ", fullscreen=" + fullscreen); } // Expand the clip rect for surface insets. final WindowManager.LayoutParams attrs = w.mAttrs; @@ -1143,6 +1164,7 @@ class WindowStateAnimator { clipRect.offset(attrs.surfaceInsets.left, attrs.surfaceInsets.top); adjustCropToStackBounds(w, clipRect, isFreeformResizing); + if (DEBUG_WINDOW_CROP) Slog.d(TAG, "Clip rect after stack adjustment=" + mClipRect); w.transformFromScreenToSurfaceSpace(clipRect); @@ -1160,13 +1182,14 @@ class WindowStateAnimator { } // We don't apply the stack bounds crop if: - // 1. The window is currently animating docked mode, otherwise the animating window will be - // suddenly cut off. + // 1. The window is currently animating docked mode or in freeform mode, otherwise the + // animating window will be suddenly (docked) or for whole animation (freeform) cut off. // 2. The window that is being replaced during animation, because it was living in a // different stack. If we suddenly crop it to the new stack bounds, it might get cut off. // We don't want it to happen, so we let it ignore the stack bounds until it gets removed. // The window that will replace it will abide them. - if (isAnimating() && (appToken.mWillReplaceWindow || w.inDockedWorkspace())) { + if (isAnimating() && (appToken.mWillReplaceWindow || w.inDockedWorkspace() + || w.inFreeformWorkspace())) { return; } @@ -1646,6 +1669,12 @@ class WindowStateAnimator { if (dumpAll) { pw.print(prefix); pw.print("mDrawState="); pw.print(drawStateToString()); pw.print(prefix); pw.print(" mLastHidden="); pw.println(mLastHidden); + pw.print(prefix); pw.print("mSystemDecorRect="); mSystemDecorRect.printShortString(pw); + pw.print(" last="); mLastSystemDecorRect.printShortString(pw); + if (mHasClipRect) { + pw.print(" mLastClipRect="); mLastClipRect.printShortString(pw); + } + pw.println(); } if (mPendingDestroySurface != null) { -- 2.11.0