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 package android.view.autofill;
17 
18 import android.annotation.NonNull;
19 import android.annotation.Nullable;
20 import android.annotation.TestApi;
21 import android.os.Parcel;
22 import android.os.Parcelable;
23 import android.view.View;
24 
25 /**
26  * A unique identifier for an autofill node inside an {@link android.app.Activity}.
27  */
28 public final class AutofillId implements Parcelable {
29 
30     /** @hide */
31     public static final int NO_SESSION = 0;
32 
33     private static final int FLAG_IS_VIRTUAL_INT = 0x1;
34     private static final int FLAG_IS_VIRTUAL_LONG = 0x2;
35     private static final int FLAG_HAS_SESSION = 0x4;
36 
37     private final int mViewId;
38     private int mFlags;
39     private final int mVirtualIntId;
40     private final long mVirtualLongId;
41     private int mSessionId;
42 
43     /** @hide */
44     @TestApi
AutofillId(int id)45     public AutofillId(int id) {
46         this(/* flags= */ 0, id, View.NO_ID, NO_SESSION);
47     }
48 
49     /** @hide */
50     @TestApi
AutofillId(@onNull AutofillId hostId, int virtualChildId)51     public AutofillId(@NonNull AutofillId hostId, int virtualChildId) {
52         this(FLAG_IS_VIRTUAL_INT, hostId.mViewId, virtualChildId, NO_SESSION);
53     }
54 
55     /** @hide */
56     @TestApi
AutofillId(int hostId, int virtualChildId)57     public AutofillId(int hostId, int virtualChildId) {
58         this(FLAG_IS_VIRTUAL_INT, hostId, virtualChildId, NO_SESSION);
59     }
60 
61     /** @hide */
62     @TestApi
AutofillId(@onNull AutofillId hostId, long virtualChildId, int sessionId)63     public AutofillId(@NonNull AutofillId hostId, long virtualChildId, int sessionId) {
64         this(FLAG_IS_VIRTUAL_LONG | FLAG_HAS_SESSION, hostId.mViewId, virtualChildId, sessionId);
65     }
66 
AutofillId(int flags, int parentId, long virtualChildId, int sessionId)67     private AutofillId(int flags, int parentId, long virtualChildId, int sessionId) {
68         mFlags = flags;
69         mViewId = parentId;
70         mVirtualIntId = ((flags & FLAG_IS_VIRTUAL_INT) != 0) ? (int) virtualChildId : View.NO_ID;
71         mVirtualLongId = ((flags & FLAG_IS_VIRTUAL_LONG) != 0) ? virtualChildId : View.NO_ID;
72         mSessionId = sessionId;
73     }
74 
75     /** @hide */
withoutSession(@onNull AutofillId id)76     public static AutofillId withoutSession(@NonNull AutofillId id) {
77         final int flags = id.mFlags & ~FLAG_HAS_SESSION;
78         return new AutofillId(flags, id.mViewId, id.mVirtualLongId, NO_SESSION);
79     }
80 
81     /** @hide */
getViewId()82     public int getViewId() {
83         return mViewId;
84     }
85 
86     /**
87      * Gets the virtual child id.
88      *
89      * <p>Should only be used on subsystems where such id is represented by an {@code int}
90      * (Assist and Autofill).
91      *
92      * @hide
93      */
getVirtualChildIntId()94     public int getVirtualChildIntId() {
95         return mVirtualIntId;
96     }
97 
98     /**
99      * Gets the virtual child id.
100      *
101      * <p>Should only be used on subsystems where such id is represented by a {@code long}
102      * (ContentCapture).
103      *
104      * @hide
105      */
getVirtualChildLongId()106     public long getVirtualChildLongId() {
107         return mVirtualLongId;
108     }
109 
110     /**
111      * Checks whether this node represents a virtual child, whose id is represented by an
112      * {@code int}.
113      *
114      * <p>Should only be used on subsystems where such id is represented by an {@code int}
115      * (Assist and Autofill).
116      *
117      * @hide
118      */
isVirtualInt()119     public boolean isVirtualInt() {
120         return (mFlags & FLAG_IS_VIRTUAL_INT) != 0;
121     }
122 
123     /**
124      * Checks whether this node represents a virtual child, whose id is represented by an
125      * {@code long}.
126      *
127      * <p>Should only be used on subsystems where such id is represented by a {@code long}
128      * (ContentCapture).
129      *
130      * @hide
131      */
isVirtualLong()132     public boolean isVirtualLong() {
133         return (mFlags & FLAG_IS_VIRTUAL_LONG) != 0;
134     }
135 
136     /**
137      * Checks whether this node represents a non-virtual child.
138      *
139      * @hide
140      */
isNonVirtual()141     public boolean isNonVirtual() {
142         return !isVirtualInt() && !isVirtualLong();
143     }
144 
145     /** @hide */
hasSession()146     public boolean hasSession() {
147         return (mFlags & FLAG_HAS_SESSION) != 0;
148     }
149 
150     /** @hide */
getSessionId()151     public int getSessionId() {
152         return mSessionId;
153     }
154 
155     /** @hide */
setSessionId(int sessionId)156     public void setSessionId(int sessionId) {
157         mFlags |= FLAG_HAS_SESSION;
158         mSessionId = sessionId;
159     }
160 
161     /** @hide */
resetSessionId()162     public void resetSessionId() {
163         mFlags &= ~FLAG_HAS_SESSION;
164         mSessionId = NO_SESSION;
165     }
166 
167     /////////////////////////////////
168     //  Object "contract" methods. //
169     /////////////////////////////////
170 
171     @Override
hashCode()172     public int hashCode() {
173         final int prime = 31;
174         int result = 1;
175         result = prime * result + mViewId;
176         result = prime * result + mVirtualIntId;
177         result = prime * result + (int) (mVirtualLongId ^ (mVirtualLongId >>> 32));
178         result = prime * result + mSessionId;
179         return result;
180     }
181 
182     @Override
equals(Object obj)183     public boolean equals(Object obj) {
184         if (this == obj) return true;
185         if (obj == null) return false;
186         if (getClass() != obj.getClass()) return false;
187         final AutofillId other = (AutofillId) obj;
188         if (mViewId != other.mViewId) return false;
189         if (mVirtualIntId != other.mVirtualIntId) return false;
190         if (mVirtualLongId != other.mVirtualLongId) return false;
191         if (mSessionId != other.mSessionId) return false;
192         return true;
193     }
194 
195     /** @hide */
196     @TestApi
equalsIgnoreSession(@ullable AutofillId other)197     public boolean equalsIgnoreSession(@Nullable AutofillId other) {
198         if (this == other) return true;
199         if (other == null) return false;
200         if (mViewId != other.mViewId) return false;
201         if (mVirtualIntId != other.mVirtualIntId) return false;
202         if (mVirtualLongId != other.mVirtualLongId) return false;
203         return true;
204     }
205 
206     @Override
toString()207     public String toString() {
208         final StringBuilder builder = new StringBuilder().append(mViewId);
209         if (isVirtualInt()) {
210             builder.append(':').append(mVirtualIntId);
211         } else if (isVirtualLong()) {
212             builder.append(':').append(mVirtualLongId);
213         }
214 
215         if (hasSession()) {
216             builder.append('@').append(mSessionId);
217         }
218         return builder.toString();
219     }
220 
221     @Override
describeContents()222     public int describeContents() {
223         return 0;
224     }
225 
226     @Override
writeToParcel(Parcel parcel, int flags)227     public void writeToParcel(Parcel parcel, int flags) {
228         parcel.writeInt(mViewId);
229         parcel.writeInt(mFlags);
230         if (hasSession()) {
231             parcel.writeInt(mSessionId);
232         }
233         if (isVirtualInt()) {
234             parcel.writeInt(mVirtualIntId);
235         } else if (isVirtualLong()) {
236             parcel.writeLong(mVirtualLongId);
237         }
238     }
239 
240     public static final @android.annotation.NonNull Parcelable.Creator<AutofillId> CREATOR =
241             new Parcelable.Creator<AutofillId>() {
242         @Override
243         public AutofillId createFromParcel(Parcel source) {
244             final int viewId = source.readInt();
245             final int flags = source.readInt();
246             final int sessionId = (flags & FLAG_HAS_SESSION) != 0 ? source.readInt() : NO_SESSION;
247             if ((flags & FLAG_IS_VIRTUAL_INT) != 0) {
248                 return new AutofillId(flags, viewId, source.readInt(), sessionId);
249             }
250             if ((flags & FLAG_IS_VIRTUAL_LONG) != 0) {
251                 return new AutofillId(flags, viewId, source.readLong(), sessionId);
252             }
253             return new AutofillId(flags, viewId, View.NO_ID, sessionId);
254         }
255 
256         @Override
257         public AutofillId[] newArray(int size) {
258             return new AutofillId[size];
259         }
260     };
261 }
262