Loading core/java/android/app/Activity.java +13 −0 Original line number Diff line number Diff line Loading @@ -7622,6 +7622,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() { Loading core/java/android/view/ViewRootImpl.java +21 −1 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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: Loading Loading @@ -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) { Loading Loading @@ -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 Loading Loading @@ -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; Loading Loading @@ -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. * Loading core/java/android/view/autofill/AutofillManager.java +34 −0 Original line number Diff line number Diff line Loading @@ -46,6 +46,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; Loading Loading @@ -410,6 +411,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. * Loading Loading @@ -1668,6 +1676,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 */ Loading Loading @@ -2609,6 +2635,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(); Loading core/java/android/view/autofill/IAutoFillManagerClient.aidl +8 −0 Original line number Diff line number Diff line Loading @@ -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. Loading Loading @@ -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. */ Loading core/res/res/layout/autofill_dataset_picker.xml +3 −2 Original line number Diff line number Diff line Loading @@ -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" Loading @@ -30,4 +31,4 @@ android:visibility="gone"> </ListView> </FrameLayout> </view> Loading
core/java/android/app/Activity.java +13 −0 Original line number Diff line number Diff line Loading @@ -7622,6 +7622,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() { Loading
core/java/android/view/ViewRootImpl.java +21 −1 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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: Loading Loading @@ -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) { Loading Loading @@ -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 Loading Loading @@ -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; Loading Loading @@ -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. * Loading
core/java/android/view/autofill/AutofillManager.java +34 −0 Original line number Diff line number Diff line Loading @@ -46,6 +46,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; Loading Loading @@ -410,6 +411,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. * Loading Loading @@ -1668,6 +1676,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 */ Loading Loading @@ -2609,6 +2635,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(); Loading
core/java/android/view/autofill/IAutoFillManagerClient.aidl +8 −0 Original line number Diff line number Diff line Loading @@ -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. Loading Loading @@ -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. */ Loading
core/res/res/layout/autofill_dataset_picker.xml +3 −2 Original line number Diff line number Diff line Loading @@ -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" Loading @@ -30,4 +31,4 @@ android:visibility="gone"> </ListView> </FrameLayout> </view>