Skip to content

Commit

Permalink
Fix testTag not working for Jetpack Compose gesture detection (#3878)
Browse files Browse the repository at this point in the history
* Fix testTag not working in new versions of Jetpack Compose

* Ensure field is accessible

* Update changelog

* Fix use getDeclaredField instead of getField
  • Loading branch information
markushi authored Nov 27, 2024
1 parent faa4779 commit 262123a
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 1 deletion.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Changelog

## Unreleased

### Fixes

- Fix testTag not working for Jetpack Compose user interaction tracking ([#3878](https://github.com/getsentry/sentry-java/pull/3878))

## 7.18.0

### Features
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.sentry.compose.gestures;

import androidx.compose.ui.Modifier;
import androidx.compose.ui.geometry.Rect;
import androidx.compose.ui.layout.ModifierInfo;
import androidx.compose.ui.node.LayoutNode;
Expand All @@ -13,6 +14,7 @@
import io.sentry.compose.helper.BuildConfig;
import io.sentry.internal.gestures.GestureTargetLocator;
import io.sentry.internal.gestures.UiElement;
import java.lang.reflect.Field;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
Expand Down Expand Up @@ -90,13 +92,28 @@ public ComposeGestureTargetLocator(final @NotNull ILogger logger) {
}
}
} else {
final @NotNull Modifier modifier = modifierInfo.getModifier();
// Newer Jetpack Compose 1.5 uses Node modifiers for clicks/scrolls
final @Nullable String type = modifierInfo.getModifier().getClass().getCanonicalName();
final @Nullable String type = modifier.getClass().getCanonicalName();
if ("androidx.compose.foundation.ClickableElement".equals(type)
|| "androidx.compose.foundation.CombinedClickableElement".equals(type)) {
isClickable = true;
} else if ("androidx.compose.foundation.ScrollingLayoutElement".equals(type)) {
isScrollable = true;
} else if ("androidx.compose.ui.platform.TestTagElement".equals(type)) {
// Newer Jetpack Compose uses TestTagElement as node elements
// See
// 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
try {
final Field tagField = modifier.getClass().getDeclaredField("tag");
tagField.setAccessible(true);
final @Nullable Object value = tagField.get(modifier);
if (value instanceof String) {
lastKnownTag = (String) value;
}
} catch (Throwable e) {
// ignored
}
}
}
}
Expand Down
1 change: 1 addition & 0 deletions sentry-compose/proguard-rules.pro
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
-keepnames class androidx.compose.foundation.ClickableElement
-keepnames class androidx.compose.foundation.CombinedClickableElement
-keepnames class androidx.compose.foundation.ScrollingLayoutElement
-keepnames class androidx.compose.ui.platform.TestTagElement { *; }

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

0 comments on commit 262123a

Please sign in to comment.