Merge "Refactor list-caches into Custom Views with Listeners"
diff --git a/src/com/android/contacts/list/ContactEntryListAdapter.java b/src/com/android/contacts/list/ContactEntryListAdapter.java
index 16f63e2..f7f4fdb 100644
--- a/src/com/android/contacts/list/ContactEntryListAdapter.java
+++ b/src/com/android/contacts/list/ContactEntryListAdapter.java
@@ -152,7 +152,6 @@
         mSortOrder = sortOrder;
     }
 
-    // TODO no highlighting in STREQUENT mode
     public void setNameHighlightingEnabled(boolean flag) {
         mNameHighlightingEnabled = flag;
     }
diff --git a/src/com/android/contacts/list/ContactEntryListFragment.java b/src/com/android/contacts/list/ContactEntryListFragment.java
index 0da9a36..44c50af 100644
--- a/src/com/android/contacts/list/ContactEntryListFragment.java
+++ b/src/com/android/contacts/list/ContactEntryListFragment.java
@@ -224,6 +224,9 @@
     @Override
     protected void onLoadFinished(Loader<Cursor> loader, Cursor data) {
         if (!checkProviderStatus(false)) {
+            if (data != null) {
+                data.close();
+            }
             return;
         }
 
@@ -234,6 +237,10 @@
             onRequeryFinished(partitionIndex, data);
         }
 
+        if (partitionIndex == mAdapter.getIndexedPartition()) {
+            mAizy.setIndexer(mAdapter.getIndexer());
+        }
+
 // TODO fix the empty view
 //            if (mEmptyView != null && (data == null || data.getCount() == 0)) {
 //                prepareEmptyView();
@@ -308,9 +315,6 @@
             mAdapter.changeCursor(partitionIndex, data);
             showCount(partitionIndex, data);
         }
-        if (partitionIndex == mAdapter.getIndexedPartition()) {
-            mAizy.setIndexer(mAdapter.getIndexer());
-        }
     }
 
     private DirectoryPartition createDirectoryPartition(int partitionIndex, Cursor cursor) {
@@ -343,31 +347,34 @@
         } else {
             mAdapter.configureLoader(loader, partition.getDirectoryId());
             if (forceLoad) {
-                loader.cancelLoad();
                 loader.forceLoad();
             }
         }
     }
 
     protected void reloadData() {
-        mAdapter.onDataReload();
-        if (mDirectoryPartitions.size() > 0) {
-            // We need to cancel _all_ current queries and then launch
-            // a new query for the 0th partition.
+        if (mInitialLoadComplete) {
+            mAdapter.onDataReload();
+            if (mDirectoryPartitions.size() > 0) {
+                // We need to cancel _all_ current queries and then launch
+                // a new query for the 0th partition.
 
-            CursorLoader directoryLoader = (CursorLoader)getLoader(DIRECTORY_LOADER_ID);
-            if (directoryLoader != null) {
-                directoryLoader.cancelLoad();
-            }
-            int size = mDirectoryPartitions.size();
-            for (int i = 0; i < size; i++) {
-                CursorLoader loader = (CursorLoader)getLoader(i);
-                if (loader != null) {
-                    loader.cancelLoad();
+                CursorLoader directoryLoader = (CursorLoader)getLoader(DIRECTORY_LOADER_ID);
+                if (directoryLoader != null) {
+                    directoryLoader.cancelLoad();
                 }
-            }
+                int size = mDirectoryPartitions.size();
+                for (int i = 0; i < size; i++) {
+                    CursorLoader loader = (CursorLoader)getLoader(i);
+                    if (loader != null) {
+                        loader.cancelLoad();
+                    }
+                }
 
-            startLoading(mDirectoryPartitions.get(0), true);
+                startLoading(mDirectoryPartitions.get(0), true);
+            }
+        } else {
+            startLoading(0, null);
         }
     }
 
@@ -378,6 +385,13 @@
         }
     }
 
+    @Override
+    public void onStop() {
+        super.onStop();
+        mAdapter.resetPartitions();
+        mInitialLoadComplete = false;
+    }
+
     /**
      * Configures the empty view. It is called when we are about to populate
      * the list with an empty cursor.
@@ -630,17 +644,18 @@
     }
 
     protected void configureAdapter() {
-        if (mAdapter != null) {
-            mAdapter.setQueryString(mQueryString);
-            mAdapter.setPinnedPartitionHeadersEnabled(mSearchMode);
-            mAdapter.setContactNameDisplayOrder(mDisplayOrder);
-            mAdapter.setSortOrder(mSortOrder);
-            mAdapter.setNameHighlightingEnabled(isNameHighlighingEnabled());
-            mAdapter.setSectionHeaderDisplayEnabled(mSectionHeaderDisplayEnabled);
+        if (mAdapter == null) {
+            return;
         }
+        mAdapter.setQueryString(mQueryString);
+        mAdapter.setPinnedPartitionHeadersEnabled(mSearchMode);
+        mAdapter.setContactNameDisplayOrder(mDisplayOrder);
+        mAdapter.setSortOrder(mSortOrder);
+        mAdapter.setNameHighlightingEnabled(isNameHighlighingEnabled());
+        mAdapter.setSectionHeaderDisplayEnabled(mSectionHeaderDisplayEnabled);
     }
 
-    private boolean isNameHighlighingEnabled() {
+    protected boolean isNameHighlighingEnabled() {
         // When sort order and display order contradict each other, we want to
         // highlight the part of the name used for sorting.
         if (mSortOrder == ContactsContract.Preferences.SORT_ORDER_PRIMARY &&
diff --git a/src/com/android/contacts/list/ContactPickerFragment.java b/src/com/android/contacts/list/ContactPickerFragment.java
index 1f1e155..2907603 100644
--- a/src/com/android/contacts/list/ContactPickerFragment.java
+++ b/src/com/android/contacts/list/ContactPickerFragment.java
@@ -36,6 +36,10 @@
     private boolean mCreateContactEnabled;
     private boolean mShortcutRequested;
 
+    public ContactPickerFragment() {
+        setPhotoLoaderEnabled(true);
+    }
+
     public void setOnContactPickerActionListener(OnContactPickerActionListener listener) {
         mListener = listener;
     }
diff --git a/src/com/android/contacts/list/DefaultContactBrowseListFragment.java b/src/com/android/contacts/list/DefaultContactBrowseListFragment.java
index 6c5559f..24b48d3 100644
--- a/src/com/android/contacts/list/DefaultContactBrowseListFragment.java
+++ b/src/com/android/contacts/list/DefaultContactBrowseListFragment.java
@@ -25,7 +25,6 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.FrameLayout;
-import android.widget.ListAdapter;
 import android.widget.TextView;
 
 /**
diff --git a/src/com/android/contacts/list/StrequentContactListAdapter.java b/src/com/android/contacts/list/StrequentContactListAdapter.java
index 4a72f63..b5aec28 100644
--- a/src/com/android/contacts/list/StrequentContactListAdapter.java
+++ b/src/com/android/contacts/list/StrequentContactListAdapter.java
@@ -35,7 +35,7 @@
  */
 public class StrequentContactListAdapter extends ContactListAdapter {
 
-    private int mFrequentSeparatorPos;
+    private int mFrequentSeparatorPos = ListView.INVALID_POSITION;
     private TextView mSeparatorView;
     private OnClickListener mCallButtonListener;
     private int mCallButtonId;
@@ -83,8 +83,17 @@
     }
 
     @Override
-    public void changeCursor(Cursor cursor) {
-        super.changeCursor(cursor);
+    protected void invalidate() {
+        super.invalidate();
+
+        // Sometimes the adapter is invalidated without calling changeCursor,
+        // need to reset the separator position then.
+        mFrequentSeparatorPos = ListView.INVALID_POSITION;
+    }
+
+    @Override
+    public void changeCursor(int partition, Cursor cursor) {
+        super.changeCursor(partition, cursor);
 
         // Get the split between starred and frequent items, if the mode is strequent
         mFrequentSeparatorPos = ListView.INVALID_POSITION;
diff --git a/src/com/android/contacts/list/StrequentContactListFragment.java b/src/com/android/contacts/list/StrequentContactListFragment.java
index 264f2c0..4b8e2bb 100644
--- a/src/com/android/contacts/list/StrequentContactListFragment.java
+++ b/src/com/android/contacts/list/StrequentContactListFragment.java
@@ -38,6 +38,13 @@
         setPhotoLoaderEnabled(true);
     }
 
+    @Override
+    protected boolean isNameHighlighingEnabled() {
+        // Since the list is not ordered alphabetically, we don't need to highlight the part
+        // that is used for sorting.
+        return false;
+    }
+
     public void setStarredContactsIncluded(boolean flag) {
         mStarredContactsIncluded = flag;
         configureAdapter();
diff --git a/src/com/android/contacts/widget/CompositeCursorAdapter.java b/src/com/android/contacts/widget/CompositeCursorAdapter.java
index 3eb48bb..c6d2ea3 100644
--- a/src/com/android/contacts/widget/CompositeCursorAdapter.java
+++ b/src/com/android/contacts/widget/CompositeCursorAdapter.java
@@ -80,6 +80,12 @@
     }
 
     public void resetPartitions() {
+        for (int i = 0; i < mSize; i++) {
+            Cursor cursor = mPartitions[i].cursor;
+            if (cursor != null && !cursor.isClosed()) {
+                cursor.close();
+            }
+        }
         mSize = 0;
         invalidate();
         notifyDataSetChanged();
@@ -140,12 +146,18 @@
      * Changes the cursor for an individual partition.
      */
     public void changeCursor(int partition, Cursor cursor) {
-        mPartitions[partition].cursor = cursor;
-        if (cursor != null) {
-            mPartitions[partition].idColumnIndex = cursor.getColumnIndex("_id");
+        Cursor prevCursor = mPartitions[partition].cursor;
+        if (prevCursor != cursor) {
+            if (prevCursor != null && !prevCursor.isClosed()) {
+                prevCursor.close();
+            }
+            mPartitions[partition].cursor = cursor;
+            if (cursor != null) {
+                mPartitions[partition].idColumnIndex = cursor.getColumnIndex("_id");
+            }
+            invalidate();
+            notifyDataSetChanged();
         }
-        invalidate();
-        notifyDataSetChanged();
     }
 
     /**
diff --git a/src/com/android/contacts/widget/PinnedHeaderListView.java b/src/com/android/contacts/widget/PinnedHeaderListView.java
index 055e05d..c51db9e 100644
--- a/src/com/android/contacts/widget/PinnedHeaderListView.java
+++ b/src/com/android/contacts/widget/PinnedHeaderListView.java
@@ -457,7 +457,7 @@
         // First draw top headers, then the bottom ones to handle the Z axis correctly
         for (int i = mSize; --i >= 0;) {
             PinnedHeader header = mHeaders[i];
-            if (header.visible && header.state == TOP) {
+            if (header.visible && (header.state == TOP || header.state == FADING)) {
                 drawHeader(canvas, header, currentTime);
             }
         }
diff --git a/src/com/android/contacts/widget/TextHighlightingAnimation.java b/src/com/android/contacts/widget/TextHighlightingAnimation.java
index 049e5cd..21bbc63 100644
--- a/src/com/android/contacts/widget/TextHighlightingAnimation.java
+++ b/src/com/android/contacts/widget/TextHighlightingAnimation.java
@@ -20,7 +20,6 @@
 import android.database.CharArrayBuffer;
 import android.graphics.Color;
 import android.os.Handler;
-import android.text.Spanned;
 import android.text.TextPaint;
 import android.text.style.CharacterStyle;
 import android.view.animation.AccelerateInterpolator;