Loading core/java/android/view/View.java +6 −0 Original line number Original line Diff line number Diff line Loading @@ -12115,6 +12115,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * a precision touch gesture in a small area in either the X or Y dimension, such as * a precision touch gesture in a small area in either the X or Y dimension, such as * an edge swipe or dragging a <code>SeekBar</code> thumb.</p> * an edge swipe or dragging a <code>SeekBar</code> thumb.</p> * * * <p>On Wear OS, these rects control where system-level swipe-to-dismiss gesture can start. If * the attribute {@code android:windowSwipeToDismiss} has been set to {@code false}, the system * will create an exclusion rect with size equal to the window frame size. In order words, the * system swipe-to-dismiss will not apply, and the app must handle gestural input within itself. * </p> * * <p>Note: the system will put a limit of <code>200dp</code> on the vertical extent of the * <p>Note: the system will put a limit of <code>200dp</code> on the vertical extent of the * exclusions it takes into account. The limit does not apply while the navigation * exclusions it takes into account. The limit does not apply while the navigation * bar is {@link #SYSTEM_UI_FLAG_IMMERSIVE_STICKY stickily} hidden, nor to the * bar is {@link #SYSTEM_UI_FLAG_IMMERSIVE_STICKY stickily} hidden, nor to the core/java/android/view/ViewRootImpl.java +7 −1 Original line number Original line Diff line number Diff line Loading @@ -2193,7 +2193,9 @@ public final class ViewRootImpl implements ViewParent, mStopped = stopped; mStopped = stopped; final ThreadedRenderer renderer = mAttachInfo.mThreadedRenderer; final ThreadedRenderer renderer = mAttachInfo.mThreadedRenderer; if (renderer != null) { if (renderer != null) { if (DEBUG_DRAW) Log.d(mTag, "WindowStopped on " + getTitle() + " set to " + mStopped); if (DEBUG_DRAW) { Log.d(mTag, "WindowStopped on " + getTitle() + " set to " + mStopped); } renderer.setStopped(mStopped); renderer.setStopped(mStopped); } } if (!mStopped) { if (!mStopped) { Loading Loading @@ -8431,6 +8433,10 @@ public final class ViewRootImpl implements ViewParent, mLastLayoutFrame.set(frame); mLastLayoutFrame.set(frame); } } if (mOnBackInvokedDispatcher.isSystemGestureExclusionNeeded()) { setRootSystemGestureExclusionRects(List.of(frame)); } final WindowConfiguration winConfig = getCompatWindowConfiguration(); final WindowConfiguration winConfig = getCompatWindowConfiguration(); mPendingBackDropFrame.set(mPendingDragResizing && !winConfig.useWindowFrameForBackdrop() mPendingBackDropFrame.set(mPendingDragResizing && !winConfig.useWindowFrameForBackdrop() ? winConfig.getMaxBounds() ? winConfig.getMaxBounds() Loading core/java/android/window/WindowOnBackInvokedDispatcher.java +43 −15 Original line number Original line Diff line number Diff line Loading @@ -16,6 +16,9 @@ package android.window; package android.window; import static java.lang.annotation.RetentionPolicy.SOURCE; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.Nullable; import android.app.Activity; import android.app.Activity; Loading @@ -34,8 +37,8 @@ import android.view.IWindowSession; import androidx.annotation.VisibleForTesting; import androidx.annotation.VisibleForTesting; import java.io.PrintWriter; import java.io.PrintWriter; import java.lang.annotation.Retention; import java.lang.ref.WeakReference; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.ArrayList; import java.util.HashMap; import java.util.HashMap; Loading @@ -57,6 +60,18 @@ import java.util.TreeMap; * @hide * @hide */ */ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher { public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher { @Retention(SOURCE) @IntDef({ BACK_CALLBACK_ENABLED, BACK_CALLBACK_DISABLED, BACK_CALLBACK_DISABLED_LEGACY_WINDOW_SWIPE_TO_DISMISS }) public @interface OnBackInvokedCallbackType {} public static final int BACK_CALLBACK_ENABLED = 0; public static final int BACK_CALLBACK_DISABLED = 1; public static final int BACK_CALLBACK_DISABLED_LEGACY_WINDOW_SWIPE_TO_DISMISS = 2; private IWindowSession mWindowSession; private IWindowSession mWindowSession; private IWindow mWindow; private IWindow mWindow; private static final String TAG = "WindowOnBackDispatcher"; private static final String TAG = "WindowOnBackDispatcher"; Loading Loading @@ -267,13 +282,6 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher { mChecker = new Checker(context); mChecker = new Checker(context); } } /** * Returns false if the legacy back behavior should be used. */ public boolean isOnBackInvokedCallbackEnabled() { return Checker.isOnBackInvokedCallbackEnabled(mChecker.getContext()); } /** /** * Dump information about this WindowOnBackInvokedDispatcher * Dump information about this WindowOnBackInvokedDispatcher * @param prefix the prefix that will be prepended to each line of the produced output * @param prefix the prefix that will be prepended to each line of the produced output Loading Loading @@ -387,6 +395,20 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher { } } } } /** Returns false if the legacy back behavior should be used. */ public boolean isOnBackInvokedCallbackEnabled() { return isOnBackInvokedCallbackEnabled(mChecker.getContext()); } /** * Returns true if system gesture exclusion is needed for global gesture compatibility with * windowSwipeToDismiss styleable. */ public boolean isSystemGestureExclusionNeeded() { return Checker.getBackCallbackType(mChecker.getContext()) == BACK_CALLBACK_DISABLED_LEGACY_WINDOW_SWIPE_TO_DISMISS; } /** /** * Returns false if the legacy back behavior should be used. * Returns false if the legacy back behavior should be used. * <p> * <p> Loading @@ -394,7 +416,7 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher { * {@link OnBackInvokedCallback}. * {@link OnBackInvokedCallback}. */ */ public static boolean isOnBackInvokedCallbackEnabled(@NonNull Context context) { public static boolean isOnBackInvokedCallbackEnabled(@NonNull Context context) { return Checker.isOnBackInvokedCallbackEnabled(context); return Checker.getBackCallbackType(context) == BACK_CALLBACK_ENABLED; } } @Override @Override Loading Loading @@ -446,22 +468,24 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher { return mContext.get(); return mContext.get(); } } private static boolean isOnBackInvokedCallbackEnabled(@Nullable Context context) { @OnBackInvokedCallbackType private static int getBackCallbackType(@Nullable Context context) { // new back is enabled if the feature flag is enabled AND the app does not explicitly // new back is enabled if the feature flag is enabled AND the app does not explicitly // request legacy back. // request legacy back. boolean featureFlagEnabled = ENABLE_PREDICTIVE_BACK; boolean featureFlagEnabled = ENABLE_PREDICTIVE_BACK; if (!featureFlagEnabled) { if (!featureFlagEnabled) { return false; return BACK_CALLBACK_DISABLED; } } if (ALWAYS_ENFORCE_PREDICTIVE_BACK) { if (ALWAYS_ENFORCE_PREDICTIVE_BACK) { return true; Log.i(TAG, "getBackCallbackType: always enable"); return BACK_CALLBACK_ENABLED; } } // If the context is null, return false to use legacy back. // If the context is null, return false to use legacy back. if (context == null) { if (context == null) { Log.w(TAG, "OnBackInvokedCallback is not enabled because context is null."); Log.w(TAG, "OnBackInvokedCallback is not enabled because context is null."); return false; return BACK_CALLBACK_DISABLED; } } boolean requestsPredictiveBack = false; boolean requestsPredictiveBack = false; Loading Loading @@ -528,11 +552,15 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher { Log.i(TAG, "falling back to windowSwipeToDismiss: " + windowSwipeToDismiss); Log.i(TAG, "falling back to windowSwipeToDismiss: " + windowSwipeToDismiss); } } requestsPredictiveBack = windowSwipeToDismiss; if (!windowSwipeToDismiss) { return BACK_CALLBACK_DISABLED_LEGACY_WINDOW_SWIPE_TO_DISMISS; } else { return BACK_CALLBACK_ENABLED; } } } } } return requestsPredictiveBack; return requestsPredictiveBack ? BACK_CALLBACK_ENABLED : BACK_CALLBACK_DISABLED; } } } } } } Loading
core/java/android/view/View.java +6 −0 Original line number Original line Diff line number Diff line Loading @@ -12115,6 +12115,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * a precision touch gesture in a small area in either the X or Y dimension, such as * a precision touch gesture in a small area in either the X or Y dimension, such as * an edge swipe or dragging a <code>SeekBar</code> thumb.</p> * an edge swipe or dragging a <code>SeekBar</code> thumb.</p> * * * <p>On Wear OS, these rects control where system-level swipe-to-dismiss gesture can start. If * the attribute {@code android:windowSwipeToDismiss} has been set to {@code false}, the system * will create an exclusion rect with size equal to the window frame size. In order words, the * system swipe-to-dismiss will not apply, and the app must handle gestural input within itself. * </p> * * <p>Note: the system will put a limit of <code>200dp</code> on the vertical extent of the * <p>Note: the system will put a limit of <code>200dp</code> on the vertical extent of the * exclusions it takes into account. The limit does not apply while the navigation * exclusions it takes into account. The limit does not apply while the navigation * bar is {@link #SYSTEM_UI_FLAG_IMMERSIVE_STICKY stickily} hidden, nor to the * bar is {@link #SYSTEM_UI_FLAG_IMMERSIVE_STICKY stickily} hidden, nor to the
core/java/android/view/ViewRootImpl.java +7 −1 Original line number Original line Diff line number Diff line Loading @@ -2193,7 +2193,9 @@ public final class ViewRootImpl implements ViewParent, mStopped = stopped; mStopped = stopped; final ThreadedRenderer renderer = mAttachInfo.mThreadedRenderer; final ThreadedRenderer renderer = mAttachInfo.mThreadedRenderer; if (renderer != null) { if (renderer != null) { if (DEBUG_DRAW) Log.d(mTag, "WindowStopped on " + getTitle() + " set to " + mStopped); if (DEBUG_DRAW) { Log.d(mTag, "WindowStopped on " + getTitle() + " set to " + mStopped); } renderer.setStopped(mStopped); renderer.setStopped(mStopped); } } if (!mStopped) { if (!mStopped) { Loading Loading @@ -8431,6 +8433,10 @@ public final class ViewRootImpl implements ViewParent, mLastLayoutFrame.set(frame); mLastLayoutFrame.set(frame); } } if (mOnBackInvokedDispatcher.isSystemGestureExclusionNeeded()) { setRootSystemGestureExclusionRects(List.of(frame)); } final WindowConfiguration winConfig = getCompatWindowConfiguration(); final WindowConfiguration winConfig = getCompatWindowConfiguration(); mPendingBackDropFrame.set(mPendingDragResizing && !winConfig.useWindowFrameForBackdrop() mPendingBackDropFrame.set(mPendingDragResizing && !winConfig.useWindowFrameForBackdrop() ? winConfig.getMaxBounds() ? winConfig.getMaxBounds() Loading
core/java/android/window/WindowOnBackInvokedDispatcher.java +43 −15 Original line number Original line Diff line number Diff line Loading @@ -16,6 +16,9 @@ package android.window; package android.window; import static java.lang.annotation.RetentionPolicy.SOURCE; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.Nullable; import android.app.Activity; import android.app.Activity; Loading @@ -34,8 +37,8 @@ import android.view.IWindowSession; import androidx.annotation.VisibleForTesting; import androidx.annotation.VisibleForTesting; import java.io.PrintWriter; import java.io.PrintWriter; import java.lang.annotation.Retention; import java.lang.ref.WeakReference; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.ArrayList; import java.util.HashMap; import java.util.HashMap; Loading @@ -57,6 +60,18 @@ import java.util.TreeMap; * @hide * @hide */ */ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher { public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher { @Retention(SOURCE) @IntDef({ BACK_CALLBACK_ENABLED, BACK_CALLBACK_DISABLED, BACK_CALLBACK_DISABLED_LEGACY_WINDOW_SWIPE_TO_DISMISS }) public @interface OnBackInvokedCallbackType {} public static final int BACK_CALLBACK_ENABLED = 0; public static final int BACK_CALLBACK_DISABLED = 1; public static final int BACK_CALLBACK_DISABLED_LEGACY_WINDOW_SWIPE_TO_DISMISS = 2; private IWindowSession mWindowSession; private IWindowSession mWindowSession; private IWindow mWindow; private IWindow mWindow; private static final String TAG = "WindowOnBackDispatcher"; private static final String TAG = "WindowOnBackDispatcher"; Loading Loading @@ -267,13 +282,6 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher { mChecker = new Checker(context); mChecker = new Checker(context); } } /** * Returns false if the legacy back behavior should be used. */ public boolean isOnBackInvokedCallbackEnabled() { return Checker.isOnBackInvokedCallbackEnabled(mChecker.getContext()); } /** /** * Dump information about this WindowOnBackInvokedDispatcher * Dump information about this WindowOnBackInvokedDispatcher * @param prefix the prefix that will be prepended to each line of the produced output * @param prefix the prefix that will be prepended to each line of the produced output Loading Loading @@ -387,6 +395,20 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher { } } } } /** Returns false if the legacy back behavior should be used. */ public boolean isOnBackInvokedCallbackEnabled() { return isOnBackInvokedCallbackEnabled(mChecker.getContext()); } /** * Returns true if system gesture exclusion is needed for global gesture compatibility with * windowSwipeToDismiss styleable. */ public boolean isSystemGestureExclusionNeeded() { return Checker.getBackCallbackType(mChecker.getContext()) == BACK_CALLBACK_DISABLED_LEGACY_WINDOW_SWIPE_TO_DISMISS; } /** /** * Returns false if the legacy back behavior should be used. * Returns false if the legacy back behavior should be used. * <p> * <p> Loading @@ -394,7 +416,7 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher { * {@link OnBackInvokedCallback}. * {@link OnBackInvokedCallback}. */ */ public static boolean isOnBackInvokedCallbackEnabled(@NonNull Context context) { public static boolean isOnBackInvokedCallbackEnabled(@NonNull Context context) { return Checker.isOnBackInvokedCallbackEnabled(context); return Checker.getBackCallbackType(context) == BACK_CALLBACK_ENABLED; } } @Override @Override Loading Loading @@ -446,22 +468,24 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher { return mContext.get(); return mContext.get(); } } private static boolean isOnBackInvokedCallbackEnabled(@Nullable Context context) { @OnBackInvokedCallbackType private static int getBackCallbackType(@Nullable Context context) { // new back is enabled if the feature flag is enabled AND the app does not explicitly // new back is enabled if the feature flag is enabled AND the app does not explicitly // request legacy back. // request legacy back. boolean featureFlagEnabled = ENABLE_PREDICTIVE_BACK; boolean featureFlagEnabled = ENABLE_PREDICTIVE_BACK; if (!featureFlagEnabled) { if (!featureFlagEnabled) { return false; return BACK_CALLBACK_DISABLED; } } if (ALWAYS_ENFORCE_PREDICTIVE_BACK) { if (ALWAYS_ENFORCE_PREDICTIVE_BACK) { return true; Log.i(TAG, "getBackCallbackType: always enable"); return BACK_CALLBACK_ENABLED; } } // If the context is null, return false to use legacy back. // If the context is null, return false to use legacy back. if (context == null) { if (context == null) { Log.w(TAG, "OnBackInvokedCallback is not enabled because context is null."); Log.w(TAG, "OnBackInvokedCallback is not enabled because context is null."); return false; return BACK_CALLBACK_DISABLED; } } boolean requestsPredictiveBack = false; boolean requestsPredictiveBack = false; Loading Loading @@ -528,11 +552,15 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher { Log.i(TAG, "falling back to windowSwipeToDismiss: " + windowSwipeToDismiss); Log.i(TAG, "falling back to windowSwipeToDismiss: " + windowSwipeToDismiss); } } requestsPredictiveBack = windowSwipeToDismiss; if (!windowSwipeToDismiss) { return BACK_CALLBACK_DISABLED_LEGACY_WINDOW_SWIPE_TO_DISMISS; } else { return BACK_CALLBACK_ENABLED; } } } } } return requestsPredictiveBack; return requestsPredictiveBack ? BACK_CALLBACK_ENABLED : BACK_CALLBACK_DISABLED; } } } } } }