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>