1 /*
2  * Copyright (C) 2017 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 package android.autofillservice.cts;
17 
18 import static android.autofillservice.cts.Helper.getAutofillIds;
19 
20 import static com.google.common.truth.Truth.assertWithMessage;
21 
22 import android.app.assist.AssistStructure;
23 import android.app.assist.AssistStructure.ViewNode;
24 import android.content.IntentSender;
25 import android.os.Bundle;
26 import android.service.autofill.CustomDescription;
27 import android.service.autofill.Dataset;
28 import android.service.autofill.FillCallback;
29 import android.service.autofill.FillResponse;
30 import android.service.autofill.Sanitizer;
31 import android.service.autofill.SaveInfo;
32 import android.service.autofill.UserData;
33 import android.service.autofill.Validator;
34 import android.util.Pair;
35 import android.view.autofill.AutofillId;
36 import android.view.autofill.AutofillValue;
37 import android.widget.RemoteViews;
38 
39 import java.util.ArrayList;
40 import java.util.Arrays;
41 import java.util.HashMap;
42 import java.util.List;
43 import java.util.Map;
44 import java.util.function.Function;
45 import java.util.regex.Pattern;
46 
47 /**
48  * Helper class used to produce a {@link FillResponse} based on expected fields that should be
49  * present in the {@link AssistStructure}.
50  *
51  * <p>Typical usage:
52  *
53  * <pre class="prettyprint">
54  * InstrumentedAutoFillService.setFillResponse(new CannedFillResponse.Builder()
55  *               .addDataset(new CannedDataset.Builder("dataset_name")
56  *                   .setField("resource_id1", AutofillValue.forText("value1"))
57  *                   .setField("resource_id2", AutofillValue.forText("value2"))
58  *                   .build())
59  *               .build());
60  * </pre class="prettyprint">
61  */
62 final class CannedFillResponse {
63 
64     private final ResponseType mResponseType;
65     private final List<CannedDataset> mDatasets;
66     private final ArrayList<Pair<Sanitizer, AutofillId[]>> mSanitizers;
67     private final String mFailureMessage;
68     private final int mSaveType;
69     private final Validator mValidator;
70     private final String[] mRequiredSavableIds;
71     private final String[] mOptionalSavableIds;
72     private final AutofillId[] mRequiredSavableAutofillIds;
73     private final String mSaveDescription;
74     private final CustomDescription mCustomDescription;
75     private final Bundle mExtras;
76     private final RemoteViews mPresentation;
77     private final RemoteViews mHeader;
78     private final RemoteViews mFooter;
79     private final IntentSender mAuthentication;
80     private final String[] mAuthenticationIds;
81     private final String[] mIgnoredIds;
82     private final int mNegativeActionStyle;
83     private final IntentSender mNegativeActionListener;
84     private final int mSaveInfoFlags;
85     private final int mFillResponseFlags;
86     private final AutofillId mSaveTriggerId;
87     private final long mDisableDuration;
88     private final AutofillId[] mFieldClassificationIds;
89     private final boolean mFieldClassificationIdsOverflow;
90 
CannedFillResponse(Builder builder)91     private CannedFillResponse(Builder builder) {
92         mResponseType = builder.mResponseType;
93         mDatasets = builder.mDatasets;
94         mFailureMessage = builder.mFailureMessage;
95         mValidator = builder.mValidator;
96         mRequiredSavableIds = builder.mRequiredSavableIds;
97         mRequiredSavableAutofillIds = builder.mRequiredSavableAutofillIds;
98         mOptionalSavableIds = builder.mOptionalSavableIds;
99         mSaveDescription = builder.mSaveDescription;
100         mCustomDescription = builder.mCustomDescription;
101         mSaveType = builder.mSaveType;
102         mExtras = builder.mExtras;
103         mPresentation = builder.mPresentation;
104         mHeader = builder.mHeader;
105         mFooter = builder.mFooter;
106         mAuthentication = builder.mAuthentication;
107         mAuthenticationIds = builder.mAuthenticationIds;
108         mIgnoredIds = builder.mIgnoredIds;
109         mNegativeActionStyle = builder.mNegativeActionStyle;
110         mNegativeActionListener = builder.mNegativeActionListener;
111         mSanitizers = builder.mSanitizers;
112         mSaveInfoFlags = builder.mSaveInfoFlags;
113         mFillResponseFlags = builder.mFillResponseFlags;
114         mSaveTriggerId = builder.mSaveTriggerId;
115         mDisableDuration = builder.mDisableDuration;
116         mFieldClassificationIds = builder.mFieldClassificationIds;
117         mFieldClassificationIdsOverflow = builder.mFieldClassificationIdsOverflow;
118     }
119 
120     /**
121      * Constant used to pass a {@code null} response to the
122      * {@link FillCallback#onSuccess(FillResponse)} method.
123      */
124     static final CannedFillResponse NO_RESPONSE =
125             new Builder(ResponseType.NULL).build();
126 
127     /**
128      * Constant used to emulate a timeout by not calling any method on {@link FillCallback}.
129      */
130     static final CannedFillResponse DO_NOT_REPLY_RESPONSE =
131             new Builder(ResponseType.TIMEOUT).build();
132 
133 
getFailureMessage()134     String getFailureMessage() {
135         return mFailureMessage;
136     }
137 
getResponseType()138     ResponseType getResponseType() {
139         return mResponseType;
140     }
141 
142     /**
143      * Creates a new response, replacing the dataset field ids by the real ids from the assist
144      * structure.
145      */
asFillResponse(Function<String, ViewNode> nodeResolver)146     FillResponse asFillResponse(Function<String, ViewNode> nodeResolver) {
147         final FillResponse.Builder builder = new FillResponse.Builder()
148                 .setFlags(mFillResponseFlags);
149         if (mDatasets != null) {
150             for (CannedDataset cannedDataset : mDatasets) {
151                 final Dataset dataset = cannedDataset.asDataset(nodeResolver);
152                 assertWithMessage("Cannot create datase").that(dataset).isNotNull();
153                 builder.addDataset(dataset);
154             }
155         }
156         if (mRequiredSavableIds != null || mRequiredSavableAutofillIds != null) {
157             final SaveInfo.Builder saveInfo;
158             if (mRequiredSavableAutofillIds != null) {
159                 saveInfo = new SaveInfo.Builder(mSaveType, mRequiredSavableAutofillIds);
160             } else {
161                 saveInfo = mRequiredSavableIds == null || mRequiredSavableIds.length == 0
162                         ? new SaveInfo.Builder(mSaveType)
163                             : new SaveInfo.Builder(mSaveType,
164                                     getAutofillIds(nodeResolver, mRequiredSavableIds));
165             }
166 
167             saveInfo.setFlags(mSaveInfoFlags);
168 
169             if (mValidator != null) {
170                 saveInfo.setValidator(mValidator);
171             }
172             if (mOptionalSavableIds != null) {
173                 saveInfo.setOptionalIds(getAutofillIds(nodeResolver, mOptionalSavableIds));
174             }
175             if (mSaveDescription != null) {
176                 saveInfo.setDescription(mSaveDescription);
177             }
178             saveInfo.setNegativeAction(mNegativeActionStyle, mNegativeActionListener);
179 
180             if (mCustomDescription != null) {
181                 saveInfo.setCustomDescription(mCustomDescription);
182             }
183 
184             for (Pair<Sanitizer, AutofillId[]> sanitizer : mSanitizers) {
185                 saveInfo.addSanitizer(sanitizer.first, sanitizer.second);
186             }
187 
188             if (mSaveTriggerId != null) {
189                 saveInfo.setTriggerId(mSaveTriggerId);
190             }
191             builder.setSaveInfo(saveInfo.build());
192         }
193         if (mIgnoredIds != null) {
194             builder.setIgnoredIds(getAutofillIds(nodeResolver, mIgnoredIds));
195         }
196         if (mAuthenticationIds != null) {
197             builder.setAuthentication(getAutofillIds(nodeResolver, mAuthenticationIds),
198                     mAuthentication, mPresentation);
199         }
200         if (mDisableDuration > 0) {
201             builder.disableAutofill(mDisableDuration);
202         }
203         if (mFieldClassificationIdsOverflow) {
204             final int length = UserData.getMaxFieldClassificationIdsSize() + 1;
205             final AutofillId[] fieldIds = new AutofillId[length];
206             for (int i = 0; i < length; i++) {
207                 fieldIds[i] = new AutofillId(i);
208             }
209             builder.setFieldClassificationIds(fieldIds);
210         } else if (mFieldClassificationIds != null) {
211             builder.setFieldClassificationIds(mFieldClassificationIds);
212         }
213         if (mExtras != null) {
214             builder.setClientState(mExtras);
215         }
216         if (mHeader != null) {
217             builder.setHeader(mHeader);
218         }
219         if (mFooter != null) {
220             builder.setFooter(mFooter);
221         }
222         return builder.build();
223     }
224 
225     @Override
toString()226     public String toString() {
227         return "CannedFillResponse: [type=" + mResponseType
228                 + ",datasets=" + mDatasets
229                 + ", requiredSavableIds=" + Arrays.toString(mRequiredSavableIds)
230                 + ", optionalSavableIds=" + Arrays.toString(mOptionalSavableIds)
231                 + ", requiredSavableAutofillIds=" + Arrays.toString(mRequiredSavableAutofillIds)
232                 + ", saveInfoFlags=" + mSaveInfoFlags
233                 + ", fillResponseFlags=" + mFillResponseFlags
234                 + ", failureMessage=" + mFailureMessage
235                 + ", saveDescription=" + mSaveDescription
236                 + ", mCustomDescription=" + mCustomDescription
237                 + ", hasPresentation=" + (mPresentation != null)
238                 + ", hasHeader=" + (mHeader != null)
239                 + ", hasFooter=" + (mFooter != null)
240                 + ", hasAuthentication=" + (mAuthentication != null)
241                 + ", authenticationIds=" + Arrays.toString(mAuthenticationIds)
242                 + ", ignoredIds=" + Arrays.toString(mIgnoredIds)
243                 + ", sanitizers =" + mSanitizers
244                 + ", saveTriggerId=" + mSaveTriggerId
245                 + ", disableDuration=" + mDisableDuration
246                 + ", fieldClassificationIds=" + Arrays.toString(mFieldClassificationIds)
247                 + ", fieldClassificationIdsOverflow=" + mFieldClassificationIdsOverflow
248                 + "]";
249     }
250 
251     enum ResponseType {
252         NORMAL,
253         NULL,
254         TIMEOUT
255     }
256 
257     static class Builder {
258         private final List<CannedDataset> mDatasets = new ArrayList<>();
259         private final ArrayList<Pair<Sanitizer, AutofillId[]>> mSanitizers = new ArrayList<>();
260         private final ResponseType mResponseType;
261         private String mFailureMessage;
262         private Validator mValidator;
263         private String[] mRequiredSavableIds;
264         private String[] mOptionalSavableIds;
265         private AutofillId[] mRequiredSavableAutofillIds;
266         private String mSaveDescription;
267         public CustomDescription mCustomDescription;
268         public int mSaveType = -1;
269         private Bundle mExtras;
270         private RemoteViews mPresentation;
271         private RemoteViews mFooter;
272         private RemoteViews mHeader;
273         private IntentSender mAuthentication;
274         private String[] mAuthenticationIds;
275         private String[] mIgnoredIds;
276         private int mNegativeActionStyle;
277         private IntentSender mNegativeActionListener;
278         private int mSaveInfoFlags;
279         private int mFillResponseFlags;
280         private AutofillId mSaveTriggerId;
281         private long mDisableDuration;
282         private AutofillId[] mFieldClassificationIds;
283         private boolean mFieldClassificationIdsOverflow;
284 
Builder(ResponseType type)285         public Builder(ResponseType type) {
286             mResponseType = type;
287         }
288 
Builder()289         public Builder() {
290             this(ResponseType.NORMAL);
291         }
292 
addDataset(CannedDataset dataset)293         public Builder addDataset(CannedDataset dataset) {
294             assertWithMessage("already set failure").that(mFailureMessage).isNull();
295             mDatasets.add(dataset);
296             return this;
297         }
298 
299         /**
300          * Sets the validator for this request
301          */
setValidator(Validator validator)302         public Builder setValidator(Validator validator) {
303             mValidator = validator;
304             return this;
305         }
306 
307         /**
308          * Sets the required savable ids based on their {@code resourceId}.
309          */
setRequiredSavableIds(int type, String... ids)310         public Builder setRequiredSavableIds(int type, String... ids) {
311             if (mRequiredSavableAutofillIds != null) {
312                 throw new IllegalStateException("Already set required autofill ids: "
313                         + Arrays.toString(mRequiredSavableAutofillIds));
314             }
315             mSaveType = type;
316             mRequiredSavableIds = ids;
317             return this;
318         }
319 
320         /**
321          * Sets the required savable ids based on their {@code autofillId}.
322          */
setRequiredSavableAutofillIds(int type, AutofillId... ids)323         public Builder setRequiredSavableAutofillIds(int type, AutofillId... ids) {
324             if (mRequiredSavableIds != null) {
325                 throw new IllegalStateException("Already set required resource ids: "
326                         + Arrays.toString(mRequiredSavableIds));
327             }
328             mSaveType = type;
329             mRequiredSavableAutofillIds = ids;
330             return this;
331         }
332 
setSaveInfoFlags(int flags)333         public Builder setSaveInfoFlags(int flags) {
334             mSaveInfoFlags = flags;
335             return this;
336         }
337 
setFillResponseFlags(int flags)338         public Builder setFillResponseFlags(int flags) {
339             mFillResponseFlags = flags;
340             return this;
341         }
342 
343         /**
344          * Sets the optional savable ids based on they {@code resourceId}.
345          */
setOptionalSavableIds(String... ids)346         public Builder setOptionalSavableIds(String... ids) {
347             mOptionalSavableIds = ids;
348             return this;
349         }
350 
351         /**
352          * Sets the description passed to the {@link SaveInfo}.
353          */
setSaveDescription(String description)354         public Builder setSaveDescription(String description) {
355             mSaveDescription = description;
356             return this;
357         }
358 
359         /**
360          * Sets the description passed to the {@link SaveInfo}.
361          */
setCustomDescription(CustomDescription description)362         public Builder setCustomDescription(CustomDescription description) {
363             mCustomDescription = description;
364             return this;
365         }
366 
367         /**
368          * Sets the extra passed to {@link
369          * android.service.autofill.FillResponse.Builder#setClientState(Bundle)}.
370          */
setExtras(Bundle data)371         public Builder setExtras(Bundle data) {
372             mExtras = data;
373             return this;
374         }
375 
376         /**
377          * Sets the view to present the response in the UI.
378          */
setPresentation(RemoteViews presentation)379         public Builder setPresentation(RemoteViews presentation) {
380             mPresentation = presentation;
381             return this;
382         }
383 
384         /**
385          * Sets the authentication intent.
386          */
setAuthentication(IntentSender authentication, String... ids)387         public Builder setAuthentication(IntentSender authentication, String... ids) {
388             mAuthenticationIds = ids;
389             mAuthentication = authentication;
390             return this;
391         }
392 
393         /**
394          * Sets the ignored fields based on resource ids.
395          */
setIgnoreFields(String...ids)396         public Builder setIgnoreFields(String...ids) {
397             mIgnoredIds = ids;
398             return this;
399         }
400 
401         /**
402          * Sets the negative action spec.
403          */
setNegativeAction(int style, IntentSender listener)404         public Builder setNegativeAction(int style, IntentSender listener) {
405             mNegativeActionStyle = style;
406             mNegativeActionListener = listener;
407             return this;
408         }
409 
410         /**
411          * Adds a save sanitizer.
412          */
addSanitizer(Sanitizer sanitizer, AutofillId... ids)413         public Builder addSanitizer(Sanitizer sanitizer, AutofillId... ids) {
414             mSanitizers.add(new Pair<>(sanitizer, ids));
415             return this;
416         }
417 
build()418         public CannedFillResponse build() {
419             return new CannedFillResponse(this);
420         }
421 
422         /**
423          * Sets the response to call {@link FillCallback#onFailure(CharSequence)}.
424          */
returnFailure(String message)425         public Builder returnFailure(String message) {
426             assertWithMessage("already added datasets").that(mDatasets).isEmpty();
427             mFailureMessage = message;
428             return this;
429         }
430 
431         /**
432          * Sets the view that explicitly triggers save.
433          */
setSaveTriggerId(AutofillId id)434         public Builder setSaveTriggerId(AutofillId id) {
435             assertWithMessage("already set").that(mSaveTriggerId).isNull();
436             mSaveTriggerId = id;
437             return this;
438         }
439 
disableAutofill(long duration)440         public Builder disableAutofill(long duration) {
441             assertWithMessage("already set").that(mDisableDuration).isEqualTo(0L);
442             mDisableDuration = duration;
443             return this;
444         }
445 
446         /**
447          * Sets the ids used for field classification.
448          */
setFieldClassificationIds(AutofillId... ids)449         public Builder setFieldClassificationIds(AutofillId... ids) {
450             assertWithMessage("already set").that(mFieldClassificationIds).isNull();
451             mFieldClassificationIds = ids;
452             return this;
453         }
454 
455         /**
456          * Forces the service to throw an exception when setting the fields classification ids.
457          */
setFieldClassificationIdsOverflow()458         public Builder setFieldClassificationIdsOverflow() {
459             mFieldClassificationIdsOverflow = true;
460             return this;
461         }
462 
setHeader(RemoteViews header)463         public Builder setHeader(RemoteViews header) {
464             assertWithMessage("already set").that(mHeader).isNull();
465             mHeader = header;
466             return this;
467         }
468 
setFooter(RemoteViews footer)469         public Builder setFooter(RemoteViews footer) {
470             assertWithMessage("already set").that(mFooter).isNull();
471             mFooter = footer;
472             return this;
473         }
474     }
475 
476     /**
477      * Helper class used to produce a {@link Dataset} based on expected fields that should be
478      * present in the {@link AssistStructure}.
479      *
480      * <p>Typical usage:
481      *
482      * <pre class="prettyprint">
483      * InstrumentedAutoFillService.setFillResponse(new CannedFillResponse.Builder()
484      *               .addDataset(new CannedDataset.Builder("dataset_name")
485      *                   .setField("resource_id1", AutofillValue.forText("value1"))
486      *                   .setField("resource_id2", AutofillValue.forText("value2"))
487      *                   .build())
488      *               .build());
489      * </pre class="prettyprint">
490      */
491     static class CannedDataset {
492         private final Map<String, AutofillValue> mFieldValues;
493         private final Map<AutofillId, AutofillValue> mFieldValuesById;
494         private final Map<AutofillId, RemoteViews> mFieldPresentationsById;
495         private final Map<String, RemoteViews> mFieldPresentations;
496         private final Map<String, Pair<Boolean, Pattern>> mFieldFilters;
497         private final RemoteViews mPresentation;
498         private final IntentSender mAuthentication;
499         private final String mId;
500 
CannedDataset(Builder builder)501         private CannedDataset(Builder builder) {
502             mFieldValues = builder.mFieldValues;
503             mFieldValuesById = builder.mFieldValuesById;
504             mFieldPresentationsById = builder.mFieldPresentationsById;
505             mFieldPresentations = builder.mFieldPresentations;
506             mFieldFilters = builder.mFieldFilters;
507             mPresentation = builder.mPresentation;
508             mAuthentication = builder.mAuthentication;
509             mId = builder.mId;
510         }
511 
512         /**
513          * Creates a new dataset, replacing the field ids by the real ids from the assist structure.
514          */
asDataset(Function<String, ViewNode> nodeResolver)515         Dataset asDataset(Function<String, ViewNode> nodeResolver) {
516             final Dataset.Builder builder = (mPresentation == null)
517                     ? new Dataset.Builder()
518                     : new Dataset.Builder(mPresentation);
519 
520             if (mFieldValues != null) {
521                 for (Map.Entry<String, AutofillValue> entry : mFieldValues.entrySet()) {
522                     final String id = entry.getKey();
523                     final ViewNode node = nodeResolver.apply(id);
524                     if (node == null) {
525                         throw new AssertionError("No node with resource id " + id);
526                     }
527                     final AutofillId autofillId = node.getAutofillId();
528                     final AutofillValue value = entry.getValue();
529                     final RemoteViews presentation = mFieldPresentations.get(id);
530                     final Pair<Boolean, Pattern> filter = mFieldFilters.get(id);
531                     if (presentation != null) {
532                         if (filter == null) {
533                             builder.setValue(autofillId, value, presentation);
534                         } else {
535                             builder.setValue(autofillId, value, filter.second, presentation);
536                         }
537                     } else {
538                         if (filter == null) {
539                             builder.setValue(autofillId, value);
540                         } else {
541                             builder.setValue(autofillId, value, filter.second);
542                         }
543                     }
544                 }
545             }
546             if (mFieldValuesById != null) {
547                 // NOTE: filter is not yet supported when calling methods that explicitly pass
548                 // autofill id
549                 for (Map.Entry<AutofillId, AutofillValue> entry : mFieldValuesById.entrySet()) {
550                     final AutofillId autofillId = entry.getKey();
551                     final AutofillValue value = entry.getValue();
552                     final RemoteViews presentation = mFieldPresentationsById.get(autofillId);
553                     if (presentation != null) {
554                         builder.setValue(autofillId, value, presentation);
555                     } else {
556                         builder.setValue(autofillId, value);
557                     }
558                 }
559             }
560             builder.setId(mId).setAuthentication(mAuthentication);
561             return builder.build();
562         }
563 
564         @Override
toString()565         public String toString() {
566             return "CannedDataset " + mId + " : [hasPresentation=" + (mPresentation != null)
567                     + ", fieldPresentations=" + (mFieldPresentations)
568                     + ", fieldPresentationsById=" + (mFieldPresentationsById)
569                     + ", hasAuthentication=" + (mAuthentication != null)
570                     + ", fieldValues=" + mFieldValues
571                     + ", fieldValuesById=" + mFieldValuesById
572                     + ", fieldFilters=" + mFieldFilters + "]";
573         }
574 
575         static class Builder {
576             private final Map<String, AutofillValue> mFieldValues = new HashMap<>();
577             private final Map<AutofillId, AutofillValue> mFieldValuesById = new HashMap<>();
578             private final Map<String, RemoteViews> mFieldPresentations = new HashMap<>();
579             private final Map<AutofillId, RemoteViews> mFieldPresentationsById = new HashMap<>();
580             private final Map<String, Pair<Boolean, Pattern>> mFieldFilters = new HashMap<>();
581 
582             private RemoteViews mPresentation;
583             private IntentSender mAuthentication;
584             private String mId;
585 
Builder()586             public Builder() {
587 
588             }
589 
Builder(RemoteViews presentation)590             public Builder(RemoteViews presentation) {
591                 mPresentation = presentation;
592             }
593 
594             /**
595              * Sets the canned value of a text field based on its {@code id}.
596              *
597              * <p>The meaning of the id is defined by the object using the canned dataset.
598              * For example, {@link InstrumentedAutoFillService.Replier} resolves the id based on
599              * {@link IdMode}.
600              */
setField(String id, String text)601             public Builder setField(String id, String text) {
602                 return setField(id, AutofillValue.forText(text));
603             }
604 
605             /**
606              * Sets the canned value of a text field based on its {@code id}.
607              *
608              * <p>The meaning of the id is defined by the object using the canned dataset.
609              * For example, {@link InstrumentedAutoFillService.Replier} resolves the id based on
610              * {@link IdMode}.
611              */
setField(String id, String text, Pattern filter)612             public Builder setField(String id, String text, Pattern filter) {
613                 return setField(id, AutofillValue.forText(text), true, filter);
614             }
615 
setUnfilterableField(String id, String text)616             public Builder setUnfilterableField(String id, String text) {
617                 return setField(id, AutofillValue.forText(text), false, null);
618             }
619 
620             /**
621              * Sets the canned value of a list field based on its its {@code id}.
622              *
623              * <p>The meaning of the id is defined by the object using the canned dataset.
624              * For example, {@link InstrumentedAutoFillService.Replier} resolves the id based on
625              * {@link IdMode}.
626              */
setField(String id, int index)627             public Builder setField(String id, int index) {
628                 return setField(id, AutofillValue.forList(index));
629             }
630 
631             /**
632              * Sets the canned value of a toggle field based on its {@code id}.
633              *
634              * <p>The meaning of the id is defined by the object using the canned dataset.
635              * For example, {@link InstrumentedAutoFillService.Replier} resolves the id based on
636              * {@link IdMode}.
637              */
setField(String id, boolean toggled)638             public Builder setField(String id, boolean toggled) {
639                 return setField(id, AutofillValue.forToggle(toggled));
640             }
641 
642             /**
643              * Sets the canned value of a date field based on its {@code id}.
644              *
645              * <p>The meaning of the id is defined by the object using the canned dataset.
646              * For example, {@link InstrumentedAutoFillService.Replier} resolves the id based on
647              * {@link IdMode}.
648              */
setField(String id, long date)649             public Builder setField(String id, long date) {
650                 return setField(id, AutofillValue.forDate(date));
651             }
652 
653             /**
654              * Sets the canned value of a date field based on its {@code id}.
655              *
656              * <p>The meaning of the id is defined by the object using the canned dataset.
657              * For example, {@link InstrumentedAutoFillService.Replier} resolves the id based on
658              * {@link IdMode}.
659              */
setField(String id, AutofillValue value)660             public Builder setField(String id, AutofillValue value) {
661                 mFieldValues.put(id, value);
662                 return this;
663             }
664 
665             /**
666              * Sets the canned value of a date field based on its {@code autofillId}.
667              */
setField(AutofillId autofillId, AutofillValue value)668             public Builder setField(AutofillId autofillId, AutofillValue value) {
669                 mFieldValuesById.put(autofillId, value);
670                 return this;
671             }
672 
673             /**
674              * Sets the canned value of a date field based on its {@code id}.
675              *
676              * <p>The meaning of the id is defined by the object using the canned dataset.
677              * For example, {@link InstrumentedAutoFillService.Replier} resolves the id based on
678              * {@link IdMode}.
679              */
setField(String id, AutofillValue value, boolean filterable, Pattern filter)680             public Builder setField(String id, AutofillValue value, boolean filterable,
681                     Pattern filter) {
682                 setField(id, value);
683                 mFieldFilters.put(id, new Pair<>(filterable, filter));
684                 return this;
685             }
686 
687             /**
688              * Sets the canned value of a field based on its {@code id}.
689              *
690              * <p>The meaning of the id is defined by the object using the canned dataset.
691              * For example, {@link InstrumentedAutoFillService.Replier} resolves the id based on
692              * {@link IdMode}.
693              */
setField(String id, String text, RemoteViews presentation)694             public Builder setField(String id, String text, RemoteViews presentation) {
695                 setField(id, text);
696                 mFieldPresentations.put(id, presentation);
697                 return this;
698             }
699 
700             /**
701              * Sets the canned value of a date field based on its {@code autofillId}.
702              */
setField(AutofillId autofillId, String text, RemoteViews presentation)703             public Builder setField(AutofillId autofillId, String text, RemoteViews presentation) {
704                 setField(autofillId, AutofillValue.forText(text));
705                 mFieldPresentationsById.put(autofillId, presentation);
706                 return this;
707             }
708 
709             /**
710              * Sets the canned value of a field based on its {@code id}.
711              *
712              * <p>The meaning of the id is defined by the object using the canned dataset.
713              * For example, {@link InstrumentedAutoFillService.Replier} resolves the id based on
714              * {@link IdMode}.
715              */
setField(String id, String text, RemoteViews presentation, Pattern filter)716             public Builder setField(String id, String text, RemoteViews presentation,
717                     Pattern filter) {
718                 setField(id, text, presentation);
719                 mFieldFilters.put(id, new Pair<>(true, filter));
720                 return this;
721             }
722 
723             /**
724              * Sets the view to present the response in the UI.
725              */
setPresentation(RemoteViews presentation)726             public Builder setPresentation(RemoteViews presentation) {
727                 mPresentation = presentation;
728                 return this;
729             }
730 
731             /**
732              * Sets the authentication intent.
733              */
setAuthentication(IntentSender authentication)734             public Builder setAuthentication(IntentSender authentication) {
735                 mAuthentication = authentication;
736                 return this;
737             }
738 
739             /**
740              * Sets the name.
741              */
setId(String id)742             public Builder setId(String id) {
743                 mId = id;
744                 return this;
745             }
746 
build()747             public CannedDataset build() {
748                 return new CannedDataset(this);
749             }
750         }
751     }
752 }
753