diff options
| author | 2023-06-27 00:02:21 +0000 | |
|---|---|---|
| committer | 2023-06-27 00:02:21 +0000 | |
| commit | 8f7f72a50dd69ac45edb237626c0c97bbb831fd6 (patch) | |
| tree | b1ebce709d7bcab9c97670e676fbb120a718db7f | |
| parent | 7e79f078103a93fe3147ae1bea6b995f40a94507 (diff) | |
| parent | 26088fe87e70f539312fd3d0858719047d244824 (diff) | |
Merge "Exit insert mode when TextView#setText is called" into udc-qpr-dev
| -rw-r--r-- | core/java/android/widget/Editor.java | 59 | ||||
| -rw-r--r-- | core/java/android/widget/TextView.java | 22 |
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 = ""; |