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

Commit 48acd240 authored by Yifei Zhang's avatar Yifei Zhang
Browse files

swipe-dismiss: set up gesture exlcusion for explicit windowSwipeToDismiss=false

WindowOnBackInvokedDispatcher:
- Convert binary Checker to tri-state so that we can determine if
  windowSwipeToDismiss=false is explicitly set.
- Other minor refactor.

ViewRootImpl:
- Set window frame as root system gesture exclusion rect if
  windowSwipeToDismiss=false is explicitly set & not opt-in.

Test: manual, validate mSystemExclusion set
Test: on phone: http://shortn/_wOryjDg8aB
Test: on watch: http://shortn/_mPypnw2Ibt
Bug: 290801678
Bug: 291531205
Change-Id: Ie7d925869fad25b3f7599d388c0e7ae5ef6fef53
parent 0b69edfa
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -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
     * 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
     * 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
+7 −1
Original line number Diff line number Diff line
@@ -2183,7 +2183,9 @@ public final class ViewRootImpl implements ViewParent,
            mStopped = stopped;
            final ThreadedRenderer renderer = mAttachInfo.mThreadedRenderer;
            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);
            }
            if (!mStopped) {
@@ -8421,6 +8423,10 @@ public final class ViewRootImpl implements ViewParent,
            mLastLayoutFrame.set(frame);
        }

        if (mOnBackInvokedDispatcher.isSystemGestureExclusionNeeded()) {
            setRootSystemGestureExclusionRects(List.of(frame));
        }

        final WindowConfiguration winConfig = getCompatWindowConfiguration();
        mPendingBackDropFrame.set(mPendingDragResizing && !winConfig.useWindowFrameForBackdrop()
                ? winConfig.getMaxBounds()
+43 −15
Original line number Diff line number Diff line
@@ -16,6 +16,9 @@

package android.window;

import static java.lang.annotation.RetentionPolicy.SOURCE;

import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.Activity;
@@ -34,8 +37,8 @@ import android.view.IWindowSession;

import androidx.annotation.VisibleForTesting;


import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.HashMap;
@@ -57,6 +60,18 @@ import java.util.TreeMap;
 * @hide
 */
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 IWindow mWindow;
    private static final String TAG = "WindowOnBackDispatcher";
@@ -267,13 +282,6 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
        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
     * @param prefix the prefix that will be prepended to each line of the produced output
@@ -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.
     * <p>
@@ -394,7 +416,7 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
     * {@link OnBackInvokedCallback}.
     */
    public static boolean isOnBackInvokedCallbackEnabled(@NonNull Context context) {
        return Checker.isOnBackInvokedCallbackEnabled(context);
        return Checker.getBackCallbackType(context) == BACK_CALLBACK_ENABLED;
    }

    @Override
@@ -446,22 +468,24 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
            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
            // request legacy back.
            boolean featureFlagEnabled = ENABLE_PREDICTIVE_BACK;
            if (!featureFlagEnabled) {
                return false;
                return BACK_CALLBACK_DISABLED;
            }

            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 (context == null) {
                Log.w(TAG, "OnBackInvokedCallback is not enabled because context is null.");
                return false;
                return BACK_CALLBACK_DISABLED;
            }

            boolean requestsPredictiveBack = false;
@@ -528,11 +552,15 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
                        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;
        }
    }
}