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

Commit bee9f829 authored by Luca Zuccarini's avatar Luca Zuccarini Committed by Android (Google) Code Review
Browse files

Merge "Animation takeovers in Predictive Back." into main

parents 34117946 3c2f615f
Loading
Loading
Loading
Loading
+40 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License

 */

package android.window;

import android.os.Bundle;
import android.view.RemoteAnimationTarget;
import android.window.BackMotionEvent;
import android.window.WindowAnimationState;


/**
 * Interface that allows an {@link OnBackInvokedCallback} object to hand off an animation to another
 * handler.
 *
 * @hide
 */
oneway interface IBackAnimationHandoffHandler {
    /**
     * Triggers a handoff of the animation of the given targets and their associated states.
     * Important: since this is a one-way method, the caller must first make sure that the animation
     * can indeed be taken over.
     */
    oneway void handOffAnimation(in RemoteAnimationTarget[] targets,
                    in WindowAnimationState[] states);
}
+6 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@
package android.window;

import android.window.BackMotionEvent;
import android.window.IBackAnimationHandoffHandler;

/**
 * Interface that wraps a {@link OnBackInvokedCallback} object, to be stored in window manager
@@ -61,4 +62,9 @@ oneway interface IOnBackInvokedCallback {
     * Sets whether the back gesture is past the trigger threshold.
     */
    void setTriggerBack(in boolean triggerBack);

   /**
    * Sets a {@link IBackAnimationHandoffHandler} that can be used to hand off the back animation.
    */
    void setHandoffHandler(in IBackAnimationHandoffHandler handoffHandler);
}
+5 −0
Original line number Diff line number Diff line
@@ -392,6 +392,11 @@ public class ImeOnBackInvokedDispatcher implements OnBackInvokedDispatcher, Parc
            // no-op
        }

        @Override
        public void setHandoffHandler(IBackAnimationHandoffHandler handoffHandler) {
            // no-op
        }

        private void maybeRunOnAnimationCallback(Consumer<OnBackAnimationCallback> block) {
            if (mCallback instanceof OnBackAnimationCallback) {
                mHandler.post(() -> block.accept((OnBackAnimationCallback) mCallback));
+5 −0
Original line number Diff line number Diff line
@@ -545,6 +545,11 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
            });
        }

        @Override
        public void setHandoffHandler(IBackAnimationHandoffHandler handoffHandler) {
            // no-op
        }

        @Override
        public void onBackProgressed(BackMotionEvent backEvent) {
            // This is only called in some special cases such as when activity embedding is active
+94 −5
Original line number Diff line number Diff line
@@ -37,6 +37,7 @@ import static com.android.wm.shell.shared.ShellSharedConstants.KEY_EXTRA_SHELL_B
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SuppressLint;
import android.app.ActivityManager;
import android.app.ActivityTaskManager;
import android.app.IActivityTaskManager;
import android.app.TaskInfo;
@@ -73,10 +74,12 @@ import android.window.BackMotionEvent;
import android.window.BackNavigationInfo;
import android.window.BackTouchTracker;
import android.window.IBackAnimationFinishedCallback;
import android.window.IBackAnimationHandoffHandler;
import android.window.IBackAnimationRunner;
import android.window.IOnBackInvokedCallback;
import android.window.TransitionInfo;
import android.window.TransitionRequestInfo;
import android.window.WindowAnimationState;
import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;

@@ -84,6 +87,8 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.ProtoLog;
import com.android.internal.util.LatencyTracker;
import com.android.internal.view.AppearanceRegion;
import com.android.systemui.animation.TransitionAnimator;
import com.android.window.flags.Flags;
import com.android.wm.shell.R;
import com.android.wm.shell.common.ExternalInterfaceBinder;
import com.android.wm.shell.common.RemoteCallable;
@@ -227,6 +232,15 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
    private Runnable mPilferPointerCallback;
    private BackAnimation.TopUiRequest mRequestTopUiCallback;

    private final IBackAnimationHandoffHandler mHandoffHandler =
            new IBackAnimationHandoffHandler.Stub() {
                @Override
                public void handOffAnimation(
                        RemoteAnimationTarget[] targets, WindowAnimationState[] states) {
                    mBackTransitionHandler.handOffAnimation(targets, states);
                }
            };

    public BackAnimationController(
            @NonNull ShellInit shellInit,
            @NonNull ShellController shellController,
@@ -282,7 +296,7 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
        mShellCommandHandler = shellCommandHandler;
        mWindowManager = context.getSystemService(WindowManager.class);
        mTransitions = transitions;
        mBackTransitionHandler = new BackTransitionHandler();
        mBackTransitionHandler = new BackTransitionHandler(mTransitions);
        mTransitions.addHandler(mBackTransitionHandler);
        mHandler = handler;
        mTransitions.registerObserver(mBackTransitionObserver);
@@ -715,6 +729,9 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
        }
        try {
            callback.onBackStarted(backEvent);
            if (mBackTransitionHandler.canHandOffAnimation()) {
                callback.setHandoffHandler(mHandoffHandler);
            }
            mOnBackStartDispatched = true;
        } catch (RemoteException e) {
            Log.e(TAG, "dispatchOnBackStarted error: ", e);
@@ -1192,6 +1209,7 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
    }

    class BackTransitionHandler implements Transitions.TransitionHandler {
        private final Transitions mTransitions;

        Runnable mOnAnimationFinishCallback;
        boolean mCloseTransitionRequested;
@@ -1203,6 +1221,12 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
        // animation is canceled, start a close prepare transition to finish the whole transition.
        IBinder mClosePrepareTransition;
        TransitionInfo mOpenTransitionInfo;
        Transitions.TransitionHandler mTakeoverHandler;

        BackTransitionHandler(Transitions transitions) {
            mTransitions = transitions;
        }

        void onAnimationFinished() {
            if (!mCloseTransitionRequested && mPrepareOpenTransition != null) {
                createClosePrepareTransition();
@@ -1214,18 +1238,23 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
        }

        private void applyFinishOpenTransition() {
            mOpenTransitionInfo = null;
            mPrepareOpenTransition = null;
            if (mFinishOpenTransaction != null) {
                final SurfaceControl.Transaction t = mFinishOpenTransaction;
                mFinishOpenTransaction = null;
                t.apply();
            }
            if (mFinishOpenTransitionCallback != null) {
                final Transitions.TransitionFinishCallback callback = mFinishOpenTransitionCallback;
                mFinishOpenTransitionCallback = null;
                callback.onTransitionFinished(null);
            }
            cleanUpInternalState();
        }

        private void cleanUpInternalState() {
            mOpenTransitionInfo = null;
            mPrepareOpenTransition = null;
            mFinishOpenTransaction = null;
            mFinishOpenTransitionCallback = null;
            mTakeoverHandler = null;
        }

        private void applyAndFinish(@NonNull SurfaceControl.Transaction st,
@@ -1237,6 +1266,7 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
            finishCallback.onTransitionFinished(null);
            mCloseTransitionRequested = false;
        }

        @Override
        public boolean startAnimation(@NonNull IBinder transition,
                @NonNull TransitionInfo info,
@@ -1246,6 +1276,9 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
            final boolean isPrepareTransition =
                    info.getType() == WindowManager.TRANSIT_PREPARE_BACK_NAVIGATION;
            if (isPrepareTransition) {
                if (checkTakeoverFlags()) {
                    mTakeoverHandler = mTransitions.getHandlerForTakeover(transition, info);
                }
                kickStartAnimation();
            }
            // Both mShellExecutor and Transitions#mMainExecutor are ShellMainThread, so we don't
@@ -1288,6 +1321,57 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
            return handleCloseTransition(info, st, ft, finishCallback);
        }

        private boolean canHandOffAnimation() {
            if (!checkTakeoverFlags()) {
                return false;
            }

            return mTakeoverHandler != null;
        }

        private void handOffAnimation(
                RemoteAnimationTarget[] targets, WindowAnimationState[] states) {
            if (!checkTakeoverFlags()) {
                ProtoLog.e(WM_SHELL_BACK_PREVIEW,
                        "Trying to hand off the animation, but the required flags are disabled.");
                return;
            } else if (mTakeoverHandler == null) {
                ProtoLog.e(WM_SHELL_BACK_PREVIEW,
                        "Missing takeover handler when trying to hand off animation.");
                return;
            } else if (targets.length != states.length) {
                ProtoLog.e(WM_SHELL_BACK_PREVIEW,
                        "Targets passed for takeover don't match the window states.");
                return;
            }

            // The states passed to this method are paired with the targets, but they need to be
            // paired with the changes inside the TransitionInfo. So for each change we find its
            // matching target, and leave the state for any change missing a matching target blank.
            WindowAnimationState[] updatedStates =
                    new WindowAnimationState[mOpenTransitionInfo.getChanges().size()];
            for (int i = 0; i < mOpenTransitionInfo.getChanges().size(); i++) {
                ActivityManager.RunningTaskInfo taskInfo =
                        mOpenTransitionInfo.getChanges().get(i).getTaskInfo();
                if (taskInfo == null) {
                    continue;
                }

                for (int j = 0; j < targets.length; j++) {
                    if (taskInfo.taskId == targets[j].taskId) {
                        updatedStates[i] = states[j];
                        break;
                    }
                }
            }

            mTakeoverHandler.takeOverAnimation(
                    mPrepareOpenTransition, mOpenTransitionInfo, new SurfaceControl.Transaction(),
                    mFinishOpenTransitionCallback, updatedStates);

            cleanUpInternalState();
        }

        @Override
        public void onTransitionConsumed(@NonNull IBinder transition, boolean aborted,
                @Nullable SurfaceControl.Transaction finishTransaction) {
@@ -1673,6 +1757,11 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
            }
            return null;
        }

        private static boolean checkTakeoverFlags() {
            return TransitionAnimator.Companion.longLivedReturnAnimationsEnabled()
                    && Flags.unifyBackNavigationTransition();
        }
    }

    private static boolean isNotGestureBackTransition(@NonNull TransitionInfo info) {
Loading