More ExpandableListView fixes to take headers into account.
All direct calls to mConnector in ExpandableListView should convert group/child flat positions
to/from absolute flat positions (that take header count into account).
Two conversion methods were added to do that.
diff --git a/core/java/android/widget/ExpandableListConnector.java b/core/java/android/widget/ExpandableListConnector.java
index 9c43e9b..01d3a4a 100644
--- a/core/java/android/widget/ExpandableListConnector.java
+++ b/core/java/android/widget/ExpandableListConnector.java
@@ -67,7 +67,7 @@
private int mMaxExpGroupCount = Integer.MAX_VALUE;
/** Change observer used to have ExpandableListAdapter changes pushed to us */
- private DataSetObserver mDataSetObserver = new MyDataSetObserver();
+ private final DataSetObserver mDataSetObserver = new MyDataSetObserver();
/**
* Constructs the connector
@@ -849,7 +849,7 @@
* position to either a) group position for groups, or b) child position for
* children
*/
- static class GroupMetadata implements Parcelable, Comparable {
+ static class GroupMetadata implements Parcelable, Comparable<GroupMetadata> {
final static int REFRESH = -1;
/** This group's flat list position */
@@ -885,12 +885,12 @@
return gm;
}
- public int compareTo(Object another) {
- if (another == null || !(another instanceof GroupMetadata)) {
- throw new ClassCastException();
+ public int compareTo(GroupMetadata another) {
+ if (another == null) {
+ throw new IllegalArgumentException();
}
- return gPos - ((GroupMetadata) another).gPos;
+ return gPos - another.gPos;
}
public int describeContents() {
diff --git a/core/java/android/widget/ExpandableListView.java b/core/java/android/widget/ExpandableListView.java
index 9cc8bd5..8bd797b 100644
--- a/core/java/android/widget/ExpandableListView.java
+++ b/core/java/android/widget/ExpandableListView.java
@@ -389,7 +389,8 @@
// Only proceed as possible child if the divider isn't above all items (if it is above
// all items, then the item below it has to be a group)
if (flatListPosition >= 0) {
- PositionMetadata pos = mConnector.getUnflattenedPos(flatListPosition);
+ final int adjustedPosition = getFlatPositionForConnector(flatListPosition);
+ PositionMetadata pos = mConnector.getUnflattenedPos(adjustedPosition);
// If this item is a child, or it is a non-empty group that is expanded
if ((pos.position.type == ExpandableListPosition.CHILD) || (pos.isExpanded() &&
pos.groupMetadata.lastChildFlPos != pos.groupMetadata.flPos)) {
@@ -482,11 +483,37 @@
return mAdapter;
}
+ /**
+ * @param position An absolute (including header and footer) flat list position.
+ * @return true if the position corresponds to a header or a footer item.
+ */
private boolean isHeaderOrFooterPosition(int position) {
final int footerViewsStart = mItemCount - getFooterViewsCount();
return (position < getHeaderViewsCount() || position >= footerViewsStart);
}
+ /**
+ * Converts an absolute item flat position into a group/child flat position, shifting according
+ * to the number of header items.
+ *
+ * @param flatListPosition The absolute flat position
+ * @return A group/child flat position as expected by the connector.
+ */
+ private int getFlatPositionForConnector(int flatListPosition) {
+ return flatListPosition - getHeaderViewsCount();
+ }
+
+ /**
+ * Converts a group/child flat position into an absolute flat position, that takes into account
+ * the possible headers.
+ *
+ * @param flatListPosition The child/group flat position
+ * @return An absolute flat position.
+ */
+ private int getAbsoluteFlatPosition(int flatListPosition) {
+ return flatListPosition + getHeaderViewsCount();
+ }
+
@Override
public boolean performItemClick(View v, int position, long id) {
// Ignore clicks in header/footers
@@ -496,8 +523,8 @@
}
// Internally handle the item click
- final int headerViewsCount = getHeaderViewsCount();
- return handleItemClick(v, position - headerViewsCount, id);
+ final int adjustedPosition = getFlatPositionForConnector(position);
+ return handleItemClick(v, adjustedPosition, id);
}
/**
@@ -711,8 +738,8 @@
return PACKED_POSITION_VALUE_NULL;
}
- final int shiftedPosition = flatListPosition - getHeaderViewsCount();
- PositionMetadata pm = mConnector.getUnflattenedPos(shiftedPosition);
+ final int adjustedPosition = getFlatPositionForConnector(flatListPosition);
+ PositionMetadata pm = mConnector.getUnflattenedPos(adjustedPosition);
long packedPos = pm.position.getPackedPosition();
pm.recycle();
return packedPos;
@@ -732,9 +759,9 @@
public int getFlatListPosition(long packedPosition) {
PositionMetadata pm = mConnector.getFlattenedPos(ExpandableListPosition
.obtainPosition(packedPosition));
- int retValue = pm.position.flatListPos;
+ final int flatListPosition = pm.position.flatListPos;
pm.recycle();
- return retValue + getHeaderViewsCount();
+ return getAbsoluteFlatPosition(flatListPosition);
}
/**
@@ -783,7 +810,8 @@
.obtainGroupPosition(groupPosition);
PositionMetadata pm = mConnector.getFlattenedPos(elGroupPos);
elGroupPos.recycle();
- super.setSelection(pm.position.flatListPos);
+ final int absoluteFlatPosition = getAbsoluteFlatPosition(pm.position.flatListPos);
+ super.setSelection(absoluteFlatPosition);
pm.recycle();
}
@@ -819,7 +847,8 @@
}
}
- super.setSelection(flatChildPos.position.flatListPos);
+ int absoluteFlatPosition = getAbsoluteFlatPosition(flatChildPos.position.flatListPos);
+ super.setSelection(absoluteFlatPosition);
elChildPos.recycle();
flatChildPos.recycle();
@@ -937,7 +966,7 @@
return new AdapterContextMenuInfo(view, flatListPosition, id);
}
- final int adjustedPosition = flatListPosition - getHeaderViewsCount();
+ final int adjustedPosition = getFlatPositionForConnector(flatListPosition);
PositionMetadata pm = mConnector.getUnflattenedPos(adjustedPosition);
ExpandableListPosition pos = pm.position;
pm.recycle();