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

Commit 0288dc27 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Add predictive back support in origin transition backend." into main

parents a539e40a 5872195a
Loading
Loading
Loading
Loading
+88 −18
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@

package com.android.systemui.animation;

import static android.view.WindowManager.TRANSIT_CHANGE;

import android.animation.Animator;
import android.animation.Animator.AnimatorListener;
import android.animation.ValueAnimator;
@@ -39,6 +41,7 @@ import com.android.internal.policy.ScreenDecorationsUtils;
import com.android.wm.shell.shared.TransitionUtil;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
@@ -90,7 +93,7 @@ public class OriginRemoteTransition extends IRemoteTransition.Stub {
                () -> {
                    mStartTransaction = t;
                    mFinishCallback = finishCallback;
                    startAnimationInternal(info);
                    startAnimationInternal(info, /* states= */ null);
                });
    }

@@ -112,7 +115,13 @@ public class OriginRemoteTransition extends IRemoteTransition.Stub {
            SurfaceControl.Transaction t,
            IRemoteTransitionFinishedCallback finishCallback,
            WindowAnimationState[] states) {
        logD("takeOverAnimation - " + info);
        logD("takeOverAnimation - info=" + info + ", states=" + Arrays.toString(states));
        mHandler.post(
                () -> {
                    mStartTransaction = t;
                    mFinishCallback = finishCallback;
                    startAnimationInternal(info, states);
                });
    }

    @Override
@@ -121,14 +130,19 @@ public class OriginRemoteTransition extends IRemoteTransition.Stub {
        mHandler.post(this::cancel);
    }

    private void startAnimationInternal(TransitionInfo info) {
    private void startAnimationInternal(
            TransitionInfo info, @Nullable WindowAnimationState[] states) {
        if (!prepareUIs(info)) {
            logE("Unable to prepare UI!");
            finishAnimation(/* finished= */ false);
            return;
        }
        // Notify player that we are starting.
        mPlayer.onStart(info, mStartTransaction, mOrigin, mOriginTransaction);
        mPlayer.onStart(info, states, mStartTransaction, mOrigin, mOriginTransaction);

        // Apply the initial transactions in case the player forgot to apply them.
        mOriginTransaction.commit();
        mStartTransaction.apply();

        // Start the animator.
        mAnimator = ValueAnimator.ofFloat(0.0f, 1.0f);
@@ -205,7 +219,8 @@ public class OriginRemoteTransition extends IRemoteTransition.Stub {
                            .setCornerRadius(leash, windowRadius)
                            .setWindowCrop(leash, bounds.width(), bounds.height());
                }
            } else if (TransitionUtil.isClosingMode(mode)) {
            } else if (TransitionUtil.isClosingMode(mode) || mode == TRANSIT_CHANGE) {
                // TRANSIT_CHANGE refers to the closing window in predictive back animation.
                closingSurfaces.add(change.getLeash());
                // For closing surfaces, starting bounds are base bounds. Apply corner radius if
                // it's full screen.
@@ -236,13 +251,8 @@ public class OriginRemoteTransition extends IRemoteTransition.Stub {

        // Attach origin UIComponent to origin leash.
        mOriginTransaction = mOrigin.newTransaction();
        mOriginTransaction
                .attachToTransitionLeash(
                        mOrigin, mOriginLeash, displayBounds.width(), displayBounds.height())
                .commit();

        // Apply all surface changes.
        mStartTransaction.apply();
        mOriginTransaction.attachToTransitionLeash(
                mOrigin, mOriginLeash, displayBounds.width(), displayBounds.height());
        return true;
    }

@@ -328,6 +338,58 @@ public class OriginRemoteTransition extends IRemoteTransition.Stub {
                /* baseBounds= */ maxBounds);
    }

    private static void applyWindowAnimationStates(
            TransitionInfo info,
            @Nullable WindowAnimationState[] states,
            UIComponent closingApp,
            UIComponent openingApp) {
        if (states == null) {
            // Nothing to apply.
            return;
        }
        // Calculate bounds.
        Rect maxClosingBounds = new Rect();
        Rect maxOpeningBounds = new Rect();
        for (int i = 0; i < info.getChanges().size(); i++) {
            Rect bound = getBounds(states[i]);
            if (bound == null) {
                continue;
            }
            int mode = info.getChanges().get(i).getMode();
            if (TransitionUtil.isOpeningMode(mode)) {
                maxOpeningBounds.union(bound);
            } else if (TransitionUtil.isClosingMode(mode) || mode == TRANSIT_CHANGE) {
                // TRANSIT_CHANGE refers to the closing window in predictive back animation.
                maxClosingBounds.union(bound);
            }
        }

        // Intentionally use a new transaction instead of reusing the existing transaction since we
        // want to apply window animation states first without committing any other pending changes
        // in the existing transaction. The existing transaction is expected to be committed by the
        // onStart() client callback together with client's custom transformation.
        UIComponent.Transaction transaction = closingApp.newTransaction();
        if (!maxClosingBounds.isEmpty()) {
            logD("Applying closing window bounds: " + maxClosingBounds);
            transaction.setBounds(closingApp, maxClosingBounds);
        }
        if (!maxOpeningBounds.isEmpty()) {
            logD("Applying opening window bounds: " + maxOpeningBounds);
            transaction.setBounds(openingApp, maxOpeningBounds);
        }
        transaction.commit();
    }

    @Nullable
    private static Rect getBounds(@Nullable WindowAnimationState state) {
        if (state == null || state.bounds == null) {
            return null;
        }
        Rect out = new Rect();
        state.bounds.roundOut(out);
        return out;
    }

    /**
     * An interface that represents an origin transitions.
     *
@@ -338,9 +400,14 @@ public class OriginRemoteTransition extends IRemoteTransition.Stub {
        /**
         * Called when an origin transition starts. This method exposes the raw {@link
         * TransitionInfo} so that clients can extract more information from it.
         *
         * <p>Note: if this transition is taking over a predictive back animation, the {@link
         * WindowAnimationState} will be passed to this method. The concrete implementation is
         * expected to apply the {@link WindowAnimationState} before continuing the transition.
         */
        default void onStart(
                TransitionInfo transitionInfo,
                @Nullable WindowAnimationState[] states,
                SurfaceControl.Transaction sfTransaction,
                UIComponent origin,
                UIComponent.Transaction uiTransaction) {
@@ -351,12 +418,15 @@ public class OriginRemoteTransition extends IRemoteTransition.Stub {
                            .registerTransactionForClass(
                                    SurfaceUIComponent.class,
                                    new SurfaceUIComponent.Transaction(sfTransaction));
            // Wrap surfaces and start.
            onStart(
                    transactions,
                    origin,
                    wrapSurfaces(transitionInfo, /* isOpening= */ false),
                    wrapSurfaces(transitionInfo, /* isOpening= */ true));
            // Wrap surfaces.
            UIComponent closingApp = wrapSurfaces(transitionInfo, /* isOpening= */ false);
            UIComponent openingApp = wrapSurfaces(transitionInfo, /* isOpening= */ true);

            // Restore the pending animation states coming from predictive back transition.
            applyWindowAnimationStates(transitionInfo, states, closingApp, openingApp);

            // Start.
            onStart(transactions, origin, closingApp, openingApp);
        }

        /**
+7 −2
Original line number Diff line number Diff line
@@ -89,7 +89,6 @@ public class ViewUIComponent implements UIComponent {
        mSurfaceControl =
                new SurfaceControl.Builder().setName("ViewUIComponent").setBufferSize(w, h).build();
        mSurface = new Surface(mSurfaceControl);
        forceDraw();

        // Attach surface to transition leash
        SurfaceControl.Transaction t = new SurfaceControl.Transaction();
@@ -99,7 +98,13 @@ public class ViewUIComponent implements UIComponent {
        mView.getViewTreeObserver().addOnDrawListener(mOnDrawListener);

        // Make the view invisible AFTER the surface is shown.
        t.addTransactionCommittedListener(mView::post, () -> mView.setVisibility(View.INVISIBLE))
        t.addTransactionCommittedListener(
                        mView::post,
                        () -> {
                            logD("Surface attached!");
                            forceDraw();
                            mView.setVisibility(View.INVISIBLE);
                        })
                .apply();
    }

+66 −20
Original line number Diff line number Diff line
@@ -16,8 +16,10 @@

package com.android.systemui.animation.server;

import static android.view.WindowManager.TRANSIT_CHANGE;
import static android.view.WindowManager.TRANSIT_CLOSE;
import static android.view.WindowManager.TRANSIT_OPEN;
import static android.view.WindowManager.TRANSIT_PREPARE_BACK_NAVIGATION;
import static android.view.WindowManager.TRANSIT_TO_BACK;
import static android.view.WindowManager.TRANSIT_TO_FRONT;

@@ -26,6 +28,7 @@ import android.annotation.Nullable;
import android.app.TaskInfo;
import android.content.ComponentName;
import android.content.Context;
import android.os.Build;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.ArrayMap;
@@ -51,8 +54,8 @@ import java.util.function.Predicate;

/** An implementation of the {@link IOriginTransitions}. */
public class IOriginTransitionsImpl extends IOriginTransitions.Stub {
    private static final boolean DEBUG = true;
    private static final String TAG = "OriginTransitions";
    private static final boolean DEBUG = Build.IS_USERDEBUG || Log.isLoggable(TAG, Log.DEBUG);

    private final Object mLock = new Object();
    private final ShellTransitions mShellTransitions;
@@ -149,18 +152,7 @@ public class IOriginTransitionsImpl extends IOriginTransitions.Stub {
            if (DEBUG) {
                Log.d(TAG, "startAnimation: " + info);
            }
            if (!mOnStarting.test(info)) {
                Log.w(TAG, "Skipping cancelled transition " + mTransition);
                t.addTransactionCommittedListener(
                                mExecutor,
                                () -> {
                                    try {
                                        finishCallback.onTransitionFinished(null, null);
                                    } catch (RemoteException e) {
                                        Log.e(TAG, "Unable to report finish.", e);
                                    }
                                })
                        .apply();
            if (maybeInterceptTransition(info, t, finishCallback)) {
                return;
            }
            mTransition.startAnimation(token, info, t, finishCallback);
@@ -191,6 +183,9 @@ public class IOriginTransitionsImpl extends IOriginTransitions.Stub {
            if (DEBUG) {
                Log.d(TAG, "takeOverAnimation: " + info);
            }
            if (maybeInterceptTransition(info, t, finishCallback)) {
                return;
            }
            mTransition.takeOverAnimation(transition, info, t, finishCallback, states);
        }

@@ -207,6 +202,27 @@ public class IOriginTransitionsImpl extends IOriginTransitions.Stub {
        public String toString() {
            return "RemoteTransitionDelegate{transition=" + mTransition + "}";
        }

        private boolean maybeInterceptTransition(
                TransitionInfo info,
                SurfaceControl.Transaction t,
                IRemoteTransitionFinishedCallback finishCallback) {
            if (!mOnStarting.test(info)) {
                Log.w(TAG, "Intercepting cancelled transition " + mTransition);
                t.addTransactionCommittedListener(
                                mExecutor,
                                () -> {
                                    try {
                                        finishCallback.onTransitionFinished(null, null);
                                    } catch (RemoteException e) {
                                        Log.e(TAG, "Unable to report finish.", e);
                                    }
                                })
                        .apply();
                return true;
            }
            return false;
        }
    }

    /** A data record containing the origin transition pieces. */
@@ -229,13 +245,25 @@ public class IOriginTransitionsImpl extends IOriginTransitions.Stub {
                if (mDestroyed) {
                    return false;
                }
                TransitionFilter filter = createFilterForReverseTransition(info);
                TransitionFilter filter =
                        createFilterForReverseTransition(
                                info, /* forPredictiveBackTakeover= */ false);
                if (filter != null) {
                    if (DEBUG) {
                        Log.d(TAG, "Registering filter " + filter);
                    }
                    mShellTransitions.registerRemote(filter, mWrappedReturnTransition);
                }
                TransitionFilter takeoverFilter =
                        createFilterForReverseTransition(
                                info, /* forPredictiveBackTakeover= */ true);
                if (takeoverFilter != null) {
                    if (DEBUG) {
                        Log.d(TAG, "Registering filter for takeover " + takeoverFilter);
                    }
                    mShellTransitions.registerRemoteForTakeover(
                            takeoverFilter, mWrappedReturnTransition);
                }
                return true;
            }
        }
@@ -331,7 +359,8 @@ public class IOriginTransitionsImpl extends IOriginTransitions.Stub {
        }

        @Nullable
        private static TransitionFilter createFilterForReverseTransition(TransitionInfo info) {
        private static TransitionFilter createFilterForReverseTransition(
                TransitionInfo info, boolean forPredictiveBackTakeover) {
            TaskInfo launchingTaskInfo = null;
            TaskInfo launchedTaskInfo = null;
            ComponentName launchingActivity = null;
@@ -365,7 +394,9 @@ public class IOriginTransitionsImpl extends IOriginTransitions.Stub {
            if (DEBUG) {
                Log.d(
                        TAG,
                        "createFilterForReverseTransition: launchingTaskInfo="
                        "createFilterForReverseTransition: forPredictiveBackTakeover="
                                + forPredictiveBackTakeover
                                + ", launchingTaskInfo="
                                + launchingTaskInfo
                                + ", launchedTaskInfo="
                                + launchedTaskInfo
@@ -395,8 +426,20 @@ public class IOriginTransitionsImpl extends IOriginTransitions.Stub {
                                + " cookie!");
                return null;
            }
            if (forPredictiveBackTakeover && launchedTaskInfo == null) {
                // Predictive back take over currently only support cross-task transition.
                Log.d(
                        TAG,
                        "createFilterForReverseTransition: skipped - unable to find launched task"
                                + " for predictive back takeover");
                return null;
            }
            TransitionFilter filter = new TransitionFilter();
            if (forPredictiveBackTakeover) {
                filter.mTypeSet = new int[] {TRANSIT_PREPARE_BACK_NAVIGATION};
            } else {
                filter.mTypeSet = new int[] {TRANSIT_CLOSE, TRANSIT_TO_BACK};
            }

            // The opening activity of the return transition must match the activity we just closed.
            TransitionFilter.Requirement req1 = new TransitionFilter.Requirement();
@@ -405,15 +448,18 @@ public class IOriginTransitionsImpl extends IOriginTransitions.Stub {
                    launchingActivity == null ? launchingTaskInfo.topActivity : launchingActivity;

            TransitionFilter.Requirement req2 = new TransitionFilter.Requirement();
            if (forPredictiveBackTakeover) {
                req2.mModes = new int[] {TRANSIT_CHANGE};
            } else {
                req2.mModes = new int[] {TRANSIT_CLOSE, TRANSIT_TO_BACK};
            }
            if (launchedTaskInfo != null) {
                // For task transitions, the closing task's cookie must match the task we just
                // launched.
                req2.mLaunchCookie = launchedTaskInfo.launchCookies.get(0);
            } else {
                // For activity transitions, the closing activity of the return transition must
                // match
                // the activity we just launched.
                // match the activity we just launched.
                req2.mTopActivity = launchedActivity;
            }