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

Commit 6a20a194 authored by Dake Gu's avatar Dake Gu
Browse files

autofill: pass keyevent from fillui to app

Since autofill window was made to have window focus, app lost the
ability to accept physical keyboard typing. User can no longer
type on physical keyboard to filter autofill result.

This CL dispatches unhandled keyevent(e.g. A/B/C) from autofill
window to app ViewRootImpl in a similar way InputMethodService
dispatches keyevent to app's ViewRoot.

The unhandled key is sent to app window's ViewRootImpl
PreImeStage so that the keystroke could be translated to CJK by IME.

This CL does not affect fullscreen autofill window for TV  where app
window is fully covered: user has to close fullscreen autofill window
first.

Bug: 72951156
Test: atest CtsAutoFillServiceTestCases:LoginActivityTest

Change-Id: I8e50cfdfe8d5691d2b248d85f924c38488ca30f4
parent 961b465a
Loading
Loading
Loading
Loading
+13 −0
Original line number Diff line number Diff line
@@ -7611,6 +7611,19 @@ public class Activity extends ContextThemeWrapper
        return !wasShowing && mAutofillPopupWindow.isShowing();
    }

    /** @hide */
    @Override
    public final void autofillClientDispatchUnhandledKey(@NonNull View anchor,
            @NonNull KeyEvent keyEvent) {
        ViewRootImpl rootImpl = anchor.getViewRootImpl();
        if (rootImpl != null) {
            // dont care if anchorView is current focus, for example a custom view may only receive
            // touchEvent, not focusable but can still trigger autofill window. The Key handling
            // might be inside parent of the custom view.
            rootImpl.dispatchKeyFromAutofill(keyEvent);
        }
    }

    /** @hide */
    @Override
    public final boolean autofillClientRequestHideFillUi() {
+21 −1
Original line number Diff line number Diff line
@@ -3925,6 +3925,7 @@ public final class ViewRootImpl implements ViewParent,
    private final static int MSG_DISPATCH_APP_VISIBILITY = 8;
    private final static int MSG_DISPATCH_GET_NEW_SURFACE = 9;
    private final static int MSG_DISPATCH_KEY_FROM_IME = 11;
    private final static int MSG_DISPATCH_KEY_FROM_AUTOFILL = 12;
    private final static int MSG_CHECK_FOCUS = 13;
    private final static int MSG_CLOSE_SYSTEM_DIALOGS = 14;
    private final static int MSG_DISPATCH_DRAG_EVENT = 15;
@@ -3966,6 +3967,8 @@ public final class ViewRootImpl implements ViewParent,
                    return "MSG_DISPATCH_GET_NEW_SURFACE";
                case MSG_DISPATCH_KEY_FROM_IME:
                    return "MSG_DISPATCH_KEY_FROM_IME";
                case MSG_DISPATCH_KEY_FROM_AUTOFILL:
                    return "MSG_DISPATCH_KEY_FROM_AUTOFILL";
                case MSG_CHECK_FOCUS:
                    return "MSG_CHECK_FOCUS";
                case MSG_CLOSE_SYSTEM_DIALOGS:
@@ -4143,6 +4146,15 @@ public final class ViewRootImpl implements ViewParent,
                    }
                    enqueueInputEvent(event, null, QueuedInputEvent.FLAG_DELIVER_POST_IME, true);
                } break;
                case MSG_DISPATCH_KEY_FROM_AUTOFILL: {
                    if (LOCAL_LOGV) {
                        Log.v(TAG, "Dispatching key " + msg.obj + " from Autofill to " + mView);
                    }
                    KeyEvent event = (KeyEvent) msg.obj;
                    // send InputEvent to pre IME, set FLAG_FROM_AUTOFILL so the InputEvent
                    // wont be dropped as app window is not focus.
                    enqueueInputEvent(event, null, QueuedInputEvent.FLAG_FROM_AUTOFILL, true);
                } break;
                case MSG_CHECK_FOCUS: {
                    InputMethodManager imm = InputMethodManager.peekInstance();
                    if (imm != null) {
@@ -4433,7 +4445,8 @@ public final class ViewRootImpl implements ViewParent,
                Slog.w(mTag, "Dropping event due to root view being removed: " + q.mEvent);
                return true;
            } else if ((!mAttachInfo.mHasWindowFocus
                    && !q.mEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) || mStopped
                    && !q.mEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER)
                    && (q.mFlags & QueuedInputEvent.FLAG_FROM_AUTOFILL) == 0) || mStopped
                    || (mIsAmbientMode && !q.mEvent.isFromSource(InputDevice.SOURCE_CLASS_BUTTON))
                    || (mPausedForTransition && !isBack(q.mEvent))) {
                // This is a focus event and the window doesn't currently have input focus or
@@ -6805,6 +6818,7 @@ public final class ViewRootImpl implements ViewParent,
        public static final int FLAG_FINISHED_HANDLED = 1 << 3;
        public static final int FLAG_RESYNTHESIZED = 1 << 4;
        public static final int FLAG_UNHANDLED = 1 << 5;
        public static final int FLAG_FROM_AUTOFILL = 1 << 6;

        public QueuedInputEvent mNext;

@@ -7262,6 +7276,12 @@ public final class ViewRootImpl implements ViewParent,
        mHandler.sendMessage(msg);
    }

    public void dispatchKeyFromAutofill(KeyEvent event) {
        Message msg = mHandler.obtainMessage(MSG_DISPATCH_KEY_FROM_AUTOFILL, event);
        msg.setAsynchronous(true);
        mHandler.sendMessage(msg);
    }

    /**
     * Reinject unhandled {@link InputEvent}s in order to synthesize fallbacks events.
     *
+34 −0
Original line number Diff line number Diff line
@@ -45,6 +45,7 @@ import android.util.ArraySet;
import android.util.Log;
import android.util.SparseArray;
import android.view.Choreographer;
import android.view.KeyEvent;
import android.view.View;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
@@ -408,6 +409,13 @@ public final class AutofillManager {
        boolean autofillClientRequestShowFillUi(@NonNull View anchor, int width, int height,
                @Nullable Rect virtualBounds, IAutofillWindowPresenter presenter);

        /**
         * Dispatch unhandled keyevent from Autofill window
         * @param anchor The real view the UI needs to anchor to.
         * @param keyEvent Unhandled KeyEvent from autofill window.
         */
        void autofillClientDispatchUnhandledKey(@NonNull View anchor, @NonNull KeyEvent keyEvent);

        /**
         * Request hiding the autofill UI.
         *
@@ -1666,6 +1674,24 @@ public final class AutofillManager {
        }
    }

    private void dispatchUnhandledKey(int sessionId, AutofillId id, KeyEvent keyEvent) {
        final View anchor = findView(id);
        if (anchor == null) {
            return;
        }

        AutofillCallback callback = null;
        synchronized (mLock) {
            if (mSessionId == sessionId) {
                AutofillClient client = getClient();

                if (client != null) {
                    client.autofillClientDispatchUnhandledKey(anchor, keyEvent);
                }
            }
        }
    }

    /** @hide */
    public static final int SET_STATE_FLAG_ENABLED = 0x01;
    /** @hide */
@@ -2607,6 +2633,14 @@ public final class AutofillManager {
            }
        }

        @Override
        public void dispatchUnhandledKey(int sessionId, AutofillId id, KeyEvent fullScreen) {
            final AutofillManager afm = mAfm.get();
            if (afm != null) {
                afm.post(() -> afm.dispatchUnhandledKey(sessionId, id, fullScreen));
            }
        }

        @Override
        public void startIntentSender(IntentSender intentSender, Intent intent) {
            final AutofillManager afm = mAfm.get();
+8 −0
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ import android.os.IBinder;
import android.view.autofill.AutofillId;
import android.view.autofill.AutofillValue;
import android.view.autofill.IAutofillWindowPresenter;
import android.view.KeyEvent;

/**
 * Object running in the application process and responsible for autofilling it.
@@ -73,6 +74,13 @@ oneway interface IAutoFillManagerClient {
     */
    void notifyNoFillUi(int sessionId, in AutofillId id, int sessionFinishedState);

    /**
     * Dispatches unhandled keyevent from autofill ui. Autofill ui handles DPAD and ENTER events,
     * other unhandled keyevents are dispatched to app's window to filter autofill result.
     * Note this method is not called when autofill ui is in fullscreen mode (TV only).
     */
    void dispatchUnhandledKey(int sessionId, in AutofillId id, in KeyEvent keyEvent);

    /**
     * Starts the provided intent sender.
     */
+3 −2
Original line number Diff line number Diff line
@@ -14,7 +14,8 @@
     limitations under the License.
-->

<FrameLayout  xmlns:android="http://schemas.android.com/apk/res/android"
<view  xmlns:android="http://schemas.android.com/apk/res/android"
    class="com.android.server.autofill.ui.FillUi$AutofillFrameLayout"
    android:id="@+id/autofill_dataset_picker"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
@@ -30,4 +31,4 @@
        android:visibility="gone">
    </ListView>

</FrameLayout>
</view>
Loading