Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6a7c90a1 authored by Jorim Jaggi's avatar Jorim Jaggi
Browse files

Implement clip modes during animation

Introduce modes how surfaces are clipped to the stack bounds
during transitions.

Use setFinalCrop to implement STACK_CLIP_AFTER_ANIM.

Add logic to determine which stack clip mode to use.

Bug: 26559810
Change-Id: I8edc47de3aaf1ef12055cefd8ceb8df536c5109a
parent 3876fbcf
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -43,6 +43,8 @@ import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_NONE;
import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_AFTER_ANIM;

import android.annotation.Nullable;
import android.content.Context;
@@ -1467,6 +1469,12 @@ public class AppTransition implements Dump {
        return a;
    }

    int getAppStackClipMode() {
        return mNextAppTransition == TRANSIT_ACTIVITY_RELAUNCH
                ? STACK_CLIP_NONE
                : STACK_CLIP_AFTER_ANIM;
    }

    void postAnimationCallback() {
        if (mNextAppTransitionCallback != null) {
            mService.mH.sendMessage(mService.mH.obtainMessage(H.DO_ANIMATION_CALLBACK,
+10 −1
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import static com.android.server.wm.WindowManagerService.TYPE_LAYER_OFFSET;
import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_BEFORE_ANIM;

import android.graphics.Matrix;
import android.util.Slog;
@@ -106,6 +107,7 @@ public class AppWindowAnimator {
    boolean usingTransferredAnimation = false;

    private boolean mSkipFirstFrame = false;
    private int mStackClip = STACK_CLIP_BEFORE_ANIM;

    static final Animation sDummyAnimation = new DummyAnimation();

@@ -115,7 +117,8 @@ public class AppWindowAnimator {
        mAnimator = mService.mAnimator;
    }

    public void setAnimation(Animation anim, int width, int height, boolean skipFirstFrame) {
    public void setAnimation(Animation anim, int width, int height, boolean skipFirstFrame,
            int stackClip) {
        if (WindowManagerService.localLOGV) Slog.v(TAG, "Setting animation in " + mAppToken
                + ": " + anim + " wxh=" + width + "x" + height
                + " isVisible=" + mAppToken.isVisible());
@@ -142,6 +145,7 @@ public class AppWindowAnimator {
        transformation.clear();
        transformation.setAlpha(mAppToken.isVisible() ? 1 : 0);
        hasTransformation = true;
        mStackClip = stackClip;

        this.mSkipFirstFrame = skipFirstFrame;

@@ -186,6 +190,7 @@ public class AppWindowAnimator {
            mAppToken.allDrawn = false;
            mAppToken.deferClearAllDrawn = false;
        }
        mStackClip = STACK_CLIP_BEFORE_ANIM;
    }

    public boolean isAnimating() {
@@ -201,6 +206,10 @@ public class AppWindowAnimator {
        deferThumbnailDestruction = false;
    }

    int getStackClip() {
        return mStackClip;
    }

    void transferCurrentAnimation(
            AppWindowAnimator toAppAnimator, WindowStateAnimator transferWinAnimator) {

+6 −3
Original line number Diff line number Diff line
@@ -36,6 +36,8 @@ import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_TRACE;
import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import static com.android.server.wm.WindowStateAnimator.READY_TO_SHOW;
import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_BEFORE_ANIM;
import static com.android.server.wm.WindowSurfacePlacer.SET_FORCE_HIDING_CHANGED;
import static com.android.server.wm.WindowSurfacePlacer.SET_ORIENTATION_CHANGE_COMPLETE;
import static com.android.server.wm.WindowSurfacePlacer.SET_UPDATE_ROTATION;
@@ -406,7 +408,8 @@ public class WindowAnimator {

                            Animation a = mPolicy.createForceHideEnterAnimation(false,
                                    keyguardGoingAwayToShade);
                            winAnimator.setAnimation(a, mPostKeyguardExitAnimation.getStartTime());
                            winAnimator.setAnimation(a, mPostKeyguardExitAnimation.getStartTime(),
                                    STACK_CLIP_BEFORE_ANIM);
                            winAnimator.mKeyguardGoingAwayAnimation = true;
                            winAnimator.mKeyguardGoingAwayWithWallpaper
                                    = keyguardGoingAwayWithWallpaper;
@@ -445,7 +448,7 @@ public class WindowAnimator {
            }

            final AppWindowToken atoken = win.mAppToken;
            if (winAnimator.mDrawState == WindowStateAnimator.READY_TO_SHOW) {
            if (winAnimator.mDrawState == READY_TO_SHOW) {
                if (atoken == null || atoken.allDrawn) {
                    if (winAnimator.performShowLocked()) {
                        setPendingLayoutChanges(displayId,
@@ -487,7 +490,7 @@ public class WindowAnimator {
                    if (a != null) {
                        if (DEBUG_KEYGUARD) Slog.v(TAG,
                                "Starting keyguard exit animation on window " + winAnimator.mWin);
                        winAnimator.setAnimation(a);
                        winAnimator.setAnimation(a, STACK_CLIP_BEFORE_ANIM);
                        winAnimator.mKeyguardGoingAwayAnimation = true;
                        winAnimator.mKeyguardGoingAwayWithWallpaper
                                = keyguardGoingAwayWithWallpaper;
+4 −3
Original line number Diff line number Diff line
@@ -236,6 +236,7 @@ import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS;
import static com.android.server.wm.WindowManagerDebugConfig.SHOW_VERBOSE_TRANSACTIONS;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import static com.android.server.wm.WindowStateAnimator.DRAW_PENDING;

/** {@hide} */
public class WindowManagerService extends IWindowManager.Stub
@@ -3039,7 +3040,7 @@ public class WindowManagerService extends IWindowManager.Stub
                final int containingWidth = frame.width();
                final int containingHeight = frame.height();
                atoken.mAppAnimator.setAnimation(a, containingWidth, containingHeight,
                        mAppTransition.canSkipFirstFrame());
                        mAppTransition.canSkipFirstFrame(), mAppTransition.getAppStackClipMode());
            }
        } else {
            atoken.mAppAnimator.clearAnimation();
@@ -8973,7 +8974,7 @@ public class WindowManagerService extends IWindowManager.Stub
                                + ", mDrawState=DRAW_PENDING in " + w
                                + ", surfaceController " + winAnimator.mSurfaceController);
                    }
                    winAnimator.mDrawState = WindowStateAnimator.DRAW_PENDING;
                    winAnimator.mDrawState = DRAW_PENDING;
                    if (w.mAppToken != null) {
                        w.mAppToken.allDrawn = false;
                        w.mAppToken.deferClearAllDrawn = false;
@@ -10787,7 +10788,7 @@ public class WindowManagerService extends IWindowManager.Stub
                    final boolean isForceHiding = mPolicy.isForceHiding(win.mAttrs);
                    if (win.isVisibleLw()
                            && (win.mAppToken != null || isForceHiding)) {
                        win.mWinAnimator.mDrawState = WindowStateAnimator.DRAW_PENDING;
                        win.mWinAnimator.mDrawState = DRAW_PENDING;
                        // Force add to mResizingWindows.
                        win.mLastContentInsets.set(-1, -1, -1, -1);
                        mWaitingForDrawn.add(win);
+86 −37
Original line number Diff line number Diff line
@@ -75,6 +75,25 @@ class WindowStateAnimator {
    static final String TAG = TAG_WITH_CLASS_NAME ? "WindowStateAnimator" : TAG_WM;
    static final int WINDOW_FREEZE_LAYER = TYPE_LAYER_MULTIPLIER * 200;

    /**
     * Mode how the window gets clipped by the stack bounds during an animation: The clipping should
     * be applied after applying the animation transformation, i.e. the stack bounds don't move
     * during the animation.
     */
    static final int STACK_CLIP_AFTER_ANIM = 0;

    /**
     * Mode how the window gets clipped by the stack bounds: The clipping should be applied before
     * applying the animation transformation, i.e. the stack bounds move with the window.
     */
    static final int STACK_CLIP_BEFORE_ANIM = 1;

    /**
     * Mode how window gets clipped by the stack bounds during an animation: Don't clip the window
     * by the stack bounds.
     */
    static final int STACK_CLIP_NONE = 2;

    // Unchanging local convenience fields.
    final WindowManagerService mService;
    final WindowState mWin;
@@ -100,6 +119,7 @@ class WindowStateAnimator {
    int mLastLayer;
    long mAnimationStartTime;
    long mLastAnimationTime;
    int mStackClip = STACK_CLIP_BEFORE_ANIM;

    /**
     * Set when we have changed the size of the surface, to know that
@@ -128,7 +148,9 @@ class WindowStateAnimator {
    boolean mHasClipRect;
    Rect mClipRect = new Rect();
    Rect mTmpClipRect = new Rect();
    Rect mTmpFinalClipRect = new Rect();
    Rect mLastClipRect = new Rect();
    Rect mLastFinalClipRect = new Rect();
    Rect mTmpStackBounds = new Rect();

    /**
@@ -226,7 +248,7 @@ class WindowStateAnimator {
        mWallpaperControllerLocked = mService.mWallpaperControllerLocked;
    }

    public void setAnimation(Animation anim, long startTime) {
    public void setAnimation(Animation anim, long startTime, int stackClip) {
        if (localLOGV) Slog.v(TAG, "Setting animation in " + this + ": " + anim);
        mAnimating = false;
        mLocalAnimating = false;
@@ -238,10 +260,15 @@ class WindowStateAnimator {
        mTransformation.setAlpha(mLastHidden ? 0 : 1);
        mHasLocalTransformation = true;
        mAnimationStartTime = startTime;
        mStackClip = stackClip;
    }

    public void setAnimation(Animation anim, int stackClip) {
        setAnimation(anim, -1, stackClip);
    }

    public void setAnimation(Animation anim) {
        setAnimation(anim, -1);
        setAnimation(anim, -1, STACK_CLIP_AFTER_ANIM);
    }

    public void clearAnimation() {
@@ -252,6 +279,7 @@ class WindowStateAnimator {
            mAnimation = null;
            mKeyguardGoingAwayAnimation = false;
            mKeyguardGoingAwayWithWallpaper = false;
            mStackClip = STACK_CLIP_BEFORE_ANIM;
        }
    }

@@ -397,6 +425,7 @@ class WindowStateAnimator {
        if (DEBUG_LAYERS) Slog.v(TAG, "Stepping win " + this + " anim layer: " + mAnimLayer);
        mHasTransformation = false;
        mHasLocalTransformation = false;
        mStackClip = STACK_CLIP_BEFORE_ANIM;
        mWin.checkPolicyVisibilityChange();
        mTransformation.clear();
        if (mDrawState == HAS_DRAWN
@@ -1130,11 +1159,13 @@ class WindowStateAnimator {
        }
    }

    Rect calculateSurfaceWindowCrop() {
    void calculateSurfaceWindowCrop(Rect clipRect, Rect finalClipRect) {
        final WindowState w = mWin;
        final DisplayContent displayContent = w.getDisplayContent();
        if (displayContent == null) {
            return null;
            clipRect.setEmpty();
            finalClipRect.setEmpty();
            return;
        }
        final DisplayInfo displayInfo = displayContent.getDisplayInfo();
        if (DEBUG_WINDOW_CROP) Slog.d(TAG, "Updating crop for window: " + w + ", " + "mLastCrop=" +
@@ -1170,7 +1201,6 @@ class WindowStateAnimator {
        final boolean fullscreen = w.isFrameFullscreen(displayInfo);
        final boolean isFreeformResizing =
                w.isDragResizing() && w.getResizeMode() == DRAG_RESIZE_MODE_FREEFORM;
        final Rect clipRect = mTmpClipRect;

        // We use the clip rect as provided by the tranformation for non-fullscreen windows to
        // avoid premature clipping with the system decor rect.
@@ -1201,7 +1231,8 @@ class WindowStateAnimator {
        // so we need to translate to match the actual surface coordinates.
        clipRect.offset(attrs.surfaceInsets.left, attrs.surfaceInsets.top);

        adjustCropToStackBounds(w, clipRect, isFreeformResizing);
        finalClipRect.setEmpty();
        adjustCropToStackBounds(w, clipRect, finalClipRect, isFreeformResizing);
        if (DEBUG_WINDOW_CROP) Slog.d(TAG, "Clip rect after stack adjustment=" + clipRect);

        w.transformFromScreenToSurfaceSpace(clipRect);
@@ -1210,35 +1241,39 @@ class WindowStateAnimator {
        if (w.hasJustMovedInStack() && mLastClipRect.isEmpty() && !clipRect.isEmpty()) {
            clipRect.setEmpty();
        }

        return clipRect;
    }

    void updateSurfaceWindowCrop(Rect clipRect, boolean recoveringMemory) {
    void updateSurfaceWindowCrop(Rect clipRect, Rect finalClipRect, boolean recoveringMemory) {
        if (!clipRect.equals(mLastClipRect)) {
            mLastClipRect.set(clipRect);
            mSurfaceController.setCropInTransaction(clipRect, recoveringMemory);
        }
        if (!finalClipRect.equals(mLastFinalClipRect)) {
            mLastFinalClipRect.set(finalClipRect);
            mSurfaceController.setFinalCropInTransaction(finalClipRect);
        }
    }

    private void adjustCropToStackBounds(WindowState w, Rect clipRect, boolean isFreeformResizing) {
    private int resolveStackClip() {

        // App animation overrides window animation stack clip mode.
        if (mAppAnimator != null && mAppAnimator.animation != null) {
            return mAppAnimator.getStackClip();
        } else {
            return mStackClip;
        }
    }
    private void adjustCropToStackBounds(WindowState w, Rect clipRect, Rect finalClipRect,
            boolean isFreeformResizing) {
        final Task task = w.getTask();
        if (task == null || !task.cropWindowsToStackBounds()) {
            return;
        }

        // We don't apply the stack bounds crop if:
        // 1. The window is currently animating 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.
        // TODO: identify animations where we don't want to apply docked stack crop to the docked
        //       task. For example, if the app is going from freeform to docked mode, we may not
        //       want to apply the crop during the animation, since it will make the app appear
        //       cropped prematurely.
        if (isAnimating() && (w.mWillReplaceWindow || w.inFreeformWorkspace())) {
        final int stackClip = resolveStackClip();

        // It's animating and we don't want to clip it to stack bounds during animation - abort.
        if (isAnimating() && stackClip == STACK_CLIP_NONE) {
            return;
        }

@@ -1257,8 +1292,15 @@ class WindowStateAnimator {
        final int frameY = isFreeformResizing ? (int) mSurfaceController.getY() :
                w.mFrame.top + mWin.mYOffset - w.getAttrs().surfaceInsets.top;

        // If we are animating, we either apply the clip before applying all the animation
        // transformation or after all the transformation.
        final boolean useFinalClipRect = isAnimating() && stackClip == STACK_CLIP_AFTER_ANIM;

        // 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.
        if (useFinalClipRect) {
            finalClipRect.set(mTmpStackBounds);
        } else {
            clipRect.left = Math.max(0,
                    Math.max(mTmpStackBounds.left, frameX + clipRect.left) - frameX);
            clipRect.top = Math.max(0,
@@ -1268,6 +1310,7 @@ class WindowStateAnimator {
            clipRect.bottom = Math.max(0,
                    Math.min(mTmpStackBounds.bottom, frameY + clipRect.bottom) - frameY);
        }
    }

    void setSurfaceBoundariesLocked(final boolean recoveringMemory) {
        final WindowState w = mWin;
@@ -1279,10 +1322,10 @@ class WindowStateAnimator {
        float extraHScale = (float) 1.0;
        float extraVScale = (float) 1.0;

        final Rect crop = calculateSurfaceWindowCrop();
        calculateSurfaceWindowCrop(mTmpClipRect, mTmpFinalClipRect);
        if (task != null && task.mStack.getForceScaleToCrop()) {
            extraHScale = crop.width() / (float)mTmpSize.width();
            extraVScale = crop.height() / (float)mTmpSize.height();
            extraHScale = mTmpClipRect.width() / (float)mTmpSize.width();
            extraVScale = mTmpClipRect.height() / (float)mTmpSize.height();

            // In the case of ForceScaleToCrop we scale entire tasks together,
            // and so we need to scale our offsets relative to the task bounds
@@ -1296,12 +1339,13 @@ class WindowStateAnimator {
            // Since we are scaled to fit in our previously desired crop, we can now
            // expose the whole window in buffer space, and not risk extending
            // past where the system would have cropped us
            crop.set(0, 0, mTmpSize.width(), mTmpSize.height());
            updateSurfaceWindowCrop(crop, recoveringMemory);
            mTmpClipRect.set(0, 0, mTmpSize.width(), mTmpSize.height());
            mTmpFinalClipRect.setEmpty();
            updateSurfaceWindowCrop(mTmpClipRect, mTmpFinalClipRect, recoveringMemory);
        } else {
            mSurfaceController.setPositionInTransaction(mTmpSize.left, mTmpSize.top,
                    recoveringMemory);
            updateSurfaceWindowCrop(crop, recoveringMemory);
            updateSurfaceWindowCrop(mTmpClipRect, mTmpFinalClipRect, recoveringMemory);
        }


@@ -1458,7 +1502,8 @@ class WindowStateAnimator {
            SurfaceControl.openTransaction();
            mSurfaceController.setPositionInTransaction(mWin.mFrame.left + left,
                    mWin.mFrame.top + top, false);
            updateSurfaceWindowCrop(calculateSurfaceWindowCrop(), false);
            calculateSurfaceWindowCrop(mTmpClipRect, mTmpFinalClipRect);
            updateSurfaceWindowCrop(mTmpClipRect, mTmpFinalClipRect, false);
        } catch (RuntimeException e) {
            Slog.w(TAG, "Error positioning surface of " + mWin
                    + " pos=(" + left + "," + top + ")", e);
@@ -1721,6 +1766,7 @@ class WindowStateAnimator {
                    pw.print(" mLocalAnimating="); pw.print(mLocalAnimating);
                    pw.print(" mAnimationIsEntrance="); pw.print(mAnimationIsEntrance);
                    pw.print(" mAnimation="); pw.println(mAnimation);
                    pw.print(" mStackClip="); pw.println(mStackClip);
        }
        if (mHasTransformation || mHasLocalTransformation) {
            pw.print(prefix); pw.print("XForm: has=");
@@ -1740,6 +1786,9 @@ class WindowStateAnimator {
            if (mHasClipRect) {
                pw.print(" mLastClipRect="); mLastClipRect.printShortString(pw);
            }
            if (!mLastFinalClipRect.isEmpty()) {
                pw.print(" mLastFinalClipRect="); mLastFinalClipRect.printShortString(pw);
            }
            pw.println();
        }

Loading