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
This commit is contained in:
@@ -8206,24 +8206,25 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
|
|||||||
if (canNotifyAutofillEnterExitEvent()) {
|
if (canNotifyAutofillEnterExitEvent()) {
|
||||||
AutofillManager afm = getAutofillManager();
|
AutofillManager afm = getAutofillManager();
|
||||||
if (afm != null) {
|
if (afm != null) {
|
||||||
if (enter && isFocused()) {
|
if (enter) {
|
||||||
// We have not been laid out yet, hence cannot evaluate
|
// We have not been laid out yet, hence cannot evaluate
|
||||||
// whether this view is visible to the user, we will do
|
// whether this view is visible to the user, we will do
|
||||||
// the evaluation once layout is complete.
|
// the evaluation once layout is complete.
|
||||||
if (!isLaidOut()) {
|
if (!isLaidOut()) {
|
||||||
mPrivateFlags3 |= PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT;
|
mPrivateFlags3 |= PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT;
|
||||||
} else if (isVisibleToUser()) {
|
} else if (isVisibleToUser()) {
|
||||||
// TODO This is a potential problem that View gets focus before it's visible
|
if (isFocused()) {
|
||||||
// to User. Ideally View should handle the event when isVisibleToUser()
|
// TODO This is a potential problem that View gets focus before it's
|
||||||
// becomes true where it should issue notifyViewEntered().
|
// visible to User. Ideally View should handle the event when
|
||||||
afm.notifyViewEntered(this);
|
// isVisibleToUser() becomes true where it should issue
|
||||||
} else {
|
// notifyViewEntered().
|
||||||
afm.enableFillRequestActivityStarted(this);
|
afm.notifyViewEntered(this);
|
||||||
|
} else {
|
||||||
|
afm.notifyViewEnteredForFillDialog(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if (!enter && !isFocused()) {
|
} else if (!isFocused()) {
|
||||||
afm.notifyViewExited(this);
|
afm.notifyViewExited(this);
|
||||||
} else if (enter) {
|
|
||||||
afm.enableFillRequestActivityStarted(this);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -585,7 +585,6 @@ public final class ViewRootImpl implements ViewParent,
|
|||||||
@Nullable
|
@Nullable
|
||||||
int mContentCaptureEnabled = CONTENT_CAPTURE_ENABLED_NOT_CHECKED;
|
int mContentCaptureEnabled = CONTENT_CAPTURE_ENABLED_NOT_CHECKED;
|
||||||
boolean mPerformContentCapture;
|
boolean mPerformContentCapture;
|
||||||
boolean mPerformAutoFill;
|
|
||||||
|
|
||||||
|
|
||||||
boolean mReportNextDraw;
|
boolean mReportNextDraw;
|
||||||
@@ -883,7 +882,6 @@ public final class ViewRootImpl implements ViewParent,
|
|||||||
mPreviousTransparentRegion = new Region();
|
mPreviousTransparentRegion = new Region();
|
||||||
mFirst = true; // true for the first time the view is added
|
mFirst = true; // true for the first time the view is added
|
||||||
mPerformContentCapture = true; // also 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;
|
mAdded = false;
|
||||||
mAttachInfo = new View.AttachInfo(mWindowSession, mWindow, display, this, mHandler, this,
|
mAttachInfo = new View.AttachInfo(mWindowSession, mWindow, display, this, mHandler, this,
|
||||||
context);
|
context);
|
||||||
@@ -4310,18 +4308,6 @@ public final class ViewRootImpl implements ViewParent,
|
|||||||
if (mPerformContentCapture) {
|
if (mPerformContentCapture) {
|
||||||
performContentCaptureInitialReport();
|
performContentCaptureInitialReport();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mPerformAutoFill) {
|
|
||||||
notifyEnterForAutoFillIfNeeded();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void notifyEnterForAutoFillIfNeeded() {
|
|
||||||
mPerformAutoFill = false;
|
|
||||||
final AutofillManager afm = getAutofillManager();
|
|
||||||
if (afm != null) {
|
|
||||||
afm.notifyViewEnteredForActivityStarted(mView);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -102,6 +102,7 @@ import java.util.Collections;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
import sun.misc.Cleaner;
|
import sun.misc.Cleaner;
|
||||||
|
|
||||||
@@ -644,16 +645,6 @@ public final class AutofillManager {
|
|||||||
@GuardedBy("mLock")
|
@GuardedBy("mLock")
|
||||||
private boolean mEnabledForAugmentedAutofillOnly;
|
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
|
* Indicates whether there is already a field to do a fill request after
|
||||||
* the activity started.
|
* the activity started.
|
||||||
@@ -663,7 +654,7 @@ public final class AutofillManager {
|
|||||||
* triggered autofill, it is unnecessary to trigger again through
|
* triggered autofill, it is unnecessary to trigger again through
|
||||||
* AutofillManager#notifyViewEnteredForActivityStarted.
|
* AutofillManager#notifyViewEnteredForActivityStarted.
|
||||||
*/
|
*/
|
||||||
private boolean mIsFillRequested;
|
private AtomicBoolean mIsFillRequested;
|
||||||
|
|
||||||
@Nullable private List<AutofillId> mFillDialogTriggerIds;
|
@Nullable private List<AutofillId> mFillDialogTriggerIds;
|
||||||
|
|
||||||
@@ -811,8 +802,7 @@ public final class AutofillManager {
|
|||||||
mContext = Objects.requireNonNull(context, "context cannot be null");
|
mContext = Objects.requireNonNull(context, "context cannot be null");
|
||||||
mService = service;
|
mService = service;
|
||||||
mOptions = context.getAutofillOptions();
|
mOptions = context.getAutofillOptions();
|
||||||
mIsFillRequested = false;
|
mIsFillRequested = new AtomicBoolean(false);
|
||||||
mRequireAutofill = false;
|
|
||||||
|
|
||||||
mIsFillDialogEnabled = DeviceConfig.getBoolean(
|
mIsFillDialogEnabled = DeviceConfig.getBoolean(
|
||||||
DeviceConfig.NAMESPACE_AUTOFILL,
|
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 {@link #DEVICE_CONFIG_AUTOFILL_DIALOG_ENABLED} is {@code true} or the view have
|
||||||
* the field does not trigger a fill request.
|
* the allowed autofill hints, performs a fill request to know there is any field supported
|
||||||
|
* fill dialog.
|
||||||
*
|
*
|
||||||
* @hide
|
* @hide
|
||||||
*/
|
*/
|
||||||
public void enableFillRequestActivityStarted(View v) {
|
public void notifyViewEnteredForFillDialog(View v) {
|
||||||
if (mRequireAutofill) {
|
// Skip if the fill request has been performed for a view.
|
||||||
|
if (mIsFillRequested.get()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mIsFillDialogEnabled
|
if (mIsFillDialogEnabled
|
||||||
|| ArrayUtils.containsAny(v.getAutofillHints(), mFillDialogEnabledHints)) {
|
|| ArrayUtils.containsAny(v.getAutofillHints(), mFillDialogEnabledHints)) {
|
||||||
if (sDebug) {
|
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);
|
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) {
|
private int getImeStateFlag(View v) {
|
||||||
final WindowInsets rootWindowInsets = v.getRootWindowInsets();
|
final WindowInsets rootWindowInsets = v.getRootWindowInsets();
|
||||||
if (rootWindowInsets != null && rootWindowInsets.isVisible(WindowInsets.Type.ime())) {
|
if (rootWindowInsets != null && rootWindowInsets.isVisible(WindowInsets.Type.ime())) {
|
||||||
@@ -1203,7 +1183,7 @@ public final class AutofillManager {
|
|||||||
}
|
}
|
||||||
AutofillCallback callback;
|
AutofillCallback callback;
|
||||||
synchronized (mLock) {
|
synchronized (mLock) {
|
||||||
mIsFillRequested = true;
|
mIsFillRequested.set(true);
|
||||||
callback = notifyViewEnteredLocked(view, flags);
|
callback = notifyViewEnteredLocked(view, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2119,8 +2099,7 @@ public final class AutofillManager {
|
|||||||
mFillableIds = null;
|
mFillableIds = null;
|
||||||
mSaveTriggerId = null;
|
mSaveTriggerId = null;
|
||||||
mIdShownFillUi = null;
|
mIdShownFillUi = null;
|
||||||
mIsFillRequested = false;
|
mIsFillRequested.set(false);
|
||||||
mRequireAutofill = false;
|
|
||||||
mShowAutofillDialogCalled = false;
|
mShowAutofillDialogCalled = false;
|
||||||
mFillDialogTriggerIds = null;
|
mFillDialogTriggerIds = null;
|
||||||
if (resetEnteredIds) {
|
if (resetEnteredIds) {
|
||||||
|
|||||||
Reference in New Issue
Block a user