Home | History | Annotate | Download | only in cts
      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 
     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 
    134     String getFailureMessage() {
    135         return mFailureMessage;
    136     }
    137 
    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      */
    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
    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 
    285         public Builder(ResponseType type) {
    286             mResponseType = type;
    287         }
    288 
    289         public Builder() {
    290             this(ResponseType.NORMAL);
    291         }
    292 
    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          */
    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          */
    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          */
    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 
    333         public Builder setSaveInfoFlags(int flags) {
    334             mSaveInfoFlags = flags;
    335             return this;
    336         }
    337 
    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          */
    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          */
    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          */
    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          */
    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          */
    379         public Builder setPresentation(RemoteViews presentation) {
    380             mPresentation = presentation;
    381             return this;
    382         }
    383 
    384         /**
    385          * Sets the authentication intent.
    386          */
    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          */
    396         public Builder setIgnoreFields(String...ids) {
    397             mIgnoredIds = ids;
    398             return this;
    399         }
    400 
    401         /**
    402          * Sets the negative action spec.
    403          */
    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          */
    413         public Builder addSanitizer(Sanitizer sanitizer, AutofillId... ids) {
    414             mSanitizers.add(new Pair<>(sanitizer, ids));
    415             return this;
    416         }
    417 
    418         public CannedFillResponse build() {
    419             return new CannedFillResponse(this);
    420         }
    421 
    422         /**
    423          * Sets the response to call {@link FillCallback#onFailure(CharSequence)}.
    424          */
    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          */
    434         public Builder setSaveTriggerId(AutofillId id) {
    435             assertWithMessage("already set").that(mSaveTriggerId).isNull();
    436             mSaveTriggerId = id;
    437             return this;
    438         }
    439 
    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          */
    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          */
    458         public Builder setFieldClassificationIdsOverflow() {
    459             mFieldClassificationIdsOverflow = true;
    460             return this;
    461         }
    462 
    463         public Builder setHeader(RemoteViews header) {
    464             assertWithMessage("already set").that(mHeader).isNull();
    465             mHeader = header;
    466             return this;
    467         }
    468 
    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 
    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          */
    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
    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 
    586             public Builder() {
    587 
    588             }
    589 
    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              */
    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              */
    612             public Builder setField(String id, String text, Pattern filter) {
    613                 return setField(id, AutofillValue.forText(text), true, filter);
    614             }
    615 
    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              */
    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              */
    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              */
    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              */
    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              */
    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              */
    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              */
    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              */
    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              */
    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              */
    726             public Builder setPresentation(RemoteViews presentation) {
    727                 mPresentation = presentation;
    728                 return this;
    729             }
    730 
    731             /**
    732              * Sets the authentication intent.
    733              */
    734             public Builder setAuthentication(IntentSender authentication) {
    735                 mAuthentication = authentication;
    736                 return this;
    737             }
    738 
    739             /**
    740              * Sets the name.
    741              */
    742             public Builder setId(String id) {
    743                 mId = id;
    744                 return this;
    745             }
    746 
    747             public CannedDataset build() {
    748                 return new CannedDataset(this);
    749             }
    750         }
    751     }
    752 }
    753