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

Commit 475bef64 authored by Alex Salo's avatar Alex Salo
Browse files

Add PENDING_AUTH state to AutofillManager

This state allows to keep track from when the user selected the inline suggestion to when we completed the authentication (e.g. biometric prompt or bad password check).

While in this state, we should ignore the changes in view visibility (and potentially other changes related to re-layout) because the user already selected to apply the inline suggestion for that view state.

Specifically this helps with cases when 3P apps do custom visibility change logic when activity goes onPause(). For example, apps can hide EditText for better UX, but it's not a real onPause(), so we should not treat it like one.

Another scenario is a manual password selection via PasswordManager - it takes user to another activity to choose the right password, than provides it to the app - but app has hidden the fields. This fix resolves such case as well.

Verified this change is correctly guarded by the trunk flags by running:
$ adb shell device_config put autofill android.service.autofill.relayout true

Change-Id: Icb0eeecdd037946b1f471e198674fb3be32a7ae7
Fixes: 294330426
Fixes: 295262306
Bug: 238252288
parent d3aecab2
Loading
Loading
Loading
Loading
+34 −2
Original line number Diff line number Diff line
@@ -67,6 +67,7 @@ import android.os.SystemClock;
import android.service.autofill.AutofillService;
import android.service.autofill.FillCallback;
import android.service.autofill.FillEventHistory;
import android.service.autofill.Flags;
import android.service.autofill.IFillCallback;
import android.service.autofill.UserData;
import android.text.TextUtils;
@@ -427,6 +428,14 @@ public final class AutofillManager {
     */
    public static final int STATE_UNKNOWN_FAILED = 6;

    /**
     * Same as {@link #STATE_ACTIVE}, but when pending authentication after
     * {@link AutofillManagerClient#authenticate(int, int, IntentSender, Intent, boolean)}
     *
     * @hide
     */
    public static final int STATE_PENDING_AUTHENTICATION = 7;

    /**
     * Timeout in ms for calls to the field classification service.
     * @hide
@@ -731,6 +740,10 @@ public final class AutofillManager {
    // Indicate whether WebView should always be included in the assist structure
    private boolean mShouldAlwaysIncludeWebviewInAssistStructure;

    // Controls logic around apps changing some properties of their views when activity loses
    // focus due to autofill showing biometric activity, password manager, or password breach check.
    private boolean mRelayoutFix;

    // Indicates whether called the showAutofillDialog() method.
    private boolean mShowAutofillDialogCalled = false;

@@ -952,6 +965,8 @@ public final class AutofillManager {

        mShouldAlwaysIncludeWebviewInAssistStructure =
                AutofillFeatureFlags.shouldAlwaysIncludeWebviewInAssistStructure();

        mRelayoutFix = Flags.relayout();
    }

    /**
@@ -1719,6 +1734,12 @@ public final class AutofillManager {
                }
                return;
            }
            if (mRelayoutFix && mState == STATE_PENDING_AUTHENTICATION) {
                if (sVerbose) {
                    Log.v(TAG, "notifyViewVisibilityChanged(): ignoring in auth pending mode");
                }
                return;
            }
            if (mEnabled && isActiveLocked()) {
                final AutofillId id = virtual ? getAutofillId(view, virtualId)
                        : view.getAutofillId();
@@ -2342,6 +2363,7 @@ public final class AutofillManager {
            if (!isActiveLocked()) {
                return;
            }
            mState = STATE_ACTIVE;
            // If authenticate activity closes itself during onCreate(), there is no onStop/onStart
            // of app activity.  We enforce enter event to re-show fill ui in such case.
            // CTS example:
@@ -2830,6 +2852,9 @@ public final class AutofillManager {
            Intent fillInIntent, boolean authenticateInline) {
        synchronized (mLock) {
            if (sessionId == mSessionId) {
                if (mRelayoutFix) {
                    mState = STATE_PENDING_AUTHENTICATION;
                }
                final AutofillClient client = getClient();
                if (client != null) {
                    // clear mOnInvisibleCalled and we will see if receive onInvisibleForAutofill()
@@ -3563,6 +3588,8 @@ public final class AutofillManager {
                return "UNKNOWN";
            case STATE_ACTIVE:
                return "ACTIVE";
            case STATE_PENDING_AUTHENTICATION:
                return "PENDING_AUTHENTICATION";
            case STATE_FINISHED:
                return "FINISHED";
            case STATE_SHOWING_SAVE_UI:
@@ -3592,7 +3619,12 @@ public final class AutofillManager {

    @GuardedBy("mLock")
    private boolean isActiveLocked() {
        return mState == STATE_ACTIVE;
        return mState == STATE_ACTIVE || isPendingAuthenticationLocked();
    }

    @GuardedBy("mLock")
    private boolean isPendingAuthenticationLocked() {
        return mRelayoutFix && mState == STATE_PENDING_AUTHENTICATION;
    }

    @GuardedBy("mLock")