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