Loading core/java/android/view/ViewGroup.java +5 −3 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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 Loading Loading @@ -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 Loading core/java/android/window/BackTouchTracker.java +16 −0 Original line number Diff line number Diff line Loading @@ -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. Loading Loading @@ -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; Loading Loading @@ -154,6 +169,7 @@ public class BackTouchTracker { mState = TouchTrackerState.INITIAL; mSwipeEdge = BackEvent.EDGE_LEFT; mShouldUpdateStartLocation = false; mIsInterceptedMotionEvent = false; } /** Creates a start {@link BackMotionEvent}. */ Loading core/java/android/window/WindowOnBackInvokedDispatcher.java +18 −0 Original line number Diff line number Diff line Loading @@ -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) { Loading core/java/android/window/flags/windowing_frontend.aconfig +11 −0 Original line number Diff line number Diff line Loading @@ -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 core/java/com/android/internal/policy/DecorView.java +58 −15 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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(); Loading Loading @@ -519,6 +559,7 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind } } if (!interceptMotionFromMoveToCancel()) { ViewRootImpl viewRootImpl = getViewRootImpl(); if (viewRootImpl != null) { viewRootImpl.getOnBackInvokedDispatcher().onMotionEvent(event); Loading @@ -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); } Loading @@ -537,6 +579,7 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind return true; } } } if (!SWEEP_OPEN_MENU) { return false; Loading Loading
core/java/android/view/ViewGroup.java +5 −3 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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 Loading Loading @@ -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 Loading
core/java/android/window/BackTouchTracker.java +16 −0 Original line number Diff line number Diff line Loading @@ -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. Loading Loading @@ -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; Loading Loading @@ -154,6 +169,7 @@ public class BackTouchTracker { mState = TouchTrackerState.INITIAL; mSwipeEdge = BackEvent.EDGE_LEFT; mShouldUpdateStartLocation = false; mIsInterceptedMotionEvent = false; } /** Creates a start {@link BackMotionEvent}. */ Loading
core/java/android/window/WindowOnBackInvokedDispatcher.java +18 −0 Original line number Diff line number Diff line Loading @@ -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) { Loading
core/java/android/window/flags/windowing_frontend.aconfig +11 −0 Original line number Diff line number Diff line Loading @@ -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
core/java/com/android/internal/policy/DecorView.java +58 −15 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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(); Loading Loading @@ -519,6 +559,7 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind } } if (!interceptMotionFromMoveToCancel()) { ViewRootImpl viewRootImpl = getViewRootImpl(); if (viewRootImpl != null) { viewRootImpl.getOnBackInvokedDispatcher().onMotionEvent(event); Loading @@ -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); } Loading @@ -537,6 +579,7 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind return true; } } } if (!SWEEP_OPEN_MENU) { return false; Loading