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

Commit 6ca97d84 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Revert^2 "Enable IME predictive back animation in all apps"" into main

parents ebd2d073 d189ec36
Loading
Loading
Loading
Loading
+39 −11
Original line number Diff line number Diff line
@@ -7511,6 +7511,8 @@ public final class ViewRootImpl implements ViewParent,
            final KeyEvent event = (KeyEvent)q.mEvent;
            if (mView.dispatchKeyEventPreIme(event)) {
                return FINISH_HANDLED;
            } else if (q.forPreImeOnly()) {
                return FINISH_NOT_HANDLED;
            }
            return FORWARD;
        }
@@ -10007,6 +10009,7 @@ public final class ViewRootImpl implements ViewParent,
        public static final int FLAG_RESYNTHESIZED = 1 << 4;
        public static final int FLAG_UNHANDLED = 1 << 5;
        public static final int FLAG_MODIFIED_FOR_COMPATIBILITY = 1 << 6;
        public static final int FLAG_PRE_IME_ONLY = 1 << 7;
        public QueuedInputEvent mNext;
@@ -10014,6 +10017,13 @@ public final class ViewRootImpl implements ViewParent,
        public InputEventReceiver mReceiver;
        public int mFlags;
        public boolean forPreImeOnly() {
            if ((mFlags & FLAG_PRE_IME_ONLY) != 0) {
                return true;
            }
            return false;
        }
        public boolean shouldSkipIme() {
            if ((mFlags & FLAG_DELIVER_POST_IME) != 0) {
                return true;
@@ -10040,6 +10050,7 @@ public final class ViewRootImpl implements ViewParent,
            hasPrevious = flagToString("FINISHED_HANDLED", FLAG_FINISHED_HANDLED, hasPrevious, sb);
            hasPrevious = flagToString("RESYNTHESIZED", FLAG_RESYNTHESIZED, hasPrevious, sb);
            hasPrevious = flagToString("UNHANDLED", FLAG_UNHANDLED, hasPrevious, sb);
            hasPrevious = flagToString("FLAG_PRE_IME_ONLY", FLAG_PRE_IME_ONLY, hasPrevious, sb);
            if (!hasPrevious) {
                sb.append("0");
            }
@@ -10096,7 +10107,7 @@ public final class ViewRootImpl implements ViewParent,
    }
    @UnsupportedAppUsage
    void enqueueInputEvent(InputEvent event,
    QueuedInputEvent enqueueInputEvent(InputEvent event,
            InputEventReceiver receiver, int flags, boolean processImmediately) {
        QueuedInputEvent q = obtainQueuedInputEvent(event, receiver, flags);
@@ -10135,6 +10146,7 @@ public final class ViewRootImpl implements ViewParent,
        } else {
            scheduleProcessInputEvents();
        }
        return q;
    }
    private void scheduleProcessInputEvents() {
@@ -12456,29 +12468,45 @@ public final class ViewRootImpl implements ViewParent,
                            + "IWindow:%s Session:%s",
                    mOnBackInvokedDispatcher, mBasePackageName, mWindow, mWindowSession));
        }
        mOnBackInvokedDispatcher.attachToWindow(mWindowSession, mWindow,
        mOnBackInvokedDispatcher.attachToWindow(mWindowSession, mWindow, this,
                mImeBackAnimationController);
    }
    private void sendBackKeyEvent(int action) {
    /**
     * Sends {@link KeyEvent#ACTION_DOWN ACTION_DOWN} and {@link KeyEvent#ACTION_UP ACTION_UP}
     * back key events
     *
     * @param preImeOnly whether the back events should be sent to the pre-ime stage only
     * @return whether the event was handled (i.e. onKeyPreIme consumed it if preImeOnly=true)
     */
    public boolean injectBackKeyEvents(boolean preImeOnly) {
        boolean consumed;
        try {
            processingBackKey(true);
            sendBackKeyEvent(KeyEvent.ACTION_DOWN, preImeOnly);
            consumed = sendBackKeyEvent(KeyEvent.ACTION_UP, preImeOnly);
        } finally {
            processingBackKey(false);
        }
        return consumed;
    }
    private boolean sendBackKeyEvent(int action, boolean preImeOnly) {
        long when = SystemClock.uptimeMillis();
        final KeyEvent ev = new KeyEvent(when, when, action,
                KeyEvent.KEYCODE_BACK, 0 /* repeat */, 0 /* metaState */,
                KeyCharacterMap.VIRTUAL_KEYBOARD, 0 /* scancode */,
                KeyEvent.FLAG_FROM_SYSTEM | KeyEvent.FLAG_VIRTUAL_HARD_KEY,
                InputDevice.SOURCE_KEYBOARD);
        enqueueInputEvent(ev, null /* receiver */, 0 /* flags */, true /* processImmediately */);
        int flags = preImeOnly ? QueuedInputEvent.FLAG_PRE_IME_ONLY : 0;
        QueuedInputEvent q = enqueueInputEvent(ev, null /* receiver */, flags,
                true /* processImmediately */);
        return (q.mFlags & QueuedInputEvent.FLAG_FINISHED_HANDLED) != 0;
    }
    private void registerCompatOnBackInvokedCallback() {
        mCompatOnBackInvokedCallback = () -> {
            try {
                processingBackKey(true);
                sendBackKeyEvent(KeyEvent.ACTION_DOWN);
                sendBackKeyEvent(KeyEvent.ACTION_UP);
            } finally {
                processingBackKey(false);
            }
            injectBackKeyEvents(/* preImeOnly */ false);
        };
        if (mOnBackInvokedDispatcher.hasImeOnBackInvokedDispatcher()) {
            Log.d(TAG, "Skip registering CompatOnBackInvokedCallback on IME dispatcher");
+46 −5
Original line number Diff line number Diff line
@@ -37,6 +37,7 @@ import android.view.IWindow;
import android.view.IWindowSession;
import android.view.ImeBackAnimationController;
import android.view.MotionEvent;
import android.view.ViewRootImpl;

import androidx.annotation.VisibleForTesting;

@@ -49,6 +50,7 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.Objects;
import java.util.TreeMap;
import java.util.function.BooleanSupplier;
import java.util.function.Supplier;

/**
@@ -68,6 +70,7 @@ import java.util.function.Supplier;
public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
    private IWindowSession mWindowSession;
    private IWindow mWindow;
    private ViewRootImpl mViewRoot;
    @VisibleForTesting
    public final BackTouchTracker mTouchTracker = new BackTouchTracker();
    @VisibleForTesting
@@ -134,10 +137,12 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
     * is attached a window.
     */
    public void attachToWindow(@NonNull IWindowSession windowSession, @NonNull IWindow window,
            @Nullable ViewRootImpl viewRoot,
            @Nullable ImeBackAnimationController imeBackAnimationController) {
        synchronized (mLock) {
            mWindowSession = windowSession;
            mWindow = window;
            mViewRoot = viewRoot;
            mImeBackAnimationController = imeBackAnimationController;
            if (!mAllCallbacks.isEmpty()) {
                setTopOnBackInvokedCallback(getTopCallback());
@@ -151,6 +156,7 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
            clear();
            mWindow = null;
            mWindowSession = null;
            mViewRoot = null;
            mImeBackAnimationController = null;
        }
    }
@@ -176,8 +182,6 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
                return;
            }
            if (callback instanceof ImeOnBackInvokedDispatcher.ImeOnBackInvokedCallback) {
                // Fall back to compat back key injection if legacy back behaviour should be used.
                if (!isOnBackInvokedCallbackEnabled()) return;
                if (callback instanceof ImeOnBackInvokedDispatcher.DefaultImeOnBackAnimationCallback
                        && mImeBackAnimationController != null) {
                    // register ImeBackAnimationController instead to play predictive back animation
@@ -300,6 +304,14 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
        }
    }

    private boolean callOnKeyPreIme() {
        if (mViewRoot != null && !isOnBackInvokedCallbackEnabled(mViewRoot.mContext)) {
            return mViewRoot.injectBackKeyEvents(/*preImeOnly*/ true);
        } else {
            return false;
        }
    }

    private void setTopOnBackInvokedCallback(@Nullable OnBackInvokedCallback callback) {
        if (mWindowSession == null || mWindow == null) {
            return;
@@ -308,8 +320,8 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
            OnBackInvokedCallbackInfo callbackInfo = null;
            if (callback != null) {
                int priority = mAllCallbacks.get(callback);
                final IOnBackInvokedCallback iCallback = new OnBackInvokedCallbackWrapper(
                        callback, mTouchTracker, mProgressAnimator, mHandler);
                final IOnBackInvokedCallback iCallback = new OnBackInvokedCallbackWrapper(callback,
                        mTouchTracker, mProgressAnimator, mHandler, this::callOnKeyPreIme);
                callbackInfo = new OnBackInvokedCallbackInfo(
                        iCallback,
                        priority,
@@ -399,16 +411,20 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
        private final BackTouchTracker mTouchTracker;
        @NonNull
        private final Handler mHandler;
        @NonNull
        private final BooleanSupplier mOnKeyPreIme;

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

        @Override
@@ -460,6 +476,7 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
        public void onBackInvoked() throws RemoteException {
            mHandler.post(() -> {
                mTouchTracker.reset();
                if (consumedByOnKeyPreIme()) return;
                boolean isInProgress = mProgressAnimator.isBackAnimationInProgress();
                final OnBackInvokedCallback callback = mCallback.get();
                if (callback == null) {
@@ -481,6 +498,30 @@ public class WindowOnBackInvokedDispatcher implements OnBackInvokedDispatcher {
            });
        }

        private boolean consumedByOnKeyPreIme() {
            final OnBackInvokedCallback callback = mCallback.get();
            if (callback instanceof ImeBackAnimationController
                    || callback instanceof ImeOnBackInvokedDispatcher.ImeOnBackInvokedCallback) {
                // call onKeyPreIme API if the current callback is an IME callback and the app has
                // not set enableOnBackInvokedCallback="false"
                try {
                    boolean consumed = mOnKeyPreIme.getAsBoolean();
                    if (consumed) {
                        // back event intercepted by app in onKeyPreIme -> cancel the IME animation.
                        final OnBackAnimationCallback animationCallback =
                                getBackAnimationCallback();
                        if (animationCallback != null) {
                            mProgressAnimator.onBackCancelled(animationCallback::onBackCancelled);
                        }
                        return true;
                    }
                } catch (Exception e) {
                    Log.d(TAG, "Failed to call onKeyPreIme", e);
                }
            }
            return false;
        }

        @Override
        public void setTriggerBack(boolean triggerBack) throws RemoteException {
            mTouchTracker.setTriggerBack(triggerBack);
+15 −14
Original line number Diff line number Diff line
@@ -112,7 +112,7 @@ public class WindowOnBackInvokedDispatcherTest {
        doReturn(mApplicationInfo).when(mContext).getApplicationInfo();

        mDispatcher = new WindowOnBackInvokedDispatcher(mContext, Looper.getMainLooper());
        mDispatcher.attachToWindow(mWindowSession, mWindow, mImeBackAnimationController);
        mDispatcher.attachToWindow(mWindowSession, mWindow, null, mImeBackAnimationController);
    }

    private void waitForIdle() {
@@ -455,25 +455,26 @@ public class WindowOnBackInvokedDispatcherTest {

    @Test
    public void registerImeCallbacks_onBackInvokedCallbackEnabled() throws RemoteException {
        mDispatcher.registerOnBackInvokedCallback(PRIORITY_DEFAULT, mDefaultImeCallback);
        verifyImeCallackRegistrations();
    }

    @Test
    public void registerImeCallbacks_onBackInvokedCallbackDisabled() throws RemoteException {
        doReturn(false).when(mApplicationInfo).isOnBackInvokedCallbackEnabled();
        verifyImeCallackRegistrations();
    }

    private void verifyImeCallackRegistrations() throws RemoteException {
        // verify default callback is replaced with ImeBackAnimationController
        mDispatcher.registerOnBackInvokedCallbackUnchecked(mDefaultImeCallback, PRIORITY_DEFAULT);
        assertCallbacksSize(/* default */ 1, /* overlay */ 0);
        assertSetCallbackInfo();
        assertTopCallback(mImeBackAnimationController);

        mDispatcher.registerOnBackInvokedCallback(PRIORITY_DEFAULT, mImeCallback);
        // verify regular ime callback is successfully registered
        mDispatcher.registerOnBackInvokedCallbackUnchecked(mImeCallback, PRIORITY_DEFAULT);
        assertCallbacksSize(/* default */ 2, /* overlay */ 0);
        assertSetCallbackInfo();
        assertTopCallback(mImeCallback);
    }

    @Test
    public void registerImeCallbacks_legacyBack() throws RemoteException {
        doReturn(false).when(mApplicationInfo).isOnBackInvokedCallbackEnabled();

        mDispatcher.registerOnBackInvokedCallback(PRIORITY_DEFAULT, mDefaultImeCallback);
        assertNoSetCallbackInfo();

        mDispatcher.registerOnBackInvokedCallback(PRIORITY_DEFAULT, mImeCallback);
        assertNoSetCallbackInfo();
    }
}
+1 −1
Original line number Diff line number Diff line
@@ -550,7 +550,7 @@ public class BackNavigationControllerTests extends WindowTestsBase {
        }).when(appWindow.mSession).setOnBackInvokedCallbackInfo(eq(appWindow.mClient), any());

        addToWindowMap(appWindow, true);
        dispatcher.attachToWindow(appWindow.mSession, appWindow.mClient, null);
        dispatcher.attachToWindow(appWindow.mSession, appWindow.mClient, null, null);


        OnBackInvokedCallback appCallback = createBackCallback(appLatch);