Merge "Change the behavior of SuggestionSpan."
diff --git a/api/current.txt b/api/current.txt
index 68c830f..1e3d40e 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -20730,7 +20730,7 @@
     method public void writeToParcel(android.os.Parcel, int);
   }
 
-  public class SuggestionSpan implements android.text.ParcelableSpan {
+  public class SuggestionSpan extends android.text.style.CharacterStyle implements android.text.ParcelableSpan {
     ctor public SuggestionSpan(android.content.Context, java.lang.String[], int);
     ctor public SuggestionSpan(java.util.Locale, java.lang.String[], int);
     ctor public SuggestionSpan(android.content.Context, java.util.Locale, java.lang.String[], int, java.lang.Class<?>);
@@ -20740,10 +20740,12 @@
     method public java.lang.String getLocale();
     method public int getSpanTypeId();
     method public java.lang.String[] getSuggestions();
+    method public void updateDrawState(android.text.TextPaint);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final java.lang.String ACTION_SUGGESTION_PICKED = "android.text.style.SUGGESTION_PICKED";
     field public static final android.os.Parcelable.Creator CREATOR;
-    field public static final int FLAG_VERBATIM = 1; // 0x1
+    field public static final int FLAG_EASY_CORRECT = 1; // 0x1
+    field public static final int FLAG_MISSPELLED = 2; // 0x2
     field public static final int SUGGESTIONS_MAX_SIZE = 5; // 0x5
     field public static final java.lang.String SUGGESTION_SPAN_PICKED_AFTER = "after";
     field public static final java.lang.String SUGGESTION_SPAN_PICKED_BEFORE = "before";
diff --git a/core/java/android/text/style/SuggestionSpan.java b/core/java/android/text/style/SuggestionSpan.java
index 555aac5..fb94bc7 100644
--- a/core/java/android/text/style/SuggestionSpan.java
+++ b/core/java/android/text/style/SuggestionSpan.java
@@ -17,10 +17,13 @@
 package android.text.style;
 
 import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Color;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.SystemClock;
 import android.text.ParcelableSpan;
+import android.text.TextPaint;
 import android.text.TextUtils;
 import android.widget.TextView;
 
@@ -34,23 +37,36 @@
  * display a popup dialog listing suggestion replacement for that text. The user can then replace
  * the original text by one of the suggestions.
  *
- * These spans should typically be created by the input method to privide correction and alternates
+ * These spans should typically be created by the input method to provide correction and alternates
  * for the text.
  *
  * @see TextView#setSuggestionsEnabled(boolean)
  */
-public class SuggestionSpan implements ParcelableSpan {
+public class SuggestionSpan extends CharacterStyle implements ParcelableSpan {
+
     /**
-     * Flag for indicating that the input is verbatim. TextView refers to this flag to determine
-     * how it displays a word with SuggestionSpan.
+     * Sets this flag if the suggestions should be easily accessible with few interactions.
+     * This flag should be set for every suggestions that the user is likely to use.
      */
-    public static final int FLAG_VERBATIM = 0x0001;
+    public static final int FLAG_EASY_CORRECT = 0x0001;
+
+    /**
+     * Sets this flag if the suggestions apply to a misspelled word/text. This type of suggestion is
+     * rendered differently to highlight the error.
+     */
+    public static final int FLAG_MISSPELLED = 0x0002;
 
     public static final String ACTION_SUGGESTION_PICKED = "android.text.style.SUGGESTION_PICKED";
     public static final String SUGGESTION_SPAN_PICKED_AFTER = "after";
     public static final String SUGGESTION_SPAN_PICKED_BEFORE = "before";
     public static final String SUGGESTION_SPAN_PICKED_HASHCODE = "hashcode";
 
+    /**
+     * The default underline thickness as a percentage of the system's default underline thickness
+     * (i.e., 100 means the default thickness, and 200 is a double thickness).
+     */
+    private static final int DEFAULT_UNDERLINE_PERCENTAGE = 100;
+
     public static final int SUGGESTIONS_MAX_SIZE = 5;
 
     /*
@@ -66,6 +82,11 @@
     private final String mNotificationTargetClassName;
     private final int mHashCode;
 
+    private float mMisspelledUnderlineThickness;
+    private int mMisspelledUnderlineColor;
+    private float mEasyCorrectUnderlineThickness;
+    private int mEasyCorrectUnderlineColor;
+
     /*
      * TODO: If switching IME is required, needs to add parameters for ids of InputMethodInfo
      * and InputMethodSubtype.
@@ -107,6 +128,7 @@
         } else {
             mLocaleString = locale.toString();
         }
+
         if (notificationTargetClass != null) {
             mNotificationTargetClassName = notificationTargetClass.getCanonicalName();
         } else {
@@ -114,6 +136,36 @@
         }
         mHashCode = hashCodeInternal(
                 mFlags, mSuggestions, mLocaleString, mNotificationTargetClassName);
+
+        initStyle(context);
+    }
+
+    private void initStyle(Context context) {
+        // Read the colors. We need to store the color and the underline thickness, as the span
+        // does not have access to the context when it is read from a parcel.
+        TypedArray typedArray;
+
+        typedArray = context.obtainStyledAttributes(null,
+                com.android.internal.R.styleable.SuggestionSpan,
+                com.android.internal.R.attr.textAppearanceEasyCorrectSuggestion, 0);
+
+        mEasyCorrectUnderlineThickness = getThicknessPercentage(typedArray,
+                com.android.internal.R.styleable.SuggestionSpan_textUnderlineThicknessPercentage);
+        mEasyCorrectUnderlineColor = typedArray.getColor(
+                com.android.internal.R.styleable.SuggestionSpan_textUnderlineColor, Color.BLACK);
+
+        typedArray = context.obtainStyledAttributes(null,
+                com.android.internal.R.styleable.SuggestionSpan,
+                com.android.internal.R.attr.textAppearanceMisspelledSuggestion, 0);
+        mMisspelledUnderlineThickness = getThicknessPercentage(typedArray,
+                com.android.internal.R.styleable.SuggestionSpan_textUnderlineThicknessPercentage);
+        mMisspelledUnderlineColor = typedArray.getColor(
+                com.android.internal.R.styleable.SuggestionSpan_textUnderlineColor, Color.BLACK);
+    }
+
+    private static float getThicknessPercentage(TypedArray typedArray, int index) {
+        int value  = typedArray.getInteger(index, DEFAULT_UNDERLINE_PERCENTAGE);
+        return value / 100.0f;
     }
 
     public SuggestionSpan(Parcel src) {
@@ -122,6 +174,10 @@
         mLocaleString = src.readString();
         mNotificationTargetClassName = src.readString();
         mHashCode = src.readInt();
+        mEasyCorrectUnderlineColor = src.readInt();
+        mEasyCorrectUnderlineThickness = src.readFloat();
+        mMisspelledUnderlineColor = src.readInt();
+        mMisspelledUnderlineThickness = src.readFloat();
     }
 
     /**
@@ -167,6 +223,10 @@
         dest.writeString(mLocaleString);
         dest.writeString(mNotificationTargetClassName);
         dest.writeInt(mHashCode);
+        dest.writeInt(mEasyCorrectUnderlineColor);
+        dest.writeFloat(mEasyCorrectUnderlineThickness);
+        dest.writeInt(mMisspelledUnderlineColor);
+        dest.writeFloat(mMisspelledUnderlineThickness);
     }
 
     @Override
@@ -205,4 +265,13 @@
             return new SuggestionSpan[size];
         }
     };
+
+    @Override
+    public void updateDrawState(TextPaint tp) {
+        if ((getFlags() & FLAG_MISSPELLED) != 0) {
+            tp.setUnderlineText(true, mMisspelledUnderlineColor, mMisspelledUnderlineThickness);
+        } else if ((getFlags() & FLAG_EASY_CORRECT) != 0) {
+            tp.setUnderlineText(true, mEasyCorrectUnderlineColor, mEasyCorrectUnderlineThickness);
+        }
+    }
 }
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index d1a5196..d6cb61d 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -139,11 +139,6 @@
 
 import org.xmlpull.v1.XmlPullParserException;
 
-import com.android.internal.util.FastMath;
-import com.android.internal.widget.EditableInputConnection;
-
-import org.xmlpull.v1.XmlPullParserException;
-
 import java.io.IOException;
 import java.lang.ref.WeakReference;
 import java.text.BreakIterator;
@@ -7966,8 +7961,12 @@
                     startSelectionActionMode();
                 } else {
                     hideControllers();
-                    if (hasInsertionController() && !selectAllGotFocus && mText.length() > 0) {
-                        getInsertionController().show();
+                    if (!selectAllGotFocus && mText.length() > 0) {
+                        if (isCursorInsideEasyCorrectionSpan()) {
+                            showSuggestions();
+                        } else if (hasInsertionController()) {
+                            getInsertionController().show();
+                        }
                     }
                 }
             }
@@ -7980,6 +7979,22 @@
         return superResult;
     }
 
+    /**
+     * @return <code>true</code> if the cursor is inside an {@link SuggestionSpan} with
+     * {@link SuggestionSpan#FLAG_EASY_CORRECT} set.
+     */
+    private boolean isCursorInsideEasyCorrectionSpan() {
+        Spannable spannable = (Spannable) TextView.this.mText;
+        SuggestionSpan[] suggestionSpans = spannable.getSpans(getSelectionStart(),
+                getSelectionEnd(), SuggestionSpan.class);
+        for (int i = 0; i < suggestionSpans.length; i++) {
+            if ((suggestionSpans[i].getFlags() & SuggestionSpan.FLAG_EASY_CORRECT) != 0) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     @Override
     public boolean onGenericMotionEvent(MotionEvent event) {
         if (mMovement != null && mText instanceof Spannable && mLayout != null) {
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index f63eb62..40355e3 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -152,6 +152,18 @@
         <!-- Text color, typeface, size, and style for small text inside of a popup menu. -->
         <attr name="textAppearanceSmallPopupMenu" format="reference" />
 
+        <!-- The underline color and thickness for easy correct suggestion -->
+        <attr name="textAppearanceEasyCorrectSuggestion" format="reference" />
+
+        <!-- The underline color and thickness for misspelled suggestion -->
+        <attr name="textAppearanceMisspelledSuggestion" format="reference" />
+
+        <!--  The underline color -->
+        <attr name="textUnderlineColor" format="reference|color" />
+        <!--  The underline thickness, expressed as a percentage of the default underline thickness
+              (i.e., 100 means default thickness, and 200 means double thickness). -->
+        <attr name="textUnderlineThicknessPercentage" format="reference|integer" />
+
         <!-- EditText text foreground color. -->
         <attr name="editTextColor" format="reference|color" />
         <!-- EditText background drawable. -->
@@ -3136,6 +3148,10 @@
         <!-- Present the text in ALL CAPS. This may use a small-caps form when available. -->
         <attr name="textAllCaps" />
     </declare-styleable>
+    <declare-styleable name="SuggestionSpan">
+        <attr name="textUnderlineColor" />
+        <attr name="textUnderlineThicknessPercentage" />
+    </declare-styleable>
     <!-- An <code>input-extras</code> is a container for extra data to supply to
          an input method.  Contains
          one more more {@link #Extra <extra>} tags.  -->
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index d54eddf..6f2f1e5 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -243,6 +243,18 @@
         <item name="android:textStyle">bold</item>
     </style>
 
+    <style name="TextAppearance.Suggestion">
+        <item name="android:textUnderlineThicknessPercentage">200</item>
+    </style>
+
+    <style name="TextAppearance.EasyCorrectSuggestion" parent="TextAppearance.Suggestion">
+        <item name="android:textUnderlineColor">@color/holo_blue_dark</item>
+    </style>
+
+    <style name="TextAppearance.MisspelledSuggestion" parent="TextAppearance.Suggestion">
+        <item name="android:textUnderlineColor">@color/holo_red_light</item>
+    </style>
+
     <!-- Widget Styles -->
 
     <style name="Widget">
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index 397278c..6278c82 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -88,7 +88,10 @@
         <item name="textAppearanceSmallInverse">@android:style/TextAppearance.Small.Inverse</item>
         <item name="textAppearanceSearchResultTitle">@android:style/TextAppearance.SearchResult.Title</item>
         <item name="textAppearanceSearchResultSubtitle">@android:style/TextAppearance.SearchResult.Subtitle</item>
-        
+
+        <item name="textAppearanceEasyCorrectSuggestion">@android:style/TextAppearance.EasyCorrectSuggestion</item>
+        <item name="textAppearanceMisspelledSuggestion">@android:style/TextAppearance.MisspelledSuggestion</item>
+
         <item name="textAppearanceButton">@android:style/TextAppearance.Widget.Button</item>
         
         <item name="editTextColor">?android:attr/textColorPrimaryInverse</item>