/** * <p>Gets combined ID for child item.</p> * <p>bit 0-27: Lower 28 bits of the childId * bit 28-55: Lower 28 bits of the groupId * bit 56-61: reserved</p> * * @param groupId The ID of the group that contains the child. * @param childId The ID of the child. * @return The unique ID of the child across all groups and children in the list */ public static long getCombinedChildId(long groupId, long childId) { return ItemIdComposer.composeExpandableChildId(groupId, childId); }
/** * <p>Gets combined ID for child item.</p> * <p>bit 0-27: all bits are set to 1 * bit 28-55: Lower 28 bits of the groupId * bit 56-61: reserved</p> * * @param groupId The ID of the group that contains the child. * @return The unique ID of the child across all groups and children in the list */ public static long getCombinedGroupId(long groupId) { return ItemIdComposer.composeExpandableGroupId(groupId); }
/** * Gets child item ID from a raw ID. * * @param rawId raw item ID value (return value of {@link androidx.recyclerview.widget.RecyclerView.ViewHolder#getItemId()}) * @return Child item ID for the given raw item ID. */ public static long getChildItemId(long rawId) { return ItemIdComposer.extractExpandableChildIdPart(rawId); }
@Test public void extractExpandableChildIdPart() throws Exception { // invalid - 1 assertThat(ItemIdComposer.extractExpandableChildIdPart(ItemIdComposer.composeExpandableGroupId(0L)), is(RecyclerView.NO_ID)); // invalid - 2 assertThat(ItemIdComposer.extractExpandableChildIdPart(RecyclerView.NO_ID), is(RecyclerView.NO_ID)); // zero assertThat(ItemIdComposer.extractExpandableChildIdPart(ItemIdComposer.composeExpandableChildId(0L, 0L)), is(0L)); // one assertThat(ItemIdComposer.extractExpandableChildIdPart(ItemIdComposer.composeExpandableChildId(0L, 1L)), is(1L)); // minus one assertThat(ItemIdComposer.extractExpandableChildIdPart(ItemIdComposer.composeExpandableChildId(0L, -1L)), is(-1L)); // min assertThat(ItemIdComposer.extractExpandableChildIdPart(ItemIdComposer.composeExpandableChildId(0L, ItemIdComposer.MIN_CHILD_ID)), is(ItemIdComposer.MIN_CHILD_ID)); // max assertThat(ItemIdComposer.extractExpandableChildIdPart(ItemIdComposer.composeExpandableChildId(0L, ItemIdComposer.MAX_CHILD_ID)), is(ItemIdComposer.MAX_CHILD_ID)); // etc - 1 assertThat(ItemIdComposer.extractExpandableChildIdPart(ItemIdComposer.BIT_MASK_RESERVED_SIGN_FLAG), is(0L)); // etc - 2 assertThat(ItemIdComposer.extractExpandableChildIdPart(ItemIdComposer.BIT_MASK_SEGMENT), is(0L)); }
@Test public void extractExpandableGroupIdPart() throws Exception { // invalid - 1 assertThat(ItemIdComposer.extractExpandableGroupIdPart(0L), is(RecyclerView.NO_ID)); // invalid - 2 assertThat(ItemIdComposer.extractExpandableGroupIdPart(1), is(RecyclerView.NO_ID)); // invalid - 3 assertThat(ItemIdComposer.extractExpandableGroupIdPart(RecyclerView.NO_ID), is(RecyclerView.NO_ID)); // zero assertThat(ItemIdComposer.extractExpandableGroupIdPart(ItemIdComposer.composeExpandableGroupId(0L)), is(0L)); // one assertThat(ItemIdComposer.extractExpandableGroupIdPart(ItemIdComposer.composeExpandableGroupId(1L)), is(1L)); // minus one assertThat(ItemIdComposer.extractExpandableGroupIdPart(ItemIdComposer.composeExpandableGroupId(-1L)), is(-1L)); // min assertThat(ItemIdComposer.extractExpandableGroupIdPart(ItemIdComposer.composeExpandableGroupId(ItemIdComposer.MIN_GROUP_ID)), is(ItemIdComposer.MIN_GROUP_ID)); // max assertThat(ItemIdComposer.extractExpandableGroupIdPart(ItemIdComposer.composeExpandableGroupId(ItemIdComposer.MAX_GROUP_ID)), is(ItemIdComposer.MAX_GROUP_ID)); // etc - 1 assertThat(ItemIdComposer.extractExpandableGroupIdPart(ItemIdComposer.BIT_MASK_RESERVED_SIGN_FLAG | ItemIdComposer.BIT_MASK_CHILD_ID), is(0L)); // etc - 2 assertThat(ItemIdComposer.extractExpandableGroupIdPart(ItemIdComposer.BIT_MASK_SEGMENT | ItemIdComposer.BIT_MASK_CHILD_ID), is(0L)); }
@Override public long getItemId(int position) { if (mExpandableItemAdapter == null) { return RecyclerView.NO_ID; } final long expandablePosition = mPositionTranslator.getExpandablePosition(position); final int groupPosition = ExpandableAdapterHelper.getPackedPositionGroup(expandablePosition); final int childPosition = ExpandableAdapterHelper.getPackedPositionChild(expandablePosition); if (childPosition == RecyclerView.NO_POSITION) { final long groupId = mExpandableItemAdapter.getGroupId(groupPosition); return ItemIdComposer.composeExpandableGroupId(groupId); } else { final long groupId = mExpandableItemAdapter.getGroupId(groupPosition); final long childId = mExpandableItemAdapter.getChildId(groupPosition, childPosition); return ItemIdComposer.composeExpandableChildId(groupId, childId); } }
@Test public void composeSegment() throws Exception { // zero assertThat(ItemIdComposer.composeSegment(0, 0L), is(0L)); // one assertThat(ItemIdComposer.composeSegment(1, 0L), is(1L << ItemIdComposer.BIT_OFFSET_SEGMENT)); // min assertThat(ItemIdComposer.composeSegment(ItemIdComposer.MIN_SEGMENT, 0L), is(((long) ItemIdComposer.MIN_SEGMENT) << ItemIdComposer.BIT_OFFSET_SEGMENT)); // max assertThat(ItemIdComposer.composeSegment(ItemIdComposer.MAX_SEGMENT, 0L), is(((long) ItemIdComposer.MAX_SEGMENT) << ItemIdComposer.BIT_OFFSET_SEGMENT)); }
/** * Checks whether the passed item ID is a group's one. * * @param rawId raw item ID value (return value of {@link androidx.recyclerview.widget.RecyclerView.ViewHolder#getItemId()}) * @return True for the a group view type, otherwise false */ public static boolean isGroupItemId(long rawId) { return ItemIdComposer.isExpandableGroup(rawId); }
@Test public void extractWrappedIdPart() throws Exception { // invalid - 1 assertThat(ItemIdComposer.extractWrappedIdPart(RecyclerView.NO_ID), is(RecyclerView.NO_ID)); // zero assertThat(ItemIdComposer.extractWrappedIdPart(0L), is(0L)); // full bits assertThat(ItemIdComposer.extractWrappedIdPart(ItemIdComposer.BIT_MASK_GROUP_ID | ItemIdComposer.BIT_MASK_CHILD_ID), is(-1L)); // etc - 1 assertThat(ItemIdComposer.extractWrappedIdPart(ItemIdComposer.BIT_MASK_RESERVED_SIGN_FLAG), is(0L)); // etc - 2 assertThat(ItemIdComposer.extractWrappedIdPart(ItemIdComposer.BIT_MASK_SEGMENT), is(0L)); }
/** * Gets group item ID from a raw ID. * * @param rawId raw item ID value (return value of {@link androidx.recyclerview.widget.RecyclerView.ViewHolder#getItemId()}) * @return Group item ID for the given raw item ID. */ public static long getGroupItemId(long rawId) { return ItemIdComposer.extractExpandableGroupIdPart(rawId); }
@Test public void extractSegmentPart() throws Exception { // zero assertThat(ItemIdComposer.extractSegmentPart(0L), is(0)); // one assertThat(ItemIdComposer.extractSegmentPart(1L << ItemIdComposer.BIT_OFFSET_SEGMENT), is(1)); // min assertThat(ItemIdComposer.extractSegmentPart(((long) ItemIdComposer.MIN_SEGMENT) << ItemIdComposer.BIT_OFFSET_SEGMENT), is(ItemIdComposer.MIN_SEGMENT)); // max assertThat(ItemIdComposer.extractSegmentPart(((long) ItemIdComposer.MAX_SEGMENT) << ItemIdComposer.BIT_OFFSET_SEGMENT), is(ItemIdComposer.MAX_SEGMENT)); // etc - 1 assertThat(ItemIdComposer.extractSegmentPart(ItemIdComposer.BIT_MASK_RESERVED_SIGN_FLAG | ItemIdComposer.BIT_MASK_GROUP_ID | ItemIdComposer.BIT_MASK_CHILD_ID), is(0)); // etc - 2 assertThat(ItemIdComposer.extractSegmentPart(ItemIdComposer.BIT_MASK_SEGMENT), is(ItemIdComposer.MAX_SEGMENT)); }
@Test public void composeSegment_MinOutOfRange() throws Exception { thrown.expect(IllegalArgumentException.class); //noinspection Range ItemIdComposer.composeSegment(ItemIdComposer.MIN_SEGMENT - 1, 0L); }
/** * Extracts "Group ID" part from composed ID. * * @param composedId Composed ID * @return Group ID part. If the specified composed ID is not an expandable group, returns {@link RecyclerView#NO_ID}. */ @IntRange(from = MIN_GROUP_ID, to = MAX_GROUP_ID) public static long extractExpandableGroupIdPart(long composedId) { if ((composedId == RecyclerView.NO_ID) || !isExpandableGroup(composedId)) { return RecyclerView.NO_ID; } return (composedId << (64 - BIT_WIDTH_GROUP_ID - BIT_OFFSET_GROUP_ID)) >> (64 - BIT_WIDTH_GROUP_ID); }
final long wrappedAdapterItemId = ItemIdComposer.extractWrappedIdPart(mWrapperAdapter.getItemId(fromPosition)); final long wrappedItemId = ItemIdComposer.extractWrappedIdPart(mDraggingItemInfo.id); if (wrappedAdapterItemId != wrappedItemId) { if (LOCAL_LOGV) {
@Test public void composeExpandableChildId() throws Exception { // zero assertThat(ItemIdComposer.composeExpandableChildId(0L, 0L), is(0L)); // one assertThat(ItemIdComposer.composeExpandableChildId(1L, 0L), is(1L << ItemIdComposer.BIT_OFFSET_GROUP_ID)); assertThat(ItemIdComposer.composeExpandableChildId(0L, 1L), is(1L << ItemIdComposer.BIT_OFFSET_CHILD_ID)); // minus one assertThat(ItemIdComposer.composeExpandableChildId(-1L, 0L), is(ItemIdComposer.BIT_MASK_GROUP_ID)); assertThat(ItemIdComposer.composeExpandableChildId(0L, -1L), is(ItemIdComposer.BIT_MASK_CHILD_ID)); // min assertThat(ItemIdComposer.composeExpandableChildId(ItemIdComposer.MIN_GROUP_ID, 0L), is(genBitMask(1, (ItemIdComposer.BIT_WIDTH_GROUP_ID - 1) + ItemIdComposer.BIT_OFFSET_GROUP_ID))); assertThat(ItemIdComposer.composeExpandableChildId(0L, ItemIdComposer.MIN_CHILD_ID), is(genBitMask(1, (ItemIdComposer.BIT_WIDTH_CHILD_ID - 1) + ItemIdComposer.BIT_OFFSET_CHILD_ID))); // max assertThat(ItemIdComposer.composeExpandableChildId(ItemIdComposer.MAX_GROUP_ID, 0L), is(genBitMask(ItemIdComposer.BIT_WIDTH_GROUP_ID - 1, ItemIdComposer.BIT_OFFSET_GROUP_ID))); assertThat(ItemIdComposer.composeExpandableChildId(0L, ItemIdComposer.MAX_CHILD_ID), is(genBitMask(ItemIdComposer.BIT_WIDTH_CHILD_ID - 1, ItemIdComposer.BIT_OFFSET_CHILD_ID))); }
@Test public void composeSegment_MaxOutOfRange() throws Exception { thrown.expect(IllegalArgumentException.class); //noinspection Range ItemIdComposer.composeSegment(ItemIdComposer.MAX_SEGMENT + 1, 0L); }
/** * Extracts "Child ID" part from composed ID. * * @param composedId Composed ID * @return Child ID part. If the specified composed ID is not a child of an expandable group, returns {@link RecyclerView#NO_ID}. */ @IntRange(from = MIN_CHILD_ID, to = MAX_CHILD_ID) public static long extractExpandableChildIdPart(long composedId) { if ((composedId == RecyclerView.NO_ID) || isExpandableGroup(composedId)) { return RecyclerView.NO_ID; } return (composedId << (64 - BIT_WIDTH_CHILD_ID - BIT_OFFSET_CHILD_ID)) >> (64 - BIT_WIDTH_CHILD_ID); }
final long wrappedAdapterItemId = ItemIdComposer.extractWrappedIdPart(mWrapperAdapter.getItemId(wrappedItemPosition)); final long wrappedItemId = ItemIdComposer.extractWrappedIdPart(holder.getItemId());
@Test public void composeExpandableGroupId() throws Exception { // zero //noinspection PointlessBitwiseExpression assertThat(ItemIdComposer.composeExpandableGroupId(0L), is((0L << ItemIdComposer.BIT_OFFSET_GROUP_ID) | ItemIdComposer.BIT_MASK_CHILD_ID)); // one assertThat(ItemIdComposer.composeExpandableGroupId(1L), is((1L << ItemIdComposer.BIT_OFFSET_GROUP_ID) | ItemIdComposer.BIT_MASK_CHILD_ID)); // minus one assertThat(ItemIdComposer.composeExpandableGroupId(-1L), is(ItemIdComposer.BIT_MASK_GROUP_ID | ItemIdComposer.BIT_MASK_CHILD_ID)); // min assertThat( ItemIdComposer.composeExpandableGroupId(ItemIdComposer.MIN_GROUP_ID), is(genBitMask(1, (ItemIdComposer.BIT_WIDTH_GROUP_ID - 1) + ItemIdComposer.BIT_OFFSET_GROUP_ID) | ItemIdComposer.BIT_MASK_CHILD_ID)); // max assertThat( ItemIdComposer.composeExpandableGroupId(ItemIdComposer.MAX_GROUP_ID), is(genBitMask(ItemIdComposer.BIT_WIDTH_GROUP_ID - 1, ItemIdComposer.BIT_OFFSET_GROUP_ID) | ItemIdComposer.BIT_MASK_CHILD_ID)); }
@Test public void composeExpandableChildId_ChildIdMinOutOfRange() throws Exception { thrown.expect(IllegalArgumentException.class); ItemIdComposer.composeExpandableChildId(0, ItemIdComposer.MIN_CHILD_ID - 1); }