Skip to content

Commit 262123a

Browse files
authored
Fix testTag not working for Jetpack Compose gesture detection (#3878)
* Fix testTag not working in new versions of Jetpack Compose * Ensure field is accessible * Update changelog * Fix use getDeclaredField instead of getField
1 parent faa4779 commit 262123a

File tree

3 files changed

+25
-1
lines changed

3 files changed

+25
-1
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# Changelog
22

3+
## Unreleased
4+
5+
### Fixes
6+
7+
- Fix testTag not working for Jetpack Compose user interaction tracking ([#3878](https://github.com/getsentry/sentry-java/pull/3878))
8+
39
## 7.18.0
410

511
### Features

sentry-compose-helper/src/jvmMain/java/io/sentry/compose/gestures/ComposeGestureTargetLocator.java

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package io.sentry.compose.gestures;
22

3+
import androidx.compose.ui.Modifier;
34
import androidx.compose.ui.geometry.Rect;
45
import androidx.compose.ui.layout.ModifierInfo;
56
import androidx.compose.ui.node.LayoutNode;
@@ -13,6 +14,7 @@
1314
import io.sentry.compose.helper.BuildConfig;
1415
import io.sentry.internal.gestures.GestureTargetLocator;
1516
import io.sentry.internal.gestures.UiElement;
17+
import java.lang.reflect.Field;
1618
import java.util.LinkedList;
1719
import java.util.List;
1820
import java.util.Map;
@@ -90,13 +92,28 @@ public ComposeGestureTargetLocator(final @NotNull ILogger logger) {
9092
}
9193
}
9294
} else {
95+
final @NotNull Modifier modifier = modifierInfo.getModifier();
9396
// Newer Jetpack Compose 1.5 uses Node modifiers for clicks/scrolls
94-
final @Nullable String type = modifierInfo.getModifier().getClass().getCanonicalName();
97+
final @Nullable String type = modifier.getClass().getCanonicalName();
9598
if ("androidx.compose.foundation.ClickableElement".equals(type)
9699
|| "androidx.compose.foundation.CombinedClickableElement".equals(type)) {
97100
isClickable = true;
98101
} else if ("androidx.compose.foundation.ScrollingLayoutElement".equals(type)) {
99102
isScrollable = true;
103+
} else if ("androidx.compose.ui.platform.TestTagElement".equals(type)) {
104+
// Newer Jetpack Compose uses TestTagElement as node elements
105+
// See
106+
// 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
107+
try {
108+
final Field tagField = modifier.getClass().getDeclaredField("tag");
109+
tagField.setAccessible(true);
110+
final @Nullable Object value = tagField.get(modifier);
111+
if (value instanceof String) {
112+
lastKnownTag = (String) value;
113+
}
114+
} catch (Throwable e) {
115+
// ignored
116+
}
100117
}
101118
}
102119
}

sentry-compose/proguard-rules.pro

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
-keepnames class androidx.compose.foundation.ClickableElement
1313
-keepnames class androidx.compose.foundation.CombinedClickableElement
1414
-keepnames class androidx.compose.foundation.ScrollingLayoutElement
15+
-keepnames class androidx.compose.ui.platform.TestTagElement { *; }
1516

1617
# R8 will warn about missing classes if people don't have androidx.compose-navigation on their
1718
# classpath, but this is fine, these classes are used in an internal class which is only used when

0 commit comments

Comments
 (0)