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

Commit 37b2b6ab authored by Riddle Hsu's avatar Riddle Hsu Committed by Android (Google) Code Review
Browse files

Merge "Handle non-app windows in app rotation transition asynchronously"

parents 3beb2c61 2c90f3b1
Loading
Loading
Loading
Loading
+15 −6
Original line number Diff line number Diff line
@@ -1843,6 +1843,17 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
        }
    }

    /** Returns {@code true} if the decided new rotation has not applied to configuration yet. */
    private boolean isRotationChanging() {
        return mDisplayRotation.getRotation() != getWindowConfiguration().getRotation();
    }

    private void startFadeRotationAnimationIfNeeded() {
        if (isRotationChanging()) {
            startFadeRotationAnimation(false /* shouldDebounce */);
        }
    }

    /**
     * Starts the hide animation for the windows which will be rotated seamlessly.
     *
@@ -3189,11 +3200,8 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp

        // Hide the windows which are not significant in rotation animation. So that the windows
        // don't need to block the unfreeze time.
        if (screenRotationAnimation != null && screenRotationAnimation.hasScreenshot()
                // Do not fade for freezing without rotation change.
                && mDisplayRotation.getRotation() != getWindowConfiguration().getRotation()
                && mFadeRotationAnimationController == null) {
            startFadeRotationAnimation(false /* shouldDebounce */);
        if (screenRotationAnimation != null && screenRotationAnimation.hasScreenshot()) {
            startFadeRotationAnimationIfNeeded();
        }
    }

@@ -3214,6 +3222,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
            }
            if (!controller.isCollecting(this)) {
                controller.collect(this);
                startFadeRotationAnimationIfNeeded();
            }
            return;
        }
@@ -3221,7 +3230,7 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
                this, this, null /* remoteTransition */, displayChange);
        if (t != null) {
            mAtmService.startLaunchPowerMode(POWER_MODE_REASON_CHANGE_DISPLAY);
            if (getRotation() != getWindowConfiguration().getRotation()) {
            if (isRotationChanging()) {
                mWmService.mLatencyTracker.onActionStart(ACTION_ROTATE_SCREEN);
                controller.mTransitionMetricsReporter.associate(t,
                        startTime -> mWmService.mLatencyTracker.onActionEnd(ACTION_ROTATE_SCREEN));
+6 −19
Original line number Diff line number Diff line
@@ -21,7 +21,6 @@ import static com.android.server.wm.WindowAnimationSpecProto.ANIMATION;

import android.annotation.NonNull;
import android.content.Context;
import android.util.ArrayMap;
import android.util.proto.ProtoOutputStream;
import android.view.SurfaceControl;
import android.view.animation.Animation;
@@ -38,7 +37,6 @@ import java.io.PrintWriter;
public class FadeAnimationController {
    protected final DisplayContent mDisplayContent;
    protected final Context mContext;
    protected final ArrayMap<WindowToken, Runnable> mDeferredFinishCallbacks = new ArrayMap<>();

    public FadeAnimationController(DisplayContent displayContent) {
        mDisplayContent = displayContent;
@@ -78,16 +76,8 @@ public class FadeAnimationController {
            return;
        }

        // We deferred the end of the animation when hiding the token, so we need to end it now that
        // it's shown again.
        final SurfaceAnimator.OnAnimationFinishedCallback finishedCallback = show ? (t, r) -> {
            final Runnable runnable = mDeferredFinishCallbacks.remove(windowToken);
            if (runnable != null) {
                runnable.run();
            }
        } : null;
        windowToken.startAnimation(windowToken.getPendingTransaction(), animationAdapter,
                show /* hidden */, animationType, finishedCallback);
                show /* hidden */, animationType, null /* finishedCallback */);
    }

    protected FadeAnimationAdapter createAdapter(LocalAnimationAdapter.AnimationSpec animationSpec,
@@ -135,7 +125,7 @@ public class FadeAnimationController {
        };
    }

    protected class FadeAnimationAdapter extends LocalAnimationAdapter {
    protected static class FadeAnimationAdapter extends LocalAnimationAdapter {
        protected final boolean mShow;
        protected final WindowToken mToken;

@@ -149,13 +139,10 @@ public class FadeAnimationController {

        @Override
        public boolean shouldDeferAnimationFinish(Runnable endDeferFinishCallback) {
            // We defer the end of the hide animation to ensure the tokens stay hidden until
            // we show them again.
            if (!mShow) {
                mDeferredFinishCallbacks.put(mToken, endDeferFinishCallback);
                return true;
            }
            return false;
            // Defer the finish callback (restore leash) of the hide animation to ensure the token
            // stay hidden until it needs to show again. Besides, when starting the show animation,
            // the previous hide animation will be cancelled, so the callback can be ignored.
            return !mShow;
        }
    }
}
+86 −14
Original line number Diff line number Diff line
@@ -50,7 +50,7 @@ public class FadeRotationAnimationController extends FadeAnimationController {
    /** Whether to use constant zero alpha animation. */
    private boolean mHideImmediately;

    /** Whether this controller is triggered from shell transition. */
    /** Whether this controller is triggered from shell transition with type CHANGE. */
    private final boolean mIsChangeTransition;

    /** Whether the start transaction of the transition is committed (by shell). */
@@ -59,21 +59,30 @@ public class FadeRotationAnimationController extends FadeAnimationController {
    /** The list to store the drawn tokens before the rotation animation starts. */
    private ArrayList<WindowToken> mPendingShowTokens;

    /** It is used when the display has rotated, but some windows fade out in old rotation. */
    private SeamlessRotator mRotator;

    private final int mOriginalRotation;
    private final boolean mHasScreenRotationAnimation;

    public FadeRotationAnimationController(DisplayContent displayContent) {
        super(displayContent);
        mService = displayContent.mWmService;
        mIsChangeTransition = displayContent.inTransition()
                && displayContent.mTransitionController.getCollectingTransitionType()
                == WindowManager.TRANSIT_CHANGE;
        mOriginalRotation = displayContent.getWindowConfiguration().getRotation();
        final int transitionType =
                displayContent.mTransitionController.getCollectingTransitionType();
        mIsChangeTransition = transitionType == WindowManager.TRANSIT_CHANGE;
        // Only CHANGE type (rotation animation) needs to wait for the start transaction.
        mIsStartTransactionCommitted = !mIsChangeTransition;
        mTimeoutRunnable = displayContent.getRotationAnimation() != null
                || mIsChangeTransition ? () -> {
        mTimeoutRunnable = displayContent.inTransition() ? () -> {
            synchronized (mService.mGlobalLock) {
                displayContent.finishFadeRotationAnimationIfPossible();
                mService.mWindowPlacerLocked.performSurfacePlacement();
            }
        } : null;
        if (mTimeoutRunnable != null) {
        mHasScreenRotationAnimation =
                displayContent.getRotationAnimation() != null || mIsChangeTransition;
        if (mHasScreenRotationAnimation) {
            // Hide the windows immediately because screen should have been covered by screenshot.
            mHideImmediately = true;
        }
@@ -103,6 +112,19 @@ public class FadeRotationAnimationController extends FadeAnimationController {
        }, true /* traverseTopToBottom */);
    }

    @Override
    public void fadeWindowToken(boolean show, WindowToken windowToken, int animationType) {
        if (show) {
            final SurfaceControl leash = mTargetWindowTokens.remove(windowToken);
            if (leash != null && mRotator != null) {
                // The leash was unrotated by start transaction of transition. Clear the transform
                // to reshow the window in current rotation.
                mRotator.setIdentityMatrix(mDisplayContent.getPendingTransaction(), leash);
            }
        }
        super.fadeWindowToken(show, windowToken, animationType);
    }

    /** Applies show animation on the previously hidden window tokens. */
    void show() {
        for (int i = mTargetWindowTokens.size() - 1; i >= 0; i--) {
@@ -125,19 +147,23 @@ public class FadeRotationAnimationController extends FadeAnimationController {
     * controller is created for normal rotation.
     */
    boolean show(WindowToken token) {
        if (!isTargetToken(token)) return false;
        if (!mIsStartTransactionCommitted) {
            // The fade-in animation should only start after the screenshot layer is shown by shell.
            // Otherwise the window will be blinking before the rotation animation starts. So store
            // to a pending list and animate them until the transaction is committed.
            if (mTargetWindowTokens.containsKey(token)) {
            if (mPendingShowTokens == null) {
                mPendingShowTokens = new ArrayList<>();
            }
            mPendingShowTokens.add(token);
            return false;
        }
        if (!mHasScreenRotationAnimation && token.mTransitionController.inTransition()) {
            // Defer showing to onTransitionFinished().
            return false;
        }
        if (mTimeoutRunnable != null && mTargetWindowTokens.remove(token) != null) {
        // If the timeout runnable is null (fixed rotation), the case will be handled by show().
        if (mTimeoutRunnable != null) {
            fadeWindowToken(true /* show */, token, ANIMATION_TYPE_FIXED_TRANSFORM);
            if (mTargetWindowTokens.isEmpty()) {
                mService.mH.removeCallbacks(mTimeoutRunnable);
@@ -177,6 +203,15 @@ public class FadeRotationAnimationController extends FadeAnimationController {
        return mTargetWindowTokens.containsKey(token);
    }

    /**
     * Whether the insets animation leash should use previous position when running fade out
     * animation in rotated display.
     */
    boolean shouldFreezeInsetsPosition(WindowState w) {
        return !mHasScreenRotationAnimation && w.mTransitionController.inTransition()
                && isTargetToken(w.mToken);
    }

    void setOnShowRunnable(Runnable onShowRunnable) {
        mOnShowRunnable = onShowRunnable;
    }
@@ -186,6 +221,22 @@ public class FadeRotationAnimationController extends FadeAnimationController {
     * transition starts. And associate transaction callback to consume pending animations.
     */
    void setupStartTransaction(SurfaceControl.Transaction t) {
        if (!mIsChangeTransition) {
            // Take OPEN/CLOSE transition type as the example, the non-activity windows need to
            // fade out in previous rotation while display has rotated to the new rotation, so
            // their leashes are unrotated with the start transaction.
            mRotator = new SeamlessRotator(mOriginalRotation,
                    mDisplayContent.getWindowConfiguration().getRotation(),
                    mDisplayContent.getDisplayInfo(),
                    false /* applyFixedTransformationHint */);
            for (int i = mTargetWindowTokens.size() - 1; i >= 0; i--) {
                final SurfaceControl leash = mTargetWindowTokens.valueAt(i);
                if (leash != null) {
                    mRotator.applyTransform(t, leash);
                }
            }
            return;
        }
        // Hide the windows immediately because a screenshot layer should cover the screen.
        for (int i = mTargetWindowTokens.size() - 1; i >= 0; i--) {
            final SurfaceControl leash = mTargetWindowTokens.valueAt(i);
@@ -208,9 +259,30 @@ public class FadeRotationAnimationController extends FadeAnimationController {
        });
    }

    void onTransitionFinished() {
        if (mIsChangeTransition) {
            // With screen rotation animation, the windows are always faded in when they are drawn.
            // Because if they are drawn fast enough, the fade animation should not be observable.
            return;
        }
        // For other transition types, the fade-in animation runs after the transition to make the
        // transition animation (e.g. launch activity) look cleaner.
        for (int i = mTargetWindowTokens.size() - 1; i >= 0; i--) {
            final WindowToken token = mTargetWindowTokens.keyAt(i);
            for (int j = token.getChildCount() - 1; j >= 0; j--) {
                // Only fade in the drawn windows. If the remaining windows are drawn later,
                // show(WindowToken) will be called to fade in them.
                if (token.getChildAt(j).isDrawFinishedLw()) {
                    mDisplayContent.finishFadeRotationAnimation(token);
                    break;
                }
            }
        }
    }

    @Override
    public Animation getFadeInAnimation() {
        if (mTimeoutRunnable != null) {
        if (mHasScreenRotationAnimation) {
            // Use a shorter animation so it is easier to align with screen rotation animation.
            return AnimationUtils.loadAnimation(mContext, R.anim.screen_rotate_0_enter);
        }
+8 −0
Original line number Diff line number Diff line
@@ -297,6 +297,14 @@ class InsetsSourceProvider {
    }

    private Point getWindowFrameSurfacePosition() {
        if (mControl != null) {
            final FadeRotationAnimationController fadeController =
                    mWin.mDisplayContent.getFadeRotationAnimationController();
            if (fadeController != null && fadeController.shouldFreezeInsetsPosition(mWin)) {
                // Use previous position because the fade-out animation runs in old rotation.
                return mControl.getSurfacePosition();
            }
        }
        final Rect frame = mWin.getFrame();
        final Point position = new Point();
        mWin.transformFrameToSurfacePosition(frame.left, frame.top, position);
+0 −8
Original line number Diff line number Diff line
@@ -95,14 +95,6 @@ public class NavBarFadeAnimationController extends FadeAnimationController{
            } else {
                fadeAnim.run();
            }
        } else {
            // If fade rotation animation is running and controlling the nav bar, make sure we empty
            // the mDeferredFinishCallbacks and defer the runnable until fade rotation animation
            // finishes.
            final Runnable runnable = mDeferredFinishCallbacks.remove(mNavigationBar.mToken);
            if (runnable != null) {
                controller.setOnShowRunnable(runnable);
            }
        }
    }

Loading