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

Commit 78bdebcf authored by TYM Tsai's avatar TYM Tsai
Browse files

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
parent b95aecc5
Loading
Loading
Loading
Loading
+54 −95
Original line number Diff line number Diff line
@@ -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,27 +1430,25 @@ 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;
            return mCallback;
        }
        } else {

        mIsFillRequested.set(true);

        // don't notify entered when Activity is already in background
        if (!isClientDisablingEnterExitEvent()) {
            if (view instanceof TextView && ((TextView) view).isAnyPasswordInputType()) {
@@ -1505,7 +1459,7 @@ public final class AutofillManager {

            if (!isActiveLocked()) {
                // Starts new session.
                    startSessionLocked(id, bounds, null, flags);
                startSessionLocked(id, bounds, value, flags);
            } else {
                // Update focus on existing session.
                if (mForAugmentedAutofillOnly && (flags & FLAG_MANUAL_REQUEST) != 0) {
@@ -1515,12 +1469,16 @@ public final class AutofillManager {
                    }
                    mForAugmentedAutofillOnly = false;
                }
                    updateSessionLocked(id, bounds, null, ACTION_VIEW_ENTERED, flags);

                if ((flags & FLAG_SUPPORTS_FILL_DIALOG) != 0) {
                    flags |= FLAG_RESET_FILL_DIALOG_STATE;
                }
                addEnteredIdLocked(id);

                updateSessionLocked(id, bounds, value, ACTION_VIEW_ENTERED, flags);
            }
            addEnteredIdLocked(id);
        }
        return callback;
        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