Manual merge from cupcake_dcm. Need to be reviewed by enf.
diff --git a/core/java/android/text/LoginFilter.java b/core/java/android/text/LoginFilter.java
index 27c703f..9045c09 100644
--- a/core/java/android/text/LoginFilter.java
+++ b/core/java/android/text/LoginFilter.java
@@ -49,10 +49,6 @@
      */
     public CharSequence filter(CharSequence source, int start, int end,
             Spanned dest, int dstart, int dend) {
-        char[] out = new char[end - start]; // reserve enough space for whole string
-        int outidx = 0;
-        boolean changed = false;
-        
         onStart();
         
         // Scan through beginning characters in dest, calling onInvalidCharacter() 
@@ -63,14 +59,26 @@
         }
 
         // Scan through changed characters rejecting disallowed chars
+        SpannableStringBuilder modification = null;
+        int modoff = 0;
+
         for (int i = start; i < end; i++) {
             char c = source.charAt(i);
             if (isAllowed(c)) {
-                // Character allowed. Add it to the sequence.
-                out[outidx++] = c;
+                // Character allowed.
+                modoff++;
             } else {
-                if (mAppendInvalid) out[outidx++] = c;
-                else changed = true; // we changed the original string
+                if (mAppendInvalid) {
+                    modoff++;
+                } else {
+                    if (modification == null) {
+                        modification = new SpannableStringBuilder(source, start, end);
+                        modoff = i - start;
+                    }
+
+                    modification.delete(modoff, modoff + 1);
+                }
+
                 onInvalidCharacter(c);
             }
         }
@@ -84,20 +92,9 @@
         
         onStop();
 
-        if (!changed) {
-            return null;
-        }
-        
-        String s = new String(out, 0, outidx);
-        
-        if (source instanceof Spanned) {
-            SpannableString sp = new SpannableString(s);
-            TextUtils.copySpansFrom((Spanned) source,
-                                    start, end, null, sp, 0);
-            return sp;
-        } else {
-            return s;
-        }
+        // Either returns null if we made no changes,
+        // or what we wanted to change it to if there were changes.
+        return modification;
     }
     
     /**
diff --git a/core/java/android/text/TextUtils.java b/core/java/android/text/TextUtils.java
index 5b4c380..53096dd 100644
--- a/core/java/android/text/TextUtils.java
+++ b/core/java/android/text/TextUtils.java
@@ -916,6 +916,17 @@
         sp.setSpan(o, p.readInt(), p.readInt(), p.readInt());
     }
 
+    /**
+     * Copies the spans from the region <code>start...end</code> in
+     * <code>source</code> to the region
+     * <code>destoff...destoff+end-start</code> in <code>dest</code>.
+     * Spans in <code>source</code> that begin before <code>start</code>
+     * or end after <code>end</code> but overlap this range are trimmed
+     * as if they began at <code>start</code> or ended at <code>end</code>.
+     *
+     * @throws IndexOutOfBoundsException if any of the copied spans
+     * are out of range in <code>dest</code>.
+     */
     public static void copySpansFrom(Spanned source, int start, int end,
                                      Class kind,
                                      Spannable dest, int destoff) {
diff --git a/core/java/android/widget/AutoCompleteTextView.java b/core/java/android/widget/AutoCompleteTextView.java
index a1d16ea..f376ce5 100644
--- a/core/java/android/widget/AutoCompleteTextView.java
+++ b/core/java/android/widget/AutoCompleteTextView.java
@@ -950,6 +950,8 @@
      * @param text the selected suggestion in the drop down list
      */
     protected void replaceText(CharSequence text) {
+        clearComposingText();
+
         setText(text);
         // make sure we keep the caret at the end of the text view
         Editable spannable = getText();
diff --git a/core/java/android/widget/MultiAutoCompleteTextView.java b/core/java/android/widget/MultiAutoCompleteTextView.java
index 05abc26..ae80277 100644
--- a/core/java/android/widget/MultiAutoCompleteTextView.java
+++ b/core/java/android/widget/MultiAutoCompleteTextView.java
@@ -195,6 +195,8 @@
      */
     @Override
     protected void replaceText(CharSequence text) {
+        clearComposingText();
+
         int end = getSelectionEnd();
         int start = mTokenizer.findTokenStart(getText(), end);