diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index dc3620bcc5e56..19a28ffd4e148 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -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(). - afm.notifyViewEntered(this); - } else { - afm.enableFillRequestActivityStarted(this); + 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.notifyViewEnteredForFillDialog(this); + } } - } else if (!enter && !isFocused()) { + } else if (!isFocused()) { afm.notifyViewExited(this); - } else if (enter) { - afm.enableFillRequestActivityStarted(this); } } } diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index fbb86ff3a55a8..4f00bed27cd3e 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -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); - } } /** diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java index 0a75992811f4b..dcedb3083f769 100644 --- a/core/java/android/view/autofill/AutofillManager.java +++ b/core/java/android/view/autofill/AutofillManager.java @@ -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 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,22 +1103,31 @@ 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"); + Log.d(TAG, "Trigger fill request at view entered"); } - mRequireAutofill = true; + + // 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); } } @@ -1136,25 +1135,6 @@ public final class AutofillManager { return mIsFillDialogEnabled || !ArrayUtils.isEmpty(mFillDialogEnabledHints); } - /** - * Notify autofill to do a fill request while the activity started. - * - * @hide - */ - public void notifyViewEnteredForActivityStarted(@NonNull View view) { - if (!hasAutofillFeature() || !hasFillDialogUiFeature()) { - return; - } - - if (!mRequireAutofill || mIsFillRequested) { - return; - } - - int flags = FLAG_SUPPORTS_FILL_DIALOG; - flags |= FLAG_VIEW_NOT_FOCUSED; - notifyViewEntered(view, flags); - } - private int getImeStateFlag(View v) { final WindowInsets rootWindowInsets = v.getRootWindowInsets(); if (rootWindowInsets != null && rootWindowInsets.isVisible(WindowInsets.Type.ime())) { @@ -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) {