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