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

Commit dbb7991b authored by Craig Mautner's avatar Craig Mautner
Browse files

Separate animation steps into start, step and finish phases.

Fixes bug 6089126.

Change-Id: Iafbde36ff719640335a7ecf762e1d991cf7915e4
parent 5bb59daf
Loading
Loading
Loading
Loading
+25 −17
Original line number Diff line number Diff line
@@ -37,7 +37,7 @@ import java.util.ArrayList;
 * Version of WindowToken that is specifically for a particular application (or
 * really activity) that is displaying windows.
 */
class AppWindowToken extends WindowToken {
class AppWindowToken extends WindowToken implements WindowManagerService.StepAnimator {
    // Non-null only for application tokens.
    final IApplicationToken appToken;

@@ -195,8 +195,28 @@ class AppWindowToken extends WindowToken {
        }
    }

    @Override
    public boolean stepAnimation(long currentTime) {
        if (animation == null) {
            return false;
        }
        transformation.clear();
        final boolean more = animation.getTransformation(currentTime, transformation);
        if (WindowManagerService.DEBUG_ANIM) Slog.v(
            WindowManagerService.TAG, "Stepped animation in " + this +
            ": more=" + more + ", xform=" + transformation);
        if (!more) {
            animation = null;
            if (WindowManagerService.DEBUG_ANIM) Slog.v(
                WindowManagerService.TAG, "Finished animation in " + this +
                " @ " + currentTime);
        }
        hasTransformation = more;
        return more;
    }

    // This must be called while inside a transaction.
    boolean stepAnimationLocked(long currentTime, int dw, int dh) {
    boolean startAndFinishAnimationLocked(long currentTime, int dw, int dh) {
        if (!service.mDisplayFrozen && service.mPolicy.isScreenOnFully()) {
            // We will run animations as long as the display isn't frozen.

@@ -219,22 +239,9 @@ class AppWindowToken extends WindowToken {
                    animation.setStartTime(currentTime);
                    animating = true;
                }
                transformation.clear();
                final boolean more = animation.getTransformation(
                    currentTime, transformation);
                if (WindowManagerService.DEBUG_ANIM) Slog.v(
                    WindowManagerService.TAG, "Stepped animation in " + this +
                    ": more=" + more + ", xform=" + transformation);
                if (more) {
                // we're done!
                    hasTransformation = true;
                return true;
            }
                if (WindowManagerService.DEBUG_ANIM) Slog.v(
                    WindowManagerService.TAG, "Finished animation in " + this +
                    " @ " + currentTime);
                animation = null;
            }
        } else if (animation != null) {
            // If the display is frozen, and there is a pending animation,
            // clear it and make sure we run the cleanup code.
@@ -369,6 +376,7 @@ class AppWindowToken extends WindowToken {
        return null;
    }

    @Override
    void dump(PrintWriter pw, String prefix) {
        super.dump(pw, prefix);
        if (appToken != null) {
+70 −55
Original line number Diff line number Diff line
@@ -29,7 +29,7 @@ import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.animation.Transformation;

class ScreenRotationAnimation {
class ScreenRotationAnimation implements WindowManagerService.StepAnimator {
    static final String TAG = "ScreenRotationAnimation";
    static final boolean DEBUG_STATE = false;
    static final boolean DEBUG_TRANSFORMS = false;
@@ -97,6 +97,12 @@ class ScreenRotationAnimation {
    final Matrix mSnapshotFinalMatrix = new Matrix();
    final Matrix mTmpMatrix = new Matrix();
    final float[] mTmpFloats = new float[9];
    private boolean mMoreRotateEnter;
    private boolean mMoreRotateExit;
    private boolean mMoreFinishEnter;
    private boolean mMoreFinishExit;
    private boolean mMoreStartEnter;
    private boolean mMoreStartExit;

    public void printTo(String prefix, PrintWriter pw) {
        pw.print(prefix); pw.print("mSurface="); pw.print(mSurface);
@@ -456,34 +462,8 @@ class ScreenRotationAnimation {
                && mRotateEnterAnimation != null || mRotateExitAnimation != null;
    }

    @Override
    public boolean stepAnimation(long now) {
        if (!isAnimating()) {
            if (DEBUG_STATE) Slog.v(TAG, "Step: no animations running");
            return false;
        }

        if (!mAnimRunning) {
            if (DEBUG_STATE) Slog.v(TAG, "Step: starting start, finish, rotate");
            if (mStartEnterAnimation != null) {
                mStartEnterAnimation.setStartTime(now);
            }
            if (mStartExitAnimation != null) {
                mStartExitAnimation.setStartTime(now);
            }
            if (mFinishEnterAnimation != null) {
                mFinishEnterAnimation.setStartTime(0);
            }
            if (mFinishExitAnimation != null) {
                mFinishExitAnimation.setStartTime(0);
            }
            if (mRotateEnterAnimation != null) {
                mRotateEnterAnimation.setStartTime(now);
            }
            if (mRotateExitAnimation != null) {
                mRotateExitAnimation.setStartTime(now);
            }
            mAnimRunning = true;
        }

        if (mFinishAnimReady && mFinishAnimStartTime < 0) {
            if (DEBUG_STATE) Slog.v(TAG, "Step: finish anim now ready");
@@ -493,24 +473,24 @@ class ScreenRotationAnimation {
        // If the start animation is no longer running, we want to keep its
        // transformation intact until the finish animation also completes.

        boolean moreStartExit = false;
        mMoreStartExit = false;
        if (mStartExitAnimation != null) {
            mStartExitTransformation.clear();
            moreStartExit = mStartExitAnimation.getTransformation(now, mStartExitTransformation);
            mMoreStartExit = mStartExitAnimation.getTransformation(now, mStartExitTransformation);
            if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped start exit: " + mStartExitTransformation);
            if (!moreStartExit) {
            if (!mMoreStartExit) {
                if (DEBUG_STATE) Slog.v(TAG, "Start exit animation done!");
                mStartExitAnimation.cancel();
                mStartExitAnimation = null;
            }
        }

        boolean moreStartEnter = false;
        mMoreStartEnter = false;
        if (mStartEnterAnimation != null) {
            mStartEnterTransformation.clear();
            moreStartEnter = mStartEnterAnimation.getTransformation(now, mStartEnterTransformation);
            mMoreStartEnter = mStartEnterAnimation.getTransformation(now, mStartEnterTransformation);
            if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped start enter: " + mStartEnterTransformation);
            if (!moreStartEnter) {
            if (!mMoreStartEnter) {
                if (DEBUG_STATE) Slog.v(TAG, "Start enter animation done!");
                mStartEnterAnimation.cancel();
                mStartEnterAnimation = null;
@@ -521,11 +501,11 @@ class ScreenRotationAnimation {
        if (DEBUG_STATE) Slog.v(TAG, "Step: finishNow=" + finishNow);

        mFinishExitTransformation.clear();
        boolean moreFinishExit = false;
        mMoreFinishExit = false;
        if (mFinishExitAnimation != null) {
            moreFinishExit = mFinishExitAnimation.getTransformation(finishNow, mFinishExitTransformation);
            mMoreFinishExit = mFinishExitAnimation.getTransformation(finishNow, mFinishExitTransformation);
            if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped finish exit: " + mFinishExitTransformation);
            if (!moreStartExit && !moreFinishExit) {
            if (!mMoreStartExit && !mMoreFinishExit) {
                if (DEBUG_STATE) Slog.v(TAG, "Finish exit animation done, clearing start/finish anims!");
                mStartExitTransformation.clear();
                mFinishExitAnimation.cancel();
@@ -535,11 +515,11 @@ class ScreenRotationAnimation {
        }

        mFinishEnterTransformation.clear();
        boolean moreFinishEnter = false;
        mMoreFinishEnter = false;
        if (mFinishEnterAnimation != null) {
            moreFinishEnter = mFinishEnterAnimation.getTransformation(finishNow, mFinishEnterTransformation);
            mMoreFinishEnter = mFinishEnterAnimation.getTransformation(finishNow, mFinishEnterTransformation);
            if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped finish enter: " + mFinishEnterTransformation);
            if (!moreStartEnter && !moreFinishEnter) {
            if (!mMoreStartEnter && !mMoreFinishEnter) {
                if (DEBUG_STATE) Slog.v(TAG, "Finish enter animation done, clearing start/finish anims!");
                mStartEnterTransformation.clear();
                mFinishEnterAnimation.cancel();
@@ -549,13 +529,13 @@ class ScreenRotationAnimation {
        }

        mRotateExitTransformation.clear();
        boolean moreRotateExit = false;
        mMoreRotateExit = false;
        if (mRotateExitAnimation != null) {
            moreRotateExit = mRotateExitAnimation.getTransformation(now, mRotateExitTransformation);
            mMoreRotateExit = mRotateExitAnimation.getTransformation(now, mRotateExitTransformation);
            if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped rotate exit: " + mRotateExitTransformation);
        }

        if (!moreFinishExit && !moreRotateExit) {
        if (!mMoreFinishExit && !mMoreRotateExit) {
            if (DEBUG_STATE) Slog.v(TAG, "Rotate exit animation done!");
            mRotateExitAnimation.cancel();
            mRotateExitAnimation = null;
@@ -563,13 +543,13 @@ class ScreenRotationAnimation {
        }

        mRotateEnterTransformation.clear();
        boolean moreRotateEnter = false;
        mMoreRotateEnter = false;
        if (mRotateEnterAnimation != null) {
            moreRotateEnter = mRotateEnterAnimation.getTransformation(now, mRotateEnterTransformation);
            mMoreRotateEnter = mRotateEnterAnimation.getTransformation(now, mRotateEnterTransformation);
            if (DEBUG_TRANSFORMS) Slog.v(TAG, "Stepped rotate enter: " + mRotateEnterTransformation);
        }

        if (!moreFinishEnter && !moreRotateEnter) {
        if (!mMoreFinishEnter && !mMoreRotateEnter) {
            if (DEBUG_STATE) Slog.v(TAG, "Rotate enter animation done!");
            mRotateEnterAnimation.cancel();
            mRotateEnterAnimation = null;
@@ -587,14 +567,25 @@ class ScreenRotationAnimation {
        if (DEBUG_TRANSFORMS) Slog.v(TAG, "Final exit: " + mExitTransformation);
        if (DEBUG_TRANSFORMS) Slog.v(TAG, "Final enter: " + mEnterTransformation);

        if (!moreStartExit && !moreFinishExit && !moreRotateExit) {
        final boolean more = mMoreStartEnter || mMoreStartExit || mMoreFinishEnter
                || mMoreFinishExit || mMoreRotateEnter || mMoreRotateExit || !mFinishAnimReady;

        mSnapshotFinalMatrix.setConcat(mExitTransformation.getMatrix(), mSnapshotInitialMatrix);

        if (DEBUG_STATE) Slog.v(TAG, "Step: more=" + more);

        return more;
    }

    void updateSurfaces() {
        if (!mMoreStartExit && !mMoreFinishExit && !mMoreRotateExit) {
            if (mSurface != null) {
                if (DEBUG_STATE) Slog.v(TAG, "Exit animations done, hiding screenshot surface");
                mSurface.hide();
            }
        }

        if (!moreStartEnter && !moreFinishEnter && !moreRotateEnter) {
        if (!mMoreStartEnter && !mMoreFinishEnter && !mMoreRotateEnter) {
            if (mBlackFrame != null) {
                if (DEBUG_STATE) Slog.v(TAG, "Enter animations done, hiding black frame");
                mBlackFrame.hide();
@@ -605,15 +596,39 @@ class ScreenRotationAnimation {
            }
        }

        mSnapshotFinalMatrix.setConcat(mExitTransformation.getMatrix(), mSnapshotInitialMatrix);
        setSnapshotTransform(mSnapshotFinalMatrix, mExitTransformation.getAlpha());
    }
    
        final boolean more = moreStartEnter || moreStartExit || moreFinishEnter || moreFinishExit
                || moreRotateEnter || moreRotateExit || !mFinishAnimReady;
    public boolean startAndFinishAnimationLocked(long now) {
        if (!isAnimating()) {
            if (DEBUG_STATE) Slog.v(TAG, "Step: no animations running");
            return false;
        }

        if (DEBUG_STATE) Slog.v(TAG, "Step: more=" + more);
        if (!mAnimRunning) {
            if (DEBUG_STATE) Slog.v(TAG, "Step: starting start, finish, rotate");
            if (mStartEnterAnimation != null) {
                mStartEnterAnimation.setStartTime(now);
            }
            if (mStartExitAnimation != null) {
                mStartExitAnimation.setStartTime(now);
            }
            if (mFinishEnterAnimation != null) {
                mFinishEnterAnimation.setStartTime(0);
            }
            if (mFinishExitAnimation != null) {
                mFinishExitAnimation.setStartTime(0);
            }
            if (mRotateEnterAnimation != null) {
                mRotateEnterAnimation.setStartTime(now);
            }
            if (mRotateExitAnimation != null) {
                mRotateExitAnimation.setStartTime(now);
            }
            mAnimRunning = true;
        }
        
        return more;
        return true;
    }

    public Transformation getEnterTransformation() {
+55 −15
Original line number Diff line number Diff line
@@ -617,6 +617,18 @@ public class WindowManagerService extends IWindowManager.Stub
    final AnimationRunnable mAnimationRunnable = new AnimationRunnable();
    boolean mAnimationScheduled;

    interface StepAnimator {
        /**
         * Continue the stepping of an ongoing animation. When the animation completes this method
         * must disable the animation on the StepAnimator. 
         * @param currentTime Animation time in milliseconds. Use SystemClock.uptimeMillis().
         * @return True if the animation is still going on, false if the animation has completed
         *      and stepAnimation has cleared the animation locally.
         */
        boolean stepAnimation(long currentTime);
    }
    final ArrayList<StepAnimator> mStepAnimators = new ArrayList<StepAnimator>();
    
    final class DragInputEventReceiver extends InputEventReceiver {
        public DragInputEventReceiver(InputChannel inputChannel, Looper looper) {
            super(inputChannel, looper);
@@ -7614,6 +7626,20 @@ public class WindowManagerService extends IWindowManager.Stub
        }
    }

    /**
     * Run through each of the animating objects saved in mStepAnimators.
     */
    private void stepAnimations() {
        final long currentTime = SystemClock.uptimeMillis();
        for (final StepAnimator stepAnimator : mStepAnimators) {
            final boolean more = stepAnimator.stepAnimation(currentTime);
            if (DEBUG_ANIM) {
                Slog.v(TAG, "stepAnimations: " + currentTime + ": Stepped " + stepAnimator
                        + (more ? " more" : " done"));
            }
        }
    }
    
    /**
     * Extracted from {@link #performLayoutAndPlaceSurfacesLockedInner} to reduce size of method.
     * Update animations of all applications, including those associated with exiting/removed apps.
@@ -7621,31 +7647,33 @@ public class WindowManagerService extends IWindowManager.Stub
     * @param currentTime The time which animations use for calculating transitions.
     * @param innerDw Width of app window.
     * @param innerDh Height of app window.
     * @return true if rotation has stopped, false otherwise
     */
    private void updateWindowsAppsAndRotationAnimationsLocked(long currentTime,
                                                          int innerDw, int innerDh) {
        int i;
        for (i = mWindows.size() - 1; i >= 0; i--) {
            mInnerFields.mAnimating |= mWindows.get(i).stepAnimationLocked(currentTime);
        }

        final int NAT = mAppTokens.size();
        for (i=0; i<NAT; i++) {
            mInnerFields.mAnimating |=
                    mAppTokens.get(i).stepAnimationLocked(currentTime, innerDw, innerDh);
            final AppWindowToken appToken = mAppTokens.get(i);
            if (appToken.startAndFinishAnimationLocked(currentTime, innerDw, innerDh)) {
                mStepAnimators.add(appToken);
                mInnerFields.mAnimating = true;
            }
        }
        final int NEAT = mExitingAppTokens.size();
        for (i=0; i<NEAT; i++) {
            mInnerFields.mAnimating |=
                    mExitingAppTokens.get(i).stepAnimationLocked(currentTime, innerDw, innerDh);
            final AppWindowToken appToken = mAppTokens.get(i);
            if (appToken.startAndFinishAnimationLocked(currentTime, innerDw, innerDh)) {
                mStepAnimators.add(appToken);
                mInnerFields.mAnimating = true;
            }
        }

        if (mScreenRotationAnimation != null) {
            if (mScreenRotationAnimation.isAnimating()) {
                if (mScreenRotationAnimation.stepAnimation(currentTime)) {
                if (mScreenRotationAnimation.startAndFinishAnimationLocked(currentTime)) {
                    mInnerFields.mUpdateRotation = false;
                    mInnerFields.mAnimating = true;
                    mStepAnimators.add(mScreenRotationAnimation);
                } else {
                    mInnerFields.mUpdateRotation = true;
                    mScreenRotationAnimation.kill();
@@ -7704,7 +7732,13 @@ public class WindowManagerService extends IWindowManager.Stub
                }

                final boolean wasAnimating = w.mWasAnimating;
                final boolean nowAnimating = w.mLocalAnimating;
                
                
                final boolean nowAnimating = w.startAndFinishAnimationLocked(currentTime);
                if (nowAnimating) {
                    mStepAnimators.add(w);
                    mInnerFields.mAnimating = true;
                }

                if (DEBUG_WALLPAPER) {
                    Slog.v(TAG, w + ": wasAnimating=" + wasAnimating +
@@ -8290,6 +8324,10 @@ public class WindowManagerService extends IWindowManager.Stub
        // difficult because we do need to resize surfaces in some
        // cases while they are hidden such as when first showing a
        // window.
        
        if (mScreenRotationAnimation != null) {
            mScreenRotationAnimation.updateSurfaces();
        }
        boolean displayed = false;

        w.computeShownFrameLocked();
@@ -8562,7 +8600,7 @@ public class WindowManagerService extends IWindowManager.Stub
            // so we want to leave all of them as unblurred (for
            // performance reasons).
            mInnerFields.mObscured = true;
        } else if (canBeSeen && (attrFlags & FLAG_BLUR_BEHIND | FLAG_DIM_BEHIND) != 0) {
        } else if (canBeSeen && (attrFlags & (FLAG_BLUR_BEHIND | FLAG_DIM_BEHIND)) != 0) {
            if (localLOGV) Slog.v(TAG, "Win " + w
                    + ": blurring=" + mInnerFields.mBlurring
                    + " obscured=" + mInnerFields.mObscured);
@@ -8735,6 +8773,7 @@ public class WindowManagerService extends IWindowManager.Stub
                mInnerFields.mWindowAnimationBackground = null;
                mInnerFields.mWindowAnimationBackgroundColor = 0;

                mStepAnimators.clear();
                changes = updateWindowsAndWallpaperLocked(currentTime, dw, dh, innerDw, innerDh);

                if (mInnerFields.mTokenMayBeDrawn) {
@@ -8782,10 +8821,11 @@ public class WindowManagerService extends IWindowManager.Stub

            // Update animations of all applications, including those
            // associated with exiting/removed apps
            mInnerFields.mAnimating = false;

            updateWindowsAppsAndRotationAnimationsLocked(currentTime, innerDw, innerDh);
            
            stepAnimations();

            // THIRD LOOP: Update the surfaces of all windows.

            final boolean someoneLosingFocus = mLosingFocus.size() != 0;
@@ -9667,8 +9707,8 @@ public class WindowManagerService extends IWindowManager.Stub
            pw.println();
            pw.println("  Application tokens in Z order:");
            for (int i=mAppTokens.size()-1; i>=0; i--) {
                pw.print("  App #"); pw.print(i); pw.print(": ");
                        pw.println(mAppTokens.get(i));
                pw.print("  App #"); pw.print(i); pw.println(": ");
                        mAppTokens.get(i).dump(pw, "    ");
            }
        }
        if (mFinishedStarting.size() > 0) {
+21 −15
Original line number Diff line number Diff line
@@ -54,7 +54,8 @@ import java.util.ArrayList;
/**
 * A window in the window manager.
 */
final class WindowState implements WindowManagerPolicy.WindowState {
final class WindowState implements WindowManagerPolicy.WindowState,
        WindowManagerService.StepAnimator {
    static final boolean DEBUG_VISIBILITY = WindowManagerService.DEBUG_VISIBILITY;
    static final boolean SHOW_TRANSACTIONS = WindowManagerService.SHOW_TRANSACTIONS;
    static final boolean SHOW_LIGHT_TRANSACTIONS = WindowManagerService.SHOW_LIGHT_TRANSACTIONS;
@@ -977,9 +978,26 @@ final class WindowState implements WindowManagerPolicy.WindowState {
        return true;
    }

    @Override
    public boolean stepAnimation(long currentTime) {
        if ((mAnimation == null) || !mLocalAnimating) {
            return false;
        }
        mTransformation.clear();
        final boolean more = mAnimation.getTransformation(currentTime, mTransformation);
        if (WindowManagerService.DEBUG_ANIM) Slog.v(
            WindowManagerService.TAG, "Stepped animation in " + this +
            ": more=" + more + ", xform=" + mTransformation);
        if (!more) {
            mAnimation.cancel();
            mAnimation = null;
        }
        return more;
    }

    // This must be called while inside a transaction.  Returns true if
    // there is more animation to run.
    boolean stepAnimationLocked(long currentTime) {
    boolean startAndFinishAnimationLocked(long currentTime) {
        // Save the animation state as it was before this step so WindowManagerService can tell if
        // we just started or just stopped animating by comparing mWasAnimating with isAnimating().
        mWasAnimating = mAnimating;
@@ -1001,24 +1019,12 @@ final class WindowState implements WindowManagerPolicy.WindowState {
                    mLocalAnimating = true;
                    mAnimating = true;
                }
                mTransformation.clear();
                final boolean more = mAnimation.getTransformation(
                    currentTime, mTransformation);
                if (WindowManagerService.DEBUG_ANIM) Slog.v(
                    WindowManagerService.TAG, "Stepped animation in " + this +
                    ": more=" + more + ", xform=" + mTransformation);
                if (more) {
                    // we're not done!
                if ((mAnimation != null) && mLocalAnimating) {
                    return true;
                }
                if (WindowManagerService.DEBUG_ANIM) Slog.v(
                    WindowManagerService.TAG, "Finished animation in " + this +
                    " @ " + currentTime);

                if (mAnimation != null) {
                    mAnimation.cancel();
                    mAnimation = null;
                }
                //WindowManagerService.this.dump();
            }
            mHasLocalTransformation = false;