Merge "Bug 5278473 & 5278471: delete option in suggestion popup menu"
This commit is contained in:
committed by
Android (Google) Code Review
commit
404c8e5764
@@ -9613,6 +9613,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
|||||||
|
|
||||||
private class SuggestionsPopupWindow extends PinnedPopupWindow implements OnItemClickListener {
|
private class SuggestionsPopupWindow extends PinnedPopupWindow implements OnItemClickListener {
|
||||||
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 ADD_TO_DICTIONARY = -1;
|
||||||
|
private static final int DELETE_TEXT = -2;
|
||||||
private SuggestionInfo[] mSuggestionInfos;
|
private SuggestionInfo[] mSuggestionInfos;
|
||||||
private int mNumberOfSuggestions;
|
private int mNumberOfSuggestions;
|
||||||
private boolean mCursorWasVisibleBeforeSuggestions;
|
private boolean mCursorWasVisibleBeforeSuggestions;
|
||||||
@@ -9664,9 +9666,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
|||||||
listView.setOnItemClickListener(this);
|
listView.setOnItemClickListener(this);
|
||||||
mContentView = listView;
|
mContentView = listView;
|
||||||
|
|
||||||
// Inflate the suggestion items once and for all. +1 for add to dictionary
|
// Inflate the suggestion items once and for all. + 2 for add to dictionary and delete
|
||||||
mSuggestionInfos = new SuggestionInfo[MAX_NUMBER_SUGGESTIONS + 1];
|
mSuggestionInfos = new SuggestionInfo[MAX_NUMBER_SUGGESTIONS + 2];
|
||||||
for (int i = 0; i < MAX_NUMBER_SUGGESTIONS + 1; i++) {
|
for (int i = 0; i < mSuggestionInfos.length; i++) {
|
||||||
mSuggestionInfos[i] = new SuggestionInfo();
|
mSuggestionInfos[i] = new SuggestionInfo();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -9717,7 +9719,19 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
|||||||
false);
|
false);
|
||||||
}
|
}
|
||||||
|
|
||||||
textView.setText(mSuggestionInfos[position].text);
|
final SuggestionInfo suggestionInfo = mSuggestionInfos[position];
|
||||||
|
textView.setText(suggestionInfo.text);
|
||||||
|
|
||||||
|
if (suggestionInfo.suggestionIndex == ADD_TO_DICTIONARY) {
|
||||||
|
textView.setCompoundDrawablesWithIntrinsicBounds(
|
||||||
|
com.android.internal.R.drawable.ic_suggestions_add, 0, 0, 0);
|
||||||
|
} else if (suggestionInfo.suggestionIndex == DELETE_TEXT) {
|
||||||
|
textView.setCompoundDrawablesWithIntrinsicBounds(
|
||||||
|
com.android.internal.R.drawable.ic_suggestions_delete, 0, 0, 0);
|
||||||
|
} else {
|
||||||
|
textView.setCompoundDrawables(null, null, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
return textView;
|
return textView;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -9768,11 +9782,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
|||||||
public void show() {
|
public void show() {
|
||||||
if (!(mText instanceof Editable)) return;
|
if (!(mText instanceof Editable)) return;
|
||||||
|
|
||||||
if (updateSuggestions()) {
|
updateSuggestions();
|
||||||
mCursorWasVisibleBeforeSuggestions = mCursorVisible;
|
mCursorWasVisibleBeforeSuggestions = mCursorVisible;
|
||||||
setCursorVisible(false);
|
setCursorVisible(false);
|
||||||
super.show();
|
super.show();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -9828,7 +9841,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
|||||||
super.hide();
|
super.hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean updateSuggestions() {
|
private void updateSuggestions() {
|
||||||
Spannable spannable = (Spannable) TextView.this.mText;
|
Spannable spannable = (Spannable) TextView.this.mText;
|
||||||
SuggestionSpan[] suggestionSpans = getSuggestionSpans();
|
SuggestionSpan[] suggestionSpans = getSuggestionSpans();
|
||||||
|
|
||||||
@@ -9877,13 +9890,14 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
|||||||
highlightTextDifferences(mSuggestionInfos[i], spanUnionStart, spanUnionEnd);
|
highlightTextDifferences(mSuggestionInfos[i], spanUnionStart, spanUnionEnd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add to dictionary item is there a span with the misspelled flag
|
||||||
if (misspelledSpan != null) {
|
if (misspelledSpan != null) {
|
||||||
final int misspelledStart = spannable.getSpanStart(misspelledSpan);
|
final int misspelledStart = spannable.getSpanStart(misspelledSpan);
|
||||||
final int misspelledEnd = spannable.getSpanEnd(misspelledSpan);
|
final int misspelledEnd = spannable.getSpanEnd(misspelledSpan);
|
||||||
if (misspelledStart >= 0 && misspelledEnd > misspelledStart) {
|
if (misspelledStart >= 0 && misspelledEnd > misspelledStart) {
|
||||||
SuggestionInfo suggestionInfo = mSuggestionInfos[mNumberOfSuggestions];
|
SuggestionInfo suggestionInfo = mSuggestionInfos[mNumberOfSuggestions];
|
||||||
suggestionInfo.suggestionSpan = misspelledSpan;
|
suggestionInfo.suggestionSpan = misspelledSpan;
|
||||||
suggestionInfo.suggestionIndex = -1;
|
suggestionInfo.suggestionIndex = ADD_TO_DICTIONARY;
|
||||||
suggestionInfo.text.replace(0, suggestionInfo.text.length(),
|
suggestionInfo.text.replace(0, suggestionInfo.text.length(),
|
||||||
getContext().getString(com.android.internal.R.string.addToDictionary));
|
getContext().getString(com.android.internal.R.string.addToDictionary));
|
||||||
|
|
||||||
@@ -9891,7 +9905,13 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mNumberOfSuggestions == 0) return false;
|
// Delete item
|
||||||
|
SuggestionInfo suggestionInfo = mSuggestionInfos[mNumberOfSuggestions];
|
||||||
|
suggestionInfo.suggestionSpan = null;
|
||||||
|
suggestionInfo.suggestionIndex = DELETE_TEXT;
|
||||||
|
suggestionInfo.text.replace(0, suggestionInfo.text.length(),
|
||||||
|
getContext().getString(com.android.internal.R.string.deleteText));
|
||||||
|
mNumberOfSuggestions++;
|
||||||
|
|
||||||
if (mSuggestionRangeSpan == null) mSuggestionRangeSpan = new SuggestionRangeSpan();
|
if (mSuggestionRangeSpan == null) mSuggestionRangeSpan = new SuggestionRangeSpan();
|
||||||
if (underlineColor == 0) {
|
if (underlineColor == 0) {
|
||||||
@@ -9907,8 +9927,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
|||||||
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||||
|
|
||||||
mSuggestionsAdapter.notifyDataSetChanged();
|
mSuggestionsAdapter.notifyDataSetChanged();
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void highlightTextDifferences(SuggestionInfo suggestionInfo, int unionStart,
|
private void highlightTextDifferences(SuggestionInfo suggestionInfo, int unionStart,
|
||||||
@@ -9933,77 +9951,94 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
||||||
hide();
|
TextView textView = (TextView) view;
|
||||||
|
Editable editable = (Editable) mText;
|
||||||
|
|
||||||
if (view instanceof TextView) {
|
SuggestionInfo suggestionInfo = mSuggestionInfos[position];
|
||||||
TextView textView = (TextView) view;
|
|
||||||
Editable editable = (Editable) mText;
|
|
||||||
|
|
||||||
SuggestionInfo suggestionInfo = mSuggestionInfos[position];
|
if (suggestionInfo.suggestionIndex == DELETE_TEXT) {
|
||||||
final int spanStart = editable.getSpanStart(suggestionInfo.suggestionSpan);
|
final int spanUnionStart = editable.getSpanStart(mSuggestionRangeSpan);
|
||||||
final int spanEnd = editable.getSpanEnd(suggestionInfo.suggestionSpan);
|
int spanUnionEnd = editable.getSpanEnd(mSuggestionRangeSpan);
|
||||||
if (spanStart < 0 || spanEnd < 0) return; // Span has been removed
|
// Do not leave two adjacent spaces after deletion, or one at beginning of text
|
||||||
final String originalText = mText.subSequence(spanStart, spanEnd).toString();
|
if (spanUnionEnd < editable.length() &&
|
||||||
|
Character.isSpaceChar(editable.charAt(spanUnionEnd)) &&
|
||||||
if (suggestionInfo.suggestionIndex < 0) {
|
(spanUnionStart == 0 ||
|
||||||
Intent intent = new Intent(Settings.ACTION_USER_DICTIONARY_INSERT);
|
Character.isSpaceChar(editable.charAt(spanUnionStart - 1)))) {
|
||||||
intent.putExtra("word", originalText);
|
spanUnionEnd = spanUnionEnd + 1;
|
||||||
intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
|
|
||||||
getContext().startActivity(intent);
|
|
||||||
suggestionInfo.removeMisspelledFlag();
|
|
||||||
} else {
|
|
||||||
// SuggestionSpans are removed by replace: save them before
|
|
||||||
SuggestionSpan[] suggestionSpans = editable.getSpans(spanStart, spanEnd,
|
|
||||||
SuggestionSpan.class);
|
|
||||||
final int length = suggestionSpans.length;
|
|
||||||
int[] suggestionSpansStarts = new int[length];
|
|
||||||
int[] suggestionSpansEnds = new int[length];
|
|
||||||
int[] suggestionSpansFlags = new int[length];
|
|
||||||
for (int i = 0; i < length; i++) {
|
|
||||||
final SuggestionSpan suggestionSpan = suggestionSpans[i];
|
|
||||||
suggestionSpansStarts[i] = editable.getSpanStart(suggestionSpan);
|
|
||||||
suggestionSpansEnds[i] = editable.getSpanEnd(suggestionSpan);
|
|
||||||
suggestionSpansFlags[i] = editable.getSpanFlags(suggestionSpan);
|
|
||||||
}
|
|
||||||
|
|
||||||
final int suggestionStart = suggestionInfo.suggestionStart;
|
|
||||||
final int suggestionEnd = suggestionInfo.suggestionEnd;
|
|
||||||
final String suggestion = textView.getText().subSequence(
|
|
||||||
suggestionStart, suggestionEnd).toString();
|
|
||||||
editable.replace(spanStart, spanEnd, suggestion);
|
|
||||||
|
|
||||||
suggestionInfo.removeMisspelledFlag();
|
|
||||||
|
|
||||||
// Notify source IME of the suggestion pick. Do this before swaping texts.
|
|
||||||
if (!TextUtils.isEmpty(
|
|
||||||
suggestionInfo.suggestionSpan.getNotificationTargetClassName())) {
|
|
||||||
InputMethodManager imm = InputMethodManager.peekInstance();
|
|
||||||
imm.notifySuggestionPicked(suggestionInfo.suggestionSpan, originalText,
|
|
||||||
suggestionInfo.suggestionIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Swap text content between actual text and Suggestion span
|
|
||||||
String[] suggestions = suggestionInfo.suggestionSpan.getSuggestions();
|
|
||||||
suggestions[suggestionInfo.suggestionIndex] = originalText;
|
|
||||||
|
|
||||||
// Restore previous SuggestionSpans
|
|
||||||
final int lengthDifference = suggestion.length() - (spanEnd - spanStart);
|
|
||||||
for (int i = 0; i < length; i++) {
|
|
||||||
// Only spans that include the modified region make sense after replacement
|
|
||||||
// Spans partially included in the replaced region are removed, there is no
|
|
||||||
// way to assign them a valid range after replacement
|
|
||||||
if (suggestionSpansStarts[i] <= spanStart &&
|
|
||||||
suggestionSpansEnds[i] >= spanEnd) {
|
|
||||||
editable.setSpan(suggestionSpans[i], suggestionSpansStarts[i],
|
|
||||||
suggestionSpansEnds[i] + lengthDifference,
|
|
||||||
suggestionSpansFlags[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Move cursor at the end of the replacement word
|
|
||||||
Selection.setSelection(editable, spanEnd + lengthDifference);
|
|
||||||
}
|
}
|
||||||
|
editable.replace(spanUnionStart, spanUnionEnd, "");
|
||||||
|
hide();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final int spanStart = editable.getSpanStart(suggestionInfo.suggestionSpan);
|
||||||
|
final int spanEnd = editable.getSpanEnd(suggestionInfo.suggestionSpan);
|
||||||
|
if (spanStart < 0 || spanEnd < 0) {
|
||||||
|
// Span has been removed
|
||||||
|
hide();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final String originalText = mText.subSequence(spanStart, spanEnd).toString();
|
||||||
|
|
||||||
|
if (suggestionInfo.suggestionIndex == ADD_TO_DICTIONARY) {
|
||||||
|
Intent intent = new Intent(Settings.ACTION_USER_DICTIONARY_INSERT);
|
||||||
|
intent.putExtra("word", originalText);
|
||||||
|
intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||||
|
getContext().startActivity(intent);
|
||||||
|
suggestionInfo.removeMisspelledFlag();
|
||||||
|
} else {
|
||||||
|
// SuggestionSpans are removed by replace: save them before
|
||||||
|
SuggestionSpan[] suggestionSpans = editable.getSpans(spanStart, spanEnd,
|
||||||
|
SuggestionSpan.class);
|
||||||
|
final int length = suggestionSpans.length;
|
||||||
|
int[] suggestionSpansStarts = new int[length];
|
||||||
|
int[] suggestionSpansEnds = new int[length];
|
||||||
|
int[] suggestionSpansFlags = new int[length];
|
||||||
|
for (int i = 0; i < length; i++) {
|
||||||
|
final SuggestionSpan suggestionSpan = suggestionSpans[i];
|
||||||
|
suggestionSpansStarts[i] = editable.getSpanStart(suggestionSpan);
|
||||||
|
suggestionSpansEnds[i] = editable.getSpanEnd(suggestionSpan);
|
||||||
|
suggestionSpansFlags[i] = editable.getSpanFlags(suggestionSpan);
|
||||||
|
}
|
||||||
|
|
||||||
|
final int suggestionStart = suggestionInfo.suggestionStart;
|
||||||
|
final int suggestionEnd = suggestionInfo.suggestionEnd;
|
||||||
|
final String suggestion = textView.getText().subSequence(
|
||||||
|
suggestionStart, suggestionEnd).toString();
|
||||||
|
editable.replace(spanStart, spanEnd, suggestion);
|
||||||
|
|
||||||
|
suggestionInfo.removeMisspelledFlag();
|
||||||
|
|
||||||
|
// Notify source IME of the suggestion pick. Do this before swaping texts.
|
||||||
|
if (!TextUtils.isEmpty(
|
||||||
|
suggestionInfo.suggestionSpan.getNotificationTargetClassName())) {
|
||||||
|
InputMethodManager imm = InputMethodManager.peekInstance();
|
||||||
|
imm.notifySuggestionPicked(suggestionInfo.suggestionSpan, originalText,
|
||||||
|
suggestionInfo.suggestionIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Swap text content between actual text and Suggestion span
|
||||||
|
String[] suggestions = suggestionInfo.suggestionSpan.getSuggestions();
|
||||||
|
suggestions[suggestionInfo.suggestionIndex] = originalText;
|
||||||
|
|
||||||
|
// Restore previous SuggestionSpans
|
||||||
|
final int lengthDifference = suggestion.length() - (spanEnd - spanStart);
|
||||||
|
for (int i = 0; i < length; i++) {
|
||||||
|
// Only spans that include the modified region make sense after replacement
|
||||||
|
// Spans partially included in the replaced region are removed, there is no
|
||||||
|
// way to assign them a valid range after replacement
|
||||||
|
if (suggestionSpansStarts[i] <= spanStart &&
|
||||||
|
suggestionSpansEnds[i] >= spanEnd) {
|
||||||
|
editable.setSpan(suggestionSpans[i], suggestionSpansStarts[i],
|
||||||
|
suggestionSpansEnds[i] + lengthDifference, suggestionSpansFlags[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move cursor at the end of the replacement word
|
||||||
|
Selection.setSelection(editable, spanEnd + lengthDifference);
|
||||||
|
}
|
||||||
|
|
||||||
|
hide();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
BIN
core/res/res/drawable-hdpi/ic_suggestions_add.png
Normal file
BIN
core/res/res/drawable-hdpi/ic_suggestions_add.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 381 B |
BIN
core/res/res/drawable-hdpi/ic_suggestions_delete.png
Normal file
BIN
core/res/res/drawable-hdpi/ic_suggestions_delete.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 478 B |
BIN
core/res/res/drawable-mdpi/ic_suggestions_add.png
Normal file
BIN
core/res/res/drawable-mdpi/ic_suggestions_add.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 353 B |
BIN
core/res/res/drawable-mdpi/ic_suggestions_delete.png
Normal file
BIN
core/res/res/drawable-mdpi/ic_suggestions_delete.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 401 B |
BIN
core/res/res/drawable-xhdpi/ic_suggestions_add.png
Normal file
BIN
core/res/res/drawable-xhdpi/ic_suggestions_add.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 401 B |
BIN
core/res/res/drawable-xhdpi/ic_suggestions_delete.png
Normal file
BIN
core/res/res/drawable-xhdpi/ic_suggestions_delete.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 627 B |
@@ -23,6 +23,7 @@
|
|||||||
android:paddingBottom="8dip"
|
android:paddingBottom="8dip"
|
||||||
android:layout_gravity="left|center_vertical"
|
android:layout_gravity="left|center_vertical"
|
||||||
android:singleLine="true"
|
android:singleLine="true"
|
||||||
|
android:drawablePadding="8dip"
|
||||||
android:ellipsize="marquee"
|
android:ellipsize="marquee"
|
||||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||||
android:textColor="@android:color/dim_foreground_light" />
|
android:textColor="@android:color/dim_foreground_light" />
|
||||||
|
|||||||
Reference in New Issue
Block a user