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

Commit 5753b4fb authored by Shan Huang's avatar Shan Huang Committed by Automerger Merge Worker
Browse files

Merge "Migrate IME to handle back with OnBackInvokedDispatcher." into tm-dev...

Merge "Migrate IME to handle back with OnBackInvokedDispatcher." into tm-dev am: e3a61826 am: 4472170c am: 78c429f9

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/17952046



Change-Id: I297c0cfde12b4c668203400446e897f51c0d543b
Signed-off-by: default avatarAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
parents 333762b7 78c429f9
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -800,6 +800,7 @@ package android.content.pm {
    method public boolean hasRequestForegroundServiceExemption();
    method public boolean isPrivilegedApp();
    method public boolean isSystemApp();
    method public void setEnableOnBackInvokedCallback(boolean);
    field public static final int PRIVATE_FLAG_PRIVILEGED = 8; // 0x8
    field public int privateFlags;
  }
+17 −0
Original line number Diff line number Diff line
@@ -2752,4 +2752,21 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
            mKnownActivityEmbeddingCerts.add(knownCert.toUpperCase(Locale.US));
        }
    }

    /**
     * Sets whether the application will use the {@link android.window.OnBackInvokedCallback}
     * navigation system instead of the {@link android.view.KeyEvent#KEYCODE_BACK} and related
     * callbacks. Intended to be used from tests only.
     *
     * @see #isOnBackInvokedCallbackEnabled()
     * @hide
     */
    @TestApi
    public void setEnableOnBackInvokedCallback(boolean isEnable) {
        if (isEnable) {
            privateFlagsExt |= PRIVATE_FLAG_EXT_ENABLE_ON_BACK_INVOKED_CALLBACK;
        } else {
            privateFlagsExt &= ~PRIVATE_FLAG_EXT_ENABLE_ON_BACK_INVOKED_CALLBACK;
        }
    }
}
+11 −4
Original line number Diff line number Diff line
@@ -37,6 +37,7 @@ import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputMethod;
import android.view.inputmethod.InputMethodSession;
import android.view.inputmethod.InputMethodSubtype;
import android.window.ImeOnBackInvokedDispatcher;

import com.android.internal.inputmethod.CancellationGroup;
import com.android.internal.inputmethod.IInputMethodPrivilegedOperations;
@@ -194,7 +195,9 @@ class IInputMethodWrapper extends IInputMethod.Stub
            case DO_START_INPUT: {
                final SomeArgs args = (SomeArgs) msg.obj;
                final IBinder startInputToken = (IBinder) args.arg1;
                final IInputContext inputContext = (IInputContext) args.arg2;
                final IInputContext inputContext = (IInputContext) ((SomeArgs) args.arg2).arg1;
                final ImeOnBackInvokedDispatcher imeDispatcher =
                        (ImeOnBackInvokedDispatcher) ((SomeArgs) args.arg2).arg2;
                final EditorInfo info = (EditorInfo) args.arg3;
                final CancellationGroup cancellationGroup = (CancellationGroup) args.arg4;
                final boolean restarting = args.argi5 == 1;
@@ -205,7 +208,7 @@ class IInputMethodWrapper extends IInputMethod.Stub
                        : null;
                info.makeCompatible(mTargetSdkVersion);
                inputMethod.dispatchStartInputWithToken(ic, info, restarting, startInputToken,
                        navButtonFlags);
                        navButtonFlags, imeDispatcher);
                args.recycle();
                return;
            }
@@ -348,13 +351,17 @@ class IInputMethodWrapper extends IInputMethod.Stub
    @Override
    public void startInput(IBinder startInputToken, IInputContext inputContext,
            EditorInfo attribute, boolean restarting,
            @InputMethodNavButtonFlags int navButtonFlags) {
            @InputMethodNavButtonFlags int navButtonFlags,
            @NonNull ImeOnBackInvokedDispatcher imeDispatcher) {
        if (mCancellationGroup == null) {
            Log.e(TAG, "startInput must be called after bindInput.");
            mCancellationGroup = new CancellationGroup();
        }
        SomeArgs args = SomeArgs.obtain();
        args.arg1 = inputContext;
        args.arg2 = imeDispatcher;
        mCaller.executeOrSendMessage(mCaller.obtainMessageOOOOII(DO_START_INPUT, startInputToken,
                inputContext, attribute, mCancellationGroup, restarting ? 1 : 0, navButtonFlags));
                args, attribute, mCancellationGroup, restarting ? 1 : 0, navButtonFlags));
    }

    @BinderThread
+69 −1
Original line number Diff line number Diff line
@@ -101,6 +101,7 @@ import android.view.BatchedInputEventReceiver.SimpleBatchedInputEventReceiver;
import android.view.Choreographer;
import android.view.Gravity;
import android.view.InputChannel;
import android.view.InputDevice;
import android.view.InputEventReceiver;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
@@ -134,6 +135,9 @@ import android.widget.FrameLayout;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.window.ImeOnBackInvokedDispatcher;
import android.window.OnBackInvokedCallback;
import android.window.OnBackInvokedDispatcher;
import android.window.WindowMetricsHelper;

import com.android.internal.annotations.GuardedBy;
@@ -344,6 +348,9 @@ public class InputMethodService extends AbstractInputMethodService {
     * A circular buffer of size MAX_EVENTS_BUFFER in case IME is taking too long to add ink view.
     **/
    private RingBuffer<MotionEvent> mPendingEvents;
    private ImeOnBackInvokedDispatcher mImeDispatcher;
    private Boolean mBackCallbackRegistered = false;
    private final OnBackInvokedCallback mCompatBackCallback = this::compatHandleBack;

    /**
     * Returns whether {@link InputMethodService} is responsible for rendering the back button and
@@ -797,7 +804,13 @@ public class InputMethodService extends AbstractInputMethodService {
        @Override
        public final void dispatchStartInputWithToken(@Nullable InputConnection inputConnection,
                @NonNull EditorInfo editorInfo, boolean restarting,
                @NonNull IBinder startInputToken, @InputMethodNavButtonFlags int navButtonFlags) {
                @NonNull IBinder startInputToken, @InputMethodNavButtonFlags int navButtonFlags,
                @NonNull ImeOnBackInvokedDispatcher imeDispatcher) {
            mImeDispatcher = imeDispatcher;
            if (mWindow != null) {
                mWindow.getOnBackInvokedDispatcher().setImeOnBackInvokedDispatcher(
                        imeDispatcher);
            }
            mPrivOps.reportStartInputAsync(startInputToken);
            mNavigationBarController.onNavButtonFlagsChanged(navButtonFlags);
            if (restarting) {
@@ -1496,6 +1509,10 @@ public class InputMethodService extends AbstractInputMethodService {
                Context.LAYOUT_INFLATER_SERVICE);
        Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.initSoftInputWindow");
        mWindow = new SoftInputWindow(this, mTheme, mDispatcherState);
        if (mImeDispatcher != null) {
            mWindow.getOnBackInvokedDispatcher()
                    .setImeOnBackInvokedDispatcher(mImeDispatcher);
        }
        mNavigationBarController.onSoftInputWindowCreated(mWindow);
        {
            final Window window = mWindow.getWindow();
@@ -1608,6 +1625,8 @@ public class InputMethodService extends AbstractInputMethodService {
            // when IME developers are doing something unsupported.
            InputMethodPrivilegedOperationsRegistry.remove(mToken);
        }
        unregisterCompatOnBackInvokedCallback();
        mImeDispatcher = null;
    }

    /**
@@ -2568,9 +2587,47 @@ public class InputMethodService extends AbstractInputMethodService {
        cancelImeSurfaceRemoval();
        mInShowWindow = false;
        Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
        registerCompatOnBackInvokedCallback();
    }


    /**
     * Registers an {@link OnBackInvokedCallback} to handle back invocation when ahead-of-time
     *  back dispatching is enabled. We keep the {@link KeyEvent#KEYCODE_BACK} based legacy code
     *  around to handle back on older devices.
     */
    private void registerCompatOnBackInvokedCallback() {
        if (mBackCallbackRegistered) {
            return;
        }
        if (mWindow != null) {
            mWindow.getOnBackInvokedDispatcher().registerOnBackInvokedCallback(
                    OnBackInvokedDispatcher.PRIORITY_DEFAULT, mCompatBackCallback);
            mBackCallbackRegistered = true;
        }
    }

    private void unregisterCompatOnBackInvokedCallback() {
        if (!mBackCallbackRegistered) {
            return;
        }
        if (mWindow != null) {
            mWindow.getOnBackInvokedDispatcher()
                    .unregisterOnBackInvokedCallback(mCompatBackCallback);
            mBackCallbackRegistered = false;
        }
    }

    private KeyEvent createBackKeyEvent(int action, boolean isTracking) {
        final long when = SystemClock.uptimeMillis();
        return 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
                        | (isTracking ? KeyEvent.FLAG_TRACKING : 0),
                InputDevice.SOURCE_KEYBOARD);
    }

    private boolean prepareWindow(boolean showInput) {
        boolean doShowInput = false;
        mDecorViewVisible = true;
@@ -2658,6 +2715,7 @@ public class InputMethodService extends AbstractInputMethodService {
        }
        mLastWasInFullscreenMode = mIsFullscreen;
        updateFullscreenMode();
        unregisterCompatOnBackInvokedCallback();
    }

    /**
@@ -3797,4 +3855,14 @@ public class InputMethodService extends AbstractInputMethodService {
            proto.end(token);
        }
    };

    private void compatHandleBack() {
        final KeyEvent downEvent = createBackKeyEvent(
                KeyEvent.ACTION_DOWN, false /* isTracking */);
        onKeyDown(KeyEvent.KEYCODE_BACK, downEvent);
        final boolean hasStartedTracking =
                (downEvent.getFlags() & KeyEvent.FLAG_START_TRACKING) != 0;
        final KeyEvent upEvent = createBackKeyEvent(KeyEvent.ACTION_UP, hasStartedTracking);
        onKeyUp(KeyEvent.KEYCODE_BACK, upEvent);
    }
}
+22 −18
Original line number Diff line number Diff line
@@ -6110,6 +6110,28 @@ public final class ViewRootImpl implements ViewParent,

        @Override
        protected int onProcess(QueuedInputEvent q) {
            if (q.mEvent instanceof KeyEvent) {
                final KeyEvent event = (KeyEvent) q.mEvent;

                // If the new back dispatch is enabled, intercept KEYCODE_BACK before it reaches the
                // view tree or IME, and invoke the appropriate {@link OnBackInvokedCallback}.
                if (isBack(event)
                        && mContext != null
                        && WindowOnBackInvokedDispatcher.isOnBackInvokedCallbackEnabled(mContext)) {
                    OnBackInvokedCallback topCallback =
                            getOnBackInvokedDispatcher().getTopCallback();
                    if (event.getAction() == KeyEvent.ACTION_UP) {
                        if (topCallback != null) {
                            topCallback.onBackInvoked();
                            return FINISH_HANDLED;
                        }
                    } else {
                        // Drop other actions such as {@link KeyEvent.ACTION_DOWN}.
                        return FINISH_NOT_HANDLED;
                    }
                }
            }

            if (mInputQueue != null && q.mEvent instanceof KeyEvent) {
                mInputQueue.sendInputEvent(q.mEvent, q, true, this);
                return DEFER;
@@ -6461,24 +6483,6 @@ public final class ViewRootImpl implements ViewParent,
                return FINISH_HANDLED;
            }

            // If the new back dispatch is enabled, intercept KEYCODE_BACK before it reaches the
            // view tree and invoke the appropriate {@link OnBackInvokedCallback}.
            if (isBack(event)
                    && mContext != null
                    && WindowOnBackInvokedDispatcher.isOnBackInvokedCallbackEnabled(mContext)) {
                OnBackInvokedCallback topCallback =
                        getOnBackInvokedDispatcher().getTopCallback();
                if (event.getAction() == KeyEvent.ACTION_UP) {
                    if (topCallback != null) {
                        topCallback.onBackInvoked();
                        return FINISH_HANDLED;
                    }
                } else {
                    // Drop other actions such as {@link KeyEvent.ACTION_DOWN}.
                    return FINISH_NOT_HANDLED;
                }
            }

            // Deliver the key to the view hierarchy.
            if (mView.dispatchKeyEvent(event)) {
                return FINISH_HANDLED;
Loading