From 78bdebcf6a24bb133532987c705709f745823000 Mon Sep 17 00:00:00 2001 From: TYM Tsai Date: Thu, 10 Nov 2022 07:30:35 +0800 Subject: [PATCH] Fix prefill request is blocked waiting for an inline request. When asking the IME for an inline request, the IME will check if the autofill id of the target view matches the id of the current IME served view, otherwise the IME does not respond inline request to the Autofill. When an activity starts, the id of the IME served view is reset to 0. And the target view, Autofill used to do the pre-fill request is the root view, sometimes its id is not 0. Then the request is blocked to wait for an inline request because autofill does not have a timeout mechanism. To resolve this issue, use AutofillId.NO_AUTOFILL_ID to make sure the id of the pre-fill request is 0. Also this change remove the duplicate code about the notifyViewEnteredLocked for normal view and virtual view. Bug: 258532947 Bug: 253180120 Test Manual Test: atest CtsAutoFillServiceTestCases Change-Id: I6962ab6d844fd8b7c9ba778ac40630586ef73c39 --- .../view/autofill/AutofillManager.java | 161 +++++++----------- 1 file changed, 60 insertions(+), 101 deletions(-) diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java index ef683b70172cf..a92bc945c0041 100644 --- a/core/java/android/view/autofill/AutofillManager.java +++ b/core/java/android/view/autofill/AutofillManager.java @@ -1197,6 +1197,9 @@ public final class AutofillManager { * @hide */ public void notifyViewEnteredForFillDialog(View v) { + if (!hasAutofillFeature()) { + return; + } synchronized (mLock) { if (mTrackedViews != null) { // To support the fill dialog can show for the autofillable Views in @@ -1218,13 +1221,18 @@ public final class AutofillManager { Log.d(TAG, "Trigger fill request at view entered"); } - // Note: No need for atomic getAndSet as this method is called on the UI thread. - mIsFillRequested.set(true); - int flags = FLAG_SUPPORTS_FILL_DIALOG; flags |= FLAG_VIEW_NOT_FOCUSED; - // use root view, so autofill UI does not trigger immediately. - notifyViewEntered(v.getRootView(), flags); + + synchronized (mLock) { + // To match the id of the IME served view, used AutofillId.NO_AUTOFILL_ID on prefill + // request, because IME will reset the id of IME served view to 0 when activity + // start and does not focus on any view. If the id of the prefill request is + // not match to the IME served view's, Autofill will be blocking to wait inline + // request from the IME. + notifyViewEnteredLocked(/* view= */ null, AutofillId.NO_AUTOFILL_ID, + /* bounds= */ null, /* value= */ null, flags); + } } } @@ -1233,6 +1241,8 @@ public final class AutofillManager { } private int getImeStateFlag(View v) { + if (v == null) return 0; + final WindowInsets rootWindowInsets = v.getRootWindowInsets(); if (rootWindowInsets != null && rootWindowInsets.isVisible(WindowInsets.Type.ime())) { return FLAG_IME_SHOWING; @@ -1280,8 +1290,8 @@ public final class AutofillManager { } AutofillCallback callback; synchronized (mLock) { - mIsFillRequested.set(true); - callback = notifyViewEnteredLocked(view, flags); + callback = notifyViewEnteredLocked( + view, view.getAutofillId(), /* bounds= */ null, view.getAutofillValue(), flags); } if (callback != null) { @@ -1289,62 +1299,6 @@ public final class AutofillManager { } } - /** Returns AutofillCallback if need fire EVENT_INPUT_UNAVAILABLE */ - @GuardedBy("mLock") - private AutofillCallback notifyViewEnteredLocked(@NonNull View view, int flags) { - final AutofillId id = view.getAutofillId(); - if (shouldIgnoreViewEnteredLocked(id, flags)) return null; - - AutofillCallback callback = null; - - final boolean clientAdded = tryAddServiceClientIfNeededLocked(); - - if (!clientAdded) { - if (sVerbose) Log.v(TAG, "ignoring notifyViewEntered(" + id + "): no service client"); - return callback; - } - - if (!mEnabled && !mEnabledForAugmentedAutofillOnly) { - if (sVerbose) Log.v(TAG, "ignoring notifyViewEntered(" + id + "): disabled"); - - if (mCallback != null) { - callback = mCallback; - } - } else { - // don't notify entered when Activity is already in background - if (!isClientDisablingEnterExitEvent()) { - final AutofillValue value = view.getAutofillValue(); - - if (view instanceof TextView && ((TextView) view).isAnyPasswordInputType()) { - flags |= FLAG_PASSWORD_INPUT_TYPE; - } - - flags |= getImeStateFlag(view); - - if (!isActiveLocked()) { - // Starts new session. - startSessionLocked(id, null, value, flags); - } else { - // Update focus on existing session. - if (mForAugmentedAutofillOnly && (flags & FLAG_MANUAL_REQUEST) != 0) { - if (sDebug) { - Log.d(TAG, "notifyViewEntered(" + id + "): resetting " - + "mForAugmentedAutofillOnly on manual request"); - } - mForAugmentedAutofillOnly = false; - } - - if ((flags & FLAG_SUPPORTS_FILL_DIALOG) != 0) { - flags |= FLAG_RESET_FILL_DIALOG_STATE; - } - updateSessionLocked(id, null, value, ACTION_VIEW_ENTERED, flags); - } - addEnteredIdLocked(id); - } - } - return callback; - } - /** * Called when a {@link View} that supports autofill is exited. * @@ -1461,9 +1415,11 @@ public final class AutofillManager { if (!hasAutofillFeature()) { return; } + AutofillCallback callback; synchronized (mLock) { - callback = notifyViewEnteredLocked(view, virtualId, bounds, flags); + callback = notifyViewEnteredLocked( + view, getAutofillId(view, virtualId), bounds, /* value= */ null, flags); } if (callback != null) { @@ -1474,53 +1430,55 @@ public final class AutofillManager { /** Returns AutofillCallback if need fire EVENT_INPUT_UNAVAILABLE */ @GuardedBy("mLock") - private AutofillCallback notifyViewEnteredLocked(View view, int virtualId, Rect bounds, - int flags) { - final AutofillId id = getAutofillId(view, virtualId); - AutofillCallback callback = null; - if (shouldIgnoreViewEnteredLocked(id, flags)) return callback; + private AutofillCallback notifyViewEnteredLocked(@Nullable View view, AutofillId id, + Rect bounds, AutofillValue value, int flags) { + if (shouldIgnoreViewEnteredLocked(id, flags)) return null; final boolean clientAdded = tryAddServiceClientIfNeededLocked(); - if (!clientAdded) { if (sVerbose) Log.v(TAG, "ignoring notifyViewEntered(" + id + "): no service client"); - return callback; + return null; } if (!mEnabled && !mEnabledForAugmentedAutofillOnly) { if (sVerbose) { Log.v(TAG, "ignoring notifyViewEntered(" + id + "): disabled"); } - if (mCallback != null) { - callback = mCallback; - } - } else { - // don't notify entered when Activity is already in background - if (!isClientDisablingEnterExitEvent()) { - if (view instanceof TextView && ((TextView) view).isAnyPasswordInputType()) { - flags |= FLAG_PASSWORD_INPUT_TYPE; - } - - flags |= getImeStateFlag(view); - - if (!isActiveLocked()) { - // Starts new session. - startSessionLocked(id, bounds, null, flags); - } else { - // Update focus on existing session. - if (mForAugmentedAutofillOnly && (flags & FLAG_MANUAL_REQUEST) != 0) { - if (sDebug) { - Log.d(TAG, "notifyViewEntered(" + id + "): resetting " - + "mForAugmentedAutofillOnly on manual request"); - } - mForAugmentedAutofillOnly = false; - } - updateSessionLocked(id, bounds, null, ACTION_VIEW_ENTERED, flags); - } - addEnteredIdLocked(id); - } + return mCallback; } - return callback; + + mIsFillRequested.set(true); + + // don't notify entered when Activity is already in background + if (!isClientDisablingEnterExitEvent()) { + if (view instanceof TextView && ((TextView) view).isAnyPasswordInputType()) { + flags |= FLAG_PASSWORD_INPUT_TYPE; + } + + flags |= getImeStateFlag(view); + + if (!isActiveLocked()) { + // Starts new session. + startSessionLocked(id, bounds, value, flags); + } else { + // Update focus on existing session. + if (mForAugmentedAutofillOnly && (flags & FLAG_MANUAL_REQUEST) != 0) { + if (sDebug) { + Log.d(TAG, "notifyViewEntered(" + id + "): resetting " + + "mForAugmentedAutofillOnly on manual request"); + } + mForAugmentedAutofillOnly = false; + } + + if ((flags & FLAG_SUPPORTS_FILL_DIALOG) != 0) { + flags |= FLAG_RESET_FILL_DIALOG_STATE; + } + + updateSessionLocked(id, bounds, value, ACTION_VIEW_ENTERED, flags); + } + addEnteredIdLocked(id); + } + return null; } @GuardedBy("mLock") @@ -2025,7 +1983,8 @@ public final class AutofillManager { if (!mOnInvisibleCalled && focusView != null && focusView.canNotifyAutofillEnterExitEvent()) { notifyViewExitedLocked(focusView); - notifyViewEnteredLocked(focusView, 0); + notifyViewEnteredLocked(focusView, focusView.getAutofillId(), + /* bounds= */ null, focusView.getAutofillValue(), /* flags= */ 0); } if (data == null) { // data is set to null when result is not RESULT_OK