Status Update
Comments
an...@google.com <an...@google.com> #2
This should be moved to the Android Public Tracker > Text
component, but I don't have permissions so I'm redirecting to the appropriate owner.
js...@google.com <js...@google.com> #3
So after updating to 1.4.1 and all deps too, the crash was a little different see below.
The repro for that one is easy
- create a new app from AS 7.1 RC 1
- update deps to (Appcompat 1.4.1/Material 1.5.0/Constraintlayout 2.1.3)
- Add 2 textViews
<TextView
android:id="@+id/text1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/text2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/text1" />```
- In onCreate:
val t1 = findViewById<TextView>(R.id.text1)
val t2 = findViewById<TextView>(R.id.text2)
val charBuffer1 = CharArrayBuffer("AAA".toCharArray())
charBuffer1.sizeCopied = 3
val charBuffer2 = CharArrayBuffer("AAA".toCharArray())
charBuffer2.sizeCopied = 3
t1.setText(charBuffer1.data, 0, charBuffer1.sizeCopied)
t2.setText(charBuffer2.data, 0, charBuffer2.sizeCopied)
- Run see the texts updated then crash with the following. (Tested on P6 Pro Android 12)
Process: org.debug.myapplication, PID: 32493
java.lang.NullPointerException: src == null
at java.lang.System.arraycopy(Native Method)
at android.widget.TextView$CharWrapper.getChars(TextView.java:13588)
at android.text.TextUtils.getChars(TextUtils.java:155)
at android.text.BoringLayout.hasAnyInterestingChars(BoringLayout.java:314)
at android.text.BoringLayout.isBoring(BoringLayout.java:340)
at android.widget.TextView.onMeasure(TextView.java:9413)
at androidx.appcompat.widget.AppCompatTextView.onMeasure(AppCompatTextView.java:607)
at android.view.View.measure(View.java:25774)
at androidx.constraintlayout.widget.ConstraintLayout$Measurer.measure(ConstraintLayout.java:811)
at androidx.constraintlayout.core.widgets.analyzer.BasicMeasure.measure(BasicMeasure.java:466)
at androidx.constraintlayout.core.widgets.analyzer.BasicMeasure.measureChildren(BasicMeasure.java:134)
at androidx.constraintlayout.core.widgets.analyzer.BasicMeasure.solverMeasure(BasicMeasure.java:278)
at androidx.constraintlayout.core.widgets.ConstraintWidgetContainer.measure(ConstraintWidgetContainer.java:120)
at androidx.constraintlayout.widget.ConstraintLayout.resolveSystem(ConstraintLayout.java:1594)
at androidx.constraintlayout.widget.ConstraintLayout.onMeasure(ConstraintLayout.java:1708)
at android.view.View.measure(View.java:25774)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6980)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
at androidx.appcompat.widget.ContentFrameLayout.onMeasure(ContentFrameLayout.java:145)
at android.view.View.measure(View.java:25774)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6980)
at androidx.appcompat.widget.ActionBarOverlayLayout.onMeasure(ActionBarOverlayLayout.java:496)
at android.view.View.measure(View.java:25774)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6980)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
at android.view.View.measure(View.java:25774)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6980)
at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1552)
at android.widget.LinearLayout.measureVertical(LinearLayout.java:842)
at android.widget.LinearLayout.onMeasure(LinearLayout.java:721)
at android.view.View.measure(View.java:25774)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:6980)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
at com.android.internal.policy.DecorView.onMeasure(DecorView.java:761)
at android.view.View.measure(View.java:25774)
at android.view.ViewRootImpl.performMeasure(ViewRootImpl.java:3628)
at android.view.ViewRootImpl.measureHierarchy(ViewRootImpl.java:2424)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2694)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:2143)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:8665)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1037)
at android.view.Choreographer.doCallbacks(Choreographer.java:845)
at android.view.Choreographer.doFrame(Choreographer.java:780)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:1022)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loopOnce(Looper.java:201)
at android.os.Looper.loop(Looper.java:288)
at android.app.ActivityThread.main(ActivityThread.java:7839)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003)
an...@google.com <an...@google.com> #4
since it is possibly related to emojicompat reassigned
js...@google.com <js...@google.com> #5
Thanks for the report.
What version of Android are you testing this on?
js...@google.com <js...@google.com> #6
Android 12 P6 pro P3a and emulator A 11.
Can test on others the last repro is easy to test.
lp...@google.com <lp...@google.com> #7
Thanks! That's helpful to know it's reproing on both 11 and 12 - no need to test on others. We'll have to explore a bit.
js...@google.com <js...@google.com> #8
Any feedback on this? Appcompat 1.6 is around the corner with Android T. Migrating away from CharArrayBuffer is a ton of work to try to keep the huge performance gain it provide for my use case.
an...@google.com <an...@google.com> #9
Going out in next release.
ap...@google.com <ap...@google.com> #10
There's no code workaround that enables emoji and allows that setText overload to be used in the current version.
Other options:
emojiCompatEnabled=false
in your theme will skip emoji processing (please enable it again once fix goes out)- Don't use setText(char[]) (sounds like this is not really an option for you)
- Hold back appcompat upgrade until the fix goes out.
The fix will go out in emoji2:emoji2-views-helpers 1.2-alpha02 so you may be able to bump that dependency early to test it.
js...@google.com <js...@google.com> #11
Branch: androidx-main
commit 297989f164a9913a4c4c90e3fdd571203dca0830
Author: Sean McQuillan <seanmcq@google.com>
Date: Thu Mar 03 13:21:07 2022
Safely process no emoji from TextView$CharWrapper
This avoids calling TextView.setText when the text has not been updated
by emoji2. This has the impact of avoiding an extra text layout on emoji
font loading.
Fixes:
Test: ./gradlew :e2:e2-v-h:cAT
Relnote: "Fix crash when emoji2 loads font and TextView.setText(char[])
was used."
Change-Id: Id511e36ce9a9077309855082de88f00c26024c9d
M emoji2/emoji2-views-helper/src/main/java/androidx/emoji2/viewsintegration/EmojiInputFilter.java
M emoji2/emoji2-views-helper/src/androidTest/java/androidx/emoji2/viewsintegration/EmojiInputFilterTest.java
js...@google.com <js...@google.com> #12
Thanks for the fix I can wait as nothing mandatory in appcompat 1.4 for my use case.
Is there some compatibility matrix between appcompat and emoji ? (Mostly will emoji 1.2 work with app compat 1.4 in case there's blocking stuff to support T and appcompat 1.6?)
an...@google.com <an...@google.com> #13
Great to hear!
I don't have a compat spreadsheet, but 1.2 is going to be 1.1 with bugfixes like this so no concerns here.
Description
TLDR: The
object Button
should be renamedobject ButtonConstants
. Similarly we should probably renameScaffold
,TabRow
,FilledTextField
,OutlinedTextField
(and are there any others?) to follow the same pattern.As per Compose API Council on April 6, 2020, we decided the public constants for any composable
Foo
should go on an object calledFooConstants
instead of an object namedFoo
. The primary motivation is that there is a naming overload/collision such that when you search for a widget by name in AndroidStudio, you would naturally open the wrong object and then get confused by how it worked, although there were also other similar considerations that pushed us in this direction.