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

Commit de9005c3 authored by TYM Tsai's avatar TYM Tsai
Browse files

Fix Autofill dialog does not work

Apps have only one chance to get Autofill dialog support, it requires
attaching the autofillable view before the Activity has finished
laying out. This change moves the doing request to the view being
laid out, that is the same timing with what Autofill is doing about
the view is auto focused but under different conditions.

Bug: 226674898
Test: atest android.autofillservice.cts.dialog.LoginActivityTest
Change-Id: I9018b8db8673e3b917a303476666ae766fbe7891
Merged-In: I9018b8db8673e3b917a303476666ae766fbe7891
parent 3f598fad
Loading
Loading
Loading
Loading
+11 −10
Original line number Diff line number Diff line
@@ -8206,24 +8206,25 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
        if (canNotifyAutofillEnterExitEvent()) {
            AutofillManager afm = getAutofillManager();
            if (afm != null) {
                if (enter && isFocused()) {
                if (enter) {
                    // We have not been laid out yet, hence cannot evaluate
                    // whether this view is visible to the user, we will do
                    // the evaluation once layout is complete.
                    if (!isLaidOut()) {
                        mPrivateFlags3 |= PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT;
                    } else if (isVisibleToUser()) {
                        // TODO This is a potential problem that View gets focus before it's visible
                        // to User. Ideally View should handle the event when isVisibleToUser()
                        // becomes true where it should issue notifyViewEntered().
                        if (isFocused()) {
                            // TODO This is a potential problem that View gets focus before it's
                            // visible to User. Ideally View should handle the event when
                            // isVisibleToUser() becomes true where it should issue
                            // notifyViewEntered().
                            afm.notifyViewEntered(this);
                        } else {
                        afm.enableFillRequestActivityStarted(this);
                            afm.notifyViewEnteredForFillDialog(this);
                        }
                    }
                } else if (!enter && !isFocused()) {
                } else if (!isFocused()) {
                    afm.notifyViewExited(this);
                } else if (enter) {
                    afm.enableFillRequestActivityStarted(this);
                }
            }
        }
+0 −14
Original line number Diff line number Diff line
@@ -585,7 +585,6 @@ public final class ViewRootImpl implements ViewParent,
    @Nullable
    int mContentCaptureEnabled = CONTENT_CAPTURE_ENABLED_NOT_CHECKED;
    boolean mPerformContentCapture;
    boolean mPerformAutoFill;


    boolean mReportNextDraw;
@@ -883,7 +882,6 @@ public final class ViewRootImpl implements ViewParent,
        mPreviousTransparentRegion = new Region();
        mFirst = true; // true for the first time the view is added
        mPerformContentCapture = true; // also true for the first time the view is added
        mPerformAutoFill = true;
        mAdded = false;
        mAttachInfo = new View.AttachInfo(mWindowSession, mWindow, display, this, mHandler, this,
                context);
@@ -4310,18 +4308,6 @@ public final class ViewRootImpl implements ViewParent,
        if (mPerformContentCapture) {
            performContentCaptureInitialReport();
        }

        if (mPerformAutoFill) {
            notifyEnterForAutoFillIfNeeded();
        }
    }

    private void notifyEnterForAutoFillIfNeeded() {
        mPerformAutoFill = false;
        final AutofillManager afm = getAutofillManager();
        if (afm != null) {
            afm.notifyViewEnteredForActivityStarted(mView);
        }
    }

    /**
+20 −41
Original line number Diff line number Diff line
@@ -102,6 +102,7 @@ import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;

import sun.misc.Cleaner;

@@ -644,16 +645,6 @@ public final class AutofillManager {
    @GuardedBy("mLock")
    private boolean mEnabledForAugmentedAutofillOnly;

    /**
     * Indicates whether there are any fields that need to do a fill request
     * after the activity starts.
     *
     * Note: This field will be set to true multiple times if there are many
     * autofillable views. So needs to check mIsFillRequested at the same time to
     * avoid re-trigger autofill.
     */
    private boolean mRequireAutofill;

    /**
     * Indicates whether there is already a field to do a fill request after
     * the activity started.
@@ -663,7 +654,7 @@ public final class AutofillManager {
     * triggered autofill, it is unnecessary to trigger again through
     * AutofillManager#notifyViewEnteredForActivityStarted.
     */
    private boolean mIsFillRequested;
    private AtomicBoolean mIsFillRequested;

    @Nullable private List<AutofillId> mFillDialogTriggerIds;

@@ -811,8 +802,7 @@ public final class AutofillManager {
        mContext = Objects.requireNonNull(context, "context cannot be null");
        mService = service;
        mOptions = context.getAutofillOptions();
        mIsFillRequested = false;
        mRequireAutofill = false;
        mIsFillRequested = new AtomicBoolean(false);

        mIsFillDialogEnabled = DeviceConfig.getBoolean(
                DeviceConfig.NAMESPACE_AUTOFILL,
@@ -1113,46 +1103,36 @@ public final class AutofillManager {
    }

    /**
     * The view have the allowed autofill hints, marked to perform a fill request after layout if
     * the field does not trigger a fill request.
     * The {@link #DEVICE_CONFIG_AUTOFILL_DIALOG_ENABLED} is {@code true} or the view have
     * the allowed autofill hints, performs a fill request to know there is any field supported
     * fill dialog.
     *
     * @hide
     */
    public void enableFillRequestActivityStarted(View v) {
        if (mRequireAutofill) {
    public void notifyViewEnteredForFillDialog(View v) {
        // Skip if the fill request has been performed for a view.
        if (mIsFillRequested.get()) {
            return;
        }

        if (mIsFillDialogEnabled
                || ArrayUtils.containsAny(v.getAutofillHints(), mFillDialogEnabledHints)) {
            if (sDebug) {
                Log.d(TAG, "Trigger fill request at starting");
            }
            mRequireAutofill = true;
        }
                Log.d(TAG, "Trigger fill request at view entered");
            }

    private boolean hasFillDialogUiFeature() {
        return mIsFillDialogEnabled || !ArrayUtils.isEmpty(mFillDialogEnabledHints);
    }
            // Note: No need for atomic getAndSet as this method is called on the UI thread.
            mIsFillRequested.set(true);

    /**
     * Notify autofill to do a fill request while the activity started.
     *
     * @hide
     */
    public void notifyViewEnteredForActivityStarted(@NonNull View view) {
        if (!hasAutofillFeature() || !hasFillDialogUiFeature()) {
            return;
            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);
        }

        if (!mRequireAutofill || mIsFillRequested) {
            return;
    }

        int flags = FLAG_SUPPORTS_FILL_DIALOG;
        flags |= FLAG_VIEW_NOT_FOCUSED;
        notifyViewEntered(view, flags);
    private boolean hasFillDialogUiFeature() {
        return mIsFillDialogEnabled || !ArrayUtils.isEmpty(mFillDialogEnabledHints);
    }

    private int getImeStateFlag(View v) {
@@ -1203,7 +1183,7 @@ public final class AutofillManager {
        }
        AutofillCallback callback;
        synchronized (mLock) {
            mIsFillRequested = true;
            mIsFillRequested.set(true);
            callback = notifyViewEnteredLocked(view, flags);
        }

@@ -2119,8 +2099,7 @@ public final class AutofillManager {
        mFillableIds = null;
        mSaveTriggerId = null;
        mIdShownFillUi = null;
        mIsFillRequested = false;
        mRequireAutofill = false;
        mIsFillRequested.set(false);
        mShowAutofillDialogCalled = false;
        mFillDialogTriggerIds = null;
        if (resetEnteredIds) {