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.NonNull;
21import android.annotation.Nullable;
22import android.os.Bundle;
23import android.os.Parcel;
24import android.os.Parcelable;
25import android.view.View;
26
27import com.android.internal.util.Preconditions;
28
29import java.lang.annotation.Retention;
30import java.lang.annotation.RetentionPolicy;
31import java.util.ArrayList;
32import java.util.List;
33
34/**
35 * This class represents a request to an autofill service
36 * to interpret the screen and provide information to the system which views are
37 * interesting for saving and what are the possible ways to fill the inputs on
38 * the screen if applicable.
39 *
40 * @see AutofillService#onFillRequest(FillRequest, android.os.CancellationSignal, FillCallback)
41 */
42public final class FillRequest implements Parcelable {
43
44    /**
45     * Indicates autofill was explicitly requested by the user.
46     *
47     * <p>Users typically make an explicit request to autofill a screen in two situations:
48     * <ul>
49     *   <li>The app disabled autofill (using {@link View#setImportantForAutofill(int)}.
50     *   <li>The service could not figure out how to autofill a screen (but the user knows the
51     *       service has data for that app).
52     * </ul>
53     *
54     * <p>This flag is particularly useful for the second case. For example, the service could offer
55     * a complex UI where the user can map which screen views belong to each user data, or it could
56     * offer a simpler UI where the user picks the data for just the view used to trigger the
57     * request (that would be the view whose
58     * {@link android.app.assist.AssistStructure.ViewNode#isFocused()} method returns {@code true}).
59     *
60     * <p>An explicit autofill request is triggered when the
61     * {@link android.view.autofill.AutofillManager#requestAutofill(View)} or
62     * {@link android.view.autofill.AutofillManager#requestAutofill(View, int, android.graphics.Rect)}
63     * is called. For example, standard {@link android.widget.TextView} views show an
64     * {@code AUTOFILL} option in the overflow menu that triggers such request.
65     */
66    public static final int FLAG_MANUAL_REQUEST = 0x1;
67
68    /** @hide */
69    public static final int INVALID_REQUEST_ID = Integer.MIN_VALUE;
70
71    /** @hide */
72    @IntDef(flag = true, prefix = { "FLAG_" }, value = {
73            FLAG_MANUAL_REQUEST
74    })
75    @Retention(RetentionPolicy.SOURCE)
76    @interface RequestFlags{}
77
78    private final int mId;
79    private final @RequestFlags int mFlags;
80    private final @NonNull ArrayList<FillContext> mContexts;
81    private final @Nullable Bundle mClientState;
82
83    private FillRequest(@NonNull Parcel parcel) {
84        mId = parcel.readInt();
85        mContexts = new ArrayList<>();
86        parcel.readParcelableList(mContexts, null);
87
88        mClientState = parcel.readBundle();
89        mFlags = parcel.readInt();
90    }
91
92    /** @hide */
93    public FillRequest(int id, @NonNull ArrayList<FillContext> contexts,
94            @Nullable Bundle clientState, @RequestFlags int flags) {
95        mId = id;
96        mFlags = Preconditions.checkFlagsArgument(flags, FLAG_MANUAL_REQUEST);
97        mContexts = Preconditions.checkCollectionElementsNotNull(contexts, "contexts");
98        mClientState = clientState;
99    }
100
101    /**
102     * Gets the unique id of this request.
103     */
104    public int getId() {
105        return mId;
106    }
107
108    /**
109     * Gets the flags associated with this request.
110     *
111     * @see #FLAG_MANUAL_REQUEST
112     */
113    public @RequestFlags int getFlags() {
114        return mFlags;
115    }
116
117    /**
118     * Gets the contexts associated with each previous fill request.
119     */
120    public @NonNull List<FillContext> getFillContexts() {
121        return mContexts;
122    }
123
124    @Override
125    public String toString() {
126        return "FillRequest: [id=" + mId + ", flags=" + mFlags + ", ctxts= " + mContexts + "]";
127    }
128
129    /**
130     * Gets the latest client state bundle set by the service in a
131     * {@link FillResponse.Builder#setClientState(Bundle) fill response}.
132     *
133     * <p><b>Note:</b> Prior to Android {@link android.os.Build.VERSION_CODES#P}, only client state
134     * bundles set by {@link FillResponse.Builder#setClientState(Bundle)} were considered. On
135     * Android {@link android.os.Build.VERSION_CODES#P} and higher, bundles set in the result of
136     * an authenticated request through the
137     * {@link android.view.autofill.AutofillManager#EXTRA_CLIENT_STATE} extra are
138     * also considered (and take precedence when set).
139     *
140     * @return The client state.
141     */
142    public @Nullable Bundle getClientState() {
143        return mClientState;
144    }
145
146    @Override
147    public int describeContents() {
148        return 0;
149    }
150
151    @Override
152    public void writeToParcel(Parcel parcel, int flags) {
153        parcel.writeInt(mId);
154        parcel.writeParcelableList(mContexts, flags);
155        parcel.writeBundle(mClientState);
156        parcel.writeInt(mFlags);
157    }
158
159    public static final Parcelable.Creator<FillRequest> CREATOR =
160            new Parcelable.Creator<FillRequest>() {
161        @Override
162        public FillRequest createFromParcel(Parcel parcel) {
163            return new FillRequest(parcel);
164        }
165
166        @Override
167        public FillRequest[] newArray(int size) {
168            return new FillRequest[size];
169        }
170    };
171}
172