element-x-android icon indicating copy to clipboard operation
element-x-android copied to clipboard

Compose 1.7.0 crashes the composer

Open jmartinesp opened this issue 1 year ago • 5 comments

Contents

This is an issue to describe what's happening when trying to update to the latest Compose BOM. It seems like the new Compose version is having issues with handling focus between Android Views <--> Compose components.

Ideally we should find a solution for this, but if it can't be done maybe we'll need to simplify the UI somehow.

Steps to reproduce

  1. Use https://github.com/element-hq/element-x-android/pull/3399.
  2. Go into a room, change into the RTE mode. Notice the focus can take a while to be applied to the edit text.
  3. Then close the rich text mode.

Outcome

What did you expect?

The plain text/markdown mode should be displayed back.

What happened instead?

The app crashes with:

Thread: main, Exception: java.lang.IllegalArgumentException: performMeasureAndLayout called during measure layout
at androidx.compose.ui.internal.InlineClassHelperKt.throwIllegalArgumentException(InlineClassHelper.kt:34)
at androidx.compose.ui.node.MeasureAndLayoutDelegate.measureAndLayout-0kLqBqw(MeasureAndLayoutDelegate.kt:874)
at androidx.compose.ui.platform.AndroidComposeView.measureAndLayout-0kLqBqw(AndroidComposeView.android.kt:1285)
at androidx.compose.ui.node.LayoutNode.forceRemeasure(LayoutNode.kt:1295)
at androidx.compose.foundation.lazy.LazyListBeyondBoundsState.remeasure(LazyListBeyondBoundsModifier.kt:39)
at androidx.compose.foundation.lazy.layout.LazyLayoutBeyondBoundsModifierLocal.layout-o7g1Pn8(LazyLayoutBeyondBoundsModifierLocal.kt:108)
at androidx.compose.ui.focus.BeyondBoundsLayoutKt.searchBeyondBounds--OM-vw8(BeyondBoundsLayout.kt:45)
at androidx.compose.ui.focus.TwoDimensionalFocusSearchKt.generateAndSearchChildren-4C6V_qg(TwoDimensionalFocusSearch.kt:160)
at androidx.compose.ui.focus.TwoDimensionalFocusSearchKt.searchChildren-4C6V_qg(TwoDimensionalFocusSearch.kt:188)
at androidx.compose.ui.focus.TwoDimensionalFocusSearchKt.generateAndSearchChildren-4C6V_qg(TwoDimensionalFocusSearch.kt:155)
at androidx.compose.ui.focus.TwoDimensionalFocusSearchKt.twoDimensionalFocusSearch-sMXa3k8(TwoDimensionalFocusSearch.kt:81)
at androidx.compose.ui.focus.FocusTraversalKt.focusSearch-0X8WOeE(FocusTraversal.kt:109)
at androidx.compose.ui.focus.FocusOwnerImpl.focusSearch-ULY8qGw(FocusOwnerImpl.kt:247)
at androidx.compose.ui.platform.AndroidComposeView.focusSearch(AndroidComposeView.android.kt:855)
at android.view.ViewGroup.focusSearch(ViewGroup.java:1081)
at android.view.ViewGroup.focusSearch(ViewGroup.java:1081)
at android.view.View.focusSearch(View.java:13798)
at android.widget.TextView.hasEditorInFocusSearchDirection(TextView.java:9722)
at android.widget.TextView.onCreateInputConnection(TextView.java:9748)
at androidx.appcompat.widget.AppCompatEditText.onCreateInputConnection(AppCompatEditText.java:270)
at android.view.inputmethod.InputMethodManager.createInputConnection(InputMethodManager.java:4448)
at android.view.inputmethod.InputMethodManager.startInputInner(InputMethodManager.java:2735)
at android.view.inputmethod.InputMethodManager.startInputOnWindowFocusGainInternal(InputMethodManager.java:976)
at android.view.inputmethod.InputMethodManager.checkFocus(InputMethodManager.java:3005)
at android.view.inputmethod.InputMethodManager.restartInput(InputMethodManager.java:2584)
at android.widget.TextView.setKeyListener(TextView.java:2694)
at androidx.appcompat.widget.AppCompatEditText.initEmojiKeyListener(AppCompatEditText.java:151)
at androidx.appcompat.widget.AppCompatEditText.(AppCompatEditText.java:117)
at androidx.appcompat.widget.AppCompatEditText.(AppCompatEditText.java:96)
at androidx.appcompat.widget.AppCompatEditText.(AppCompatEditText.java:92)
at io.element.android.libraries.textcomposer.components.markdown.MarkdownEditText.(MarkdownEditText.kt:24)
at io.element.android.libraries.textcomposer.components.markdown.MarkdownTextInputKt$MarkdownTextInput$1$1.invoke(MarkdownTextInput.kt:93)
at io.element.android.libraries.textcomposer.components.markdown.MarkdownTextInputKt$MarkdownTextInput$1$1.invoke(MarkdownTextInput.kt:92)
at androidx.compose.ui.viewinterop.ViewFactoryHolder.(AndroidView.android.kt:344)
at androidx.compose.ui.viewinterop.AndroidView_androidKt$createAndroidViewNodeFactory$1$1.invoke(AndroidView.android.kt:275)
at androidx.compose.ui.viewinterop.AndroidView_androidKt$createAndroidViewNodeFactory$1$1.invoke(AndroidView.android.kt:274)
at androidx.compose.runtime.changelist.Operation$InsertNodeFixup.execute(Operation.kt:583)
at androidx.compose.runtime.changelist.Operations.executeAndFlushAllPendingOperations(Operations.kt:309)
at androidx.compose.runtime.changelist.FixupList.executeAndFlushAllPendingFixups(FixupList.kt:50)
at androidx.compose.runtime.changelist.Operation$InsertSlotsWithFixups.execute(Operation.kt:550)
at androidx.compose.runtime.changelist.Operations.executeAndFlushAllPendingOperations(Operations.kt:309)
at androidx.compose.runtime.changelist.ChangeList.executeAndFlushAllPendingChanges(ChangeList.kt:81)
at androidx.compose.runtime.CompositionImpl.applyChangesInLocked(Composition.kt:984)
at androidx.compose.runtime.CompositionImpl.applyChanges(Composition.kt:1013)
at androidx.compose.runtime.Recomposer.composeInitial$runtime_release(Recomposer.kt:1150)
at androidx.compose.runtime.ComposerImpl$CompositionContextImpl.composeInitial$runtime_release(Composer.kt:3874)
at androidx.compose.runtime.ComposerImpl$CompositionContextImpl.composeInitial$runtime_release(Composer.kt:3874)
at androidx.compose.runtime.CompositionImpl.composeInitial(Composition.kt:649)
at androidx.compose.runtime.CompositionImpl.setContent(Composition.kt:635)
at androidx.compose.ui.layout.LayoutNodeSubcompositionsState.subcomposeInto(SubcomposeLayout.kt:516)
at androidx.compose.ui.layout.LayoutNodeSubcompositionsState.subcompose(SubcomposeLayout.kt:488)
at androidx.compose.ui.layout.LayoutNodeSubcompositionsState.subcompose(SubcomposeLayout.kt:479)
at androidx.compose.ui.layout.LayoutNodeSubcompositionsState.subcompose(SubcomposeLayout.kt:463)
at androidx.compose.ui.layout.LayoutNodeSubcompositionsState$Scope.subcompose(SubcomposeLayout.kt:895)
at io.element.android.features.messages.impl.ExpandableBottomSheetScaffoldKt$ExpandableBottomSheetScaffold$2$1.invoke-0kLqBqw(ExpandableBottomSheetScaffold.kt:124)
at io.element.android.features.messages.impl.ExpandableBottomSheetScaffoldKt$ExpandableBottomSheetScaffold$2$1.invoke(ExpandableBottomSheetScaffold.kt:123)
at androidx.compose.ui.layout.LayoutNodeSubcompositionsState$createMeasurePolicy$1.measure-3p2s80s(SubcomposeLayout.kt:725)
at androidx.compose.ui.node.InnerNodeCoordinator.measure-BRTryo0(InnerNodeCoordinator.kt:135)
at androidx.compose.ui.node.LayoutNodeLayoutDelegate$performMeasureBlock$1.invoke(LayoutNodeLayoutDelegate.kt:316)
at androidx.compose.ui.node.LayoutNodeLayoutDelegate$performMeasureBlock$1.invoke(LayoutNodeLayoutDelegate.kt:315)
at androidx.compose.runtime.snapshots.Snapshot$Companion.observe(Snapshot.kt:2441)
at androidx.compose.runtime.snapshots.SnapshotStateObserver$ObservedScopeMap.observe(SnapshotStateObserver.kt:502)
at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.kt:258)
at androidx.compose.ui.node.OwnerSnapshotObserver.observeReads$ui_release(OwnerSnapshotObserver.kt:133)
at androidx.compose.ui.node.OwnerSnapshotObserver.observeMeasureSnapshotReads$ui_release(OwnerSnapshotObserver.kt:113)
at androidx.compose.ui.node.LayoutNodeLayoutDelegate.performMeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:1775)
at androidx.compose.ui.node.LayoutNodeLayoutDelegate.access$performMeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:40)
at androidx.compose.ui.node.LayoutNodeLayoutDelegate$MeasurePassDelegate.remeasure-BRTryo0(LayoutNodeLayoutDelegate.kt:696)
at androidx.compose.ui.node.LayoutNode.remeasure-_Sx5XlM$ui_release(LayoutNode.kt:1221)
at androidx.compose.ui.node.LayoutNode.remeasure-_Sx5XlM$ui_release$default(LayoutNode.kt:1212)
at androidx.compose.ui.node.MeasureAndLayoutDelegate.doRemeasure-sdFAvZA(MeasureAndLayoutDelegate.kt:369)
at androidx.compose.ui.node.MeasureAndLayoutDelegate.remeasureAndRelayoutIfNeeded(MeasureAndLayoutDelegate.kt:566)
at androidx.compose.ui.node.MeasureAndLayoutDelegate.remeasureAndRelayoutIfNeeded$default(MeasureAndLayoutDelegate.kt:534)
at androidx.compose.ui.node.MeasureAndLayoutDelegate.measureAndLayout(MeasureAndLayoutDelegate.kt:390)
at androidx.compose.ui.platform.AndroidComposeView.measureAndLayout(AndroidComposeView.android.kt:1273)
at androidx.compose.ui.node.Owner.measureAndLayout$default(Owner.kt:248)
at androidx.compose.ui.platform.AndroidComposeView.dispatchDraw(AndroidComposeView.android.kt:1555)
at android.view.View.draw(View.java:23923)
at android.view.View.updateDisplayListIfDirty(View.java:22787)
at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:4543)
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:4516)
at android.view.View.updateDisplayListIfDirty(View.java:22743)
at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:4543)
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:4516)
at android.view.View.updateDisplayListIfDirty(View.java:22743)
at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:4543)
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:4516)
at android.view.View.updateDisplayListIfDirty(View.java:22743)
at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:4543)
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:4516)
at android.view.View.updateDisplayListIfDirty(View.java:22743)
at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:4543)
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:4516)
at android.view.View.updateDisplayListIfDirty(View.java:22743)
at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:4543)
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:4516)
at android.view.View.updateDisplayListIfDirty(View.java:22743)
at android.view.ThreadedRenderer.updateViewTreeDisplayList(ThreadedRenderer.java:706)
at android.view.ThreadedRenderer.updateRootDisplayList(ThreadedRenderer.java:712)
at android.view.ThreadedRenderer.draw(ThreadedRenderer.java:810)
at android.view.ViewRootImpl.draw(ViewRootImpl.java:5144)
at android.view.ViewRootImpl.performDraw(ViewRootImpl.java:4835)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:4011)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:2650)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:9529)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1343)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1352)
at android.view.Choreographer.doCallbacks(Choreographer.java:952)
at android.view.Choreographer.doFrame(Choreographer.java:882)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:1326)
at android.os.Handler.handleCallback(Handler.java:958)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loopOnce(Looper.java:205)
at android.os.Looper.loop(Looper.java:294)
at android.app.ActivityThread.main(ActivityThread.java:8282)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:554)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:885)

Your phone model

Xiaomi Mi 9T

Operating system version

Android 14

Application version and app store

No response

Homeserver

No response

Will you send logs?

Yes

Are you willing to provide a PR?

Yes

jmartinesp avatar Sep 06 '24 10:09 jmartinesp

Apparently this can be worked around by overriding this in MarkdownEditText:

override fun focusSearch(direction: Int): View? {
    return null
}

Although I'm not sure about the implications. It should be fine since we don't care about the next focused view at all in this component.

jmartinesp avatar Sep 06 '24 11:09 jmartinesp

Will you apply this patch on #3399?

bmarty avatar Sep 18 '24 08:09 bmarty

Yes, it's already in use there.

jmartinesp avatar Sep 18 '24 08:09 jmartinesp

Hello @jmartinesp I believe that we can we close this issue?

bmarty avatar Apr 24 '25 14:04 bmarty

I think the workaround is not even needed with Compose 1.8.0.

jmartinesp avatar Apr 24 '25 15:04 jmartinesp