All Downloads are FREE. Search and download functionalities are using the official Maven repository.

src.com.android.server.autofill.ui.InlineSuggestionFactory Maven / Gradle / Ivy

/*
 * 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.ui;

import static android.view.inputmethod.InlineSuggestionInfo.TYPE_SUGGESTION;

import static com.android.server.autofill.Helper.sDebug;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.IntentSender;
import android.service.autofill.Dataset;
import android.service.autofill.FillResponse;
import android.service.autofill.InlinePresentation;
import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
import android.view.autofill.AutofillManager;
import android.view.inputmethod.InlineSuggestion;
import android.view.inputmethod.InlineSuggestionInfo;
import android.view.inputmethod.InlineSuggestionsRequest;
import android.widget.inline.InlinePresentationSpec;

import com.android.internal.view.inline.IInlineContentProvider;

import java.util.List;

final class InlineSuggestionFactory {
    private static final String TAG = "InlineSuggestionFactory";

    public static InlineSuggestion createInlineAuthentication(
            @NonNull InlineFillUi.InlineFillUiInfo inlineFillUiInfo, @NonNull FillResponse response,
            @NonNull InlineFillUi.InlineSuggestionUiCallback uiCallback) {
        InlinePresentation inlineAuthentication = response.getInlinePresentation();
        final int requestId = response.getRequestId();

        return createInlineSuggestion(inlineFillUiInfo, InlineSuggestionInfo.SOURCE_AUTOFILL,
                InlineSuggestionInfo.TYPE_ACTION, () -> uiCallback.authenticate(requestId,
                        AutofillManager.AUTHENTICATION_ID_DATASET_ID_UNDEFINED),
                mergedInlinePresentation(inlineFillUiInfo.mInlineRequest, 0, inlineAuthentication),
                createInlineSuggestionTooltip(inlineFillUiInfo.mInlineRequest,
                        inlineFillUiInfo, InlineSuggestionInfo.SOURCE_AUTOFILL,
                        response.getInlineTooltipPresentation()),
                uiCallback);
    }

    /**
     * Creates an array of {@link InlineSuggestion}s with the {@code datasets} provided by either
     * regular/augmented autofill services.
     */
    @Nullable
    public static SparseArray> createInlineSuggestions(
            @NonNull InlineFillUi.InlineFillUiInfo inlineFillUiInfo,
            @NonNull @InlineSuggestionInfo.Source String suggestionSource,
            @NonNull List datasets,
            @NonNull InlineFillUi.InlineSuggestionUiCallback uiCallback) {
        if (sDebug) Slog.d(TAG, "createInlineSuggestions(source=" + suggestionSource + ") called");

        final InlineSuggestionsRequest request = inlineFillUiInfo.mInlineRequest;
        SparseArray> response = new SparseArray<>(datasets.size());

        boolean hasTooltip = false;
        for (int datasetIndex = 0; datasetIndex < datasets.size(); datasetIndex++) {
            final Dataset dataset = datasets.get(datasetIndex);
            final int fieldIndex = dataset.getFieldIds().indexOf(inlineFillUiInfo.mFocusedId);
            if (fieldIndex < 0) {
                Slog.w(TAG, "AutofillId=" + inlineFillUiInfo.mFocusedId + " not found in dataset");
                continue;
            }

            final InlinePresentation inlinePresentation =
                    dataset.getFieldInlinePresentation(fieldIndex);
            if (inlinePresentation == null) {
                Slog.w(TAG, "InlinePresentation not found in dataset");
                continue;
            }

            final String suggestionType =
                    dataset.getAuthentication() == null ? TYPE_SUGGESTION
                            : InlineSuggestionInfo.TYPE_ACTION;
            final int index = datasetIndex;

            InlineSuggestion inlineSuggestionTooltip = null;
            if (!hasTooltip) {
                // Only available for first one inline suggestion tooltip.
                inlineSuggestionTooltip = createInlineSuggestionTooltip(request,
                        inlineFillUiInfo, suggestionSource,
                        dataset.getFieldInlineTooltipPresentation(fieldIndex));
                if (inlineSuggestionTooltip != null) {
                    hasTooltip = true;
                }
            }
            InlineSuggestion inlineSuggestion = createInlineSuggestion(
                    inlineFillUiInfo, suggestionSource, suggestionType,
                    () -> uiCallback.autofill(dataset, index),
                    mergedInlinePresentation(request, datasetIndex, inlinePresentation),
                    inlineSuggestionTooltip,
                    uiCallback);
            response.append(datasetIndex, Pair.create(dataset, inlineSuggestion));
        }

        return response;
    }

    private static InlineSuggestion createInlineSuggestion(
            @NonNull InlineFillUi.InlineFillUiInfo inlineFillUiInfo,
            @NonNull @InlineSuggestionInfo.Source String suggestionSource,
            @NonNull @InlineSuggestionInfo.Type String suggestionType,
            @NonNull Runnable onClickAction,
            @NonNull InlinePresentation inlinePresentation,
            @Nullable InlineSuggestion tooltip,
            @NonNull InlineFillUi.InlineSuggestionUiCallback uiCallback) {

        final InlineSuggestionInfo inlineSuggestionInfo = new InlineSuggestionInfo(
                inlinePresentation.getInlinePresentationSpec(), suggestionSource,
                inlinePresentation.getAutofillHints(), suggestionType,
                inlinePresentation.isPinned(), tooltip);

        return new InlineSuggestion(inlineSuggestionInfo,
                createInlineContentProvider(inlineFillUiInfo, inlinePresentation,
                        onClickAction, uiCallback));
    }

    /**
     * Returns an {@link InlinePresentation} with the style spec from the request/host, and
     * everything else from the provided {@code inlinePresentation}.
     */
    private static InlinePresentation mergedInlinePresentation(
            @NonNull InlineSuggestionsRequest request,
            int index, @NonNull InlinePresentation inlinePresentation) {
        final List specs = request.getInlinePresentationSpecs();
        if (specs.isEmpty()) {
            return inlinePresentation;
        }
        InlinePresentationSpec specFromHost = specs.get(Math.min(specs.size() - 1, index));
        InlinePresentationSpec mergedInlinePresentation = new InlinePresentationSpec.Builder(
                inlinePresentation.getInlinePresentationSpec().getMinSize(),
                inlinePresentation.getInlinePresentationSpec().getMaxSize()).setStyle(
                specFromHost.getStyle()).build();

        return new InlinePresentation(inlinePresentation.getSlice(), mergedInlinePresentation,
                inlinePresentation.isPinned());
    }

    // TODO(182306770): creates new class instead of the InlineSuggestion.
    private static InlineSuggestion createInlineSuggestionTooltip(
            @NonNull InlineSuggestionsRequest request,
            @NonNull InlineFillUi.InlineFillUiInfo inlineFillUiInfo,
            String suggestionSource,
            @NonNull InlinePresentation tooltipPresentation) {
        if (tooltipPresentation == null) {
            return null;
        }

        final InlinePresentationSpec spec = request.getInlineTooltipPresentationSpec();
        InlinePresentationSpec mergedSpec;
        if (spec == null) {
            mergedSpec = tooltipPresentation.getInlinePresentationSpec();
        } else {
            mergedSpec = new InlinePresentationSpec.Builder(
                    tooltipPresentation.getInlinePresentationSpec().getMinSize(),
                    tooltipPresentation.getInlinePresentationSpec().getMaxSize()).setStyle(
                    spec.getStyle()).build();
        }

        InlineFillUi.InlineSuggestionUiCallback uiCallback =
                new InlineFillUi.InlineSuggestionUiCallback() {
                    @Override
                    public void autofill(Dataset dataset, int datasetIndex) {
                        /* nothing */
                    }

                    @Override
                    public void authenticate(int requestId, int datasetIndex) {
                        /* nothing */
                    }

                    @Override
                    public void startIntentSender(IntentSender intentSender) {
                        /* nothing */
                    }

                    @Override
                    public void onError() {
                        Slog.w(TAG, "An error happened on the tooltip");
                    }
                };

        InlinePresentation tooltipInline = new InlinePresentation(tooltipPresentation.getSlice(),
                mergedSpec, false);
        IInlineContentProvider tooltipContentProvider = createInlineContentProvider(
                inlineFillUiInfo, tooltipInline, () -> { /* no operation */ }, uiCallback);
        final InlineSuggestionInfo tooltipInlineSuggestionInfo = new InlineSuggestionInfo(
                mergedSpec, suggestionSource, /* autofillHints */ null, TYPE_SUGGESTION,
                        /* pinned */ false, /* tooltip */ null);
        return new InlineSuggestion(tooltipInlineSuggestionInfo, tooltipContentProvider);
    }

    private static IInlineContentProvider createInlineContentProvider(
            @NonNull InlineFillUi.InlineFillUiInfo inlineFillUiInfo,
            @NonNull InlinePresentation inlinePresentation, @Nullable Runnable onClickAction,
            @NonNull InlineFillUi.InlineSuggestionUiCallback uiCallback) {
        RemoteInlineSuggestionViewConnector remoteInlineSuggestionViewConnector =
                new RemoteInlineSuggestionViewConnector(inlineFillUiInfo, inlinePresentation,
                        onClickAction, uiCallback);

        return new InlineContentProviderImpl(remoteInlineSuggestionViewConnector, null);
    }

    private InlineSuggestionFactory() {
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy