Merge "Optimizing contact list scrolling"
diff --git a/src/com/android/contacts/list/ContactEntryListAdapter.java b/src/com/android/contacts/list/ContactEntryListAdapter.java
index f71fd09..2d94eb0 100644
--- a/src/com/android/contacts/list/ContactEntryListAdapter.java
+++ b/src/com/android/contacts/list/ContactEntryListAdapter.java
@@ -31,6 +31,7 @@
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import android.widget.ListView;
import android.widget.TextView;
import java.util.HashSet;
@@ -63,6 +64,25 @@
private boolean mSelectionVisible;
+ /**
+ * An item view is displayed differently depending on whether it is placed
+ * at the beginning, middle or end of a section. It also needs to know the
+ * section header when it is at the beginning of a section. This object
+ * captures all this configuration.
+ */
+ public static final class Placement {
+ private int position = ListView.INVALID_POSITION;
+ public boolean firstInSection;
+ public boolean lastInSection;
+ public String sectionHeader;
+
+ public void invalidate() {
+ position = ListView.INVALID_POSITION;
+ }
+ }
+
+ private Placement mPlacementCache = new Placement();
+
public ContactEntryListAdapter(Context context) {
super(context, R.layout.list_section, R.id.header_text);
addPartitions();
@@ -256,6 +276,8 @@
@Override
public void changeCursor(int partitionIndex, Cursor cursor) {
+ mPlacementCache.invalidate();
+
Partition partition = getPartition(partitionIndex);
if (partition instanceof DirectoryPartition) {
((DirectoryPartition)partition).setLoading(false);
@@ -292,6 +314,54 @@
}
}
+ /**
+ * Computes the item's placement within its section and populates the {@code placement}
+ * object accordingly. Please note that the returned object is volatile and should be
+ * copied if the result needs to be used later.
+ */
+ public Placement getItemPlacementInSection(int position) {
+ if (mPlacementCache.position == position) {
+ return mPlacementCache;
+ }
+
+ mPlacementCache.position = position;
+ if (isSectionHeaderDisplayEnabled()) {
+ int section = getSectionForPosition(position);
+ if (section != -1 && getPositionForSection(section) == position) {
+ mPlacementCache.firstInSection = true;
+ mPlacementCache.sectionHeader = (String)getSections()[section];
+ } else {
+ mPlacementCache.firstInSection = false;
+ mPlacementCache.sectionHeader = null;
+ }
+
+ mPlacementCache.lastInSection = (getPositionForSection(section + 1) - 1 == position);
+ } else {
+ mPlacementCache.firstInSection = false;
+ mPlacementCache.lastInSection = false;
+ mPlacementCache.sectionHeader = null;
+ }
+ return mPlacementCache;
+ }
+
+ @Override
+ public int getViewTypeCount() {
+ // We need a separate view type for each item type, plus another one for
+ // each type with header, plus one for "other".
+ return super.getItemViewTypeCount() * 2 + 1;
+ }
+
+ @Override
+ public int getItemViewType(int position) {
+ int type = super.getItemViewType(position);
+ if (isSectionHeaderDisplayEnabled()) {
+ Placement placement = getItemPlacementInSection(position);
+ return placement.firstInSection ? type : getItemViewTypeCount() + type;
+ } else {
+ return type;
+ }
+ }
+
@Override
public boolean isEmpty() {
// TODO
diff --git a/src/com/android/contacts/list/ContactListAdapter.java b/src/com/android/contacts/list/ContactListAdapter.java
index fd949ec..cb1e63f 100644
--- a/src/com/android/contacts/list/ContactListAdapter.java
+++ b/src/com/android/contacts/list/ContactListAdapter.java
@@ -166,26 +166,9 @@
}
protected void bindSectionHeaderAndDivider(ContactListItemView view, int position) {
- if (isSectionHeaderDisplayEnabled()) {
- final int section = getSectionForPosition(position);
- if (section != -1 && getPositionForSection(section) == position) {
- String title = (String)getSections()[section];
- view.setSectionHeader(title);
- } else {
- view.setDividerVisible(false);
- view.setSectionHeader(null);
- }
-
- // move the divider for the last item in a section
- if (getPositionForSection(section + 1) - 1 == position) {
- view.setDividerVisible(false);
- } else {
- view.setDividerVisible(true);
- }
- } else {
- view.setSectionHeader(null);
- view.setDividerVisible(true);
- }
+ Placement placement = getItemPlacementInSection(position);
+ view.setSectionHeader(placement.firstInSection ? placement.sectionHeader : null);
+ view.setDividerVisible(!placement.lastInSection);
}
protected void bindPhoto(final ContactListItemView view, Cursor cursor) {
diff --git a/src/com/android/contacts/list/ContactListItemView.java b/src/com/android/contacts/list/ContactListItemView.java
index 102497a..755fed7 100644
--- a/src/com/android/contacts/list/ContactListItemView.java
+++ b/src/com/android/contacts/list/ContactListItemView.java
@@ -853,4 +853,12 @@
requestLayout();
}
}
+
+ @Override
+ public void requestLayout() {
+ // We will assume that once measured this will not need to resize
+ // itself, so there is no need to pass the layout request to the parent
+ // view (ListView).
+ forceLayout();
+ }
}
diff --git a/src/com/android/contacts/list/JoinContactListAdapter.java b/src/com/android/contacts/list/JoinContactListAdapter.java
index 83c5da2..09b8caf 100644
--- a/src/com/android/contacts/list/JoinContactListAdapter.java
+++ b/src/com/android/contacts/list/JoinContactListAdapter.java
@@ -141,8 +141,8 @@
}
@Override
- public int getViewTypeCount() {
- return super.getViewTypeCount() + 1;
+ public int getItemViewTypeCount() {
+ return super.getItemViewTypeCount() + 1;
}
@Override
diff --git a/src/com/android/contacts/list/MultiplePhonePickerAdapter.java b/src/com/android/contacts/list/MultiplePhonePickerAdapter.java
index 2b1196b..1eba085 100644
--- a/src/com/android/contacts/list/MultiplePhonePickerAdapter.java
+++ b/src/com/android/contacts/list/MultiplePhonePickerAdapter.java
@@ -229,7 +229,7 @@
}
@Override
- public int getViewTypeCount() {
+ public int getItemViewTypeCount() {
return 2;
}
diff --git a/src/com/android/contacts/widget/CompositeCursorAdapter.java b/src/com/android/contacts/widget/CompositeCursorAdapter.java
index 147ed42..e3a32c8 100644
--- a/src/com/android/contacts/widget/CompositeCursorAdapter.java
+++ b/src/com/android/contacts/widget/CompositeCursorAdapter.java
@@ -264,14 +264,18 @@
return position;
}
- /**
- * Returns the overall number of view types across all partitions. An implementation
- * of this method needs to ensure that the returned count is consistent with the
- * values returned by {@link #getItemViewType(int,int)}.
- */
@Override
public int getViewTypeCount() {
- return 2;
+ return getItemViewTypeCount() + 1;
+ }
+
+ /**
+ * Returns the overall number of item view types across all partitions. An
+ * implementation of this method needs to ensure that the returned count is
+ * consistent with the values returned by {@link #getItemViewType(int,int)}.
+ */
+ public int getItemViewTypeCount() {
+ return 1;
}
/**
@@ -279,7 +283,7 @@
* specified partition.
*/
protected int getItemViewType(int partition, int position) {
- return 0;
+ return 1;
}
@Override