Breaking name highlighting animation out of ContactsListActivity

Change-Id: I6b08100e20d86f12bd04a88aa513e832df3608fe
diff --git a/src/com/android/contacts/ContactEntryListView.java b/src/com/android/contacts/ContactEntryListView.java
new file mode 100644
index 0000000..795be43
--- /dev/null
+++ b/src/com/android/contacts/ContactEntryListView.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.contacts;
+
+import com.android.contacts.list.ContactEntryListAdapter;
+import com.android.contacts.widget.PinnedHeaderListView;
+import com.android.contacts.widget.TextHighlightingAnimation;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.widget.AbsListView;
+import android.widget.ListAdapter;
+
+/**
+ * A custom list view for a list of contacts or contact-related entries.  It handles
+ * animation of names on scroll.
+ */
+public class ContactEntryListView extends PinnedHeaderListView {
+
+    private static final int TEXT_HIGHLIGHTING_ANIMATION_DURATION = 350;
+
+    private final TextHighlightingAnimation mHighlightingAnimation =
+            new ContactNameHighlightingAnimation(this, TEXT_HIGHLIGHTING_ANIMATION_DURATION);
+
+    private boolean mHighlightNamesWhenScrolling;
+
+    public ContactEntryListView(Context context) {
+        super(context);
+    }
+
+    public ContactEntryListView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public ContactEntryListView(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+    }
+
+    public TextHighlightingAnimation getTextHighlightingAnimation() {
+        return mHighlightingAnimation;
+    }
+
+    public boolean getHighlightNamesWhenScrolling() {
+        return mHighlightNamesWhenScrolling;
+    }
+
+    public void setHighlightNamesWhenScrolling(boolean flag) {
+        mHighlightNamesWhenScrolling = flag;
+    }
+
+    @Override
+    public void setAdapter(ListAdapter adapter) {
+        super.setAdapter(adapter);
+        if (adapter instanceof ContactEntryListAdapter) {
+            ((ContactEntryListAdapter)adapter)
+                    .setTextWithHighlightingFactory(mHighlightingAnimation);
+        }
+    }
+
+    @Override
+    public void onScrollStateChanged(AbsListView view, int scrollState) {
+        super.onScrollStateChanged(view, scrollState);
+        if (mHighlightNamesWhenScrolling) {
+            if (scrollState != OnScrollListener.SCROLL_STATE_IDLE) {
+                mHighlightingAnimation.startHighlighting();
+            } else {
+                mHighlightingAnimation.stopHighlighting();
+            }
+        }
+    }
+}
diff --git a/src/com/android/contacts/ContactNameHighlightingAnimation.java b/src/com/android/contacts/ContactNameHighlightingAnimation.java
new file mode 100644
index 0000000..3a17bb6
--- /dev/null
+++ b/src/com/android/contacts/ContactNameHighlightingAnimation.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.contacts;
+
+import com.android.contacts.widget.TextHighlightingAnimation;
+
+import android.view.View;
+import android.widget.ListView;
+
+/**
+ * A {@link TextHighlightingAnimation} that redraws just the contact display name in a
+ * list item.
+ */
+public class ContactNameHighlightingAnimation extends TextHighlightingAnimation {
+    private final ListView mListView;
+
+    public ContactNameHighlightingAnimation(ListView listView, int duration) {
+        super(duration);
+        this.mListView = listView;
+    }
+
+    /**
+     * Redraws all visible items of the list corresponding to contacts
+     */
+    @Override
+    protected void invalidate() {
+        int childCount = mListView.getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            View itemView = mListView.getChildAt(i);
+            if (itemView instanceof ContactListItemView) {
+                final ContactListItemView view = (ContactListItemView)itemView;
+                view.getNameTextView().invalidate();
+            }
+        }
+    }
+
+    @Override
+    protected void onAnimationStarted() {
+        mListView.setScrollingCacheEnabled(false);
+    }
+
+    @Override
+    protected void onAnimationEnded() {
+        mListView.setScrollingCacheEnabled(true);
+    }
+}
diff --git a/src/com/android/contacts/ContactsListActivity.java b/src/com/android/contacts/ContactsListActivity.java
index 16f41b1..0fb03e5 100644
--- a/src/com/android/contacts/ContactsListActivity.java
+++ b/src/com/android/contacts/ContactsListActivity.java
@@ -16,7 +16,6 @@
 
 package com.android.contacts;
 
-import com.android.contacts.TextHighlightingAnimation.TextWithHighlighting;
 import com.android.contacts.list.ContactEntryListAdapter;
 import com.android.contacts.list.ContactEntryListConfiguration;
 import com.android.contacts.list.ContactItemListAdapter;
@@ -28,12 +27,12 @@
 import com.android.contacts.ui.ContactsPreferencesActivity.Prefs;
 import com.android.contacts.util.AccountSelectionUtil;
 import com.android.contacts.util.Constants;
+import com.android.contacts.widget.TextWithHighlighting;
 
 import android.accounts.Account;
 import android.app.Activity;
 import android.app.AlertDialog;
 import android.app.Dialog;
-import android.app.ListActivity;
 import android.app.SearchManager;
 import android.content.AsyncQueryHandler;
 import android.content.ContentResolver;
@@ -44,7 +43,6 @@
 import android.content.Intent;
 import android.content.SharedPreferences;
 import android.content.UriMatcher;
-import android.content.res.ColorStateList;
 import android.content.res.Resources;
 import android.database.CharArrayBuffer;
 import android.database.ContentObserver;
@@ -83,7 +81,6 @@
 import android.provider.ContactsContract.Intents.Insert;
 import android.telephony.TelephonyManager;
 import android.text.Editable;
-import android.text.Html;
 import android.text.TextUtils;
 import android.text.TextWatcher;
 import android.util.Log;
@@ -149,8 +146,6 @@
     private static final int SUBACTIVITY_SEARCH = 4;
     protected static final int SUBACTIVITY_FILTER = 5;
 
-    private static final int TEXT_HIGHLIGHTING_ANIMATION_DURATION = 350;
-
     public static final String AUTHORITIES_FILTER_KEY = "authorities";
 
     private static final Uri CONTACTS_CONTENT_URI_WITH_LETTER_COUNTS =
@@ -443,51 +438,11 @@
         }
     }
 
-    /**
-     * A {@link TextHighlightingAnimation} that redraws just the contact display name in a
-     * list item.
-     */
-    private static class NameHighlightingAnimation extends TextHighlightingAnimation {
-        private final ListView mListView;
-
-        private NameHighlightingAnimation(ListView listView, int duration) {
-            super(duration);
-            this.mListView = listView;
-        }
-
-        /**
-         * Redraws all visible items of the list corresponding to contacts
-         */
-        @Override
-        protected void invalidate() {
-            int childCount = mListView.getChildCount();
-            for (int i = 0; i < childCount; i++) {
-                View itemView = mListView.getChildAt(i);
-                if (itemView instanceof ContactListItemView) {
-                    final ContactListItemView view = (ContactListItemView)itemView;
-                    view.getNameTextView().invalidate();
-                }
-            }
-        }
-
-        @Override
-        protected void onAnimationStarted() {
-            mListView.setScrollingCacheEnabled(false);
-        }
-
-        @Override
-        protected void onAnimationEnded() {
-            mListView.setScrollingCacheEnabled(true);
-        }
-    }
-
     // The size of a home screen shortcut icon.
     private int mIconSize;
     private ContactsPreferences mContactsPrefs;
     public int mDisplayOrder;
     private int mSortOrder;
-    public boolean mHighlightWhenScrolling;
-    public TextHighlightingAnimation mHighlightingAnimation;
     private SearchEditText mSearchEditText;
 
     private ContentObserver mProviderStatusObserver = new ContentObserver(new Handler()) {
@@ -588,9 +543,6 @@
     @Deprecated
     public void setupListView(ListAdapter adapter, ListView list) {
 
-        mHighlightingAnimation =
-                new NameHighlightingAnimation(list, TEXT_HIGHLIGHTING_ANIMATION_DURATION);
-
         // Tell list view to not show dividers. We'll do it ourself so that we can *not* show
         // them when an A-Z headers is visible.
         list.setDividerHeight(0);
@@ -629,14 +581,6 @@
     }
 
     public void onScrollStateChanged(AbsListView view, int scrollState) {
-        if (mHighlightWhenScrolling) {
-            if (scrollState != OnScrollListener.SCROLL_STATE_IDLE) {
-                mHighlightingAnimation.startHighlighting();
-            } else {
-                mHighlightingAnimation.stopHighlighting();
-            }
-        }
-
         if (scrollState == OnScrollListener.SCROLL_STATE_FLING) {
             mPhotoLoader.pause();
         } else if (mConfig.isPhotoLoaderEnabled()) {
@@ -2048,15 +1992,23 @@
         mSortOrder = mContactsPrefs.getSortOrder();
         mDisplayOrder = mContactsPrefs.getDisplayOrder();
 
-        // When sort order and display order contradict each other, we want to
-        // highlight the part of the name used for sorting.
-        mHighlightWhenScrolling = false;
-        if (mSortOrder == ContactsContract.Preferences.SORT_ORDER_PRIMARY &&
-                mDisplayOrder == ContactsContract.Preferences.DISPLAY_ORDER_ALTERNATIVE) {
-            mHighlightWhenScrolling = true;
-        } else if (mSortOrder == ContactsContract.Preferences.SORT_ORDER_ALTERNATIVE &&
-                mDisplayOrder == ContactsContract.Preferences.DISPLAY_ORDER_PRIMARY) {
-            mHighlightWhenScrolling = true;
+        if (mListView instanceof ContactEntryListView) {
+            ContactEntryListView listView = (ContactEntryListView)mListView;
+
+            // 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 &&
+                    mDisplayOrder == ContactsContract.Preferences.DISPLAY_ORDER_ALTERNATIVE) {
+                listView.setHighlightNamesWhenScrolling(true);
+                mAdapter.setNameHighlightingEnabled(true);
+            } else if (mSortOrder == ContactsContract.Preferences.SORT_ORDER_ALTERNATIVE &&
+                    mDisplayOrder == ContactsContract.Preferences.DISPLAY_ORDER_PRIMARY) {
+                listView.setHighlightNamesWhenScrolling(true);
+                mAdapter.setNameHighlightingEnabled(true);
+            } else {
+                listView.setHighlightNamesWhenScrolling(false);
+                mAdapter.setNameHighlightingEnabled(false);
+            }
         }
 
         String[] projection = getProjectionForQuery();
diff --git a/src/com/android/contacts/list/ContactEntryListAdapter.java b/src/com/android/contacts/list/ContactEntryListAdapter.java
index 2cf12c5..86c7ba5 100644
--- a/src/com/android/contacts/list/ContactEntryListAdapter.java
+++ b/src/com/android/contacts/list/ContactEntryListAdapter.java
@@ -15,6 +15,9 @@
  */
 package com.android.contacts.list;
 
+import com.android.contacts.widget.TextWithHighlighting;
+import com.android.contacts.widget.TextWithHighlightingFactory;
+
 import android.content.Context;
 
 /**
@@ -23,6 +26,13 @@
  */
 public abstract class ContactEntryListAdapter extends PinnedHeaderListAdapter {
 
+    /**
+     * The animation is used here to allocate animated name text views.
+     */
+    private TextWithHighlightingFactory mTextWithHighlightingFactory;
+
+    private boolean mNameHighlightingEnabled;
+
     public ContactEntryListAdapter(Context context) {
         super(context);
     }
@@ -31,6 +41,22 @@
         return mContext;
     }
 
+    public void setNameHighlightingEnabled(boolean flag) {
+        mNameHighlightingEnabled = flag;
+    }
+
+    public boolean isNameHighlightingEnabled() {
+        return mNameHighlightingEnabled;
+    }
+
+    public void setTextWithHighlightingFactory(TextWithHighlightingFactory factory) {
+        mTextWithHighlightingFactory = factory;
+    }
+
+    protected TextWithHighlighting createTextWithHighlighting() {
+        return mTextWithHighlightingFactory.createTextWithHighlighting();
+    }
+
     /*
      * TODO change this method when loaders are introduced.
      */
diff --git a/src/com/android/contacts/list/ContactItemListAdapter.java b/src/com/android/contacts/list/ContactItemListAdapter.java
index 6b228c6..4fc8142 100644
--- a/src/com/android/contacts/list/ContactItemListAdapter.java
+++ b/src/com/android/contacts/list/ContactItemListAdapter.java
@@ -21,7 +21,7 @@
 import com.android.contacts.ContactsSectionIndexer;
 import com.android.contacts.R;
 import com.android.contacts.ContactsListActivity.ContactListItemCache;
-import com.android.contacts.TextHighlightingAnimation.TextWithHighlighting;
+import com.android.contacts.widget.TextWithHighlighting;
 
 import android.content.Context;
 import android.database.CharArrayBuffer;
@@ -310,7 +310,7 @@
                 labelColumnIndex = -1;
                 defaultType = Phone.TYPE_HOME;
                 displayAdditionalData = false;
-                highlightingEnabled = contactsListActivity.mHighlightWhenScrolling
+                highlightingEnabled = isNameHighlightingEnabled()
                         && contactsListActivity.mMode != ContactsListActivity.MODE_STREQUENT;
             }
         }
@@ -322,8 +322,7 @@
         if (size != 0) {
             if (highlightingEnabled) {
                 if (cache.textWithHighlighting == null) {
-                    cache.textWithHighlighting =
-                            contactsListActivity.mHighlightingAnimation.createTextWithHighlighting();
+                    cache.textWithHighlighting = createTextWithHighlighting();
                 }
                 buildDisplayNameWithHighlighting(nameView, cursor, cache.nameBuffer,
                         cache.highlightedTextBuffer, cache.textWithHighlighting);
diff --git a/src/com/android/contacts/list/MultiplePhonePickerAdapter.java b/src/com/android/contacts/list/MultiplePhonePickerAdapter.java
index fd0feeb..e5dd609 100644
--- a/src/com/android/contacts/list/MultiplePhonePickerAdapter.java
+++ b/src/com/android/contacts/list/MultiplePhonePickerAdapter.java
@@ -93,7 +93,6 @@
         int phoneticNameColumnIndex;
         int photoColumnIndex = ContactsListActivity.SUMMARY_PHOTO_ID_COLUMN_INDEX;
         boolean displayAdditionalData = mDisplayAdditionalData;
-        boolean highlightingEnabled = false;
         nameColumnIndex = ContactsListActivity.PHONE_DISPLAY_NAME_COLUMN_INDEX;
         phoneticNameColumnIndex = -1;
         dataColumnIndex = ContactsListActivity.PHONE_NUMBER_COLUMN_INDEX;
@@ -116,17 +115,7 @@
         TextView nameView = view.getNameTextView();
         int size = cache.nameBuffer.sizeCopied;
         if (size != 0) {
-            if (highlightingEnabled) {
-                if (cache.textWithHighlighting == null) {
-                    cache.textWithHighlighting =
-                            mMultiplePhonePickerActivity.mHighlightingAnimation
-                                    .createTextWithHighlighting();
-                }
-                buildDisplayNameWithHighlighting(nameView, cursor, cache.nameBuffer,
-                        cache.highlightedTextBuffer, cache.textWithHighlighting);
-            } else {
-                nameView.setText(cache.nameBuffer.data, 0, size);
-            }
+            nameView.setText(cache.nameBuffer.data, 0, size);
         } else {
             nameView.setText(mUnknownNameText);
         }
diff --git a/src/com/android/contacts/widget/PinnedHeaderListView.java b/src/com/android/contacts/widget/PinnedHeaderListView.java
index a3e6794..f37423d 100644
--- a/src/com/android/contacts/widget/PinnedHeaderListView.java
+++ b/src/com/android/contacts/widget/PinnedHeaderListView.java
@@ -88,6 +88,7 @@
 
     public PinnedHeaderListView(Context context, AttributeSet attrs) {
         super(context, attrs);
+        super.setOnScrollListener(this);
     }
 
     public PinnedHeaderListView(Context context, AttributeSet attrs, int defStyle) {
diff --git a/src/com/android/contacts/TextHighlightingAnimation.java b/src/com/android/contacts/widget/TextHighlightingAnimation.java
similarity index 96%
rename from src/com/android/contacts/TextHighlightingAnimation.java
rename to src/com/android/contacts/widget/TextHighlightingAnimation.java
index e35ae1e..049e5cd 100644
--- a/src/com/android/contacts/TextHighlightingAnimation.java
+++ b/src/com/android/contacts/widget/TextHighlightingAnimation.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.contacts;
+package com.android.contacts.widget;
 
 import com.android.internal.R;
 
@@ -29,7 +29,7 @@
 /**
  * An animation that alternately dims and brightens the non-highlighted portion of text.
  */
-public abstract class TextHighlightingAnimation implements Runnable {
+public abstract class TextHighlightingAnimation implements Runnable, TextWithHighlightingFactory {
 
     private static final int MAX_ALPHA = 255;
     private static final int MIN_ALPHA = 50;
@@ -54,7 +54,7 @@
     /**
      * A Spanned that highlights a part of text by dimming another part of that text.
      */
-    public class TextWithHighlighting implements Spanned {
+    public class TextWithHighlightingImpl implements TextWithHighlighting {
 
         private final DimmingSpan[] mSpans;
         private boolean mDimmingEnabled;
@@ -63,7 +63,7 @@
         private int mDimmingSpanEnd;
         private String mString;
 
-        public TextWithHighlighting() {
+        public TextWithHighlightingImpl() {
             mSpans = new DimmingSpan[] { mDimmingSpan };
         }
 
@@ -216,12 +216,12 @@
     /**
      * Returns a Spanned that can be used by a text view to show text with highlighting.
      */
-    public TextWithHighlighting createTextWithHighlighting() {
-        return new TextWithHighlighting();
+    public TextWithHighlightingImpl createTextWithHighlighting() {
+        return new TextWithHighlightingImpl();
     }
 
     /**
-     * Override and invalidate (redraw) TextViews showing {@link TextWithHighlighting}.
+     * Override and invalidate (redraw) TextViews showing {@link TextWithHighlightingImpl}.
      */
     protected abstract void invalidate();
 
diff --git a/src/com/android/contacts/widget/TextWithHighlighting.java b/src/com/android/contacts/widget/TextWithHighlighting.java
new file mode 100644
index 0000000..3a32b02
--- /dev/null
+++ b/src/com/android/contacts/widget/TextWithHighlighting.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.contacts.widget;
+
+import android.database.CharArrayBuffer;
+import android.text.Spanned;
+
+/**
+ * A Spanned that highlights a part of text by dimming another part of that text.
+ */
+public interface TextWithHighlighting extends Spanned {
+    void setText(CharArrayBuffer baseText, CharArrayBuffer highlightedText);
+}
diff --git a/src/com/android/contacts/widget/TextWithHighlightingFactory.java b/src/com/android/contacts/widget/TextWithHighlightingFactory.java
new file mode 100644
index 0000000..ee5744d
--- /dev/null
+++ b/src/com/android/contacts/widget/TextWithHighlightingFactory.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.contacts.widget;
+
+/**
+ * A factory for text fields with animated highlighting.
+ */
+public interface TextWithHighlightingFactory {
+    TextWithHighlighting createTextWithHighlighting();
+}