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