Extracted text problems
Bug 5557258: recent text editing changed in ExtractedText mode is
broken. The modifications of the text performed by:
- drag and drop
- text suggestions, deletion
- voice IME's delete button
all change the ExtractEditText itself, while they should affect the underlying
EditText (and the change will be forwarded to the ExtractEditText). As a results,
changes are not actually modifying the underlying text.
Created new protected methods in TextView, overloaded in ExtractTextView to
affect the underlying text instead.
Changes to spans should also be forwarded to the original TV (see the 2 TODOs),
this is tracked in bug 5589158.
Change-Id: Ibfec272469e8db191b3875e7576e32481a9dc1bd
diff --git a/core/java/android/inputmethodservice/ExtractEditText.java b/core/java/android/inputmethodservice/ExtractEditText.java
index 4fc63ed..72431f3 100644
--- a/core/java/android/inputmethodservice/ExtractEditText.java
+++ b/core/java/android/inputmethodservice/ExtractEditText.java
@@ -156,4 +156,27 @@
mIME.onViewClicked(false);
}
}
+
+ /**
+ * Delete the range of text, supposedly valid
+ * @hide
+ */
+ @Override
+ protected void deleteText_internal(int start, int end) {
+ // Do not call the super method. This will change the source TextView instead, which
+ // will update the ExtractTextView.
+ mIME.onExtractedDeleteText(start, end);
+ }
+
+ /**
+ * Replaces the range of text [start, end[ by replacement text
+ * @hide
+ */
+ @Override
+ protected void replaceText_internal(int start, int end, CharSequence text) {
+ // Do not call the super method. This will change the source TextView instead, which
+ // will update the ExtractTextView.
+ mIME.onExtractedReplaceText(start, end, text);
+ }
+
}
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 60188ea..02839db 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -1982,7 +1982,29 @@
conn.setSelection(start, end);
}
}
-
+
+ /**
+ * @hide
+ */
+ public void onExtractedDeleteText(int start, int end) {
+ InputConnection conn = getCurrentInputConnection();
+ if (conn != null) {
+ conn.setSelection(start, start);
+ conn.deleteSurroundingText(0, end-start);
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public void onExtractedReplaceText(int start, int end, CharSequence text) {
+ InputConnection conn = getCurrentInputConnection();
+ if (conn != null) {
+ conn.setComposingRegion(start, end);
+ conn.commitText(text, 1);
+ }
+ }
+
/**
* This is called when the user has clicked on the extracted text view,
* when running in fullscreen mode. The default implementation hides
@@ -1998,7 +2020,7 @@
setCandidatesViewShown(false);
}
}
-
+
/**
* This is called when the user has performed a cursor movement in the
* extracted text view, when it is running in fullscreen mode. The default
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 5833afd..b39db27 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -36,7 +36,6 @@
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.inputmethodservice.ExtractEditText;
-import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
@@ -101,7 +100,6 @@
import android.util.TypedValue;
import android.view.ActionMode;
import android.view.ActionMode.Callback;
-import android.view.ContextMenu;
import android.view.DragEvent;
import android.view.Gravity;
import android.view.HapticFeedbackConstants;
@@ -7964,16 +7962,12 @@
@Override
public void onClick(View view) {
if (view == mDeleteTextView) {
- deleteText();
- }
- }
-
- private void deleteText() {
- Editable editable = (Editable) mText;
- int start = editable.getSpanStart(mEasyEditSpan);
- int end = editable.getSpanEnd(mEasyEditSpan);
- if (start >= 0 && end >= 0) {
- editable.delete(start, end);
+ Editable editable = (Editable) mText;
+ int start = editable.getSpanStart(mEasyEditSpan);
+ int end = editable.getSpanEnd(mEasyEditSpan);
+ if (start >= 0 && end >= 0) {
+ deleteText_internal(start, end);
+ }
}
}
@@ -9112,7 +9106,7 @@
case ID_CUT:
setPrimaryClip(ClipData.newPlainText(null, getTransformedText(min, max)));
- ((Editable) mText).delete(min, max);
+ deleteText_internal(min, max);
stopSelectionActionMode();
return true;
@@ -9143,7 +9137,7 @@
if (Character.isSpaceChar(charBefore) && Character.isSpaceChar(charAfter)) {
// Two spaces at beginning of paste: remove one
final int originalLength = mText.length();
- ((Editable) mText).delete(min - 1, min);
+ deleteText_internal(min - 1, min);
// Due to filters, there is no guarantee that exactly one character was
// removed: count instead.
final int delta = mText.length() - originalLength;
@@ -9153,7 +9147,7 @@
!Character.isSpaceChar(charAfter) && charAfter != '\n') {
// No space at beginning of paste: add one
final int originalLength = mText.length();
- ((Editable) mText).replace(min, min, " ");
+ replaceText_internal(min, min, " ");
// Taking possible filters into account as above.
final int delta = mText.length() - originalLength;
min += delta;
@@ -9167,11 +9161,11 @@
if (Character.isSpaceChar(charBefore) && Character.isSpaceChar(charAfter)) {
// Two spaces at end of paste: remove one
- ((Editable) mText).delete(max, max + 1);
+ deleteText_internal(max, max + 1);
} else if (!Character.isSpaceChar(charBefore) && charBefore != '\n' &&
!Character.isSpaceChar(charAfter) && charAfter != '\n') {
// No space at end of paste: add one
- ((Editable) mText).replace(max, max, " ");
+ replaceText_internal(max, max, " ");
}
}
}
@@ -9883,9 +9877,7 @@
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
- TextView textView = (TextView) view;
Editable editable = (Editable) mText;
-
SuggestionInfo suggestionInfo = mSuggestionInfos[position];
if (suggestionInfo.suggestionIndex == DELETE_TEXT) {
@@ -9899,7 +9891,7 @@
Character.isSpaceChar(editable.charAt(spanUnionStart - 1)))) {
spanUnionEnd = spanUnionEnd + 1;
}
- editable.replace(spanUnionStart, spanUnionEnd, "");
+ deleteText_internal(spanUnionStart, spanUnionEnd);
}
hide();
return;
@@ -9920,6 +9912,7 @@
intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
getContext().startActivity(intent);
// There is no way to know if the word was indeed added. Re-check.
+ // TODO The ExtractEditText should remove the span in the original text instead
editable.removeSpan(suggestionInfo.suggestionSpan);
updateSpellCheckSpans(spanStart, spanEnd);
} else {
@@ -9947,9 +9940,9 @@
final int suggestionStart = suggestionInfo.suggestionStart;
final int suggestionEnd = suggestionInfo.suggestionEnd;
- final String suggestion = textView.getText().subSequence(
+ final String suggestion = suggestionInfo.text.subSequence(
suggestionStart, suggestionEnd).toString();
- editable.replace(spanStart, spanEnd, suggestion);
+ replaceText_internal(spanStart, spanEnd, suggestion);
// Notify source IME of the suggestion pick. Do this before swaping texts.
if (!TextUtils.isEmpty(
@@ -9973,6 +9966,7 @@
// way to assign them a valid range after replacement
if (suggestionSpansStarts[i] <= spanStart &&
suggestionSpansEnds[i] >= spanEnd) {
+ // TODO The ExtractEditText should restore these spans in the original text
editable.setSpan(suggestionSpans[i], suggestionSpansStarts[i],
suggestionSpansEnds[i] + lengthDifference, suggestionSpansFlags[i]);
}
@@ -11245,7 +11239,7 @@
int max = extractRangeEndFromLong(minMax);
Selection.setSelection((Spannable) mText, max);
- ((Editable) mText).replace(min, max, content);
+ replaceText_internal(min, max, content);
if (dragDropIntoItself) {
int dragSourceStart = dragLocalState.start;
@@ -11258,7 +11252,7 @@
}
// Delete original selection
- ((Editable) mText).delete(dragSourceStart, dragSourceEnd);
+ deleteText_internal(dragSourceStart, dragSourceEnd);
// Make sure we do not leave two adjacent spaces.
if ((dragSourceStart == 0 ||
@@ -11267,7 +11261,7 @@
Character.isSpaceChar(mTransformed.charAt(dragSourceStart)))) {
final int pos = dragSourceStart == mText.length() ?
dragSourceStart - 1 : dragSourceStart;
- ((Editable) mText).delete(pos, pos + 1);
+ deleteText_internal(pos, pos + 1);
}
}
}
@@ -11428,6 +11422,22 @@
}
}
+ /**
+ * Deletes the range of text [start, end[.
+ * @hide
+ */
+ protected void deleteText_internal(int start, int end) {
+ ((Editable) mText).delete(start, end);
+ }
+
+ /**
+ * Replaces the range of text [start, end[ by replacement text
+ * @hide
+ */
+ protected void replaceText_internal(int start, int end, CharSequence text) {
+ ((Editable) mText).replace(start, end, text);
+ }
+
@ViewDebug.ExportedProperty(category = "text")
private CharSequence mText;
private CharSequence mTransformed;