Loading core/java/android/service/autofill/augmented/AugmentedAutofillService.java +16 −5 Original line number Diff line number Diff line Loading @@ -38,6 +38,7 @@ import android.os.ICancellationSignal; 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; Loading @@ -47,6 +48,7 @@ import android.view.autofill.AutofillManager; 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; Loading Loading @@ -106,10 +108,11 @@ public abstract class AugmentedAutofillService extends Service { @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 Loading Loading @@ -212,6 +215,7 @@ public abstract class AugmentedAutofillService extends Service { 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<>(); Loading @@ -236,9 +240,8 @@ public abstract class AugmentedAutofillService extends Service { } 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() { Loading Loading @@ -484,6 +487,14 @@ public abstract class AugmentedAutofillService extends Service { } } 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); Loading core/java/android/service/autofill/augmented/FillCallback.java +10 −1 Original line number Diff line number Diff line Loading @@ -21,9 +21,12 @@ import android.annotation.NonNull; 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. * Loading Loading @@ -55,6 +58,12 @@ public final class FillCallback { 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(); Loading core/java/android/service/autofill/augmented/IAugmentedAutofillService.aidl +4 −1 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import android.os.IBinder; 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; Loading @@ -35,7 +36,9 @@ oneway interface IAugmentedAutofillService { 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(); } core/java/com/android/internal/infra/ServiceConnector.java +1 −1 Original line number Diff line number Diff line Loading @@ -223,7 +223,7 @@ public interface ServiceConnector<I extends IInterface> { 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; Loading services/autofill/java/com/android/server/autofill/InlineSuggestionFactory.java 0 → 100644 +135 −0 Original line number Diff line number Diff line /* * 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() { } } Loading
core/java/android/service/autofill/augmented/AugmentedAutofillService.java +16 −5 Original line number Diff line number Diff line Loading @@ -38,6 +38,7 @@ import android.os.ICancellationSignal; 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; Loading @@ -47,6 +48,7 @@ import android.view.autofill.AutofillManager; 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; Loading Loading @@ -106,10 +108,11 @@ public abstract class AugmentedAutofillService extends Service { @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 Loading Loading @@ -212,6 +215,7 @@ public abstract class AugmentedAutofillService extends Service { 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<>(); Loading @@ -236,9 +240,8 @@ public abstract class AugmentedAutofillService extends Service { } 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() { Loading Loading @@ -484,6 +487,14 @@ public abstract class AugmentedAutofillService extends Service { } } 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); Loading
core/java/android/service/autofill/augmented/FillCallback.java +10 −1 Original line number Diff line number Diff line Loading @@ -21,9 +21,12 @@ import android.annotation.NonNull; 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. * Loading Loading @@ -55,6 +58,12 @@ public final class FillCallback { 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(); Loading
core/java/android/service/autofill/augmented/IAugmentedAutofillService.aidl +4 −1 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import android.os.IBinder; 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; Loading @@ -35,7 +36,9 @@ oneway interface IAugmentedAutofillService { 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(); }
core/java/com/android/internal/infra/ServiceConnector.java +1 −1 Original line number Diff line number Diff line Loading @@ -223,7 +223,7 @@ public interface ServiceConnector<I extends IInterface> { 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; Loading
services/autofill/java/com/android/server/autofill/InlineSuggestionFactory.java 0 → 100644 +135 −0 Original line number Diff line number Diff line /* * 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() { } }