Loading core/java/android/view/accessibility/AccessibilityNodeInfo.java +310 −235 Original line number Diff line number Diff line Loading @@ -16,6 +16,9 @@ package android.view.accessibility; import static com.android.internal.util.BitUtils.bitAt; import static com.android.internal.util.BitUtils.isBitSet; import static java.util.Collections.EMPTY_LIST; import android.accessibilityservice.AccessibilityService; Loading @@ -41,10 +44,12 @@ import android.util.Pools.SynchronizedPool; import android.view.View; import com.android.internal.R; import com.android.internal.util.CollectionUtils; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Objects; import java.util.concurrent.atomic.AtomicInteger; /** Loading Loading @@ -636,7 +641,6 @@ public class AccessibilityNodeInfo implements Parcelable { * Bits that provide the id of a virtual descendant of a view. */ private static final long VIRTUAL_DESCENDANT_ID_MASK = 0xffffffff00000000L; /** * Bit shift of {@link #VIRTUAL_DESCENDANT_ID_MASK} to get to the id for a * virtual descendant of a view. Such a descendant does not exist in the view Loading Loading @@ -692,6 +696,8 @@ public class AccessibilityNodeInfo implements Parcelable { private static final SynchronizedPool<AccessibilityNodeInfo> sPool = new SynchronizedPool<>(MAX_POOL_SIZE); private static final AccessibilityNodeInfo DEFAULT = new AccessibilityNodeInfo(); private boolean mSealed; // Data. Loading Loading @@ -1068,11 +1074,7 @@ public class AccessibilityNodeInfo implements Parcelable { * Gets the actions that can be performed on the node. */ public List<AccessibilityAction> getActionList() { if (mActions == null) { return Collections.emptyList(); } return mActions; return CollectionUtils.emptyIfNull(mActions); } /** Loading Loading @@ -3050,17 +3052,118 @@ public class AccessibilityNodeInfo implements Parcelable { */ @Override public void writeToParcel(Parcel parcel, int flags) { parcel.writeInt(isSealed() ? 1 : 0); parcel.writeLong(mSourceNodeId); parcel.writeInt(mWindowId); parcel.writeLong(mParentNodeId); parcel.writeLong(mLabelForId); parcel.writeLong(mLabeledById); parcel.writeLong(mTraversalBefore); parcel.writeLong(mTraversalAfter); parcel.writeInt(mConnectionId); // Write bit set of indices of fields with values differing from default long nonDefaultFields = 0; int fieldIndex = 0; // index of the current field if (isSealed() != DEFAULT.isSealed()) nonDefaultFields |= bitAt(fieldIndex); fieldIndex++; if (mSourceNodeId != DEFAULT.mSourceNodeId) nonDefaultFields |= bitAt(fieldIndex); fieldIndex++; if (mWindowId != DEFAULT.mWindowId) nonDefaultFields |= bitAt(fieldIndex); fieldIndex++; if (mParentNodeId != DEFAULT.mParentNodeId) nonDefaultFields |= bitAt(fieldIndex); fieldIndex++; if (mLabelForId != DEFAULT.mLabelForId) nonDefaultFields |= bitAt(fieldIndex); fieldIndex++; if (mLabeledById != DEFAULT.mLabeledById) nonDefaultFields |= bitAt(fieldIndex); fieldIndex++; if (mTraversalBefore != DEFAULT.mTraversalBefore) nonDefaultFields |= bitAt(fieldIndex); fieldIndex++; if (mTraversalAfter != DEFAULT.mTraversalAfter) nonDefaultFields |= bitAt(fieldIndex); fieldIndex++; if (mConnectionId != DEFAULT.mConnectionId) nonDefaultFields |= bitAt(fieldIndex); fieldIndex++; if (!Objects.equals(mChildNodeIds, DEFAULT.mChildNodeIds)) { nonDefaultFields |= bitAt(fieldIndex); } fieldIndex++; if (!Objects.equals(mBoundsInParent, DEFAULT.mBoundsInParent)) { nonDefaultFields |= bitAt(fieldIndex); } fieldIndex++; if (!Objects.equals(mBoundsInScreen, DEFAULT.mBoundsInScreen)) { nonDefaultFields |= bitAt(fieldIndex); } fieldIndex++; if (!Objects.equals(mActions, DEFAULT.mActions)) nonDefaultFields |= bitAt(fieldIndex); fieldIndex++; if (mMaxTextLength != DEFAULT.mMaxTextLength) nonDefaultFields |= bitAt(fieldIndex); fieldIndex++; if (mMovementGranularities != DEFAULT.mMovementGranularities) { nonDefaultFields |= bitAt(fieldIndex); } fieldIndex++; if (mBooleanProperties != DEFAULT.mBooleanProperties) nonDefaultFields |= bitAt(fieldIndex); fieldIndex++; if (!Objects.equals(mPackageName, DEFAULT.mPackageName)) { nonDefaultFields |= bitAt(fieldIndex); } fieldIndex++; if (!Objects.equals(mClassName, DEFAULT.mClassName)) nonDefaultFields |= bitAt(fieldIndex); fieldIndex++; if (!Objects.equals(mText, DEFAULT.mText)) nonDefaultFields |= bitAt(fieldIndex); fieldIndex++; if (!Objects.equals(mHintText, DEFAULT.mHintText)) { nonDefaultFields |= bitAt(fieldIndex); } fieldIndex++; if (!Objects.equals(mError, DEFAULT.mError)) nonDefaultFields |= bitAt(fieldIndex); fieldIndex++; if (!Objects.equals(mContentDescription, DEFAULT.mContentDescription)) { nonDefaultFields |= bitAt(fieldIndex); } fieldIndex++; if (!Objects.equals(mViewIdResourceName, DEFAULT.mViewIdResourceName)) { nonDefaultFields |= bitAt(fieldIndex); } fieldIndex++; if (mTextSelectionStart != DEFAULT.mTextSelectionStart) { nonDefaultFields |= bitAt(fieldIndex); } fieldIndex++; if (mTextSelectionEnd != DEFAULT.mTextSelectionEnd) { nonDefaultFields |= bitAt(fieldIndex); } fieldIndex++; if (mInputType != DEFAULT.mInputType) nonDefaultFields |= bitAt(fieldIndex); fieldIndex++; if (mLiveRegion != DEFAULT.mLiveRegion) nonDefaultFields |= bitAt(fieldIndex); fieldIndex++; if (mDrawingOrderInParent != DEFAULT.mDrawingOrderInParent) { nonDefaultFields |= bitAt(fieldIndex); } fieldIndex++; if (!Objects.equals(mExtraDataKeys, DEFAULT.mExtraDataKeys)) { nonDefaultFields |= bitAt(fieldIndex); } fieldIndex++; if (!Objects.equals(mExtras, DEFAULT.mExtras)) nonDefaultFields |= bitAt(fieldIndex); fieldIndex++; if (!Objects.equals(mRangeInfo, DEFAULT.mRangeInfo)) nonDefaultFields |= bitAt(fieldIndex); fieldIndex++; if (!Objects.equals(mCollectionInfo, DEFAULT.mCollectionInfo)) { nonDefaultFields |= bitAt(fieldIndex); } fieldIndex++; if (!Objects.equals(mCollectionItemInfo, DEFAULT.mCollectionItemInfo)) { nonDefaultFields |= bitAt(fieldIndex); } int totalFields = fieldIndex; parcel.writeLong(nonDefaultFields); fieldIndex = 0; if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeInt(isSealed() ? 1 : 0); if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeLong(mSourceNodeId); if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeInt(mWindowId); if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeLong(mParentNodeId); if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeLong(mLabelForId); if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeLong(mLabeledById); if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeLong(mTraversalBefore); if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeLong(mTraversalAfter); if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeInt(mConnectionId); if (isBitSet(nonDefaultFields, fieldIndex++)) { final LongArray childIds = mChildNodeIds; if (childIds == null) { parcel.writeInt(0); Loading @@ -3071,17 +3174,23 @@ public class AccessibilityNodeInfo implements Parcelable { parcel.writeLong(childIds.get(i)); } } } if (isBitSet(nonDefaultFields, fieldIndex++)) { parcel.writeInt(mBoundsInParent.top); parcel.writeInt(mBoundsInParent.bottom); parcel.writeInt(mBoundsInParent.left); parcel.writeInt(mBoundsInParent.right); } if (isBitSet(nonDefaultFields, fieldIndex++)) { parcel.writeInt(mBoundsInScreen.top); parcel.writeInt(mBoundsInScreen.bottom); parcel.writeInt(mBoundsInScreen.left); parcel.writeInt(mBoundsInScreen.right); } if (isBitSet(nonDefaultFields, fieldIndex++)) { if (mActions != null && !mActions.isEmpty()) { final int actionCount = mActions.size(); Loading Loading @@ -3109,68 +3218,61 @@ public class AccessibilityNodeInfo implements Parcelable { parcel.writeInt(0); parcel.writeInt(0); } } parcel.writeInt(mMaxTextLength); parcel.writeInt(mMovementGranularities); parcel.writeInt(mBooleanProperties); if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeInt(mMaxTextLength); if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeInt(mMovementGranularities); if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeInt(mBooleanProperties); parcel.writeCharSequence(mPackageName); parcel.writeCharSequence(mClassName); parcel.writeCharSequence(mText); parcel.writeCharSequence(mHintText); parcel.writeCharSequence(mError); if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeCharSequence(mPackageName); if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeCharSequence(mClassName); if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeCharSequence(mText); if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeCharSequence(mHintText); if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeCharSequence(mError); if (isBitSet(nonDefaultFields, fieldIndex++)) { parcel.writeCharSequence(mContentDescription); parcel.writeString(mViewIdResourceName); parcel.writeInt(mTextSelectionStart); parcel.writeInt(mTextSelectionEnd); parcel.writeInt(mInputType); parcel.writeInt(mLiveRegion); parcel.writeInt(mDrawingOrderInParent); if (mExtraDataKeys != null) { parcel.writeInt(1); parcel.writeStringList(mExtraDataKeys); } else { parcel.writeInt(0); } if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeString(mViewIdResourceName); if (mExtras != null) { parcel.writeInt(1); parcel.writeBundle(mExtras); } else { parcel.writeInt(0); } if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeInt(mTextSelectionStart); if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeInt(mTextSelectionEnd); if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeInt(mInputType); if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeInt(mLiveRegion); if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeInt(mDrawingOrderInParent); if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeStringList(mExtraDataKeys); if (mRangeInfo != null) { parcel.writeInt(1); if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeBundle(mExtras); if (isBitSet(nonDefaultFields, fieldIndex++)) { parcel.writeInt(mRangeInfo.getType()); parcel.writeFloat(mRangeInfo.getMin()); parcel.writeFloat(mRangeInfo.getMax()); parcel.writeFloat(mRangeInfo.getCurrent()); } else { parcel.writeInt(0); } if (mCollectionInfo != null) { parcel.writeInt(1); if (isBitSet(nonDefaultFields, fieldIndex++)) { parcel.writeInt(mCollectionInfo.getRowCount()); parcel.writeInt(mCollectionInfo.getColumnCount()); parcel.writeInt(mCollectionInfo.isHierarchical() ? 1 : 0); parcel.writeInt(mCollectionInfo.getSelectionMode()); } else { parcel.writeInt(0); } if (mCollectionItemInfo != null) { parcel.writeInt(1); if (isBitSet(nonDefaultFields, fieldIndex++)) { parcel.writeInt(mCollectionItemInfo.getRowIndex()); parcel.writeInt(mCollectionItemInfo.getRowSpan()); parcel.writeInt(mCollectionItemInfo.getColumnIndex()); parcel.writeInt(mCollectionItemInfo.getColumnSpan()); parcel.writeInt(mCollectionItemInfo.isHeading() ? 1 : 0); parcel.writeInt(mCollectionItemInfo.isSelected() ? 1 : 0); } else { parcel.writeInt(0); } if (DEBUG) { fieldIndex--; if (totalFields != fieldIndex) { throw new IllegalStateException("Number of fields mismatch: " + totalFields + " vs " + fieldIndex); } } // Since instances of this class are fetched via synchronous i.e. blocking Loading Loading @@ -3203,12 +3305,12 @@ public class AccessibilityNodeInfo implements Parcelable { mContentDescription = other.mContentDescription; mViewIdResourceName = other.mViewIdResourceName; if (mActions != null) mActions.clear(); final ArrayList<AccessibilityAction> otherActions = other.mActions; if (otherActions != null && otherActions.size() > 0) { if (mActions == null) { mActions = new ArrayList(otherActions); } else { mActions.clear(); mActions.addAll(other.mActions); } } Loading @@ -3217,12 +3319,13 @@ public class AccessibilityNodeInfo implements Parcelable { mMaxTextLength = other.mMaxTextLength; mMovementGranularities = other.mMovementGranularities; if (mChildNodeIds != null) mChildNodeIds.clear(); final LongArray otherChildNodeIds = other.mChildNodeIds; if (otherChildNodeIds != null && otherChildNodeIds.size() > 0) { if (mChildNodeIds == null) { mChildNodeIds = otherChildNodeIds.clone(); } else { mChildNodeIds.clear(); mChildNodeIds.addAll(otherChildNodeIds); } } Loading @@ -3232,17 +3335,18 @@ public class AccessibilityNodeInfo implements Parcelable { mInputType = other.mInputType; mLiveRegion = other.mLiveRegion; mDrawingOrderInParent = other.mDrawingOrderInParent; mExtraDataKeys = other.mExtraDataKeys; if (other.mExtras != null) { mExtras = new Bundle(other.mExtras); } else { mExtras = null; } mExtras = other.mExtras != null ? new Bundle(other.mExtras) : null; if (mRangeInfo != null) mRangeInfo.recycle(); mRangeInfo = (other.mRangeInfo != null) ? RangeInfo.obtain(other.mRangeInfo) : null; if (mCollectionInfo != null) mCollectionInfo.recycle(); mCollectionInfo = (other.mCollectionInfo != null) ? CollectionInfo.obtain(other.mCollectionInfo) : null; if (mCollectionItemInfo != null) mCollectionItemInfo.recycle(); mCollectionItemInfo = (other.mCollectionItemInfo != null) ? CollectionItemInfo.obtain(other.mCollectionItemInfo) : null; } Loading @@ -3253,17 +3357,23 @@ public class AccessibilityNodeInfo implements Parcelable { * @param parcel A parcel containing the state of a {@link AccessibilityNodeInfo}. */ private void initFromParcel(Parcel parcel) { final boolean sealed = (parcel.readInt() == 1); mSourceNodeId = parcel.readLong(); mWindowId = parcel.readInt(); mParentNodeId = parcel.readLong(); mLabelForId = parcel.readLong(); mLabeledById = parcel.readLong(); mTraversalBefore = parcel.readLong(); mTraversalAfter = parcel.readLong(); mConnectionId = parcel.readInt(); // Bit mask of non-default-valued field indices long nonDefaultFields = parcel.readLong(); int fieldIndex = 0; final boolean sealed = isBitSet(nonDefaultFields, fieldIndex++) ? (parcel.readInt() == 1) : DEFAULT.mSealed; if (isBitSet(nonDefaultFields, fieldIndex++)) mSourceNodeId = parcel.readLong(); if (isBitSet(nonDefaultFields, fieldIndex++)) mWindowId = parcel.readInt(); if (isBitSet(nonDefaultFields, fieldIndex++)) mParentNodeId = parcel.readLong(); if (isBitSet(nonDefaultFields, fieldIndex++)) mLabelForId = parcel.readLong(); if (isBitSet(nonDefaultFields, fieldIndex++)) mLabeledById = parcel.readLong(); if (isBitSet(nonDefaultFields, fieldIndex++)) mTraversalBefore = parcel.readLong(); if (isBitSet(nonDefaultFields, fieldIndex++)) mTraversalAfter = parcel.readLong(); if (isBitSet(nonDefaultFields, fieldIndex++)) mConnectionId = parcel.readInt(); if (isBitSet(nonDefaultFields, fieldIndex++)) { final int childrenSize = parcel.readInt(); if (childrenSize <= 0) { mChildNodeIds = null; Loading @@ -3274,17 +3384,23 @@ public class AccessibilityNodeInfo implements Parcelable { mChildNodeIds.add(childId); } } } if (isBitSet(nonDefaultFields, fieldIndex++)) { mBoundsInParent.top = parcel.readInt(); mBoundsInParent.bottom = parcel.readInt(); mBoundsInParent.left = parcel.readInt(); mBoundsInParent.right = parcel.readInt(); } if (isBitSet(nonDefaultFields, fieldIndex++)) { mBoundsInScreen.top = parcel.readInt(); mBoundsInScreen.bottom = parcel.readInt(); mBoundsInScreen.left = parcel.readInt(); mBoundsInScreen.right = parcel.readInt(); } if (isBitSet(nonDefaultFields, fieldIndex++)) { final int legacyStandardActions = parcel.readInt(); addLegacyStandardActions(legacyStandardActions); final int nonLegacyActionCount = parcel.readInt(); Loading @@ -3293,63 +3409,65 @@ public class AccessibilityNodeInfo implements Parcelable { parcel.readInt(), parcel.readCharSequence()); addActionUnchecked(action); } } mMaxTextLength = parcel.readInt(); mMovementGranularities = parcel.readInt(); mBooleanProperties = parcel.readInt(); if (isBitSet(nonDefaultFields, fieldIndex++)) mMaxTextLength = parcel.readInt(); if (isBitSet(nonDefaultFields, fieldIndex++)) mMovementGranularities = parcel.readInt(); if (isBitSet(nonDefaultFields, fieldIndex++)) mBooleanProperties = parcel.readInt(); mPackageName = parcel.readCharSequence(); mClassName = parcel.readCharSequence(); mText = parcel.readCharSequence(); mHintText = parcel.readCharSequence(); mError = parcel.readCharSequence(); if (isBitSet(nonDefaultFields, fieldIndex++)) mPackageName = parcel.readCharSequence(); if (isBitSet(nonDefaultFields, fieldIndex++)) mClassName = parcel.readCharSequence(); if (isBitSet(nonDefaultFields, fieldIndex++)) mText = parcel.readCharSequence(); if (isBitSet(nonDefaultFields, fieldIndex++)) mHintText = parcel.readCharSequence(); if (isBitSet(nonDefaultFields, fieldIndex++)) mError = parcel.readCharSequence(); if (isBitSet(nonDefaultFields, fieldIndex++)) { mContentDescription = parcel.readCharSequence(); mViewIdResourceName = parcel.readString(); } if (isBitSet(nonDefaultFields, fieldIndex++)) mViewIdResourceName = parcel.readString(); mTextSelectionStart = parcel.readInt(); mTextSelectionEnd = parcel.readInt(); if (isBitSet(nonDefaultFields, fieldIndex++)) mTextSelectionStart = parcel.readInt(); if (isBitSet(nonDefaultFields, fieldIndex++)) mTextSelectionEnd = parcel.readInt(); mInputType = parcel.readInt(); mLiveRegion = parcel.readInt(); mDrawingOrderInParent = parcel.readInt(); if (isBitSet(nonDefaultFields, fieldIndex++)) mInputType = parcel.readInt(); if (isBitSet(nonDefaultFields, fieldIndex++)) mLiveRegion = parcel.readInt(); if (isBitSet(nonDefaultFields, fieldIndex++)) mDrawingOrderInParent = parcel.readInt(); if (parcel.readInt() == 1) { mExtraDataKeys = parcel.createStringArrayList(); } else { mExtraDataKeys = null; } mExtraDataKeys = isBitSet(nonDefaultFields, fieldIndex++) ? parcel.createStringArrayList() : null; if (parcel.readInt() == 1) { mExtras = parcel.readBundle(); } else { mExtras = null; } mExtras = isBitSet(nonDefaultFields, fieldIndex++) ? parcel.readBundle() : null; if (parcel.readInt() == 1) { mRangeInfo = RangeInfo.obtain( if (mRangeInfo != null) mRangeInfo.recycle(); mRangeInfo = isBitSet(nonDefaultFields, fieldIndex++) ? RangeInfo.obtain( parcel.readInt(), parcel.readFloat(), parcel.readFloat(), parcel.readFloat()); } parcel.readFloat()) : null; if (parcel.readInt() == 1) { mCollectionInfo = CollectionInfo.obtain( if (mCollectionInfo != null) mCollectionInfo.recycle(); mCollectionInfo = isBitSet(nonDefaultFields, fieldIndex++) ? CollectionInfo.obtain( parcel.readInt(), parcel.readInt(), parcel.readInt() == 1, parcel.readInt()); } parcel.readInt()) : null; if (parcel.readInt() == 1) { mCollectionItemInfo = CollectionItemInfo.obtain( if (mCollectionItemInfo != null) mCollectionItemInfo.recycle(); mCollectionItemInfo = isBitSet(nonDefaultFields, fieldIndex++) ? CollectionItemInfo.obtain( parcel.readInt(), parcel.readInt(), parcel.readInt(), parcel.readInt(), parcel.readInt() == 1, parcel.readInt() == 1); } parcel.readInt() == 1) : null; mSealed = sealed; } Loading @@ -3358,50 +3476,7 @@ public class AccessibilityNodeInfo implements Parcelable { * Clears the state of this instance. */ private void clear() { mSealed = false; mSourceNodeId = UNDEFINED_NODE_ID; mParentNodeId = UNDEFINED_NODE_ID; mLabelForId = UNDEFINED_NODE_ID; mLabeledById = UNDEFINED_NODE_ID; mTraversalBefore = UNDEFINED_NODE_ID; mTraversalAfter = UNDEFINED_NODE_ID; mWindowId = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; mConnectionId = UNDEFINED_CONNECTION_ID; mMaxTextLength = -1; mMovementGranularities = 0; if (mChildNodeIds != null) { mChildNodeIds.clear(); } mBoundsInParent.set(0, 0, 0, 0); mBoundsInScreen.set(0, 0, 0, 0); mBooleanProperties = 0; mDrawingOrderInParent = 0; mExtraDataKeys = null; mPackageName = null; mClassName = null; mText = null; mHintText = null; mError = null; mContentDescription = null; mViewIdResourceName = null; removeAllActions(); mTextSelectionStart = UNDEFINED_SELECTION_INDEX; mTextSelectionEnd = UNDEFINED_SELECTION_INDEX; mInputType = InputType.TYPE_NULL; mLiveRegion = View.ACCESSIBILITY_LIVE_REGION_NONE; mExtras = null; if (mRangeInfo != null) { mRangeInfo.recycle(); mRangeInfo = null; } if (mCollectionInfo != null) { mCollectionInfo.recycle(); mCollectionInfo = null; } if (mCollectionItemInfo != null) { mCollectionItemInfo.recycle(); mCollectionItemInfo = null; } init(DEFAULT); } private static boolean isDefaultLegacyStandardAction(AccessibilityAction action) { Loading core/java/com/android/internal/util/BitUtils.java +8 −0 Original line number Diff line number Diff line Loading @@ -124,4 +124,12 @@ public final class BitUtils { buffer.put(bytes); buffer.position(original); } public static boolean isBitSet(long flags, int bitIndex) { return (flags & bitAt(bitIndex)) != 0; } public static long bitAt(int bitIndex) { return 1L << bitIndex; } } Loading
core/java/android/view/accessibility/AccessibilityNodeInfo.java +310 −235 Original line number Diff line number Diff line Loading @@ -16,6 +16,9 @@ package android.view.accessibility; import static com.android.internal.util.BitUtils.bitAt; import static com.android.internal.util.BitUtils.isBitSet; import static java.util.Collections.EMPTY_LIST; import android.accessibilityservice.AccessibilityService; Loading @@ -41,10 +44,12 @@ import android.util.Pools.SynchronizedPool; import android.view.View; import com.android.internal.R; import com.android.internal.util.CollectionUtils; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Objects; import java.util.concurrent.atomic.AtomicInteger; /** Loading Loading @@ -636,7 +641,6 @@ public class AccessibilityNodeInfo implements Parcelable { * Bits that provide the id of a virtual descendant of a view. */ private static final long VIRTUAL_DESCENDANT_ID_MASK = 0xffffffff00000000L; /** * Bit shift of {@link #VIRTUAL_DESCENDANT_ID_MASK} to get to the id for a * virtual descendant of a view. Such a descendant does not exist in the view Loading Loading @@ -692,6 +696,8 @@ public class AccessibilityNodeInfo implements Parcelable { private static final SynchronizedPool<AccessibilityNodeInfo> sPool = new SynchronizedPool<>(MAX_POOL_SIZE); private static final AccessibilityNodeInfo DEFAULT = new AccessibilityNodeInfo(); private boolean mSealed; // Data. Loading Loading @@ -1068,11 +1074,7 @@ public class AccessibilityNodeInfo implements Parcelable { * Gets the actions that can be performed on the node. */ public List<AccessibilityAction> getActionList() { if (mActions == null) { return Collections.emptyList(); } return mActions; return CollectionUtils.emptyIfNull(mActions); } /** Loading Loading @@ -3050,17 +3052,118 @@ public class AccessibilityNodeInfo implements Parcelable { */ @Override public void writeToParcel(Parcel parcel, int flags) { parcel.writeInt(isSealed() ? 1 : 0); parcel.writeLong(mSourceNodeId); parcel.writeInt(mWindowId); parcel.writeLong(mParentNodeId); parcel.writeLong(mLabelForId); parcel.writeLong(mLabeledById); parcel.writeLong(mTraversalBefore); parcel.writeLong(mTraversalAfter); parcel.writeInt(mConnectionId); // Write bit set of indices of fields with values differing from default long nonDefaultFields = 0; int fieldIndex = 0; // index of the current field if (isSealed() != DEFAULT.isSealed()) nonDefaultFields |= bitAt(fieldIndex); fieldIndex++; if (mSourceNodeId != DEFAULT.mSourceNodeId) nonDefaultFields |= bitAt(fieldIndex); fieldIndex++; if (mWindowId != DEFAULT.mWindowId) nonDefaultFields |= bitAt(fieldIndex); fieldIndex++; if (mParentNodeId != DEFAULT.mParentNodeId) nonDefaultFields |= bitAt(fieldIndex); fieldIndex++; if (mLabelForId != DEFAULT.mLabelForId) nonDefaultFields |= bitAt(fieldIndex); fieldIndex++; if (mLabeledById != DEFAULT.mLabeledById) nonDefaultFields |= bitAt(fieldIndex); fieldIndex++; if (mTraversalBefore != DEFAULT.mTraversalBefore) nonDefaultFields |= bitAt(fieldIndex); fieldIndex++; if (mTraversalAfter != DEFAULT.mTraversalAfter) nonDefaultFields |= bitAt(fieldIndex); fieldIndex++; if (mConnectionId != DEFAULT.mConnectionId) nonDefaultFields |= bitAt(fieldIndex); fieldIndex++; if (!Objects.equals(mChildNodeIds, DEFAULT.mChildNodeIds)) { nonDefaultFields |= bitAt(fieldIndex); } fieldIndex++; if (!Objects.equals(mBoundsInParent, DEFAULT.mBoundsInParent)) { nonDefaultFields |= bitAt(fieldIndex); } fieldIndex++; if (!Objects.equals(mBoundsInScreen, DEFAULT.mBoundsInScreen)) { nonDefaultFields |= bitAt(fieldIndex); } fieldIndex++; if (!Objects.equals(mActions, DEFAULT.mActions)) nonDefaultFields |= bitAt(fieldIndex); fieldIndex++; if (mMaxTextLength != DEFAULT.mMaxTextLength) nonDefaultFields |= bitAt(fieldIndex); fieldIndex++; if (mMovementGranularities != DEFAULT.mMovementGranularities) { nonDefaultFields |= bitAt(fieldIndex); } fieldIndex++; if (mBooleanProperties != DEFAULT.mBooleanProperties) nonDefaultFields |= bitAt(fieldIndex); fieldIndex++; if (!Objects.equals(mPackageName, DEFAULT.mPackageName)) { nonDefaultFields |= bitAt(fieldIndex); } fieldIndex++; if (!Objects.equals(mClassName, DEFAULT.mClassName)) nonDefaultFields |= bitAt(fieldIndex); fieldIndex++; if (!Objects.equals(mText, DEFAULT.mText)) nonDefaultFields |= bitAt(fieldIndex); fieldIndex++; if (!Objects.equals(mHintText, DEFAULT.mHintText)) { nonDefaultFields |= bitAt(fieldIndex); } fieldIndex++; if (!Objects.equals(mError, DEFAULT.mError)) nonDefaultFields |= bitAt(fieldIndex); fieldIndex++; if (!Objects.equals(mContentDescription, DEFAULT.mContentDescription)) { nonDefaultFields |= bitAt(fieldIndex); } fieldIndex++; if (!Objects.equals(mViewIdResourceName, DEFAULT.mViewIdResourceName)) { nonDefaultFields |= bitAt(fieldIndex); } fieldIndex++; if (mTextSelectionStart != DEFAULT.mTextSelectionStart) { nonDefaultFields |= bitAt(fieldIndex); } fieldIndex++; if (mTextSelectionEnd != DEFAULT.mTextSelectionEnd) { nonDefaultFields |= bitAt(fieldIndex); } fieldIndex++; if (mInputType != DEFAULT.mInputType) nonDefaultFields |= bitAt(fieldIndex); fieldIndex++; if (mLiveRegion != DEFAULT.mLiveRegion) nonDefaultFields |= bitAt(fieldIndex); fieldIndex++; if (mDrawingOrderInParent != DEFAULT.mDrawingOrderInParent) { nonDefaultFields |= bitAt(fieldIndex); } fieldIndex++; if (!Objects.equals(mExtraDataKeys, DEFAULT.mExtraDataKeys)) { nonDefaultFields |= bitAt(fieldIndex); } fieldIndex++; if (!Objects.equals(mExtras, DEFAULT.mExtras)) nonDefaultFields |= bitAt(fieldIndex); fieldIndex++; if (!Objects.equals(mRangeInfo, DEFAULT.mRangeInfo)) nonDefaultFields |= bitAt(fieldIndex); fieldIndex++; if (!Objects.equals(mCollectionInfo, DEFAULT.mCollectionInfo)) { nonDefaultFields |= bitAt(fieldIndex); } fieldIndex++; if (!Objects.equals(mCollectionItemInfo, DEFAULT.mCollectionItemInfo)) { nonDefaultFields |= bitAt(fieldIndex); } int totalFields = fieldIndex; parcel.writeLong(nonDefaultFields); fieldIndex = 0; if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeInt(isSealed() ? 1 : 0); if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeLong(mSourceNodeId); if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeInt(mWindowId); if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeLong(mParentNodeId); if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeLong(mLabelForId); if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeLong(mLabeledById); if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeLong(mTraversalBefore); if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeLong(mTraversalAfter); if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeInt(mConnectionId); if (isBitSet(nonDefaultFields, fieldIndex++)) { final LongArray childIds = mChildNodeIds; if (childIds == null) { parcel.writeInt(0); Loading @@ -3071,17 +3174,23 @@ public class AccessibilityNodeInfo implements Parcelable { parcel.writeLong(childIds.get(i)); } } } if (isBitSet(nonDefaultFields, fieldIndex++)) { parcel.writeInt(mBoundsInParent.top); parcel.writeInt(mBoundsInParent.bottom); parcel.writeInt(mBoundsInParent.left); parcel.writeInt(mBoundsInParent.right); } if (isBitSet(nonDefaultFields, fieldIndex++)) { parcel.writeInt(mBoundsInScreen.top); parcel.writeInt(mBoundsInScreen.bottom); parcel.writeInt(mBoundsInScreen.left); parcel.writeInt(mBoundsInScreen.right); } if (isBitSet(nonDefaultFields, fieldIndex++)) { if (mActions != null && !mActions.isEmpty()) { final int actionCount = mActions.size(); Loading Loading @@ -3109,68 +3218,61 @@ public class AccessibilityNodeInfo implements Parcelable { parcel.writeInt(0); parcel.writeInt(0); } } parcel.writeInt(mMaxTextLength); parcel.writeInt(mMovementGranularities); parcel.writeInt(mBooleanProperties); if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeInt(mMaxTextLength); if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeInt(mMovementGranularities); if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeInt(mBooleanProperties); parcel.writeCharSequence(mPackageName); parcel.writeCharSequence(mClassName); parcel.writeCharSequence(mText); parcel.writeCharSequence(mHintText); parcel.writeCharSequence(mError); if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeCharSequence(mPackageName); if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeCharSequence(mClassName); if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeCharSequence(mText); if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeCharSequence(mHintText); if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeCharSequence(mError); if (isBitSet(nonDefaultFields, fieldIndex++)) { parcel.writeCharSequence(mContentDescription); parcel.writeString(mViewIdResourceName); parcel.writeInt(mTextSelectionStart); parcel.writeInt(mTextSelectionEnd); parcel.writeInt(mInputType); parcel.writeInt(mLiveRegion); parcel.writeInt(mDrawingOrderInParent); if (mExtraDataKeys != null) { parcel.writeInt(1); parcel.writeStringList(mExtraDataKeys); } else { parcel.writeInt(0); } if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeString(mViewIdResourceName); if (mExtras != null) { parcel.writeInt(1); parcel.writeBundle(mExtras); } else { parcel.writeInt(0); } if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeInt(mTextSelectionStart); if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeInt(mTextSelectionEnd); if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeInt(mInputType); if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeInt(mLiveRegion); if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeInt(mDrawingOrderInParent); if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeStringList(mExtraDataKeys); if (mRangeInfo != null) { parcel.writeInt(1); if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeBundle(mExtras); if (isBitSet(nonDefaultFields, fieldIndex++)) { parcel.writeInt(mRangeInfo.getType()); parcel.writeFloat(mRangeInfo.getMin()); parcel.writeFloat(mRangeInfo.getMax()); parcel.writeFloat(mRangeInfo.getCurrent()); } else { parcel.writeInt(0); } if (mCollectionInfo != null) { parcel.writeInt(1); if (isBitSet(nonDefaultFields, fieldIndex++)) { parcel.writeInt(mCollectionInfo.getRowCount()); parcel.writeInt(mCollectionInfo.getColumnCount()); parcel.writeInt(mCollectionInfo.isHierarchical() ? 1 : 0); parcel.writeInt(mCollectionInfo.getSelectionMode()); } else { parcel.writeInt(0); } if (mCollectionItemInfo != null) { parcel.writeInt(1); if (isBitSet(nonDefaultFields, fieldIndex++)) { parcel.writeInt(mCollectionItemInfo.getRowIndex()); parcel.writeInt(mCollectionItemInfo.getRowSpan()); parcel.writeInt(mCollectionItemInfo.getColumnIndex()); parcel.writeInt(mCollectionItemInfo.getColumnSpan()); parcel.writeInt(mCollectionItemInfo.isHeading() ? 1 : 0); parcel.writeInt(mCollectionItemInfo.isSelected() ? 1 : 0); } else { parcel.writeInt(0); } if (DEBUG) { fieldIndex--; if (totalFields != fieldIndex) { throw new IllegalStateException("Number of fields mismatch: " + totalFields + " vs " + fieldIndex); } } // Since instances of this class are fetched via synchronous i.e. blocking Loading Loading @@ -3203,12 +3305,12 @@ public class AccessibilityNodeInfo implements Parcelable { mContentDescription = other.mContentDescription; mViewIdResourceName = other.mViewIdResourceName; if (mActions != null) mActions.clear(); final ArrayList<AccessibilityAction> otherActions = other.mActions; if (otherActions != null && otherActions.size() > 0) { if (mActions == null) { mActions = new ArrayList(otherActions); } else { mActions.clear(); mActions.addAll(other.mActions); } } Loading @@ -3217,12 +3319,13 @@ public class AccessibilityNodeInfo implements Parcelable { mMaxTextLength = other.mMaxTextLength; mMovementGranularities = other.mMovementGranularities; if (mChildNodeIds != null) mChildNodeIds.clear(); final LongArray otherChildNodeIds = other.mChildNodeIds; if (otherChildNodeIds != null && otherChildNodeIds.size() > 0) { if (mChildNodeIds == null) { mChildNodeIds = otherChildNodeIds.clone(); } else { mChildNodeIds.clear(); mChildNodeIds.addAll(otherChildNodeIds); } } Loading @@ -3232,17 +3335,18 @@ public class AccessibilityNodeInfo implements Parcelable { mInputType = other.mInputType; mLiveRegion = other.mLiveRegion; mDrawingOrderInParent = other.mDrawingOrderInParent; mExtraDataKeys = other.mExtraDataKeys; if (other.mExtras != null) { mExtras = new Bundle(other.mExtras); } else { mExtras = null; } mExtras = other.mExtras != null ? new Bundle(other.mExtras) : null; if (mRangeInfo != null) mRangeInfo.recycle(); mRangeInfo = (other.mRangeInfo != null) ? RangeInfo.obtain(other.mRangeInfo) : null; if (mCollectionInfo != null) mCollectionInfo.recycle(); mCollectionInfo = (other.mCollectionInfo != null) ? CollectionInfo.obtain(other.mCollectionInfo) : null; if (mCollectionItemInfo != null) mCollectionItemInfo.recycle(); mCollectionItemInfo = (other.mCollectionItemInfo != null) ? CollectionItemInfo.obtain(other.mCollectionItemInfo) : null; } Loading @@ -3253,17 +3357,23 @@ public class AccessibilityNodeInfo implements Parcelable { * @param parcel A parcel containing the state of a {@link AccessibilityNodeInfo}. */ private void initFromParcel(Parcel parcel) { final boolean sealed = (parcel.readInt() == 1); mSourceNodeId = parcel.readLong(); mWindowId = parcel.readInt(); mParentNodeId = parcel.readLong(); mLabelForId = parcel.readLong(); mLabeledById = parcel.readLong(); mTraversalBefore = parcel.readLong(); mTraversalAfter = parcel.readLong(); mConnectionId = parcel.readInt(); // Bit mask of non-default-valued field indices long nonDefaultFields = parcel.readLong(); int fieldIndex = 0; final boolean sealed = isBitSet(nonDefaultFields, fieldIndex++) ? (parcel.readInt() == 1) : DEFAULT.mSealed; if (isBitSet(nonDefaultFields, fieldIndex++)) mSourceNodeId = parcel.readLong(); if (isBitSet(nonDefaultFields, fieldIndex++)) mWindowId = parcel.readInt(); if (isBitSet(nonDefaultFields, fieldIndex++)) mParentNodeId = parcel.readLong(); if (isBitSet(nonDefaultFields, fieldIndex++)) mLabelForId = parcel.readLong(); if (isBitSet(nonDefaultFields, fieldIndex++)) mLabeledById = parcel.readLong(); if (isBitSet(nonDefaultFields, fieldIndex++)) mTraversalBefore = parcel.readLong(); if (isBitSet(nonDefaultFields, fieldIndex++)) mTraversalAfter = parcel.readLong(); if (isBitSet(nonDefaultFields, fieldIndex++)) mConnectionId = parcel.readInt(); if (isBitSet(nonDefaultFields, fieldIndex++)) { final int childrenSize = parcel.readInt(); if (childrenSize <= 0) { mChildNodeIds = null; Loading @@ -3274,17 +3384,23 @@ public class AccessibilityNodeInfo implements Parcelable { mChildNodeIds.add(childId); } } } if (isBitSet(nonDefaultFields, fieldIndex++)) { mBoundsInParent.top = parcel.readInt(); mBoundsInParent.bottom = parcel.readInt(); mBoundsInParent.left = parcel.readInt(); mBoundsInParent.right = parcel.readInt(); } if (isBitSet(nonDefaultFields, fieldIndex++)) { mBoundsInScreen.top = parcel.readInt(); mBoundsInScreen.bottom = parcel.readInt(); mBoundsInScreen.left = parcel.readInt(); mBoundsInScreen.right = parcel.readInt(); } if (isBitSet(nonDefaultFields, fieldIndex++)) { final int legacyStandardActions = parcel.readInt(); addLegacyStandardActions(legacyStandardActions); final int nonLegacyActionCount = parcel.readInt(); Loading @@ -3293,63 +3409,65 @@ public class AccessibilityNodeInfo implements Parcelable { parcel.readInt(), parcel.readCharSequence()); addActionUnchecked(action); } } mMaxTextLength = parcel.readInt(); mMovementGranularities = parcel.readInt(); mBooleanProperties = parcel.readInt(); if (isBitSet(nonDefaultFields, fieldIndex++)) mMaxTextLength = parcel.readInt(); if (isBitSet(nonDefaultFields, fieldIndex++)) mMovementGranularities = parcel.readInt(); if (isBitSet(nonDefaultFields, fieldIndex++)) mBooleanProperties = parcel.readInt(); mPackageName = parcel.readCharSequence(); mClassName = parcel.readCharSequence(); mText = parcel.readCharSequence(); mHintText = parcel.readCharSequence(); mError = parcel.readCharSequence(); if (isBitSet(nonDefaultFields, fieldIndex++)) mPackageName = parcel.readCharSequence(); if (isBitSet(nonDefaultFields, fieldIndex++)) mClassName = parcel.readCharSequence(); if (isBitSet(nonDefaultFields, fieldIndex++)) mText = parcel.readCharSequence(); if (isBitSet(nonDefaultFields, fieldIndex++)) mHintText = parcel.readCharSequence(); if (isBitSet(nonDefaultFields, fieldIndex++)) mError = parcel.readCharSequence(); if (isBitSet(nonDefaultFields, fieldIndex++)) { mContentDescription = parcel.readCharSequence(); mViewIdResourceName = parcel.readString(); } if (isBitSet(nonDefaultFields, fieldIndex++)) mViewIdResourceName = parcel.readString(); mTextSelectionStart = parcel.readInt(); mTextSelectionEnd = parcel.readInt(); if (isBitSet(nonDefaultFields, fieldIndex++)) mTextSelectionStart = parcel.readInt(); if (isBitSet(nonDefaultFields, fieldIndex++)) mTextSelectionEnd = parcel.readInt(); mInputType = parcel.readInt(); mLiveRegion = parcel.readInt(); mDrawingOrderInParent = parcel.readInt(); if (isBitSet(nonDefaultFields, fieldIndex++)) mInputType = parcel.readInt(); if (isBitSet(nonDefaultFields, fieldIndex++)) mLiveRegion = parcel.readInt(); if (isBitSet(nonDefaultFields, fieldIndex++)) mDrawingOrderInParent = parcel.readInt(); if (parcel.readInt() == 1) { mExtraDataKeys = parcel.createStringArrayList(); } else { mExtraDataKeys = null; } mExtraDataKeys = isBitSet(nonDefaultFields, fieldIndex++) ? parcel.createStringArrayList() : null; if (parcel.readInt() == 1) { mExtras = parcel.readBundle(); } else { mExtras = null; } mExtras = isBitSet(nonDefaultFields, fieldIndex++) ? parcel.readBundle() : null; if (parcel.readInt() == 1) { mRangeInfo = RangeInfo.obtain( if (mRangeInfo != null) mRangeInfo.recycle(); mRangeInfo = isBitSet(nonDefaultFields, fieldIndex++) ? RangeInfo.obtain( parcel.readInt(), parcel.readFloat(), parcel.readFloat(), parcel.readFloat()); } parcel.readFloat()) : null; if (parcel.readInt() == 1) { mCollectionInfo = CollectionInfo.obtain( if (mCollectionInfo != null) mCollectionInfo.recycle(); mCollectionInfo = isBitSet(nonDefaultFields, fieldIndex++) ? CollectionInfo.obtain( parcel.readInt(), parcel.readInt(), parcel.readInt() == 1, parcel.readInt()); } parcel.readInt()) : null; if (parcel.readInt() == 1) { mCollectionItemInfo = CollectionItemInfo.obtain( if (mCollectionItemInfo != null) mCollectionItemInfo.recycle(); mCollectionItemInfo = isBitSet(nonDefaultFields, fieldIndex++) ? CollectionItemInfo.obtain( parcel.readInt(), parcel.readInt(), parcel.readInt(), parcel.readInt(), parcel.readInt() == 1, parcel.readInt() == 1); } parcel.readInt() == 1) : null; mSealed = sealed; } Loading @@ -3358,50 +3476,7 @@ public class AccessibilityNodeInfo implements Parcelable { * Clears the state of this instance. */ private void clear() { mSealed = false; mSourceNodeId = UNDEFINED_NODE_ID; mParentNodeId = UNDEFINED_NODE_ID; mLabelForId = UNDEFINED_NODE_ID; mLabeledById = UNDEFINED_NODE_ID; mTraversalBefore = UNDEFINED_NODE_ID; mTraversalAfter = UNDEFINED_NODE_ID; mWindowId = AccessibilityWindowInfo.UNDEFINED_WINDOW_ID; mConnectionId = UNDEFINED_CONNECTION_ID; mMaxTextLength = -1; mMovementGranularities = 0; if (mChildNodeIds != null) { mChildNodeIds.clear(); } mBoundsInParent.set(0, 0, 0, 0); mBoundsInScreen.set(0, 0, 0, 0); mBooleanProperties = 0; mDrawingOrderInParent = 0; mExtraDataKeys = null; mPackageName = null; mClassName = null; mText = null; mHintText = null; mError = null; mContentDescription = null; mViewIdResourceName = null; removeAllActions(); mTextSelectionStart = UNDEFINED_SELECTION_INDEX; mTextSelectionEnd = UNDEFINED_SELECTION_INDEX; mInputType = InputType.TYPE_NULL; mLiveRegion = View.ACCESSIBILITY_LIVE_REGION_NONE; mExtras = null; if (mRangeInfo != null) { mRangeInfo.recycle(); mRangeInfo = null; } if (mCollectionInfo != null) { mCollectionInfo.recycle(); mCollectionInfo = null; } if (mCollectionItemInfo != null) { mCollectionItemInfo.recycle(); mCollectionItemInfo = null; } init(DEFAULT); } private static boolean isDefaultLegacyStandardAction(AccessibilityAction action) { Loading
core/java/com/android/internal/util/BitUtils.java +8 −0 Original line number Diff line number Diff line Loading @@ -124,4 +124,12 @@ public final class BitUtils { buffer.put(bytes); buffer.position(original); } public static boolean isBitSet(long flags, int bitIndex) { return (flags & bitAt(bitIndex)) != 0; } public static long bitAt(int bitIndex) { return 1L << bitIndex; } }