Skip to content

Commit c9fd978

Browse files
author
Gilles Debunne
committed
Bug 5281947: add to dictionnary option promoted in suggestions.
When several SuggestionSpans are available at a given position, their content are merged, in creation time order. As a result, the IME's suggestions are picked before the spell check, and no add to dictionnary option is created. This CL modifies the comparator to make easy correction spans appear first (Voice IME), then misspelled words and then regular suggestions. Also avoids the creation of a new comparator and length hash map on every display. Change-Id: I1f9f031a6fdcbbc09f248a192b83051092765f8e
1 parent 5132273 commit c9fd978

File tree

4 files changed

+61
-72
lines changed

4 files changed

+61
-72
lines changed

core/java/android/text/TextLine.java

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -723,7 +723,7 @@ private float handleText(TextPaint wp, int start, int end,
723723
float ret = 0;
724724

725725
int contextLen = contextEnd - contextStart;
726-
if (needWidth || (c != null && (wp.bgColor != 0 || wp.underlineCount != 0 || runIsRtl))) {
726+
if (needWidth || (c != null && (wp.bgColor != 0 || wp.underlineColor != 0 || runIsRtl))) {
727727
int flags = runIsRtl ? Paint.DIRECTION_RTL : Paint.DIRECTION_LTR;
728728
if (mCharsValid) {
729729
ret = wp.getTextRunAdvances(mChars, start, runLen,
@@ -753,7 +753,7 @@ private float handleText(TextPaint wp, int start, int end,
753753
wp.setColor(previousColor);
754754
}
755755

756-
if (wp.underlineCount != 0) {
756+
if (wp.underlineColor != 0) {
757757
// kStdUnderline_Offset = 1/9, defined in SkTextFormatParams.h
758758
float underlineTop = y + wp.baselineShift + (1.0f / 9.0f) * wp.getTextSize();
759759

@@ -764,11 +764,8 @@ private float handleText(TextPaint wp, int start, int end,
764764
wp.setStyle(Paint.Style.FILL);
765765
wp.setAntiAlias(true);
766766

767-
for (int i = 0; i < wp.underlineCount; i++) {
768-
wp.setColor(wp.underlineColors[i]);
769-
c.drawRect(x, underlineTop, x + ret, underlineTop + wp.underlineThicknesses[i],
770-
wp);
771-
}
767+
wp.setColor(wp.underlineColor);
768+
c.drawRect(x, underlineTop, x + ret, underlineTop + wp.underlineThickness, wp);
772769

773770
wp.setStyle(previousStyle);
774771
wp.setColor(previousColor);

core/java/android/text/TextPaint.java

Lines changed: 6 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,6 @@
2424
*/
2525
public class TextPaint extends Paint {
2626

27-
private static final int DEFAULT_UNDERLINE_SIZE = 3;
28-
2927
// Special value 0 means no background paint
3028
public int bgColor;
3129
public int baselineShift;
@@ -36,17 +34,12 @@ public class TextPaint extends Paint {
3634
* Special value 0 means no custom underline
3735
* @hide
3836
*/
39-
public int[] underlineColors;
37+
public int underlineColor = 0;
4038
/**
4139
* Defined as a multiplier of the default underline thickness. Use 1.0f for default thickness.
4240
* @hide
4341
*/
44-
public float[] underlineThicknesses;
45-
/**
46-
* The number of underlines currently stored in the array. If 0, no underline is drawn.
47-
* @hide
48-
*/
49-
public int underlineCount;
42+
public float underlineThickness;
5043

5144
public TextPaint() {
5245
super();
@@ -72,16 +65,8 @@ public void set(TextPaint tp) {
7265
linkColor = tp.linkColor;
7366
drawableState = tp.drawableState;
7467
density = tp.density;
75-
76-
if (tp.underlineColors != null) {
77-
if (underlineColors == null || underlineColors.length < tp.underlineCount) {
78-
underlineColors = new int[tp.underlineCount];
79-
underlineThicknesses = new float[tp.underlineCount];
80-
}
81-
System.arraycopy(tp.underlineColors, 0, underlineColors, 0, tp.underlineCount);
82-
System.arraycopy(tp.underlineThicknesses, 0, underlineThicknesses, 0, tp.underlineCount);
83-
}
84-
underlineCount = tp.underlineCount;
68+
underlineColor = tp.underlineColor;
69+
underlineThickness = tp.underlineThickness;
8570
}
8671

8772
/**
@@ -91,31 +76,7 @@ public void set(TextPaint tp) {
9176
* @hide
9277
*/
9378
public void setUnderlineText(int color, float thickness) {
94-
if (color == 0) {
95-
// No underline
96-
return;
97-
}
98-
99-
if (underlineCount == 0) {
100-
underlineColors = new int[DEFAULT_UNDERLINE_SIZE];
101-
underlineThicknesses = new float[DEFAULT_UNDERLINE_SIZE];
102-
underlineColors[underlineCount] = color;
103-
underlineThicknesses[underlineCount] = thickness;
104-
underlineCount++;
105-
} else {
106-
if (underlineCount == underlineColors.length) {
107-
int[] newColors = new int[underlineColors.length + DEFAULT_UNDERLINE_SIZE];
108-
float[] newThickness = new float[underlineThicknesses.length
109-
+ DEFAULT_UNDERLINE_SIZE];
110-
System.arraycopy(underlineColors, 0, newColors, 0, underlineColors.length);
111-
System.arraycopy(
112-
underlineThicknesses, 0, newThickness, 0, underlineThicknesses.length);
113-
underlineColors = newColors;
114-
underlineThicknesses = newThickness;
115-
}
116-
underlineColors[underlineCount] = color;
117-
underlineThicknesses[underlineCount] = thickness;
118-
underlineCount++;
119-
}
79+
underlineColor = color;
80+
underlineThickness = thickness;
12081
}
12182
}

core/java/android/text/style/SuggestionSpan.java

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,8 @@ public SuggestionSpan(Locale locale, String[] suggestions, int flags) {
108108
/**
109109
* @param context Context for the application
110110
* @param locale locale Locale of the suggestions
111-
* @param suggestions Suggestions for the string under the span
111+
* @param suggestions Suggestions for the string under the span. Only the first up to
112+
* {@link SuggestionSpan#SUGGESTIONS_MAX_SIZE} will be considered.
112113
* @param flags Additional flags indicating how this span is handled in TextView
113114
* @param notificationTargetClass if not null, this class will get notified when the user
114115
* selects one of the suggestions.
@@ -258,10 +259,16 @@ public SuggestionSpan[] newArray(int size) {
258259

259260
@Override
260261
public void updateDrawState(TextPaint tp) {
261-
if ((mFlags & FLAG_MISSPELLED) != 0) {
262-
tp.setUnderlineText(mMisspelledUnderlineColor, mMisspelledUnderlineThickness);
263-
} else if ((mFlags & FLAG_EASY_CORRECT) != 0) {
264-
tp.setUnderlineText(mEasyCorrectUnderlineColor, mEasyCorrectUnderlineThickness);
262+
final boolean misspelled = (mFlags & FLAG_MISSPELLED) != 0;
263+
final boolean easy = (mFlags & FLAG_EASY_CORRECT) != 0;
264+
if (easy) {
265+
if (!misspelled) {
266+
tp.setUnderlineText(mEasyCorrectUnderlineColor, mEasyCorrectUnderlineThickness);
267+
} else if (tp.underlineColor == 0) {
268+
// Spans are rendered in an arbitrary order. Since misspelled is less prioritary
269+
// than just easy, do not apply misspelled if an easy (or a mispelled) has been set
270+
tp.setUnderlineText(mMisspelledUnderlineColor, mMisspelledUnderlineThickness);
271+
}
265272
}
266273
}
267274

@@ -272,8 +279,15 @@ public void updateDrawState(TextPaint tp) {
272279
*/
273280
public int getUnderlineColor() {
274281
// The order here should match what is used in updateDrawState
275-
if ((mFlags & FLAG_MISSPELLED) != 0) return mMisspelledUnderlineColor;
276-
if ((mFlags & FLAG_EASY_CORRECT) != 0) return mEasyCorrectUnderlineColor;
282+
final boolean misspelled = (mFlags & FLAG_MISSPELLED) != 0;
283+
final boolean easy = (mFlags & FLAG_EASY_CORRECT) != 0;
284+
if (easy) {
285+
if (!misspelled) {
286+
return mEasyCorrectUnderlineColor;
287+
} else {
288+
return mMisspelledUnderlineColor;
289+
}
290+
}
277291
return 0;
278292
}
279293
}

core/java/android/widget/TextView.java

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9547,6 +9547,9 @@ private class SuggestionsPopupWindow extends PinnedPopupWindow implements OnItem
95479547
private int mNumberOfSuggestions;
95489548
private boolean mCursorWasVisibleBeforeSuggestions;
95499549
private SuggestionAdapter mSuggestionsAdapter;
9550+
private final Comparator<SuggestionSpan> mSuggestionSpanComparator;
9551+
private final HashMap<SuggestionSpan, Integer> mSpansLengths;
9552+
95509553

95519554
private class CustomPopupWindow extends PopupWindow {
95529555
public CustomPopupWindow(Context context, int defStyle) {
@@ -9572,6 +9575,8 @@ public void dismiss() {
95729575

95739576
public SuggestionsPopupWindow() {
95749577
mCursorWasVisibleBeforeSuggestions = mCursorVisible;
9578+
mSuggestionSpanComparator = new SuggestionSpanComparator();
9579+
mSpansLengths = new HashMap<SuggestionSpan, Integer>();
95759580
}
95769581

95779582
@Override
@@ -9650,6 +9655,26 @@ public View getView(int position, View convertView, ViewGroup parent) {
96509655
}
96519656
}
96529657

9658+
private class SuggestionSpanComparator implements Comparator<SuggestionSpan> {
9659+
public int compare(SuggestionSpan span1, SuggestionSpan span2) {
9660+
final int flag1 = span1.getFlags();
9661+
final int flag2 = span2.getFlags();
9662+
if (flag1 != flag2) {
9663+
// The order here should match what is used in updateDrawState
9664+
final boolean easy1 = (flag1 & SuggestionSpan.FLAG_EASY_CORRECT) != 0;
9665+
final boolean easy2 = (flag2 & SuggestionSpan.FLAG_EASY_CORRECT) != 0;
9666+
final boolean misspelled1 = (flag1 & SuggestionSpan.FLAG_MISSPELLED) != 0;
9667+
final boolean misspelled2 = (flag2 & SuggestionSpan.FLAG_MISSPELLED) != 0;
9668+
if (easy1 && !misspelled1) return -1;
9669+
if (easy2 && !misspelled2) return 1;
9670+
if (misspelled1) return -1;
9671+
if (misspelled2) return 1;
9672+
}
9673+
9674+
return mSpansLengths.get(span1).intValue() - mSpansLengths.get(span2).intValue();
9675+
}
9676+
}
9677+
96539678
/**
96549679
* Returns the suggestion spans that cover the current cursor position. The suggestion
96559680
* spans are sorted according to the length of text that they are attached to.
@@ -9659,24 +9684,16 @@ private SuggestionSpan[] getSuggestionSpans() {
96599684
Spannable spannable = (Spannable) TextView.this.mText;
96609685
SuggestionSpan[] suggestionSpans = spannable.getSpans(pos, pos, SuggestionSpan.class);
96619686

9662-
// Cache the span length for performance reason.
9663-
final HashMap<SuggestionSpan, Integer> spansLengths =
9664-
new HashMap<SuggestionSpan, Integer>();
9665-
9687+
mSpansLengths.clear();
96669688
for (SuggestionSpan suggestionSpan : suggestionSpans) {
96679689
int start = spannable.getSpanStart(suggestionSpan);
96689690
int end = spannable.getSpanEnd(suggestionSpan);
9669-
spansLengths.put(suggestionSpan, Integer.valueOf(end - start));
9691+
mSpansLengths.put(suggestionSpan, Integer.valueOf(end - start));
96709692
}
96719693

9672-
// The suggestions are sorted according to the lenght of the text that they cover
9673-
// (shorter first)
9674-
Arrays.sort(suggestionSpans, new Comparator<SuggestionSpan>() {
9675-
public int compare(SuggestionSpan span1, SuggestionSpan span2) {
9676-
return spansLengths.get(span1).intValue() - spansLengths.get(span2).intValue();
9677-
}
9678-
});
9679-
9694+
// The suggestions are sorted according to their types (easy correction first, then
9695+
// misspelled) and to the length of the text that they cover (shorter first).
9696+
Arrays.sort(suggestionSpans, mSuggestionSpanComparator);
96809697
return suggestionSpans;
96819698
}
96829699

0 commit comments

Comments
 (0)