1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.service.autofill; 18 19 import static android.service.autofill.AutofillServiceHelper.assertValid; 20 import static android.service.autofill.FillRequest.INVALID_REQUEST_ID; 21 import static android.view.autofill.Helper.sDebug; 22 23 import android.annotation.DrawableRes; 24 import android.annotation.IntDef; 25 import android.annotation.NonNull; 26 import android.annotation.Nullable; 27 import android.annotation.StringRes; 28 import android.annotation.SuppressLint; 29 import android.annotation.TestApi; 30 import android.app.Activity; 31 import android.content.Intent; 32 import android.content.IntentSender; 33 import android.content.pm.ParceledListSlice; 34 import android.os.Bundle; 35 import android.os.Parcel; 36 import android.os.Parcelable; 37 import android.service.assist.classification.FieldClassification; 38 import android.view.autofill.AutofillId; 39 import android.widget.RemoteViews; 40 41 import com.android.internal.util.Preconditions; 42 43 import java.lang.annotation.Retention; 44 import java.lang.annotation.RetentionPolicy; 45 import java.util.ArrayList; 46 import java.util.Arrays; 47 import java.util.List; 48 import java.util.Objects; 49 import java.util.Set; 50 51 /** 52 * Response for an {@link 53 * AutofillService#onFillRequest(FillRequest, android.os.CancellationSignal, FillCallback)}. 54 * 55 * <p>See the main {@link AutofillService} documentation for more details and examples. 56 */ 57 public final class FillResponse implements Parcelable { 58 59 /** 60 * Flag used to generate {@link FillEventHistory.Event events} of type 61 * {@link FillEventHistory.Event#TYPE_CONTEXT_COMMITTED}—if this flag is not passed to 62 * {@link Builder#setFlags(int)}, these events are not generated. 63 */ 64 public static final int FLAG_TRACK_CONTEXT_COMMITED = 0x1; 65 66 /** 67 * Flag used to change the behavior of {@link FillResponse.Builder#disableAutofill(long)}— 68 * when this flag is passed to {@link Builder#setFlags(int)}, autofill is disabled only for the 69 * activiy that generated the {@link FillRequest}, not the whole app. 70 */ 71 public static final int FLAG_DISABLE_ACTIVITY_ONLY = 0x2; 72 73 /** 74 * Flag used to request to wait for a delayed fill from the remote Autofill service if it's 75 * passed to {@link Builder#setFlags(int)}. 76 * 77 * <p>Some datasets (i.e. OTP) take time to produce. This flags allows remote service to send 78 * a {@link FillResponse} to the latest {@link FillRequest} via 79 * {@link FillRequest#getDelayedFillIntentSender()} even if the original {@link FillCallback} 80 * has timed out. 81 */ 82 public static final int FLAG_DELAY_FILL = 0x4; 83 84 /** @hide */ 85 @IntDef(flag = true, prefix = { "FLAG_" }, value = { 86 FLAG_TRACK_CONTEXT_COMMITED, 87 FLAG_DISABLE_ACTIVITY_ONLY, 88 FLAG_DELAY_FILL 89 }) 90 @Retention(RetentionPolicy.SOURCE) 91 @interface FillResponseFlags {} 92 93 private final @Nullable ParceledListSlice<Dataset> mDatasets; 94 private final @Nullable SaveInfo mSaveInfo; 95 private final @Nullable Bundle mClientState; 96 private final @Nullable RemoteViews mPresentation; 97 private final @Nullable InlinePresentation mInlinePresentation; 98 private final @Nullable InlinePresentation mInlineTooltipPresentation; 99 private final @Nullable RemoteViews mDialogPresentation; 100 private final @Nullable RemoteViews mDialogHeader; 101 private final @Nullable RemoteViews mHeader; 102 private final @Nullable RemoteViews mFooter; 103 private final @Nullable IntentSender mAuthentication; 104 private final @Nullable AutofillId[] mAuthenticationIds; 105 private final @Nullable AutofillId[] mIgnoredIds; 106 private final @Nullable AutofillId[] mFillDialogTriggerIds; 107 private final long mDisableDuration; 108 private final @Nullable AutofillId[] mFieldClassificationIds; 109 private final int mFlags; 110 private int mRequestId; 111 private final @Nullable UserData mUserData; 112 private final @Nullable int[] mCancelIds; 113 private final boolean mSupportsInlineSuggestions; 114 private final @DrawableRes int mIconResourceId; 115 private final @StringRes int mServiceDisplayNameResourceId; 116 private final boolean mShowFillDialogIcon; 117 private final boolean mShowSaveDialogIcon; 118 private final @Nullable FieldClassification[] mDetectedFieldTypes; 119 120 /** 121 * Creates a shollow copy of the provided FillResponse. 122 * 123 * @hide 124 */ shallowCopy( FillResponse r, List<Dataset> datasets, SaveInfo saveInfo)125 public static FillResponse shallowCopy( 126 FillResponse r, List<Dataset> datasets, SaveInfo saveInfo) { 127 return new FillResponse( 128 (datasets != null) ? new ParceledListSlice<>(datasets) : null, 129 saveInfo, 130 r.mClientState, 131 r.mPresentation, 132 r.mInlinePresentation, 133 r.mInlineTooltipPresentation, 134 r.mDialogPresentation, 135 r.mDialogHeader, 136 r.mHeader, 137 r.mFooter, 138 r.mAuthentication, 139 r.mAuthenticationIds, 140 r.mIgnoredIds, 141 r.mFillDialogTriggerIds, 142 r.mDisableDuration, 143 r.mFieldClassificationIds, 144 r.mFlags, 145 r.mRequestId, 146 r.mUserData, 147 r.mCancelIds, 148 r.mSupportsInlineSuggestions, 149 r.mIconResourceId, 150 r.mServiceDisplayNameResourceId, 151 r.mShowFillDialogIcon, 152 r.mShowSaveDialogIcon, 153 r.mDetectedFieldTypes); 154 } 155 FillResponse(ParceledListSlice<Dataset> datasets, SaveInfo saveInfo, Bundle clientState, RemoteViews presentation, InlinePresentation inlinePresentation, InlinePresentation inlineTooltipPresentation, RemoteViews dialogPresentation, RemoteViews dialogHeader, RemoteViews header, RemoteViews footer, IntentSender authentication, AutofillId[] authenticationIds, AutofillId[] ignoredIds, AutofillId[] fillDialogTriggerIds, long disableDuration, AutofillId[] fieldClassificationIds, int flags, int requestId, UserData userData, int[] cancelIds, boolean supportsInlineSuggestions, int iconResourceId, int serviceDisplayNameResourceId, boolean showFillDialogIcon, boolean showSaveDialogIcon, FieldClassification[] detectedFieldTypes)156 private FillResponse(ParceledListSlice<Dataset> datasets, SaveInfo saveInfo, Bundle clientState, 157 RemoteViews presentation, InlinePresentation inlinePresentation, 158 InlinePresentation inlineTooltipPresentation, RemoteViews dialogPresentation, 159 RemoteViews dialogHeader, RemoteViews header, RemoteViews footer, 160 IntentSender authentication, AutofillId[] authenticationIds, AutofillId[] ignoredIds, 161 AutofillId[] fillDialogTriggerIds, long disableDuration, 162 AutofillId[] fieldClassificationIds, int flags, int requestId, UserData userData, 163 int[] cancelIds, boolean supportsInlineSuggestions, int iconResourceId, 164 int serviceDisplayNameResourceId, boolean showFillDialogIcon, 165 boolean showSaveDialogIcon, 166 FieldClassification[] detectedFieldTypes) { 167 mDatasets = datasets; 168 mSaveInfo = saveInfo; 169 mClientState = clientState; 170 mPresentation = presentation; 171 mInlinePresentation = inlinePresentation; 172 mInlineTooltipPresentation = inlineTooltipPresentation; 173 mDialogPresentation = dialogPresentation; 174 mDialogHeader = dialogHeader; 175 mHeader = header; 176 mFooter = footer; 177 mAuthentication = authentication; 178 mAuthenticationIds = authenticationIds; 179 mIgnoredIds = ignoredIds; 180 mFillDialogTriggerIds = fillDialogTriggerIds; 181 mDisableDuration = disableDuration; 182 mFieldClassificationIds = fieldClassificationIds; 183 mFlags = flags; 184 mRequestId = requestId; 185 mUserData = userData; 186 mCancelIds = cancelIds; 187 mSupportsInlineSuggestions = supportsInlineSuggestions; 188 mIconResourceId = iconResourceId; 189 mServiceDisplayNameResourceId = serviceDisplayNameResourceId; 190 mShowFillDialogIcon = showFillDialogIcon; 191 mShowSaveDialogIcon = showSaveDialogIcon; 192 mDetectedFieldTypes = detectedFieldTypes; 193 } 194 FillResponse(@onNull Builder builder)195 private FillResponse(@NonNull Builder builder) { 196 mDatasets = (builder.mDatasets != null) ? new ParceledListSlice<>(builder.mDatasets) : null; 197 mSaveInfo = builder.mSaveInfo; 198 mClientState = builder.mClientState; 199 mPresentation = builder.mPresentation; 200 mInlinePresentation = builder.mInlinePresentation; 201 mInlineTooltipPresentation = builder.mInlineTooltipPresentation; 202 mDialogPresentation = builder.mDialogPresentation; 203 mDialogHeader = builder.mDialogHeader; 204 mHeader = builder.mHeader; 205 mFooter = builder.mFooter; 206 mAuthentication = builder.mAuthentication; 207 mAuthenticationIds = builder.mAuthenticationIds; 208 mFillDialogTriggerIds = builder.mFillDialogTriggerIds; 209 mIgnoredIds = builder.mIgnoredIds; 210 mDisableDuration = builder.mDisableDuration; 211 mFieldClassificationIds = builder.mFieldClassificationIds; 212 mFlags = builder.mFlags; 213 mRequestId = INVALID_REQUEST_ID; 214 mUserData = builder.mUserData; 215 mCancelIds = builder.mCancelIds; 216 mSupportsInlineSuggestions = builder.mSupportsInlineSuggestions; 217 mIconResourceId = builder.mIconResourceId; 218 mServiceDisplayNameResourceId = builder.mServiceDisplayNameResourceId; 219 mShowFillDialogIcon = builder.mShowFillDialogIcon; 220 mShowSaveDialogIcon = builder.mShowSaveDialogIcon; 221 mDetectedFieldTypes = builder.mDetectedFieldTypes; 222 } 223 224 /** @hide */ 225 @TestApi 226 @NonNull getDetectedFieldClassifications()227 public Set<FieldClassification> getDetectedFieldClassifications() { 228 return Set.of(mDetectedFieldTypes); 229 } 230 231 /** @hide */ getClientState()232 public @Nullable Bundle getClientState() { 233 return mClientState; 234 } 235 236 /** @hide */ getDatasets()237 public @Nullable List<Dataset> getDatasets() { 238 return (mDatasets != null) ? mDatasets.getList() : null; 239 } 240 241 /** @hide */ getSaveInfo()242 public @Nullable SaveInfo getSaveInfo() { 243 return mSaveInfo; 244 } 245 246 /** @hide */ getPresentation()247 public @Nullable RemoteViews getPresentation() { 248 return mPresentation; 249 } 250 251 /** @hide */ getInlinePresentation()252 public @Nullable InlinePresentation getInlinePresentation() { 253 return mInlinePresentation; 254 } 255 256 /** @hide */ getInlineTooltipPresentation()257 public @Nullable InlinePresentation getInlineTooltipPresentation() { 258 return mInlineTooltipPresentation; 259 } 260 261 /** @hide */ getDialogPresentation()262 public @Nullable RemoteViews getDialogPresentation() { 263 return mDialogPresentation; 264 } 265 266 /** @hide */ getDialogHeader()267 public @Nullable RemoteViews getDialogHeader() { 268 return mDialogHeader; 269 } 270 271 /** @hide */ getHeader()272 public @Nullable RemoteViews getHeader() { 273 return mHeader; 274 } 275 276 /** @hide */ getFooter()277 public @Nullable RemoteViews getFooter() { 278 return mFooter; 279 } 280 281 /** @hide */ getAuthentication()282 public @Nullable IntentSender getAuthentication() { 283 return mAuthentication; 284 } 285 286 /** @hide */ getAuthenticationIds()287 public @Nullable AutofillId[] getAuthenticationIds() { 288 return mAuthenticationIds; 289 } 290 291 /** @hide */ getFillDialogTriggerIds()292 public @Nullable AutofillId[] getFillDialogTriggerIds() { 293 return mFillDialogTriggerIds; 294 } 295 296 /** @hide */ getIgnoredIds()297 public @Nullable AutofillId[] getIgnoredIds() { 298 return mIgnoredIds; 299 } 300 301 /** @hide */ getDisableDuration()302 public long getDisableDuration() { 303 return mDisableDuration; 304 } 305 306 /** @hide */ getFieldClassificationIds()307 public @Nullable AutofillId[] getFieldClassificationIds() { 308 return mFieldClassificationIds; 309 } 310 311 /** @hide */ getUserData()312 public @Nullable UserData getUserData() { 313 return mUserData; 314 } 315 316 /** @hide */ getIconResourceId()317 public @DrawableRes int getIconResourceId() { 318 return mIconResourceId; 319 } 320 321 /** @hide */ getServiceDisplayNameResourceId()322 public @StringRes int getServiceDisplayNameResourceId() { 323 return mServiceDisplayNameResourceId; 324 } 325 326 /** @hide */ getShowFillDialogIcon()327 public boolean getShowFillDialogIcon() { 328 return mShowFillDialogIcon; 329 } 330 331 /** @hide */ getShowSaveDialogIcon()332 public boolean getShowSaveDialogIcon() { 333 return mShowSaveDialogIcon; 334 } 335 336 /** @hide */ 337 @TestApi getFlags()338 public int getFlags() { 339 return mFlags; 340 } 341 342 /** 343 * Associates a {@link FillResponse} to a request. 344 * 345 * <p>Set inside of the {@link FillCallback} code, not the {@link AutofillService}. 346 * 347 * @param requestId The id of the request to associate the response to. 348 * 349 * @hide 350 */ setRequestId(int requestId)351 public void setRequestId(int requestId) { 352 mRequestId = requestId; 353 } 354 355 /** @hide */ getRequestId()356 public int getRequestId() { 357 return mRequestId; 358 } 359 360 /** @hide */ 361 @Nullable getCancelIds()362 public int[] getCancelIds() { 363 return mCancelIds; 364 } 365 366 /** @hide */ supportsInlineSuggestions()367 public boolean supportsInlineSuggestions() { 368 return mSupportsInlineSuggestions; 369 } 370 371 /** 372 * Builder for {@link FillResponse} objects. You must to provide at least 373 * one dataset or set an authentication intent with a presentation view. 374 */ 375 public static final class Builder { 376 private ArrayList<Dataset> mDatasets; 377 private SaveInfo mSaveInfo; 378 private Bundle mClientState; 379 private RemoteViews mPresentation; 380 private InlinePresentation mInlinePresentation; 381 private InlinePresentation mInlineTooltipPresentation; 382 private RemoteViews mDialogPresentation; 383 private RemoteViews mDialogHeader; 384 private RemoteViews mHeader; 385 private RemoteViews mFooter; 386 private IntentSender mAuthentication; 387 private AutofillId[] mAuthenticationIds; 388 private AutofillId[] mIgnoredIds; 389 private long mDisableDuration; 390 private AutofillId[] mFieldClassificationIds; 391 private AutofillId[] mFillDialogTriggerIds; 392 private int mFlags; 393 private boolean mDestroyed; 394 private UserData mUserData; 395 private int[] mCancelIds; 396 private boolean mSupportsInlineSuggestions; 397 private int mIconResourceId; 398 private int mServiceDisplayNameResourceId; 399 private boolean mShowFillDialogIcon = true; 400 private boolean mShowSaveDialogIcon = true; 401 private FieldClassification[] mDetectedFieldTypes; 402 403 /** 404 * Adds a new {@link FieldClassification} to this response, to 405 * help the platform provide more accurate detection results. 406 * 407 * Call this when a field has been detected with a type. 408 * 409 * Altough similiarly named with {@link setFieldClassificationIds}, 410 * it provides a different functionality - setFieldClassificationIds should 411 * be used when a field is only suspected to be Autofillable. 412 * This method should be used when a field is certainly Autofillable 413 * with a certain type. 414 */ 415 @NonNull setDetectedFieldClassifications( @onNull Set<FieldClassification> fieldInfos)416 public Builder setDetectedFieldClassifications( 417 @NonNull Set<FieldClassification> fieldInfos) { 418 throwIfDestroyed(); 419 throwIfDisableAutofillCalled(); 420 mDetectedFieldTypes = fieldInfos.toArray(new FieldClassification[0]); 421 return this; 422 } 423 424 /** 425 * Triggers a custom UI before autofilling the screen with any data set in this 426 * response. 427 * 428 * <p><b>Note:</b> Although the name of this method suggests that it should be used just for 429 * authentication flow, it can be used for other advanced flows; see {@link AutofillService} 430 * for examples. 431 * 432 * <p>This is typically useful when a user interaction is required to unlock their 433 * data vault if you encrypt the data set labels and data set data. It is recommended 434 * to encrypt only the sensitive data and not the data set labels which would allow 435 * auth on the data set level leading to a better user experience. Note that if you 436 * use sensitive data as a label, for example an email address, then it should also 437 * be encrypted. The provided {@link android.app.PendingIntent intent} must be an 438 * {@link Activity} which implements your authentication flow. Also if you provide an auth 439 * intent you also need to specify the presentation view to be shown in the fill UI 440 * for the user to trigger your authentication flow. 441 * 442 * <p>When a user triggers autofill, the system launches the provided intent 443 * whose extras will have the 444 * {@link android.view.autofill.AutofillManager#EXTRA_ASSIST_STRUCTURE screen 445 * content} and your {@link android.view.autofill.AutofillManager#EXTRA_CLIENT_STATE 446 * client state}. Once you complete your authentication flow you should set the 447 * {@link Activity} result to {@link android.app.Activity#RESULT_OK} and set the 448 * {@link android.view.autofill.AutofillManager#EXTRA_AUTHENTICATION_RESULT} extra 449 * with the fully populated {@link FillResponse response} (or {@code null} if the screen 450 * cannot be autofilled). 451 * 452 * <p> <b>IMPORTANT</b>: Extras must be non-null on the intent being set for Android 12 453 * otherwise it will cause a crash. Do not use {@link Activity#setResult(int)}, instead use 454 * {@link Activity#setResult(int, Intent) with non-null extras. Consider setting { 455 * @link android.view.autofill.AutofillManager#EXTRA_AUTHENTICATION_RESULT} to null or use 456 * {@link Bundle#EMPTY} with {@link Intent#putExtras(Bundle)} on the intent when 457 * finishing activity to avoid crash). </p> 458 * 459 * <p>For example, if you provided an empty {@link FillResponse response} because the 460 * user's data was locked and marked that the response needs an authentication then 461 * in the response returned if authentication succeeds you need to provide all 462 * available data sets some of which may need to be further authenticated, for 463 * example a credit card whose CVV needs to be entered. 464 * 465 * <p>If you provide an authentication intent you must also provide a presentation 466 * which is used to visualize the response for triggering the authentication 467 * flow. 468 * 469 * <p><b>Note:</b> Do not make the provided pending intent 470 * immutable by using {@link android.app.PendingIntent#FLAG_IMMUTABLE} as the 471 * platform needs to fill in the authentication arguments. 472 * 473 * <p>Theme does not work with RemoteViews layout. Avoid hardcoded text color 474 * or background color: Autofill on different platforms may have different themes. 475 * 476 * @param authentication Intent to an activity with your authentication flow. 477 * @param presentation The presentation to visualize the response. 478 * @param ids id of Views that when focused will display the authentication UI. 479 * 480 * @return This builder. 481 * 482 * @throws IllegalArgumentException if any of the following occurs: 483 * <ul> 484 * <li>{@code ids} is {@code null}</li> 485 * <li>{@code ids} is empty</li> 486 * <li>{@code ids} contains a {@code null} element</li> 487 * <li>both {@code authentication} and {@code presentation} are {@code null}</li> 488 * <li>both {@code authentication} and {@code presentation} are non-{@code null}</li> 489 * </ul> 490 * 491 * @throws IllegalStateException if a {@link #setHeader(RemoteViews) header} or a 492 * {@link #setFooter(RemoteViews) footer} are already set for this builder. 493 * 494 * @see android.app.PendingIntent#getIntentSender() 495 * @deprecated Use 496 * {@link #setAuthentication(AutofillId[], IntentSender, Presentations)} 497 * instead. 498 */ 499 @Deprecated 500 @NonNull setAuthentication(@onNull AutofillId[] ids, @Nullable IntentSender authentication, @Nullable RemoteViews presentation)501 public Builder setAuthentication(@NonNull AutofillId[] ids, 502 @Nullable IntentSender authentication, @Nullable RemoteViews presentation) { 503 throwIfDestroyed(); 504 throwIfDisableAutofillCalled(); 505 if (mHeader != null || mFooter != null) { 506 throw new IllegalStateException("Already called #setHeader() or #setFooter()"); 507 } 508 509 if (authentication == null ^ presentation == null) { 510 throw new IllegalArgumentException("authentication and presentation" 511 + " must be both non-null or null"); 512 } 513 mAuthentication = authentication; 514 mPresentation = presentation; 515 mAuthenticationIds = assertValid(ids); 516 return this; 517 } 518 519 /** 520 * Triggers a custom UI before autofilling the screen with any data set in this 521 * response. 522 * 523 * <p><b>Note:</b> Although the name of this method suggests that it should be used just for 524 * authentication flow, it can be used for other advanced flows; see {@link AutofillService} 525 * for examples. 526 * 527 * <p>This method is similar to 528 * {@link #setAuthentication(AutofillId[], IntentSender, RemoteViews)}, but also accepts 529 * an {@link InlinePresentation} presentation which is required for authenticating through 530 * the inline autofill flow. 531 * 532 * <p><b>Note:</b> {@link #setHeader(RemoteViews)} or {@link #setFooter(RemoteViews)} does 533 * not work with {@link InlinePresentation}.</p> 534 * 535 * @param authentication Intent to an activity with your authentication flow. 536 * @param presentation The presentation to visualize the response. 537 * @param inlinePresentation The inlinePresentation to visualize the response inline. 538 * @param ids id of Views that when focused will display the authentication UI. 539 * 540 * @return This builder. 541 * 542 * @throws IllegalArgumentException if any of the following occurs: 543 * <ul> 544 * <li>{@code ids} is {@code null}</li> 545 * <li>{@code ids} is empty</li> 546 * <li>{@code ids} contains a {@code null} element</li> 547 * <li>both {@code authentication} and {@code presentation} are {@code null}</li> 548 * <li>both {@code authentication} and {@code presentation} are non-{@code null}</li> 549 * <li>both {@code authentication} and {@code inlinePresentation} are {@code null}</li> 550 * <li>both {@code authentication} and {@code inlinePresentation} are 551 * non-{@code null}</li> 552 * </ul> 553 * 554 * @throws IllegalStateException if a {@link #setHeader(RemoteViews) header} or a 555 * {@link #setFooter(RemoteViews) footer} are already set for this builder. 556 * 557 * @see android.app.PendingIntent#getIntentSender() 558 * @deprecated Use 559 * {@link #setAuthentication(AutofillId[], IntentSender, Presentations)} 560 * instead. 561 */ 562 @Deprecated 563 @NonNull setAuthentication(@onNull AutofillId[] ids, @Nullable IntentSender authentication, @Nullable RemoteViews presentation, @Nullable InlinePresentation inlinePresentation)564 public Builder setAuthentication(@NonNull AutofillId[] ids, 565 @Nullable IntentSender authentication, @Nullable RemoteViews presentation, 566 @Nullable InlinePresentation inlinePresentation) { 567 return setAuthentication(ids, authentication, presentation, inlinePresentation, null); 568 } 569 570 /** 571 * Triggers a custom UI before autofilling the screen with any data set in this 572 * response. 573 * 574 * <p>This method like 575 * {@link #setAuthentication(AutofillId[], IntentSender, RemoteViews, InlinePresentation)} 576 * but allows setting an {@link InlinePresentation} for the inline suggestion tooltip. 577 * 578 * @deprecated Use 579 * {@link #setAuthentication(AutofillId[], IntentSender, Presentations)} 580 * instead. 581 */ 582 @Deprecated 583 @NonNull setAuthentication(@uppressLintR) @onNull AutofillId[] ids, @Nullable IntentSender authentication, @Nullable RemoteViews presentation, @Nullable InlinePresentation inlinePresentation, @Nullable InlinePresentation inlineTooltipPresentation)584 public Builder setAuthentication(@SuppressLint("ArrayReturn") @NonNull AutofillId[] ids, 585 @Nullable IntentSender authentication, @Nullable RemoteViews presentation, 586 @Nullable InlinePresentation inlinePresentation, 587 @Nullable InlinePresentation inlineTooltipPresentation) { 588 throwIfDestroyed(); 589 throwIfDisableAutofillCalled(); 590 return setAuthentication(ids, authentication, presentation, 591 inlinePresentation, inlineTooltipPresentation, null); 592 } 593 594 /** 595 * Triggers a custom UI before autofilling the screen with any data set in this 596 * response. 597 * 598 * <p><b>Note:</b> Although the name of this method suggests that it should be used just for 599 * authentication flow, it can be used for other advanced flows; see {@link AutofillService} 600 * for examples. 601 * 602 * <p>This is typically useful when a user interaction is required to unlock their 603 * data vault if you encrypt the data set labels and data set data. It is recommended 604 * to encrypt only the sensitive data and not the data set labels which would allow 605 * auth on the data set level leading to a better user experience. Note that if you 606 * use sensitive data as a label, for example an email address, then it should also 607 * be encrypted. The provided {@link android.app.PendingIntent intent} must be an 608 * {@link Activity} which implements your authentication flow. Also if you provide an auth 609 * intent you also need to specify the presentation view to be shown in the fill UI 610 * for the user to trigger your authentication flow. 611 * 612 * <p>When a user triggers autofill, the system launches the provided intent 613 * whose extras will have the 614 * {@link android.view.autofill.AutofillManager#EXTRA_ASSIST_STRUCTURE screen 615 * content} and your {@link android.view.autofill.AutofillManager#EXTRA_CLIENT_STATE 616 * client state}. Once you complete your authentication flow you should set the 617 * {@link Activity} result to {@link android.app.Activity#RESULT_OK} and set the 618 * {@link android.view.autofill.AutofillManager#EXTRA_AUTHENTICATION_RESULT} extra 619 * with the fully populated {@link FillResponse response} (or {@code null} if the screen 620 * cannot be autofilled). 621 * 622 * <p>For example, if you provided an empty {@link FillResponse response} because the 623 * user's data was locked and marked that the response needs an authentication then 624 * in the response returned if authentication succeeds you need to provide all 625 * available data sets some of which may need to be further authenticated, for 626 * example a credit card whose CVV needs to be entered. 627 * 628 * <p>If you provide an authentication intent you must also provide a presentation 629 * which is used to visualize the response for triggering the authentication 630 * flow. 631 * 632 * <p><b>Note:</b> Do not make the provided pending intent 633 * immutable by using {@link android.app.PendingIntent#FLAG_IMMUTABLE} as the 634 * platform needs to fill in the authentication arguments. 635 * 636 * <p><b>Note:</b> {@link #setHeader(RemoteViews)} or {@link #setFooter(RemoteViews)} does 637 * not work with {@link InlinePresentation}.</p> 638 * 639 * @param ids id of Views that when focused will display the authentication UI. 640 * @param authentication Intent to an activity with your authentication flow. 641 * @param presentations The presentations to visualize the response. 642 * 643 * @throws IllegalArgumentException if any of the following occurs: 644 * <ul> 645 * <li>{@code ids} is {@code null}</li> 646 * <li>{@code ids} is empty</li> 647 * <li>{@code ids} contains a {@code null} element</li> 648 * <li>{@code authentication} is {@code null}, but either or both of 649 * {@code presentations.getPresentation()} and 650 * {@code presentations.getInlinePresentation()} is non-{@code null}</li> 651 * <li>{@code authentication} is non-{{@code null}, but both 652 * {@code presentations.getPresentation()} and 653 * {@code presentations.getInlinePresentation()} are {@code null}</li> 654 * </ul> 655 * 656 * @throws IllegalStateException if a {@link #setHeader(RemoteViews) header} or a 657 * {@link #setFooter(RemoteViews) footer} are already set for this builder. 658 * 659 * @return This builder. 660 */ 661 @NonNull setAuthentication(@uppressLintR) @onNull AutofillId[] ids, @Nullable IntentSender authentication, @Nullable Presentations presentations)662 public Builder setAuthentication(@SuppressLint("ArrayReturn") @NonNull AutofillId[] ids, 663 @Nullable IntentSender authentication, 664 @Nullable Presentations presentations) { 665 throwIfDestroyed(); 666 throwIfDisableAutofillCalled(); 667 if (presentations == null) { 668 return setAuthentication(ids, authentication, null, null, null, null); 669 } 670 return setAuthentication(ids, authentication, 671 presentations.getMenuPresentation(), 672 presentations.getInlinePresentation(), 673 presentations.getInlineTooltipPresentation(), 674 presentations.getDialogPresentation()); 675 } 676 677 /** 678 * Triggers a custom UI before autofilling the screen with any data set in this 679 * response. 680 */ 681 @NonNull setAuthentication(@uppressLintR) @onNull AutofillId[] ids, @Nullable IntentSender authentication, @Nullable RemoteViews presentation, @Nullable InlinePresentation inlinePresentation, @Nullable InlinePresentation inlineTooltipPresentation, @Nullable RemoteViews dialogPresentation)682 private Builder setAuthentication(@SuppressLint("ArrayReturn") @NonNull AutofillId[] ids, 683 @Nullable IntentSender authentication, @Nullable RemoteViews presentation, 684 @Nullable InlinePresentation inlinePresentation, 685 @Nullable InlinePresentation inlineTooltipPresentation, 686 @Nullable RemoteViews dialogPresentation) { 687 throwIfDestroyed(); 688 throwIfDisableAutofillCalled(); 689 if (mHeader != null || mFooter != null) { 690 throw new IllegalStateException("Already called #setHeader() or #setFooter()"); 691 } 692 693 if (authentication == null ^ (presentation == null && inlinePresentation == null)) { 694 throw new IllegalArgumentException("authentication and presentation " 695 + "(dropdown or inline), must be both non-null or null"); 696 } 697 mAuthentication = authentication; 698 mPresentation = presentation; 699 mInlinePresentation = inlinePresentation; 700 mInlineTooltipPresentation = inlineTooltipPresentation; 701 mDialogPresentation = dialogPresentation; 702 mAuthenticationIds = assertValid(ids); 703 return this; 704 } 705 706 /** 707 * Specifies views that should not trigger new 708 * {@link AutofillService#onFillRequest(FillRequest, android.os.CancellationSignal, 709 * FillCallback)} requests. 710 * 711 * <p>This is typically used when the service cannot autofill the view; for example, a 712 * text field representing the result of a Captcha challenge. 713 */ 714 @NonNull setIgnoredIds(AutofillId...ids)715 public Builder setIgnoredIds(AutofillId...ids) { 716 throwIfDestroyed(); 717 mIgnoredIds = ids; 718 return this; 719 } 720 721 /** 722 * Adds a new {@link Dataset} to this response. 723 * 724 * <p><b>Note: </b> on Android {@link android.os.Build.VERSION_CODES#O}, the total number of 725 * datasets is limited by the Binder transaction size, so it's recommended to keep it 726 * small (in the range of 10-20 at most) and use pagination by adding a fake 727 * {@link Dataset.Builder#setAuthentication(IntentSender) authenticated dataset} at the end 728 * with a presentation string like "Next 10" that would return a new {@link FillResponse} 729 * with the next 10 datasets, and so on. This limitation was lifted on 730 * Android {@link android.os.Build.VERSION_CODES#O_MR1}, although the Binder transaction 731 * size can still be reached if each dataset itself is too big. 732 * 733 * @return This builder. 734 */ 735 @NonNull addDataset(@ullable Dataset dataset)736 public Builder addDataset(@Nullable Dataset dataset) { 737 throwIfDestroyed(); 738 throwIfDisableAutofillCalled(); 739 if (dataset == null) { 740 return this; 741 } 742 if (mDatasets == null) { 743 mDatasets = new ArrayList<>(); 744 } 745 if (!mDatasets.add(dataset)) { 746 return this; 747 } 748 return this; 749 } 750 751 /** 752 * @hide 753 */ 754 @NonNull setDatasets(ArrayList<Dataset> dataset)755 public Builder setDatasets(ArrayList<Dataset> dataset) { 756 mDatasets = dataset; 757 return this; 758 } 759 760 /** 761 * Sets the {@link SaveInfo} associated with this response. 762 * 763 * @return This builder. 764 */ setSaveInfo(@onNull SaveInfo saveInfo)765 public @NonNull Builder setSaveInfo(@NonNull SaveInfo saveInfo) { 766 throwIfDestroyed(); 767 throwIfDisableAutofillCalled(); 768 mSaveInfo = saveInfo; 769 return this; 770 } 771 772 /** 773 * Sets a bundle with state that is passed to subsequent APIs that manipulate this response. 774 * 775 * <p>You can use this bundle to store intermediate state that is passed to subsequent calls 776 * to {@link AutofillService#onFillRequest(FillRequest, android.os.CancellationSignal, 777 * FillCallback)} and {@link AutofillService#onSaveRequest(SaveRequest, SaveCallback)}, and 778 * you can also retrieve it by calling {@link FillEventHistory.Event#getClientState()}. 779 * 780 * <p>If this method is called on multiple {@link FillResponse} objects for the same 781 * screen, just the latest bundle is passed back to the service. 782 * 783 * @param clientState The custom client state. 784 * @return This builder. 785 */ 786 @NonNull setClientState(@ullable Bundle clientState)787 public Builder setClientState(@Nullable Bundle clientState) { 788 throwIfDestroyed(); 789 throwIfDisableAutofillCalled(); 790 mClientState = clientState; 791 return this; 792 } 793 794 /** 795 * Sets which fields are used for 796 * <a href="AutofillService.html#FieldClassification">field classification</a> 797 * 798 * <p><b>Note:</b> This method automatically adds the 799 * {@link FillResponse#FLAG_TRACK_CONTEXT_COMMITED} to the {@link #setFlags(int) flags}. 800 801 * @throws IllegalArgumentException is length of {@code ids} args is more than 802 * {@link UserData#getMaxFieldClassificationIdsSize()}. 803 * @throws IllegalStateException if {@link #build()} or {@link #disableAutofill(long)} was 804 * already called. 805 * @throws NullPointerException if {@code ids} or any element on it is {@code null}. 806 */ 807 @NonNull setFieldClassificationIds(@onNull AutofillId... ids)808 public Builder setFieldClassificationIds(@NonNull AutofillId... ids) { 809 throwIfDestroyed(); 810 throwIfDisableAutofillCalled(); 811 Preconditions.checkArrayElementsNotNull(ids, "ids"); 812 Preconditions.checkArgumentInRange(ids.length, 1, 813 UserData.getMaxFieldClassificationIdsSize(), "ids length"); 814 mFieldClassificationIds = ids; 815 mFlags |= FLAG_TRACK_CONTEXT_COMMITED; 816 return this; 817 } 818 819 /** 820 * Sets flags changing the response behavior. 821 * 822 * @param flags a combination of {@link #FLAG_TRACK_CONTEXT_COMMITED} and 823 * {@link #FLAG_DISABLE_ACTIVITY_ONLY}, or {@code 0}. 824 * 825 * @return This builder. 826 */ 827 @NonNull setFlags(@illResponseFlags int flags)828 public Builder setFlags(@FillResponseFlags int flags) { 829 throwIfDestroyed(); 830 mFlags = Preconditions.checkFlagsArgument(flags, 831 FLAG_TRACK_CONTEXT_COMMITED | FLAG_DISABLE_ACTIVITY_ONLY | FLAG_DELAY_FILL); 832 return this; 833 } 834 835 /** 836 * Disables autofill for the app or activity. 837 * 838 * <p>This method is useful to optimize performance in cases where the service knows it 839 * can not autofill an app—for example, when the service has a list of "denylisted" 840 * apps such as office suites. 841 * 842 * <p>By default, it disables autofill for all activities in the app, unless the response is 843 * {@link #setFlags(int) flagged} with {@link #FLAG_DISABLE_ACTIVITY_ONLY}. 844 * 845 * <p>Autofill for the app or activity is automatically re-enabled after any of the 846 * following conditions: 847 * 848 * <ol> 849 * <li>{@code duration} milliseconds have passed. 850 * <li>The autofill service for the user has changed. 851 * <li>The device has rebooted. 852 * </ol> 853 * 854 * <p><b>Note:</b> Activities that are running when autofill is re-enabled remain 855 * disabled for autofill until they finish and restart. 856 * 857 * @param duration duration to disable autofill, in milliseconds. 858 * 859 * @return this builder 860 * 861 * @throws IllegalArgumentException if {@code duration} is not a positive number. 862 * @throws IllegalStateException if either {@link #addDataset(Dataset)}, 863 * {@link #setAuthentication(AutofillId[], IntentSender, Presentations)}, 864 * {@link #setSaveInfo(SaveInfo)}, {@link #setClientState(Bundle)}, or 865 * {@link #setFieldClassificationIds(AutofillId...)} was already called. 866 */ 867 @NonNull disableAutofill(long duration)868 public Builder disableAutofill(long duration) { 869 throwIfDestroyed(); 870 if (duration <= 0) { 871 throw new IllegalArgumentException("duration must be greater than 0"); 872 } 873 if (mAuthentication != null || mDatasets != null || mSaveInfo != null 874 || mFieldClassificationIds != null || mClientState != null) { 875 throw new IllegalStateException("disableAutofill() must be the only method called"); 876 } 877 878 mDisableDuration = duration; 879 return this; 880 } 881 882 /** 883 * Overwrites Save/Fill dialog header icon with a specific one specified by resource id. 884 * The image is pulled from the package, so id should be defined in the manifest. 885 * 886 * @param id {@link android.graphics.drawable.Drawable} resource id of the icon to be used. 887 * A value of 0 indicates to use the default header icon. 888 * 889 * @return this builder 890 */ 891 @NonNull setIconResourceId(@rawableRes int id)892 public Builder setIconResourceId(@DrawableRes int id) { 893 throwIfDestroyed(); 894 895 mIconResourceId = id; 896 return this; 897 } 898 899 /** 900 * Overrides the service name in the Save Dialog header with a specific string defined 901 * in the service provider's manifest.xml 902 * 903 * @param id Resoure Id of the custom string defined in the provider's manifest. If set 904 * to 0, the default name will be used. 905 * 906 * @return this builder 907 */ 908 @NonNull setServiceDisplayNameResourceId(@tringRes int id)909 public Builder setServiceDisplayNameResourceId(@StringRes int id) { 910 throwIfDestroyed(); 911 912 mServiceDisplayNameResourceId = id; 913 return this; 914 } 915 916 /** 917 * Whether or not to show the Autofill provider icon inside of the Fill Dialog 918 * 919 * @param show True to show, false to hide. Defaults to true. 920 * 921 * @return this builder 922 */ 923 @NonNull setShowFillDialogIcon(boolean show)924 public Builder setShowFillDialogIcon(boolean show) { 925 throwIfDestroyed(); 926 927 mShowFillDialogIcon = show; 928 return this; 929 } 930 931 /** 932 * Whether or not to show the Autofill provider icon inside of the Save Dialog 933 * 934 * @param show True to show, false to hide. Defaults to true. 935 * 936 * @return this builder 937 */ 938 @NonNull setShowSaveDialogIcon(boolean show)939 public Builder setShowSaveDialogIcon(boolean show) { 940 throwIfDestroyed(); 941 942 mShowSaveDialogIcon = show; 943 return this; 944 } 945 946 /** 947 * Sets a header to be shown as the first element in the list of datasets. 948 * 949 * <p>When this method is called, you must also {@link #addDataset(Dataset) add a dataset}, 950 * otherwise {@link #build()} throws an {@link IllegalStateException}. Similarly, this 951 * method should only be used on {@link FillResponse FillResponses} that do not require 952 * authentication (as the header could have been set directly in the main presentation in 953 * these cases). 954 * 955 * <p>Theme does not work with RemoteViews layout. Avoid hardcoded text color 956 * or background color: Autofill on different platforms may have different themes. 957 * 958 * @param header a presentation to represent the header. This presentation is not clickable 959 * —calling 960 * {@link RemoteViews#setOnClickPendingIntent(int, android.app.PendingIntent)} on it would 961 * have no effect. 962 * 963 * @return this builder 964 * 965 * @throws IllegalStateException if an 966 * {@link #setAuthentication(AutofillId[], IntentSender, Presentations) 967 * authentication} was already set for this builder. 968 */ 969 // TODO(b/69796626): make it sticky / update javadoc 970 @NonNull setHeader(@onNull RemoteViews header)971 public Builder setHeader(@NonNull RemoteViews header) { 972 throwIfDestroyed(); 973 throwIfAuthenticationCalled(); 974 mHeader = Objects.requireNonNull(header); 975 return this; 976 } 977 978 /** 979 * Sets a footer to be shown as the last element in the list of datasets. 980 * 981 * <p>When this method is called, you must also {@link #addDataset(Dataset) add a dataset}, 982 * otherwise {@link #build()} throws an {@link IllegalStateException}. Similarly, this 983 * method should only be used on {@link FillResponse FillResponses} that do not require 984 * authentication (as the footer could have been set directly in the main presentation in 985 * these cases). 986 * 987 * <p>Theme does not work with RemoteViews layout. Avoid hardcoded text color 988 * or background color: Autofill on different platforms may have different themes. 989 * 990 * @param footer a presentation to represent the footer. This presentation is not clickable 991 * —calling 992 * {@link RemoteViews#setOnClickPendingIntent(int, android.app.PendingIntent)} on it would 993 * have no effect. 994 * 995 * @return this builder 996 * 997 * @throws IllegalStateException if the FillResponse 998 * {@link #setAuthentication(AutofillId[], IntentSender, Presentations) 999 * requires authentication}. 1000 */ 1001 // TODO(b/69796626): make it sticky / update javadoc 1002 @NonNull setFooter(@onNull RemoteViews footer)1003 public Builder setFooter(@NonNull RemoteViews footer) { 1004 throwIfDestroyed(); 1005 throwIfAuthenticationCalled(); 1006 mFooter = Objects.requireNonNull(footer); 1007 return this; 1008 } 1009 1010 /** 1011 * Sets a specific {@link UserData} for field classification for this request only. 1012 * 1013 * <p>Any fields in this UserData will override corresponding fields in the generic 1014 * UserData object 1015 * 1016 * @return this builder 1017 * @throws IllegalStateException if the FillResponse 1018 * {@link #setAuthentication(AutofillId[], IntentSender, Presentations) 1019 * requires authentication}. 1020 */ 1021 @NonNull setUserData(@onNull UserData userData)1022 public Builder setUserData(@NonNull UserData userData) { 1023 throwIfDestroyed(); 1024 throwIfAuthenticationCalled(); 1025 mUserData = Objects.requireNonNull(userData); 1026 return this; 1027 } 1028 1029 /** 1030 * Sets target resource IDs of the child view in {@link RemoteViews Presentation Template} 1031 * which will cancel the session when clicked. 1032 * Those targets will be respectively applied to a child of the header, footer and 1033 * each {@link Dataset}. 1034 * 1035 * @param ids array of the resource id. Empty list or non-existing id has no effect. 1036 * 1037 * @return this builder 1038 * 1039 * @throws IllegalStateException if {@link #build()} was already called. 1040 */ 1041 @NonNull setPresentationCancelIds(@ullable int[] ids)1042 public Builder setPresentationCancelIds(@Nullable int[] ids) { 1043 throwIfDestroyed(); 1044 mCancelIds = ids; 1045 return this; 1046 } 1047 1048 /** 1049 * Sets the presentation of header in fill dialog UI. The header should have 1050 * a prompt for what datasets are shown in the dialog. If this is not set, 1051 * the dialog only shows your application icon. 1052 * 1053 * More details about the fill dialog, see 1054 * <a href="Dataset.html#FillDialogUI">fill dialog UI</a> 1055 */ 1056 @NonNull setDialogHeader(@onNull RemoteViews header)1057 public Builder setDialogHeader(@NonNull RemoteViews header) { 1058 throwIfDestroyed(); 1059 Objects.requireNonNull(header); 1060 mDialogHeader = header; 1061 return this; 1062 } 1063 1064 /** 1065 * Sets which fields are used for the fill dialog UI. 1066 * 1067 * More details about the fill dialog, see 1068 * <a href="Dataset.html#FillDialogUI">fill dialog UI</a> 1069 * 1070 * @throws IllegalStateException if {@link #build()} was already called. 1071 * @throws NullPointerException if {@code ids} or any element on it is {@code null}. 1072 */ 1073 @NonNull setFillDialogTriggerIds(@onNull AutofillId... ids)1074 public Builder setFillDialogTriggerIds(@NonNull AutofillId... ids) { 1075 throwIfDestroyed(); 1076 Preconditions.checkArrayElementsNotNull(ids, "ids"); 1077 mFillDialogTriggerIds = ids; 1078 return this; 1079 } 1080 1081 /** 1082 * Builds a new {@link FillResponse} instance. 1083 * 1084 * @throws IllegalStateException if any of the following conditions occur: 1085 * <ol> 1086 * <li>{@link #build()} was already called. 1087 * <li>No call was made to {@link #addDataset(Dataset)}, 1088 * {@link #setAuthentication(AutofillId[], IntentSender, Presentations)}, 1089 * {@link #setSaveInfo(SaveInfo)}, {@link #disableAutofill(long)}, 1090 * {@link #setClientState(Bundle)}, 1091 * or {@link #setFieldClassificationIds(AutofillId...)}. 1092 * <li>{@link #setHeader(RemoteViews)} or {@link #setFooter(RemoteViews)} is called 1093 * without any previous calls to {@link #addDataset(Dataset)}. 1094 * </ol> 1095 * 1096 * @return A built response. 1097 */ 1098 @NonNull build()1099 public FillResponse build() { 1100 throwIfDestroyed(); 1101 if (mAuthentication == null && mDatasets == null && mSaveInfo == null 1102 && mDisableDuration == 0 && mFieldClassificationIds == null 1103 && mClientState == null) { 1104 throw new IllegalStateException("need to provide: at least one DataSet, or a " 1105 + "SaveInfo, or an authentication with a presentation, " 1106 + "or a FieldsDetection, or a client state, or disable autofill"); 1107 } 1108 if (mDatasets == null && (mHeader != null || mFooter != null)) { 1109 throw new IllegalStateException( 1110 "must add at least 1 dataset when using header or footer"); 1111 } 1112 1113 if (mDatasets != null) { 1114 for (final Dataset dataset : mDatasets) { 1115 if (dataset.getFieldInlinePresentation(0) != null) { 1116 mSupportsInlineSuggestions = true; 1117 break; 1118 } 1119 } 1120 } else if (mInlinePresentation != null) { 1121 mSupportsInlineSuggestions = true; 1122 } 1123 1124 mDestroyed = true; 1125 return new FillResponse(this); 1126 } 1127 throwIfDestroyed()1128 private void throwIfDestroyed() { 1129 if (mDestroyed) { 1130 throw new IllegalStateException("Already called #build()"); 1131 } 1132 } 1133 throwIfDisableAutofillCalled()1134 private void throwIfDisableAutofillCalled() { 1135 if (mDisableDuration > 0) { 1136 throw new IllegalStateException("Already called #disableAutofill()"); 1137 } 1138 } 1139 throwIfAuthenticationCalled()1140 private void throwIfAuthenticationCalled() { 1141 if (mAuthentication != null) { 1142 throw new IllegalStateException("Already called #setAuthentication()"); 1143 } 1144 } 1145 } 1146 1147 ///////////////////////////////////// 1148 // Object "contract" methods. // 1149 ///////////////////////////////////// 1150 @Override toString()1151 public String toString() { 1152 if (!sDebug) return super.toString(); 1153 1154 // TODO: create a dump() method instead 1155 final StringBuilder builder = new StringBuilder( 1156 "FillResponse : [mRequestId=" + mRequestId); 1157 if (mDatasets != null) { 1158 builder.append(", datasets=").append(mDatasets.getList()); 1159 } 1160 if (mSaveInfo != null) { 1161 builder.append(", saveInfo=").append(mSaveInfo); 1162 } 1163 if (mClientState != null) { 1164 builder.append(", hasClientState"); 1165 } 1166 if (mPresentation != null) { 1167 builder.append(", hasPresentation"); 1168 } 1169 if (mInlinePresentation != null) { 1170 builder.append(", hasInlinePresentation"); 1171 } 1172 if (mInlineTooltipPresentation != null) { 1173 builder.append(", hasInlineTooltipPresentation"); 1174 } 1175 if (mDialogPresentation != null) { 1176 builder.append(", hasDialogPresentation"); 1177 } 1178 if (mDialogHeader != null) { 1179 builder.append(", hasDialogHeader"); 1180 } 1181 if (mHeader != null) { 1182 builder.append(", hasHeader"); 1183 } 1184 if (mFooter != null) { 1185 builder.append(", hasFooter"); 1186 } 1187 if (mAuthentication != null) { 1188 builder.append(", hasAuthentication"); 1189 } 1190 if (mAuthenticationIds != null) { 1191 builder.append(", authenticationIds=").append(Arrays.toString(mAuthenticationIds)); 1192 } 1193 if (mFillDialogTriggerIds != null) { 1194 builder.append(", fillDialogTriggerIds=") 1195 .append(Arrays.toString(mFillDialogTriggerIds)); 1196 } 1197 builder.append(", disableDuration=").append(mDisableDuration); 1198 if (mFlags != 0) { 1199 builder.append(", flags=").append(mFlags); 1200 } 1201 if (mFieldClassificationIds != null) { 1202 builder.append(Arrays.toString(mFieldClassificationIds)); 1203 } 1204 if (mUserData != null) { 1205 builder.append(", userData=").append(mUserData); 1206 } 1207 if (mCancelIds != null) { 1208 builder.append(", mCancelIds=").append(mCancelIds.length); 1209 } 1210 builder.append(", mSupportInlinePresentations=").append(mSupportsInlineSuggestions); 1211 return builder.append("]").toString(); 1212 } 1213 1214 ///////////////////////////////////// 1215 // Parcelable "contract" methods. // 1216 ///////////////////////////////////// 1217 1218 @Override describeContents()1219 public int describeContents() { 1220 return 0; 1221 } 1222 1223 @Override writeToParcel(Parcel parcel, int flags)1224 public void writeToParcel(Parcel parcel, int flags) { 1225 parcel.writeParcelable(mDatasets, flags); 1226 parcel.writeParcelable(mSaveInfo, flags); 1227 parcel.writeParcelable(mClientState, flags); 1228 parcel.writeParcelableArray(mAuthenticationIds, flags); 1229 parcel.writeParcelable(mAuthentication, flags); 1230 parcel.writeParcelable(mPresentation, flags); 1231 parcel.writeParcelable(mInlinePresentation, flags); 1232 parcel.writeParcelable(mInlineTooltipPresentation, flags); 1233 parcel.writeParcelable(mDialogPresentation, flags); 1234 parcel.writeParcelable(mDialogHeader, flags); 1235 parcel.writeParcelableArray(mFillDialogTriggerIds, flags); 1236 parcel.writeParcelable(mHeader, flags); 1237 parcel.writeParcelable(mFooter, flags); 1238 parcel.writeParcelable(mUserData, flags); 1239 parcel.writeParcelableArray(mIgnoredIds, flags); 1240 parcel.writeLong(mDisableDuration); 1241 parcel.writeParcelableArray(mFieldClassificationIds, flags); 1242 parcel.writeParcelableArray(mDetectedFieldTypes, flags); 1243 parcel.writeInt(mIconResourceId); 1244 parcel.writeInt(mServiceDisplayNameResourceId); 1245 parcel.writeBoolean(mShowFillDialogIcon); 1246 parcel.writeBoolean(mShowSaveDialogIcon); 1247 parcel.writeInt(mFlags); 1248 parcel.writeIntArray(mCancelIds); 1249 parcel.writeInt(mRequestId); 1250 } 1251 1252 public static final @android.annotation.NonNull Parcelable.Creator<FillResponse> CREATOR = 1253 new Parcelable.Creator<FillResponse>() { 1254 @Override 1255 public FillResponse createFromParcel(Parcel parcel) { 1256 // Always go through the builder to ensure the data ingested by 1257 // the system obeys the contract of the builder to avoid attacks 1258 // using specially crafted parcels. 1259 final Builder builder = new Builder(); 1260 final ParceledListSlice<Dataset> datasetSlice = parcel.readParcelable(null, android.content.pm.ParceledListSlice.class); 1261 final List<Dataset> datasets = (datasetSlice != null) ? datasetSlice.getList() : null; 1262 final int datasetCount = (datasets != null) ? datasets.size() : 0; 1263 for (int i = 0; i < datasetCount; i++) { 1264 builder.addDataset(datasets.get(i)); 1265 } 1266 builder.setSaveInfo(parcel.readParcelable(null, android.service.autofill.SaveInfo.class)); 1267 builder.setClientState(parcel.readParcelable(null, android.os.Bundle.class)); 1268 1269 // Sets authentication state. 1270 final AutofillId[] authenticationIds = parcel.readParcelableArray(null, 1271 AutofillId.class); 1272 final IntentSender authentication = parcel.readParcelable(null, android.content.IntentSender.class); 1273 final RemoteViews presentation = parcel.readParcelable(null, android.widget.RemoteViews.class); 1274 final InlinePresentation inlinePresentation = parcel.readParcelable(null, android.service.autofill.InlinePresentation.class); 1275 final InlinePresentation inlineTooltipPresentation = parcel.readParcelable(null, android.service.autofill.InlinePresentation.class); 1276 final RemoteViews dialogPresentation = parcel.readParcelable(null, android.widget.RemoteViews.class); 1277 if (authenticationIds != null) { 1278 builder.setAuthentication(authenticationIds, authentication, presentation, 1279 inlinePresentation, inlineTooltipPresentation, dialogPresentation); 1280 } 1281 final RemoteViews dialogHeader = parcel.readParcelable(null, android.widget.RemoteViews.class); 1282 if (dialogHeader != null) { 1283 builder.setDialogHeader(dialogHeader); 1284 } 1285 final AutofillId[] triggerIds = parcel.readParcelableArray(null, AutofillId.class); 1286 if (triggerIds != null) { 1287 builder.setFillDialogTriggerIds(triggerIds); 1288 } 1289 final RemoteViews header = parcel.readParcelable(null, android.widget.RemoteViews.class); 1290 if (header != null) { 1291 builder.setHeader(header); 1292 } 1293 final RemoteViews footer = parcel.readParcelable(null, android.widget.RemoteViews.class); 1294 if (footer != null) { 1295 builder.setFooter(footer); 1296 } 1297 final UserData userData = parcel.readParcelable(null, android.service.autofill.UserData.class); 1298 if (userData != null) { 1299 builder.setUserData(userData); 1300 } 1301 1302 builder.setIgnoredIds(parcel.readParcelableArray(null, AutofillId.class)); 1303 final long disableDuration = parcel.readLong(); 1304 if (disableDuration > 0) { 1305 builder.disableAutofill(disableDuration); 1306 } 1307 final AutofillId[] fieldClassifactionIds = 1308 parcel.readParcelableArray(null, AutofillId.class); 1309 if (fieldClassifactionIds != null) { 1310 builder.setFieldClassificationIds(fieldClassifactionIds); 1311 } 1312 1313 final FieldClassification[] detectedFields = 1314 parcel.readParcelableArray(null, FieldClassification.class); 1315 if (detectedFields != null) { 1316 builder.setDetectedFieldClassifications(Set.of(detectedFields)); 1317 } 1318 1319 builder.setIconResourceId(parcel.readInt()); 1320 builder.setServiceDisplayNameResourceId(parcel.readInt()); 1321 builder.setShowFillDialogIcon(parcel.readBoolean()); 1322 builder.setShowSaveDialogIcon(parcel.readBoolean()); 1323 builder.setFlags(parcel.readInt()); 1324 final int[] cancelIds = parcel.createIntArray(); 1325 builder.setPresentationCancelIds(cancelIds); 1326 1327 final FillResponse response = builder.build(); 1328 response.setRequestId(parcel.readInt()); 1329 1330 return response; 1331 } 1332 1333 @Override 1334 public FillResponse[] newArray(int size) { 1335 return new FillResponse[size]; 1336 } 1337 }; 1338 } 1339