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 
17 package android.view.autofill;
18 
19 import static android.view.View.AUTOFILL_TYPE_DATE;
20 import static android.view.View.AUTOFILL_TYPE_LIST;
21 import static android.view.View.AUTOFILL_TYPE_TEXT;
22 import static android.view.View.AUTOFILL_TYPE_TOGGLE;
23 import static android.view.autofill.Helper.sDebug;
24 import static android.view.autofill.Helper.sVerbose;
25 
26 import android.annotation.NonNull;
27 import android.annotation.Nullable;
28 import android.os.Looper;
29 import android.os.Parcel;
30 import android.os.Parcelable;
31 import android.text.TextUtils;
32 import android.util.Log;
33 import android.view.View;
34 
35 import com.android.internal.util.Preconditions;
36 
37 import java.util.Objects;
38 
39 /**
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  */
46 public final class AutofillValue implements Parcelable {
47 
48     private static final String TAG = "AutofillValue";
49 
50     private final @View.AutofillType int mType;
51     private final @NonNull Object mValue;
52 
AutofillValue(@iew.AutofillType int type, @NonNull Object value)53     private AutofillValue(@View.AutofillType int type, @NonNull Object value) {
54         mType = type;
55         mValue = value;
56     }
57 
58     /**
59      * Gets the value to autofill a text field.
60      *
61      * <p>See {@link View#AUTOFILL_TYPE_TEXT} for more info.</p>
62      *
63      * @throws IllegalStateException if the value is not a text value
64      */
getTextValue()65     @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      */
isText()75     public boolean isText() {
76         return mType == AUTOFILL_TYPE_TEXT;
77     }
78 
79     /**
80      * Gets the value to autofill a toggable field.
81      *
82      * <p>See {@link View#AUTOFILL_TYPE_TOGGLE} for more info.</p>
83      *
84      * @throws IllegalStateException if the value is not a toggle value
85      */
getToggleValue()86     public boolean getToggleValue() {
87         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      */
isToggle()96     public boolean isToggle() {
97         return mType == AUTOFILL_TYPE_TOGGLE;
98     }
99 
100     /**
101      * Gets the value to autofill a selection list field.
102      *
103      * <p>See {@link View#AUTOFILL_TYPE_LIST} for more info.</p>
104      *
105      * @throws IllegalStateException if the value is not a list value
106      */
getListValue()107     public int getListValue() {
108         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      */
isList()117     public boolean isList() {
118         return mType == AUTOFILL_TYPE_LIST;
119     }
120 
121     /**
122      * Gets the value to autofill a date field.
123      *
124      * <p>See {@link View#AUTOFILL_TYPE_DATE} for more info.</p>
125      *
126      * @throws IllegalStateException if the value is not a date value
127      */
getDateValue()128     public long getDateValue() {
129         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      */
isDate()138     public boolean isDate() {
139         return mType == AUTOFILL_TYPE_DATE;
140     }
141 
142     /**
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      */
isEmpty()149     public boolean isEmpty() {
150         return isText() && ((CharSequence) mValue).length() == 0;
151     }
152 
153     /////////////////////////////////////
154     //  Object "contract" methods. //
155     /////////////////////////////////////
156 
157     @Override
hashCode()158     public int hashCode() {
159         return mType + mValue.hashCode();
160     }
161 
162     @Override
equals(Object obj)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;
168 
169         if (mType != other.mType) return false;
170 
171         if (isText()) {
172             return mValue.toString().equals(other.mValue.toString());
173         } else {
174             return Objects.equals(mValue, other.mValue);
175         }
176     }
177 
178     @Override
toString()179     public String toString() {
180         if (!sDebug) return super.toString();
181 
182         final StringBuilder string = new StringBuilder()
183                 .append("[type=").append(mType)
184                 .append(", value=");
185         if (isText()) {
186             Helper.appendRedacted(string, (CharSequence) mValue);
187         } else {
188             string.append(mValue);
189         }
190         return string.append(']').toString();
191     }
192 
193     /////////////////////////////////////
194     //  Parcelable "contract" methods. //
195     /////////////////////////////////////
196 
197     @Override
describeContents()198     public int describeContents() {
199         return 0;
200     }
201 
202     @Override
writeToParcel(Parcel parcel, int flags)203     public void writeToParcel(Parcel parcel, int flags) {
204         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         }
220     }
221 
AutofillValue(@onNull Parcel parcel)222     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         }
242     }
243 
244     public static final @android.annotation.NonNull Parcelable.Creator<AutofillValue> CREATOR =
245             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.
265      *
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.
268      */
forText(@ullable CharSequence value)269     public static AutofillValue forText(@Nullable CharSequence value) {
270         if (sVerbose && !Looper.getMainLooper().isCurrentThread()) {
271             Log.v(TAG, "forText() not called on main thread: " + Thread.currentThread());
272         }
273 
274         return value == null ? null : new AutofillValue(AUTOFILL_TYPE_TEXT,
275                 TextUtils.trimNoCopySpans(value));
276     }
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      */
forToggle(boolean value)284     public static AutofillValue forToggle(boolean value) {
285         return new AutofillValue(AUTOFILL_TYPE_TOGGLE, value);
286     }
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      */
forList(int value)294     public static AutofillValue forList(int value) {
295         return new AutofillValue(AUTOFILL_TYPE_LIST, value);
296     }
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      */
forDate(long value)303     public static AutofillValue forDate(long value) {
304         return new AutofillValue(AUTOFILL_TYPE_DATE, value);
305     }
306 }
307