diff --git a/quickstep/src/com/android/quickstep/InputConsumer.java b/quickstep/src/com/android/quickstep/InputConsumer.java index 23def14515..f898e2f002 100644 --- a/quickstep/src/com/android/quickstep/InputConsumer.java +++ b/quickstep/src/com/android/quickstep/InputConsumer.java @@ -126,4 +126,14 @@ public interface InputConsumer { } return name.toString(); } + + /** + * Returns an input consumer of the given class type, or null if none is found. + */ + default T getInputConsumerOfClass(Class c) { + if (getClass().equals(c)) { + return c.cast(this); + } + return null; + } } diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java b/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java index 3d332c2aa2..5d26ec0bb0 100644 --- a/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java +++ b/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java @@ -115,7 +115,8 @@ public class RecentsAnimationCallbacks implements /* extras= */ 0, /* gestureEvent= */ ON_START_RECENTS_ANIMATION); notifyAnimationCanceled(); - animationController.finish(false /* toHome */, false /* sendUserLeaveHint */); + animationController.finish(false /* toHome */, false /* sendUserLeaveHint */, + null /* finishCb */); return; } diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationController.java b/quickstep/src/com/android/quickstep/RecentsAnimationController.java index 8972dc84c1..341e18cc99 100644 --- a/quickstep/src/com/android/quickstep/RecentsAnimationController.java +++ b/quickstep/src/com/android/quickstep/RecentsAnimationController.java @@ -21,6 +21,7 @@ import static com.android.quickstep.TaskAnimationManager.ENABLE_SHELL_TRANSITION import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.FINISH_RECENTS_ANIMATION; import android.content.Context; +import android.os.Bundle; import android.os.RemoteException; import android.util.Log; import android.view.IRecentsAnimationController; @@ -32,6 +33,7 @@ import android.window.PictureInPictureSurfaceTransaction; import androidx.annotation.NonNull; import androidx.annotation.UiThread; +import com.android.internal.os.IResultReceiver; import com.android.launcher3.util.Preconditions; import com.android.launcher3.util.RunnableList; import com.android.quickstep.util.ActiveGestureErrorDetector; @@ -172,12 +174,19 @@ public class RecentsAnimationController { mFinishTargetIsLauncher = toRecents; mOnFinishedListener.accept(this); Runnable finishCb = () -> { - mController.finish(toRecents, sendUserLeaveHint); + mController.finish(toRecents, sendUserLeaveHint, new IResultReceiver.Stub() { + @Override + public void send(int i, Bundle bundle) throws RemoteException { + ActiveGestureLog.INSTANCE.addLog("finishRecentsAnimation-callback"); + MAIN_EXECUTOR.execute(() -> { + mPendingFinishCallbacks.executeAllAndDestroy(); + }); + } + }); InteractionJankMonitorWrapper.end(InteractionJankMonitorWrapper.CUJ_QUICK_SWITCH); InteractionJankMonitorWrapper.end(InteractionJankMonitorWrapper.CUJ_APP_CLOSE_TO_HOME); InteractionJankMonitorWrapper.end( InteractionJankMonitorWrapper.CUJ_APP_SWIPE_TO_RECENTS); - MAIN_EXECUTOR.execute(mPendingFinishCallbacks::executeAllAndDestroy); }; if (forceFinish) { finishCb.run(); diff --git a/quickstep/src/com/android/quickstep/TaskAnimationManager.java b/quickstep/src/com/android/quickstep/TaskAnimationManager.java index f5a7eccff1..f1b31f75a9 100644 --- a/quickstep/src/com/android/quickstep/TaskAnimationManager.java +++ b/quickstep/src/com/android/quickstep/TaskAnimationManager.java @@ -119,7 +119,8 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn } } // But force-finish it anyways - finishRunningRecentsAnimation(false /* toHome */, true /* forceFinish */); + finishRunningRecentsAnimation(false /* toHome */, true /* forceFinish */, + null /* forceFinishCb */); if (mCallbacks != null) { // If mCallbacks still != null, that means we are getting this startRecentsAnimation() @@ -325,19 +326,20 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn * Finishes the running recents animation. */ public void finishRunningRecentsAnimation(boolean toHome) { - finishRunningRecentsAnimation(toHome, false /* forceFinish */); + finishRunningRecentsAnimation(toHome, false /* forceFinish */, null /* forceFinishCb */); } /** * Finishes the running recents animation. * @param forceFinish will synchronously finish the controller */ - public void finishRunningRecentsAnimation(boolean toHome, boolean forceFinish) { + public void finishRunningRecentsAnimation(boolean toHome, boolean forceFinish, + Runnable forceFinishCb) { if (mController != null) { ActiveGestureLog.INSTANCE.addLog( /* event= */ "finishRunningRecentsAnimation", toHome); if (forceFinish) { - mController.finishController(toHome, null, false /* sendUserLeaveHint */, + mController.finishController(toHome, forceFinishCb, false /* sendUserLeaveHint */, true /* forceFinish */); } else { Utilities.postAsyncCallback(MAIN_EXECUTOR.getHandler(), toHome diff --git a/quickstep/src/com/android/quickstep/inputconsumers/DelegateInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/DelegateInputConsumer.java index 63771f0d56..5557639b1c 100644 --- a/quickstep/src/com/android/quickstep/inputconsumers/DelegateInputConsumer.java +++ b/quickstep/src/com/android/quickstep/inputconsumers/DelegateInputConsumer.java @@ -48,6 +48,14 @@ public abstract class DelegateInputConsumer implements InputConsumer { */ protected abstract String getDelegatorName(); + @Override + public T getInputConsumerOfClass(Class c) { + if (getClass().equals(c)) { + return c.cast(this); + } + return mDelegate.getInputConsumerOfClass(c); + } + protected void setActive(MotionEvent ev) { ActiveGestureLog.INSTANCE.addLog(new ActiveGestureLog.CompoundString(getDelegatorName()) .append(" became active")); diff --git a/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressInputConsumer.java index addcfb8691..fc3f3ab8d5 100644 --- a/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressInputConsumer.java +++ b/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressInputConsumer.java @@ -52,9 +52,15 @@ public class NavHandleLongPressInputConsumer extends DelegateInputConsumer { if (isInArea(motionEvent.getRawX())) { Runnable longPressRunnable = mNavHandleLongPressHandler.getLongPressRunnable(); if (longPressRunnable != null) { - setActive(motionEvent); - - MAIN_EXECUTOR.post(longPressRunnable); + OtherActivityInputConsumer oaic = getInputConsumerOfClass( + OtherActivityInputConsumer.class); + if (oaic != null) { + oaic.setForceFinishRecentsTransitionCallback(longPressRunnable); + setActive(motionEvent); + } else { + setActive(motionEvent); + MAIN_EXECUTOR.post(longPressRunnable); + } } } } diff --git a/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java index 7e6116720b..28c00eb426 100644 --- a/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java +++ b/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java @@ -125,6 +125,9 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC // Might be displacement in X or Y, depending on the direction we are swiping from the nav bar. private float mStartDisplacement; + // The callback called upon finishing the recents transition if it was force-canceled + private Runnable mForceFinishRecentsTransitionCallback; + public OtherActivityInputConsumer(Context base, RecentsAnimationDeviceState deviceState, TaskAnimationManager taskAnimationManager, GestureState gestureState, boolean isDeferredDownTarget, Consumer onCompleteCallback, @@ -444,7 +447,7 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC // animateToProgress so we have to manually finish here. In the case of // ACTION_CANCEL, someone else may be doing something so finish synchronously. mTaskAnimationManager.finishRunningRecentsAnimation(false /* toHome */, - isCanceled /* forceFinish */); + isCanceled /* forceFinish */, mForceFinishRecentsTransitionCallback); } else { // The animation hasn't started yet, so insert a replacement handler into the // callbacks which immediately finishes the animation after it starts. @@ -512,6 +515,14 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC return !mPassedPilferInputSlop; } + /** + * Sets a callback to be called when the recents transition is force-canceled by another input + * consumer being made active. + */ + public void setForceFinishRecentsTransitionCallback(Runnable r) { + mForceFinishRecentsTransitionCallback = r; + } + /** * A listener which just finishes the animation immediately after starting. Replaces * AbsSwipeUpHandler if the gesture itself finishes before the animation even starts.