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

Commit 7f357072 authored by Ahaan Ugale's avatar Ahaan Ugale Committed by Android (Google) Code Review
Browse files

Merge "AF Inline: Notify the registered AutofillCallback, also fix filtering." into rvc-dev

parents 9dace765 974c3114
Loading
Loading
Loading
Loading
+43 −10
Original line number Diff line number Diff line
@@ -2590,8 +2590,26 @@ public final class AutofillManager {

    private void notifyNoFillUi(int sessionId, AutofillId id, int sessionFinishedState) {
        if (sVerbose) {
            Log.v(TAG, "notifyNoFillUi(): sessionId=" + sessionId + ", autofillId=" + id
                    + ", sessionFinishedState=" + sessionFinishedState);
            Log.v(TAG, "notifyNoFillUi(): sessionFinishedState=" + sessionFinishedState);
        }
        final View anchor = findView(id);
        if (anchor == null) {
            return;
        }

        notifyCallback(sessionId, id, AutofillCallback.EVENT_INPUT_UNAVAILABLE);

        if (sessionFinishedState != STATE_UNKNOWN) {
            // Callback call was "hijacked" to also update the session state.
            setSessionFinished(sessionFinishedState, /* autofillableIds= */ null);
        }
    }

    private void notifyCallback(
            int sessionId, AutofillId id, @AutofillCallback.AutofillEventType int event) {
        if (sVerbose) {
            Log.v(TAG, "notifyCallback(): sessionId=" + sessionId + ", autofillId=" + id
                    + ", event=" + event);
        }
        final View anchor = findView(id);
        if (anchor == null) {
@@ -2607,17 +2625,12 @@ public final class AutofillManager {

        if (callback != null) {
            if (id.isVirtualInt()) {
                callback.onAutofillEvent(anchor, id.getVirtualChildIntId(),
                        AutofillCallback.EVENT_INPUT_UNAVAILABLE);
                callback.onAutofillEvent(
                        anchor, id.getVirtualChildIntId(), event);
            } else {
                callback.onAutofillEvent(anchor, AutofillCallback.EVENT_INPUT_UNAVAILABLE);
                callback.onAutofillEvent(anchor, event);
            }
        }

        if (sessionFinishedState != STATE_UNKNOWN) {
            // Callback call was "hijacked" to also update the session state.
            setSessionFinished(sessionFinishedState, /* autofillableIds= */ null);
        }
    }

    /**
@@ -3367,6 +3380,26 @@ public final class AutofillManager {
            }
        }

        @Override
        public void notifyFillUiShown(int sessionId, AutofillId id) {
            final AutofillManager afm = mAfm.get();
            if (afm != null) {
                afm.post(
                        () -> afm.notifyCallback(
                                sessionId, id, AutofillCallback.EVENT_INPUT_SHOWN));
            }
        }

        @Override
        public void notifyFillUiHidden(int sessionId, AutofillId id) {
            final AutofillManager afm = mAfm.get();
            if (afm != null) {
                afm.post(
                        () -> afm.notifyCallback(
                                sessionId, id, AutofillCallback.EVENT_INPUT_HIDDEN));
            }
        }

        @Override
        public void notifyDisableAutofill(long disableDuration, ComponentName componentName)
                throws RemoteException {
+12 −0
Original line number Diff line number Diff line
@@ -78,6 +78,18 @@ oneway interface IAutoFillManagerClient {
     */
    void notifyNoFillUi(int sessionId, in AutofillId id, int sessionFinishedState);

    /**
     * Notifies that the fill UI was shown by the system (e.g. as inline chips in the keyboard).
     */
    void notifyFillUiShown(int sessionId, in AutofillId id);

    /**
     * Notifies that the fill UI previously shown by the system has been hidden by the system.
     *
     * @see #notifyFillUiShown
     */
    void notifyFillUiHidden(int sessionId, in AutofillId id);

    /**
     * Dispatches unhandled keyevent from autofill ui. Autofill ui handles DPAD and ENTER events,
     * other unhandled keyevents are dispatched to app's window to filter autofill result.
+6 −5
Original line number Diff line number Diff line
@@ -117,13 +117,14 @@ final class AutofillInlineSessionController {
    }

    /**
     * Permanently delete the current inline fill UI. Notify the IME to hide the suggestions as
     * well.
     * Disables prefix/regex based filtering. Other filtering rules (see {@link
     * android.service.autofill.Dataset}) still apply.
     */
    @GuardedBy("mLock")
    boolean deleteInlineFillUiLocked(@NonNull AutofillId autofillId) {
        mInlineFillUi = null;
        return hideInlineSuggestionsUiLocked(autofillId);
    void disableFilterMatching(@NonNull AutofillId autofillId) {
        if (mInlineFillUi != null && mInlineFillUi.getAutofillId().equals(autofillId)) {
            mInlineFillUi.disableFilterMatching();
        }
    }

    /**
+27 −7
Original line number Diff line number Diff line
@@ -2698,6 +2698,11 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
                // TODO(b/156099633): remove this once framework gets out of business of resending
                // inline suggestions when IME visibility changes.
                mInlineSessionController.hideInlineSuggestionsUiLocked(viewState.id);
                try {
                    mClient.notifyFillUiHidden(this.id, viewState.id);
                } catch (RemoteException e) {
                    Slog.e(TAG, "Error requesting to hide fill UI", e);
                }
                viewState.resetState(ViewState.STATE_CHANGED);
                return;
            } else if ((viewState.id.equals(this.mCurrentViewId))
@@ -2713,20 +2718,20 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
        } else if (viewState.id.equals(this.mCurrentViewId)
                && (viewState.getState() & ViewState.STATE_INLINE_SHOWN) != 0) {
            if ((viewState.getState() & ViewState.STATE_INLINE_DISABLED) != 0) {
                final FillResponse response = viewState.getResponse();
                if (response != null) {
                    response.getDatasets().clear();
                mInlineSessionController.disableFilterMatching(viewState.id);
            }
                mInlineSessionController.deleteInlineFillUiLocked(viewState.id);
            } else {
            mInlineSessionController.filterInlineFillUiLocked(mCurrentViewId, filterText);
            }
        } else if (viewState.id.equals(this.mCurrentViewId)
                && (viewState.getState() & ViewState.STATE_TRIGGERED_AUGMENTED_AUTOFILL) != 0) {
            if (!TextUtils.isEmpty(filterText)) {
                // TODO: we should be able to replace this with controller#filterInlineFillUiLocked
                // to accomplish filtering for augmented autofill.
                mInlineSessionController.hideInlineSuggestionsUiLocked(mCurrentViewId);
                try {
                    mClient.notifyFillUiHidden(this.id, mCurrentViewId);
                } catch (RemoteException e) {
                    Slog.e(TAG, "Error sending fill UI hidden notification", e);
                }
            }
        }

@@ -2812,6 +2817,11 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
                if (requestShowInlineSuggestionsLocked(response, filterText)) {
                    final ViewState currentView = mViewStates.get(mCurrentViewId);
                    currentView.setState(ViewState.STATE_INLINE_SHOWN);
                    try {
                        mClient.notifyFillUiShown(this.id, mCurrentViewId);
                    } catch (RemoteException e) {
                        Slog.e(TAG, "Error sending fill UI shown notification", e);
                    }
                    //TODO(b/137800469): Fix it to log showed only when IME asks for inflation,
                    // rather than here where framework sends back the response.
                    mService.logDatasetShown(id, mClientState);
@@ -2882,6 +2892,11 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
                    synchronized (mLock) {
                        mInlineSessionController.hideInlineSuggestionsUiLocked(
                                focusedId);
                        try {
                            mClient.notifyFillUiHidden(this.id, focusedId);
                        } catch (RemoteException e) {
                            Slog.e(TAG, "Error sending fill UI hidden notification", e);
                        }
                    }
                }, remoteRenderService);
        return mInlineSessionController.setInlineFillUiLocked(inlineFillUi);
@@ -3393,6 +3408,11 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
                }
                if (mCurrentViewId != null) {
                    mInlineSessionController.hideInlineSuggestionsUiLocked(mCurrentViewId);
                    try {
                        mClient.notifyFillUiHidden(this.id, mCurrentViewId);
                    } catch (RemoteException e) {
                        Slog.e(TAG, "Error sending fill UI hidden notification", e);
                    }
                }
                autoFillApp(dataset);
                return;
+24 −6
Original line number Diff line number Diff line
@@ -83,6 +83,11 @@ public final class InlineFillUi {
    @Nullable
    private String mFilterText;

    /**
     * Whether prefix/regex based filtering is disabled.
     */
    private boolean mFilterMatchingDisabled;

    /**
     * Returns an empty inline autofill UI.
     */
@@ -199,7 +204,7 @@ public final class InlineFillUi {
                continue;
            }
            if (!inlinePresentation.isPinned()  // don't filter pinned suggestions
                    && !includeDataset(dataset, fieldIndex, mFilterText)) {
                    && !includeDataset(dataset, fieldIndex)) {
                continue;
            }
            inlineSuggestions.add(copy(i, mInlineSuggestions.get(i)));
@@ -235,14 +240,13 @@ public final class InlineFillUi {
    }

    // TODO: Extract the shared filtering logic here and in FillUi to a common method.
    private static boolean includeDataset(Dataset dataset, int fieldIndex,
            @Nullable String filterText) {
    private boolean includeDataset(Dataset dataset, int fieldIndex) {
        // Show everything when the user input is empty.
        if (TextUtils.isEmpty(filterText)) {
        if (TextUtils.isEmpty(mFilterText)) {
            return true;
        }

        final String constraintLowerCase = filterText.toString().toLowerCase();
        final String constraintLowerCase = mFilterText.toString().toLowerCase();

        // Use the filter provided by the service, if available.
        final Dataset.DatasetFieldFilter filter = dataset.getFilter(fieldIndex);
@@ -252,7 +256,10 @@ public final class InlineFillUi {
                if (sVerbose) {
                    Slog.v(TAG, "Explicitly disabling filter for dataset id" + dataset.getId());
                }
                return true;
                return false;
            }
            if (mFilterMatchingDisabled) {
                return false;
            }
            return filterPattern.matcher(constraintLowerCase).matches();
        }
@@ -261,10 +268,21 @@ public final class InlineFillUi {
        if (value == null || !value.isText()) {
            return dataset.getAuthentication() == null;
        }
        if (mFilterMatchingDisabled) {
            return false;
        }
        final String valueText = value.getTextValue().toString().toLowerCase();
        return valueText.toLowerCase().startsWith(constraintLowerCase);
    }

    /**
     * Disables prefix/regex based filtering. Other filtering rules (see {@link
     * android.service.autofill.Dataset}) still apply.
     */
    public void disableFilterMatching() {
        mFilterMatchingDisabled = true;
    }

    /**
     * Callback from the inline suggestion Ui.
     */