am 211ae635: Reduce chip jank

* commit '211ae63525c02ec914ef020af625ea4e7d8a3b29':
  Reduce chip jank
diff --git a/chips/src/com/android/ex/chips/InvisibleRecipientChip.java b/chips/src/com/android/ex/chips/InvisibleRecipientChip.java
index beeb499..83f7f8e 100644
--- a/chips/src/com/android/ex/chips/InvisibleRecipientChip.java
+++ b/chips/src/com/android/ex/chips/InvisibleRecipientChip.java
@@ -18,7 +18,6 @@
 
 import android.graphics.Canvas;
 import android.graphics.Paint;
-import android.graphics.Paint.FontMetricsInt;
 import android.graphics.Rect;
 import android.text.TextUtils;
 import android.text.style.ReplacementSpan;
@@ -148,4 +147,9 @@
     public void draw(Canvas canvas) {
         // do nothing.
     }
+
+    @Override
+    public String toString() {
+        return mDisplay + " <" + mValue + ">";
+    }
 }
diff --git a/chips/src/com/android/ex/chips/RecipientAlternatesAdapter.java b/chips/src/com/android/ex/chips/RecipientAlternatesAdapter.java
index 1aead22..f825e93 100644
--- a/chips/src/com/android/ex/chips/RecipientAlternatesAdapter.java
+++ b/chips/src/com/android/ex/chips/RecipientAlternatesAdapter.java
@@ -231,7 +231,7 @@
      * no significant differences are found.
      * TODO(skennedy) Add tests
      */
-    private static RecipientEntry getBetterRecipient(final RecipientEntry entry1,
+    static RecipientEntry getBetterRecipient(final RecipientEntry entry1,
             final RecipientEntry entry2) {
         // If only one has passed in, use it
         if (entry2 == null) {
diff --git a/chips/src/com/android/ex/chips/RecipientEditTextView.java b/chips/src/com/android/ex/chips/RecipientEditTextView.java
index 5400833..8fe6dbf 100644
--- a/chips/src/com/android/ex/chips/RecipientEditTextView.java
+++ b/chips/src/com/android/ex/chips/RecipientEditTextView.java
@@ -36,6 +36,7 @@
 import android.graphics.drawable.Drawable;
 import android.os.AsyncTask;
 import android.os.Handler;
+import android.os.Looper;
 import android.os.Message;
 import android.os.Parcelable;
 import android.text.Editable;
@@ -2426,6 +2427,34 @@
         }
 
         @Override
+        protected void onPreExecute() {
+            // Ensure everything is in chip-form already, so we don't have text that slowly gets
+            // replaced
+            final List<RecipientChip> originalRecipients = new ArrayList<RecipientChip>();
+            final RecipientChip[] existingChips = getSortedRecipients();
+            for (int i = 0; i < existingChips.length; i++) {
+                originalRecipients.add(existingChips[i]);
+            }
+            if (mRemovedSpans != null) {
+                originalRecipients.addAll(mRemovedSpans);
+            }
+
+            final List<RecipientChip> replacements =
+                    new ArrayList<RecipientChip>(originalRecipients.size());
+
+            for (final RecipientChip chip : originalRecipients) {
+                if (RecipientEntry.isCreatedRecipient(chip.getEntry().getContactId())
+                        && getSpannable().getSpanStart(chip) != -1) {
+                    replacements.add(createFreeChip(chip.getEntry()));
+                } else {
+                    replacements.add(null);
+                }
+            }
+
+            processReplacements(originalRecipients, replacements);
+        }
+
+        @Override
         protected Void doInBackground(Void... params) {
             if (mIndividualReplacements != null) {
                 mIndividualReplacements.cancel(true);
@@ -2433,18 +2462,18 @@
             // For each chip in the list, look up the matching contact.
             // If there is a match, replace that chip with the matching
             // chip.
-            final ArrayList<RecipientChip> originalRecipients = new ArrayList<RecipientChip>();
+            final ArrayList<RecipientChip> recipients = new ArrayList<RecipientChip>();
             RecipientChip[] existingChips = getSortedRecipients();
             for (int i = 0; i < existingChips.length; i++) {
-                originalRecipients.add(existingChips[i]);
+                recipients.add(existingChips[i]);
             }
             if (mRemovedSpans != null) {
-                originalRecipients.addAll(mRemovedSpans);
+                recipients.addAll(mRemovedSpans);
             }
             ArrayList<String> addresses = new ArrayList<String>();
             RecipientChip chip;
-            for (int i = 0; i < originalRecipients.size(); i++) {
-                chip = originalRecipients.get(i);
+            for (int i = 0; i < recipients.size(); i++) {
+                chip = recipients.get(i);
                 if (chip != null) {
                     addresses.add(createAddressText(chip.getEntry()));
                 }
@@ -2457,7 +2486,7 @@
                         public void matchesFound(Map<String, RecipientEntry> entries) {
                             final ArrayList<RecipientChip> replacements =
                                     new ArrayList<RecipientChip>();
-                            for (final RecipientChip temp : originalRecipients) {
+                            for (final RecipientChip temp : recipients) {
                                 RecipientEntry entry = null;
                                 if (RecipientEntry.isCreatedRecipient(temp.getEntry()
                                         .getContactId())
@@ -2473,58 +2502,7 @@
                                     replacements.add(null);
                                 }
                             }
-                            processReplacements(replacements);
-                        }
-
-                        private void processReplacements(final List<RecipientChip> replacements) {
-                            if (replacements != null && replacements.size() > 0) {
-                                mHandler.post(new Runnable() {
-                                    @Override
-                                    public void run() {
-                                        Editable oldText = getText();
-                                        int start, end;
-                                        int i = 0;
-                                        for (RecipientChip chip : originalRecipients) {
-                                            // Find the location of the chip in
-                                            // the text currently shown.
-                                            start = oldText.getSpanStart(chip);
-                                            if (start != -1) {
-                                                RecipientChip replacement = replacements.get(i);
-                                                if (replacement != null) {
-                                                    // Replacing the entirety of
-                                                    // what the chip
-                                                    // represented, including
-                                                    // the extra space dividing
-                                                    // it from other chips.
-                                                    end = oldText.getSpanEnd(chip) + 1;
-                                                    oldText.removeSpan(chip);
-                                                    // Make sure we always have just 1 space at the
-                                                    // end to separate this chip from the next chip.
-                                                    SpannableString displayText =
-                                                            new SpannableString(
-                                                            createAddressText(
-                                                                    replacement.getEntry()).trim()
-                                                                    + " ");
-                                                    displayText.setSpan(replacement, 0,
-                                                            displayText.length() - 1,
-                                                            Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
-                                                    // Replace the old text we
-                                                    // found with with the new
-                                                    // display text, which now
-                                                    // may also contain the
-                                                    // display name of the
-                                                    // recipient.
-                                                    oldText.replace(start, end, displayText);
-                                                    replacement.setOriginalText(displayText
-                                                            .toString());
-                                                    replacements.set(i, null);
-                                                }
-                                            }
-                                            i++;
-                                        }
-                                    }
-                                });
-                            }
+                            processReplacements(recipients, replacements);
                         }
 
                         @Override
@@ -2532,7 +2510,7 @@
                             final List<RecipientChip> replacements =
                                     new ArrayList<RecipientChip>(addresses.size());
 
-                            for (final RecipientChip temp : originalRecipients) {
+                            for (final RecipientChip temp : recipients) {
                                 if (RecipientEntry.isCreatedRecipient(temp.getEntry()
                                         .getContactId())
                                         && getSpannable().getSpanStart(temp) != -1) {
@@ -2546,22 +2524,80 @@
                                 }
                             }
 
-                            processReplacements(replacements);
+                            processReplacements(recipients, replacements);
                         }
                     });
             return null;
         }
+
+        private void processReplacements(final List<RecipientChip> recipients,
+                final List<RecipientChip> replacements) {
+            if (replacements != null && replacements.size() > 0) {
+                final Runnable runnable = new Runnable() {
+                    @Override
+                    public void run() {
+                        Editable oldText = getText();
+                        int start, end;
+                        int i = 0;
+                        for (RecipientChip chip : recipients) {
+                            RecipientChip replacement = replacements.get(i);
+                            if (replacement != null) {
+                                final RecipientEntry oldEntry = chip.getEntry();
+                                final RecipientEntry newEntry = replacement.getEntry();
+                                final boolean isBetter =
+                                        RecipientAlternatesAdapter.getBetterRecipient(
+                                                oldEntry, newEntry) == newEntry;
+
+                                if (isBetter) {
+                                    // Find the location of the chip in the text currently shown.
+                                    start = oldText.getSpanStart(chip);
+                                    if (start != -1) {
+                                        // Replacing the entirety of what the chip represented,
+                                        // including the extra space dividing it from other chips.
+                                        end = oldText.getSpanEnd(chip) + 1;
+                                        oldText.removeSpan(chip);
+                                        // Make sure we always have just 1 space at the end to
+                                        // separate this chip from the next chip.
+                                        SpannableString displayText =
+                                                new SpannableString(createAddressText(
+                                                        replacement.getEntry()).trim()
+                                                        + " ");
+                                        displayText.setSpan(replacement, 0,
+                                                displayText.length() - 1,
+                                                Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+                                        // Replace the old text we found with with the new display
+                                        // text, which now may also contain the display name of the
+                                        // recipient.
+                                        oldText.replace(start, end, displayText);
+                                        replacement.setOriginalText(displayText.toString());
+                                        replacements.set(i, null);
+
+                                        recipients.set(i, replacement);
+                                    }
+                                }
+                            }
+                            i++;
+                        }
+                    }
+                };
+
+                if (Looper.myLooper() == Looper.getMainLooper()) {
+                    runnable.run();
+                } else {
+                    mHandler.post(runnable);
+                }
+            }
+        }
     }
 
-    private class IndividualReplacementTask extends AsyncTask<Object, Void, Void> {
-        @SuppressWarnings("unchecked")
+    private class IndividualReplacementTask
+            extends AsyncTask<ArrayList<RecipientChip>, Void, Void> {
         @Override
-        protected Void doInBackground(Object... params) {
+        protected Void doInBackground(ArrayList<RecipientChip>... params) {
             // For each chip in the list, look up the matching contact.
             // If there is a match, replace that chip with the matching
             // chip.
-            final ArrayList<RecipientChip> originalRecipients =
-                    (ArrayList<RecipientChip>) params[0];
+            final ArrayList<RecipientChip> originalRecipients = params[0];
             ArrayList<String> addresses = new ArrayList<String>();
             RecipientChip chip;
             for (int i = 0; i < originalRecipients.size(); i++) {
diff --git a/chips/src/com/android/ex/chips/VisibleRecipientChip.java b/chips/src/com/android/ex/chips/VisibleRecipientChip.java
index 257e3f4..49be32f 100644
--- a/chips/src/com/android/ex/chips/VisibleRecipientChip.java
+++ b/chips/src/com/android/ex/chips/VisibleRecipientChip.java
@@ -121,4 +121,9 @@
     public void draw(Canvas canvas) {
         getDrawable().draw(canvas);
     }
+
+    @Override
+    public String toString() {
+        return mDisplay + " <" + mValue + ">";
+    }
 }