1/*
2 * Copyright (C) 2017 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 android.annotation.IntDef;
20import android.annotation.Nullable;
21import android.content.IntentSender;
22import android.os.Bundle;
23import android.os.Parcel;
24import android.os.Parcelable;
25import android.view.autofill.AutofillId;
26import android.widget.RemoteViews;
27
28import com.android.internal.util.Preconditions;
29
30import java.lang.annotation.Retention;
31import java.lang.annotation.RetentionPolicy;
32import java.util.ArrayList;
33import java.util.List;
34
35/**
36 * Describes what happened after the last
37 * {@link AutofillService#onFillRequest(FillRequest, android.os.CancellationSignal, FillCallback)}
38 * call.
39 *
40 * <p>This history is typically used to keep track of previous user actions to optimize further
41 * requests. For example, the service might return email addresses in alphabetical order by
42 * default, but change that order based on the address the user picked on previous requests.
43 *
44 * <p>The history is not persisted over reboots, and it's cleared every time the service
45 * replies to a
46 * {@link AutofillService#onFillRequest(FillRequest, android.os.CancellationSignal, FillCallback)}
47 * by calling {@link FillCallback#onSuccess(FillResponse)} or
48 * {@link FillCallback#onFailure(CharSequence)} (if the service doesn't call any of these methods,
49 * the history will clear out after some pre-defined time).
50 */
51public final class FillEventHistory implements Parcelable {
52    /**
53     * Not in parcel. The UID of the {@link AutofillService} that created the {@link FillResponse}.
54     */
55    private final int mServiceUid;
56
57    /**
58     * Not in parcel. The ID of the autofill session that created the {@link FillResponse}.
59     */
60    private final int mSessionId;
61
62    @Nullable private final Bundle mClientState;
63    @Nullable List<Event> mEvents;
64
65    /**
66     * Gets the UID of the {@link AutofillService} that created the {@link FillResponse}.
67     *
68     * @return The UID of the {@link AutofillService}
69     *
70     * @hide
71     */
72    public int getServiceUid() {
73        return mServiceUid;
74    }
75
76    /** @hide */
77    public int getSessionId() {
78        return mSessionId;
79    }
80
81    /**
82     * Returns the client state set in the previous {@link FillResponse}.
83     *
84     * <p><b>NOTE: </b>the state is associated with the app that was autofilled in the previous
85     * {@link AutofillService#onFillRequest(FillRequest, android.os.CancellationSignal, FillCallback)}
86     * , which is not necessary the same app being autofilled now.
87     */
88    @Nullable public Bundle getClientState() {
89        return mClientState;
90    }
91
92    /**
93     * Returns the events occurred after the latest call to
94     * {@link FillCallback#onSuccess(FillResponse)}.
95     *
96     * @return The list of events or {@code null} if non occurred.
97     */
98    @Nullable public List<Event> getEvents() {
99        return mEvents;
100    }
101
102    /**
103     * @hide
104     */
105    public void addEvent(Event event) {
106        if (mEvents == null) {
107            mEvents = new ArrayList<>(1);
108        }
109        mEvents.add(event);
110    }
111
112    /**
113     * @hide
114     */
115    public FillEventHistory(int serviceUid, int sessionId, @Nullable Bundle clientState) {
116        mClientState = clientState;
117        mServiceUid = serviceUid;
118        mSessionId = sessionId;
119    }
120
121    @Override
122    public int describeContents() {
123        return 0;
124    }
125
126    @Override
127    public void writeToParcel(Parcel dest, int flags) {
128        dest.writeBundle(mClientState);
129
130        if (mEvents == null) {
131            dest.writeInt(0);
132        } else {
133            dest.writeInt(mEvents.size());
134
135            int numEvents = mEvents.size();
136            for (int i = 0; i < numEvents; i++) {
137                Event event = mEvents.get(i);
138                dest.writeInt(event.getType());
139                dest.writeString(event.getDatasetId());
140            }
141        }
142    }
143
144    /**
145     * Description of an event that occured after the latest call to
146     * {@link FillCallback#onSuccess(FillResponse)}.
147     */
148    public static final class Event {
149        /**
150         * A dataset was selected. The dataset selected can be read from {@link #getDatasetId()}.
151         */
152        public static final int TYPE_DATASET_SELECTED = 0;
153
154        /**
155         * A {@link Dataset.Builder#setAuthentication(IntentSender) dataset authentication} was
156         * selected. The dataset authenticated can be read from {@link #getDatasetId()}.
157         */
158        public static final int TYPE_DATASET_AUTHENTICATION_SELECTED = 1;
159
160        /**
161         * A {@link FillResponse.Builder#setAuthentication(AutofillId[], IntentSender, RemoteViews)
162         * fill response authentication} was selected.
163         */
164        public static final int TYPE_AUTHENTICATION_SELECTED = 2;
165
166        /** A save UI was shown. */
167        public static final int TYPE_SAVE_SHOWN = 3;
168
169        /** @hide */
170        @IntDef(
171                value = {TYPE_DATASET_SELECTED,
172                        TYPE_DATASET_AUTHENTICATION_SELECTED,
173                        TYPE_AUTHENTICATION_SELECTED,
174                        TYPE_SAVE_SHOWN})
175        @Retention(RetentionPolicy.SOURCE)
176        @interface EventIds{}
177
178        @EventIds private final int mEventType;
179        @Nullable private final String mDatasetId;
180
181        /**
182         * Returns the type of the event.
183         *
184         * @return The type of the event
185         */
186        public int getType() {
187            return mEventType;
188        }
189
190        /**
191         * Returns the id of dataset the id was on.
192         *
193         * @return The id of dataset, or {@code null} the event is not associated with a dataset.
194         */
195        @Nullable public String getDatasetId() {
196            return mDatasetId;
197        }
198
199        /**
200         * Creates a new event.
201         *
202         * @param eventType The type of the event
203         * @param datasetId The dataset the event was on, or {@code null} if the event was on the
204         *                  whole response.
205         *
206         * @hide
207         */
208        public Event(int eventType, String datasetId) {
209            mEventType = Preconditions.checkArgumentInRange(eventType, 0, TYPE_SAVE_SHOWN,
210                    "eventType");
211            mDatasetId = datasetId;
212        }
213    }
214
215    public static final Parcelable.Creator<FillEventHistory> CREATOR =
216            new Parcelable.Creator<FillEventHistory>() {
217                @Override
218                public FillEventHistory createFromParcel(Parcel parcel) {
219                    FillEventHistory selection = new FillEventHistory(0, 0, parcel.readBundle());
220
221                    int numEvents = parcel.readInt();
222                    for (int i = 0; i < numEvents; i++) {
223                        selection.addEvent(new Event(parcel.readInt(), parcel.readString()));
224                    }
225
226                    return selection;
227                }
228
229                @Override
230                public FillEventHistory[] newArray(int size) {
231                    return new FillEventHistory[size];
232                }
233            };
234}
235