OSDN Git Service

Add equals() and hashcode() to SpannableString
authorChet Haase <chet@google.com>
Wed, 18 Sep 2013 22:12:35 +0000 (15:12 -0700)
committerChet Haase <chet@google.com>
Fri, 20 Sep 2013 00:18:55 +0000 (17:18 -0700)
ActionBar uses a transition to animate text changes. This transition
depends on testing the equality of start/end text values in CharSequence
objects. Without equals(), SpannableString will return false for objects
whose references are different, but whose text is exactly the same.

This CL adds the equals() method, and the accompanying hashcode method,
to ensure that two Spanned implementations will always be equal
if their text and span data are equal.

Issue #10760075 Wrong unread count in actionbar

Change-Id: I5e77d40dd302eca035e8c56d40f3cd0aef8e6424

core/java/android/text/SpannableStringBuilder.java
core/java/android/text/SpannableStringInternal.java
core/java/android/transition/TextChange.java

index 8929930..6efde05 100644 (file)
@@ -1288,6 +1288,47 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable
         return mFilters;
     }
 
+    // Same as SpannableStringInternal
+    @Override
+    public boolean equals(Object o) {
+        if (o instanceof Spanned &&
+                toString().equals(o.toString())) {
+            // Check span data
+            Object[] otherSpans = ((Spanned) o).getSpans(0,
+                    ((Spanned) o).length(), Object.class);
+            if (mSpanCount == otherSpans.length) {
+                for (int i = 0; i < mSpanCount; ++i) {
+                    Object thisSpan = mSpans[i];
+                    Object otherSpan = otherSpans[i];
+                    if (!thisSpan.equals(otherSpan) ||
+                            getSpanStart(thisSpan) != getSpanStart(otherSpan) ||
+                            getSpanEnd(thisSpan) != getSpanEnd(otherSpan) ||
+                            getSpanFlags(thisSpan) != getSpanFlags(otherSpan)) {
+                        return false;
+                    }
+                }
+                return true;
+            }
+
+        }
+        return false;
+    }
+
+    // Same as SpannableStringInternal
+    @Override
+    public int hashCode() {
+        int hash = toString().hashCode();
+        hash = hash * 31 + mSpanCount;
+        for (int i = 0; i < mSpanCount; ++i) {
+            Object span = mSpans[i];
+            hash = hash * 31 + span.hashCode();
+            hash = hash * 31 + getSpanStart(span);
+            hash = hash * 31 + getSpanEnd(span);
+            hash = hash * 31 + getSpanFlags(span);
+        }
+        return hash;
+    }
+
     private static final InputFilter[] NO_FILTERS = new InputFilter[0];
     private InputFilter[] mFilters = NO_FILTERS;
 
index 0825bf3..9b24a2e 100644 (file)
@@ -358,6 +358,47 @@ import java.lang.reflect.Array;
         }
     }
 
+    // Same as SpannableStringBuilder
+    @Override
+    public boolean equals(Object o) {
+        if (o instanceof Spanned &&
+                toString().equals(o.toString())) {
+            // Check span data
+            Object[] otherSpans = ((Spanned) o).getSpans(0,
+                    ((Spanned) o).length(), Object.class);
+            if (mSpanCount == otherSpans.length) {
+                for (int i = 0; i < mSpanCount; ++i) {
+                    Object thisSpan = mSpans[i];
+                    Object otherSpan = otherSpans[i];
+                    if (!thisSpan.equals(otherSpan) ||
+                            getSpanStart(thisSpan) != getSpanStart(otherSpan) ||
+                            getSpanEnd(thisSpan) != getSpanEnd(otherSpan) ||
+                            getSpanFlags(thisSpan) != getSpanFlags(otherSpan)) {
+                        return false;
+                    }
+                }
+                return true;
+            }
+
+        }
+        return false;
+    }
+
+    // Same as SpannableStringBuilder
+    @Override
+    public int hashCode() {
+        int hash = toString().hashCode();
+        hash = hash * 31 + mSpanCount;
+        for (int i = 0; i < mSpanCount; ++i) {
+            Object span = mSpans[i];
+            hash = hash * 31 + span.hashCode();
+            hash = hash * 31 + getSpanStart(span);
+            hash = hash * 31 + getSpanEnd(span);
+            hash = hash * 31 + getSpanFlags(span);
+        }
+        return hash;
+    }
+
     private String mText;
     private Object[] mSpans;
     private int[] mSpanData;
index 0b1e4e1..fa2f548 100644 (file)
@@ -21,6 +21,7 @@ import android.animation.AnimatorListenerAdapter;
 import android.animation.AnimatorSet;
 import android.animation.ValueAnimator;
 import android.graphics.Color;
+import android.util.Log;
 import android.view.ViewGroup;
 import android.widget.TextView;
 
@@ -36,6 +37,9 @@ import java.util.Map;
  * @hide
  */
 public class TextChange extends Transition {
+
+    private static final String LOG_TAG = "TextChange";
+
     private static final String PROPNAME_TEXT = "android:textchange:text";
     private static final String PROPNAME_TEXT_COLOR = "android:textchange:textColor";
 
@@ -224,6 +228,9 @@ public class TextChange extends Transition {
                 }
             };
             addListener(transitionListener);
+            if (DBG) {
+                Log.d(LOG_TAG, "createAnimator returning " + anim);
+            }
             return anim;
         }
         return null;