Pass the values of the MotionEvent instead of the event instance itself
to BackAnimation. The original MotionEvent instance may have been recycled by the time BackAnimation processes it, since BackAnimation runs in a different thread. This could cause crashes from both Java side and native side, as described in b/233163975#comment11. We work around this by passing the numerical values that BackAnimation need instead of the MotionEvent itself. Test: Swipe back in various scenarios. Make sure back can be triggered. Try cancel. Make sure back can be cancelled. Test: atest BackAnimationControllerTest Bug: 233163975 Change-Id: I4792debc705536b49d1caafcc43e5466941c1d43 Merged-In: I4792debc705536b49d1caafcc43e5466941c1d43
This commit is contained in:
@@ -31,13 +31,15 @@ public interface BackAnimation {
|
||||
/**
|
||||
* Called when a {@link MotionEvent} is generated by a back gesture.
|
||||
*
|
||||
* @param event the original {@link MotionEvent}
|
||||
* @param action the original {@link KeyEvent#getAction()} when the event was dispatched to
|
||||
* @param touchX the X touch position of the {@link MotionEvent}.
|
||||
* @param touchY the Y touch position of the {@link MotionEvent}.
|
||||
* @param keyAction the original {@link KeyEvent#getAction()} when the event was dispatched to
|
||||
* the process. This is forwarded separately because the input pipeline may mutate
|
||||
* the {#event} action state later.
|
||||
* @param swipeEdge the edge from which the swipe begins.
|
||||
*/
|
||||
void onBackMotion(MotionEvent event, int action, @BackEvent.SwipeEdge int swipeEdge);
|
||||
void onBackMotion(float touchX, float touchY, int keyAction,
|
||||
@BackEvent.SwipeEdge int swipeEdge);
|
||||
|
||||
/**
|
||||
* Sets whether the back gesture is past the trigger threshold or not.
|
||||
|
||||
@@ -184,8 +184,8 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
|
||||
|
||||
@Override
|
||||
public void onBackMotion(
|
||||
MotionEvent event, int action, @BackEvent.SwipeEdge int swipeEdge) {
|
||||
mShellExecutor.execute(() -> onMotionEvent(event, action, swipeEdge));
|
||||
float touchX, float touchY, int keyAction, @BackEvent.SwipeEdge int swipeEdge) {
|
||||
mShellExecutor.execute(() -> onMotionEvent(touchX, touchY, keyAction, swipeEdge));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -256,33 +256,34 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
|
||||
* Called when a new motion event needs to be transferred to this
|
||||
* {@link BackAnimationController}
|
||||
*/
|
||||
public void onMotionEvent(MotionEvent event, int action, @BackEvent.SwipeEdge int swipeEdge) {
|
||||
public void onMotionEvent(float touchX, float touchY, int keyAction,
|
||||
@BackEvent.SwipeEdge int swipeEdge) {
|
||||
if (mTransitionInProgress) {
|
||||
return;
|
||||
}
|
||||
if (action == MotionEvent.ACTION_MOVE) {
|
||||
if (keyAction == MotionEvent.ACTION_MOVE) {
|
||||
if (!mBackGestureStarted) {
|
||||
// Let the animation initialized here to make sure the onPointerDownOutsideFocus
|
||||
// could be happened when ACTION_DOWN, it may change the current focus that we
|
||||
// would access it when startBackNavigation.
|
||||
initAnimation(event);
|
||||
initAnimation(touchX, touchY);
|
||||
}
|
||||
onMove(event, swipeEdge);
|
||||
} else if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
|
||||
onMove(touchX, touchY, swipeEdge);
|
||||
} else if (keyAction == MotionEvent.ACTION_UP || keyAction == MotionEvent.ACTION_CANCEL) {
|
||||
ProtoLog.d(WM_SHELL_BACK_PREVIEW,
|
||||
"Finishing gesture with event action: %d", action);
|
||||
"Finishing gesture with event action: %d", keyAction);
|
||||
onGestureFinished();
|
||||
}
|
||||
}
|
||||
|
||||
private void initAnimation(MotionEvent event) {
|
||||
private void initAnimation(float touchX, float touchY) {
|
||||
ProtoLog.d(WM_SHELL_BACK_PREVIEW, "initAnimation mMotionStarted=%b", mBackGestureStarted);
|
||||
if (mBackGestureStarted || mBackNavigationInfo != null) {
|
||||
Log.e(TAG, "Animation is being initialized but is already started.");
|
||||
finishAnimation();
|
||||
}
|
||||
|
||||
mInitTouchLocation.set(event.getX(), event.getY());
|
||||
mInitTouchLocation.set(touchX, touchY);
|
||||
mBackGestureStarted = true;
|
||||
|
||||
try {
|
||||
@@ -351,18 +352,18 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
|
||||
mTransaction.setVisibility(screenshotSurface, true);
|
||||
}
|
||||
|
||||
private void onMove(MotionEvent event, @BackEvent.SwipeEdge int swipeEdge) {
|
||||
private void onMove(float touchX, float touchY, @BackEvent.SwipeEdge int swipeEdge) {
|
||||
if (!mBackGestureStarted || mBackNavigationInfo == null) {
|
||||
return;
|
||||
}
|
||||
int deltaX = Math.round(event.getX() - mInitTouchLocation.x);
|
||||
int deltaX = Math.round(touchX - mInitTouchLocation.x);
|
||||
float progressThreshold = PROGRESS_THRESHOLD >= 0 ? PROGRESS_THRESHOLD : mProgressThreshold;
|
||||
float progress = Math.min(Math.max(Math.abs(deltaX) / progressThreshold, 0), 1);
|
||||
int backType = mBackNavigationInfo.getType();
|
||||
RemoteAnimationTarget animationTarget = mBackNavigationInfo.getDepartingAnimationTarget();
|
||||
|
||||
BackEvent backEvent = new BackEvent(
|
||||
event.getX(), event.getY(), progress, swipeEdge, animationTarget);
|
||||
touchX, touchY, progress, swipeEdge, animationTarget);
|
||||
IOnBackInvokedCallback targetCallback = null;
|
||||
if (shouldDispatchToLauncher(backType)) {
|
||||
targetCallback = mBackToLauncherCallback;
|
||||
|
||||
@@ -298,7 +298,7 @@ public class BackAnimationControllerTest {
|
||||
|
||||
private void doMotionEvent(int actionDown, int coordinate) {
|
||||
mController.onMotionEvent(
|
||||
MotionEvent.obtain(0, mEventTime, actionDown, coordinate, coordinate, 0),
|
||||
coordinate, coordinate,
|
||||
actionDown,
|
||||
BackEvent.EDGE_LEFT);
|
||||
mEventTime += 10;
|
||||
|
||||
@@ -486,7 +486,7 @@ public class NavigationBarEdgePanel extends View implements NavigationEdgeBackPl
|
||||
public void onMotionEvent(MotionEvent event) {
|
||||
if (mBackAnimation != null) {
|
||||
mBackAnimation.onBackMotion(
|
||||
event,
|
||||
event.getX(), event.getY(),
|
||||
event.getActionMasked(),
|
||||
mIsLeftPanel ? BackEvent.EDGE_LEFT : BackEvent.EDGE_RIGHT);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user