summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Haoyu Zhang <haoyuchang@google.com> 2023-06-27 00:02:21 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2023-06-27 00:02:21 +0000
commit8f7f72a50dd69ac45edb237626c0c97bbb831fd6 (patch)
treeb1ebce709d7bcab9c97670e676fbb120a718db7f
parent7e79f078103a93fe3147ae1bea6b995f40a94507 (diff)
parent26088fe87e70f539312fd3d0858719047d244824 (diff)
Merge "Exit insert mode when TextView#setText is called" into udc-qpr-dev
-rw-r--r--core/java/android/widget/Editor.java59
-rw-r--r--core/java/android/widget/TextView.java22
2 files changed, 74 insertions, 7 deletions
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index d37c37a392a5..3da9e96618f3 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -8105,6 +8105,16 @@ public class Editor {
private final Paint mHighlightPaint;
private final Path mHighlightPath;
+ /**
+ * Whether it is in the progress of updating transformation method. It's needed because
+ * {@link TextView#setTransformationMethod(TransformationMethod)} will eventually call
+ * {@link TextView#setText(CharSequence)}.
+ * Because it normally should exit insert mode when {@link TextView#setText(CharSequence)}
+ * is called externally, we need this boolean to distinguish whether setText is triggered
+ * by setTransformation or not.
+ */
+ private boolean mUpdatingTransformationMethod;
+
InsertModeController(@NonNull TextView textView) {
mTextView = Objects.requireNonNull(textView);
mIsInsertModeActive = false;
@@ -8137,7 +8147,7 @@ public class Editor {
final boolean isSingleLine = mTextView.isSingleLine();
mInsertModeTransformationMethod = new InsertModeTransformationMethod(offset,
isSingleLine, oldTransformationMethod);
- mTextView.setTransformationMethodInternal(mInsertModeTransformationMethod);
+ setTransformationMethod(mInsertModeTransformationMethod, true);
Selection.setSelection((Spannable) mTextView.getText(), offset);
mIsInsertModeActive = true;
@@ -8145,6 +8155,10 @@ public class Editor {
}
void exitInsertMode() {
+ exitInsertMode(true);
+ }
+
+ void exitInsertMode(boolean updateText) {
if (!mIsInsertModeActive) return;
if (mInsertModeTransformationMethod == null
|| mInsertModeTransformationMethod != mTextView.getTransformationMethod()) {
@@ -8157,7 +8171,7 @@ public class Editor {
final int selectionEnd = mTextView.getSelectionEnd();
final TransformationMethod oldTransformationMethod =
mInsertModeTransformationMethod.getOldTransformationMethod();
- mTextView.setTransformationMethodInternal(oldTransformationMethod);
+ setTransformationMethod(oldTransformationMethod, updateText);
Selection.setSelection((Spannable) mTextView.getText(), selectionStart, selectionEnd);
mIsInsertModeActive = false;
}
@@ -8178,6 +8192,32 @@ public class Editor {
}
/**
+ * Update the TransformationMethod on the {@link TextView}.
+ * @param method the new method to be set on the {@link TextView}/
+ * @param updateText whether to update the text during setTransformationMethod call.
+ */
+ private void setTransformationMethod(TransformationMethod method, boolean updateText) {
+ mUpdatingTransformationMethod = true;
+ mTextView.setTransformationMethodInternal(method, updateText);
+ mUpdatingTransformationMethod = false;
+ }
+
+ /**
+ * Notify the InsertMode controller that the {@link TextView} is about to set its text.
+ */
+ void beforeSetText() {
+ // TextView#setText is called because our call to
+ // TextView#setTransformationMethodInternal in enterInsertMode() or exitInsertMode().
+ // Do nothing in this case.
+ if (mUpdatingTransformationMethod) {
+ return;
+ }
+ // TextView#setText is called externally. Exit InsertMode but don't update text again
+ // when calling setTransformationMethod.
+ exitInsertMode(/* updateText */ false);
+ }
+
+ /**
* Notify the {@link InsertModeController} before the TextView's
* {@link TransformationMethod} is updated. If it's not in the insert mode,
* the given method is directly returned. Otherwise, it will wrap the given transformation
@@ -8205,6 +8245,9 @@ public class Editor {
return mInsertModeController.enterInsertMode(offset);
}
+ /**
+ * Exit insert mode if this editor is in insert mode.
+ */
void exitInsertMode() {
if (mInsertModeController == null) return;
mInsertModeController.exitInsertMode();
@@ -8217,7 +8260,7 @@ public class Editor {
*/
void setTransformationMethod(TransformationMethod method) {
if (mInsertModeController == null || !mInsertModeController.mIsInsertModeActive) {
- mTextView.setTransformationMethodInternal(method);
+ mTextView.setTransformationMethodInternal(method, /* updateText */ true);
return;
}
@@ -8226,11 +8269,19 @@ public class Editor {
final int selectionStart = mTextView.getSelectionStart();
final int selectionEnd = mTextView.getSelectionEnd();
method = mInsertModeController.updateTransformationMethod(method);
- mTextView.setTransformationMethodInternal(method);
+ mTextView.setTransformationMethodInternal(method, /* updateText */ true);
Selection.setSelection((Spannable) mTextView.getText(), selectionStart, selectionEnd);
}
/**
+ * Notify that the Editor that the associated {@link TextView} is about to set its text.
+ */
+ void beforeSetText() {
+ if (mInsertModeController == null) return;
+ mInsertModeController.beforeSetText();
+ }
+
+ /**
* Initializes the nodeInfo with smart actions.
*/
void onInitializeSmartActionsAccessibilityNodeInfo(AccessibilityNodeInfo nodeInfo) {
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 7e1e52dd0707..4f556bc848ec 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -2795,11 +2795,22 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
if (mEditor != null) {
mEditor.setTransformationMethod(method);
} else {
- setTransformationMethodInternal(method);
+ setTransformationMethodInternal(method, /* updateText */ true);
}
}
- void setTransformationMethodInternal(@Nullable TransformationMethod method) {
+ /**
+ * Set the transformation that is applied to the text that this TextView is displaying,
+ * optionally call the setText.
+ * @param method the new transformation method to be set.
+ * @param updateText whether the call {@link #setText} which will update the TextView to display
+ * the new content. This method is helpful when updating
+ * {@link TransformationMethod} inside {@link #setText}. It should only be
+ * false if text will be updated immediately after this call, otherwise the
+ * TextView will enter an inconsistent state.
+ */
+ void setTransformationMethodInternal(@Nullable TransformationMethod method,
+ boolean updateText) {
if (method == mTransformation) {
// Avoid the setText() below if the transformation is
// the same.
@@ -2821,7 +2832,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
mAllowTransformationLengthChange = false;
}
- setText(mText);
+ if (updateText) {
+ setText(mText);
+ }
if (hasPasswordTransformationMethod()) {
notifyViewAccessibilityStateChangedIfNeeded(
@@ -7000,6 +7013,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
@UnsupportedAppUsage
private void setText(CharSequence text, BufferType type,
boolean notifyBefore, int oldlen) {
+ if (mEditor != null) {
+ mEditor.beforeSetText();
+ }
mTextSetFromXmlOrResourceId = false;
if (text == null) {
text = "";