FillResponse.java revision 36b86c28f88e4c7853a4255a0fd9b754cbb547c4
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
17package android.service.autofill;
18
19import static android.service.autofill.AutofillServiceHelper.assertValid;
20import static android.service.autofill.FillRequest.INVALID_REQUEST_ID;
21import static android.view.autofill.Helper.sDebug;
22
23import android.annotation.IntDef;
24import android.annotation.NonNull;
25import android.annotation.Nullable;
26import android.annotation.TestApi;
27import android.app.Activity;
28import android.content.IntentSender;
29import android.content.pm.ParceledListSlice;
30import android.os.Bundle;
31import android.os.Parcel;
32import android.os.Parcelable;
33import android.view.autofill.AutofillId;
34import android.widget.RemoteViews;
35
36import com.android.internal.util.Preconditions;
37
38import java.lang.annotation.Retention;
39import java.lang.annotation.RetentionPolicy;
40import java.util.ArrayList;
41import java.util.Arrays;
42import java.util.List;
43
44/**
45 * Response for an {@link
46 * AutofillService#onFillRequest(FillRequest, android.os.CancellationSignal, FillCallback)}.
47 *
48 * <p>See the main {@link AutofillService} documentation for more details and examples.
49 */
50public final class FillResponse implements Parcelable {
51
52    /**
53     * Flag used to generate {@link FillEventHistory.Event events} of type
54     * {@link FillEventHistory.Event#TYPE_CONTEXT_COMMITTED}&mdash;if this flag is not passed to
55     * {@link Builder#setFlags(int)}, these events are not generated.
56     */
57    public static final int FLAG_TRACK_CONTEXT_COMMITED = 0x1;
58
59    /**
60     * Flag used to change the behavior of {@link FillResponse.Builder#disableAutofill(long)}&mdash;
61     * when this flag is passed to {@link Builder#setFlags(int)}, autofill is disabled only for the
62     * activiy that generated the {@link FillRequest}, not the whole app.
63     */
64    public static final int FLAG_DISABLE_ACTIVITY_ONLY = 0x2;
65
66    /** @hide */
67    @IntDef(flag = true, prefix = { "FLAG_" }, value = {
68            FLAG_TRACK_CONTEXT_COMMITED,
69            FLAG_DISABLE_ACTIVITY_ONLY
70    })
71    @Retention(RetentionPolicy.SOURCE)
72    @interface FillResponseFlags {}
73
74    private final @Nullable ParceledListSlice<Dataset> mDatasets;
75    private final @Nullable SaveInfo mSaveInfo;
76    private final @Nullable Bundle mClientState;
77    private final @Nullable RemoteViews mPresentation;
78    private final @Nullable RemoteViews mHeader;
79    private final @Nullable RemoteViews mFooter;
80    private final @Nullable IntentSender mAuthentication;
81    private final @Nullable AutofillId[] mAuthenticationIds;
82    private final @Nullable AutofillId[] mIgnoredIds;
83    private final long mDisableDuration;
84    private final @Nullable AutofillId[] mFieldClassificationIds;
85    private final int mFlags;
86    private int mRequestId;
87
88    private FillResponse(@NonNull Builder builder) {
89        mDatasets = (builder.mDatasets != null) ? new ParceledListSlice<>(builder.mDatasets) : null;
90        mSaveInfo = builder.mSaveInfo;
91        mClientState = builder.mClientState;
92        mPresentation = builder.mPresentation;
93        mHeader = builder.mHeader;
94        mFooter = builder.mFooter;
95        mAuthentication = builder.mAuthentication;
96        mAuthenticationIds = builder.mAuthenticationIds;
97        mIgnoredIds = builder.mIgnoredIds;
98        mDisableDuration = builder.mDisableDuration;
99        mFieldClassificationIds = builder.mFieldClassificationIds;
100        mFlags = builder.mFlags;
101        mRequestId = INVALID_REQUEST_ID;
102    }
103
104    /** @hide */
105    public @Nullable Bundle getClientState() {
106        return mClientState;
107    }
108
109    /** @hide */
110    public @Nullable List<Dataset> getDatasets() {
111        return (mDatasets != null) ? mDatasets.getList() : null;
112    }
113
114    /** @hide */
115    public @Nullable SaveInfo getSaveInfo() {
116        return mSaveInfo;
117    }
118
119    /** @hide */
120    public @Nullable RemoteViews getPresentation() {
121        return mPresentation;
122    }
123
124    /** @hide */
125    public @Nullable RemoteViews getHeader() {
126        return mHeader;
127    }
128
129    /** @hide */
130    public @Nullable RemoteViews getFooter() {
131        return mFooter;
132    }
133
134    /** @hide */
135    public @Nullable IntentSender getAuthentication() {
136        return mAuthentication;
137    }
138
139    /** @hide */
140    public @Nullable AutofillId[] getAuthenticationIds() {
141        return mAuthenticationIds;
142    }
143
144    /** @hide */
145    public @Nullable AutofillId[] getIgnoredIds() {
146        return mIgnoredIds;
147    }
148
149    /** @hide */
150    public long getDisableDuration() {
151        return mDisableDuration;
152    }
153
154    /** @hide */
155    public @Nullable AutofillId[] getFieldClassificationIds() {
156        return mFieldClassificationIds;
157    }
158
159    /** @hide */
160    @TestApi
161    public int getFlags() {
162        return mFlags;
163    }
164
165    /**
166     * Associates a {@link FillResponse} to a request.
167     *
168     * <p>Set inside of the {@link FillCallback} code, not the {@link AutofillService}.
169     *
170     * @param requestId The id of the request to associate the response to.
171     *
172     * @hide
173     */
174    public void setRequestId(int requestId) {
175        mRequestId = requestId;
176    }
177
178    /** @hide */
179    public int getRequestId() {
180        return mRequestId;
181    }
182
183    /**
184     * Builder for {@link FillResponse} objects. You must to provide at least
185     * one dataset or set an authentication intent with a presentation view.
186     */
187    public static final class Builder {
188        private ArrayList<Dataset> mDatasets;
189        private SaveInfo mSaveInfo;
190        private Bundle mClientState;
191        private RemoteViews mPresentation;
192        private RemoteViews mHeader;
193        private RemoteViews mFooter;
194        private IntentSender mAuthentication;
195        private AutofillId[] mAuthenticationIds;
196        private AutofillId[] mIgnoredIds;
197        private long mDisableDuration;
198        private AutofillId[] mFieldClassificationIds;
199        private int mFlags;
200        private boolean mDestroyed;
201
202        /**
203         * Triggers a custom UI before before autofilling the screen with any data set in this
204         * response.
205         *
206         * <p><b>Note:</b> Although the name of this method suggests that it should be used just for
207         * authentication flow, it can be used for other advanced flows; see {@link AutofillService}
208         * for examples.
209         *
210         * <p>This is typically useful when a user interaction is required to unlock their
211         * data vault if you encrypt the data set labels and data set data. It is recommended
212         * to encrypt only the sensitive data and not the data set labels which would allow
213         * auth on the data set level leading to a better user experience. Note that if you
214         * use sensitive data as a label, for example an email address, then it should also
215         * be encrypted. The provided {@link android.app.PendingIntent intent} must be an
216         * {@link Activity} which implements your authentication flow. Also if you provide an auth
217         * intent you also need to specify the presentation view to be shown in the fill UI
218         * for the user to trigger your authentication flow.
219         *
220         * <p>When a user triggers autofill, the system launches the provided intent
221         * whose extras will have the
222         * {@link android.view.autofill.AutofillManager#EXTRA_ASSIST_STRUCTURE screen
223         * content} and your {@link android.view.autofill.AutofillManager#EXTRA_CLIENT_STATE
224         * client state}. Once you complete your authentication flow you should set the
225         * {@link Activity} result to {@link android.app.Activity#RESULT_OK} and set the
226         * {@link android.view.autofill.AutofillManager#EXTRA_AUTHENTICATION_RESULT} extra
227         * with the fully populated {@link FillResponse response} (or {@code null} if the screen
228         * cannot be autofilled).
229         *
230         * <p>For example, if you provided an empty {@link FillResponse response} because the
231         * user's data was locked and marked that the response needs an authentication then
232         * in the response returned if authentication succeeds you need to provide all
233         * available data sets some of which may need to be further authenticated, for
234         * example a credit card whose CVV needs to be entered.
235         *
236         * <p>If you provide an authentication intent you must also provide a presentation
237         * which is used to visualize visualize the response for triggering the authentication
238         * flow.
239         *
240         * <p><b>Note:</b> Do not make the provided pending intent
241         * immutable by using {@link android.app.PendingIntent#FLAG_IMMUTABLE} as the
242         * platform needs to fill in the authentication arguments.
243         *
244         * <p>Theme does not work with RemoteViews layout. Avoid hardcoded text color
245         * or background color: Autofill on different platforms may have different themes.
246         *
247         * @param authentication Intent to an activity with your authentication flow.
248         * @param presentation The presentation to visualize the response.
249         * @param ids id of Views that when focused will display the authentication UI.
250         *
251         * @return This builder.
252         *
253         * @throws IllegalArgumentException if any of the following occurs:
254         * <ul>
255         *   <li>{@code ids} is {@code null}</li>
256         *   <li>{@code ids} is empty</li>
257         *   <li>{@code ids} contains a {@code null} element</li>
258         *   <li>both {@code authentication} and {@code presentation} are {@code null}</li>
259         *   <li>both {@code authentication} and {@code presentation} are non-{@code null}</li>
260         * </ul>
261         *
262         * @throws IllegalStateException if a {@link #setHeader(RemoteViews) header} or a
263         * {@link #setFooter(RemoteViews) footer} are already set for this builder.
264         *
265         * @see android.app.PendingIntent#getIntentSender()
266         */
267        public @NonNull Builder setAuthentication(@NonNull AutofillId[] ids,
268                @Nullable IntentSender authentication, @Nullable RemoteViews presentation) {
269            throwIfDestroyed();
270            throwIfDisableAutofillCalled();
271            if (mHeader != null || mFooter != null) {
272                throw new IllegalStateException("Already called #setHeader() or #setFooter()");
273            }
274
275            if (authentication == null ^ presentation == null) {
276                throw new IllegalArgumentException("authentication and presentation"
277                        + " must be both non-null or null");
278            }
279            mAuthentication = authentication;
280            mPresentation = presentation;
281            mAuthenticationIds = assertValid(ids);
282            return this;
283        }
284
285        /**
286         * Specifies views that should not trigger new
287         * {@link AutofillService#onFillRequest(FillRequest, android.os.CancellationSignal,
288         * FillCallback)} requests.
289         *
290         * <p>This is typically used when the service cannot autofill the view; for example, a
291         * text field representing the result of a Captcha challenge.
292         */
293        public Builder setIgnoredIds(AutofillId...ids) {
294            throwIfDestroyed();
295            mIgnoredIds = ids;
296            return this;
297        }
298
299        /**
300         * Adds a new {@link Dataset} to this response.
301         *
302         * <p><b>Note: </b> on Android {@link android.os.Build.VERSION_CODES#O}, the total number of
303         * datasets is limited by the Binder transaction size, so it's recommended to keep it
304         * small (in the range of 10-20 at most) and use pagination by adding a fake
305         * {@link Dataset.Builder#setAuthentication(IntentSender) authenticated dataset} at the end
306         * with a presentation string like "Next 10" that would return a new {@link FillResponse}
307         * with the next 10 datasets, and so on. This limitation was lifted on
308         * Android {@link android.os.Build.VERSION_CODES#O_MR1}, although the Binder transaction
309         * size can still be reached if each dataset itself is too big.
310         *
311         * @return This builder.
312         */
313        public @NonNull Builder addDataset(@Nullable Dataset dataset) {
314            throwIfDestroyed();
315            throwIfDisableAutofillCalled();
316            if (dataset == null) {
317                return this;
318            }
319            if (mDatasets == null) {
320                mDatasets = new ArrayList<>();
321            }
322            if (!mDatasets.add(dataset)) {
323                return this;
324            }
325            return this;
326        }
327
328        /**
329         * Sets the {@link SaveInfo} associated with this response.
330         *
331         * @return This builder.
332         */
333        public @NonNull Builder setSaveInfo(@NonNull SaveInfo saveInfo) {
334            throwIfDestroyed();
335            throwIfDisableAutofillCalled();
336            mSaveInfo = saveInfo;
337            return this;
338        }
339
340        /**
341         * Sets a bundle with state that is passed to subsequent APIs that manipulate this response.
342         *
343         * <p>You can use this bundle to store intermediate state that is passed to subsequent calls
344         * to {@link AutofillService#onFillRequest(FillRequest, android.os.CancellationSignal,
345         * FillCallback)} and {@link AutofillService#onSaveRequest(SaveRequest, SaveCallback)}, and
346         * you can also retrieve it by calling {@link FillEventHistory.Event#getClientState()}.
347         *
348         * <p>If this method is called on multiple {@link FillResponse} objects for the same
349         * screen, just the latest bundle is passed back to the service.
350         *
351         * @param clientState The custom client state.
352         * @return This builder.
353         */
354        public Builder setClientState(@Nullable Bundle clientState) {
355            throwIfDestroyed();
356            throwIfDisableAutofillCalled();
357            mClientState = clientState;
358            return this;
359        }
360
361        /**
362         * Sets which fields are used for
363         * <a href="AutofillService.html#FieldClassification">field classification</a>
364         *
365         * <p><b>Note:</b> This method automatically adds the
366         * {@link FillResponse#FLAG_TRACK_CONTEXT_COMMITED} to the {@link #setFlags(int) flags}.
367
368         * @throws IllegalArgumentException is length of {@code ids} args is more than
369         * {@link UserData#getMaxFieldClassificationIdsSize()}.
370         * @throws IllegalStateException if {@link #build()} or {@link #disableAutofill(long)} was
371         * already called.
372         * @throws NullPointerException if {@code ids} or any element on it is {@code null}.
373         */
374        public Builder setFieldClassificationIds(@NonNull AutofillId... ids) {
375            throwIfDestroyed();
376            throwIfDisableAutofillCalled();
377            Preconditions.checkArrayElementsNotNull(ids, "ids");
378            Preconditions.checkArgumentInRange(ids.length, 1,
379                    UserData.getMaxFieldClassificationIdsSize(), "ids length");
380            mFieldClassificationIds = ids;
381            mFlags |= FLAG_TRACK_CONTEXT_COMMITED;
382            return this;
383        }
384
385        /**
386         * Sets flags changing the response behavior.
387         *
388         * @param flags a combination of {@link #FLAG_TRACK_CONTEXT_COMMITED} and
389         * {@link #FLAG_DISABLE_ACTIVITY_ONLY}, or {@code 0}.
390         *
391         * @return This builder.
392         */
393        public Builder setFlags(@FillResponseFlags int flags) {
394            throwIfDestroyed();
395            mFlags = Preconditions.checkFlagsArgument(flags,
396                    FLAG_TRACK_CONTEXT_COMMITED | FLAG_DISABLE_ACTIVITY_ONLY);
397            return this;
398        }
399
400        /**
401         * Disables autofill for the app or activity.
402         *
403         * <p>This method is useful to optimize performance in cases where the service knows it
404         * can not autofill an app&mdash;for example, when the service has a list of "blacklisted"
405         * apps such as office suites.
406         *
407         * <p>By default, it disables autofill for all activities in the app, unless the response is
408         * {@link #setFlags(int) flagged} with {@link #FLAG_DISABLE_ACTIVITY_ONLY}.
409         *
410         * <p>Autofill for the app or activity is automatically re-enabled after any of the
411         * following conditions:
412         *
413         * <ol>
414         *   <li>{@code duration} milliseconds have passed.
415         *   <li>The autofill service for the user has changed.
416         *   <li>The device has rebooted.
417         * </ol>
418         *
419         * <p><b>Note:</b> Activities that are running when autofill is re-enabled remain
420         * disabled for autofill until they finish and restart.
421         *
422         * @param duration duration to disable autofill, in milliseconds.
423         *
424         * @return this builder
425         *
426         * @throws IllegalArgumentException if {@code duration} is not a positive number.
427         * @throws IllegalStateException if either {@link #addDataset(Dataset)},
428         *       {@link #setAuthentication(AutofillId[], IntentSender, RemoteViews)},
429         *       {@link #setSaveInfo(SaveInfo)}, {@link #setClientState(Bundle)}, or
430         *       {@link #setFieldClassificationIds(AutofillId...)} was already called.
431         */
432        public Builder disableAutofill(long duration) {
433            throwIfDestroyed();
434            if (duration <= 0) {
435                throw new IllegalArgumentException("duration must be greater than 0");
436            }
437            if (mAuthentication != null || mDatasets != null || mSaveInfo != null
438                    || mFieldClassificationIds != null || mClientState != null) {
439                throw new IllegalStateException("disableAutofill() must be the only method called");
440            }
441
442            mDisableDuration = duration;
443            return this;
444        }
445
446        /**
447         * Sets a header to be shown as the first element in the list of datasets.
448         *
449         * <p>When this method is called, you must also {@link #addDataset(Dataset) add a dataset},
450         * otherwise {@link #build()} throws an {@link IllegalStateException}. Similarly, this
451         * method should only be used on {@link FillResponse FillResponses} that do not require
452         * authentication (as the header could have been set directly in the main presentation in
453         * these cases).
454         *
455         * <p>Theme does not work with RemoteViews layout. Avoid hardcoded text color
456         * or background color: Autofill on different platforms may have different themes.
457         *
458         * @param header a presentation to represent the header. This presentation is not clickable
459         * &mdash;calling
460         * {@link RemoteViews#setOnClickPendingIntent(int, android.app.PendingIntent)} on it would
461         * have no effect.
462         *
463         * @return this builder
464         *
465         * @throws IllegalStateException if an
466         * {@link #setAuthentication(AutofillId[], IntentSender, RemoteViews) authentication} was
467         * already set for this builder.
468         */
469        // TODO(b/69796626): make it sticky / update javadoc
470        public Builder setHeader(@NonNull RemoteViews header) {
471            throwIfDestroyed();
472            throwIfAuthenticationCalled();
473            mHeader = Preconditions.checkNotNull(header);
474            return this;
475        }
476
477        /**
478         * Sets a footer to be shown as the last element in the list of datasets.
479         *
480         * <p>When this method is called, you must also {@link #addDataset(Dataset) add a dataset},
481         * otherwise {@link #build()} throws an {@link IllegalStateException}. Similarly, this
482         * method should only be used on {@link FillResponse FillResponses} that do not require
483         * authentication (as the footer could have been set directly in the main presentation in
484         * these cases).
485         *
486         * <p>Theme does not work with RemoteViews layout. Avoid hardcoded text color
487         * or background color: Autofill on different platforms may have different themes.
488         *
489         * @param footer a presentation to represent the footer. This presentation is not clickable
490         * &mdash;calling
491         * {@link RemoteViews#setOnClickPendingIntent(int, android.app.PendingIntent)} on it would
492         * have no effect.
493         *
494         * @return this builder
495         *
496         * @throws IllegalStateException if the FillResponse
497         * {@link #setAuthentication(AutofillId[], IntentSender, RemoteViews)
498         * requires authentication}.
499         */
500        // TODO(b/69796626): make it sticky / update javadoc
501        public Builder setFooter(@NonNull RemoteViews footer) {
502            throwIfDestroyed();
503            throwIfAuthenticationCalled();
504            mFooter = Preconditions.checkNotNull(footer);
505            return this;
506        }
507
508        /**
509         * Builds a new {@link FillResponse} instance.
510         *
511         * @throws IllegalStateException if any of the following conditions occur:
512         * <ol>
513         *   <li>{@link #build()} was already called.
514         *   <li>No call was made to {@link #addDataset(Dataset)},
515         *       {@link #setAuthentication(AutofillId[], IntentSender, RemoteViews)},
516         *       {@link #setSaveInfo(SaveInfo)}, {@link #disableAutofill(long)},
517         *       {@link #setClientState(Bundle)},
518         *       or {@link #setFieldClassificationIds(AutofillId...)}.
519         *   <li>{@link #setHeader(RemoteViews)} or {@link #setFooter(RemoteViews)} is called
520         *       without any previous calls to {@link #addDataset(Dataset)}.
521         * </ol>
522         *
523         * @return A built response.
524         */
525        public FillResponse build() {
526            throwIfDestroyed();
527            if (mAuthentication == null && mDatasets == null && mSaveInfo == null
528                    && mDisableDuration == 0 && mFieldClassificationIds == null
529                    && mClientState == null) {
530                throw new IllegalStateException("need to provide: at least one DataSet, or a "
531                        + "SaveInfo, or an authentication with a presentation, "
532                        + "or a FieldsDetection, or a client state, or disable autofill");
533            }
534            if (mDatasets == null && (mHeader != null || mFooter != null)) {
535                throw new IllegalStateException(
536                        "must add at least 1 dataset when using header or footer");
537            }
538            mDestroyed = true;
539            return new FillResponse(this);
540        }
541
542        private void throwIfDestroyed() {
543            if (mDestroyed) {
544                throw new IllegalStateException("Already called #build()");
545            }
546        }
547
548        private void throwIfDisableAutofillCalled() {
549            if (mDisableDuration > 0) {
550                throw new IllegalStateException("Already called #disableAutofill()");
551            }
552        }
553
554        private void throwIfAuthenticationCalled() {
555            if (mAuthentication != null) {
556                throw new IllegalStateException("Already called #setAuthentication()");
557            }
558        }
559    }
560
561    /////////////////////////////////////
562    // Object "contract" methods. //
563    /////////////////////////////////////
564    @Override
565    public String toString() {
566        if (!sDebug) return super.toString();
567
568        // TODO: create a dump() method instead
569        final StringBuilder builder = new StringBuilder(
570                "FillResponse : [mRequestId=" + mRequestId);
571        if (mDatasets != null) {
572            builder.append(", datasets=").append(mDatasets.getList());
573        }
574        if (mSaveInfo != null) {
575            builder.append(", saveInfo=").append(mSaveInfo);
576        }
577        if (mClientState != null) {
578            builder.append(", hasClientState");
579        }
580        if (mPresentation != null) {
581            builder.append(", hasPresentation");
582        }
583        if (mHeader != null) {
584            builder.append(", hasHeader");
585        }
586        if (mFooter != null) {
587            builder.append(", hasFooter");
588        }
589        if (mAuthentication != null) {
590            builder.append(", hasAuthentication");
591        }
592        if (mAuthenticationIds != null) {
593            builder.append(", authenticationIds=").append(Arrays.toString(mAuthenticationIds));
594        }
595        builder.append(", disableDuration=").append(mDisableDuration);
596        if (mFlags != 0) {
597            builder.append(", flags=").append(mFlags);
598        }
599        if (mFieldClassificationIds != null) {
600            builder.append(Arrays.toString(mFieldClassificationIds));
601        }
602        return builder.append("]").toString();
603    }
604
605    /////////////////////////////////////
606    // Parcelable "contract" methods. //
607    /////////////////////////////////////
608
609    @Override
610    public int describeContents() {
611        return 0;
612    }
613
614    @Override
615    public void writeToParcel(Parcel parcel, int flags) {
616        parcel.writeParcelable(mDatasets, flags);
617        parcel.writeParcelable(mSaveInfo, flags);
618        parcel.writeParcelable(mClientState, flags);
619        parcel.writeParcelableArray(mAuthenticationIds, flags);
620        parcel.writeParcelable(mAuthentication, flags);
621        parcel.writeParcelable(mPresentation, flags);
622        parcel.writeParcelable(mHeader, flags);
623        parcel.writeParcelable(mFooter, flags);
624        parcel.writeParcelableArray(mIgnoredIds, flags);
625        parcel.writeLong(mDisableDuration);
626        parcel.writeParcelableArray(mFieldClassificationIds, flags);
627        parcel.writeInt(mFlags);
628        parcel.writeInt(mRequestId);
629    }
630
631    public static final Parcelable.Creator<FillResponse> CREATOR =
632            new Parcelable.Creator<FillResponse>() {
633        @Override
634        public FillResponse createFromParcel(Parcel parcel) {
635            // Always go through the builder to ensure the data ingested by
636            // the system obeys the contract of the builder to avoid attacks
637            // using specially crafted parcels.
638            final Builder builder = new Builder();
639            final ParceledListSlice<Dataset> datasetSlice = parcel.readParcelable(null);
640            final List<Dataset> datasets = (datasetSlice != null) ? datasetSlice.getList() : null;
641            final int datasetCount = (datasets != null) ? datasets.size() : 0;
642            for (int i = 0; i < datasetCount; i++) {
643                builder.addDataset(datasets.get(i));
644            }
645            builder.setSaveInfo(parcel.readParcelable(null));
646            builder.setClientState(parcel.readParcelable(null));
647
648            // Sets authentication state.
649            final AutofillId[] authenticationIds = parcel.readParcelableArray(null,
650                    AutofillId.class);
651            final IntentSender authentication = parcel.readParcelable(null);
652            final RemoteViews presentation = parcel.readParcelable(null);
653            if (authenticationIds != null) {
654                builder.setAuthentication(authenticationIds, authentication, presentation);
655            }
656            final RemoteViews header = parcel.readParcelable(null);
657            if (header != null) {
658                builder.setHeader(header);
659            }
660            final RemoteViews footer = parcel.readParcelable(null);
661            if (footer != null) {
662                builder.setFooter(footer);
663            }
664
665            builder.setIgnoredIds(parcel.readParcelableArray(null, AutofillId.class));
666            final long disableDuration = parcel.readLong();
667            if (disableDuration > 0) {
668                builder.disableAutofill(disableDuration);
669            }
670            final AutofillId[] fieldClassifactionIds =
671                    parcel.readParcelableArray(null, AutofillId.class);
672            if (fieldClassifactionIds != null) {
673                builder.setFieldClassificationIds(fieldClassifactionIds);
674            }
675            builder.setFlags(parcel.readInt());
676
677            final FillResponse response = builder.build();
678            response.setRequestId(parcel.readInt());
679
680            return response;
681        }
682
683        @Override
684        public FillResponse[] newArray(int size) {
685            return new FillResponse[size];
686        }
687    };
688}
689