blob: 64c877759338748f8c24f8f499e0badfd1276a95 [file] [log] [blame]
Felipe Leme640f30a2017-03-06 15:44:06 -08001/*
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.view.autofill;
18
Philip P. Moltmann96689032017-03-09 13:19:55 -080019import static android.view.View.AUTOFILL_TYPE_DATE;
20import static android.view.View.AUTOFILL_TYPE_LIST;
21import static android.view.View.AUTOFILL_TYPE_TEXT;
22import static android.view.View.AUTOFILL_TYPE_TOGGLE;
Felipe Leme9f9ee252017-04-27 13:56:22 -070023import static android.view.autofill.Helper.sDebug;
Felipe Lemea11aadd2018-05-31 13:08:32 -070024import static android.view.autofill.Helper.sVerbose;
Felipe Leme640f30a2017-03-06 15:44:06 -080025
Philip P. Moltmann96689032017-03-09 13:19:55 -080026import android.annotation.NonNull;
Felipe Leme640f30a2017-03-06 15:44:06 -080027import android.annotation.Nullable;
Felipe Lemea11aadd2018-05-31 13:08:32 -070028import android.os.Looper;
Felipe Leme640f30a2017-03-06 15:44:06 -080029import android.os.Parcel;
30import android.os.Parcelable;
Felipe Lemea8fce3b2017-04-04 14:22:12 -070031import android.text.TextUtils;
Felipe Lemea11aadd2018-05-31 13:08:32 -070032import android.util.Log;
Felipe Leme640f30a2017-03-06 15:44:06 -080033import android.view.View;
34
Philip P. Moltmann96689032017-03-09 13:19:55 -080035import com.android.internal.util.Preconditions;
36
37import java.util.Objects;
38
Felipe Leme640f30a2017-03-06 15:44:06 -080039/**
40 * Abstracts how a {@link View} can be autofilled by an
41 * {@link android.service.autofill.AutofillService}.
42 *
43 * <p>Each {@link AutofillValue} is associated with a {@code type}, as defined by
44 * {@link View#getAutofillType()}.
45 */
46public final class AutofillValue implements Parcelable {
Felipe Lemea11aadd2018-05-31 13:08:32 -070047
48 private static final String TAG = "AutofillValue";
49
Philip P. Moltmann96689032017-03-09 13:19:55 -080050 private final @View.AutofillType int mType;
51 private final @NonNull Object mValue;
Felipe Leme640f30a2017-03-06 15:44:06 -080052
Philip P. Moltmann96689032017-03-09 13:19:55 -080053 private AutofillValue(@View.AutofillType int type, @NonNull Object value) {
54 mType = type;
55 mValue = value;
Felipe Leme640f30a2017-03-06 15:44:06 -080056 }
57
58 /**
59 * Gets the value to autofill a text field.
60 *
Philip P. Moltmann96689032017-03-09 13:19:55 -080061 * <p>See {@link View#AUTOFILL_TYPE_TEXT} for more info.</p>
62 *
63 * @throws IllegalStateException if the value is not a text value
Felipe Leme640f30a2017-03-06 15:44:06 -080064 */
Philip P. Moltmann96689032017-03-09 13:19:55 -080065 @NonNull public CharSequence getTextValue() {
66 Preconditions.checkState(isText(), "value must be a text value, not type=" + mType);
67 return (CharSequence) mValue;
68 }
69
70 /**
71 * Checks is this is a text value.
72 *
73 * <p>See {@link View#AUTOFILL_TYPE_TEXT} for more info.</p>
74 */
75 public boolean isText() {
76 return mType == AUTOFILL_TYPE_TEXT;
Felipe Leme640f30a2017-03-06 15:44:06 -080077 }
78
79 /**
80 * Gets the value to autofill a toggable field.
81 *
Philip P. Moltmann96689032017-03-09 13:19:55 -080082 * <p>See {@link View#AUTOFILL_TYPE_TOGGLE} for more info.</p>
83 *
84 * @throws IllegalStateException if the value is not a toggle value
Felipe Leme640f30a2017-03-06 15:44:06 -080085 */
86 public boolean getToggleValue() {
Philip P. Moltmann96689032017-03-09 13:19:55 -080087 Preconditions.checkState(isToggle(), "value must be a toggle value, not type=" + mType);
88 return (Boolean) mValue;
89 }
90
91 /**
92 * Checks is this is a toggle value.
93 *
94 * <p>See {@link View#AUTOFILL_TYPE_TOGGLE} for more info.</p>
95 */
96 public boolean isToggle() {
97 return mType == AUTOFILL_TYPE_TOGGLE;
Felipe Leme640f30a2017-03-06 15:44:06 -080098 }
99
100 /**
101 * Gets the value to autofill a selection list field.
102 *
Philip P. Moltmann96689032017-03-09 13:19:55 -0800103 * <p>See {@link View#AUTOFILL_TYPE_LIST} for more info.</p>
104 *
105 * @throws IllegalStateException if the value is not a list value
Felipe Leme640f30a2017-03-06 15:44:06 -0800106 */
107 public int getListValue() {
Philip P. Moltmann96689032017-03-09 13:19:55 -0800108 Preconditions.checkState(isList(), "value must be a list value, not type=" + mType);
109 return (Integer) mValue;
110 }
111
112 /**
113 * Checks is this is a list value.
114 *
115 * <p>See {@link View#AUTOFILL_TYPE_LIST} for more info.</p>
116 */
117 public boolean isList() {
118 return mType == AUTOFILL_TYPE_LIST;
Felipe Leme640f30a2017-03-06 15:44:06 -0800119 }
120
121 /**
122 * Gets the value to autofill a date field.
123 *
Philip P. Moltmann96689032017-03-09 13:19:55 -0800124 * <p>See {@link View#AUTOFILL_TYPE_DATE} for more info.</p>
125 *
126 * @throws IllegalStateException if the value is not a date value
Felipe Leme640f30a2017-03-06 15:44:06 -0800127 */
128 public long getDateValue() {
Philip P. Moltmann96689032017-03-09 13:19:55 -0800129 Preconditions.checkState(isDate(), "value must be a date value, not type=" + mType);
130 return (Long) mValue;
131 }
132
133 /**
134 * Checks is this is a date value.
135 *
136 * <p>See {@link View#AUTOFILL_TYPE_DATE} for more info.</p>
137 */
138 public boolean isDate() {
139 return mType == AUTOFILL_TYPE_DATE;
Felipe Leme640f30a2017-03-06 15:44:06 -0800140 }
141
Felipe Leme82e37932017-03-10 10:05:56 -0800142 /**
143 * Used to define whether a field is empty so it's not sent to service on save.
144 *
145 * <p>Only applies to some types, like text.
146 *
147 * @hide
148 */
149 public boolean isEmpty() {
Felipe Leme313cf3f2017-06-16 22:57:58 +0000150 return isText() && ((CharSequence) mValue).length() == 0;
Felipe Leme82e37932017-03-10 10:05:56 -0800151 }
152
Felipe Leme640f30a2017-03-06 15:44:06 -0800153 /////////////////////////////////////
154 // Object "contract" methods. //
155 /////////////////////////////////////
156
157 @Override
158 public int hashCode() {
Philip P. Moltmann96689032017-03-09 13:19:55 -0800159 return mType + mValue.hashCode();
Felipe Leme640f30a2017-03-06 15:44:06 -0800160 }
161
162 @Override
163 public boolean equals(Object obj) {
164 if (this == obj) return true;
165 if (obj == null) return false;
166 if (getClass() != obj.getClass()) return false;
167 final AutofillValue other = (AutofillValue) obj;
Philip P. Moltmann96689032017-03-09 13:19:55 -0800168
169 if (mType != other.mType) return false;
170
171 if (isText()) {
172 return mValue.toString().equals(other.mValue.toString());
Felipe Leme640f30a2017-03-06 15:44:06 -0800173 } else {
Philip P. Moltmann96689032017-03-09 13:19:55 -0800174 return Objects.equals(mValue, other.mValue);
Felipe Leme640f30a2017-03-06 15:44:06 -0800175 }
Felipe Leme640f30a2017-03-06 15:44:06 -0800176 }
177
Felipe Leme640f30a2017-03-06 15:44:06 -0800178 @Override
179 public String toString() {
Felipe Leme9f9ee252017-04-27 13:56:22 -0700180 if (!sDebug) return super.toString();
Felipe Leme640f30a2017-03-06 15:44:06 -0800181
Felipe Leme9f9ee252017-04-27 13:56:22 -0700182 final StringBuilder string = new StringBuilder()
183 .append("[type=").append(mType)
184 .append(", value=");
185 if (isText()) {
Felipe Leme452886a2017-11-27 13:09:13 -0800186 Helper.appendRedacted(string, (CharSequence) mValue);
Felipe Leme9f9ee252017-04-27 13:56:22 -0700187 } else {
188 string.append(mValue);
189 }
190 return string.append(']').toString();
Felipe Leme640f30a2017-03-06 15:44:06 -0800191 }
192
193 /////////////////////////////////////
194 // Parcelable "contract" methods. //
195 /////////////////////////////////////
196
197 @Override
198 public int describeContents() {
199 return 0;
200 }
201
202 @Override
203 public void writeToParcel(Parcel parcel, int flags) {
Philip P. Moltmann96689032017-03-09 13:19:55 -0800204 parcel.writeInt(mType);
205
206 switch (mType) {
207 case AUTOFILL_TYPE_TEXT:
208 parcel.writeCharSequence((CharSequence) mValue);
209 break;
210 case AUTOFILL_TYPE_TOGGLE:
211 parcel.writeInt((Boolean) mValue ? 1 : 0);
212 break;
213 case AUTOFILL_TYPE_LIST:
214 parcel.writeInt((Integer) mValue);
215 break;
216 case AUTOFILL_TYPE_DATE:
217 parcel.writeLong((Long) mValue);
218 break;
219 }
Felipe Leme640f30a2017-03-06 15:44:06 -0800220 }
221
Philip P. Moltmann96689032017-03-09 13:19:55 -0800222 private AutofillValue(@NonNull Parcel parcel) {
223 mType = parcel.readInt();
224
225 switch (mType) {
226 case AUTOFILL_TYPE_TEXT:
227 mValue = parcel.readCharSequence();
228 break;
229 case AUTOFILL_TYPE_TOGGLE:
230 int rawValue = parcel.readInt();
231 mValue = rawValue != 0;
232 break;
233 case AUTOFILL_TYPE_LIST:
234 mValue = parcel.readInt();
235 break;
236 case AUTOFILL_TYPE_DATE:
237 mValue = parcel.readLong();
238 break;
239 default:
240 throw new IllegalArgumentException("type=" + mType + " not valid");
241 }
Felipe Leme640f30a2017-03-06 15:44:06 -0800242 }
243
Jeff Sharkey9e8f83d2019-02-28 12:06:45 -0700244 public static final @android.annotation.NonNull Parcelable.Creator<AutofillValue> CREATOR =
Felipe Leme640f30a2017-03-06 15:44:06 -0800245 new Parcelable.Creator<AutofillValue>() {
246 @Override
247 public AutofillValue createFromParcel(Parcel source) {
248 return new AutofillValue(source);
249 }
250
251 @Override
252 public AutofillValue[] newArray(int size) {
253 return new AutofillValue[size];
254 }
255 };
256
257 ////////////////////
258 // Factory methods //
259 ////////////////////
260
261 /**
262 * Creates a new {@link AutofillValue} to autofill a {@link View} representing a text field.
263 *
264 * <p>See {@link View#AUTOFILL_TYPE_TEXT} for more info.
Felipe Lemea11aadd2018-05-31 13:08:32 -0700265 *
266 * <p><b>Note:</b> This method is not thread safe and can throw an exception if the
267 * {@code value} is modified by a different thread before it returns.
Felipe Leme640f30a2017-03-06 15:44:06 -0800268 */
Felipe Leme640f30a2017-03-06 15:44:06 -0800269 public static AutofillValue forText(@Nullable CharSequence value) {
Felipe Lemea11aadd2018-05-31 13:08:32 -0700270 if (sVerbose && !Looper.getMainLooper().isCurrentThread()) {
271 Log.v(TAG, "forText() not called on main thread: " + Thread.currentThread());
272 }
273
Felipe Lemea8fce3b2017-04-04 14:22:12 -0700274 return value == null ? null : new AutofillValue(AUTOFILL_TYPE_TEXT,
275 TextUtils.trimNoCopySpans(value));
Felipe Leme640f30a2017-03-06 15:44:06 -0800276 }
277
278 /**
279 * Creates a new {@link AutofillValue} to autofill a {@link View} representing a toggable
280 * field.
281 *
282 * <p>See {@link View#AUTOFILL_TYPE_TOGGLE} for more info.
283 */
284 public static AutofillValue forToggle(boolean value) {
Philip P. Moltmann96689032017-03-09 13:19:55 -0800285 return new AutofillValue(AUTOFILL_TYPE_TOGGLE, value);
Felipe Leme640f30a2017-03-06 15:44:06 -0800286 }
287
288 /**
289 * Creates a new {@link AutofillValue} to autofill a {@link View} representing a selection
290 * list.
291 *
292 * <p>See {@link View#AUTOFILL_TYPE_LIST} for more info.
293 */
294 public static AutofillValue forList(int value) {
Philip P. Moltmann96689032017-03-09 13:19:55 -0800295 return new AutofillValue(AUTOFILL_TYPE_LIST, value);
Felipe Leme640f30a2017-03-06 15:44:06 -0800296 }
297
298 /**
299 * Creates a new {@link AutofillValue} to autofill a {@link View} representing a date.
300 *
301 * <p>See {@link View#AUTOFILL_TYPE_DATE} for more info.
302 */
303 public static AutofillValue forDate(long value) {
Philip P. Moltmann96689032017-03-09 13:19:55 -0800304 return new AutofillValue(AUTOFILL_TYPE_DATE, value);
Felipe Leme640f30a2017-03-06 15:44:06 -0800305 }
306}