Add server side implementation for inline augmented autofill request.
Test: manual
Bug: 146453195
Change-Id: Id9c3e16cd5b05ba1c87eb8cdb4a95f2f79bfd77b
diff --git a/core/java/android/service/autofill/augmented/AugmentedAutofillService.java b/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
index 484eddc..6334d9d 100644
--- a/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
+++ b/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
@@ -38,6 +38,7 @@
import android.os.Looper;
import android.os.RemoteException;
import android.os.SystemClock;
+import android.service.autofill.Dataset;
import android.service.autofill.augmented.PresentationParams.SystemPopupPresentationParams;
import android.util.Log;
import android.util.Pair;
@@ -47,6 +48,7 @@
import android.view.autofill.AutofillValue;
import android.view.autofill.IAugmentedAutofillManagerClient;
import android.view.autofill.IAutofillWindowPresenter;
+import android.view.inputmethod.InlineSuggestionsRequest;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
@@ -106,10 +108,11 @@
@Override
public void onFillRequest(int sessionId, IBinder client, int taskId,
ComponentName componentName, AutofillId focusedId, AutofillValue focusedValue,
- long requestTime, IFillCallback callback) {
+ long requestTime, @Nullable InlineSuggestionsRequest inlineSuggestionsRequest,
+ IFillCallback callback) {
mHandler.sendMessage(obtainMessage(AugmentedAutofillService::handleOnFillRequest,
AugmentedAutofillService.this, sessionId, client, taskId, componentName,
- focusedId, focusedValue, requestTime, callback));
+ focusedId, focusedValue, requestTime, inlineSuggestionsRequest, callback));
}
@Override
@@ -212,6 +215,7 @@
private void handleOnFillRequest(int sessionId, @NonNull IBinder client, int taskId,
@NonNull ComponentName componentName, @NonNull AutofillId focusedId,
@Nullable AutofillValue focusedValue, long requestTime,
+ @Nullable InlineSuggestionsRequest inlineSuggestionsRequest,
@NonNull IFillCallback callback) {
if (mAutofillProxies == null) {
mAutofillProxies = new SparseArray<>();
@@ -236,9 +240,8 @@
} catch (RemoteException e) {
e.rethrowFromSystemServer();
}
- // TODO(b/146453195): pass the inline suggestion request over.
- onFillRequest(new FillRequest(proxy, /* inlineSuggestionsRequest= */null),
- cancellationSignal, new FillController(proxy), new FillCallback(proxy));
+ onFillRequest(new FillRequest(proxy, inlineSuggestionsRequest), cancellationSignal,
+ new FillController(proxy), new FillCallback(proxy));
}
private void handleOnDestroyAllFillWindowsRequest() {
@@ -484,6 +487,14 @@
}
}
+ public void onInlineSuggestionsDataReady(@NonNull List<Dataset> inlineSuggestionsData) {
+ try {
+ mCallback.onSuccess(inlineSuggestionsData.toArray(new Dataset[]{}));
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error calling back with the inline suggestions data: " + e);
+ }
+ }
+
// Used (mostly) for metrics.
public void report(@ReportEvent int event) {
if (sVerbose) Log.v(TAG, "report(): " + event);
diff --git a/core/java/android/service/autofill/augmented/FillCallback.java b/core/java/android/service/autofill/augmented/FillCallback.java
index 0251386..b767799 100644
--- a/core/java/android/service/autofill/augmented/FillCallback.java
+++ b/core/java/android/service/autofill/augmented/FillCallback.java
@@ -21,9 +21,12 @@
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.annotation.TestApi;
+import android.service.autofill.Dataset;
import android.service.autofill.augmented.AugmentedAutofillService.AutofillProxy;
import android.util.Log;
+import java.util.List;
+
/**
* Callback used to indicate at {@link FillRequest} has been fulfilled.
*
@@ -45,7 +48,7 @@
* Sets the response associated with the request.
*
* @param response response associated with the request, or {@code null} if the service
- * could not provide autofill for the request.
+ * could not provide autofill for the request.
*/
public void onSuccess(@Nullable FillResponse response) {
if (sDebug) Log.d(TAG, "onSuccess(): " + response);
@@ -55,6 +58,12 @@
return;
}
+ List<Dataset> inlineSuggestions = response.getInlineSuggestions();
+ if (inlineSuggestions != null && !inlineSuggestions.isEmpty()) {
+ mProxy.onInlineSuggestionsDataReady(inlineSuggestions);
+ return;
+ }
+
final FillWindow fillWindow = response.getFillWindow();
if (fillWindow != null) {
fillWindow.show();
diff --git a/core/java/android/service/autofill/augmented/IAugmentedAutofillService.aidl b/core/java/android/service/autofill/augmented/IAugmentedAutofillService.aidl
index 103fc4d..4911348 100644
--- a/core/java/android/service/autofill/augmented/IAugmentedAutofillService.aidl
+++ b/core/java/android/service/autofill/augmented/IAugmentedAutofillService.aidl
@@ -22,6 +22,7 @@
import android.service.autofill.augmented.IFillCallback;
import android.view.autofill.AutofillId;
import android.view.autofill.AutofillValue;
+import android.view.inputmethod.InlineSuggestionsRequest;
import java.util.List;
@@ -35,7 +36,9 @@
void onDisconnected();
void onFillRequest(int sessionId, in IBinder autofillManagerClient, int taskId,
in ComponentName activityComponent, in AutofillId focusedId,
- in AutofillValue focusedValue, long requestTime, in IFillCallback callback);
+ in AutofillValue focusedValue, long requestTime,
+ in InlineSuggestionsRequest inlineSuggestionsRequest,
+ in IFillCallback callback);
void onDestroyAllFillWindowsRequest();
}
diff --git a/core/java/com/android/internal/infra/ServiceConnector.java b/core/java/com/android/internal/infra/ServiceConnector.java
index 857377a..e9d7d05 100644
--- a/core/java/com/android/internal/infra/ServiceConnector.java
+++ b/core/java/com/android/internal/infra/ServiceConnector.java
@@ -223,7 +223,7 @@
private final @NonNull ServiceConnection mServiceConnection = this;
private final @NonNull Runnable mTimeoutDisconnect = this;
- private final @NonNull Context mContext;
+ protected final @NonNull Context mContext;
private final @NonNull Intent mIntent;
private final int mBindingFlags;
private final int mUserId;
diff --git a/services/autofill/java/com/android/server/autofill/InlineSuggestionFactory.java b/services/autofill/java/com/android/server/autofill/InlineSuggestionFactory.java
new file mode 100644
index 0000000..3af15c7
--- /dev/null
+++ b/services/autofill/java/com/android/server/autofill/InlineSuggestionFactory.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.autofill;
+
+import static com.android.server.autofill.Helper.sDebug;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.os.Handler;
+import android.os.RemoteException;
+import android.service.autofill.Dataset;
+import android.util.Slog;
+import android.view.SurfaceControl;
+import android.view.View;
+import android.view.autofill.AutofillId;
+import android.view.autofill.IAutoFillManagerClient;
+import android.view.inline.InlinePresentationSpec;
+import android.view.inputmethod.InlineSuggestion;
+import android.view.inputmethod.InlineSuggestionInfo;
+import android.view.inputmethod.InlineSuggestionsRequest;
+import android.view.inputmethod.InlineSuggestionsResponse;
+
+import com.android.internal.view.inline.IInlineContentCallback;
+import com.android.internal.view.inline.IInlineContentProvider;
+import com.android.server.autofill.ui.InlineSuggestionUi;
+
+import java.util.ArrayList;
+
+
+/**
+ * @hide
+ */
+public final class InlineSuggestionFactory {
+ private static final String TAG = "InlineSuggestionFactory";
+
+ /**
+ * Creates an {@link InlineSuggestionsResponse} with the {@code datasets} provided by
+ * augmented autofill service.
+ */
+ public static InlineSuggestionsResponse createAugmentedInlineSuggestionsResponse(
+ int sessionId,
+ @NonNull Dataset[] datasets,
+ @NonNull AutofillId autofillId,
+ @NonNull InlineSuggestionsRequest request,
+ @NonNull Handler uiHandler,
+ @NonNull Context context,
+ @NonNull IAutoFillManagerClient client) {
+ if (sDebug) Slog.d(TAG, "createInlineSuggestionsResponse called");
+
+ final ArrayList<InlineSuggestion> inlineSuggestions = new ArrayList<>();
+ final InlineSuggestionUi inlineSuggestionUi = new InlineSuggestionUi(context);
+ for (Dataset dataset : datasets) {
+ // TODO(b/146453195): use the spec in the dataset.
+ InlinePresentationSpec spec = request.getPresentationSpecs().get(0);
+ if (spec == null) {
+ Slog.w(TAG, "InlinePresentationSpec is not provided in the response data set");
+ continue;
+ }
+ InlineSuggestion inlineSuggestion = createAugmentedInlineSuggestion(sessionId, dataset,
+ autofillId, spec, uiHandler, inlineSuggestionUi, client);
+ inlineSuggestions.add(inlineSuggestion);
+ }
+ return new InlineSuggestionsResponse(inlineSuggestions);
+ }
+
+ private static InlineSuggestion createAugmentedInlineSuggestion(int sessionId,
+ @NonNull Dataset dataset,
+ @NonNull AutofillId autofillId,
+ @NonNull InlinePresentationSpec spec,
+ @NonNull Handler uiHandler,
+ @NonNull InlineSuggestionUi inlineSuggestionUi,
+ @NonNull IAutoFillManagerClient client) {
+ // TODO(b/146453195): fill in the autofill hint properly.
+ final InlineSuggestionInfo inlineSuggestionInfo = new InlineSuggestionInfo(
+ spec, InlineSuggestionInfo.SOURCE_PLATFORM, new String[]{""});
+ final View.OnClickListener onClickListener = createOnClickListener(sessionId, dataset,
+ client);
+ final InlineSuggestion inlineSuggestion = new InlineSuggestion(inlineSuggestionInfo,
+ createInlineContentProvider(autofillId, dataset, uiHandler, inlineSuggestionUi,
+ onClickListener));
+ return inlineSuggestion;
+ }
+
+ private static IInlineContentProvider.Stub createInlineContentProvider(
+ @NonNull AutofillId autofillId, @NonNull Dataset dataset, @NonNull Handler uiHandler,
+ @NonNull InlineSuggestionUi inlineSuggestionUi,
+ @Nullable View.OnClickListener onClickListener) {
+ return new IInlineContentProvider.Stub() {
+ @Override
+ public void provideContent(int width, int height,
+ IInlineContentCallback callback) {
+ uiHandler.post(() -> {
+ SurfaceControl sc = inlineSuggestionUi.inflate(dataset, autofillId,
+ width, height, onClickListener);
+ try {
+ callback.onContent(sc);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Encounter exception calling back with inline content.");
+ }
+ });
+ }
+ };
+ }
+
+ private static View.OnClickListener createOnClickListener(int sessionId,
+ @NonNull Dataset dataset,
+ @NonNull IAutoFillManagerClient client) {
+ return v -> {
+ if (sDebug) Slog.d(TAG, "Inline suggestion clicked");
+ try {
+ client.autofill(sessionId, dataset.getFieldIds(), dataset.getFieldValues());
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Encounter exception autofilling the values");
+ }
+ };
+ }
+
+ private InlineSuggestionFactory() {
+ }
+}
diff --git a/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java b/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
index c5011b3..2a7357b 100644
--- a/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
+++ b/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
@@ -46,12 +46,15 @@
import android.view.autofill.AutofillManager;
import android.view.autofill.AutofillValue;
import android.view.autofill.IAutoFillManagerClient;
+import android.view.inputmethod.InlineSuggestionsRequest;
import com.android.internal.infra.AbstractRemoteService;
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 java.util.concurrent.CancellationException;
import java.util.concurrent.TimeUnit;
@@ -137,7 +140,9 @@
*/
public void onRequestAutofillLocked(int sessionId, @NonNull IAutoFillManagerClient client,
int taskId, @NonNull ComponentName activityComponent, @NonNull AutofillId focusedId,
- @Nullable AutofillValue focusedValue) {
+ @Nullable AutofillValue focusedValue,
+ @Nullable InlineSuggestionsRequest inlineSuggestionsRequest,
+ @Nullable IInlineSuggestionsResponseCallback inlineSuggestionsCallback) {
long requestTime = SystemClock.elapsedRealtime();
AtomicReference<ICancellationSignal> cancellationRef = new AtomicReference<>();
@@ -151,10 +156,13 @@
final IBinder realClient = resultData
.getBinder(AutofillManager.EXTRA_AUGMENTED_AUTOFILL_CLIENT);
service.onFillRequest(sessionId, realClient, taskId, activityComponent,
- focusedId, focusedValue, requestTime, new IFillCallback.Stub() {
+ focusedId, focusedValue, requestTime, inlineSuggestionsRequest,
+ new IFillCallback.Stub() {
@Override
public void onSuccess(@Nullable Dataset[] inlineSuggestionsData) {
- // TODO(b/146453195): handle non-null inline suggestions data.
+ maybeHandleInlineSuggestions(sessionId, inlineSuggestionsData,
+ focusedId, inlineSuggestionsRequest,
+ inlineSuggestionsCallback, client);
requestAutofill.complete(null);
}
@@ -216,6 +224,26 @@
});
}
+ private void maybeHandleInlineSuggestions(int sessionId,
+ @Nullable Dataset[] inlineSuggestionsData, @NonNull AutofillId focusedId,
+ @Nullable InlineSuggestionsRequest inlineSuggestionsRequest,
+ @Nullable IInlineSuggestionsResponseCallback inlineSuggestionsCallback,
+ @NonNull IAutoFillManagerClient client) {
+ if (inlineSuggestionsRequest == null
+ || ArrayUtils.isEmpty(inlineSuggestionsData)
+ || inlineSuggestionsCallback == null) {
+ return;
+ }
+ try {
+ inlineSuggestionsCallback.onInlineSuggestionsResponse(
+ InlineSuggestionFactory.createAugmentedInlineSuggestionsResponse(
+ sessionId, inlineSuggestionsData, focusedId, inlineSuggestionsRequest,
+ getJobHandler(), mContext, client));
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Exception sending inline suggestions response back to IME.");
+ }
+ }
+
@Override
public String toString() {
return "RemoteAugmentedAutofillService["
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 5af4399..864c96d 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -424,19 +424,7 @@
final ArrayList<FillContext> contexts =
mergePreviousSessionLocked(/* forSave= */ false);
- InlineSuggestionsRequest suggestionsRequest = null;
- if (mSuggestionsRequestFuture != null) {
- try {
- suggestionsRequest = mSuggestionsRequestFuture.get(
- INLINE_REQUEST_TIMEOUT_MS, TimeUnit.MILLISECONDS);
- } catch (TimeoutException e) {
- Log.w(TAG, "Exception getting inline suggestions request in time: " + e);
- } catch (CancellationException e) {
- Log.w(TAG, "Inline suggestions request cancelled");
- } catch (InterruptedException | ExecutionException e) {
- throw new RuntimeException(e);
- }
- }
+ final InlineSuggestionsRequest suggestionsRequest = getInlineSuggestionsRequest();
request = new FillRequest(requestId, contexts, mClientState, flags,
suggestionsRequest);
@@ -2692,21 +2680,8 @@
*/
private boolean requestShowInlineSuggestions(List<Slice> inlineSuggestionSlices,
FillResponse response) {
- IInlineSuggestionsResponseCallback inlineContentCallback = null;
- synchronized (mLock) {
- if (mInlineSuggestionsResponseCallbackFuture != null) {
- try {
- inlineContentCallback = mInlineSuggestionsResponseCallbackFuture.get(
- INLINE_REQUEST_TIMEOUT_MS, TimeUnit.MILLISECONDS);
- } catch (TimeoutException e) {
- Log.w(TAG, "Exception getting inline suggestions callback in time: " + e);
- } catch (CancellationException e) {
- Log.w(TAG, "Inline suggestions callback cancelled");
- } catch (InterruptedException | ExecutionException e) {
- throw new RuntimeException(e);
- }
- }
- }
+ final IInlineSuggestionsResponseCallback inlineContentCallback =
+ getInlineSuggestionsResponseCallback();
if (inlineContentCallback == null) {
Log.w(TAG, "Session input method callback is not set yet");
@@ -3063,9 +3038,12 @@
final AutofillId focusedId = AutofillId.withoutSession(mCurrentViewId);
- // TODO(b/137800469): implement inlined suggestions for augmented autofill
+ final InlineSuggestionsRequest inlineSuggestionsRequest = getInlineSuggestionsRequest();
+ final IInlineSuggestionsResponseCallback inlineSuggestionsResponseCallback =
+ getInlineSuggestionsResponseCallback();
+
remoteService.onRequestAutofillLocked(id, mClient, taskId, mComponentName, focusedId,
- currentValue);
+ currentValue, inlineSuggestionsRequest, inlineSuggestionsResponseCallback);
if (mAugmentedAutofillDestroyer == null) {
mAugmentedAutofillDestroyer = () -> remoteService.onDestroyAutofillWindowsRequest();
@@ -3073,6 +3051,40 @@
return mAugmentedAutofillDestroyer;
}
+ @Nullable
+ private InlineSuggestionsRequest getInlineSuggestionsRequest() {
+ if (mSuggestionsRequestFuture != null) {
+ try {
+ return mSuggestionsRequestFuture.get(
+ INLINE_REQUEST_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+ } catch (TimeoutException e) {
+ Log.w(TAG, "Exception getting inline suggestions request in time: " + e);
+ } catch (CancellationException e) {
+ Log.w(TAG, "Inline suggestions request cancelled");
+ } catch (InterruptedException | ExecutionException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ return null;
+ }
+
+ @Nullable
+ private IInlineSuggestionsResponseCallback getInlineSuggestionsResponseCallback() {
+ if (mInlineSuggestionsResponseCallbackFuture != null) {
+ try {
+ return mInlineSuggestionsResponseCallbackFuture.get(
+ INLINE_REQUEST_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+ } catch (TimeoutException e) {
+ Log.w(TAG, "Exception getting inline suggestions callback in time: " + e);
+ } catch (CancellationException e) {
+ Log.w(TAG, "Inline suggestions callback cancelled");
+ } catch (InterruptedException | ExecutionException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ return null;
+ }
+
@GuardedBy("mLock")
private void cancelAugmentedAutofillLocked() {
final RemoteAugmentedAutofillService remoteService = mService
diff --git a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
index e57b7b3..0511bf2 100644
--- a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
+++ b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
@@ -24,8 +24,6 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentSender;
-import android.graphics.Color;
-import android.graphics.PixelFormat;
import android.graphics.drawable.Drawable;
import android.metrics.LogMaker;
import android.os.Bundle;
@@ -40,13 +38,9 @@
import android.util.Slog;
import android.view.KeyEvent;
import android.view.SurfaceControl;
-import android.view.SurfaceControlViewHost;
-import android.view.WindowManager;
import android.view.autofill.AutofillId;
import android.view.autofill.AutofillManager;
-import android.view.autofill.AutofillValue;
import android.view.autofill.IAutofillWindowPresenter;
-import android.widget.TextView;
import android.widget.Toast;
import com.android.internal.logging.MetricsLogger;
@@ -189,8 +183,16 @@
Slog.w(TAG, "getSuggestionSurfaceForShowing() called with null dataset");
}
mHandler.post(() -> {
- final SurfaceControl suggestionSurface = inflateInlineSuggestion(dataset, response,
- autofillId, width, height);
+ final InlineSuggestionUi inlineSuggestionUi = new InlineSuggestionUi(mContext);
+ final SurfaceControl suggestionSurface = inlineSuggestionUi.inflate(dataset,
+ autofillId, width, height, v -> {
+ Slog.d(TAG, "Inline suggestion clicked");
+ hideFillUiUiThread(mCallback, true);
+ if (mCallback != null) {
+ final int datasetIndex = response.getDatasets().indexOf(dataset);
+ mCallback.fill(response.getRequestId(), datasetIndex, dataset);
+ }
+ });
try {
cb.onContent(suggestionSurface);
@@ -201,51 +203,6 @@
}
/**
- * TODO(b/137800469): Fill in javadoc, generate custom templated view for inline suggestions.
- * TODO: Move to ExtServices.
- *
- * @return a {@link SurfaceControl} with the inflated content embedded in it.
- */
- private SurfaceControl inflateInlineSuggestion(@NonNull Dataset dataset,
- @NonNull FillResponse response, AutofillId autofillId, int width, int height) {
- Slog.i(TAG, "inflate() called");
- final Context context = mContext;
- final int index = dataset.getFieldIds().indexOf(autofillId);
- if (index < 0) {
- Slog.w(TAG, "inflateInlineSuggestion(): AutofillId=" + autofillId
- + " not found in dataset");
- }
-
- final AutofillValue datasetValue = dataset.getFieldValues().get(index);
- //TODO(b/137800469): Pass in inputToken from IME.
- final SurfaceControlViewHost wvr = new SurfaceControlViewHost(context, context.getDisplay(),
- (IBinder) null);
- // TODO(b/134365580): Use the package instead of the SurfaceControl itself
- // for accessibility support.
- final SurfaceControl sc = wvr.getSurfacePackage().getSurfaceControl();
-
- TextView textView = new TextView(context);
- textView.setText(datasetValue.getTextValue());
- textView.setBackgroundColor(Color.WHITE);
- textView.setTextColor(Color.BLACK);
- textView.setOnClickListener(v -> {
- Slog.d(TAG, "Inline suggestion clicked");
- hideFillUiUiThread(mCallback, true);
- if (mCallback != null) {
- final int datasetIndex = response.getDatasets().indexOf(dataset);
- mCallback.fill(response.getRequestId(), datasetIndex, dataset);
- }
- });
-
- WindowManager.LayoutParams lp =
- new WindowManager.LayoutParams(width, height,
- WindowManager.LayoutParams.TYPE_APPLICATION, 0, PixelFormat.OPAQUE);
- wvr.addView(textView, lp);
-
- return sc;
- }
-
- /**
* Shows the fill UI, removing the previous fill UI if the has changed.
*
* @param focusedId the currently focused field
diff --git a/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionUi.java b/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionUi.java
new file mode 100644
index 0000000..17cb739
--- /dev/null
+++ b/services/autofill/java/com/android/server/autofill/ui/InlineSuggestionUi.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.autofill.ui;
+
+import android.annotation.MainThread;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.graphics.Color;
+import android.graphics.PixelFormat;
+import android.os.IBinder;
+import android.service.autofill.Dataset;
+import android.util.Log;
+import android.util.Slog;
+import android.view.SurfaceControl;
+import android.view.SurfaceControlViewHost;
+import android.view.View;
+import android.view.WindowManager;
+import android.view.autofill.AutofillId;
+import android.view.autofill.AutofillValue;
+import android.widget.TextView;
+
+/**
+ * This is a temporary inline suggestion UI inflater which will be replaced by the ExtServices
+ * implementation.
+ *
+ * TODO(b/146453086): remove this class once autofill ext service is implemented.
+ *
+ * @hide
+ */
+public class InlineSuggestionUi {
+
+ private static final String TAG = "InlineSuggestionUi";
+
+ private final Context mContext;
+
+ public InlineSuggestionUi(Context context) {
+ this.mContext = context;
+ }
+
+ /**
+ * Returns a {@link SurfaceControl} with the inflated content embedded in it.
+ */
+ @MainThread
+ @Nullable
+ public SurfaceControl inflate(@NonNull Dataset dataset, @NonNull AutofillId autofillId,
+ int width, int height, @Nullable View.OnClickListener onClickListener) {
+ Log.d(TAG, "Inflating the inline suggestion UI");
+ final int index = dataset.getFieldIds().indexOf(autofillId);
+ if (index < 0) {
+ Slog.w(TAG, "inflateInlineSuggestion(): AutofillId=" + autofillId
+ + " not found in dataset");
+ return null;
+ }
+ final AutofillValue datasetValue = dataset.getFieldValues().get(index);
+ //TODO(b/137800469): Pass in inputToken from IME.
+ final SurfaceControlViewHost wvr = new SurfaceControlViewHost(mContext,
+ mContext.getDisplay(), (IBinder) null);
+ final SurfaceControl sc = wvr.getSurfacePackage().getSurfaceControl();
+
+ TextView textView = new TextView(mContext);
+ textView.setText(datasetValue.getTextValue());
+ textView.setBackgroundColor(Color.WHITE);
+ textView.setTextColor(Color.BLACK);
+ if (onClickListener != null) {
+ textView.setOnClickListener(onClickListener);
+ }
+
+ WindowManager.LayoutParams lp =
+ new WindowManager.LayoutParams(width, height,
+ WindowManager.LayoutParams.TYPE_APPLICATION, 0, PixelFormat.TRANSPARENT);
+ wvr.addView(textView, lp);
+ return sc;
+ }
+}