Several improvements and bug fixes to the inline autofill flow

* Pipe the augmented autofill's inline actions through to the
  InlineSuggestionsResponse
* Do not send the inline action if the number of inline suggestions is
  zero
* Refactor autofill inline suggstion session so that all the calls to
  the IME has happens within the class
* Send an empty response to IME to hide the inline suggestion UI  when
  view exits and the previous response wasn't empty

Test: manual verification, atest InlineLoginActivityTest
Bug: 149522488
Bug: 150312201

Change-Id: I7a0dbf44e9fad6e7da857448c0f2b186e1681d17
This commit is contained in:
Feng Cao
2020-02-28 11:36:59 -08:00
parent 8839aaee6d
commit ec496000ec
9 changed files with 152 additions and 117 deletions

View File

@@ -27,6 +27,7 @@ import android.os.IBinder;
import android.os.Looper;
import android.os.RemoteException;
import android.util.Log;
import android.view.autofill.AutofillId;
import android.view.inputmethod.InlineSuggestionsRequest;
import android.view.inputmethod.InlineSuggestionsResponse;
@@ -145,8 +146,8 @@ class InlineSuggestionSession {
}
@Override
public void onInlineSuggestionsResponse(InlineSuggestionsResponse response)
throws RemoteException {
public void onInlineSuggestionsResponse(AutofillId fieldId,
InlineSuggestionsResponse response) {
final InlineSuggestionSession session = mInlineSuggestionSession.get();
if (session != null) {
session.mHandler.sendMessage(obtainMessage(

View File

@@ -40,6 +40,7 @@ import android.os.RemoteException;
import android.os.SystemClock;
import android.service.autofill.Dataset;
import android.service.autofill.FillEventHistory;
import android.service.autofill.InlinePresentation;
import android.service.autofill.augmented.PresentationParams.SystemPopupPresentationParams;
import android.util.Log;
import android.util.Pair;
@@ -557,12 +558,10 @@ public abstract class AugmentedAutofillService extends Service {
}
}
void reportResult(@Nullable List<Dataset> inlineSuggestionsData) {
void reportResult(@Nullable List<Dataset> inlineSuggestionsData,
@Nullable List<InlinePresentation> inlineActions) {
try {
final Dataset[] inlineSuggestions = (inlineSuggestionsData != null)
? inlineSuggestionsData.toArray(new Dataset[inlineSuggestionsData.size()])
: null;
mCallback.onSuccess(inlineSuggestions);
mCallback.onSuccess(inlineSuggestionsData, inlineActions);
} catch (RemoteException e) {
Log.e(TAG, "Error calling back with the inline suggestions data: " + e);
}

View File

@@ -55,14 +55,14 @@ public final class FillCallback {
if (response == null) {
mProxy.logEvent(AutofillProxy.REPORT_EVENT_NO_RESPONSE);
mProxy.reportResult(null /*inlineSuggestions*/);
mProxy.reportResult(/* inlineSuggestionsData */ null, /* inlineActions */null);
return;
}
List<Dataset> inlineSuggestions = response.getInlineSuggestions();
if (inlineSuggestions != null && !inlineSuggestions.isEmpty()) {
mProxy.logEvent(AutofillProxy.REPORT_EVENT_INLINE_RESPONSE);
mProxy.reportResult(inlineSuggestions);
mProxy.reportResult(inlineSuggestions, response.getInlineActions());
return;
}

View File

@@ -20,6 +20,9 @@ import android.os.Bundle;
import android.os.ICancellationSignal;
import android.service.autofill.Dataset;
import android.service.autofill.InlinePresentation;
import java.util.List;
/**
* Interface to receive the result of an autofill request.
@@ -28,7 +31,8 @@ import android.service.autofill.Dataset;
*/
interface IFillCallback {
void onCancellable(in ICancellationSignal cancellation);
void onSuccess(in @nullable Dataset[] inlineSuggestionsData);
void onSuccess(in @nullable List<Dataset> inlineSuggestionsData,
in @nullable List<InlinePresentation> inlineActions);
boolean isCompleted();
void cancel();
}

View File

@@ -16,6 +16,7 @@
package com.android.internal.view;
import android.view.autofill.AutofillId;
import android.view.inputmethod.InlineSuggestionsResponse;
/**
@@ -23,5 +24,5 @@ import android.view.inputmethod.InlineSuggestionsResponse;
* {@hide}
*/
oneway interface IInlineSuggestionsResponseCallback {
void onInlineSuggestionsResponse(in InlineSuggestionsResponse response);
void onInlineSuggestionsResponse(in AutofillId fieldId, in InlineSuggestionsResponse response);
}

View File

@@ -24,8 +24,10 @@ import android.content.ComponentName;
import android.os.Bundle;
import android.os.RemoteException;
import android.util.Log;
import android.util.Slog;
import android.view.autofill.AutofillId;
import android.view.inputmethod.InlineSuggestionsRequest;
import android.view.inputmethod.InlineSuggestionsResponse;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.view.IInlineSuggestionsRequestCallback;
@@ -33,6 +35,8 @@ import com.android.internal.view.IInlineSuggestionsResponseCallback;
import com.android.internal.view.InlineSuggestionsRequestInfo;
import com.android.server.inputmethod.InputMethodManagerInternal;
import java.util.Collections;
import java.util.Optional;
import java.util.concurrent.CancellationException;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
@@ -40,9 +44,16 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
/**
* Maintains an inline suggestion autofill session.
* Maintains an autofill inline suggestion session that communicates with the IME.
*
* <p> This class is thread safe.
* <p>
* The same session may be reused for multiple input fields involved in the same autofill
* {@link Session}. Therefore, one {@link InlineSuggestionsRequest} and one
* {@link IInlineSuggestionsResponseCallback} may be used to generate and callback with inline
* suggestions for different input fields.
*
* <p>
* This class is thread safe.
*/
final class InlineSuggestionSession {
@@ -61,6 +72,9 @@ final class InlineSuggestionSession {
@Nullable
private CompletableFuture<ImeResponse> mPendingImeResponse;
@GuardedBy("mLock")
private boolean mIsLastResponseNonEmpty = false;
InlineSuggestionSession(InputMethodManagerInternal inputMethodManagerInternal,
int userId, ComponentName componentName) {
mInputMethodManagerInternal = inputMethodManagerInternal;
@@ -69,26 +83,28 @@ final class InlineSuggestionSession {
mLock = new Object();
}
public void createRequest(@NonNull AutofillId currentViewId) {
public void onCreateInlineSuggestionsRequest(@NonNull AutofillId autofillId) {
if (sDebug) Log.d(TAG, "onCreateInlineSuggestionsRequest called for " + autofillId);
synchronized (mLock) {
cancelCurrentRequest();
mPendingImeResponse = new CompletableFuture<>();
// TODO(b/146454892): pipe the uiExtras from the ExtServices.
mInputMethodManagerInternal.onCreateInlineSuggestionsRequest(
mUserId,
new InlineSuggestionsRequestInfo(mComponentName, currentViewId, new Bundle()),
new InlineSuggestionsRequestInfo(mComponentName, autofillId, new Bundle()),
new InlineSuggestionsRequestCallbackImpl(mPendingImeResponse));
}
}
@Nullable
public ImeResponse waitAndGetImeResponse() {
CompletableFuture<ImeResponse> pendingImeResponse = getPendingImeResponse();
if (pendingImeResponse == null || pendingImeResponse.isCancelled()) {
return null;
public Optional<InlineSuggestionsRequest> waitAndGetInlineSuggestionsRequest() {
final CompletableFuture<ImeResponse> pendingImeResponse = getPendingImeResponse();
if (pendingImeResponse == null) {
return Optional.empty();
}
try {
return pendingImeResponse.get(INLINE_REQUEST_TIMEOUT_MS, TimeUnit.MILLISECONDS);
return Optional.ofNullable(pendingImeResponse.get(INLINE_REQUEST_TIMEOUT_MS,
TimeUnit.MILLISECONDS)).map(ImeResponse::getRequest);
} catch (TimeoutException e) {
Log.w(TAG, "Exception getting inline suggestions request in time: " + e);
} catch (CancellationException e) {
@@ -96,13 +112,59 @@ final class InlineSuggestionSession {
} catch (InterruptedException | ExecutionException e) {
throw new RuntimeException(e);
}
return null;
return Optional.empty();
}
public boolean hideInlineSuggestionsUi(@NonNull AutofillId autofillId) {
if (sDebug) Log.d(TAG, "Called hideInlineSuggestionsUi for " + autofillId);
synchronized (mLock) {
if (mIsLastResponseNonEmpty) {
if (sDebug) Log.d(TAG, "Send empty suggestion to IME");
return onInlineSuggestionsResponseLocked(autofillId,
new InlineSuggestionsResponse(Collections.EMPTY_LIST));
}
return false;
}
}
public boolean onInlineSuggestionsResponse(@NonNull AutofillId autofillId,
@NonNull InlineSuggestionsResponse inlineSuggestionsResponse) {
synchronized (mLock) {
return onInlineSuggestionsResponseLocked(autofillId, inlineSuggestionsResponse);
}
}
private boolean onInlineSuggestionsResponseLocked(@NonNull AutofillId autofillId,
@NonNull InlineSuggestionsResponse inlineSuggestionsResponse) {
final CompletableFuture<ImeResponse> completedImsResponse = getPendingImeResponse();
if (completedImsResponse == null || !completedImsResponse.isDone()) {
return false;
}
// There is no need to wait on the CompletableFuture since it should have been completed
// when {@link #waitAndGetInlineSuggestionsRequest()} was called.
ImeResponse imeResponse = completedImsResponse.getNow(null);
if (imeResponse == null) {
return false;
}
try {
imeResponse.mCallback.onInlineSuggestionsResponse(autofillId,
inlineSuggestionsResponse);
mIsLastResponseNonEmpty = !inlineSuggestionsResponse.getInlineSuggestions().isEmpty();
if (sDebug) {
Log.d(TAG, "Autofill sends inline response to IME: "
+ inlineSuggestionsResponse.getInlineSuggestions().size());
}
return true;
} catch (RemoteException e) {
Slog.e(TAG, "RemoteException sending InlineSuggestionsResponse to IME");
return false;
}
}
private void cancelCurrentRequest() {
CompletableFuture<ImeResponse> pendingImeResponse = getPendingImeResponse();
if (pendingImeResponse != null) {
pendingImeResponse.cancel(true);
if (pendingImeResponse != null && !pendingImeResponse.isDone()) {
pendingImeResponse.complete(null);
}
}
@@ -125,22 +187,18 @@ final class InlineSuggestionSession {
@Override
public void onInlineSuggestionsUnsupported() throws RemoteException {
if (sDebug) {
Log.d(TAG, "onInlineSuggestionsUnsupported() called.");
}
mResponse.cancel(true);
if (sDebug) Log.d(TAG, "onInlineSuggestionsUnsupported() called.");
mResponse.complete(null);
}
@Override
public void onInlineSuggestionsRequest(InlineSuggestionsRequest request,
IInlineSuggestionsResponseCallback callback) throws RemoteException {
if (sDebug) {
Log.d(TAG, "onInlineSuggestionsRequest() received: " + request);
}
IInlineSuggestionsResponseCallback callback) {
if (sDebug) Log.d(TAG, "onInlineSuggestionsRequest() received: " + request);
if (request != null && callback != null) {
mResponse.complete(new ImeResponse(request, callback));
} else {
mResponse.cancel(true);
mResponse.complete(null);
}
}
}
@@ -148,12 +206,12 @@ final class InlineSuggestionSession {
/**
* A data class wrapping IME responses for the inline suggestion request.
*/
public static class ImeResponse {
private static class ImeResponse {
@NonNull
private final InlineSuggestionsRequest mRequest;
final InlineSuggestionsRequest mRequest;
@NonNull
private final IInlineSuggestionsResponseCallback mCallback;
final IInlineSuggestionsResponseCallback mCallback;
ImeResponse(@NonNull InlineSuggestionsRequest request,
@NonNull IInlineSuggestionsResponseCallback callback) {
@@ -161,12 +219,8 @@ final class InlineSuggestionSession {
mCallback = callback;
}
public InlineSuggestionsRequest getRequest() {
InlineSuggestionsRequest getRequest() {
return mRequest;
}
public IInlineSuggestionsResponseCallback getCallback() {
return mCallback;
}
}
}

View File

@@ -37,6 +37,7 @@ import android.os.ICancellationSignal;
import android.os.RemoteException;
import android.os.SystemClock;
import android.service.autofill.Dataset;
import android.service.autofill.InlinePresentation;
import android.service.autofill.augmented.AugmentedAutofillService;
import android.service.autofill.augmented.IAugmentedAutofillService;
import android.service.autofill.augmented.IFillCallback;
@@ -54,14 +55,14 @@ import com.android.internal.infra.AndroidFuture;
import com.android.internal.infra.ServiceConnector;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.os.IResultReceiver;
import com.android.internal.util.ArrayUtils;
import com.android.internal.view.IInlineSuggestionsResponseCallback;
import com.android.server.autofill.ui.InlineSuggestionFactory;
import java.util.List;
import java.util.concurrent.CancellationException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Function;
final class RemoteAugmentedAutofillService
extends ServiceConnector.Impl<IAugmentedAutofillService> {
@@ -146,7 +147,7 @@ final class RemoteAugmentedAutofillService
int taskId, @NonNull ComponentName activityComponent, @NonNull AutofillId focusedId,
@Nullable AutofillValue focusedValue,
@Nullable InlineSuggestionsRequest inlineSuggestionsRequest,
@Nullable IInlineSuggestionsResponseCallback inlineSuggestionsCallback,
@Nullable Function<InlineSuggestionsResponse, Boolean> inlineSuggestionsCallback,
@NonNull Runnable onErrorCallback,
@NonNull RemoteInlineSuggestionRenderService remoteRenderService) {
long requestTime = SystemClock.elapsedRealtime();
@@ -165,12 +166,13 @@ final class RemoteAugmentedAutofillService
focusedId, focusedValue, requestTime, inlineSuggestionsRequest,
new IFillCallback.Stub() {
@Override
public void onSuccess(@Nullable Dataset[] inlineSuggestionsData) {
public void onSuccess(@Nullable List<Dataset> inlineSuggestionsData,
@Nullable List<InlinePresentation> inlineActions) {
mCallbacks.resetLastResponse();
maybeRequestShowInlineSuggestions(sessionId,
inlineSuggestionsRequest, inlineSuggestionsData,
focusedId, inlineSuggestionsCallback, client,
onErrorCallback, remoteRenderService);
inlineActions, focusedId, inlineSuggestionsCallback,
client, onErrorCallback, remoteRenderService);
requestAutofill.complete(null);
}
@@ -233,20 +235,21 @@ final class RemoteAugmentedAutofillService
}
private void maybeRequestShowInlineSuggestions(int sessionId,
@Nullable InlineSuggestionsRequest request, @Nullable Dataset[] inlineSuggestionsData,
@NonNull AutofillId focusedId,
@Nullable IInlineSuggestionsResponseCallback inlineSuggestionsCallback,
@Nullable InlineSuggestionsRequest request,
@Nullable List<Dataset> inlineSuggestionsData,
@Nullable List<InlinePresentation> inlineActions, @NonNull AutofillId focusedId,
@Nullable Function<InlineSuggestionsResponse, Boolean> inlineSuggestionsCallback,
@NonNull IAutoFillManagerClient client, @NonNull Runnable onErrorCallback,
@NonNull RemoteInlineSuggestionRenderService remoteRenderService) {
if (ArrayUtils.isEmpty(inlineSuggestionsData) || inlineSuggestionsCallback == null
|| request == null) {
if (inlineSuggestionsData == null || inlineSuggestionsData.isEmpty()
|| inlineSuggestionsCallback == null || request == null) {
return;
}
mCallbacks.setLastResponse(sessionId);
final InlineSuggestionsResponse inlineSuggestionsResponse =
InlineSuggestionFactory.createAugmentedInlineSuggestionsResponse(
request, inlineSuggestionsData, focusedId, mContext,
request, inlineSuggestionsData, inlineActions, focusedId, mContext,
dataset -> {
mCallbacks.logAugmentedAutofillSelected(sessionId,
dataset.getId());
@@ -262,14 +265,9 @@ final class RemoteAugmentedAutofillService
Slog.w(TAG, "InlineSuggestionFactory created null response");
return;
}
try {
inlineSuggestionsCallback.onInlineSuggestionsResponse(inlineSuggestionsResponse);
} catch (RemoteException e) {
Slog.w(TAG, "Exception sending inline suggestions response back to IME.");
if (inlineSuggestionsCallback.apply(inlineSuggestionsResponse)) {
mCallbacks.logAugmentedAutofillShown(sessionId);
}
mCallbacks.logAugmentedAutofillShown(sessionId);
}
@Override

View File

@@ -100,7 +100,6 @@ import com.android.internal.annotations.GuardedBy;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.util.ArrayUtils;
import com.android.internal.view.IInlineSuggestionsResponseCallback;
import com.android.server.autofill.ui.AutoFillUI;
import com.android.server.autofill.ui.InlineSuggestionFactory;
import com.android.server.autofill.ui.PendingUi;
@@ -113,6 +112,7 @@ import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicInteger;
/**
@@ -403,11 +403,10 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
final ArrayList<FillContext> contexts =
mergePreviousSessionLocked(/* forSave= */ false);
final InlineSuggestionSession.ImeResponse imeResponse =
mInlineSuggestionSession.waitAndGetImeResponse();
final Optional<InlineSuggestionsRequest> inlineSuggestionsRequest =
mInlineSuggestionSession.waitAndGetInlineSuggestionsRequest();
request = new FillRequest(requestId, contexts, mClientState, flags,
imeResponse != null ? imeResponse.getRequest() : null);
inlineSuggestionsRequest.orElse(null));
}
if (mActivityToken != null) {
@@ -605,7 +604,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
private void maybeRequestInlineSuggestionsRequestThenFillLocked(@NonNull ViewState viewState,
int newState, int flags) {
if (isInlineSuggestionsEnabled()) {
mInlineSuggestionSession.createRequest(mCurrentViewId);
mInlineSuggestionSession.onCreateInlineSuggestionsRequest(mCurrentViewId);
}
requestNewFillResponseLocked(viewState, newState, flags);
@@ -1158,18 +1157,6 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
} catch (RemoteException e) {
Slog.e(TAG, "Error requesting to hide fill UI", e);
}
try {
final InlineSuggestionSession.ImeResponse imeResponse =
mInlineSuggestionSession.waitAndGetImeResponse();
if (imeResponse == null) {
Log.w(TAG, "Session input method callback is not set yet");
return;
}
imeResponse.getCallback().onInlineSuggestionsResponse(
new InlineSuggestionsResponse(Collections.EMPTY_LIST));
} catch (RemoteException e) {
Slog.e(TAG, "RemoteException hiding inline suggestions");
}
}
}
@@ -2501,6 +2488,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
if (sVerbose) Slog.v(TAG, "Exiting view " + id);
mUi.hideFillUi(this);
hideAugmentedAutofillLocked(viewState);
mInlineSuggestionSession.hideInlineSuggestionsUi(mCurrentViewId);
mCurrentViewId = null;
}
break;
@@ -2668,38 +2656,27 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
*/
private boolean requestShowInlineSuggestionsLocked(@NonNull FillResponse response,
@Nullable String filterText) {
final List<Dataset> datasets = response.getDatasets();
final InlineSuggestionSession.ImeResponse imeResponse =
mInlineSuggestionSession.waitAndGetImeResponse();
if (imeResponse == null) {
Log.w(TAG, "Session input method callback is not set yet");
final Optional<InlineSuggestionsRequest> inlineSuggestionsRequest =
mInlineSuggestionSession.waitAndGetInlineSuggestionsRequest();
if (!inlineSuggestionsRequest.isPresent()) {
Log.w(TAG, "InlineSuggestionsRequest unavailable");
return false;
}
final InlineSuggestionsRequest request = imeResponse.getRequest();
InlineSuggestionsResponse inlineSuggestionsResponse =
InlineSuggestionFactory.createInlineSuggestionsResponse(request,
InlineSuggestionFactory.createInlineSuggestionsResponse(
inlineSuggestionsRequest.get(),
response, filterText, response.getInlineActions(), mCurrentViewId, mContext,
this, () -> {
synchronized (mLock) {
requestHideFillUi(mCurrentViewId);
}
}, mService.getRemoteInlineSuggestionRenderServiceLocked());
if (inlineSuggestionsResponse == null) {
Slog.w(TAG, "InlineSuggestionFactory created null response");
return false;
}
try {
imeResponse.getCallback().onInlineSuggestionsResponse(inlineSuggestionsResponse);
} catch (RemoteException e) {
Log.w(TAG, "onFillReady() remote error calling onInlineSuggestionsResponse()");
return false;
}
return true;
return mInlineSuggestionSession.onInlineSuggestionsResponse(mCurrentViewId,
inlineSuggestionsResponse);
}
boolean isDestroyed() {
@@ -2982,16 +2959,16 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
// doesn't want autofill
if (mForAugmentedAutofillOnly || !isInlineSuggestionsEnabled()) {
if (sDebug) Slog.d(TAG, "Create inline request for augmented autofill");
mInlineSuggestionSession.createRequest(mCurrentViewId);
mInlineSuggestionSession.onCreateInlineSuggestionsRequest(mCurrentViewId);
}
InlineSuggestionSession.ImeResponse imeResponse =
mInlineSuggestionSession.waitAndGetImeResponse();
final InlineSuggestionsRequest inlineSuggestionsRequest =
imeResponse != null ? imeResponse.getRequest() : null;
final IInlineSuggestionsResponseCallback inlineSuggestionsResponseCallback =
imeResponse != null ? imeResponse.getCallback() : null;
Optional<InlineSuggestionsRequest> inlineSuggestionsRequest =
mInlineSuggestionSession.waitAndGetInlineSuggestionsRequest();
remoteService.onRequestAutofillLocked(id, mClient, taskId, mComponentName, focusedId,
currentValue, inlineSuggestionsRequest, inlineSuggestionsResponseCallback, () -> {
currentValue, inlineSuggestionsRequest.orElse(null),
response -> mInlineSuggestionSession.onInlineSuggestionsResponse(
mCurrentViewId, response),
() -> {
synchronized (mLock) {
cancelAugmentedAutofillLocked();
}

View File

@@ -70,6 +70,7 @@ public final class InlineSuggestionFactory {
* Creates an {@link InlineSuggestionsResponse} with the {@code datasets} provided by the
* autofill service, potentially filtering the datasets.
*/
@Nullable
public static InlineSuggestionsResponse createInlineSuggestionsResponse(
@NonNull InlineSuggestionsRequest request, @NonNull FillResponse response,
@Nullable String filterText, @Nullable List<InlinePresentation> inlineActions,
@@ -92,23 +93,21 @@ public final class InlineSuggestionFactory {
};
}
final List<Dataset> datasetList = response.getDatasets();
final Dataset[] datasets = datasetList == null
? null
: datasetList.toArray(new Dataset[]{});
final InlinePresentation inlineAuthentication =
response.getAuthentication() == null ? null : response.getInlinePresentation();
return createInlineSuggestionsResponseInternal(/* isAugmented= */ false, request,
datasets, filterText, inlineAuthentication, inlineActions, autofillId, context,
onErrorCallback, onClickFactory, remoteRenderService);
response.getDatasets(), filterText, inlineAuthentication, inlineActions, autofillId,
context, onErrorCallback, onClickFactory, remoteRenderService);
}
/**
* Creates an {@link InlineSuggestionsResponse} with the {@code datasets} provided by augmented
* autofill service.
*/
@Nullable
public static InlineSuggestionsResponse createAugmentedInlineSuggestionsResponse(
@NonNull InlineSuggestionsRequest request, @NonNull Dataset[] datasets,
@NonNull InlineSuggestionsRequest request, @NonNull List<Dataset> datasets,
@Nullable List<InlinePresentation> inlineActions,
@NonNull AutofillId autofillId, @NonNull Context context,
@NonNull InlineSuggestionUiCallback inlineSuggestionUiCallback,
@NonNull Runnable onErrorCallback,
@@ -116,14 +115,15 @@ public final class InlineSuggestionFactory {
if (sDebug) Slog.d(TAG, "createAugmentedInlineSuggestionsResponse called");
return createInlineSuggestionsResponseInternal(/* isAugmented= */ true, request,
datasets, /* filterText= */ null, /* inlineAuthentication= */ null,
/* inlineActions= */ null, autofillId, context, onErrorCallback,
inlineActions, autofillId, context, onErrorCallback,
(dataset, datasetIndex) ->
inlineSuggestionUiCallback.autofill(dataset), remoteRenderService);
}
@Nullable
private static InlineSuggestionsResponse createInlineSuggestionsResponseInternal(
boolean isAugmented, @NonNull InlineSuggestionsRequest request,
@Nullable Dataset[] datasets, @Nullable String filterText,
@Nullable List<Dataset> datasets, @Nullable String filterText,
@Nullable InlinePresentation inlineAuthentication,
@Nullable List<InlinePresentation> inlineActions, @NonNull AutofillId autofillId,
@NonNull Context context, @NonNull Runnable onErrorCallback,
@@ -145,8 +145,8 @@ public final class InlineSuggestionFactory {
return null;
}
for (int datasetIndex = 0; datasetIndex < datasets.length; datasetIndex++) {
final Dataset dataset = datasets[datasetIndex];
for (int datasetIndex = 0; datasetIndex < datasets.size(); datasetIndex++) {
final Dataset dataset = datasets.get(datasetIndex);
final int fieldIndex = dataset.getFieldIds().indexOf(autofillId);
if (fieldIndex < 0) {
Slog.w(TAG, "AutofillId=" + autofillId + " not found in dataset");
@@ -169,7 +169,8 @@ public final class InlineSuggestionFactory {
inlineSuggestions.add(inlineSuggestion);
}
if (inlineActions != null) {
// We should only add inline actions if there is at least one suggestion.
if (!inlineSuggestions.isEmpty() && inlineActions != null) {
for (InlinePresentation inlinePresentation : inlineActions) {
final InlineSuggestion inlineAction = createInlineAction(isAugmented, context,
mergedInlinePresentation(request, 0, inlinePresentation),