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

Commit c4332d11 authored by Johannes Gallmann's avatar Johannes Gallmann Committed by Android (Google) Code Review
Browse files

Merge "Remove restriction that only one callback with..." into main

parents 5aeed432 224c1343
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -7733,7 +7733,7 @@ public final class ViewRootImpl implements ViewParent,
                        if (keyEvent.isCanceled()) {
                            animationCallback.onBackCancelled();
                        } else {
                            dispatcher.tryInvokeSystemNavigationObserverCallback();
                            dispatcher.tryInvokeSystemNavigationObserverCallbacks();
                            topCallback.onBackInvoked();
                        }
                        break;
@@ -7741,7 +7741,7 @@ public final class ViewRootImpl implements ViewParent,
            } else if (topCallback != null) {
                if (keyEvent.getAction() == KeyEvent.ACTION_UP) {
                    if (!keyEvent.isCanceled()) {
                        dispatcher.tryInvokeSystemNavigationObserverCallback();
                        dispatcher.tryInvokeSystemNavigationObserverCallbacks();
                        topCallback.onBackInvoked();
                    } else {
                        Log.d(mTag, "Skip onBackInvoked(), reason: keyEvent.isCanceled=true");
+15 −5
Original line number Diff line number Diff line
@@ -74,12 +74,22 @@ public interface OnBackInvokedDispatcher {
     * Priority level of {@link OnBackInvokedCallback}s designed to observe system-level back
     * handling.
     *
     * <p>Callbacks registered with this priority do not consume back events. They receive back
     * events whenever the system handles a back navigation and have no impact on the normal back
     * navigation flow. Useful for logging or analytics.
     * <p>Callbacks registered with this priority are invoked only when a back event is not
     * consumed by any other registered {@link OnBackInvokedCallback} with a priority of
     * {@link #PRIORITY_DEFAULT} or higher. This means they are called when the system is about
     * to perform its default back navigation action, such as finishing the current activity or
     * executing a back-to-home animation.
     *
     * <p>Only one callback with {@link #PRIORITY_SYSTEM_NAVIGATION_OBSERVER} can be registered at a
     * time.
     * <p>These callbacks are purely observational. They do not consume the back event and
     * cannot intercept it. Their invocation has no impact on the normal back navigation flow,
     * making them suitable for logging, analytics, or triggering actions that should not
     * prevent the system's own back handling.
     *
     * <p>The invocation order for multiple callbacks registered with this priority is undefined.
     *
     * <p>On API level 36 only, there is a restriction that only one callback with
     * {@link #PRIORITY_SYSTEM_NAVIGATION_OBSERVER} can be registered at a time. On API level 37 and
     * higher, the number of registered observer callbacks is unrestricted.
     */
    @FlaggedApi(Flags.FLAG_PREDICTIVE_BACK_PRIORITY_SYSTEM_NAVIGATION_OBSERVER)
    int PRIORITY_SYSTEM_NAVIGATION_OBSERVER = -2;
+51 −14
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package android.window;

import static android.window.SystemOverrideOnBackInvokedCallback.OVERRIDE_UNDEFINED;

import static com.android.window.flags.Flags.multipleSystemNavigationObserverCallbacks;
import static com.android.window.flags.Flags.predictiveBackSystemOverrideCallback;
import static com.android.window.flags.Flags.predictiveBackPrioritySystemNavigationObserver;
import static com.android.window.flags.Flags.predictiveBackTimestampApi;
@@ -54,7 +55,9 @@ import java.io.PrintWriter;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import java.util.TreeMap;
import java.util.function.BooleanSupplier;
import java.util.function.Supplier;
@@ -111,6 +114,8 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher {

    @VisibleForTesting
    public OnBackInvokedCallback mSystemNavigationObserverCallback = null;
    @VisibleForTesting
    public Set<OnBackInvokedCallback> mSystemNavigationObserverCallbacks = new HashSet<>();

    private Checker mChecker;
    private final Object mLock = new Object();
@@ -189,9 +194,13 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
                }
                removeCallbackInternal(callback);
            }
            if (multipleSystemNavigationObserverCallbacks()) {
                mSystemNavigationObserverCallbacks.add(callback);
            } else {
                mSystemNavigationObserverCallback = callback;
            }
        }
    }

    /**
     * Register a callback bypassing platform checks. This is used to register compatibility
@@ -240,6 +249,15 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
                Integer prevPriority = mAllCallbacks.get(callback);
                mOnBackInvokedCallbacks.get(prevPriority).remove(callback);
            }
            if (multipleSystemNavigationObserverCallbacks()) {
                if (mSystemNavigationObserverCallbacks.contains(callback)) {
                    mSystemNavigationObserverCallbacks.remove(callback);
                    if (DEBUG) {
                        Log.i(TAG, "Callback already registered (as system-navigation-observer "
                                + "callback). Removing and re-adding it.");
                    }
                }
            } else {
                if (mSystemNavigationObserverCallback == callback) {
                    mSystemNavigationObserverCallback = null;
                    if (DEBUG) {
@@ -247,6 +265,7 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
                                + "callback). Removing and re-adding it.");
                    }
                }
            }

            OnBackInvokedCallback previousTopCallback = getTopCallback();
            callbacks.add(callback);
@@ -266,10 +285,17 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
                mImeDispatcher.unregisterOnBackInvokedCallback(callback);
                return;
            }
            if (multipleSystemNavigationObserverCallbacks()) {
                if (mSystemNavigationObserverCallbacks.contains(callback)) {
                    mSystemNavigationObserverCallbacks.remove(callback);
                    return;
                }
            } else {
                if (mSystemNavigationObserverCallback == callback) {
                    mSystemNavigationObserverCallback = null;
                    return;
                }
            }
            if (callback instanceof ImeOnBackInvokedDispatcher.DefaultImeOnBackAnimationCallback) {
                callback = mImeBackAnimationController;
            }
@@ -373,6 +399,7 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
            mAllCallbacks.clear();
            mOnBackInvokedCallbacks.clear();
            mSystemNavigationObserverCallback = null;
            mSystemNavigationObserverCallbacks.clear();
        }
    }

@@ -385,11 +412,11 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
    }

    /**
     * Tries to call {@link OnBackInvokedCallback#onBackInvoked} on the system navigation observer
     * callback (if one is set and if the top-most regular callback has
     * Tries to call {@link OnBackInvokedCallback#onBackInvoked} on all system navigation observer
     * callback (if any are registered and if the top-most regular callback has
     * {@link OnBackInvokedDispatcher#PRIORITY_SYSTEM})
     */
    public void tryInvokeSystemNavigationObserverCallback() {
    public void tryInvokeSystemNavigationObserverCallbacks() {
        OnBackInvokedCallback topCallback = getTopCallback();
        Integer callbackPriority = mAllCallbacks.getOrDefault(topCallback, null);
        final boolean isSystemOverride = topCallback instanceof SystemOverrideOnBackInvokedCallback;
@@ -399,10 +426,20 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
    }

    private void invokeSystemNavigationObserverCallback() {
        if (multipleSystemNavigationObserverCallbacks()) {
            Set<OnBackInvokedCallback> observerCallbacks;
            synchronized (mLock) {
                observerCallbacks = new HashSet<>(mSystemNavigationObserverCallbacks);
            }
            for (OnBackInvokedCallback callback : observerCallbacks) {
                callback.onBackInvoked();
            }
        } else {
            if (mSystemNavigationObserverCallback != null) {
                mSystemNavigationObserverCallback.onBackInvoked();
            }
        }
    }

    private void setTopOnBackInvokedCallback(@Nullable OnBackInvokedCallback callback) {
        if (mWindowSession == null || mWindow == null) {
+7 −0
Original line number Diff line number Diff line
@@ -472,3 +472,10 @@ flag {
        purpose: PURPOSE_BUGFIX
    }
}

flag {
    name: "multiple_system_navigation_observer_callbacks"
    namespace: "windowing_frontend"
    description: "Removes restriction that only one back callback with PRIORITY_SYSTEM_NAVIGATION_OBSERVER can be registered"
    bug: "424146227"
}
+37 −1
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ import static android.window.OnBackInvokedDispatcher.PRIORITY_DEFAULT;
import static android.window.OnBackInvokedDispatcher.PRIORITY_OVERLAY;
import static android.window.OnBackInvokedDispatcher.PRIORITY_SYSTEM_NAVIGATION_OBSERVER;

import static com.android.window.flags.Flags.FLAG_MULTIPLE_SYSTEM_NAVIGATION_OBSERVER_CALLBACKS;
import static com.android.window.flags.Flags.FLAG_PREDICTIVE_BACK_PRIORITY_SYSTEM_NAVIGATION_OBSERVER;
import static com.android.window.flags.Flags.FLAG_PREDICTIVE_BACK_TIMESTAMP_API;

@@ -167,7 +168,8 @@ public class WindowOnBackInvokedDispatcherTest {
        int actualSizeOverlay = callbacksOverlay != null ? callbacksOverlay.size() : 0;
        assertEquals("mOnBackInvokedCallbacks OVERLAY size", expectedOverlay, actualSizeOverlay);

        int actualSizeObserver = mDispatcher.mSystemNavigationObserverCallback == null ? 0 : 1;
        int actualSizeObserver = mDispatcher.mSystemNavigationObserverCallback == null
                ? mDispatcher.mSystemNavigationObserverCallbacks.size() : 1;
        assertEquals("mOnBackInvokedCallbacks SYSTEM_NAVIGATION_OBSERVER size", expectedObserver,
                actualSizeObserver);
    }
@@ -666,6 +668,7 @@ public class WindowOnBackInvokedDispatcherTest {

    @Test
    @RequiresFlagsEnabled(FLAG_PREDICTIVE_BACK_PRIORITY_SYSTEM_NAVIGATION_OBSERVER)
    @RequiresFlagsDisabled(FLAG_MULTIPLE_SYSTEM_NAVIGATION_OBSERVER_CALLBACKS)
    public void testObserverCallback_reregistrations() {
        mDispatcher.registerOnBackInvokedCallback(PRIORITY_SYSTEM_NAVIGATION_OBSERVER, mCallback1);
        assertCallbacksSize(/* default */ 0, /* overlay */ 0, /* observer */ 1);
@@ -688,6 +691,39 @@ public class WindowOnBackInvokedDispatcherTest {
        assertCallbacksSize(/* default */ 0, /* overlay */ 0, /* observer */ 0);
    }

    @Test
    @RequiresFlagsEnabled({FLAG_PREDICTIVE_BACK_PRIORITY_SYSTEM_NAVIGATION_OBSERVER,
            FLAG_MULTIPLE_SYSTEM_NAVIGATION_OBSERVER_CALLBACKS})
    public void testObserverCallback_multiple_registrations() {
        mDispatcher.registerOnBackInvokedCallback(PRIORITY_SYSTEM_NAVIGATION_OBSERVER, mCallback1);
        assertCallbacksSize(/* default */ 0, /* overlay */ 0, /* observer */ 1);
        assertTrue(mDispatcher.mSystemNavigationObserverCallbacks.contains(mCallback1));

        // test registration of another observer-callback
        mDispatcher.registerOnBackInvokedCallback(PRIORITY_SYSTEM_NAVIGATION_OBSERVER, mCallback2);
        assertCallbacksSize(/* default */ 0, /* overlay */ 0, /* observer */ 2);
        assertTrue(mDispatcher.mSystemNavigationObserverCallbacks.contains(mCallback1));
        assertTrue(mDispatcher.mSystemNavigationObserverCallbacks.contains(mCallback2));

        // test reregistration of first observer-callback
        mDispatcher.registerOnBackInvokedCallback(PRIORITY_SYSTEM_NAVIGATION_OBSERVER, mCallback1);
        assertCallbacksSize(/* default */ 0, /* overlay */ 0, /* observer */ 2);

        // test reregistration of observer-callback with default priority
        mDispatcher.registerOnBackInvokedCallback(PRIORITY_DEFAULT, mCallback1);
        assertCallbacksSize(/* default */ 1, /* overlay */ 0, /* observer */ 1);

        // test reregistration of regular callback as observer-callback
        mDispatcher.registerOnBackInvokedCallback(PRIORITY_SYSTEM_NAVIGATION_OBSERVER, mCallback1);
        assertCallbacksSize(/* default */ 0, /* overlay */ 0, /* observer */ 2);

        mDispatcher.unregisterOnBackInvokedCallback(mCallback2);
        assertCallbacksSize(/* default */ 0, /* overlay */ 0, /* observer */ 1);

        mDispatcher.unregisterOnBackInvokedCallback(mCallback1);
        assertCallbacksSize(/* default */ 0, /* overlay */ 0, /* observer */ 0);
    }

    private BackMotionEvent backMotionEventFrom(float progress) {
        return new BackMotionEvent(
                /* touchX = */ 0,