diff options
author | Nikita Dubrovsky <dubrovsky@google.com> | 2020-06-08 09:55:47 -0700 |
---|---|---|
committer | Nikita Dubrovsky <dubrovsky@google.com> | 2020-06-16 16:03:36 -0700 |
commit | d0433c71081e702ed37540e749c813f608983e32 (patch) | |
tree | 8fb50105d63493815bf2dfd5028a28df3adb45a8 | |
parent | e710511e85d10e0e65f71291812c69e219bf8aa7 (diff) |
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
5 files changed, 113 insertions, 6 deletions
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java index 96b593d9682f..57ffe0498a88 100644 --- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java +++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java @@ -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) { @@ -1199,6 +1212,14 @@ final class AutofillManagerServiceImpl } @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"); final RemoteAugmentedAutofillService remoteService = diff --git a/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java b/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java index a7d0061cc043..4e0970f1e40b 100644 --- a/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java +++ b/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java @@ -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); } } diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java index fa449ad29e53..158ed8ca6906 100644 --- a/services/autofill/java/com/android/server/autofill/Session.java +++ b/services/autofill/java/com/android/server/autofill/Session.java @@ -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"); @@ -1411,6 +1417,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) { Slog.w(TAG, "Call to Session#setHasCallbackLocked() rejected - session: " @@ -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 diff --git a/services/autofill/java/com/android/server/autofill/ui/InlineFillUi.java b/services/autofill/java/com/android/server/autofill/ui/InlineFillUi.java index a3d0fb955da4..1c430b3543ac 100644 --- a/services/autofill/java/com/android/server/autofill/ui/InlineFillUi.java +++ b/services/autofill/java/com/android/server/autofill/ui/InlineFillUi.java @@ -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. diff --git a/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java b/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java index c8485b7c2b38..462ffd668e2e 100644 --- a/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java +++ b/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java @@ -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); |