diff options
| author | 2024-01-17 17:02:54 -0800 | |
|---|---|---|
| committer | 2024-01-23 12:55:15 -0800 | |
| commit | 97edc8f25a7f53a74ef7f7cfeb4cf9d89b361f9c (patch) | |
| tree | ae32bf028ae92e811d8610b413a41edb2c0dbee8 | |
| parent | 64fccbba24fc7071536e320bd27e300ba2a4f564 (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.java | 35 | ||||
| -rw-r--r-- | core/java/android/text/flags/flags.aconfig | 7 | ||||
| -rw-r--r-- | core/java/android/widget/Editor.java | 8 |
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 = |