/* * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.view.autofill; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.TestApi; import android.os.Parcel; import android.os.Parcelable; import android.view.View; import java.util.Objects; /** * A unique identifier for an autofill node inside an {@link android.app.Activity}. */ public final class AutofillId implements Parcelable { /** @hide */ public static final int NO_SESSION = 0; private static final int FLAG_IS_VIRTUAL_INT = 0x1; private static final int FLAG_IS_VIRTUAL_LONG = 0x2; private static final int FLAG_HAS_SESSION = 0x4; private final int mViewId; private int mFlags; private final int mVirtualIntId; private final long mVirtualLongId; private int mSessionId; /** @hide */ @TestApi public AutofillId(int id) { this(/* flags= */ 0, id, View.NO_ID, NO_SESSION); } /** @hide */ @TestApi public AutofillId(@NonNull AutofillId hostId, int virtualChildId) { this(FLAG_IS_VIRTUAL_INT, hostId.mViewId, virtualChildId, NO_SESSION); } /** @hide */ @TestApi public AutofillId(int hostId, int virtualChildId) { this(FLAG_IS_VIRTUAL_INT, hostId, virtualChildId, NO_SESSION); } /** @hide */ @TestApi public AutofillId(@NonNull AutofillId hostId, long virtualChildId, int sessionId) { this(FLAG_IS_VIRTUAL_LONG | FLAG_HAS_SESSION, hostId.mViewId, virtualChildId, sessionId); } private AutofillId(int flags, int parentId, long virtualChildId, int sessionId) { mFlags = flags; mViewId = parentId; mVirtualIntId = ((flags & FLAG_IS_VIRTUAL_INT) != 0) ? (int) virtualChildId : View.NO_ID; mVirtualLongId = ((flags & FLAG_IS_VIRTUAL_LONG) != 0) ? virtualChildId : View.NO_ID; mSessionId = sessionId; } /** @hide */ @NonNull public static final AutofillId NO_AUTOFILL_ID = new AutofillId(0); /** * Creates an {@link AutofillId} with the virtual id. * * This method is used by a {@link View} that contains the virtual view hierarchy. Use this * method to create the {@link AutofillId} for each virtual view. * * @param host the view hosting the virtual view hierarchy which is used to show autofill * suggestions. * @param virtualId id identifying the virtual view inside the host view. * @return an {@link AutofillId} for the virtual view */ @NonNull public static AutofillId create(@NonNull View host, int virtualId) { Objects.requireNonNull(host); return new AutofillId(host.getAutofillId(), virtualId); } /** @hide */ @NonNull @TestApi public static AutofillId withoutSession(@NonNull AutofillId id) { final int flags = id.mFlags & ~FLAG_HAS_SESSION; final long virtualChildId = ((id.mFlags & FLAG_IS_VIRTUAL_LONG) != 0) ? id.mVirtualLongId : id.mVirtualIntId; return new AutofillId(flags, id.mViewId, virtualChildId, NO_SESSION); } /** @hide */ public int getViewId() { return mViewId; } /** * Gets the virtual child id. * *
Should only be used on subsystems where such id is represented by an {@code int} * (Assist and Autofill). * * @hide */ public int getVirtualChildIntId() { return mVirtualIntId; } /** * Gets the virtual child id. * *
Should only be used on subsystems where such id is represented by a {@code long} * (ContentCapture). * * @hide */ public long getVirtualChildLongId() { return mVirtualLongId; } /** * Checks whether this node represents a virtual child, whose id is represented by an * {@code int}. * *
Should only be used on subsystems where such id is represented by an {@code int} * (Assist and Autofill). * * @hide */ public boolean isVirtualInt() { return (mFlags & FLAG_IS_VIRTUAL_INT) != 0; } /** * Checks whether this node represents a virtual child, whose id is represented by an * {@code long}. * *
Should only be used on subsystems where such id is represented by a {@code long}
* (ContentCapture).
*
* @hide
*/
public boolean isVirtualLong() {
return (mFlags & FLAG_IS_VIRTUAL_LONG) != 0;
}
/**
* Checks whether this node represents a non-virtual child.
*
* @hide
*/
@TestApi
public boolean isNonVirtual() {
return !isVirtualInt() && !isVirtualLong();
}
/** @hide */
public boolean hasSession() {
return (mFlags & FLAG_HAS_SESSION) != 0;
}
/** @hide */
public int getSessionId() {
return mSessionId;
}
/** @hide */
public void setSessionId(int sessionId) {
mFlags |= FLAG_HAS_SESSION;
mSessionId = sessionId;
}
/** @hide */
public void resetSessionId() {
mFlags &= ~FLAG_HAS_SESSION;
mSessionId = NO_SESSION;
}
/////////////////////////////////
// Object "contract" methods. //
/////////////////////////////////
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + mViewId;
result = prime * result + mVirtualIntId;
result = prime * result + (int) (mVirtualLongId ^ (mVirtualLongId >>> 32));
result = prime * result + mSessionId;
return result;
}
@Override
public boolean equals(@Nullable Object obj) {
if (this == obj) return true;
if (obj == null) return false;
if (getClass() != obj.getClass()) return false;
final AutofillId other = (AutofillId) obj;
if (mViewId != other.mViewId) return false;
if (mVirtualIntId != other.mVirtualIntId) return false;
if (mVirtualLongId != other.mVirtualLongId) return false;
if (mSessionId != other.mSessionId) return false;
return true;
}
/** @hide */
@TestApi
public boolean equalsIgnoreSession(@Nullable AutofillId other) {
if (this == other) return true;
if (other == null) return false;
if (mViewId != other.mViewId) return false;
if (mVirtualIntId != other.mVirtualIntId) return false;
if (mVirtualLongId != other.mVirtualLongId) return false;
return true;
}
@Override
public String toString() {
final StringBuilder builder = new StringBuilder().append(mViewId);
if (isVirtualInt()) {
builder.append(':').append(mVirtualIntId);
} else if (isVirtualLong()) {
builder.append(':').append(mVirtualLongId);
}
if (hasSession()) {
builder.append('@').append(mSessionId);
}
return builder.toString();
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel parcel, int flags) {
parcel.writeInt(mViewId);
parcel.writeInt(mFlags);
if (hasSession()) {
parcel.writeInt(mSessionId);
}
if (isVirtualInt()) {
parcel.writeInt(mVirtualIntId);
} else if (isVirtualLong()) {
parcel.writeLong(mVirtualLongId);
}
}
public static final @android.annotation.NonNull Parcelable.Creator