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

Commit d0433c71 authored by Nikita Dubrovsky's avatar Nikita Dubrovsky
Browse files

Dataset authentication for Augmented Autofill

Setting an authentication IntentSender on an Augmented Autofill
suggestion was being ignored. With this change, it will trigger
the auth flow as documented.

Fix: 157863999
Test: Manual
Test: atest android.autofillservice.cts.inline
Change-Id: Id21c8f074bd0f49992e01445d50b1503af4720b6
parent e710511e
Loading
Loading
Loading
Loading
+21 −0
Original line number Diff line number Diff line
@@ -815,6 +815,19 @@ final class AutofillManagerServiceImpl
        }
    }

    void logAugmentedAutofillAuthenticationSelected(int sessionId, @Nullable String selectedDataset,
            @Nullable Bundle clientState) {
        synchronized (mLock) {
            if (mAugmentedAutofillEventHistory == null
                    || mAugmentedAutofillEventHistory.getSessionId() != sessionId) {
                return;
            }
            mAugmentedAutofillEventHistory.addEvent(
                    new Event(Event.TYPE_DATASET_AUTHENTICATION_SELECTED, selectedDataset,
                            clientState, null, null, null, null, null, null, null, null));
        }
    }

    void logAugmentedAutofillSelected(int sessionId, @Nullable String suggestionId,
            @Nullable Bundle clientState) {
        synchronized (mLock) {
@@ -1198,6 +1211,14 @@ final class AutofillManagerServiceImpl
                                    suggestionId, clientState);
                        }

                        @Override
                        public void logAugmentedAutofillAuthenticationSelected(int sessionId,
                                String suggestionId, Bundle clientState) {
                            AutofillManagerServiceImpl.this
                                    .logAugmentedAutofillAuthenticationSelected(
                                            sessionId, suggestionId, clientState);
                        }

                        @Override
                        public void onServiceDied(@NonNull RemoteAugmentedAutofillService service) {
                            Slog.w(TAG, "remote augmented autofill service died");
+25 −1
Original line number Diff line number Diff line
@@ -263,7 +263,28 @@ final class RemoteAugmentedAutofillService
                        request, inlineSuggestionsData, focusedId, filterText,
                        new InlineFillUi.InlineSuggestionUiCallback() {
                            @Override
                            public void autofill(Dataset dataset) {
                            public void autofill(Dataset dataset, int datasetIndex) {
                                if (dataset.getAuthentication() != null) {
                                    mCallbacks.logAugmentedAutofillAuthenticationSelected(sessionId,
                                            dataset.getId(), clientState);
                                    final IntentSender action = dataset.getAuthentication();
                                    final int authenticationId =
                                            AutofillManager.makeAuthenticationId(
                                                    Session.AUGMENTED_AUTOFILL_REQUEST_ID,
                                                    datasetIndex);
                                    final Intent fillInIntent = new Intent();
                                    fillInIntent.putExtra(AutofillManager.EXTRA_CLIENT_STATE,
                                            clientState);
                                    try {
                                        client.authenticate(sessionId, authenticationId, action,
                                                fillInIntent, false);
                                    } catch (RemoteException e) {
                                        Slog.w(TAG, "Error starting auth flow");
                                        inlineSuggestionsCallback.apply(
                                                InlineFillUi.emptyUi(focusedId));
                                    }
                                    return;
                                }
                                mCallbacks.logAugmentedAutofillSelected(sessionId,
                                        dataset.getId(), clientState);
                                try {
@@ -319,5 +340,8 @@ final class RemoteAugmentedAutofillService

        void logAugmentedAutofillSelected(int sessionId, @Nullable String suggestionId,
                @Nullable Bundle clientState);

        void logAugmentedAutofillAuthenticationSelected(int sessionId,
                @Nullable String suggestionId, @Nullable Bundle clientState);
    }
}
+65 −3
Original line number Diff line number Diff line
@@ -144,7 +144,9 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState

    private final MetricsLogger mMetricsLogger = new MetricsLogger();

    private static AtomicInteger sIdCounter = new AtomicInteger();
    static final int AUGMENTED_AUTOFILL_REQUEST_ID = 1;

    private static AtomicInteger sIdCounter = new AtomicInteger(2);

    /**
     * ID of the session.
@@ -736,7 +738,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
        viewState.setState(newState);

        int requestId;

        // TODO(b/158623971): Update this to prevent possible overflow
        do {
            requestId = sIdCounter.getAndIncrement();
        } while (requestId == INVALID_REQUEST_ID);
@@ -1344,6 +1346,11 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
                    + id + " destroyed");
            return;
        }
        final int requestId = AutofillManager.getRequestIdFromAuthenticationId(authenticationId);
        if (requestId == AUGMENTED_AUTOFILL_REQUEST_ID) {
            setAuthenticationResultForAugmentedAutofillLocked(data, authenticationId);
            return;
        }
        if (mResponses == null) {
            // Typically happens when app explicitly called cancel() while the service was showing
            // the auth UI.
@@ -1351,7 +1358,6 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
            removeSelf();
            return;
        }
        final int requestId = AutofillManager.getRequestIdFromAuthenticationId(authenticationId);
        final FillResponse authenticatedResponse = mResponses.get(requestId);
        if (authenticatedResponse == null || data == null) {
            Slog.w(TAG, "no authenticated response");
@@ -1410,6 +1416,58 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
        }
    }

    @GuardedBy("mLock")
    void setAuthenticationResultForAugmentedAutofillLocked(Bundle data, int authId) {
        final Dataset dataset = (data == null) ? null :
                data.getParcelable(AutofillManager.EXTRA_AUTHENTICATION_RESULT);
        if (sDebug) {
            Slog.d(TAG, "Auth result for augmented autofill: sessionId=" + id
                    + ", authId=" + authId + ", dataset=" + dataset);
        }
        if (dataset == null
                || dataset.getFieldIds().size() != 1
                || dataset.getFieldIds().get(0) == null
                || dataset.getFieldValues().size() != 1
                || dataset.getFieldValues().get(0) == null) {
            if (sDebug) {
                Slog.d(TAG, "Rejecting empty/invalid auth result");
            }
            mService.resetLastAugmentedAutofillResponse();
            removeSelfLocked();
            return;
        }
        final List<AutofillId> fieldIds = dataset.getFieldIds();
        final List<AutofillValue> autofillValues = dataset.getFieldValues();
        final AutofillId fieldId = fieldIds.get(0);
        final AutofillValue value = autofillValues.get(0);

        // Update state to ensure that after filling the field here we don't end up firing another
        // autofill request that will end up showing the same suggestions to the user again. When
        // the auth activity came up, the field for which the suggestions were shown lost focus and
        // mCurrentViewId was cleared. We need to set mCurrentViewId back to the id of the field
        // that we are filling.
        fieldId.setSessionId(id);
        mCurrentViewId = fieldId;

        // Notify the Augmented Autofill provider of the dataset that was selected.
        final Bundle clientState = data.getBundle(AutofillManager.EXTRA_CLIENT_STATE);
        mService.logAugmentedAutofillSelected(id, dataset.getId(), clientState);

        // Fill the value into the field.
        if (sDebug) {
            Slog.d(TAG, "Filling after auth: fieldId=" + fieldId + ", value=" + value);
        }
        try {
            mClient.autofill(id, fieldIds, autofillValues, true);
        } catch (RemoteException e) {
            Slog.w(TAG, "Error filling after auth: fieldId=" + fieldId + ", value=" + value
                    + ", error=" + e);
        }

        // Clear the suggestions since the user already accepted one of them.
        mInlineSessionController.setInlineFillUiLocked(InlineFillUi.emptyUi(fieldId));
    }

    @GuardedBy("mLock")
    void setHasCallbackLocked(boolean hasIt) {
        if (mDestroyed) {
@@ -2506,6 +2564,10 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
                    + actionAsString(action) + ", flags=" + flags);
        }
        ViewState viewState = mViewStates.get(id);
        if (sVerbose) {
            Slog.v(TAG, "updateLocked(" + this.id + "): mCurrentViewId=" + mCurrentViewId
                    + ", mExpiredResponse=" + mExpiredResponse + ", viewState=" + viewState);
        }

        if (viewState == null) {
            if (action == ACTION_START_SESSION || action == ACTION_VALUE_CHANGED
+1 −1
Original line number Diff line number Diff line
@@ -290,7 +290,7 @@ public final class InlineFillUi {
        /**
         * Callback to autofill a dataset to the client app.
         */
        void autofill(@NonNull Dataset dataset);
        void autofill(@NonNull Dataset dataset, int datasetIndex);

        /**
         * Callback to start Intent in client app.
+1 −1
Original line number Diff line number Diff line
@@ -109,7 +109,7 @@ final class InlineSuggestionFactory {
        return createInlineSuggestionsInternal(/* isAugmented= */ true, request,
                datasets, autofillId, onErrorCallback,
                (dataset, datasetIndex) ->
                        inlineSuggestionUiCallback.autofill(dataset),
                        inlineSuggestionUiCallback.autofill(dataset, datasetIndex),
                (intentSender) ->
                        inlineSuggestionUiCallback.startIntentSender(intentSender, new Intent()),
                remoteRenderService);