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 static com.example.android.inlinefillservice.InlineFillService.TAG; 20 21 import android.content.Context; 22 import android.content.IntentSender; 23 import android.service.autofill.Dataset; 24 import android.service.autofill.Field; 25 import android.service.autofill.InlinePresentation; 26 import android.service.autofill.Presentations; 27 import android.util.Log; 28 import android.view.autofill.AutofillId; 29 import android.view.autofill.AutofillValue; 30 import android.view.inputmethod.InlineSuggestionsRequest; 31 import android.widget.RemoteViews; 32 33 import androidx.annotation.NonNull; 34 35 import java.util.Map; 36 import java.util.Optional; 37 38 class ResponseHelper { 39 newUnlockedDataset(@onNull Context context, @NonNull Map<String, AutofillId> fields, @NonNull String packageName, int index, @NonNull Optional<InlineSuggestionsRequest> inlineRequest)40 static Dataset newUnlockedDataset(@NonNull Context context, 41 @NonNull Map<String, AutofillId> fields, @NonNull String packageName, int index, 42 @NonNull Optional<InlineSuggestionsRequest> inlineRequest) { 43 44 Dataset.Builder dataset = new Dataset.Builder(); 45 for (Map.Entry<String, AutofillId> field : fields.entrySet()) { 46 final String hint = field.getKey(); 47 final AutofillId id = field.getValue(); 48 final String value = hint + (index + 1); 49 50 // We're simple - our dataset values are hardcoded as "hintN" (for example, 51 // "username1", "username2") and they're displayed as such, except if they're a 52 // password 53 Log.d(TAG, "hint: " + hint); 54 final String displayValue = hint.contains("password") ? "password for #" + (index + 1) 55 : value; 56 // Add Inline Suggestion required info. 57 Field.Builder fieldBuilder = new Field.Builder(); 58 fieldBuilder.setValue(AutofillValue.forText(value)); 59 // Set presentation 60 final Presentations.Builder fieldPresentationsBuilder = 61 new Presentations.Builder(); 62 // Dropdown presentation 63 final RemoteViews presentation = newDatasetPresentation(packageName, displayValue); 64 fieldPresentationsBuilder.setMenuPresentation(presentation); 65 // Inline presentation 66 if (inlineRequest.isPresent()) { 67 Log.d(TAG, "Found InlineSuggestionsRequest in FillRequest: " + inlineRequest); 68 final InlinePresentation inlinePresentation = 69 InlineRequestHelper.createInlineDataset(context, inlineRequest.get(), 70 displayValue, index); 71 fieldPresentationsBuilder.setInlinePresentation(inlinePresentation); 72 } 73 // Dialog presentation 74 RemoteViews dialogPresentation = 75 newDatasetPresentation(packageName, "Dialog Presentation " + (index + 1)); 76 fieldPresentationsBuilder.setDialogPresentation(dialogPresentation); 77 78 fieldBuilder.setPresentations(fieldPresentationsBuilder.build()); 79 dataset.setField(id, fieldBuilder.build()); 80 } 81 return dataset.build(); 82 } 83 newLockedDataset(@onNull Context context, @NonNull Map<String, AutofillId> fields, @NonNull String packageName, int index, @NonNull Optional<InlineSuggestionsRequest> inlineRequest)84 static Dataset newLockedDataset(@NonNull Context context, 85 @NonNull Map<String, AutofillId> fields, @NonNull String packageName, int index, 86 @NonNull Optional<InlineSuggestionsRequest> inlineRequest) { 87 Dataset unlockedDataset = ResponseHelper.newUnlockedDataset(context, fields, 88 packageName, index, inlineRequest); 89 90 Dataset.Builder lockedDataset = new Dataset.Builder(); 91 for (Map.Entry<String, AutofillId> field : fields.entrySet()) { 92 String hint = field.getKey(); 93 AutofillId id = field.getValue(); 94 String value = (index + 1) + "-" + hint; 95 String displayValue = "Tap to auth " + value; 96 IntentSender authentication = 97 AuthActivity.newIntentSenderForDataset(context, unlockedDataset); 98 RemoteViews presentation = newDatasetPresentation(packageName, displayValue); 99 100 Field.Builder fieldBuilder = new Field.Builder(); 101 fieldBuilder.setValue(AutofillValue.forText(value)); 102 // Dropdown presentation 103 final Presentations.Builder fieldPresentationsBuilder = 104 new Presentations.Builder(); 105 fieldPresentationsBuilder.setMenuPresentation(presentation); 106 // Inline presentation 107 if (inlineRequest.isPresent()) { 108 final InlinePresentation inlinePresentation = 109 InlineRequestHelper.createInlineDataset(context, inlineRequest.get(), 110 displayValue, index); 111 fieldPresentationsBuilder.setInlinePresentation(inlinePresentation); 112 } 113 // Dialog presentation 114 RemoteViews dialogPresentation = 115 newDatasetPresentation(packageName, "Dialog Presentation " + (index + 1)); 116 fieldPresentationsBuilder.setDialogPresentation(dialogPresentation); 117 118 fieldBuilder.setPresentations(fieldPresentationsBuilder.build()); 119 lockedDataset.setField(id, fieldBuilder.build()); 120 lockedDataset.setId(null).setAuthentication(authentication); 121 } 122 return lockedDataset.build(); 123 } 124 125 /** 126 * Helper method to create a dataset presentation with the givean text. 127 */ 128 @NonNull newDatasetPresentation(@onNull String packageName, @NonNull CharSequence text)129 static RemoteViews newDatasetPresentation(@NonNull String packageName, 130 @NonNull CharSequence text) { 131 RemoteViews presentation = 132 new RemoteViews(packageName, R.layout.list_item); 133 presentation.setTextViewText(R.id.text, text); 134 return presentation; 135 } 136 } 137