summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Haoyu Zhang <haoyuchang@google.com> 2024-01-17 17:02:54 -0800
committer Haoyu Zhang <haoyuchang@google.com> 2024-01-23 12:55:15 -0800
commit97edc8f25a7f53a74ef7f7cfeb4cf9d89b361f9c (patch)
treeae32bf028ae92e811d8610b413a41edb2c0dbee8
parent64fccbba24fc7071536e320bd27e300ba2a4f564 (diff)
Fix: insert mode crash when delete
When the editor has a Span that implement UpdateLayout, deleting text in insert mode will crash the APP. This is due to the fact that updating the text will also trigger span update. And then trigger the DynamicLayout updates and display list update. Because the insert mode applied a transformation on the text, it's hard to know the updated text range on the transformed text. This CL fixed the issue by always updating the entire when span is updated. Bug: 314254153 Test: mannually tested as the Editor.java is hidden Change-Id: If4953de0ae37f92683e5c12c7a11b29a43260fa3
-rw-r--r--core/java/android/text/DynamicLayout.java35
-rw-r--r--core/java/android/text/flags/flags.aconfig7
-rw-r--r--core/java/android/widget/Editor.java8
3 files changed, 46 insertions, 4 deletions
diff --git a/core/java/android/text/DynamicLayout.java b/core/java/android/text/DynamicLayout.java
index 7b9cb6afd6a0..928604983b70 100644
--- a/core/java/android/text/DynamicLayout.java
+++ b/core/java/android/text/DynamicLayout.java
@@ -40,6 +40,7 @@ import android.util.Pools.SynchronizedPool;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.GrowingArrayUtils;
+import com.android.text.flags.Flags;
import java.lang.ref.WeakReference;
@@ -1276,8 +1277,21 @@ public class DynamicLayout extends Layout {
}
public void onSpanRemoved(Spannable s, Object o, int start, int end) {
- if (o instanceof UpdateLayout)
- transformAndReflow(s, start, end);
+ if (o instanceof UpdateLayout) {
+ if (Flags.insertModeCrashWhenDelete()) {
+ final DynamicLayout dynamicLayout = mLayout.get();
+ if (dynamicLayout != null && dynamicLayout.mDisplay instanceof OffsetMapping) {
+ // It's possible that a Span is removed when the text covering it is
+ // deleted, in this case, the original start and end of the span might be
+ // OOB. So it'll reflow the entire string instead.
+ reflow(s, 0, 0, s.length());
+ } else {
+ reflow(s, start, end - start, end - start);
+ }
+ } else {
+ transformAndReflow(s, start, end);
+ }
+ }
}
public void onSpanChanged(Spannable s, Object o, int start, int end, int nstart, int nend) {
@@ -1287,8 +1301,21 @@ public class DynamicLayout extends Layout {
// instead of causing an exception
start = 0;
}
- transformAndReflow(s, start, end);
- transformAndReflow(s, nstart, nend);
+ if (Flags.insertModeCrashWhenDelete()) {
+ final DynamicLayout dynamicLayout = mLayout.get();
+ if (dynamicLayout != null && dynamicLayout.mDisplay instanceof OffsetMapping) {
+ // When text is changed, it'll also trigger onSpanChanged. In this case we
+ // can't determine the updated range in the transformed text. So it'll
+ // reflow the entire range instead.
+ reflow(s, 0, 0, s.length());
+ } else {
+ reflow(s, start, end - start, end - start);
+ reflow(s, nstart, nend - nstart, nend - nstart);
+ }
+ } else {
+ transformAndReflow(s, start, end);
+ transformAndReflow(s, nstart, nend);
+ }
}
}
diff --git a/core/java/android/text/flags/flags.aconfig b/core/java/android/text/flags/flags.aconfig
index bf1a59625c93..6e45fea930d2 100644
--- a/core/java/android/text/flags/flags.aconfig
+++ b/core/java/android/text/flags/flags.aconfig
@@ -89,3 +89,10 @@ flag {
description: "Feature flag for clearing focus when the escape key is pressed."
bug: "312921137"
}
+
+flag {
+ name: "insert_mode_crash_when_delete"
+ namespace: "text"
+ description: "A feature flag for fixing the crash while delete text in insert mode."
+ bug: "314254153"
+}
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index ddcfb40e00ce..57d268ced6f4 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -148,6 +148,7 @@ import com.android.internal.util.ArrayUtils;
import com.android.internal.util.GrowingArrayUtils;
import com.android.internal.util.Preconditions;
import com.android.internal.view.FloatingActionMode;
+import com.android.text.flags.Flags;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -2343,6 +2344,13 @@ public class Editor {
*/
void invalidateTextDisplayList(Layout layout, int start, int end) {
if (mTextRenderNodes != null && layout instanceof DynamicLayout) {
+ if (Flags.insertModeCrashWhenDelete()
+ && mTextView.isOffsetMappingAvailable()) {
+ // Text is transformed with an OffsetMapping, and we can't know the changed range
+ // on the transformed text. Invalidate the all display lists instead.
+ invalidateTextDisplayList();
+ return;
+ }
final int startTransformed =
mTextView.originalToTransformed(start, OffsetMapping.MAP_STRATEGY_CHARACTER);
final int endTransformed =