11package io .sentry .compose .viewhierarchy ;
22
33import androidx .compose .runtime .collection .MutableVector ;
4+ import androidx .compose .ui .Modifier ;
45import androidx .compose .ui .geometry .Rect ;
56import androidx .compose .ui .layout .ModifierInfo ;
67import androidx .compose .ui .node .LayoutNode ;
1415import io .sentry .internal .viewhierarchy .ViewHierarchyExporter ;
1516import io .sentry .protocol .ViewHierarchyNode ;
1617import io .sentry .util .AutoClosableReentrantLock ;
18+ import java .lang .reflect .Field ;
1719import java .util .ArrayList ;
1820import java .util .List ;
1921import java .util .Map ;
@@ -84,9 +86,13 @@ private static void addChild(
8486
8587 private static void setTag (
8688 final @ NotNull LayoutNode node , final @ NotNull ViewHierarchyNode vhNode ) {
89+ // needs to be in-sync with ComposeGestureTargetLocator
8790 final List <ModifierInfo > modifiers = node .getModifierInfo ();
8891 for (ModifierInfo modifierInfo : modifiers ) {
89- if (modifierInfo .getModifier () instanceof SemanticsModifier ) {
92+ final @ NotNull Modifier modifier = modifierInfo .getModifier ();
93+ // Newer Jetpack Compose 1.5 uses Node modifier elements
94+ final @ Nullable String type = modifier .getClass ().getCanonicalName ();
95+ if (modifier instanceof SemanticsModifier ) {
9096 final SemanticsModifier semanticsModifierCore =
9197 (SemanticsModifier ) modifierInfo .getModifier ();
9298 final SemanticsConfiguration semanticsConfiguration =
@@ -99,6 +105,21 @@ private static void setTag(
99105 }
100106 }
101107 }
108+ } else if ("androidx.compose.ui.platform.TestTagElement" .equals (type )
109+ || "io.sentry.compose.SentryModifier.SentryTagModifierNodeElement" .equals (type )) {
110+ // Newer Jetpack Compose uses TestTagElement as node elements
111+ // See
112+ // https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:compose/ui/ui/src/commonMain/kotlin/androidx/compose/ui/platform/TestTag.kt;l=34;drc=dcaa116fbfda77e64a319e1668056ce3b032469f
113+ try {
114+ final Field tagField = modifier .getClass ().getDeclaredField ("tag" );
115+ tagField .setAccessible (true );
116+ final @ Nullable Object value = tagField .get (modifier );
117+ if (value instanceof String ) {
118+ vhNode .setTag ((String ) value );
119+ }
120+ } catch (Throwable e ) {
121+ // ignored
122+ }
102123 }
103124 }
104125 }
0 commit comments