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