diff options
9 files changed, 153 insertions, 118 deletions
diff --git a/core/java/android/inputmethodservice/InlineSuggestionSession.java b/core/java/android/inputmethodservice/InlineSuggestionSession.java index edae06a0b9df..1f12d2a6b659 100644 --- a/core/java/android/inputmethodservice/InlineSuggestionSession.java +++ b/core/java/android/inputmethodservice/InlineSuggestionSession.java @@ -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( diff --git a/core/java/android/service/autofill/augmented/AugmentedAutofillService.java b/core/java/android/service/autofill/augmented/AugmentedAutofillService.java index 672b501bbc41..fe792b1efd9f 100644 --- a/core/java/android/service/autofill/augmented/AugmentedAutofillService.java +++ b/core/java/android/service/autofill/augmented/AugmentedAutofillService.java @@ -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); } diff --git a/core/java/android/service/autofill/augmented/FillCallback.java b/core/java/android/service/autofill/augmented/FillCallback.java index 19eff57269ae..6b4e1185703c 100644 --- a/core/java/android/service/autofill/augmented/FillCallback.java +++ b/core/java/android/service/autofill/augmented/FillCallback.java @@ -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; } diff --git a/core/java/android/service/autofill/augmented/IFillCallback.aidl b/core/java/android/service/autofill/augmented/IFillCallback.aidl index d9837211be19..bf0adcd54ab1 100644 --- a/core/java/android/service/autofill/augmented/IFillCallback.aidl +++ b/core/java/android/service/autofill/augmented/IFillCallback.aidl @@ -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(); } diff --git a/core/java/com/android/internal/view/IInlineSuggestionsResponseCallback.aidl b/core/java/com/android/internal/view/IInlineSuggestionsResponseCallback.aidl index 0f93b8ebdb53..5a78e0d3082d 100644 --- a/core/java/com/android/internal/view/IInlineSuggestionsResponseCallback.aidl +++ b/core/java/com/android/internal/view/IInlineSuggestionsResponseCallback.aidl @@ -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); } diff --git a/services/autofill/java/com/android/server/autofill/InlineSuggestionSession.java b/services/autofill/java/com/android/server/autofill/InlineSuggestionSession.java index 6daa1064c89e..941244994dab 100644 --- a/services/autofill/java/com/android/server/autofill/InlineSuggestionSession.java +++ b/services/autofill/java/com/android/server/autofill/InlineSuggestionSession.java @@ -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; - } } } diff --git a/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java b/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java index 228c6286a0f0..dcc91811905a 100644 --- a/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java +++ b/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java @@ -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 diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java index 960997dd7df8..6fb65cae2482 100644 --- a/services/autofill/java/com/android/server/autofill/Session.java +++ b/services/autofill/java/com/android/server/autofill/Session.java @@ -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); - } - InlineSuggestionSession.ImeResponse imeResponse = - mInlineSuggestionSession.waitAndGetImeResponse(); - final InlineSuggestionsRequest inlineSuggestionsRequest = - imeResponse != null ? imeResponse.getRequest() : null; - final IInlineSuggestionsResponseCallback inlineSuggestionsResponseCallback = - imeResponse != null ? imeResponse.getCallback() : null; + mInlineSuggestionSession.onCreateInlineSuggestionsRequest(mCurrentViewId); + } + + 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(); } 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 0d1b6ddd2933..9bf369089e50 100644 --- a/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java +++ b/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionFactory.java @@ -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), |