| /* |
| * 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.example.android.inlinefillservice; |
| |
| import android.app.PendingIntent; |
| import android.app.slice.Slice; |
| import android.content.Context; |
| import android.content.Intent; |
| import android.graphics.drawable.Icon; |
| import android.service.autofill.Dataset; |
| import android.service.autofill.FillRequest; |
| import android.service.autofill.InlinePresentation; |
| import android.text.TextUtils; |
| import android.util.ArrayMap; |
| import android.view.autofill.AutofillId; |
| import android.view.inputmethod.InlineSuggestionsRequest; |
| import android.widget.inline.InlinePresentationSpec; |
| |
| import androidx.autofill.inline.v1.InlineSuggestionUi; |
| import androidx.autofill.inline.v1.InlineSuggestionUi.Content; |
| |
| import java.util.Optional; |
| |
| public class InlineRequestHelper { |
| static Optional<InlineSuggestionsRequest> getInlineSuggestionsRequest(FillRequest request) { |
| final InlineSuggestionsRequest inlineRequest = request.getInlineSuggestionsRequest(); |
| if (inlineRequest != null && inlineRequest.getMaxSuggestionCount() > 0 |
| && !inlineRequest.getInlinePresentationSpecs().isEmpty()) { |
| return Optional.of(inlineRequest); |
| } |
| return Optional.empty(); |
| } |
| |
| static int getMaxSuggestionCount(Optional<InlineSuggestionsRequest> inlineRequest, int max) { |
| if (inlineRequest.isPresent()) { |
| return Math.min(max, inlineRequest.get().getMaxSuggestionCount()); |
| } |
| return max; |
| } |
| |
| static InlinePresentation maybeCreateInlineAuthenticationResponse( |
| Context context, Optional<InlineSuggestionsRequest> inlineRequest) { |
| if (!inlineRequest.isPresent()) { |
| return null; |
| } |
| final PendingIntent attribution = createAttribution(context, |
| "Please tap on the chip to authenticate the Autofill response."); |
| final Slice slice = createSlice("Tap to auth response", null, null, null, attribution); |
| final InlinePresentationSpec spec = inlineRequest.get().getInlinePresentationSpecs().get(0); |
| return new InlinePresentation(slice, spec, false); |
| } |
| |
| static InlinePresentation createInlineDataset(Context context, |
| InlineSuggestionsRequest inlineRequest, String value, int index) { |
| final PendingIntent attribution = createAttribution(context, |
| "Please tap on the chip to autofill the value:" + value); |
| final Slice slice = createSlice(value, null, null, null, attribution); |
| index = Math.min(inlineRequest.getInlinePresentationSpecs().size() - 1, index); |
| final InlinePresentationSpec spec = inlineRequest.getInlinePresentationSpecs().get(index); |
| return new InlinePresentation(slice, spec, false); |
| } |
| |
| static Dataset createInlineActionDataset(Context context, |
| ArrayMap<String, AutofillId> fields, |
| InlineSuggestionsRequest inlineRequest, int drawable) { |
| PendingIntent pendingIntent = |
| PendingIntent.getActivity(context, 0, new Intent(context, SettingsActivity.class), |
| PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE); |
| |
| Dataset.Builder builder = |
| new Dataset.Builder() |
| .setInlinePresentation(createInlineAction(context, inlineRequest, drawable)) |
| .setAuthentication(pendingIntent.getIntentSender()); |
| for (AutofillId fieldId : fields.values()) { |
| builder.setValue(fieldId, null); |
| } |
| return builder.build(); |
| } |
| |
| private static InlinePresentation createInlineAction(Context context, |
| InlineSuggestionsRequest inlineRequest, int drawable) { |
| final PendingIntent attribution = createAttribution(context, |
| "Please tap on the chip to launch the action."); |
| final Icon icon = Icon.createWithResource(context, drawable); |
| final Slice slice = createSlice(null, null, icon, null, attribution); |
| // Reuse the first spec's height for the inline action size, as there isn't dedicated |
| // value from the request for this. |
| final InlinePresentationSpec spec = inlineRequest.getInlinePresentationSpecs().get(0); |
| return new InlinePresentation(slice, spec, true); |
| } |
| |
| private static Slice createSlice( |
| String title, String subtitle, Icon startIcon, Icon endIcon, |
| PendingIntent attribution) { |
| Content.Builder builder = InlineSuggestionUi.newContentBuilder(attribution); |
| if (!TextUtils.isEmpty(title)) { |
| builder.setTitle(title); |
| } |
| if (!TextUtils.isEmpty(subtitle)) { |
| builder.setSubtitle(subtitle); |
| } |
| if (startIcon != null) { |
| builder.setStartIcon(startIcon); |
| } |
| if (endIcon != null) { |
| builder.setEndIcon(endIcon); |
| } |
| return builder.build().getSlice(); |
| } |
| |
| private static PendingIntent createAttribution(Context context, String msg) { |
| Intent intent = new Intent(context, AttributionDialogActivity.class); |
| intent.putExtra(AttributionDialogActivity.KEY_MSG, msg); |
| // Should use different request code to avoid the new intent overriding the old one. |
| PendingIntent pendingIntent = PendingIntent.getActivity(context, msg.hashCode(), intent, |
| PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE); |
| return pendingIntent; |
| } |
| |
| } |