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:
@@ -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(
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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),
|
||||
|
||||
Reference in New Issue
Block a user