1 /* 2 * Copyright (C) 2020 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.example.android.inlinefillservice; 18 19 import android.app.PendingIntent; 20 import android.app.slice.Slice; 21 import android.content.Context; 22 import android.content.Intent; 23 import android.graphics.drawable.Icon; 24 import android.service.autofill.Dataset; 25 import android.service.autofill.FillRequest; 26 import android.service.autofill.InlinePresentation; 27 import android.text.TextUtils; 28 import android.util.ArrayMap; 29 import android.view.autofill.AutofillId; 30 import android.view.inputmethod.InlineSuggestionsRequest; 31 import android.widget.inline.InlinePresentationSpec; 32 33 import androidx.autofill.inline.v1.InlineSuggestionUi; 34 import androidx.autofill.inline.v1.InlineSuggestionUi.Content; 35 36 import java.util.Optional; 37 38 public class InlineRequestHelper { getInlineSuggestionsRequest(FillRequest request)39 static Optional<InlineSuggestionsRequest> getInlineSuggestionsRequest(FillRequest request) { 40 final InlineSuggestionsRequest inlineRequest = request.getInlineSuggestionsRequest(); 41 if (inlineRequest != null && inlineRequest.getMaxSuggestionCount() > 0 42 && !inlineRequest.getInlinePresentationSpecs().isEmpty()) { 43 return Optional.of(inlineRequest); 44 } 45 return Optional.empty(); 46 } 47 getMaxSuggestionCount(Optional<InlineSuggestionsRequest> inlineRequest, int max)48 static int getMaxSuggestionCount(Optional<InlineSuggestionsRequest> inlineRequest, int max) { 49 if (inlineRequest.isPresent()) { 50 return Math.min(max, inlineRequest.get().getMaxSuggestionCount()); 51 } 52 return max; 53 } 54 maybeCreateInlineAuthenticationResponse( Context context, Optional<InlineSuggestionsRequest> inlineRequest)55 static InlinePresentation maybeCreateInlineAuthenticationResponse( 56 Context context, Optional<InlineSuggestionsRequest> inlineRequest) { 57 if (!inlineRequest.isPresent()) { 58 return null; 59 } 60 final PendingIntent attribution = createAttribution(context, 61 "Please tap on the chip to authenticate the Autofill response."); 62 final Slice slice = createSlice("Tap to auth response", null, null, null, attribution); 63 final InlinePresentationSpec spec = inlineRequest.get().getInlinePresentationSpecs().get(0); 64 return new InlinePresentation(slice, spec, false); 65 } 66 createInlineDataset(Context context, InlineSuggestionsRequest inlineRequest, String value, int index)67 static InlinePresentation createInlineDataset(Context context, 68 InlineSuggestionsRequest inlineRequest, String value, int index) { 69 final PendingIntent attribution = createAttribution(context, 70 "Please tap on the chip to autofill the value:" + value); 71 final Slice slice = createSlice(value, null, null, null, attribution); 72 index = Math.min(inlineRequest.getInlinePresentationSpecs().size() - 1, index); 73 final InlinePresentationSpec spec = inlineRequest.getInlinePresentationSpecs().get(index); 74 return new InlinePresentation(slice, spec, false); 75 } 76 createInlineActionDataset(Context context, ArrayMap<String, AutofillId> fields, InlineSuggestionsRequest inlineRequest, int drawable)77 static Dataset createInlineActionDataset(Context context, 78 ArrayMap<String, AutofillId> fields, 79 InlineSuggestionsRequest inlineRequest, int drawable) { 80 PendingIntent pendingIntent = 81 PendingIntent.getActivity(context, 0, new Intent(context, SettingsActivity.class), 82 PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE); 83 84 Dataset.Builder builder = 85 new Dataset.Builder() 86 .setInlinePresentation(createInlineAction(context, inlineRequest, drawable)) 87 .setAuthentication(pendingIntent.getIntentSender()); 88 for (AutofillId fieldId : fields.values()) { 89 builder.setValue(fieldId, null); 90 } 91 return builder.build(); 92 } 93 createInlineAction(Context context, InlineSuggestionsRequest inlineRequest, int drawable)94 private static InlinePresentation createInlineAction(Context context, 95 InlineSuggestionsRequest inlineRequest, int drawable) { 96 final PendingIntent attribution = createAttribution(context, 97 "Please tap on the chip to launch the action."); 98 final Icon icon = Icon.createWithResource(context, drawable); 99 final Slice slice = createSlice(null, null, icon, null, attribution); 100 // Reuse the first spec's height for the inline action size, as there isn't dedicated 101 // value from the request for this. 102 final InlinePresentationSpec spec = inlineRequest.getInlinePresentationSpecs().get(0); 103 return new InlinePresentation(slice, spec, true); 104 } 105 createSlice( String title, String subtitle, Icon startIcon, Icon endIcon, PendingIntent attribution)106 private static Slice createSlice( 107 String title, String subtitle, Icon startIcon, Icon endIcon, 108 PendingIntent attribution) { 109 Content.Builder builder = InlineSuggestionUi.newContentBuilder(attribution); 110 if (!TextUtils.isEmpty(title)) { 111 builder.setTitle(title); 112 } 113 if (!TextUtils.isEmpty(subtitle)) { 114 builder.setSubtitle(subtitle); 115 } 116 if (startIcon != null) { 117 builder.setStartIcon(startIcon); 118 } 119 if (endIcon != null) { 120 builder.setEndIcon(endIcon); 121 } 122 return builder.build().getSlice(); 123 } 124 createAttribution(Context context, String msg)125 private static PendingIntent createAttribution(Context context, String msg) { 126 Intent intent = new Intent(context, AttributionDialogActivity.class); 127 intent.putExtra(AttributionDialogActivity.KEY_MSG, msg); 128 // Should use different request code to avoid the new intent overriding the old one. 129 PendingIntent pendingIntent = PendingIntent.getActivity(context, msg.hashCode(), intent, 130 PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE); 131 return pendingIntent; 132 } 133 134 } 135