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

Commit 77b2b34f authored by Riddle Hsu's avatar Riddle Hsu
Browse files

Tweak animation for non-app windows with shell fixed rotation

To make it have the same behavior as legacy transition:
The bars are faded out when starting fixed rotation, and faded in
after display rotation change is completed. And the independent
seamless window such as round corner can keep showing on screen
seamlessly.

Also skip animation for seamless display change. Otherwise there will
be a no-op alpha animation with DEFAULT_APP_TRANSITION_DURATION=336ms
that adds unnecessary delay to finish the transition.

Bug: 221223435
Test: atest TransitionTests#testAppTransitionWithRotationChange
Change-Id: I3b1db4956b642fabb6061c7dbf0f7b2b8e1e300f
parent de4a9a6a
Loading
Loading
Loading
Loading
+5 −2
Original line number Diff line number Diff line
@@ -348,12 +348,13 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
        for (int i = info.getChanges().size() - 1; i >= 0; --i) {
            final TransitionInfo.Change change = info.getChanges().get(i);
            final boolean isTask = change.getTaskInfo() != null;
            boolean isSeamlessDisplayChange = false;

            if (change.getMode() == TRANSIT_CHANGE && (change.getFlags() & FLAG_IS_DISPLAY) != 0) {
                if (info.getType() == TRANSIT_CHANGE) {
                    boolean isSeamless = isRotationSeamless(info, mDisplayController);
                    isSeamlessDisplayChange = isRotationSeamless(info, mDisplayController);
                    final int anim = getRotationAnimation(info);
                    if (!(isSeamless || anim == ROTATION_ANIMATION_JUMPCUT)) {
                    if (!(isSeamlessDisplayChange || anim == ROTATION_ANIMATION_JUMPCUT)) {
                        mRotationAnimation = new ScreenRotationAnimation(mContext, mSurfaceSession,
                                mTransactionPool, startTransaction, change, info.getRootLeash(),
                                anim);
@@ -387,6 +388,8 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
                startTransaction.setPosition(change.getLeash(),
                        change.getEndAbsBounds().left - info.getRootOffset().x,
                        change.getEndAbsBounds().top - info.getRootOffset().y);
                // Seamless display transition doesn't need to animate.
                if (isSeamlessDisplayChange) continue;
                if (isTask) {
                    // Skip non-tasks since those usually have null bounds.
                    startTransaction.setWindowCrop(change.getLeash(),
+32 −17
Original line number Diff line number Diff line
@@ -94,6 +94,9 @@ class AsyncRotationController extends FadeAnimationController implements Consume
    /** Whether the start transaction of the transition is committed (by shell). */
    private boolean mIsStartTransactionCommitted;

    /** Whether the target windows have been requested to sync their draw transactions. */
    private boolean mIsSyncDrawRequested;

    private SeamlessRotator mRotator;

    private final int mOriginalRotation;
@@ -139,22 +142,10 @@ class AsyncRotationController extends FadeAnimationController implements Consume
        displayContent.forAllWindows(this, true /* traverseTopToBottom */);

        // Legacy animation doesn't need to wait for the start transaction.
        mIsStartTransactionCommitted = mTransitionOp == OP_LEGACY;
        if (mIsStartTransactionCommitted) return;
        // The transition sync group may be finished earlier because it doesn't wait for these
        // target windows. But the windows still need to use sync transaction to keep the appearance
        // in previous rotation, so request a no-op sync to keep the state.
        for (int i = mTargetWindowTokens.size() - 1; i >= 0; i--) {
            if (mHasScreenRotationAnimation
                    && mTargetWindowTokens.valueAt(i).mAction == Operation.ACTION_FADE) {
                // The windows are hidden (leash is alpha 0) before finishing drawing so it is
                // unnecessary to request sync.
                continue;
            }
            final WindowToken token = mTargetWindowTokens.keyAt(i);
            for (int j = token.getChildCount() - 1; j >= 0; j--) {
                token.getChildAt(j).applyWithNextDraw(t -> {});
            }
        if (mTransitionOp == OP_LEGACY) {
            mIsStartTransactionCommitted = true;
        } else if (displayContent.mTransitionController.useShellTransitionsRotation()) {
            keepAppearanceInPreviousRotation();
        }
    }

@@ -194,6 +185,30 @@ class AsyncRotationController extends FadeAnimationController implements Consume
        mTargetWindowTokens.put(w.mToken, new Operation(action));
    }

    /**
     * Enables {@link #handleFinishDrawing(WindowState, SurfaceControl.Transaction)} to capture the
     * draw transactions of the target windows if needed.
     */
    void keepAppearanceInPreviousRotation() {
        // The transition sync group may be finished earlier because it doesn't wait for these
        // target windows. But the windows still need to use sync transaction to keep the appearance
        // in previous rotation, so request a no-op sync to keep the state.
        for (int i = mTargetWindowTokens.size() - 1; i >= 0; i--) {
            if (mHasScreenRotationAnimation
                    && mTargetWindowTokens.valueAt(i).mAction == Operation.ACTION_FADE) {
                // The windows are hidden (leash is alpha 0) before finishing drawing so it is
                // unnecessary to request sync.
                continue;
            }
            final WindowToken token = mTargetWindowTokens.keyAt(i);
            for (int j = token.getChildCount() - 1; j >= 0; j--) {
                token.getChildAt(j).applyWithNextDraw(t -> {});
            }
        }
        mIsSyncDrawRequested = true;
        if (DEBUG) Slog.d(TAG, "Requested to sync draw transaction");
    }

    /** Lets the window fit in new rotation naturally. */
    private void finishOp(WindowToken windowToken) {
        final Operation op = mTargetWindowTokens.remove(windowToken);
@@ -433,7 +448,7 @@ class AsyncRotationController extends FadeAnimationController implements Consume
     */
    boolean handleFinishDrawing(WindowState w, SurfaceControl.Transaction postDrawTransaction) {
        if (mTransitionOp == OP_LEGACY || postDrawTransaction == null
                || !w.mTransitionController.inTransition()) {
                || !mIsSyncDrawRequested || !w.mTransitionController.inTransition()) {
            return false;
        }
        final Operation op = mTargetWindowTokens.get(w.mToken);
+19 −12
Original line number Diff line number Diff line
@@ -1736,19 +1736,19 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
    }

    void setFixedRotationLaunchingAppUnchecked(@Nullable ActivityRecord r, int rotation) {
        final boolean useAsyncRotation = !mTransitionController.isShellTransitionsEnabled();
        if (mFixedRotationLaunchingApp == null && r != null) {
            mWmService.mDisplayNotificationController.dispatchFixedRotationStarted(this,
                    rotation);
            if (useAsyncRotation) {
                startAsyncRotation(
                        // Delay the hide animation to avoid blinking by clicking navigation bar
                        // that may toggle fixed rotation in a short time.
                        r == mFixedRotationTransitionListener.mAnimatingRecents);
            }
            mWmService.mDisplayNotificationController.dispatchFixedRotationStarted(this, rotation);
            // Delay the hide animation to avoid blinking by clicking navigation bar that may
            // toggle fixed rotation in a short time.
            final boolean shouldDebounce = r == mFixedRotationTransitionListener.mAnimatingRecents
                    || mTransitionController.isTransientLaunch(r);
            startAsyncRotation(shouldDebounce);
        } else if (mFixedRotationLaunchingApp != null && r == null) {
            mWmService.mDisplayNotificationController.dispatchFixedRotationFinished(this);
            if (useAsyncRotation) finishAsyncRotationIfPossible();
            // Keep async rotation controller if the next transition of display is requested.
            if (!mTransitionController.isCollecting(this)) {
                finishAsyncRotationIfPossible();
            }
        }
        mFixedRotationLaunchingApp = r;
    }
@@ -1806,7 +1806,6 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
        }
        // Update directly because the app which will change the orientation of display is ready.
        if (mDisplayRotation.updateOrientation(getOrientation(), false /* forceUpdate */)) {
            mTransitionController.setSeamlessRotation(this);
            sendNewConfiguration();
            return;
        }
@@ -3235,7 +3234,15 @@ class DisplayContent extends RootDisplayArea implements WindowManagerPolicy.Disp
                this, this, null /* remoteTransition */, displayChange);
        if (t != null) {
            mAtmService.startLaunchPowerMode(POWER_MODE_REASON_CHANGE_DISPLAY);
            if (isRotationChanging()) {
            if (mFixedRotationLaunchingApp != null) {
                // A fixed-rotation transition is done, then continue to start a seamless display
                // transition. And be fore the start transaction is applied, the non-app windows
                // need to keep in previous rotation to avoid showing inconsistent content.
                t.setSeamlessRotation(this);
                if (mAsyncRotationController != null) {
                    mAsyncRotationController.keepAppearanceInPreviousRotation();
                }
            } else if (isRotationChanging()) {
                mWmService.mLatencyTracker.onActionStart(ACTION_ROTATE_SCREEN);
                controller.mTransitionMetricsReporter.associate(t,
                        startTime -> mWmService.mLatencyTracker.onActionEnd(ACTION_ROTATE_SCREEN));
+2 −2
Original line number Diff line number Diff line
@@ -548,7 +548,7 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
        for (int i = 0; i < mTargetDisplays.size(); ++i) {
            final DisplayContent dc = mTargetDisplays.get(i);
            final AsyncRotationController asyncRotationController = dc.getAsyncRotationController();
            if (asyncRotationController != null) {
            if (asyncRotationController != null && mTargets.contains(dc)) {
                asyncRotationController.onTransitionFinished();
            }
            if (mTransientLaunches != null) {
@@ -696,7 +696,7 @@ class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListe
        // This is non-null only if display has changes. It handles the visible windows that don't
        // need to be participated in the transition.
        final AsyncRotationController controller = dc.getAsyncRotationController();
        if (controller != null) {
        if (controller != null && mTargets.contains(dc)) {
            controller.setupStartTransaction(transaction);
        }
        mStartTransaction = transaction;
+0 −5
Original line number Diff line number Diff line
@@ -519,11 +519,6 @@ class TransitionController {
        }
    }

    void setSeamlessRotation(@NonNull WindowContainer wc) {
        if (mCollectingTransition == null) return;
        mCollectingTransition.setSeamlessRotation(wc);
    }

    void legacyDetachNavigationBarFromApp(@NonNull IBinder token) {
        final Transition transition = Transition.fromBinder(token);
        if (transition == null || !mPlayingTransitions.contains(transition)) {
Loading