16d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Leme/*
26d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Leme * Copyright (C) 2016 The Android Open Source Project
36d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Leme *
46d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Leme * Licensed under the Apache License, Version 2.0 (the "License");
56d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Leme * you may not use this file except in compliance with the License.
66d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Leme * You may obtain a copy of the License at
76d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Leme *
86d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Leme *      http://www.apache.org/licenses/LICENSE-2.0
96d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Leme *
106d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Leme * Unless required by applicable law or agreed to in writing, software
116d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Leme * distributed under the License is distributed on an "AS IS" BASIS,
126d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Leme * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
136d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Leme * See the License for the specific language governing permissions and
146d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Leme * limitations under the License.
156d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Leme */
166d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Leme
17782043caf81055aa1c331e9cc15b24a10e1bf17aSvet Ganovpackage android.service.autofill;
186d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Leme
199f9ee25515591ef33281708c0ab911962f4364a6Felipe Lemeimport static android.view.autofill.Helper.sDebug;
20d633f072552815301a559520a1f93eb7e79ba319Felipe Leme
210f4928f1f73407485d6d94beda1dba1a2360ebbfSvet Ganovimport android.annotation.NonNull;
22436ab6a91d64ef6036c67bb361d807e398fb2c4cFelipe Lemeimport android.annotation.Nullable;
230f4928f1f73407485d6d94beda1dba1a2360ebbfSvet Ganovimport android.content.IntentSender;
246d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Lemeimport android.os.Parcel;
256d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Lemeimport android.os.Parcelable;
26640f30a7763b0a4b80c767acb84c740aac04768bFelipe Lemeimport android.view.autofill.AutofillId;
27640f30a7763b0a4b80c767acb84c740aac04768bFelipe Lemeimport android.view.autofill.AutofillValue;
2800c771dc7d8242362f1491ae4ce3efd641235b36Svet Ganovimport android.widget.RemoteViews;
29d0b18d665ff8a42ccdc46be7a2382c67476c3c7bFelipe Leme
306d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Lemeimport com.android.internal.util.Preconditions;
316d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Leme
326d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Lemeimport java.util.ArrayList;
336d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Leme
346d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Leme/**
352ef19c1d73f89ca4718b5a8f0c2e7221621e844fFelipe Leme * A dataset object represents a group of key/value pairs used to autofill parts of a screen.
366d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Leme *
372ef19c1d73f89ca4718b5a8f0c2e7221621e844fFelipe Leme * <p>In its simplest form, a dataset contains one or more key / value pairs (comprised of
382ef19c1d73f89ca4718b5a8f0c2e7221621e844fFelipe Leme * {@link AutofillId} and {@link AutofillValue} respectively); and one or more
392ef19c1d73f89ca4718b5a8f0c2e7221621e844fFelipe Leme * {@link RemoteViews presentation} for these pairs (a pair could have its own
402ef19c1d73f89ca4718b5a8f0c2e7221621e844fFelipe Leme * {@link RemoteViews presentation}, or use the default {@link RemoteViews presentation} associated
412ef19c1d73f89ca4718b5a8f0c2e7221621e844fFelipe Leme * with the whole dataset). When an autofill service returns datasets in a {@link FillResponse}
422ef19c1d73f89ca4718b5a8f0c2e7221621e844fFelipe Leme * and the screen input is focused in a view that is present in at least one of these datasets,
432ef19c1d73f89ca4718b5a8f0c2e7221621e844fFelipe Leme * the Android System displays a UI affordance containing the {@link RemoteViews presentation} of
442ef19c1d73f89ca4718b5a8f0c2e7221621e844fFelipe Leme * all datasets pairs that have that view's {@link AutofillId}. Then, when the user selects a
452ef19c1d73f89ca4718b5a8f0c2e7221621e844fFelipe Leme * dataset from the affordance, all views in that dataset are autofilled.
466d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Leme *
472ef19c1d73f89ca4718b5a8f0c2e7221621e844fFelipe Leme * <p>In a more sophisticated form, the dataset value can be protected until the user authenticates
482ef19c1d73f89ca4718b5a8f0c2e7221621e844fFelipe Leme * the dataset - see {@link Dataset.Builder#setAuthentication(IntentSender)}.
496d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Leme *
502ef19c1d73f89ca4718b5a8f0c2e7221621e844fFelipe Leme * @see android.service.autofill.AutofillService for more information and examples about the
512ef19c1d73f89ca4718b5a8f0c2e7221621e844fFelipe Leme * role of datasets in the autofill workflow.
526d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Leme */
536d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Lemepublic final class Dataset implements Parcelable {
54782043caf81055aa1c331e9cc15b24a10e1bf17aSvet Ganov
55640f30a7763b0a4b80c767acb84c740aac04768bFelipe Leme    private final ArrayList<AutofillId> mFieldIds;
56640f30a7763b0a4b80c767acb84c740aac04768bFelipe Leme    private final ArrayList<AutofillValue> mFieldValues;
575311206f3434d631c6ea81ab2e76a46ca18119b6Felipe Leme    private final ArrayList<RemoteViews> mFieldPresentations;
5800c771dc7d8242362f1491ae4ce3efd641235b36Svet Ganov    private final RemoteViews mPresentation;
590f4928f1f73407485d6d94beda1dba1a2360ebbfSvet Ganov    private final IntentSender mAuthentication;
60cc684ed41f17ccdce45a056fd4034efc35b213d5Philip P. Moltmann    @Nullable String mId;
616d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Leme
620f4928f1f73407485d6d94beda1dba1a2360ebbfSvet Ganov    private Dataset(Builder builder) {
630f4928f1f73407485d6d94beda1dba1a2360ebbfSvet Ganov        mFieldIds = builder.mFieldIds;
640f4928f1f73407485d6d94beda1dba1a2360ebbfSvet Ganov        mFieldValues = builder.mFieldValues;
655311206f3434d631c6ea81ab2e76a46ca18119b6Felipe Leme        mFieldPresentations = builder.mFieldPresentations;
6600c771dc7d8242362f1491ae4ce3efd641235b36Svet Ganov        mPresentation = builder.mPresentation;
670f4928f1f73407485d6d94beda1dba1a2360ebbfSvet Ganov        mAuthentication = builder.mAuthentication;
68cc684ed41f17ccdce45a056fd4034efc35b213d5Philip P. Moltmann        mId = builder.mId;
696d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Leme    }
706d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Leme
716d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Leme    /** @hide */
72640f30a7763b0a4b80c767acb84c740aac04768bFelipe Leme    public @Nullable ArrayList<AutofillId> getFieldIds() {
730f4928f1f73407485d6d94beda1dba1a2360ebbfSvet Ganov        return mFieldIds;
74436ab6a91d64ef6036c67bb361d807e398fb2c4cFelipe Leme    }
75436ab6a91d64ef6036c67bb361d807e398fb2c4cFelipe Leme
76436ab6a91d64ef6036c67bb361d807e398fb2c4cFelipe Leme    /** @hide */
77640f30a7763b0a4b80c767acb84c740aac04768bFelipe Leme    public @Nullable ArrayList<AutofillValue> getFieldValues() {
780f4928f1f73407485d6d94beda1dba1a2360ebbfSvet Ganov        return mFieldValues;
79436ab6a91d64ef6036c67bb361d807e398fb2c4cFelipe Leme    }
80436ab6a91d64ef6036c67bb361d807e398fb2c4cFelipe Leme
81436ab6a91d64ef6036c67bb361d807e398fb2c4cFelipe Leme    /** @hide */
825311206f3434d631c6ea81ab2e76a46ca18119b6Felipe Leme    public RemoteViews getFieldPresentation(int index) {
835311206f3434d631c6ea81ab2e76a46ca18119b6Felipe Leme        final RemoteViews customPresentation = mFieldPresentations.get(index);
845311206f3434d631c6ea81ab2e76a46ca18119b6Felipe Leme        return customPresentation != null ? customPresentation : mPresentation;
855311206f3434d631c6ea81ab2e76a46ca18119b6Felipe Leme    }
865311206f3434d631c6ea81ab2e76a46ca18119b6Felipe Leme
875311206f3434d631c6ea81ab2e76a46ca18119b6Felipe Leme    /** @hide */
880f4928f1f73407485d6d94beda1dba1a2360ebbfSvet Ganov    public @Nullable IntentSender getAuthentication() {
890f4928f1f73407485d6d94beda1dba1a2360ebbfSvet Ganov        return mAuthentication;
90436ab6a91d64ef6036c67bb361d807e398fb2c4cFelipe Leme    }
91436ab6a91d64ef6036c67bb361d807e398fb2c4cFelipe Leme
92436ab6a91d64ef6036c67bb361d807e398fb2c4cFelipe Leme    /** @hide */
930f4928f1f73407485d6d94beda1dba1a2360ebbfSvet Ganov    public boolean isEmpty() {
940f4928f1f73407485d6d94beda1dba1a2360ebbfSvet Ganov        return mFieldIds == null || mFieldIds.isEmpty();
95436ab6a91d64ef6036c67bb361d807e398fb2c4cFelipe Leme    }
96436ab6a91d64ef6036c67bb361d807e398fb2c4cFelipe Leme
976d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Leme    @Override
986d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Leme    public String toString() {
999f9ee25515591ef33281708c0ab911962f4364a6Felipe Leme        if (!sDebug) return super.toString();
1006d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Leme
101cc684ed41f17ccdce45a056fd4034efc35b213d5Philip P. Moltmann        return new StringBuilder("Dataset " + mId + " [")
10278696bfeb7ac5ae298765bfb9f82cf24d12b7dccFelipe Leme                .append("fieldIds=").append(mFieldIds)
1030f4928f1f73407485d6d94beda1dba1a2360ebbfSvet Ganov                .append(", fieldValues=").append(mFieldValues)
1045311206f3434d631c6ea81ab2e76a46ca18119b6Felipe Leme                .append(", fieldPresentations=")
1055311206f3434d631c6ea81ab2e76a46ca18119b6Felipe Leme                .append(mFieldPresentations == null ? 0 : mFieldPresentations.size())
10600c771dc7d8242362f1491ae4ce3efd641235b36Svet Ganov                .append(", hasPresentation=").append(mPresentation != null)
10700c771dc7d8242362f1491ae4ce3efd641235b36Svet Ganov                .append(", hasAuthentication=").append(mAuthentication != null)
10800c771dc7d8242362f1491ae4ce3efd641235b36Svet Ganov                .append(']').toString();
1096d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Leme    }
1106d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Leme
1116d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Leme    /**
112cc684ed41f17ccdce45a056fd4034efc35b213d5Philip P. Moltmann     * Gets the id of this dataset.
113cc684ed41f17ccdce45a056fd4034efc35b213d5Philip P. Moltmann     *
114cc684ed41f17ccdce45a056fd4034efc35b213d5Philip P. Moltmann     * @return The id of this dataset or {@code null} if not set
115cc684ed41f17ccdce45a056fd4034efc35b213d5Philip P. Moltmann     *
116cc684ed41f17ccdce45a056fd4034efc35b213d5Philip P. Moltmann     * @hide
117cc684ed41f17ccdce45a056fd4034efc35b213d5Philip P. Moltmann     */
118cc684ed41f17ccdce45a056fd4034efc35b213d5Philip P. Moltmann    public String getId() {
119cc684ed41f17ccdce45a056fd4034efc35b213d5Philip P. Moltmann        return mId;
120cc684ed41f17ccdce45a056fd4034efc35b213d5Philip P. Moltmann    }
121cc684ed41f17ccdce45a056fd4034efc35b213d5Philip P. Moltmann
122cc684ed41f17ccdce45a056fd4034efc35b213d5Philip P. Moltmann    /**
1232ef19c1d73f89ca4718b5a8f0c2e7221621e844fFelipe Leme     * A builder for {@link Dataset} objects. You must provide at least
1240f4928f1f73407485d6d94beda1dba1a2360ebbfSvet Ganov     * one value for a field or set an authentication intent.
1256d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Leme     */
1266d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Leme    public static final class Builder {
127640f30a7763b0a4b80c767acb84c740aac04768bFelipe Leme        private ArrayList<AutofillId> mFieldIds;
128640f30a7763b0a4b80c767acb84c740aac04768bFelipe Leme        private ArrayList<AutofillValue> mFieldValues;
1295311206f3434d631c6ea81ab2e76a46ca18119b6Felipe Leme        private ArrayList<RemoteViews> mFieldPresentations;
13000c771dc7d8242362f1491ae4ce3efd641235b36Svet Ganov        private RemoteViews mPresentation;
1310f4928f1f73407485d6d94beda1dba1a2360ebbfSvet Ganov        private IntentSender mAuthentication;
1320f4928f1f73407485d6d94beda1dba1a2360ebbfSvet Ganov        private boolean mDestroyed;
133cc684ed41f17ccdce45a056fd4034efc35b213d5Philip P. Moltmann        @Nullable private String mId;
1340f4928f1f73407485d6d94beda1dba1a2360ebbfSvet Ganov
1356d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Leme        /**
136eb49515abd2353f32e0eb7b3964847c6399986c9Svet Ganov         * Creates a new builder.
13700c771dc7d8242362f1491ae4ce3efd641235b36Svet Ganov         *
138eb49515abd2353f32e0eb7b3964847c6399986c9Svet Ganov         * @param presentation The presentation used to visualize this dataset.
1396d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Leme         */
140eb49515abd2353f32e0eb7b3964847c6399986c9Svet Ganov        public Builder(@NonNull RemoteViews presentation) {
141eb49515abd2353f32e0eb7b3964847c6399986c9Svet Ganov            Preconditions.checkNotNull(presentation, "presentation must be non-null");
14200c771dc7d8242362f1491ae4ce3efd641235b36Svet Ganov            mPresentation = presentation;
1436d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Leme        }
1446d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Leme
1456d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Leme        /**
1465311206f3434d631c6ea81ab2e76a46ca18119b6Felipe Leme         * Creates a new builder for a dataset where each field will be visualized independently.
1475311206f3434d631c6ea81ab2e76a46ca18119b6Felipe Leme         *
1485311206f3434d631c6ea81ab2e76a46ca18119b6Felipe Leme         * <p>When using this constructor, fields must be set through
1495311206f3434d631c6ea81ab2e76a46ca18119b6Felipe Leme         * {@link #setValue(AutofillId, AutofillValue, RemoteViews)}.
1505311206f3434d631c6ea81ab2e76a46ca18119b6Felipe Leme         */
1515311206f3434d631c6ea81ab2e76a46ca18119b6Felipe Leme        public Builder() {
1525311206f3434d631c6ea81ab2e76a46ca18119b6Felipe Leme        }
1535311206f3434d631c6ea81ab2e76a46ca18119b6Felipe Leme
1545311206f3434d631c6ea81ab2e76a46ca18119b6Felipe Leme        /**
155640f30a7763b0a4b80c767acb84c740aac04768bFelipe Leme         * Requires a dataset authentication before autofilling the activity with this dataset.
156436ab6a91d64ef6036c67bb361d807e398fb2c4cFelipe Leme         *
1570f4928f1f73407485d6d94beda1dba1a2360ebbfSvet Ganov         * <p>This method is called when you need to provide an authentication
158782043caf81055aa1c331e9cc15b24a10e1bf17aSvet Ganov         * UI for the data set. For example, when a data set contains credit card information
1590f4928f1f73407485d6d94beda1dba1a2360ebbfSvet Ganov         * (such as number, expiration date, and verification code), you can display UI
16000c771dc7d8242362f1491ae4ce3efd641235b36Svet Ganov         * asking for the verification code before filing in the data. Even if the
161782043caf81055aa1c331e9cc15b24a10e1bf17aSvet Ganov         * data set is completely populated the system will launch the specified authentication
162782043caf81055aa1c331e9cc15b24a10e1bf17aSvet Ganov         * intent and will need your approval to fill it in. Since the data set is "locked"
163782043caf81055aa1c331e9cc15b24a10e1bf17aSvet Ganov         * until the user authenticates it, typically this data set name is masked
164782043caf81055aa1c331e9cc15b24a10e1bf17aSvet Ganov         * (for example, "VISA....1234"). Typically you would want to store the data set
165782043caf81055aa1c331e9cc15b24a10e1bf17aSvet Ganov         * labels non-encrypted and the actual sensitive data encrypted and not in memory.
1660f4928f1f73407485d6d94beda1dba1a2360ebbfSvet Ganov         * This allows showing the labels in the UI while involving the user if one of
1670f4928f1f73407485d6d94beda1dba1a2360ebbfSvet Ganov         * the items with these labels is chosen. Note that if you use sensitive data as
168782043caf81055aa1c331e9cc15b24a10e1bf17aSvet Ganov         * a label, for example an email address, then it should also be encrypted.</p>
169436ab6a91d64ef6036c67bb361d807e398fb2c4cFelipe Leme         *
170640f30a7763b0a4b80c767acb84c740aac04768bFelipe Leme         * <p>When a user triggers autofill, the system launches the provided intent
171782043caf81055aa1c331e9cc15b24a10e1bf17aSvet Ganov         * whose extras will have the {@link
172a9379d0b44ca1f68a0036d2b65218e17fa348514Svetoslav Ganov         * android.view.autofill.AutofillManager#EXTRA_ASSIST_STRUCTURE screen content},
173a9379d0b44ca1f68a0036d2b65218e17fa348514Svetoslav Ganov         * and your {@link android.view.autofill.AutofillManager#EXTRA_CLIENT_STATE client
174a9379d0b44ca1f68a0036d2b65218e17fa348514Svetoslav Ganov         * state}. Once you complete your authentication flow you should set the activity
175a9379d0b44ca1f68a0036d2b65218e17fa348514Svetoslav Ganov         * result to {@link android.app.Activity#RESULT_OK} and provide the fully populated
176a9379d0b44ca1f68a0036d2b65218e17fa348514Svetoslav Ganov         * {@link Dataset dataset} or a fully-populated {@link FillResponse response} by
177a9379d0b44ca1f68a0036d2b65218e17fa348514Svetoslav Ganov         * setting it to the {@link
178a9379d0b44ca1f68a0036d2b65218e17fa348514Svetoslav Ganov         * android.view.autofill.AutofillManager#EXTRA_AUTHENTICATION_RESULT} extra. If you
179a9379d0b44ca1f68a0036d2b65218e17fa348514Svetoslav Ganov         * provide a dataset in the result, it will replace the authenticated dataset and
180a9379d0b44ca1f68a0036d2b65218e17fa348514Svetoslav Ganov         * will be immediately filled in. If you provide a response, it will replace the
181a9379d0b44ca1f68a0036d2b65218e17fa348514Svetoslav Ganov         * current response and the UI will be refreshed. For example, if you provided
182a9379d0b44ca1f68a0036d2b65218e17fa348514Svetoslav Ganov         * credit card information without the CVV for the data set in the {@link FillResponse
183a9379d0b44ca1f68a0036d2b65218e17fa348514Svetoslav Ganov         * response} then the returned data set should contain the CVV entry.
184436ab6a91d64ef6036c67bb361d807e398fb2c4cFelipe Leme         *
1852ef19c1d73f89ca4718b5a8f0c2e7221621e844fFelipe Leme         * <p><b>NOTE:</b> Do not make the provided pending intent
1860f4928f1f73407485d6d94beda1dba1a2360ebbfSvet Ganov         * immutable by using {@link android.app.PendingIntent#FLAG_IMMUTABLE} as the
1872ef19c1d73f89ca4718b5a8f0c2e7221621e844fFelipe Leme         * platform needs to fill in the authentication arguments.
188436ab6a91d64ef6036c67bb361d807e398fb2c4cFelipe Leme         *
189782043caf81055aa1c331e9cc15b24a10e1bf17aSvet Ganov         * @param authentication Intent to an activity with your authentication flow.
19000c771dc7d8242362f1491ae4ce3efd641235b36Svet Ganov         * @return This builder.
191436ab6a91d64ef6036c67bb361d807e398fb2c4cFelipe Leme         *
192782043caf81055aa1c331e9cc15b24a10e1bf17aSvet Ganov         * @see android.app.PendingIntent
193436ab6a91d64ef6036c67bb361d807e398fb2c4cFelipe Leme         */
1940f4928f1f73407485d6d94beda1dba1a2360ebbfSvet Ganov        public @NonNull Builder setAuthentication(@Nullable IntentSender authentication) {
1950f4928f1f73407485d6d94beda1dba1a2360ebbfSvet Ganov            throwIfDestroyed();
1960f4928f1f73407485d6d94beda1dba1a2360ebbfSvet Ganov            mAuthentication = authentication;
197436ab6a91d64ef6036c67bb361d807e398fb2c4cFelipe Leme            return this;
198436ab6a91d64ef6036c67bb361d807e398fb2c4cFelipe Leme        }
199436ab6a91d64ef6036c67bb361d807e398fb2c4cFelipe Leme
200436ab6a91d64ef6036c67bb361d807e398fb2c4cFelipe Leme        /**
2012ef19c1d73f89ca4718b5a8f0c2e7221621e844fFelipe Leme         * Sets the id for the dataset so its usage history can be retrieved later.
202cc684ed41f17ccdce45a056fd4034efc35b213d5Philip P. Moltmann         *
203cc684ed41f17ccdce45a056fd4034efc35b213d5Philip P. Moltmann         * <p>The id of the last selected dataset can be read from
204cc684ed41f17ccdce45a056fd4034efc35b213d5Philip P. Moltmann         * {@link AutofillService#getFillEventHistory()}. If the id is not set it will not be clear
205cc684ed41f17ccdce45a056fd4034efc35b213d5Philip P. Moltmann         * if a dataset was selected as {@link AutofillService#getFillEventHistory()} uses
206cc684ed41f17ccdce45a056fd4034efc35b213d5Philip P. Moltmann         * {@code null} to indicate that no dataset was selected.
207cc684ed41f17ccdce45a056fd4034efc35b213d5Philip P. Moltmann         *
208cc684ed41f17ccdce45a056fd4034efc35b213d5Philip P. Moltmann         * @param id id for this dataset or {@code null} to unset.
209cc684ed41f17ccdce45a056fd4034efc35b213d5Philip P. Moltmann
210cc684ed41f17ccdce45a056fd4034efc35b213d5Philip P. Moltmann         * @return This builder.
211cc684ed41f17ccdce45a056fd4034efc35b213d5Philip P. Moltmann         */
212cc684ed41f17ccdce45a056fd4034efc35b213d5Philip P. Moltmann        public @NonNull Builder setId(@Nullable String id) {
213cc684ed41f17ccdce45a056fd4034efc35b213d5Philip P. Moltmann            throwIfDestroyed();
214cc684ed41f17ccdce45a056fd4034efc35b213d5Philip P. Moltmann
215cc684ed41f17ccdce45a056fd4034efc35b213d5Philip P. Moltmann            mId = id;
216cc684ed41f17ccdce45a056fd4034efc35b213d5Philip P. Moltmann            return this;
217cc684ed41f17ccdce45a056fd4034efc35b213d5Philip P. Moltmann        }
218cc684ed41f17ccdce45a056fd4034efc35b213d5Philip P. Moltmann
219cc684ed41f17ccdce45a056fd4034efc35b213d5Philip P. Moltmann        /**
2206d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Leme         * Sets the value of a field.
2216d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Leme         *
222782043caf81055aa1c331e9cc15b24a10e1bf17aSvet Ganov         * @param id id returned by {@link
223640f30a7763b0a4b80c767acb84c740aac04768bFelipe Leme         *         android.app.assist.AssistStructure.ViewNode#getAutofillId()}.
2242ef19c1d73f89ca4718b5a8f0c2e7221621e844fFelipe Leme         * @param value value to be autofilled. Pass {@code null} if you do not have the value
225a9379d0b44ca1f68a0036d2b65218e17fa348514Svetoslav Ganov         *        but the target view is a logical part of the dataset. For example, if
226a9379d0b44ca1f68a0036d2b65218e17fa348514Svetoslav Ganov         *        the dataset needs an authentication and you have no access to the value.
22700c771dc7d8242362f1491ae4ce3efd641235b36Svet Ganov         * @return This builder.
2282ef19c1d73f89ca4718b5a8f0c2e7221621e844fFelipe Leme         * @throws IllegalStateException if the builder was constructed without a
2292ef19c1d73f89ca4718b5a8f0c2e7221621e844fFelipe Leme         * {@link RemoteViews presentation}.
2306d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Leme         */
231a9379d0b44ca1f68a0036d2b65218e17fa348514Svetoslav Ganov        public @NonNull Builder setValue(@NonNull AutofillId id, @Nullable AutofillValue value) {
2320f4928f1f73407485d6d94beda1dba1a2360ebbfSvet Ganov            throwIfDestroyed();
2335311206f3434d631c6ea81ab2e76a46ca18119b6Felipe Leme            if (mPresentation == null) {
2345311206f3434d631c6ea81ab2e76a46ca18119b6Felipe Leme                throw new IllegalStateException("Dataset presentation not set on constructor");
2355311206f3434d631c6ea81ab2e76a46ca18119b6Felipe Leme            }
2365311206f3434d631c6ea81ab2e76a46ca18119b6Felipe Leme            setValueAndPresentation(id, value, null);
2375311206f3434d631c6ea81ab2e76a46ca18119b6Felipe Leme            return this;
2385311206f3434d631c6ea81ab2e76a46ca18119b6Felipe Leme        }
2395311206f3434d631c6ea81ab2e76a46ca18119b6Felipe Leme
2405311206f3434d631c6ea81ab2e76a46ca18119b6Felipe Leme        /**
2412ef19c1d73f89ca4718b5a8f0c2e7221621e844fFelipe Leme         * Sets the value of a field, using a custom {@link RemoteViews presentation} to
2422ef19c1d73f89ca4718b5a8f0c2e7221621e844fFelipe Leme         * visualize it.
2435311206f3434d631c6ea81ab2e76a46ca18119b6Felipe Leme         *
2445311206f3434d631c6ea81ab2e76a46ca18119b6Felipe Leme         * @param id id returned by {@link
2455311206f3434d631c6ea81ab2e76a46ca18119b6Felipe Leme         *         android.app.assist.AssistStructure.ViewNode#getAutofillId()}.
246a9379d0b44ca1f68a0036d2b65218e17fa348514Svetoslav Ganov         * @param value value to be auto filled. Pass {@code null} if you do not have the value
247a9379d0b44ca1f68a0036d2b65218e17fa348514Svetoslav Ganov         *        but the target view is a logical part of the dataset. For example, if
248a9379d0b44ca1f68a0036d2b65218e17fa348514Svetoslav Ganov         *        the dataset needs an authentication and you have no access to the value.
249a9379d0b44ca1f68a0036d2b65218e17fa348514Svetoslav Ganov         *        Filtering matches any user typed string to {@code null} values.
2505311206f3434d631c6ea81ab2e76a46ca18119b6Felipe Leme         * @param presentation The presentation used to visualize this field.
2515311206f3434d631c6ea81ab2e76a46ca18119b6Felipe Leme         * @return This builder.
2525311206f3434d631c6ea81ab2e76a46ca18119b6Felipe Leme         */
253a9379d0b44ca1f68a0036d2b65218e17fa348514Svetoslav Ganov        public @NonNull Builder setValue(@NonNull AutofillId id, @Nullable AutofillValue value,
2545311206f3434d631c6ea81ab2e76a46ca18119b6Felipe Leme                @NonNull RemoteViews presentation) {
2555311206f3434d631c6ea81ab2e76a46ca18119b6Felipe Leme            throwIfDestroyed();
2565311206f3434d631c6ea81ab2e76a46ca18119b6Felipe Leme            Preconditions.checkNotNull(presentation, "presentation cannot be null");
2575311206f3434d631c6ea81ab2e76a46ca18119b6Felipe Leme            setValueAndPresentation(id, value, presentation);
2585311206f3434d631c6ea81ab2e76a46ca18119b6Felipe Leme            return this;
2595311206f3434d631c6ea81ab2e76a46ca18119b6Felipe Leme        }
2605311206f3434d631c6ea81ab2e76a46ca18119b6Felipe Leme
2615311206f3434d631c6ea81ab2e76a46ca18119b6Felipe Leme        private void setValueAndPresentation(AutofillId id, AutofillValue value,
2625311206f3434d631c6ea81ab2e76a46ca18119b6Felipe Leme                RemoteViews presentation) {
2630f4928f1f73407485d6d94beda1dba1a2360ebbfSvet Ganov            Preconditions.checkNotNull(id, "id cannot be null");
2640f4928f1f73407485d6d94beda1dba1a2360ebbfSvet Ganov            if (mFieldIds != null) {
2650f4928f1f73407485d6d94beda1dba1a2360ebbfSvet Ganov                final int existingIdx = mFieldIds.indexOf(id);
2660f4928f1f73407485d6d94beda1dba1a2360ebbfSvet Ganov                if (existingIdx >= 0) {
2670f4928f1f73407485d6d94beda1dba1a2360ebbfSvet Ganov                    mFieldValues.set(existingIdx, value);
2685311206f3434d631c6ea81ab2e76a46ca18119b6Felipe Leme                    mFieldPresentations.set(existingIdx, presentation);
2695311206f3434d631c6ea81ab2e76a46ca18119b6Felipe Leme                    return;
2700f4928f1f73407485d6d94beda1dba1a2360ebbfSvet Ganov                }
2710f4928f1f73407485d6d94beda1dba1a2360ebbfSvet Ganov            } else {
2720f4928f1f73407485d6d94beda1dba1a2360ebbfSvet Ganov                mFieldIds = new ArrayList<>();
2730f4928f1f73407485d6d94beda1dba1a2360ebbfSvet Ganov                mFieldValues = new ArrayList<>();
2745311206f3434d631c6ea81ab2e76a46ca18119b6Felipe Leme                mFieldPresentations = new ArrayList<>();
2750f4928f1f73407485d6d94beda1dba1a2360ebbfSvet Ganov            }
2760f4928f1f73407485d6d94beda1dba1a2360ebbfSvet Ganov            mFieldIds.add(id);
2770f4928f1f73407485d6d94beda1dba1a2360ebbfSvet Ganov            mFieldValues.add(value);
2785311206f3434d631c6ea81ab2e76a46ca18119b6Felipe Leme            mFieldPresentations.add(presentation);
2796d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Leme        }
2806d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Leme
2816d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Leme        /**
2822ef19c1d73f89ca4718b5a8f0c2e7221621e844fFelipe Leme         * Creates a new {@link Dataset} instance.
2832ef19c1d73f89ca4718b5a8f0c2e7221621e844fFelipe Leme         *
2842ef19c1d73f89ca4718b5a8f0c2e7221621e844fFelipe Leme         * <p>You should not interact with this builder once this method is called.
2852ef19c1d73f89ca4718b5a8f0c2e7221621e844fFelipe Leme         *
2862ef19c1d73f89ca4718b5a8f0c2e7221621e844fFelipe Leme         * <p>It is required that you specify at least one field before calling this method. It's
2872ef19c1d73f89ca4718b5a8f0c2e7221621e844fFelipe Leme         * also mandatory to provide a presentation view to visualize the data set in the UI.
28800c771dc7d8242362f1491ae4ce3efd641235b36Svet Ganov         *
28900c771dc7d8242362f1491ae4ce3efd641235b36Svet Ganov         * @return The built dataset.
2906d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Leme         */
2910f4928f1f73407485d6d94beda1dba1a2360ebbfSvet Ganov        public @NonNull Dataset build() {
2920f4928f1f73407485d6d94beda1dba1a2360ebbfSvet Ganov            throwIfDestroyed();
2930f4928f1f73407485d6d94beda1dba1a2360ebbfSvet Ganov            mDestroyed = true;
29400c771dc7d8242362f1491ae4ce3efd641235b36Svet Ganov            if (mFieldIds == null) {
29524d5893b25ce62b7bc9ed9f35fa72b9d47f23cddFelipe Leme                throw new IllegalArgumentException("at least one value must be set");
29600c771dc7d8242362f1491ae4ce3efd641235b36Svet Ganov            }
2970f4928f1f73407485d6d94beda1dba1a2360ebbfSvet Ganov            return new Dataset(this);
2986d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Leme        }
2996d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Leme
3000f4928f1f73407485d6d94beda1dba1a2360ebbfSvet Ganov        private void throwIfDestroyed() {
3010f4928f1f73407485d6d94beda1dba1a2360ebbfSvet Ganov            if (mDestroyed) {
3020f4928f1f73407485d6d94beda1dba1a2360ebbfSvet Ganov                throw new IllegalStateException("Already called #build()");
3030f4928f1f73407485d6d94beda1dba1a2360ebbfSvet Ganov            }
3046d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Leme        }
3056d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Leme    }
3066d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Leme
3076d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Leme    /////////////////////////////////////
3086d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Leme    //  Parcelable "contract" methods. //
3096d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Leme    /////////////////////////////////////
3106d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Leme
3116d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Leme    @Override
3126d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Leme    public int describeContents() {
3136d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Leme        return 0;
3146d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Leme    }
3156d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Leme
3166d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Leme    @Override
3176d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Leme    public void writeToParcel(Parcel parcel, int flags) {
318eb49515abd2353f32e0eb7b3964847c6399986c9Svet Ganov        parcel.writeParcelable(mPresentation, flags);
319fe88b6028b7615f75f871ad79b436ebaa5efcad4Fyodor Kupolov        parcel.writeTypedList(mFieldIds, flags);
320fe88b6028b7615f75f871ad79b436ebaa5efcad4Fyodor Kupolov        parcel.writeTypedList(mFieldValues, flags);
3215311206f3434d631c6ea81ab2e76a46ca18119b6Felipe Leme        parcel.writeParcelableList(mFieldPresentations, flags);
3220f4928f1f73407485d6d94beda1dba1a2360ebbfSvet Ganov        parcel.writeParcelable(mAuthentication, flags);
323cc684ed41f17ccdce45a056fd4034efc35b213d5Philip P. Moltmann        parcel.writeString(mId);
3246d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Leme    }
3256d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Leme
326782043caf81055aa1c331e9cc15b24a10e1bf17aSvet Ganov    public static final Creator<Dataset> CREATOR = new Creator<Dataset>() {
3276d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Leme        @Override
3280f4928f1f73407485d6d94beda1dba1a2360ebbfSvet Ganov        public Dataset createFromParcel(Parcel parcel) {
3290f4928f1f73407485d6d94beda1dba1a2360ebbfSvet Ganov            // Always go through the builder to ensure the data ingested by
3300f4928f1f73407485d6d94beda1dba1a2360ebbfSvet Ganov            // the system obeys the contract of the builder to avoid attacks
3310f4928f1f73407485d6d94beda1dba1a2360ebbfSvet Ganov            // using specially crafted parcels.
3325311206f3434d631c6ea81ab2e76a46ca18119b6Felipe Leme            final RemoteViews presentation = parcel.readParcelable(null);
3335311206f3434d631c6ea81ab2e76a46ca18119b6Felipe Leme            final Builder builder = (presentation == null)
3345311206f3434d631c6ea81ab2e76a46ca18119b6Felipe Leme                    ? new Builder()
3355311206f3434d631c6ea81ab2e76a46ca18119b6Felipe Leme                    : new Builder(presentation);
336fe88b6028b7615f75f871ad79b436ebaa5efcad4Fyodor Kupolov            final ArrayList<AutofillId> ids = parcel.createTypedArrayList(AutofillId.CREATOR);
337fe88b6028b7615f75f871ad79b436ebaa5efcad4Fyodor Kupolov            final ArrayList<AutofillValue> values =
338fe88b6028b7615f75f871ad79b436ebaa5efcad4Fyodor Kupolov                    parcel.createTypedArrayList(AutofillValue.CREATOR);
3395311206f3434d631c6ea81ab2e76a46ca18119b6Felipe Leme            final ArrayList<RemoteViews> presentations = new ArrayList<>();
3405311206f3434d631c6ea81ab2e76a46ca18119b6Felipe Leme            parcel.readParcelableList(presentations, null);
3410f4928f1f73407485d6d94beda1dba1a2360ebbfSvet Ganov            final int idCount = (ids != null) ? ids.size() : 0;
3420f4928f1f73407485d6d94beda1dba1a2360ebbfSvet Ganov            final int valueCount = (values != null) ? values.size() : 0;
3430f4928f1f73407485d6d94beda1dba1a2360ebbfSvet Ganov            for (int i = 0; i < idCount; i++) {
344640f30a7763b0a4b80c767acb84c740aac04768bFelipe Leme                final AutofillId id = ids.get(i);
345640f30a7763b0a4b80c767acb84c740aac04768bFelipe Leme                final AutofillValue value = (valueCount > i) ? values.get(i) : null;
3465311206f3434d631c6ea81ab2e76a46ca18119b6Felipe Leme                final RemoteViews fieldPresentation = presentations.isEmpty() ? null
3475311206f3434d631c6ea81ab2e76a46ca18119b6Felipe Leme                        : presentations.get(i);
3485311206f3434d631c6ea81ab2e76a46ca18119b6Felipe Leme                builder.setValueAndPresentation(id, value, fieldPresentation);
3490f4928f1f73407485d6d94beda1dba1a2360ebbfSvet Ganov            }
3500f4928f1f73407485d6d94beda1dba1a2360ebbfSvet Ganov            builder.setAuthentication(parcel.readParcelable(null));
351cc684ed41f17ccdce45a056fd4034efc35b213d5Philip P. Moltmann            builder.setId(parcel.readString());
3520f4928f1f73407485d6d94beda1dba1a2360ebbfSvet Ganov            return builder.build();
3536d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Leme        }
3546d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Leme
3556d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Leme        @Override
3566d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Leme        public Dataset[] newArray(int size) {
3576d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Leme            return new Dataset[size];
3586d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Leme        }
3596d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Leme    };
3606d553874bed06280766ae24ea605f9bbde3f5a4aFelipe Leme}
361