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