Skip to content

Commit da23fdf

Browse files
NickGerlemanfacebook-github-bot
authored andcommitted
Partial Mitigation for Samsung TextInput Hangs
Summary: In #35936 we observed that the presence of AbsoluteSizeSpan may lead to hangs when using the Grammarly keyboard on Samsung. This mitigation makes it so that we do not emit this span in the most common cases, when it is sufficient to set `android:textSize`. In simple cases, it causes typing into the TextInput to no longer hang. This does not resolve the issue for TextInputs which meaningfully use layout-effecting spans (or at least font size), such as non-uniform text size within the input. We could potentially do further work to reduce the number of spans emitted in these scenarios, but this may be fighting a losing battle against the platform. Changelog: [Android][Fixed] - Partial Mitigation for Samsung TextInput Hangs (Paper) Reviewed By: cortinico Differential Revision: D42721684 fbshipit-source-id: 5599070f10a385c6063683e3ac7a5acbbdc10ae9
1 parent 6f7428e commit da23fdf

File tree

2 files changed

+36
-0
lines changed

2 files changed

+36
-0
lines changed

ReactAndroid/src/main/java/com/facebook/react/views/text/ReactBaseTextShadowNode.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,9 @@ protected Spannable spannedFromShadowNode(
308308
priority++;
309309
}
310310

311+
// Mitigation for https://github.com/facebook/react-native/issues/35936 (S318090)
312+
flattenAbsoluteSizeSpans(sb);
313+
311314
textShadowNode.mTextAttributes.setHeightOfTallestInlineViewOrImage(
312315
heightOfTallestInlineViewOrImage);
313316

@@ -318,6 +321,29 @@ protected Spannable spannedFromShadowNode(
318321
return sb;
319322
}
320323

324+
private void flattenAbsoluteSizeSpans(SpannableStringBuilder sb) {
325+
// If spans cover the entire input with the same size as
326+
// getEffectiveFontSize() we can omit them
327+
ReactAbsoluteSizeSpan[] spans = sb.getSpans(0, sb.length(), ReactAbsoluteSizeSpan.class);
328+
329+
int lastSpanIndex = -1;
330+
final int expectedTextSize = mTextAttributes.getEffectiveFontSize();
331+
332+
for (ReactAbsoluteSizeSpan span : spans) {
333+
if (sb.getSpanStart(span) > lastSpanIndex + 1 || span.getSize() != expectedTextSize) {
334+
return;
335+
}
336+
337+
lastSpanIndex = sb.getSpanEnd(span) - 1;
338+
}
339+
340+
if (lastSpanIndex >= sb.length() - 1) {
341+
for (ReactAbsoluteSizeSpan span : spans) {
342+
sb.removeSpan(span);
343+
}
344+
}
345+
}
346+
321347
protected TextAttributes mTextAttributes;
322348

323349
protected boolean mIsColorSet = false;

ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextShadowNode.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,16 @@ public long measure(
7373
mPreparedSpannableText,
7474
"Spannable element has not been prepared in onBeforeLayout");
7575

76+
// Unflatten AbsoluteSizeSpan for measurement (see flattenAbsoluteSizeSpans() in
77+
// ReactBaseTextShadowNode)
78+
if (text.getSpans(0, text.length(), ReactAbsoluteSizeSpan.class).length == 0) {
79+
text.setSpan(
80+
new ReactAbsoluteSizeSpan(mTextAttributes.getEffectiveFontSize()),
81+
0,
82+
text.length(),
83+
Spannable.SPAN_INCLUSIVE_INCLUSIVE);
84+
}
85+
7686
Layout layout = measureSpannedText(text, width, widthMode);
7787

7888
if (mAdjustsFontSizeToFit) {

0 commit comments

Comments
 (0)