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

Commit 85584bcb authored by Felipe Leme's avatar Felipe Leme Committed by android-build-merger
Browse files

Merge "Integrate autofill session lifecycle with URL bar changes when on compat mode." into pi-dev

am: 992d0785

Change-Id: I5720f372fa5638bbe2dca67a42962765f1a40bd1
parents a2f46f1e 992d0785
Loading
Loading
Loading
Loading
+39 −13
Original line number Diff line number Diff line
@@ -273,6 +273,16 @@ public final class AutofillManager {
     */
    public static final int STATE_DISABLED_BY_SERVICE = 4;

    /**
     * Same as {@link #STATE_UNKNOWN}, but used on
     * {@link AutofillManagerClient#setSessionFinished(int)} when the session was finished because
     * the URL bar changed on client mode
     *
     * @hide
     */
    public static final int STATE_UNKNOWN_COMPAT_MODE = 5;


    /**
     * Timeout in ms for calls to the field classification service.
     * @hide
@@ -1947,17 +1957,26 @@ public final class AutofillManager {
     * Marks the state of the session as finished.
     *
     * @param newState {@link #STATE_FINISHED} (because the autofill service returned a {@code null}
     *  FillResponse), {@link #STATE_UNKNOWN} (because the session was removed), or
     *  {@link #STATE_DISABLED_BY_SERVICE} (because the autofill service disabled further autofill
     *  requests for the activity).
     *  FillResponse), {@link #STATE_UNKNOWN} (because the session was removed),
     *  {@link #STATE_UNKNOWN_COMPAT_MODE} (beucase the session was finished when the URL bar
     *  changed on compat mode), or {@link #STATE_DISABLED_BY_SERVICE} (because the autofill service
     *  disabled further autofill requests for the activity).
     */
    private void setSessionFinished(int newState) {
        synchronized (mLock) {
            if (sVerbose) Log.v(TAG, "setSessionFinished(): from " + mState + " to " + newState);
            if (sVerbose) {
                Log.v(TAG, "setSessionFinished(): from " + getStateAsStringLocked() + " to "
                        + getStateAsString(newState));
            }
            if (newState == STATE_UNKNOWN_COMPAT_MODE) {
                resetSessionLocked(/* resetEnteredIds= */ true);
                mState = STATE_UNKNOWN;
            } else {
                resetSessionLocked(/* resetEnteredIds= */ false);
                mState = newState;
            }
        }
    }

    /** @hide */
    public void requestHideFillUi() {
@@ -2107,19 +2126,26 @@ public final class AutofillManager {

    @GuardedBy("mLock")
    private String getStateAsStringLocked() {
        switch (mState) {
        return getStateAsString(mState);
    }

    @NonNull
    private static String getStateAsString(int state) {
        switch (state) {
            case STATE_UNKNOWN:
                return "STATE_UNKNOWN";
                return "UNKNOWN";
            case STATE_ACTIVE:
                return "STATE_ACTIVE";
                return "ACTIVE";
            case STATE_FINISHED:
                return "STATE_FINISHED";
                return "FINISHED";
            case STATE_SHOWING_SAVE_UI:
                return "STATE_SHOWING_SAVE_UI";
                return "SHOWING_SAVE_UI";
            case STATE_DISABLED_BY_SERVICE:
                return "STATE_DISABLED_BY_SERVICE";
                return "DISABLED_BY_SERVICE";
            case STATE_UNKNOWN_COMPAT_MODE:
                return "UNKNOWN_COMPAT_MODE";
            default:
                return "INVALID:" + mState;
                return "INVALID:" + state;
        }
    }

+5 −2
Original line number Diff line number Diff line
@@ -180,9 +180,11 @@ public final class Helper {
     *
     * @param structure Assist structure
     * @param urlBarIds list of ids; only the first id found will be sanitized.
     *
     * @return the node containing the URL bar
     */
    @Nullable
    public static void sanitizeUrlBar(@NonNull AssistStructure structure,
    public static ViewNode sanitizeUrlBar(@NonNull AssistStructure structure,
            @NonNull String[] urlBarIds) {
        final ViewNode urlBarNode = findViewNode(structure, (node) -> {
            return ArrayUtils.contains(urlBarIds, node.getIdEntry());
@@ -191,7 +193,7 @@ public final class Helper {
            final String domain = urlBarNode.getText().toString();
            if (domain.isEmpty()) {
                if (sDebug) Slog.d(TAG, "sanitizeUrlBar(): empty on " + urlBarNode.getIdEntry());
                return;
                return null;
            }
            urlBarNode.setWebDomain(domain);
            if (sDebug) {
@@ -199,6 +201,7 @@ public final class Helper {
                        + urlBarNode.getWebDomain());
            }
        }
        return urlBarNode;
    }

    private interface ViewNodeFilter {
+98 −10
Original line number Diff line number Diff line
@@ -146,6 +146,13 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
    /** Whether the app being autofilled is running in compat mode. */
    private final boolean mCompatMode;

    /** Node representing the URL bar on compat mode. */
    @GuardedBy("mLock")
    private ViewNode mUrlBar;

    @GuardedBy("mLock")
    private boolean mSaveOnAllViewsInvisible;

    @GuardedBy("mLock")
    private final ArrayMap<AutofillId, ViewState> mViewStates = new ArrayMap<>();

@@ -280,7 +287,17 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
                        Slog.d(TAG, "url_bars in compat mode: " + Arrays.toString(urlBarIds));
                    }
                    if (urlBarIds != null) {
                        Helper.sanitizeUrlBar(structure, urlBarIds);
                        mUrlBar = Helper.sanitizeUrlBar(structure, urlBarIds);
                        if (mUrlBar != null) {
                            final AutofillId urlBarId = mUrlBar.getAutofillId();
                            if (sDebug) {
                                Slog.d(TAG, "Setting urlBar as id=" + urlBarId + " and domain "
                                        + mUrlBar.getWebDomain());
                            }
                            final ViewState viewState = new ViewState(Session.this, urlBarId,
                                    Session.this, ViewState.STATE_URL_BAR);
                            mViewStates.put(urlBarId, viewState);
                        }
                    }
                }
                structure.sanitizeForParceling(true);
@@ -1878,14 +1895,15 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
            return;
        }
        if (sVerbose) {
            Slog.v(TAG, "updateLocked(): id=" + id + ", action=" + action + ", flags=" + flags);
            Slog.v(TAG, "updateLocked(): id=" + id + ", action=" + actionAsString(action)
                    + ", flags=" + flags);
        }
        ViewState viewState = mViewStates.get(id);

        if (viewState == null) {
            if (action == ACTION_START_SESSION || action == ACTION_VALUE_CHANGED
                    || action == ACTION_VIEW_ENTERED) {
                if (sVerbose) Slog.v(TAG, "Creating viewState for " + id + " on " + action);
                if (sVerbose) Slog.v(TAG, "Creating viewState for " + id);
                boolean isIgnored = isIgnoredLocked(id);
                viewState = new ViewState(this, id, this,
                        isIgnored ? ViewState.STATE_IGNORED : ViewState.STATE_INITIAL);
@@ -1895,11 +1913,11 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
                // detectable, and batch-send them when the session is finished (but that will
                // require tracking detectable fields on AutofillManager)
                if (isIgnored) {
                    if (sDebug) Slog.d(TAG, "updateLocked(): ignoring view " + id);
                    if (sDebug) Slog.d(TAG, "updateLocked(): ignoring view " + viewState);
                    return;
                }
            } else {
                if (sVerbose) Slog.v(TAG, "Ignored action " + action + " for " + id);
                if (sVerbose) Slog.v(TAG, "Ignoring specific action when viewState=null");
                return;
            }
        }
@@ -1913,6 +1931,40 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
                requestNewFillResponseLocked(flags);
                break;
            case ACTION_VALUE_CHANGED:
                if (mCompatMode && (viewState.getState() & ViewState.STATE_URL_BAR) != 0) {
                    // Must cancel the session if the value of the URL bar changed
                    final String currentUrl = mUrlBar == null ? null
                            : mUrlBar.getText().toString().trim();
                    if (currentUrl == null) {
                        // Sanity check - shouldn't happen.
                        wtf(null, "URL bar value changed, but current value is null");
                        return;
                    }
                    if (value == null || ! value.isText()) {
                        // Sanity check - shouldn't happen.
                        wtf(null, "URL bar value changed to null or non-text: %s", value);
                        return;
                    }
                    final String newUrl = value.getTextValue().toString();
                    if (newUrl.equals(currentUrl)) {
                        if (sDebug) Slog.d(TAG, "Ignoring change on URL bar as it's the same");
                        return;
                    }
                    if (mSaveOnAllViewsInvisible) {
                        // We cannot cancel the session because it could hinder Save when all views
                        // are finished, as the URL bar changed callback is usually called before
                        // the virtual views become invisible.
                        if (sDebug) {
                            Slog.d(TAG, "Ignoring change on URL because session will finish when "
                                    + "views are gone");
                        }
                        return;
                    }
                    if (sDebug) Slog.d(TAG, "Finishing session because URL bar changed");
                    forceRemoveSelfLocked(AutofillManager.STATE_UNKNOWN_COMPAT_MODE);
                    return;
                }

                if (value != null && !value.equals(viewState.getCurrentValue())) {
                    if (value.isEmpty()
                            && viewState.getCurrentValue() != null
@@ -1953,6 +2005,12 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
                if (sVerbose && virtualBounds != null) {
                    Slog.v(TAG, "entered on virtual child " + id + ": " + virtualBounds);
                }

                if (mCompatMode && (viewState.getState() & ViewState.STATE_URL_BAR) != 0) {
                    if (sDebug) Slog.d(TAG, "Ignoring VIEW_ENTERED on URL BAR (id=" + id + ")");
                    return;
                }

                requestNewFillResponseOnViewEnteredIfNecessaryLocked(id, viewState, flags);

                // Remove the UI if the ViewState has changed.
@@ -2068,7 +2126,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
        if (response == null) return;

        ArraySet<AutofillId> trackedViews = null;
        boolean saveOnAllViewsInvisible = false;
        mSaveOnAllViewsInvisible = false;
        boolean saveOnFinish = true;
        final SaveInfo saveInfo = response.getSaveInfo();
        final AutofillId saveTriggerId;
@@ -2081,10 +2139,10 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
            if (mCompatMode) {
                flags |= SaveInfo.FLAG_SAVE_ON_ALL_VIEWS_INVISIBLE;
            }
            saveOnAllViewsInvisible = (flags & SaveInfo.FLAG_SAVE_ON_ALL_VIEWS_INVISIBLE) != 0;
            mSaveOnAllViewsInvisible = (flags & SaveInfo.FLAG_SAVE_ON_ALL_VIEWS_INVISIBLE) != 0;

            // We only need to track views if we want to save once they become invisible.
            if (saveOnAllViewsInvisible) {
            if (mSaveOnAllViewsInvisible) {
                if (trackedViews == null) {
                    trackedViews = new ArraySet<>();
                }
@@ -2129,7 +2187,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
                Slog.v(TAG, "updateTrackedIdsLocked(): " + trackedViews + " => " + fillableIds
                        + " triggerId: " + saveTriggerId + " saveOnFinish:" + saveOnFinish);
            }
            mClient.setTrackedViews(id, toArray(trackedViews), saveOnAllViewsInvisible,
            mClient.setTrackedViews(id, toArray(trackedViews), mSaveOnAllViewsInvisible,
                    saveOnFinish, toArray(fillableIds), saveTriggerId);
        } catch (RemoteException e) {
            Slog.w(TAG, "Cannot set tracked ids", e);
@@ -2421,6 +2479,16 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
        pw.print(prefix); pw.print("mClientState: "); pw.println(
                Helper.bundleToString(mClientState));
        pw.print(prefix); pw.print("mCompatMode: "); pw.println(mCompatMode);
        pw.print(prefix); pw.print("mUrlBar: ");
        if (mUrlBar == null) {
            pw.println("N/A");
        } else {
            pw.print("id="); pw.print(mUrlBar.getAutofillId());
            pw.print(" domain="); pw.print(mUrlBar.getWebDomain());
            pw.print(" text="); Helper.printlnRedactedText(pw, mUrlBar.getText());
        }
        pw.print(prefix); pw.print("mSaveOnAllViewsInvisible: "); pw.println(
                mSaveOnAllViewsInvisible);
        pw.print(prefix); pw.print("mSelectedDatasetIds: "); pw.println(mSelectedDatasetIds);
        mRemoteFillService.dump(prefix, pw);
    }
@@ -2513,6 +2581,11 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
     */
    @GuardedBy("mLock")
    void forceRemoveSelfLocked() {
        forceRemoveSelfLocked(AutofillManager.STATE_UNKNOWN);
    }

    @GuardedBy("mLock")
    void forceRemoveSelfLocked(int clientState) {
        if (sVerbose) Slog.v(TAG, "forceRemoveSelfLocked(): " + mPendingSaveUi);

        final boolean isPendingSaveUi = isSaveUiPendingLocked();
@@ -2521,7 +2594,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
        mUi.destroyAll(mPendingSaveUi, this, false);
        if (!isPendingSaveUi) {
            try {
                mClient.setSessionFinished(AutofillManager.STATE_UNKNOWN);
                mClient.setSessionFinished(clientState);
            } catch (RemoteException e) {
                Slog.e(TAG, "Error notifying client to finish session", e);
            }
@@ -2624,4 +2697,19 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
            Slog.wtf(TAG, message);
        }
    }

    private static String actionAsString(int action) {
        switch (action) {
            case ACTION_START_SESSION:
                return "START_SESSION";
            case ACTION_VIEW_ENTERED:
                return "VIEW_ENTERED";
            case ACTION_VIEW_EXITED:
                return "VIEW_EXITED";
            case ACTION_VALUE_CHANGED:
                return "VALUE_CHANGED";
            default:
                return "UNKNOWN_" + action;
        }
    }
}
+2 −0
Original line number Diff line number Diff line
@@ -67,6 +67,8 @@ final class ViewState {
    public static final int STATE_IGNORED = 0x080;
    /** User manually request autofill in this view, after it was already autofilled. */
    public static final int STATE_RESTARTED_SESSION = 0x100;
    /** View is the URL bar of a package on compat mode. */
    public  static final int STATE_URL_BAR = 0x200;

    public final AutofillId id;