Loading core/java/android/window/IBackAnimationHandoffHandler.aidl 0 → 100644 +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); } core/java/android/window/IOnBackInvokedCallback.aidl +6 −0 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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); } core/java/android/window/ImeOnBackInvokedDispatcher.java +5 −0 Original line number Diff line number Diff line Loading @@ -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)); Loading core/java/android/window/WindowOnBackInvokedDispatcher.java +5 −0 Original line number Diff line number Diff line Loading @@ -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 Loading libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java +94 −5 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading @@ -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; Loading Loading @@ -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, Loading Loading @@ -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); Loading Loading @@ -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); Loading Loading @@ -1192,6 +1209,7 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont } class BackTransitionHandler implements Transitions.TransitionHandler { private final Transitions mTransitions; Runnable mOnAnimationFinishCallback; boolean mCloseTransitionRequested; Loading @@ -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(); Loading @@ -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, Loading @@ -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, Loading @@ -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 Loading Loading @@ -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) { Loading Loading @@ -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 Loading
core/java/android/window/IBackAnimationHandoffHandler.aidl 0 → 100644 +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); }
core/java/android/window/IOnBackInvokedCallback.aidl +6 −0 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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); }
core/java/android/window/ImeOnBackInvokedDispatcher.java +5 −0 Original line number Diff line number Diff line Loading @@ -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)); Loading
core/java/android/window/WindowOnBackInvokedDispatcher.java +5 −0 Original line number Diff line number Diff line Loading @@ -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 Loading
libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java +94 −5 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading @@ -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; Loading Loading @@ -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, Loading Loading @@ -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); Loading Loading @@ -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); Loading Loading @@ -1192,6 +1209,7 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont } class BackTransitionHandler implements Transitions.TransitionHandler { private final Transitions mTransitions; Runnable mOnAnimationFinishCallback; boolean mCloseTransitionRequested; Loading @@ -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(); Loading @@ -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, Loading @@ -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, Loading @@ -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 Loading Loading @@ -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) { Loading Loading @@ -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