Merge "Add EditTextShortcutSpan to provide edit short cut in the text view."
This commit is contained in:
committed by
Android (Google) Code Review
commit
b5305007a6
@@ -20689,6 +20689,14 @@ package android.text.style {
|
||||
field protected final int mVerticalAlignment;
|
||||
}
|
||||
|
||||
public class EasyEditSpan implements android.text.ParcelableSpan {
|
||||
ctor public EasyEditSpan();
|
||||
ctor public EasyEditSpan(android.os.Parcel);
|
||||
method public int describeContents();
|
||||
method public int getSpanTypeId();
|
||||
method public void writeToParcel(android.os.Parcel, int);
|
||||
}
|
||||
|
||||
public class ForegroundColorSpan extends android.text.style.CharacterStyle implements android.text.ParcelableSpan android.text.style.UpdateAppearance {
|
||||
ctor public ForegroundColorSpan(int);
|
||||
ctor public ForegroundColorSpan(android.os.Parcel);
|
||||
|
||||
@@ -723,7 +723,7 @@ class TextLine {
|
||||
float ret = 0;
|
||||
|
||||
int contextLen = contextEnd - contextStart;
|
||||
if (needWidth || (c != null && (wp.bgColor != 0 || wp.underlineColor !=0 || runIsRtl))) {
|
||||
if (needWidth || (c != null && (wp.bgColor != 0 || wp.underlineCount != 0 || runIsRtl))) {
|
||||
int flags = runIsRtl ? Paint.DIRECTION_RTL : Paint.DIRECTION_LTR;
|
||||
if (mCharsValid) {
|
||||
ret = wp.getTextRunAdvances(mChars, start, runLen,
|
||||
@@ -753,21 +753,26 @@ class TextLine {
|
||||
wp.setColor(previousColor);
|
||||
}
|
||||
|
||||
if (wp.underlineColor != 0) {
|
||||
if (wp.underlineCount != 0) {
|
||||
// kStdUnderline_Offset = 1/9, defined in SkTextFormatParams.h
|
||||
float middle = y + wp.baselineShift + (1.0f / 9.0f) * wp.getTextSize();
|
||||
// kStdUnderline_Thickness = 1/18, defined in SkTextFormatParams.h
|
||||
float halfHeight = wp.underlineThickness * (1.0f / 18.0f / 2.0f) * wp.getTextSize();
|
||||
float underlineTop = y + wp.baselineShift + (1.0f / 9.0f) * wp.getTextSize();
|
||||
|
||||
int previousColor = wp.getColor();
|
||||
Paint.Style previousStyle = wp.getStyle();
|
||||
boolean previousAntiAlias = wp.isAntiAlias();
|
||||
|
||||
wp.setColor(wp.underlineColor);
|
||||
wp.setStyle(Paint.Style.FILL);
|
||||
c.drawRect(x, middle - halfHeight, x + ret, middle + halfHeight, wp);
|
||||
wp.setAntiAlias(true);
|
||||
|
||||
for (int i = 0; i < wp.underlineCount; i++) {
|
||||
wp.setColor(wp.underlineColors[i]);
|
||||
c.drawRect(x, underlineTop, x + ret, underlineTop + wp.underlineThicknesses[i],
|
||||
wp);
|
||||
}
|
||||
|
||||
wp.setStyle(previousStyle);
|
||||
wp.setColor(previousColor);
|
||||
wp.setAntiAlias(previousAntiAlias);
|
||||
}
|
||||
|
||||
drawTextRun(c, wp, start, end, contextStart, contextEnd, runIsRtl,
|
||||
|
||||
@@ -23,6 +23,9 @@ import android.graphics.Paint;
|
||||
* data used during text measuring and drawing.
|
||||
*/
|
||||
public class TextPaint extends Paint {
|
||||
|
||||
private static final int DEFAULT_UNDERLINE_SIZE = 3;
|
||||
|
||||
// Special value 0 means no background paint
|
||||
public int bgColor;
|
||||
public int baselineShift;
|
||||
@@ -33,12 +36,17 @@ public class TextPaint extends Paint {
|
||||
* Special value 0 means no custom underline
|
||||
* @hide
|
||||
*/
|
||||
public int underlineColor;
|
||||
public int[] underlineColors;
|
||||
/**
|
||||
* Defined as a multiplier of the default underline thickness. Use 1.0f for default thickness.
|
||||
* @hide
|
||||
*/
|
||||
public float underlineThickness;
|
||||
public float[] underlineThicknesses;
|
||||
/**
|
||||
* The number of underlines currently stored in the array. If 0, no underline is drawn.
|
||||
* @hide
|
||||
*/
|
||||
public int underlineCount;
|
||||
|
||||
public TextPaint() {
|
||||
super();
|
||||
@@ -64,24 +72,43 @@ public class TextPaint extends Paint {
|
||||
linkColor = tp.linkColor;
|
||||
drawableState = tp.drawableState;
|
||||
density = tp.density;
|
||||
underlineColor = tp.underlineColor;
|
||||
underlineThickness = tp.underlineThickness;
|
||||
underlineColors = tp.underlineColors;
|
||||
underlineThicknesses = tp.underlineThicknesses;
|
||||
underlineCount = tp.underlineCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines a custom underline for this Paint.
|
||||
* @param color underline solid color
|
||||
* @param thickness underline thickness, defined as a multiplier of the default underline
|
||||
* thickness.
|
||||
* @param thickness underline thickness
|
||||
* @hide
|
||||
*/
|
||||
public void setUnderlineText(boolean isUnderlined, int color, float thickness) {
|
||||
setUnderlineText(false);
|
||||
if (isUnderlined) {
|
||||
underlineColor = color;
|
||||
underlineThickness = thickness;
|
||||
public void setUnderlineText(int color, float thickness) {
|
||||
if (color == 0) {
|
||||
// No underline
|
||||
return;
|
||||
}
|
||||
|
||||
if (underlineCount == 0) {
|
||||
underlineColors = new int[DEFAULT_UNDERLINE_SIZE];
|
||||
underlineThicknesses = new float[DEFAULT_UNDERLINE_SIZE];
|
||||
underlineColors[underlineCount] = color;
|
||||
underlineThicknesses[underlineCount] = thickness;
|
||||
underlineCount++;
|
||||
} else {
|
||||
underlineColor = 0;
|
||||
if (underlineCount == underlineColors.length) {
|
||||
int[] newColors = new int[underlineColors.length + DEFAULT_UNDERLINE_SIZE];
|
||||
float[] newThickness = new float[underlineThicknesses.length
|
||||
+ DEFAULT_UNDERLINE_SIZE];
|
||||
System.arraycopy(underlineColors, 0, newColors, 0, underlineColors.length);
|
||||
System.arraycopy(
|
||||
underlineThicknesses, 0, newThickness, 0, underlineThicknesses.length);
|
||||
underlineColors = newColors;
|
||||
underlineThicknesses = newThickness;
|
||||
}
|
||||
underlineColors[underlineCount] = color;
|
||||
underlineThicknesses[underlineCount] = thickness;
|
||||
underlineCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ import android.text.style.BackgroundColorSpan;
|
||||
import android.text.style.BulletSpan;
|
||||
import android.text.style.CharacterStyle;
|
||||
import android.text.style.ForegroundColorSpan;
|
||||
import android.text.style.EasyEditSpan;
|
||||
import android.text.style.LeadingMarginSpan;
|
||||
import android.text.style.MetricAffectingSpan;
|
||||
import android.text.style.QuoteSpan;
|
||||
@@ -585,6 +586,8 @@ public class TextUtils {
|
||||
public static final int SPELL_CHECK_SPAN = 20;
|
||||
/** @hide */
|
||||
public static final int SUGGESTION_RANGE_SPAN = 21;
|
||||
/** @hide */
|
||||
public static final int EASY_EDIT_SPAN = 22;
|
||||
|
||||
/**
|
||||
* Flatten a CharSequence and whatever styles can be copied across processes
|
||||
@@ -748,6 +751,10 @@ public class TextUtils {
|
||||
readSpan(p, sp, new SuggestionRangeSpan());
|
||||
break;
|
||||
|
||||
case EASY_EDIT_SPAN:
|
||||
readSpan(p, sp, new EasyEditSpan(p));
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new RuntimeException("bogus span encoding " + kind);
|
||||
}
|
||||
|
||||
54
core/java/android/text/style/EasyEditSpan.java
Normal file
54
core/java/android/text/style/EasyEditSpan.java
Normal file
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.text.style;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.text.ParcelableSpan;
|
||||
import android.text.TextUtils;
|
||||
import android.widget.TextView;
|
||||
|
||||
/**
|
||||
* Provides an easy way to edit a portion of text.
|
||||
* <p>
|
||||
* The {@link TextView} uses this span to allow the user to delete a chuck of text in one click.
|
||||
* the text. {@link TextView} removes this span as soon as the text is edited, or the cursor moves.
|
||||
*/
|
||||
public class EasyEditSpan implements ParcelableSpan {
|
||||
|
||||
public EasyEditSpan() {
|
||||
// Empty
|
||||
}
|
||||
|
||||
public EasyEditSpan(Parcel src) {
|
||||
this();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
// Empty
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSpanTypeId() {
|
||||
return TextUtils.EASY_EDIT_SPAN;
|
||||
}
|
||||
}
|
||||
@@ -61,12 +61,6 @@ public class SuggestionSpan extends CharacterStyle implements ParcelableSpan {
|
||||
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;
|
||||
|
||||
/*
|
||||
@@ -82,10 +76,8 @@ public class SuggestionSpan extends CharacterStyle implements ParcelableSpan {
|
||||
private final String mNotificationTargetClassName;
|
||||
private final int mHashCode;
|
||||
|
||||
private float mMisspelledUnderlineThickness;
|
||||
private int mMisspelledUnderlineColor;
|
||||
private float mEasyCorrectUnderlineThickness;
|
||||
private int mEasyCorrectUnderlineColor;
|
||||
private float mUnderlineThickness;
|
||||
private int mUnderlineColor;
|
||||
|
||||
/*
|
||||
* TODO: If switching IME is required, needs to add parameters for ids of InputMethodInfo
|
||||
@@ -140,31 +132,26 @@ public class SuggestionSpan extends CharacterStyle implements ParcelableSpan {
|
||||
}
|
||||
|
||||
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;
|
||||
int defStyle = 0;
|
||||
if ((getFlags() & FLAG_MISSPELLED) != 0) {
|
||||
defStyle = com.android.internal.R.attr.textAppearanceMisspelledSuggestion;
|
||||
} else if ((getFlags() & FLAG_EASY_CORRECT) != 0) {
|
||||
defStyle = com.android.internal.R.attr.textAppearanceEasyCorrectSuggestion;
|
||||
} else {
|
||||
// No style is applied.
|
||||
mUnderlineThickness = 0;
|
||||
mUnderlineColor = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
typedArray = context.obtainStyledAttributes(null,
|
||||
TypedArray typedArray = context.obtainStyledAttributes(null,
|
||||
com.android.internal.R.styleable.SuggestionSpan,
|
||||
com.android.internal.R.attr.textAppearanceEasyCorrectSuggestion, 0);
|
||||
defStyle, 0);
|
||||
|
||||
mEasyCorrectUnderlineThickness = getThicknessPercentage(typedArray,
|
||||
com.android.internal.R.styleable.SuggestionSpan_textUnderlineThicknessPercentage);
|
||||
mEasyCorrectUnderlineColor = typedArray.getColor(
|
||||
mUnderlineThickness = typedArray.getDimension(
|
||||
com.android.internal.R.styleable.SuggestionSpan_textUnderlineThickness, 0);
|
||||
mUnderlineColor = 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) {
|
||||
@@ -173,10 +160,8 @@ public class SuggestionSpan extends CharacterStyle implements ParcelableSpan {
|
||||
mLocaleString = src.readString();
|
||||
mNotificationTargetClassName = src.readString();
|
||||
mHashCode = src.readInt();
|
||||
mEasyCorrectUnderlineColor = src.readInt();
|
||||
mEasyCorrectUnderlineThickness = src.readFloat();
|
||||
mMisspelledUnderlineColor = src.readInt();
|
||||
mMisspelledUnderlineThickness = src.readFloat();
|
||||
mUnderlineColor = src.readInt();
|
||||
mUnderlineThickness = src.readFloat();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -226,10 +211,8 @@ public class SuggestionSpan extends CharacterStyle implements ParcelableSpan {
|
||||
dest.writeString(mLocaleString);
|
||||
dest.writeString(mNotificationTargetClassName);
|
||||
dest.writeInt(mHashCode);
|
||||
dest.writeInt(mEasyCorrectUnderlineColor);
|
||||
dest.writeFloat(mEasyCorrectUnderlineThickness);
|
||||
dest.writeInt(mMisspelledUnderlineColor);
|
||||
dest.writeFloat(mMisspelledUnderlineThickness);
|
||||
dest.writeInt(mUnderlineColor);
|
||||
dest.writeFloat(mUnderlineThickness);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -271,10 +254,6 @@ public class SuggestionSpan extends CharacterStyle implements ParcelableSpan {
|
||||
|
||||
@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);
|
||||
}
|
||||
tp.setUnderlineText(mUnderlineColor, mUnderlineThickness);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,7 +81,9 @@ import android.text.method.TimeKeyListener;
|
||||
import android.text.method.TransformationMethod;
|
||||
import android.text.method.TransformationMethod2;
|
||||
import android.text.method.WordIterator;
|
||||
import android.text.style.CharacterStyle;
|
||||
import android.text.style.ClickableSpan;
|
||||
import android.text.style.EasyEditSpan;
|
||||
import android.text.style.ParagraphStyle;
|
||||
import android.text.style.SpellCheckSpan;
|
||||
import android.text.style.SuggestionRangeSpan;
|
||||
@@ -7705,10 +7707,148 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Controls the {@link EasyEditSpan} monitoring when it is added, and when the related
|
||||
* pop-up should be displayed.
|
||||
*/
|
||||
private class EditTextShortcutController {
|
||||
|
||||
private EditTextShortcutPopupWindow mPopupWindow;
|
||||
|
||||
private EasyEditSpan mEditTextShortcutSpan;
|
||||
|
||||
private void hide() {
|
||||
if (mEditTextShortcutSpan != null) {
|
||||
mPopupWindow.hide();
|
||||
if (mText instanceof Spannable) {
|
||||
((Spannable) mText).removeSpan(mEditTextShortcutSpan);
|
||||
}
|
||||
mEditTextShortcutSpan = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Monitors the changes in the text.
|
||||
*
|
||||
* <p>{@link ChangeWatcher#onSpanAdded(Spannable, Object, int, int)} cannot be used,
|
||||
* as the notifications are not sent when a spannable (with spans) is inserted.
|
||||
*/
|
||||
public void onTextChange(CharSequence buffer) {
|
||||
if (mEditTextShortcutSpan != null) {
|
||||
hide();
|
||||
}
|
||||
|
||||
if (buffer instanceof Spanned) {
|
||||
mEditTextShortcutSpan = getSpan((Spanned) buffer);
|
||||
if (mEditTextShortcutSpan != null) {
|
||||
if (mPopupWindow == null) {
|
||||
mPopupWindow = new EditTextShortcutPopupWindow();
|
||||
}
|
||||
mPopupWindow.show(mEditTextShortcutSpan);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private EasyEditSpan getSpan(Spanned spanned) {
|
||||
EasyEditSpan[] inputMethodSpans = spanned.getSpans(0, spanned.length(),
|
||||
EasyEditSpan.class);
|
||||
|
||||
if (inputMethodSpans.length == 0) {
|
||||
return null;
|
||||
} else {
|
||||
return inputMethodSpans[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the actions associated to an {@link EasyEditSpan}. The pop-up is controlled
|
||||
* by {@link EditTextShortcutController}.
|
||||
*/
|
||||
private class EditTextShortcutPopupWindow extends PinnedPopupWindow
|
||||
implements OnClickListener {
|
||||
private static final int POPUP_TEXT_LAYOUT =
|
||||
com.android.internal.R.layout.text_edit_action_popup_text;
|
||||
private TextView mDeleteTextView;
|
||||
private EasyEditSpan mEditTextShortcutSpan;
|
||||
|
||||
@Override
|
||||
protected void createPopupWindow() {
|
||||
mPopupWindow = new PopupWindow(TextView.this.mContext, null,
|
||||
com.android.internal.R.attr.textSelectHandleWindowStyle);
|
||||
mPopupWindow.setInputMethodMode(PopupWindow.INPUT_METHOD_NOT_NEEDED);
|
||||
mPopupWindow.setClippingEnabled(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initContentView() {
|
||||
mContentView.setOrientation(LinearLayout.HORIZONTAL);
|
||||
mContentView.setBackgroundResource(
|
||||
com.android.internal.R.drawable.text_edit_side_paste_window);
|
||||
|
||||
LayoutInflater inflater = (LayoutInflater)TextView.this.mContext.
|
||||
getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
|
||||
LayoutParams wrapContent = new LayoutParams(
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
|
||||
mDeleteTextView = (TextView) inflater.inflate(POPUP_TEXT_LAYOUT, null);
|
||||
mDeleteTextView.setLayoutParams(wrapContent);
|
||||
mDeleteTextView.setText(com.android.internal.R.string.delete);
|
||||
mDeleteTextView.setOnClickListener(this);
|
||||
mContentView.addView(mDeleteTextView);
|
||||
}
|
||||
|
||||
public void show(EasyEditSpan inputMethodSpan) {
|
||||
mEditTextShortcutSpan = inputMethodSpan;
|
||||
super.show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
if (view == mDeleteTextView) {
|
||||
deleteText();
|
||||
}
|
||||
}
|
||||
|
||||
private void deleteText() {
|
||||
Editable editable = (Editable) mText;
|
||||
int start = editable.getSpanStart(mEditTextShortcutSpan);
|
||||
int end = editable.getSpanEnd(mEditTextShortcutSpan);
|
||||
if (start >= 0 && end >= 0) {
|
||||
editable.delete(start, end);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getTextOffset() {
|
||||
// Place the pop-up at the end of the span
|
||||
Editable editable = (Editable) mText;
|
||||
return editable.getSpanEnd(mEditTextShortcutSpan);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getVerticalLocalPosition(int line) {
|
||||
return mLayout.getLineBottom(line);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int clipVertically(int positionY) {
|
||||
// As we display the pop-up below the span, no vertical clipping is required.
|
||||
return positionY;
|
||||
}
|
||||
}
|
||||
|
||||
private class ChangeWatcher implements TextWatcher, SpanWatcher {
|
||||
|
||||
private CharSequence mBeforeText;
|
||||
|
||||
private EditTextShortcutController mEditTextShortcutController;
|
||||
|
||||
private ChangeWatcher() {
|
||||
mEditTextShortcutController = new EditTextShortcutController();
|
||||
}
|
||||
|
||||
public void beforeTextChanged(CharSequence buffer, int start,
|
||||
int before, int after) {
|
||||
if (DEBUG_EXTRACT) Log.v(LOG_TAG, "beforeTextChanged start=" + start
|
||||
@@ -7729,6 +7869,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
||||
+ " before=" + before + " after=" + after + ": " + buffer);
|
||||
TextView.this.handleTextChanged(buffer, start, before, after);
|
||||
|
||||
mEditTextShortcutController.onTextChange(buffer);
|
||||
|
||||
if (AccessibilityManager.getInstance(mContext).isEnabled() &&
|
||||
(isFocused() || isSelected() && isShown())) {
|
||||
sendAccessibilityEventTypeViewTextChanged(mBeforeText, start, before, after);
|
||||
@@ -7763,6 +7905,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
||||
+ " what=" + what + ": " + buf);
|
||||
TextView.this.spanChange(buf, what, s, -1, e, -1);
|
||||
}
|
||||
|
||||
private void hideControllers() {
|
||||
mEditTextShortcutController.hide();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -9184,6 +9330,34 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
||||
}
|
||||
}
|
||||
|
||||
private static class SuggestionRangeSpan extends CharacterStyle {
|
||||
|
||||
private final int mTextColor;
|
||||
private final int mBackgroundColor;
|
||||
|
||||
public SuggestionRangeSpan(Context context) {
|
||||
TypedArray typedArray = context.obtainStyledAttributes(null,
|
||||
com.android.internal.R.styleable.SuggestionRangeSpan,
|
||||
com.android.internal.R.attr.textAppearanceSuggestionRange, 0);
|
||||
|
||||
mTextColor = typedArray.getColor(
|
||||
com.android.internal.R.styleable.SuggestionRangeSpan_textColor, 0);
|
||||
mBackgroundColor = typedArray.getColor(
|
||||
com.android.internal.R.styleable.SuggestionRangeSpan_colorBackground, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateDrawState(TextPaint tp) {
|
||||
if (mTextColor != 0) {
|
||||
tp.setColor(mTextColor);
|
||||
}
|
||||
|
||||
if (mBackgroundColor != 0) {
|
||||
tp.bgColor = mBackgroundColor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class SuggestionsPopupWindow extends PinnedPopupWindow implements OnClickListener {
|
||||
private static final int MAX_NUMBER_SUGGESTIONS = SuggestionSpan.SUGGESTIONS_MAX_SIZE;
|
||||
private static final int NO_SUGGESTIONS = -1;
|
||||
@@ -9368,7 +9542,15 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
||||
|
||||
if (totalNbSuggestions == 0) return false;
|
||||
|
||||
if (mSuggestionRangeSpan == null) mSuggestionRangeSpan = new SuggestionRangeSpan();
|
||||
if (mSuggestionRangeSpan == null) {
|
||||
mSuggestionRangeSpan = new SuggestionRangeSpan(getContext());
|
||||
}
|
||||
|
||||
((Editable) mText).setSpan(mSuggestionRangeSpan, spanUnionStart, spanUnionEnd,
|
||||
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
|
||||
if (mSuggestionRangeSpan == null) mSuggestionRangeSpan =
|
||||
new SuggestionRangeSpan(getContext());
|
||||
((Editable) mText).setSpan(mSuggestionRangeSpan, spanUnionStart, spanUnionEnd,
|
||||
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
|
||||
@@ -10695,6 +10877,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
||||
private void hideControllers() {
|
||||
hideInsertionPointCursorController();
|
||||
stopSelectionActionMode();
|
||||
|
||||
if (mChangeWatcher != null) {
|
||||
mChangeWatcher.hideControllers();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -158,11 +158,14 @@
|
||||
<!-- The underline color and thickness for misspelled suggestion -->
|
||||
<attr name="textAppearanceMisspelledSuggestion" format="reference" />
|
||||
|
||||
<!-- The text color and the background for suggestion range span. This span identifies the
|
||||
portion of text the suggestions refer to). -->
|
||||
<attr name="textAppearanceSuggestionRange" 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" />
|
||||
<!-- The underline thickness -->
|
||||
<attr name="textUnderlineThickness" format="reference|dimension" />
|
||||
|
||||
<!-- EditText text foreground color. -->
|
||||
<attr name="editTextColor" format="reference|color" />
|
||||
@@ -3149,7 +3152,11 @@
|
||||
</declare-styleable>
|
||||
<declare-styleable name="SuggestionSpan">
|
||||
<attr name="textUnderlineColor" />
|
||||
<attr name="textUnderlineThicknessPercentage" />
|
||||
<attr name="textUnderlineThickness" />
|
||||
</declare-styleable>
|
||||
<declare-styleable name="SuggestionRangeSpan">
|
||||
<attr name="textColor" />
|
||||
<attr name="colorBackground" />
|
||||
</declare-styleable>
|
||||
<!-- An <code>input-extras</code> is a container for extra data to supply to
|
||||
an input method. Contains
|
||||
|
||||
@@ -2472,6 +2472,9 @@
|
||||
<!-- Item on EditText context menu. This action is used to replace the current word by other suggested words, suggested by the IME or the spell checker -->
|
||||
<string name="replace">Replace\u2026</string>
|
||||
|
||||
<!-- Item on EditText pop-up window. This action is used to delete the text that the user recently added. [CHAR LIMIT=15] -->
|
||||
<string name="delete">Delete</string>
|
||||
|
||||
<!-- Item on EditText context menu. This action is used to copy a URL from the edit field into the clipboard. -->
|
||||
<string name="copyUrl">Copy URL</string>
|
||||
|
||||
|
||||
@@ -244,7 +244,7 @@ please see styles_device_defaults.xml.
|
||||
</style>
|
||||
|
||||
<style name="TextAppearance.Suggestion">
|
||||
<item name="android:textUnderlineThicknessPercentage">200</item>
|
||||
<item name="android:textUnderlineThickness">2dip</item>
|
||||
</style>
|
||||
|
||||
<style name="TextAppearance.EasyCorrectSuggestion" parent="TextAppearance.Suggestion">
|
||||
@@ -255,6 +255,11 @@ please see styles_device_defaults.xml.
|
||||
<item name="android:textUnderlineColor">@color/holo_red_light</item>
|
||||
</style>
|
||||
|
||||
<style name="TextAppearance.SuggestionRange">
|
||||
<item name="android:textColor">@color/white</item>
|
||||
<item name="android:colorBackground">@color/holo_blue_dark</item>
|
||||
</style>
|
||||
|
||||
<!-- Widget Styles -->
|
||||
|
||||
<style name="Widget">
|
||||
|
||||
@@ -91,6 +91,7 @@ please see themes_device_defaults.xml.
|
||||
|
||||
<item name="textAppearanceEasyCorrectSuggestion">@android:style/TextAppearance.EasyCorrectSuggestion</item>
|
||||
<item name="textAppearanceMisspelledSuggestion">@android:style/TextAppearance.MisspelledSuggestion</item>
|
||||
<item name="textAppearanceSuggestionRange">@android:style/TextAppearance.SuggestionRange</item>
|
||||
|
||||
<item name="textAppearanceButton">@android:style/TextAppearance.Widget.Button</item>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user