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

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

Merge "Don't forward KEYCODE_BACK events to app" into main

parents e022b0fe c184b5f1
Loading
Loading
Loading
Loading
+30 −0
Original line number Original line Diff line number Diff line
@@ -26,6 +26,8 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.inMultiWindowMode;
import static android.app.WindowConfiguration.inMultiWindowMode;
import static android.os.Process.myUid;
import static android.os.Process.myUid;


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

import static java.lang.Character.MIN_VALUE;
import static java.lang.Character.MIN_VALUE;


import android.Manifest;
import android.Manifest;
@@ -166,6 +168,8 @@ import android.view.translation.UiTranslationSpec;
import android.widget.AdapterView;
import android.widget.AdapterView;
import android.widget.Toast;
import android.widget.Toast;
import android.widget.Toolbar;
import android.widget.Toolbar;
import android.window.BackEvent;
import android.window.ObserverOnBackAnimationCallback;
import android.window.OnBackInvokedCallback;
import android.window.OnBackInvokedCallback;
import android.window.OnBackInvokedDispatcher;
import android.window.OnBackInvokedDispatcher;
import android.window.SplashScreen;
import android.window.SplashScreen;
@@ -822,6 +826,7 @@ public class Activity extends ContextThemeWrapper
    private static final int LOG_AM_ON_TOP_RESUMED_GAINED_CALLED = 30064;
    private static final int LOG_AM_ON_TOP_RESUMED_GAINED_CALLED = 30064;
    private static final int LOG_AM_ON_TOP_RESUMED_LOST_CALLED = 30065;
    private static final int LOG_AM_ON_TOP_RESUMED_LOST_CALLED = 30065;
    private OnBackInvokedCallback mDefaultBackCallback;
    private OnBackInvokedCallback mDefaultBackCallback;
    private ObserverOnBackAnimationCallback mObserverBackCallback;


    /**
    /**
     * After {@link Build.VERSION_CODES#TIRAMISU},
     * After {@link Build.VERSION_CODES#TIRAMISU},
@@ -1923,6 +1928,27 @@ public class Activity extends ContextThemeWrapper
            mDefaultBackCallback = this::onBackInvoked;
            mDefaultBackCallback = this::onBackInvoked;
            getOnBackInvokedDispatcher().registerSystemOnBackInvokedCallback(mDefaultBackCallback);
            getOnBackInvokedDispatcher().registerSystemOnBackInvokedCallback(mDefaultBackCallback);
        }
        }
        if (predictiveBackStopKeycodeBackForwarding()) {
            mObserverBackCallback = new ObserverOnBackAnimationCallback() {
                    @Override
                    public void onBackStarted(@NonNull BackEvent backEvent) {
                        onUserInteraction();
                    }

                    @Override
                    public void onBackInvoked() {
                        onUserInteraction();
                    }

                    @Override
                    public void onBackCancelled() {}
                };
            // Register a ObserverOnBackAnimationCallback with PRIORITY_SYSTEM_NAVIGATION_OBSERVER
            // to get notified on every back navigation so that onUserInteraction can be called.
            getOnBackInvokedDispatcher().registerOnBackInvokedCallback(
                    OnBackInvokedDispatcher.PRIORITY_SYSTEM_NAVIGATION_OBSERVER,
                    mObserverBackCallback);
        }
    }
    }


    /**
    /**
@@ -3010,6 +3036,10 @@ public class Activity extends ContextThemeWrapper
            getOnBackInvokedDispatcher().unregisterOnBackInvokedCallback(mDefaultBackCallback);
            getOnBackInvokedDispatcher().unregisterOnBackInvokedCallback(mDefaultBackCallback);
            mDefaultBackCallback = null;
            mDefaultBackCallback = null;
        }
        }
        if (mObserverBackCallback != null) {
            getOnBackInvokedDispatcher().unregisterOnBackInvokedCallback(mObserverBackCallback);
            mObserverBackCallback = null;
        }


        if (mCallbacksController != null) {
        if (mCallbacksController != null) {
            mCallbacksController.clearCallbacks();
            mCallbacksController.clearCallbacks();
+22 −23
Original line number Original line Diff line number Diff line
@@ -135,6 +135,7 @@ import static com.android.text.flags.Flags.disableHandwritingInitiatorForIme;
import static com.android.window.flags.Flags.alwaysSeqIdLayout;
import static com.android.window.flags.Flags.alwaysSeqIdLayout;
import static com.android.window.flags.Flags.alwaysSeqIdLayoutWear;
import static com.android.window.flags.Flags.alwaysSeqIdLayoutWear;
import static com.android.window.flags.Flags.enableWindowContextResourcesUpdateOnConfigChange;
import static com.android.window.flags.Flags.enableWindowContextResourcesUpdateOnConfigChange;
import static com.android.window.flags.Flags.predictiveBackStopKeycodeBackForwarding;
import static com.android.window.flags.Flags.reduceChangedExclusionRectsMsgs;
import static com.android.window.flags.Flags.reduceChangedExclusionRectsMsgs;
import static com.android.window.flags.Flags.setScPropertiesInClient;
import static com.android.window.flags.Flags.setScPropertiesInClient;
@@ -275,7 +276,6 @@ import android.window.ClientWindowFrames;
import android.window.CompatOnBackInvokedCallback;
import android.window.CompatOnBackInvokedCallback;
import android.window.ImeBackCallbackProxy;
import android.window.ImeBackCallbackProxy;
import android.window.InputTransferToken;
import android.window.InputTransferToken;
import android.window.OnBackAnimationCallback;
import android.window.OnBackInvokedCallback;
import android.window.OnBackInvokedCallback;
import android.window.OnBackInvokedDispatcher;
import android.window.OnBackInvokedDispatcher;
import android.window.ScreenCaptureInternal;
import android.window.ScreenCaptureInternal;
@@ -7816,10 +7816,7 @@ public final class ViewRootImpl implements ViewParent,
            if (dispatcher.isBackGestureInProgress()) {
            if (dispatcher.isBackGestureInProgress()) {
                return FINISH_NOT_HANDLED;
                return FINISH_NOT_HANDLED;
            }
            }
            if (topCallback instanceof OnBackAnimationCallback
            if (topCallback != null) {
                    && !(topCallback instanceof ImeBackAnimationController)) {
                final OnBackAnimationCallback animationCallback =
                        (OnBackAnimationCallback) topCallback;
                switch (keyEvent.getAction()) {
                switch (keyEvent.getAction()) {
                    case KeyEvent.ACTION_DOWN:
                    case KeyEvent.ACTION_DOWN:
                        // ACTION_DOWN is emitted twice: once when the user presses the button,
                        // ACTION_DOWN is emitted twice: once when the user presses the button,
@@ -7828,29 +7825,30 @@ public final class ViewRootImpl implements ViewParent,
                        // - 0 means the button was pressed.
                        // - 0 means the button was pressed.
                        // - 1 means the button continues to be pressed (long press).
                        // - 1 means the button continues to be pressed (long press).
                        if (keyEvent.getRepeatCount() == 0) {
                        if (keyEvent.getRepeatCount() == 0) {
                            animationCallback.onBackStarted(
                            dispatcher.onBackStarted(topCallback,
                                    new BackEvent(0, 0, 0f, BackEvent.EDGE_NONE));
                                    new BackEvent(0, 0, 0f, BackEvent.EDGE_NONE), /* observerOnly */
                                    topCallback instanceof ImeBackAnimationController);
                        }
                        }
                        break;
                        break;
                    case KeyEvent.ACTION_UP:
                    case KeyEvent.ACTION_UP:
                        if (keyEvent.isCanceled()) {
                        if (keyEvent.isCanceled()) {
                            animationCallback.onBackCancelled();
                            dispatcher.onBackCancelled(topCallback);
                        } else {
                        } else {
                            dispatcher.tryInvokeSystemNavigationObserverCallbacks();
                            dispatcher.onBackInvoked(topCallback);
                            topCallback.onBackInvoked();
                            if (predictiveBackStopKeycodeBackForwarding()) {
                                return FINISH_HANDLED;
                            }
                        }
                        }
                        break;
                        break;
                }
                }
            } else if (topCallback != null) {
                if (keyEvent.getAction() == KeyEvent.ACTION_UP) {
                    if (!keyEvent.isCanceled()) {
                        dispatcher.tryInvokeSystemNavigationObserverCallbacks();
                        topCallback.onBackInvoked();
            } else {
            } else {
                        Log.d(mTag, "Skip onBackInvoked(), reason: keyEvent.isCanceled=true");
                if (predictiveBackStopKeycodeBackForwarding()) {
                    }
                    return FORWARD;
                }
                }
            }
            }
            if (predictiveBackStopKeycodeBackForwarding()) {
                return FINISH_NOT_HANDLED;
            } else {
                // Do not cancel the keyEvent if no callback can handle the back event.
                // Do not cancel the keyEvent if no callback can handle the back event.
                if (topCallback != null && keyEvent.getAction() == KeyEvent.ACTION_UP) {
                if (topCallback != null && keyEvent.getAction() == KeyEvent.ACTION_UP) {
                    // forward a cancelled event so that following stages cancel their back logic
                    // forward a cancelled event so that following stages cancel their back logic
@@ -7858,6 +7856,7 @@ public final class ViewRootImpl implements ViewParent,
                }
                }
                return FORWARD;
                return FORWARD;
            }
            }
        }
        @Override
        @Override
        public void onFinishedInputEvent(Object token, boolean handled) {
        public void onFinishedInputEvent(Object token, boolean handled) {
+41 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2025 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.window;

import android.annotation.NonNull;

/**
 * Privileged marker interface for {@link OnBackAnimationCallback} that's only available to system
 * components. When registered with
 * {@link OnBackInvokedDispatcher#PRIORITY_SYSTEM_NAVIGATION_OBSERVER}, this callback gets
 * {@link OnBackAnimationCallback#onBackStarted}, {@link OnBackAnimationCallback#onBackInvoked()}
 * and {@link OnBackAnimationCallback#onBackCancelled()} callbacks whenever ANY back navigation
 * happens, including any non-system back navigation.
 * @hide
 */
public interface ObserverOnBackAnimationCallback extends OnBackAnimationCallback {

    @Override
    void onBackStarted(@NonNull BackEvent backEvent);

    @Override
    void onBackInvoked();

    @Override
    void onBackCancelled();

}
+90 −38
Original line number Original line Diff line number Diff line
@@ -20,6 +20,7 @@ import static android.window.SystemOverrideOnBackInvokedCallback.OVERRIDE_UNDEFI


import static com.android.window.flags.Flags.multipleSystemNavigationObserverCallbacks;
import static com.android.window.flags.Flags.multipleSystemNavigationObserverCallbacks;
import static com.android.window.flags.Flags.predictiveBackCallbackCancellationFix;
import static com.android.window.flags.Flags.predictiveBackCallbackCancellationFix;
import static com.android.window.flags.Flags.predictiveBackStopKeycodeBackForwarding;


import android.annotation.NonNull;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.Nullable;
@@ -58,6 +59,7 @@ import java.util.Objects;
import java.util.Set;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeMap;
import java.util.function.BooleanSupplier;
import java.util.function.BooleanSupplier;
import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.function.Supplier;


/**
/**
@@ -425,31 +427,88 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
    }
    }


    /**
    /**
     * Tries to call {@link OnBackInvokedCallback#onBackInvoked} on all system navigation observer
     * Calls the {@link OnBackAnimationCallback#onBackStarted} function of the provided callback
     * callback (if any are registered and if the top-most regular callback has
     * if it is an instance of {@link OnBackAnimationCallback}.
     * {@link OnBackInvokedDispatcher#PRIORITY_SYSTEM})
     * Additionally invokes any registered observer callbacks if necessary.
     *
     * @param callback The callback to call {@link OnBackAnimationCallback#onBackStarted} on.
     * @param backEvent The back event to pass to the callback.
     * @param observerOnly Whether to only invoke observer callbacks.
     */
     */
    public void tryInvokeSystemNavigationObserverCallbacks() {
    public void onBackStarted(OnBackInvokedCallback callback, BackEvent backEvent,
        OnBackInvokedCallback topCallback = getTopCallback();
            boolean observerOnly) {
        Integer callbackPriority = mAllCallbacks.getOrDefault(topCallback, null);
        if (predictiveBackStopKeycodeBackForwarding()) {
        final boolean isSystemOverride = topCallback instanceof SystemOverrideOnBackInvokedCallback;
            forEachObserverCallback((observerCallback) -> {
        if ((callbackPriority != null && callbackPriority == PRIORITY_SYSTEM) || isSystemOverride) {
                if (observerCallback instanceof ObserverOnBackAnimationCallback) {
            invokeSystemNavigationObserverCallback();
                    ((ObserverOnBackAnimationCallback) observerCallback).onBackStarted(backEvent);
                }
            });
        }
        if (callback instanceof OnBackAnimationCallback && !observerOnly) {
            ((OnBackAnimationCallback) callback).onBackStarted(backEvent);
        }
    }

    /**
     * Calls the {@link OnBackAnimationCallback#onBackCancelled} function of the provided callback
     * if it is an instance of {@link OnBackAnimationCallback}.
     * Additionally invokes any registered observer callbacks if necessary.
     *
     * @param callback The callback to call {@link OnBackAnimationCallback#onBackCancelled} on.
     */
    public void onBackCancelled(OnBackInvokedCallback callback) {
        if (predictiveBackStopKeycodeBackForwarding()) {
            forEachObserverCallback((observerCallback) -> {
                if (observerCallback instanceof ObserverOnBackAnimationCallback) {
                    ((ObserverOnBackAnimationCallback) observerCallback).onBackCancelled();
                }
            });
        }
        if (callback instanceof OnBackAnimationCallback) {
            ((OnBackAnimationCallback) callback).onBackCancelled();
        }
        }
    }
    }


    private void invokeSystemNavigationObserverCallback() {
    /**
     * Calls the {@link OnBackInvokedCallback#onBackInvoked} function of the provided callback.
     * Additionally invokes any registered observer callbacks if necessary.
     * @param callback The callback to call {@link OnBackInvokedCallback#onBackInvoked} on.
     */
    public void onBackInvoked(OnBackInvokedCallback callback) {
        Integer callbackPriority = mAllCallbacks.getOrDefault(callback, null);
        final boolean isSystemOverride = callback instanceof SystemOverrideOnBackInvokedCallback;
        final boolean isSystemCallback = isSystemOverride
                || (callbackPriority != null && callbackPriority == PRIORITY_SYSTEM);

        forEachObserverCallback((observerCallback) -> {
            if (isSystemCallback || observerCallback instanceof ObserverOnBackAnimationCallback) {
                // Call observer callback whenever there is a system back navigation happening.
                // When there is a ObserverOnBackAnimationCallback registered (which is only
                // available for system components), call it for non-system back navigation too
                observerCallback.onBackInvoked();
            }
        });
        callback.onBackInvoked();
    }

    /**
     * Executes a given action on all registered observer callback.
     *
     * @param action The action to execute for each callback.
     */
    private void forEachObserverCallback(Consumer<OnBackInvokedCallback> action) {
        if (multipleSystemNavigationObserverCallbacks()) {
        if (multipleSystemNavigationObserverCallbacks()) {
            if (mSystemNavigationObserverCallbacks.isEmpty()) return;
            Set<OnBackInvokedCallback> observerCallbacks;
            Set<OnBackInvokedCallback> observerCallbacks;
            synchronized (mLock) {
            synchronized (mLock) {
                observerCallbacks = new HashSet<>(mSystemNavigationObserverCallbacks);
                observerCallbacks = new HashSet<>(mSystemNavigationObserverCallbacks);
            }
            }
            for (OnBackInvokedCallback callback : observerCallbacks) {
            for (OnBackInvokedCallback observerCallback : observerCallbacks) {
                callback.onBackInvoked();
                action.accept(observerCallback);
            }
            }
        } else {
        } else {
            if (mSystemNavigationObserverCallback != null) {
            if (mSystemNavigationObserverCallback != null) {
                mSystemNavigationObserverCallback.onBackInvoked();
                action.accept(mSystemNavigationObserverCallback);
            }
            }
        }
        }
    }
    }
@@ -467,12 +526,12 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
                    overrideAnimation = ((SystemOverrideOnBackInvokedCallback) callback)
                    overrideAnimation = ((SystemOverrideOnBackInvokedCallback) callback)
                            .overrideBehavior();
                            .overrideBehavior();
                }
                }
                final boolean isSystemCallback = priority == PRIORITY_SYSTEM

                        || overrideAnimation != OVERRIDE_UNDEFINED;
                final WeakReference<OnBackInvokedCallback> weakRefCallback = new WeakReference<>(
                final IOnBackInvokedCallback iCallback = new OnBackInvokedCallbackWrapper(callback,
                        callback);
                        mTouchTracker, mProgressAnimator, mHandler, this::callOnKeyPreIme,
                final IOnBackInvokedCallback iCallback = new OnBackInvokedCallbackWrapper(
                        this::invokeSystemNavigationObserverCallback,
                        weakRefCallback, mTouchTracker, mProgressAnimator, mHandler,
                        isSystemCallback /*isSystemCallback*/);
                        this::callOnKeyPreIme);
                callbackInfo = new OnBackInvokedCallbackInfo(
                callbackInfo = new OnBackInvokedCallbackInfo(
                        iCallback,
                        iCallback,
                        priority,
                        priority,
@@ -564,7 +623,7 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
        }
        }
    }
    }


    private static class OnBackInvokedCallbackWrapper extends IOnBackInvokedCallback.Stub {
    private class OnBackInvokedCallbackWrapper extends IOnBackInvokedCallback.Stub {
        @NonNull
        @NonNull
        private final WeakReference<OnBackInvokedCallback> mCallback;
        private final WeakReference<OnBackInvokedCallback> mCallback;
        @NonNull
        @NonNull
@@ -575,26 +634,19 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
        private final Handler mHandler;
        private final Handler mHandler;
        @NonNull
        @NonNull
        private final BooleanSupplier mOnKeyPreIme;
        private final BooleanSupplier mOnKeyPreIme;
        @NonNull
        private final Runnable mSystemNavigationObserverCallbackRunnable;
        private final boolean mIsSystemCallback;


        OnBackInvokedCallbackWrapper(
        OnBackInvokedCallbackWrapper(
                @NonNull OnBackInvokedCallback callback,
                @NonNull WeakReference<OnBackInvokedCallback> callback,
                @NonNull BackTouchTracker touchTracker,
                @NonNull BackTouchTracker touchTracker,
                @NonNull BackProgressAnimator progressAnimator,
                @NonNull BackProgressAnimator progressAnimator,
                @NonNull Handler handler,
                @NonNull Handler handler,
                @NonNull BooleanSupplier onKeyPreIme,
                @NonNull BooleanSupplier onKeyPreIme
                @NonNull Runnable systemNavigationObserverCallbackRunnable,
                boolean isSystemCallback
        ) {
        ) {
            mCallback = new WeakReference<>(callback);
            mCallback = callback;
            mTouchTracker = touchTracker;
            mTouchTracker = touchTracker;
            mProgressAnimator = progressAnimator;
            mProgressAnimator = progressAnimator;
            mHandler = handler;
            mHandler = handler;
            mOnKeyPreIme = onKeyPreIme;
            mOnKeyPreIme = onKeyPreIme;
            mSystemNavigationObserverCallbackRunnable = systemNavigationObserverCallbackRunnable;
            mIsSystemCallback = isSystemCallback;
        }
        }


        @Override
        @Override
@@ -613,14 +665,14 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
                mTouchTracker.setGestureStartLocation(
                mTouchTracker.setGestureStartLocation(
                        backEvent.getTouchX(), backEvent.getTouchY(), backEvent.getSwipeEdge());
                        backEvent.getTouchX(), backEvent.getTouchY(), backEvent.getSwipeEdge());


                WindowOnBackInvokedDispatcher.this.onBackStarted(mCallback.get(),
                        BackEvent.fromBackMotionEvent(backEvent), /* observerOnly */ false);
                if (callback != null) {
                if (callback != null) {
                    callback.onBackStarted(BackEvent.fromBackMotionEvent(backEvent));
                    if (predictiveBackCallbackCancellationFix()) {
                    if (predictiveBackCallbackCancellationFix()) {
                        mProgressAnimator.onBackStarted(backEvent, callback::onBackProgressed,
                        mProgressAnimator.onBackStarted(backEvent, callback::onBackProgressed,
                                callback);
                                callback);
                    } else {
                    } else {
                        mProgressAnimator.onBackStarted(backEvent, callback::onBackProgressed);
                        mProgressAnimator.onBackStarted(backEvent, callback::onBackProgressed);

                    }
                    }
                }
                }
            });
            });
@@ -649,7 +701,9 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
                final OnBackAnimationCallback callback = getBackAnimationCallback();
                final OnBackAnimationCallback callback = getBackAnimationCallback();
                mTouchTracker.reset();
                mTouchTracker.reset();
                if (callback == null) return;
                if (callback == null) return;
                mProgressAnimator.onBackCancelled(callback::onBackCancelled);
                mProgressAnimator.onBackCancelled(
                        () -> WindowOnBackInvokedDispatcher.this.onBackCancelled(callback)
                );
            });
            });
        }
        }


@@ -670,10 +724,7 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
                    return;
                    return;
                }
                }
                mProgressAnimator.reset();
                mProgressAnimator.reset();
                if (mIsSystemCallback) {
                WindowOnBackInvokedDispatcher.this.onBackInvoked(callback);
                    mSystemNavigationObserverCallbackRunnable.run();
                }
                callback.onBackInvoked();
            });
            });
        }
        }


@@ -774,7 +825,8 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
                return false;
                return false;
            }
            }
            if (!WindowOnBackInvokedDispatcher.isOnBackInvokedCallbackEnabled(hostContext)
            if (!WindowOnBackInvokedDispatcher.isOnBackInvokedCallbackEnabled(hostContext)
                    && !(callback instanceof CompatOnBackInvokedCallback)) {
                    && !(callback instanceof CompatOnBackInvokedCallback
                    || callback instanceof ObserverOnBackAnimationCallback)) {
                Log.w(TAG,
                Log.w(TAG,
                        "OnBackInvokedCallback is not enabled for the application."
                        "OnBackInvokedCallback is not enabled for the application."
                                + "\nSet 'android:enableOnBackInvokedCallback=\"true\"' in the"
                                + "\nSet 'android:enableOnBackInvokedCallback=\"true\"' in the"
+10 −0
Original line number Original line Diff line number Diff line
@@ -482,3 +482,13 @@ flag {
        purpose: PURPOSE_BUGFIX
        purpose: PURPOSE_BUGFIX
    }
    }
}
}

flag {
    name: "predictive_back_stop_keycode_back_forwarding"
    namespace: "windowing_frontend"
    description: "No longer forward KEYCODE_BACK events when app has enableOnBackInvokedCallback=true"
    bug: "436871339"
    metadata {
        purpose: PURPOSE_BUGFIX
    }
}
 No newline at end of file
Loading