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

Commit 992d0785 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

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

parents bf47ae31 0c8ce322
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;