Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e796b879 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Fix on click listener for the inline suggestion, and some refactoring."

parents 55e4896d 58531839
Loading
Loading
Loading
Loading
+83 −37
Original line number Diff line number Diff line
@@ -20,23 +20,24 @@ import static com.android.server.autofill.Helper.sDebug;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.slice.Slice;
import android.content.Context;
import android.os.Handler;
import android.os.RemoteException;
import android.service.autofill.Dataset;
import android.service.autofill.InlinePresentation;
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.UiThread;
import com.android.server.autofill.ui.AutoFillUI;
import com.android.server.autofill.ui.InlineSuggestionUi;

import java.util.ArrayList;
@@ -56,23 +57,59 @@ public final class InlineSuggestionFactory {
            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");
        if (sDebug) Slog.d(TAG, "createAugmentedInlineSuggestionsResponse 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;
            final int fieldIndex = dataset.getFieldIds().indexOf(autofillId);
            if (fieldIndex < 0) {
                Slog.w(TAG, "AutofillId=" + autofillId + " not found in dataset");
                return null;
            }
            final InlinePresentation inlinePresentation = dataset.getFieldInlinePresentation(
                    fieldIndex);
            if (inlinePresentation == null) {
                Slog.w(TAG, "InlinePresentation not found in dataset");
                return null;
            }
            InlineSuggestion inlineSuggestion = createAugmentedInlineSuggestion(sessionId, dataset,
                    autofillId, spec, uiHandler, inlineSuggestionUi, client);
                    inlinePresentation, inlineSuggestionUi, client);
            inlineSuggestions.add(inlineSuggestion);
        }
        return new InlineSuggestionsResponse(inlineSuggestions);
    }

    /**
     * Creates an {@link InlineSuggestionsResponse} with the {@code datasets} provided by the
     * autofill service.
     */
    public static InlineSuggestionsResponse createInlineSuggestionsResponse(int requestId,
            @NonNull Dataset[] datasets,
            @NonNull AutofillId autofillId,
            @NonNull Context context,
            @NonNull AutoFillUI.AutoFillUiCallback client) {
        if (sDebug) Slog.d(TAG, "createInlineSuggestionsResponse called");

        final ArrayList<InlineSuggestion> inlineSuggestions = new ArrayList<>();
        final InlineSuggestionUi inlineSuggestionUi = new InlineSuggestionUi(context);
        for (Dataset dataset : datasets) {
            final int fieldIndex = dataset.getFieldIds().indexOf(autofillId);
            if (fieldIndex < 0) {
                Slog.w(TAG, "AutofillId=" + autofillId + " not found in dataset");
                return null;
            }
            final InlinePresentation inlinePresentation = dataset.getFieldInlinePresentation(
                    fieldIndex);
            if (inlinePresentation == null) {
                Slog.w(TAG, "InlinePresentation not found in dataset");
                return null;
            }
            InlineSuggestion inlineSuggestion = createInlineSuggestion(requestId, dataset,
                    fieldIndex,
                    inlinePresentation, inlineSuggestionUi, client);
            inlineSuggestions.add(inlineSuggestion);
        }
        return new InlineSuggestionsResponse(inlineSuggestions);
@@ -80,33 +117,55 @@ public final class InlineSuggestionFactory {

    private static InlineSuggestion createAugmentedInlineSuggestion(int sessionId,
            @NonNull Dataset dataset,
            @NonNull AutofillId autofillId,
            @NonNull InlinePresentationSpec spec,
            @NonNull Handler uiHandler,
            @NonNull InlinePresentation inlinePresentation,
            @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);
                inlinePresentation.getInlinePresentationSpec(),
                InlineSuggestionInfo.SOURCE_PLATFORM, new String[]{""});
        final View.OnClickListener onClickListener = v -> {
            try {
                client.autofill(sessionId, dataset.getFieldIds(), dataset.getFieldValues());
            } catch (RemoteException e) {
                Slog.w(TAG, "Encounter exception autofilling the values");
            }
        };
        final InlineSuggestion inlineSuggestion = new InlineSuggestion(inlineSuggestionInfo,
                createInlineContentProvider(autofillId, dataset, uiHandler, inlineSuggestionUi,
                createInlineContentProvider(inlinePresentation.getSlice(), inlineSuggestionUi,
                        onClickListener));
        return inlineSuggestion;
    }

    private static IInlineContentProvider.Stub createInlineContentProvider(
            @NonNull AutofillId autofillId, @NonNull Dataset dataset, @NonNull Handler uiHandler,
    private static InlineSuggestion createInlineSuggestion(int requestId,
            @NonNull Dataset dataset,
            int fieldIndex,
            @NonNull InlinePresentation inlinePresentation,
            @NonNull InlineSuggestionUi inlineSuggestionUi,
            @NonNull AutoFillUI.AutoFillUiCallback client) {
        // TODO(b/146453195): fill in the autofill hint properly.
        final InlineSuggestionInfo inlineSuggestionInfo = new InlineSuggestionInfo(
                inlinePresentation.getInlinePresentationSpec(),
                InlineSuggestionInfo.SOURCE_AUTOFILL, new String[]{""});
        final View.OnClickListener onClickListener = v -> {
            client.fill(requestId, fieldIndex, dataset);
        };
        final InlineSuggestion inlineSuggestion = new InlineSuggestion(inlineSuggestionInfo,
                createInlineContentProvider(inlinePresentation.getSlice(), inlineSuggestionUi,
                        onClickListener));
        return inlineSuggestion;
    }

    private static IInlineContentProvider.Stub createInlineContentProvider(
            @NonNull Slice slice, @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);
                UiThread.getHandler().post(() -> {
                    SurfaceControl sc = inlineSuggestionUi.inflate(slice, width, height,
                            onClickListener);
                    try {
                        callback.onContent(sc);
                    } catch (RemoteException e) {
@@ -117,19 +176,6 @@ public final class InlineSuggestionFactory {
        };
    }

    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() {
    }
}
+4 −9
Original line number Diff line number Diff line
@@ -161,8 +161,7 @@ final class RemoteAugmentedAutofillService
                                @Override
                                public void onSuccess(@Nullable Dataset[] inlineSuggestionsData) {
                                    maybeHandleInlineSuggestions(sessionId, inlineSuggestionsData,
                                            focusedId, inlineSuggestionsRequest,
                                            inlineSuggestionsCallback, client);
                                            focusedId, inlineSuggestionsCallback, client);
                                    requestAutofill.complete(null);
                                }

@@ -226,19 +225,15 @@ final class RemoteAugmentedAutofillService

    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) {
        if (ArrayUtils.isEmpty(inlineSuggestionsData) || inlineSuggestionsCallback == null) {
            return;
        }
        try {
            inlineSuggestionsCallback.onInlineSuggestionsResponse(
                    InlineSuggestionFactory.createAugmentedInlineSuggestionsResponse(
                            sessionId, inlineSuggestionsData, focusedId, inlineSuggestionsRequest,
                            getJobHandler(), mContext, client));
                    InlineSuggestionFactory.createAugmentedInlineSuggestionsResponse(sessionId,
                            inlineSuggestionsData, focusedId, mContext, client));
        } catch (RemoteException e) {
            Slog.w(TAG, "Exception sending inline suggestions response back to IME.");
        }
+6 −34
Original line number Diff line number Diff line
@@ -71,7 +71,6 @@ import android.service.autofill.FieldClassificationUserData;
import android.service.autofill.FillContext;
import android.service.autofill.FillRequest;
import android.service.autofill.FillResponse;
import android.service.autofill.InlinePresentation;
import android.service.autofill.InternalSanitizer;
import android.service.autofill.InternalValidator;
import android.service.autofill.SaveInfo;
@@ -93,9 +92,6 @@ import android.view.autofill.AutofillManager.SmartSuggestionMode;
import android.view.autofill.AutofillValue;
import android.view.autofill.IAutoFillManagerClient;
import android.view.autofill.IAutofillWindowPresenter;
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;

@@ -106,8 +102,6 @@ import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.util.ArrayUtils;
import com.android.internal.view.IInlineSuggestionsRequestCallback;
import com.android.internal.view.IInlineSuggestionsResponseCallback;
import com.android.internal.view.inline.IInlineContentCallback;
import com.android.internal.view.inline.IInlineContentProvider;
import com.android.server.autofill.ui.AutoFillUI;
import com.android.server.autofill.ui.PendingUi;
import com.android.server.inputmethod.InputMethodManagerInternal;
@@ -148,6 +142,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
    private final Handler mHandler;
    private final Object mLock;
    private final AutoFillUI mUi;
    private final Context mContext;

    private final MetricsLogger mMetricsLogger = new MetricsLogger();

@@ -773,6 +768,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
        mLock = lock;
        mUi = ui;
        mHandler = handler;
        mContext = context;
        mRemoteFillService = serviceComponentName == null ? null
                : new RemoteFillService(context, serviceComponentName, userId, this,
                        bindInstantServiceAllowed);
@@ -2733,35 +2729,11 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
            return false;
        }

        final int size = datasets.size();
        final ArrayList<InlineSuggestion> inlineSuggestions = new ArrayList<>();

        for (int index = 0; index < size; index++) {
            final Dataset dataset = datasets.get(index);
            //TODO(b/146453536): Use the proper presentation/spec for currently focused view.
            final InlinePresentation inlinePresentation = dataset.getFieldInlinePresentation(0);
            if (inlinePresentation == null) {
                if (sDebug) Log.d(TAG, "Missing InlinePresentation on dataset=" + dataset);
                continue;
            }
            final InlinePresentationSpec spec = inlinePresentation.getInlinePresentationSpec();
            final InlineSuggestionInfo inlineSuggestionInfo = new InlineSuggestionInfo(
                    spec, InlineSuggestionInfo.SOURCE_AUTOFILL, new String[] { "" });

            inlineSuggestions.add(new InlineSuggestion(inlineSuggestionInfo,
                    new IInlineContentProvider.Stub() {
                        @Override
                        public void provideContent(int width, int height,
                                IInlineContentCallback callback) throws RemoteException {
                            getUiForShowing().getSuggestionSurfaceForShowing(dataset, response,
                                    mCurrentViewId, width, height, callback);
                        }
                    }));
        }

        InlineSuggestionsResponse inlineSuggestionsResponse =
                InlineSuggestionFactory.createInlineSuggestionsResponse(response.getRequestId(),
                        datasets.toArray(new Dataset[]{}), mCurrentViewId, mContext, this);
        try  {
            inlineContentCallback.onInlineSuggestionsResponse(
                    new InlineSuggestionsResponse(inlineSuggestions));
            inlineContentCallback.onInlineSuggestionsResponse(inlineSuggestionsResponse);
        } catch (RemoteException e) {
            Log.w(TAG, "onFillReady() remote error calling onInlineSuggestionsResponse()");
            return false;
+0 −32
Original line number Diff line number Diff line
@@ -37,7 +37,6 @@ import android.service.autofill.ValueFinder;
import android.text.TextUtils;
import android.util.Slog;
import android.view.KeyEvent;
import android.view.SurfaceControl;
import android.view.autofill.AutofillId;
import android.view.autofill.AutofillManager;
import android.view.autofill.IAutofillWindowPresenter;
@@ -45,7 +44,6 @@ import android.widget.Toast;

import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.view.inline.IInlineContentCallback;
import com.android.server.LocalServices;
import com.android.server.UiModeManagerInternal;
import com.android.server.UiThread;
@@ -172,36 +170,6 @@ public final class AutoFillUI {
        });
    }

    /**
     * TODO(b/137800469): Fill in javadoc.
     * TODO(b/137800469): peoperly manage lifecycle of suggestions surfaces.
     */
    public void getSuggestionSurfaceForShowing(@NonNull Dataset dataset,
            @NonNull FillResponse response, AutofillId autofillId, int width, int height,
            IInlineContentCallback cb) {
        if (dataset == null) {
            Slog.w(TAG, "getSuggestionSurfaceForShowing() called with null dataset");
        }
        mHandler.post(() -> {
            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);
            } catch (RemoteException e) {
                Slog.w(TAG, "RemoteException replying onContent(" + suggestionSurface + "): " + e);
            }
        });
    }

    /**
     * Shows the fill UI, removing the previous fill UI if the has changed.
     *
+7 −16
Original line number Diff line number Diff line
@@ -28,17 +28,13 @@ import android.content.Context;
import android.graphics.PixelFormat;
import android.graphics.drawable.Icon;
import android.os.IBinder;
import android.service.autofill.Dataset;
import android.util.Log;
import android.util.Slog;
import android.view.LayoutInflater;
import android.view.SurfaceControl;
import android.view.SurfaceControlViewHost;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.autofill.AutofillId;
import android.view.autofill.AutofillValue;
import android.widget.ImageView;
import android.widget.TextView;

@@ -69,23 +65,18 @@ public class InlineSuggestionUi {
     */
    @MainThread
    @Nullable
    public SurfaceControl inflate(@NonNull Dataset dataset, @NonNull AutofillId autofillId,
            int width, int height, @Nullable View.OnClickListener onClickListener) {
    public SurfaceControl inflate(@NonNull Slice slice, 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();

        final ViewGroup suggestionView =
                (ViewGroup) renderSlice(dataset.getFieldInlinePresentation(index).getSlice());
        final ViewGroup suggestionView = (ViewGroup) renderSlice(slice);
        if (onClickListener != null) {
            suggestionView.setOnClickListener(onClickListener);
        }

        WindowManager.LayoutParams lp =
                new WindowManager.LayoutParams(width, height,