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

Commit 21d36fe6 authored by Wei Sheng Shih's avatar Wei Sheng Shih Committed by Android (Google) Code Review
Browse files

Merge "Fixes Activity cannot receive ACTION_CANCEL after onBackStarted." into main

parents e8224f49 f6e14231
Loading
Loading
Loading
Loading
+5 −3
Original line number Diff line number Diff line
@@ -19,8 +19,10 @@ package android.view;
import static android.view.WindowInsetsAnimation.Callback.DISPATCH_MODE_CONTINUE_ON_SUBTREE;
import static android.view.WindowInsetsAnimation.Callback.DISPATCH_MODE_STOP;
import static android.view.flags.Flags.FLAG_TOOLKIT_VIEWGROUP_SET_REQUESTED_FRAME_RATE_API;
import static android.view.flags.Flags.toolkitViewgroupSetRequestedFrameRateApi;
import static android.view.flags.Flags.scrollCaptureTargetZOrderFix;
import static android.view.flags.Flags.toolkitViewgroupSetRequestedFrameRateApi;

import static com.android.window.flags.Flags.interceptMotionFromMoveToCancel;

import android.animation.LayoutTransition;
import android.annotation.CallSuper;
@@ -88,7 +90,6 @@ import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Predicate;

/**
 * <p>
 * A <code>ViewGroup</code> is a special view that can contain other views
@@ -2674,7 +2675,8 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
            ViewRootImpl viewRootImpl = getViewRootImpl();
            if (actionMasked == MotionEvent.ACTION_DOWN || mFirstTouchTarget != null) {
                final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
                final boolean isBackGestureInProgress = (viewRootImpl != null
                final boolean isBackGestureInProgress = !interceptMotionFromMoveToCancel()
                        && (viewRootImpl != null
                        && viewRootImpl.getOnBackInvokedDispatcher().isBackGestureInProgress());
                if (!disallowIntercept || isBackGestureInProgress) {
                    // Allow back to intercept touch
+16 −0
Original line number Diff line number Diff line
@@ -52,6 +52,7 @@ public class BackTouchTracker {
    private int mSwipeEdge;
    private boolean mShouldUpdateStartLocation = false;
    private TouchTrackerState mState = TouchTrackerState.INITIAL;
    private boolean mIsInterceptedMotionEvent;

    /**
     * Updates the tracker with a new motion event.
@@ -117,6 +118,20 @@ public class BackTouchTracker {
        return mState == TouchTrackerState.FINISHED;
    }

    /**
     * Returns whether current app should not receive motion event.
     */
    public boolean isInterceptedMotionEvent() {
        return mIsInterceptedMotionEvent;
    }

    /**
     * Marks the app will not receive motion event from current gesture.
     */
    public void setMotionEventIntercepted() {
        mIsInterceptedMotionEvent = true;
    }

    /** Sets the start location of the back gesture. */
    public void setGestureStartLocation(float touchX, float touchY, int swipeEdge) {
        mInitTouchX = touchX;
@@ -154,6 +169,7 @@ public class BackTouchTracker {
        mState = TouchTrackerState.INITIAL;
        mSwipeEdge = BackEvent.EDGE_LEFT;
        mShouldUpdateStartLocation = false;
        mIsInterceptedMotionEvent = false;
    }

    /** Creates a start {@link BackMotionEvent}. */
+18 −0
Original line number Diff line number Diff line
@@ -314,6 +314,24 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
        }
    }

    /**
     * Returns whether current app should not receive motion event.
     */
    public boolean isInterceptedMotionEvent() {
        synchronized (mLock) {
            return mTouchTracker.isInterceptedMotionEvent();
        }
    }

    /**
     * Marks the app will not receive motion event from current gesture.
     */
    public void setMotionEventIntercepted() {
        synchronized (mLock) {
            mTouchTracker.setMotionEventIntercepted();
        }
    }

    private void sendCancelledIfInProgress(@NonNull OnBackInvokedCallback callback) {
        boolean isInProgress = mProgressAnimator.isBackAnimationInProgress();
        if (isInProgress && callback instanceof OnBackAnimationCallback) {
+11 −0
Original line number Diff line number Diff line
@@ -542,3 +542,14 @@ flag {
        purpose: PURPOSE_BUGFIX
    }
}

flag {
    name: "intercept_motion_from_move_to_cancel"
    namespace: "windowing_frontend"
    description: "Ensure that the client receives ACTION_CANCEL when the back gesture is intercepted."
    bug: "404173501"
    is_fixed_read_only: true
    metadata {
        purpose: PURPOSE_BUGFIX
    }
}
 No newline at end of file
+58 −15
Original line number Diff line number Diff line
@@ -42,6 +42,7 @@ import static android.window.DesktopModeFlags.ENABLE_CAPTION_COMPAT_INSET_FORCE_
import static android.window.DesktopModeFlags.ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION_ALWAYS;

import static com.android.internal.policy.PhoneWindow.FEATURE_OPTIONS_PANEL;
import static com.android.window.flags.Flags.interceptMotionFromMoveToCancel;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -436,11 +437,50 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        if (interceptBackProgress(ev)) {
            return true;
        }
        final Window.Callback cb = mWindow.getCallback();
        return cb != null && !mWindow.isDestroyed() && mFeatureId < 0
                ? cb.dispatchTouchEvent(ev) : super.dispatchTouchEvent(ev);
    }

    private boolean interceptBackProgress(MotionEvent ev) {
        if (!interceptMotionFromMoveToCancel()) {
            return false;
        }
        final ViewRootImpl viewRootImpl = getViewRootImpl();
        if (viewRootImpl == null) {
            return false;
        }
        viewRootImpl.getOnBackInvokedDispatcher().onMotionEvent(ev);
        // Intercept touch if back gesture is in progress.
        boolean isBackGestureInProgress = viewRootImpl.getOnBackInvokedDispatcher()
                .isBackGestureInProgress();
        if (!isBackGestureInProgress && mWearGestureInterceptionDetector != null) {
            boolean wasIntercepting = mWearGestureInterceptionDetector.isIntercepting();
            boolean intercepting = mWearGestureInterceptionDetector.onInterceptTouchEvent(ev);
            if (wasIntercepting != intercepting) {
                viewRootImpl.updateDecorViewGestureInterception(intercepting);
            }
            if (intercepting) {
                isBackGestureInProgress = true;
            }
        }

        if (!isBackGestureInProgress) {
            return false;
        }
        // Intercept touch if back gesture is in progress.
        if (!viewRootImpl.getOnBackInvokedDispatcher().isInterceptedMotionEvent()) {
            viewRootImpl.getOnBackInvokedDispatcher().setMotionEventIntercepted();
            ev.setAction(MotionEvent.ACTION_CANCEL);
            // Return false to deliver the first CANCEL.
            return false;
        }
        return true;
    }

    @Override
    public boolean dispatchTrackballEvent(MotionEvent ev) {
        final Window.Callback cb = mWindow.getCallback();
@@ -519,6 +559,7 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
            }
        }

        if (!interceptMotionFromMoveToCancel()) {
            ViewRootImpl viewRootImpl = getViewRootImpl();
            if (viewRootImpl != null) {
                viewRootImpl.getOnBackInvokedDispatcher().onMotionEvent(event);
@@ -529,7 +570,8 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
            }
            if (viewRootImpl != null && mWearGestureInterceptionDetector != null) {
                boolean wasIntercepting = mWearGestureInterceptionDetector.isIntercepting();
            boolean intercepting = mWearGestureInterceptionDetector.onInterceptTouchEvent(event);
                boolean intercepting = mWearGestureInterceptionDetector
                        .onInterceptTouchEvent(event);
                if (wasIntercepting != intercepting) {
                    viewRootImpl.updateDecorViewGestureInterception(intercepting);
                }
@@ -537,6 +579,7 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind
                    return true;
                }
            }
        }

        if (!SWEEP_OPEN_MENU) {
            return false;