Merge "Using ListView for Suggestion popup window"
@@ -20702,7 +20702,6 @@ package android.text.style {
|
|||||||
|
|
||||||
public class EasyEditSpan implements android.text.ParcelableSpan {
|
public class EasyEditSpan implements android.text.ParcelableSpan {
|
||||||
ctor public EasyEditSpan();
|
ctor public EasyEditSpan();
|
||||||
ctor public EasyEditSpan(android.os.Parcel);
|
|
||||||
method public int describeContents();
|
method public int describeContents();
|
||||||
method public int getSpanTypeId();
|
method public int getSpanTypeId();
|
||||||
method public void writeToParcel(android.os.Parcel, int);
|
method public void writeToParcel(android.os.Parcel, int);
|
||||||
|
|||||||
@@ -24,8 +24,8 @@ import android.text.style.AlignmentSpan;
|
|||||||
import android.text.style.BackgroundColorSpan;
|
import android.text.style.BackgroundColorSpan;
|
||||||
import android.text.style.BulletSpan;
|
import android.text.style.BulletSpan;
|
||||||
import android.text.style.CharacterStyle;
|
import android.text.style.CharacterStyle;
|
||||||
import android.text.style.ForegroundColorSpan;
|
|
||||||
import android.text.style.EasyEditSpan;
|
import android.text.style.EasyEditSpan;
|
||||||
|
import android.text.style.ForegroundColorSpan;
|
||||||
import android.text.style.LeadingMarginSpan;
|
import android.text.style.LeadingMarginSpan;
|
||||||
import android.text.style.MetricAffectingSpan;
|
import android.text.style.MetricAffectingSpan;
|
||||||
import android.text.style.QuoteSpan;
|
import android.text.style.QuoteSpan;
|
||||||
@@ -748,11 +748,11 @@ public class TextUtils {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case SUGGESTION_RANGE_SPAN:
|
case SUGGESTION_RANGE_SPAN:
|
||||||
readSpan(p, sp, new SuggestionRangeSpan());
|
readSpan(p, sp, new SuggestionRangeSpan(p));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EASY_EDIT_SPAN:
|
case EASY_EDIT_SPAN:
|
||||||
readSpan(p, sp, new EasyEditSpan(p));
|
readSpan(p, sp, new EasyEditSpan());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -33,10 +33,6 @@ public class EasyEditSpan implements ParcelableSpan {
|
|||||||
// Empty
|
// Empty
|
||||||
}
|
}
|
||||||
|
|
||||||
public EasyEditSpan(Parcel src) {
|
|
||||||
this();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int describeContents() {
|
public int describeContents() {
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -16,7 +16,6 @@
|
|||||||
|
|
||||||
package android.text.style;
|
package android.text.style;
|
||||||
|
|
||||||
import android.graphics.Color;
|
|
||||||
import android.os.Parcel;
|
import android.os.Parcel;
|
||||||
import android.text.ParcelableSpan;
|
import android.text.ParcelableSpan;
|
||||||
import android.text.TextPaint;
|
import android.text.TextPaint;
|
||||||
@@ -29,12 +28,20 @@ import android.text.TextUtils;
|
|||||||
* @hide
|
* @hide
|
||||||
*/
|
*/
|
||||||
public class SuggestionRangeSpan extends CharacterStyle implements ParcelableSpan {
|
public class SuggestionRangeSpan extends CharacterStyle implements ParcelableSpan {
|
||||||
|
private final int mBackgroundColor;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateDrawState(TextPaint tp) {
|
public void updateDrawState(TextPaint tp) {
|
||||||
tp.setColor(Color.GREEN);
|
tp.bgColor = mBackgroundColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SuggestionRangeSpan() { /* Nothing to do*/ }
|
public SuggestionRangeSpan(int color) {
|
||||||
|
mBackgroundColor = color;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SuggestionRangeSpan(Parcel src) {
|
||||||
|
mBackgroundColor = src.readInt();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int describeContents() {
|
public int describeContents() {
|
||||||
@@ -42,7 +49,9 @@ public class SuggestionRangeSpan extends CharacterStyle implements ParcelableSpa
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void writeToParcel(Parcel dest, int flags) { /* Nothing to do*/ }
|
public void writeToParcel(Parcel dest, int flags) {
|
||||||
|
dest.writeInt(mBackgroundColor);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getSpanTypeId() {
|
public int getSpanTypeId() {
|
||||||
|
|||||||
@@ -1,4 +1,18 @@
|
|||||||
// Copyright 2011 Google Inc. All Rights Reserved.
|
/*
|
||||||
|
* 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.widget;
|
package android.widget;
|
||||||
|
|
||||||
@@ -32,7 +46,7 @@ public class SpellChecker implements SpellCheckerSessionListener {
|
|||||||
|
|
||||||
private final TextView mTextView;
|
private final TextView mTextView;
|
||||||
|
|
||||||
final SpellCheckerSession spellCheckerSession;
|
final SpellCheckerSession mSpellCheckerSession;
|
||||||
final int mCookie;
|
final int mCookie;
|
||||||
|
|
||||||
// Paired arrays for the (id, spellCheckSpan) pair. mIndex is the next available position
|
// Paired arrays for the (id, spellCheckSpan) pair. mIndex is the next available position
|
||||||
@@ -49,7 +63,7 @@ public class SpellChecker implements SpellCheckerSessionListener {
|
|||||||
|
|
||||||
final TextServicesManager textServicesManager = (TextServicesManager) textView.getContext().
|
final TextServicesManager textServicesManager = (TextServicesManager) textView.getContext().
|
||||||
getSystemService(Context.TEXT_SERVICES_MANAGER_SERVICE);
|
getSystemService(Context.TEXT_SERVICES_MANAGER_SERVICE);
|
||||||
spellCheckerSession = textServicesManager.newSpellCheckerSession(
|
mSpellCheckerSession = textServicesManager.newSpellCheckerSession(
|
||||||
null /* not currently used by the textServicesManager */, Locale.getDefault(),
|
null /* not currently used by the textServicesManager */, Locale.getDefault(),
|
||||||
this, true /* means use the languages defined in Settings */);
|
this, true /* means use the languages defined in Settings */);
|
||||||
mCookie = hashCode();
|
mCookie = hashCode();
|
||||||
@@ -112,7 +126,7 @@ public class SpellChecker implements SpellCheckerSessionListener {
|
|||||||
|
|
||||||
private void scheduleSpellCheck() {
|
private void scheduleSpellCheck() {
|
||||||
if (mLength == 0) return;
|
if (mLength == 0) return;
|
||||||
if (spellCheckerSession == null) return;
|
if (mSpellCheckerSession == null) return;
|
||||||
|
|
||||||
if (mChecker != null) {
|
if (mChecker != null) {
|
||||||
mTextView.removeCallbacks(mChecker);
|
mTextView.removeCallbacks(mChecker);
|
||||||
@@ -157,7 +171,7 @@ public class SpellChecker implements SpellCheckerSessionListener {
|
|||||||
System.arraycopy(textInfos, 0, textInfosCopy, 0, textInfosCount);
|
System.arraycopy(textInfos, 0, textInfosCopy, 0, textInfosCount);
|
||||||
textInfos = textInfosCopy;
|
textInfos = textInfosCopy;
|
||||||
}
|
}
|
||||||
spellCheckerSession.getSuggestions(textInfos, SuggestionSpan.SUGGESTIONS_MAX_SIZE,
|
mSpellCheckerSession.getSuggestions(textInfos, SuggestionSpan.SUGGESTIONS_MAX_SIZE,
|
||||||
false /* TODO Set sequentialWords to true for initial spell check */);
|
false /* TODO Set sequentialWords to true for initial spell check */);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -63,8 +63,8 @@ import android.text.TextDirectionHeuristic;
|
|||||||
import android.text.TextDirectionHeuristics;
|
import android.text.TextDirectionHeuristics;
|
||||||
import android.text.TextPaint;
|
import android.text.TextPaint;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.text.TextWatcher;
|
|
||||||
import android.text.TextUtils.TruncateAt;
|
import android.text.TextUtils.TruncateAt;
|
||||||
|
import android.text.TextWatcher;
|
||||||
import android.text.method.AllCapsTransformationMethod;
|
import android.text.method.AllCapsTransformationMethod;
|
||||||
import android.text.method.ArrowKeyMovementMethod;
|
import android.text.method.ArrowKeyMovementMethod;
|
||||||
import android.text.method.DateKeyListener;
|
import android.text.method.DateKeyListener;
|
||||||
@@ -82,7 +82,6 @@ import android.text.method.TimeKeyListener;
|
|||||||
import android.text.method.TransformationMethod;
|
import android.text.method.TransformationMethod;
|
||||||
import android.text.method.TransformationMethod2;
|
import android.text.method.TransformationMethod2;
|
||||||
import android.text.method.WordIterator;
|
import android.text.method.WordIterator;
|
||||||
import android.text.style.CharacterStyle;
|
|
||||||
import android.text.style.ClickableSpan;
|
import android.text.style.ClickableSpan;
|
||||||
import android.text.style.EasyEditSpan;
|
import android.text.style.EasyEditSpan;
|
||||||
import android.text.style.ParagraphStyle;
|
import android.text.style.ParagraphStyle;
|
||||||
@@ -131,6 +130,7 @@ import android.view.inputmethod.ExtractedText;
|
|||||||
import android.view.inputmethod.ExtractedTextRequest;
|
import android.view.inputmethod.ExtractedTextRequest;
|
||||||
import android.view.inputmethod.InputConnection;
|
import android.view.inputmethod.InputConnection;
|
||||||
import android.view.inputmethod.InputMethodManager;
|
import android.view.inputmethod.InputMethodManager;
|
||||||
|
import android.widget.AdapterView.OnItemClickListener;
|
||||||
import android.widget.RemoteViews.RemoteView;
|
import android.widget.RemoteViews.RemoteView;
|
||||||
|
|
||||||
import com.android.internal.util.FastMath;
|
import com.android.internal.util.FastMath;
|
||||||
@@ -7868,7 +7868,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void initContentView() {
|
protected void initContentView() {
|
||||||
mContentView.setOrientation(LinearLayout.HORIZONTAL);
|
LinearLayout linearLayout = new LinearLayout(TextView.this.getContext());
|
||||||
|
linearLayout.setOrientation(LinearLayout.HORIZONTAL);
|
||||||
|
mContentView = linearLayout;
|
||||||
mContentView.setBackgroundResource(
|
mContentView.setBackgroundResource(
|
||||||
com.android.internal.R.drawable.text_edit_side_paste_window);
|
com.android.internal.R.drawable.text_edit_side_paste_window);
|
||||||
|
|
||||||
@@ -8177,17 +8179,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
|||||||
startStopMarquee(hasWindowFocus);
|
startStopMarquee(hasWindowFocus);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void removeSpans(int start, int end, Class<?> type) {
|
|
||||||
if (mText instanceof Editable) {
|
|
||||||
Editable editable = ((Editable) mText);
|
|
||||||
Object[] spans = editable.getSpans(start, end, type);
|
|
||||||
final int length = spans.length;
|
|
||||||
for (int i = 0; i < length; i++) {
|
|
||||||
editable.removeSpan(spans[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onVisibilityChanged(View changedView, int visibility) {
|
protected void onVisibilityChanged(View changedView, int visibility) {
|
||||||
super.onVisibilityChanged(changedView, visibility);
|
super.onVisibilityChanged(changedView, visibility);
|
||||||
@@ -9326,7 +9317,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
|||||||
|
|
||||||
private abstract class PinnedPopupWindow implements TextViewPositionListener {
|
private abstract class PinnedPopupWindow implements TextViewPositionListener {
|
||||||
protected PopupWindow mPopupWindow;
|
protected PopupWindow mPopupWindow;
|
||||||
protected LinearLayout mContentView;
|
protected ViewGroup mContentView;
|
||||||
int mPositionX, mPositionY;
|
int mPositionX, mPositionY;
|
||||||
|
|
||||||
protected abstract void createPopupWindow();
|
protected abstract void createPopupWindow();
|
||||||
@@ -9342,23 +9333,16 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
|||||||
mPopupWindow.setWidth(ViewGroup.LayoutParams.WRAP_CONTENT);
|
mPopupWindow.setWidth(ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||||
mPopupWindow.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT);
|
mPopupWindow.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||||
|
|
||||||
mContentView = new LinearLayout(TextView.this.getContext());
|
initContentView();
|
||||||
LayoutParams wrapContent = new LayoutParams(
|
|
||||||
ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
LayoutParams wrapContent = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
|
||||||
|
ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||||
mContentView.setLayoutParams(wrapContent);
|
mContentView.setLayoutParams(wrapContent);
|
||||||
|
|
||||||
initContentView();
|
|
||||||
mPopupWindow.setContentView(mContentView);
|
mPopupWindow.setContentView(mContentView);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void show() {
|
public void show() {
|
||||||
final DisplayMetrics displayMetrics = mContext.getResources().getDisplayMetrics();
|
|
||||||
mContentView.measure(
|
|
||||||
View.MeasureSpec.makeMeasureSpec(displayMetrics.widthPixels,
|
|
||||||
View.MeasureSpec.AT_MOST),
|
|
||||||
View.MeasureSpec.makeMeasureSpec(displayMetrics.heightPixels,
|
|
||||||
View.MeasureSpec.AT_MOST));
|
|
||||||
|
|
||||||
TextView.this.getPositionListener().addSubscriber(this, false);
|
TextView.this.getPositionListener().addSubscriber(this, false);
|
||||||
|
|
||||||
computeLocalPosition();
|
computeLocalPosition();
|
||||||
@@ -9366,11 +9350,24 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
|||||||
final PositionListener positionListener = TextView.this.getPositionListener();
|
final PositionListener positionListener = TextView.this.getPositionListener();
|
||||||
updatePosition(positionListener.getPositionX(), positionListener.getPositionY());
|
updatePosition(positionListener.getPositionX(), positionListener.getPositionY());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void measureContent() {
|
||||||
|
final DisplayMetrics displayMetrics = mContext.getResources().getDisplayMetrics();
|
||||||
|
mContentView.measure(
|
||||||
|
View.MeasureSpec.makeMeasureSpec(displayMetrics.widthPixels,
|
||||||
|
View.MeasureSpec.AT_MOST),
|
||||||
|
View.MeasureSpec.makeMeasureSpec(displayMetrics.heightPixels,
|
||||||
|
View.MeasureSpec.AT_MOST));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The popup window will be horizontally centered on the getTextOffset() and vertically
|
||||||
|
* positioned according to viewportToContentHorizontalOffset.
|
||||||
|
*
|
||||||
|
* This method assumes that mContentView has properly been measured from its content. */
|
||||||
private void computeLocalPosition() {
|
private void computeLocalPosition() {
|
||||||
final int offset = getTextOffset();
|
measureContent();
|
||||||
|
|
||||||
final int width = mContentView.getMeasuredWidth();
|
final int width = mContentView.getMeasuredWidth();
|
||||||
|
final int offset = getTextOffset();
|
||||||
mPositionX = (int) (mLayout.getPrimaryHorizontal(offset) - width / 2.0f);
|
mPositionX = (int) (mLayout.getPrimaryHorizontal(offset) - width / 2.0f);
|
||||||
mPositionX += viewportToContentHorizontalOffset();
|
mPositionX += viewportToContentHorizontalOffset();
|
||||||
|
|
||||||
@@ -9418,42 +9415,17 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class SuggestionRangeSpan extends CharacterStyle {
|
private class SuggestionsPopupWindow extends PinnedPopupWindow implements OnItemClickListener {
|
||||||
|
|
||||||
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 MAX_NUMBER_SUGGESTIONS = SuggestionSpan.SUGGESTIONS_MAX_SIZE;
|
||||||
private static final int NO_SUGGESTIONS = -1;
|
private static final int NO_SUGGESTIONS = -1;
|
||||||
private static final float AVERAGE_HIGHLIGHTS_PER_SUGGESTION = 1.4f;
|
private static final float AVERAGE_HIGHLIGHTS_PER_SUGGESTION = 1.4f;
|
||||||
private WordIterator mSuggestionWordIterator;
|
private WordIterator mSuggestionWordIterator;
|
||||||
private TextAppearanceSpan[] mHighlightSpans = new TextAppearanceSpan
|
private TextAppearanceSpan[] mHighlightSpans = new TextAppearanceSpan
|
||||||
[(int) (AVERAGE_HIGHLIGHTS_PER_SUGGESTION * MAX_NUMBER_SUGGESTIONS)];
|
[(int) (AVERAGE_HIGHLIGHTS_PER_SUGGESTION * MAX_NUMBER_SUGGESTIONS)];
|
||||||
|
private SuggestionInfo[] mSuggestionInfos;
|
||||||
|
private int mNumberOfSuggestions;
|
||||||
private boolean mCursorWasVisibleBeforeSuggestions;
|
private boolean mCursorWasVisibleBeforeSuggestions;
|
||||||
|
private SuggestionAdapter mSuggestionsAdapter;
|
||||||
|
|
||||||
private class CustomPopupWindow extends PopupWindow {
|
private class CustomPopupWindow extends PopupWindow {
|
||||||
public CustomPopupWindow(Context context, int defStyle) {
|
public CustomPopupWindow(Context context, int defStyle) {
|
||||||
@@ -9494,29 +9466,16 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void initContentView() {
|
protected void initContentView() {
|
||||||
mContentView.setOrientation(LinearLayout.VERTICAL);
|
ListView listView = new ListView(TextView.this.getContext());
|
||||||
|
mSuggestionsAdapter = new SuggestionAdapter();
|
||||||
LayoutInflater inflater = (LayoutInflater) TextView.this.mContext.
|
listView.setAdapter(mSuggestionsAdapter);
|
||||||
getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
listView.setOnItemClickListener(this);
|
||||||
|
mContentView = listView;
|
||||||
if (inflater == null) {
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
"Unable to create inflater for TextEdit suggestions");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Inflate the suggestion items once and for all.
|
// Inflate the suggestion items once and for all.
|
||||||
|
mSuggestionInfos = new SuggestionInfo[MAX_NUMBER_SUGGESTIONS];
|
||||||
for (int i = 0; i < MAX_NUMBER_SUGGESTIONS; i++) {
|
for (int i = 0; i < MAX_NUMBER_SUGGESTIONS; i++) {
|
||||||
View childView = inflater.inflate(mTextEditSuggestionItemLayout,
|
mSuggestionInfos[i] = new SuggestionInfo();
|
||||||
mContentView, false);
|
|
||||||
|
|
||||||
if (! (childView instanceof TextView)) {
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
"Inflated TextEdit suggestion item is not a TextView: " + childView);
|
|
||||||
}
|
|
||||||
|
|
||||||
childView.setTag(new SuggestionInfo());
|
|
||||||
mContentView.addView(childView);
|
|
||||||
childView.setOnClickListener(this);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -9525,6 +9484,40 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
|||||||
int spanStart, spanEnd; // range in TextView where text should be inserted
|
int spanStart, spanEnd; // range in TextView where text should be inserted
|
||||||
SuggestionSpan suggestionSpan; // the SuggestionSpan that this TextView represents
|
SuggestionSpan suggestionSpan; // the SuggestionSpan that this TextView represents
|
||||||
int suggestionIndex; // the index of the suggestion inside suggestionSpan
|
int suggestionIndex; // the index of the suggestion inside suggestionSpan
|
||||||
|
SpannableStringBuilder text = new SpannableStringBuilder();
|
||||||
|
}
|
||||||
|
|
||||||
|
private class SuggestionAdapter extends BaseAdapter {
|
||||||
|
private LayoutInflater mInflater = (LayoutInflater) TextView.this.mContext.
|
||||||
|
getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getCount() {
|
||||||
|
return mNumberOfSuggestions;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getItem(int position) {
|
||||||
|
return mSuggestionInfos[position];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getItemId(int position) {
|
||||||
|
return position;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View getView(int position, View convertView, ViewGroup parent) {
|
||||||
|
TextView textView = (TextView) convertView;
|
||||||
|
|
||||||
|
if (textView == null) {
|
||||||
|
textView = (TextView) mInflater.inflate(mTextEditSuggestionItemLayout, parent,
|
||||||
|
false);
|
||||||
|
}
|
||||||
|
|
||||||
|
textView.setText(mSuggestionInfos[position].text);
|
||||||
|
return textView;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -9568,6 +9561,36 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void measureContent() {
|
||||||
|
final DisplayMetrics displayMetrics = mContext.getResources().getDisplayMetrics();
|
||||||
|
final int horizontalMeasure = View.MeasureSpec.makeMeasureSpec(
|
||||||
|
displayMetrics.widthPixels, View.MeasureSpec.AT_MOST);
|
||||||
|
final int verticalMeasure = View.MeasureSpec.makeMeasureSpec(
|
||||||
|
displayMetrics.heightPixels, View.MeasureSpec.AT_MOST);
|
||||||
|
|
||||||
|
int width = 0;
|
||||||
|
View view = null;
|
||||||
|
for (int i = 0; i < mNumberOfSuggestions; i++) {
|
||||||
|
view = mSuggestionsAdapter.getView(i, view, mContentView);
|
||||||
|
view.measure(horizontalMeasure, verticalMeasure);
|
||||||
|
width = Math.max(width, view.getMeasuredWidth());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enforce the width based on actual text widths
|
||||||
|
mContentView.measure(
|
||||||
|
View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY),
|
||||||
|
verticalMeasure);
|
||||||
|
|
||||||
|
Drawable popupBackground = mPopupWindow.getBackground();
|
||||||
|
if (popupBackground != null) {
|
||||||
|
if (mTempRect == null) mTempRect = new Rect();
|
||||||
|
popupBackground.getPadding(mTempRect);
|
||||||
|
width += mTempRect.left + mTempRect.right;
|
||||||
|
}
|
||||||
|
mPopupWindow.setWidth(width);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected int getTextOffset() {
|
protected int getTextOffset() {
|
||||||
return getSelectionStart();
|
return getSelectionStart();
|
||||||
@@ -9596,7 +9619,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
|||||||
|
|
||||||
final int nbSpans = suggestionSpans.length;
|
final int nbSpans = suggestionSpans.length;
|
||||||
|
|
||||||
int totalNbSuggestions = 0;
|
mNumberOfSuggestions = 0;
|
||||||
int spanUnionStart = mText.length();
|
int spanUnionStart = mText.length();
|
||||||
int spanUnionEnd = 0;
|
int spanUnionEnd = 0;
|
||||||
|
|
||||||
@@ -9610,17 +9633,15 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
|||||||
String[] suggestions = suggestionSpan.getSuggestions();
|
String[] suggestions = suggestionSpan.getSuggestions();
|
||||||
int nbSuggestions = suggestions.length;
|
int nbSuggestions = suggestions.length;
|
||||||
for (int suggestionIndex = 0; suggestionIndex < nbSuggestions; suggestionIndex++) {
|
for (int suggestionIndex = 0; suggestionIndex < nbSuggestions; suggestionIndex++) {
|
||||||
TextView textView = (TextView) mContentView.getChildAt(
|
SuggestionInfo suggestionInfo = mSuggestionInfos[mNumberOfSuggestions];
|
||||||
totalNbSuggestions);
|
|
||||||
textView.setText(suggestions[suggestionIndex]);
|
|
||||||
SuggestionInfo suggestionInfo = (SuggestionInfo) textView.getTag();
|
|
||||||
suggestionInfo.spanStart = spanStart;
|
suggestionInfo.spanStart = spanStart;
|
||||||
suggestionInfo.spanEnd = spanEnd;
|
suggestionInfo.spanEnd = spanEnd;
|
||||||
suggestionInfo.suggestionSpan = suggestionSpan;
|
suggestionInfo.suggestionSpan = suggestionSpan;
|
||||||
suggestionInfo.suggestionIndex = suggestionIndex;
|
suggestionInfo.suggestionIndex = suggestionIndex;
|
||||||
|
suggestionInfo.text = new SpannableStringBuilder(suggestions[suggestionIndex]);
|
||||||
|
|
||||||
totalNbSuggestions++;
|
mNumberOfSuggestions++;
|
||||||
if (totalNbSuggestions == MAX_NUMBER_SUGGESTIONS) {
|
if (mNumberOfSuggestions == MAX_NUMBER_SUGGESTIONS) {
|
||||||
// Also end outer for loop
|
// Also end outer for loop
|
||||||
spanIndex = nbSpans;
|
spanIndex = nbSpans;
|
||||||
break;
|
break;
|
||||||
@@ -9628,31 +9649,18 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (totalNbSuggestions == 0) return false;
|
if (mNumberOfSuggestions == 0) return false;
|
||||||
|
|
||||||
if (mSuggestionRangeSpan == null) {
|
if (mSuggestionRangeSpan == null) mSuggestionRangeSpan =
|
||||||
mSuggestionRangeSpan = new SuggestionRangeSpan(getContext());
|
new SuggestionRangeSpan(mHighlightColor);
|
||||||
}
|
|
||||||
|
|
||||||
((Editable) mText).setSpan(mSuggestionRangeSpan, spanUnionStart, spanUnionEnd,
|
|
||||||
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
|
||||||
|
|
||||||
if (mSuggestionRangeSpan == null) mSuggestionRangeSpan =
|
|
||||||
new SuggestionRangeSpan(getContext());
|
|
||||||
((Editable) mText).setSpan(mSuggestionRangeSpan, spanUnionStart, spanUnionEnd,
|
((Editable) mText).setSpan(mSuggestionRangeSpan, spanUnionStart, spanUnionEnd,
|
||||||
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||||
|
|
||||||
for (int i = 0; i < totalNbSuggestions; i++) {
|
for (int i = 0; i < mNumberOfSuggestions; i++) {
|
||||||
final TextView textView = (TextView) mContentView.getChildAt(i);
|
highlightTextDifferences(mSuggestionInfos[i], spanUnionStart, spanUnionEnd);
|
||||||
highlightTextDifferences(textView, spanUnionStart, spanUnionEnd);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < totalNbSuggestions; i++) {
|
|
||||||
mContentView.getChildAt(i).setVisibility(VISIBLE);
|
|
||||||
}
|
|
||||||
for (int i = totalNbSuggestions; i < MAX_NUMBER_SUGGESTIONS; i++) {
|
|
||||||
mContentView.getChildAt(i).setVisibility(GONE);
|
|
||||||
}
|
}
|
||||||
|
mSuggestionsAdapter.notifyDataSetChanged();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -9719,13 +9727,13 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
|||||||
return highlightSpan;
|
return highlightSpan;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void highlightTextDifferences(TextView textView, int unionStart, int unionEnd) {
|
private void highlightTextDifferences(SuggestionInfo suggestionInfo,
|
||||||
SuggestionInfo suggestionInfo = (SuggestionInfo) textView.getTag();
|
int unionStart, int unionEnd) {
|
||||||
final int spanStart = suggestionInfo.spanStart;
|
final int spanStart = suggestionInfo.spanStart;
|
||||||
final int spanEnd = suggestionInfo.spanEnd;
|
final int spanEnd = suggestionInfo.spanEnd;
|
||||||
|
|
||||||
// Remove all text formating by converting to Strings
|
// Remove all text formating by converting to Strings
|
||||||
final String text = textView.getText().toString();
|
final String text = suggestionInfo.text.toString();
|
||||||
final String sourceText = mText.subSequence(spanStart, spanEnd).toString();
|
final String sourceText = mText.subSequence(spanStart, spanEnd).toString();
|
||||||
|
|
||||||
long[] sourceWordLimits = getWordLimits(sourceText);
|
long[] sourceWordLimits = getWordLimits(sourceText);
|
||||||
@@ -9800,7 +9808,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
|||||||
if (previousCommonWordIndex < words.length - 1) {
|
if (previousCommonWordIndex < words.length - 1) {
|
||||||
int firstDifferentPosition = previousCommonWordIndex < 0 ? 0 :
|
int firstDifferentPosition = previousCommonWordIndex < 0 ? 0 :
|
||||||
extractRangeEndFromLong(wordLimits[previousCommonWordIndex]);
|
extractRangeEndFromLong(wordLimits[previousCommonWordIndex]);
|
||||||
int lastDifferentPosition = textView.length();
|
int lastDifferentPosition = text.length();
|
||||||
ssb.setSpan(highlightSpan(nbHighlightSpans++),
|
ssb.setSpan(highlightSpan(nbHighlightSpans++),
|
||||||
shift + firstDifferentPosition, shift + lastDifferentPosition,
|
shift + firstDifferentPosition, shift + lastDifferentPosition,
|
||||||
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||||
@@ -9811,25 +9819,24 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
|||||||
|
|
||||||
int lastCommonTextWordEnd = previousCommonWordIndex < 0 ? 0 :
|
int lastCommonTextWordEnd = previousCommonWordIndex < 0 ? 0 :
|
||||||
extractRangeEndFromLong(wordLimits[previousCommonWordIndex]);
|
extractRangeEndFromLong(wordLimits[previousCommonWordIndex]);
|
||||||
String textSpaces = text.substring(lastCommonTextWordEnd, textView.length());
|
String textSpaces = text.substring(lastCommonTextWordEnd, text.length());
|
||||||
|
|
||||||
if (!sourceSpaces.equals(textSpaces) && textSpaces.length() > 0) {
|
if (!sourceSpaces.equals(textSpaces) && textSpaces.length() > 0) {
|
||||||
ssb.setSpan(highlightSpan(nbHighlightSpans++),
|
ssb.setSpan(highlightSpan(nbHighlightSpans++),
|
||||||
shift + lastCommonTextWordEnd, shift + textView.length(),
|
shift + lastCommonTextWordEnd, shift + text.length(),
|
||||||
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Final part, text after the current suggestion range.
|
// Final part, text after the current suggestion range.
|
||||||
ssb.append(mText.subSequence(spanEnd, unionEnd).toString());
|
ssb.append(mText.subSequence(spanEnd, unionEnd).toString());
|
||||||
textView.setText(ssb);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View view) {
|
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
||||||
if (view instanceof TextView) {
|
if (view instanceof TextView) {
|
||||||
TextView textView = (TextView) view;
|
TextView textView = (TextView) view;
|
||||||
SuggestionInfo suggestionInfo = (SuggestionInfo) textView.getTag();
|
SuggestionInfo suggestionInfo = mSuggestionInfos[position];
|
||||||
final int spanStart = suggestionInfo.spanStart;
|
final int spanStart = suggestionInfo.spanStart;
|
||||||
final int spanEnd = suggestionInfo.spanEnd;
|
final int spanEnd = suggestionInfo.spanEnd;
|
||||||
if (spanStart != NO_SUGGESTIONS) {
|
if (spanStart != NO_SUGGESTIONS) {
|
||||||
@@ -10190,9 +10197,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void initContentView() {
|
protected void initContentView() {
|
||||||
mContentView.setOrientation(LinearLayout.HORIZONTAL);
|
LinearLayout linearLayout = new LinearLayout(TextView.this.getContext());
|
||||||
|
linearLayout.setOrientation(LinearLayout.HORIZONTAL);
|
||||||
|
mContentView = linearLayout;
|
||||||
mContentView.setBackgroundResource(
|
mContentView.setBackgroundResource(
|
||||||
com.android.internal.R.drawable.text_edit_side_paste_window);
|
com.android.internal.R.drawable.text_edit_paste_window);
|
||||||
|
|
||||||
LayoutInflater inflater = (LayoutInflater)TextView.this.mContext.
|
LayoutInflater inflater = (LayoutInflater)TextView.this.mContext.
|
||||||
getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||||
@@ -11282,7 +11291,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
|||||||
private final TextPaint mTextPaint;
|
private final TextPaint mTextPaint;
|
||||||
private boolean mUserSetTextScaleX;
|
private boolean mUserSetTextScaleX;
|
||||||
private final Paint mHighlightPaint;
|
private final Paint mHighlightPaint;
|
||||||
private int mHighlightColor = 0xCC475925;
|
private int mHighlightColor = 0x4C33B5E5;
|
||||||
/**
|
/**
|
||||||
* This is temporarily visible to fix bug 3085564 in webView. Do not rely on
|
* This is temporarily visible to fix bug 3085564 in webView. Do not rely on
|
||||||
* this field being protected. Will be restored as private when lineHeight
|
* this field being protected. Will be restored as private when lineHeight
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 865 B After Width: | Height: | Size: 917 B |
|
Before Width: | Height: | Size: 929 B After Width: | Height: | Size: 917 B |
|
Before Width: | Height: | Size: 585 B After Width: | Height: | Size: 568 B |
|
Before Width: | Height: | Size: 605 B After Width: | Height: | Size: 568 B |
BIN
core/res/res/drawable-xhdpi/text_edit_paste_window.9.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
core/res/res/drawable-xhdpi/text_edit_suggestions_window.9.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
@@ -25,4 +25,5 @@
|
|||||||
android:textAppearance="?android:attr/textAppearanceSmallInverse"
|
android:textAppearance="?android:attr/textAppearanceSmallInverse"
|
||||||
android:textColor="@android:color/black"
|
android:textColor="@android:color/black"
|
||||||
android:textAllCaps="true"
|
android:textAllCaps="true"
|
||||||
|
android:textStyle="bold"
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -158,10 +158,6 @@
|
|||||||
<!-- The underline color and thickness for misspelled suggestion -->
|
<!-- The underline color and thickness for misspelled suggestion -->
|
||||||
<attr name="textAppearanceMisspelledSuggestion" format="reference" />
|
<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 -->
|
<!-- The underline color -->
|
||||||
<attr name="textUnderlineColor" format="reference|color" />
|
<attr name="textUnderlineColor" format="reference|color" />
|
||||||
<!-- The underline thickness -->
|
<!-- The underline thickness -->
|
||||||
@@ -3154,10 +3150,6 @@
|
|||||||
<attr name="textUnderlineColor" />
|
<attr name="textUnderlineColor" />
|
||||||
<attr name="textUnderlineThickness" />
|
<attr name="textUnderlineThickness" />
|
||||||
</declare-styleable>
|
</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 <code>input-extras</code> is a container for extra data to supply to
|
||||||
an input method. Contains
|
an input method. Contains
|
||||||
one more more {@link #Extra <extra>} tags. -->
|
one more more {@link #Extra <extra>} tags. -->
|
||||||
|
|||||||
@@ -54,8 +54,6 @@
|
|||||||
<color name="dim_foreground_light_inverse">#bebebe</color>
|
<color name="dim_foreground_light_inverse">#bebebe</color>
|
||||||
<color name="dim_foreground_light_inverse_disabled">#80bebebe</color>
|
<color name="dim_foreground_light_inverse_disabled">#80bebebe</color>
|
||||||
<color name="hint_foreground_light">#808080</color>
|
<color name="hint_foreground_light">#808080</color>
|
||||||
<color name="highlight_background">#cc475925</color>
|
|
||||||
<color name="highlight_background_inverse">#ccd2e461</color>
|
|
||||||
<color name="highlighted_text_dark">#9983CC39</color>
|
<color name="highlighted_text_dark">#9983CC39</color>
|
||||||
<color name="highlighted_text_light">#9983CC39</color>
|
<color name="highlighted_text_light">#9983CC39</color>
|
||||||
<color name="link_text_dark">#5c5cff</color>
|
<color name="link_text_dark">#5c5cff</color>
|
||||||
@@ -135,10 +133,8 @@
|
|||||||
<color name="dim_foreground_inverse_holo_light">#bebebe</color>
|
<color name="dim_foreground_inverse_holo_light">#bebebe</color>
|
||||||
<color name="dim_foreground_inverse_disabled_holo_light">#80bebebe</color>
|
<color name="dim_foreground_inverse_disabled_holo_light">#80bebebe</color>
|
||||||
<color name="hint_foreground_holo_light">#808080</color>
|
<color name="hint_foreground_holo_light">#808080</color>
|
||||||
<color name="highlight_background_holo">#cc475925</color>
|
<color name="highlighted_text_holo_dark">#4c33b5e5</color>
|
||||||
<color name="highlight_background_inverse_holo">#ccd2e461</color>
|
<color name="highlighted_text_holo_light">#4c33b5e5</color>
|
||||||
<color name="highlighted_text_holo_dark">#9983CC39</color>
|
|
||||||
<color name="highlighted_text_holo_light">#9983CC39</color>
|
|
||||||
<color name="link_text_holo_dark">#5c5cff</color>
|
<color name="link_text_holo_dark">#5c5cff</color>
|
||||||
<color name="link_text_holo_light">#0000ee</color>
|
<color name="link_text_holo_light">#0000ee</color>
|
||||||
|
|
||||||
|
|||||||
@@ -255,11 +255,6 @@ please see styles_device_defaults.xml.
|
|||||||
<item name="android:textUnderlineColor">@color/holo_red_light</item>
|
<item name="android:textUnderlineColor">@color/holo_red_light</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style name="TextAppearance.SuggestionRange">
|
|
||||||
<item name="android:textColor">@color/white</item>
|
|
||||||
<item name="android:colorBackground">@color/holo_blue_dark</item>
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<!-- Widget Styles -->
|
<!-- Widget Styles -->
|
||||||
|
|
||||||
<style name="Widget">
|
<style name="Widget">
|
||||||
|
|||||||
@@ -91,7 +91,6 @@ please see themes_device_defaults.xml.
|
|||||||
|
|
||||||
<item name="textAppearanceEasyCorrectSuggestion">@android:style/TextAppearance.EasyCorrectSuggestion</item>
|
<item name="textAppearanceEasyCorrectSuggestion">@android:style/TextAppearance.EasyCorrectSuggestion</item>
|
||||||
<item name="textAppearanceMisspelledSuggestion">@android:style/TextAppearance.MisspelledSuggestion</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>
|
<item name="textAppearanceButton">@android:style/TextAppearance.Widget.Button</item>
|
||||||
|
|
||||||
|
|||||||