Defer nav handle action until after the recents transition is complete

Bug: 303078360
Test: Force delay in finishing recents transition and verify with bug steps
Change-Id: I2021cc291204261de56ef9c912d8b5935059c7fb
Signed-off-by: Winson Chung <winsonc@google.com>
This commit is contained in:
Winson Chung
2023-10-05 07:41:22 +00:00
parent 528356e744
commit 4f17c97d03
7 changed files with 58 additions and 11 deletions

View File

@@ -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 extends InputConsumer> T getInputConsumerOfClass(Class<T> c) {
if (getClass().equals(c)) {
return c.cast(this);
}
return null;
}
}

View File

@@ -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;
}

View File

@@ -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();

View File

@@ -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

View File

@@ -48,6 +48,14 @@ public abstract class DelegateInputConsumer implements InputConsumer {
*/
protected abstract String getDelegatorName();
@Override
public <T extends InputConsumer> T getInputConsumerOfClass(Class<T> 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"));

View File

@@ -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);
}
}
}
}

View File

@@ -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<OtherActivityInputConsumer> 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.