Skip to content

Conversation

@Mateusz-Stasielowicz
Copy link

This PR enchances the compose-click module for better detection of the name of tapped compose element.

It introduces two ways of detecting name of the tapped element:

  1. Modifier.opentelemetry - introduces a custom Modifier (similar solution is used by other telemetry SDKs like Datadog and Sentry. Developers can use this modifier to mark a composable element and give it a name. Then the compose-click module will be able to easily find such tapped element and retrieve a name from it.
  2. Modifier.testTag - handling as a fallback to read the TestTag value of tapped element. TestTag is often used for Unit tests and therefore it is useful to take it during composable element name discovery.

(cherry picked from commit 47708dcb8fa804fbbd0bac2573dfb89a3d29b657)
(cherry picked from commit 7e36c1efb2c450051da424d868be2a5fbaad5628)
(cherry picked from commit c2aa0f168f2d01ad3eb8b9eddfb63c21116357dd)
(cherry picked from commit 7883fbdd4bd53a2c41f96fb0a0f1a6db4a27d100)
(cherry picked from commit a088638b217ec60e707adad03c04bbb2be35f8d1)
(cherry picked from commit c2b4483761a40eed2a771e74190c7b25e57f8134)
@codecov
Copy link

codecov bot commented Nov 20, 2025

Codecov Report

❌ Patch coverage is 89.65517% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 63.41%. Comparing base (150491e) to head (7d1f5bb).

Files with missing lines Patch % Lines
...entation/compose/click/ComposeTapTargetDetector.kt 90.00% 0 Missing and 1 partial ⚠️
...rumentation/compose/click/OpentelemetryModifier.kt 83.33% 1 Missing ⚠️
...try/instrumentation/compose/click/TestTagFinder.kt 92.30% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1415      +/-   ##
==========================================
+ Coverage   63.10%   63.41%   +0.30%     
==========================================
  Files         158      160       +2     
  Lines        3128     3154      +26     
  Branches      324      331       +7     
==========================================
+ Hits         1974     2000      +26     
  Misses       1059     1059              
  Partials       95       95              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@breedx-splk
Copy link
Contributor

Relates to #1311.

Does it resolve it? Seems like it probably does....

Comment on lines -70 to +78
var target: LayoutNode? = null

while (queue.isNotEmpty()) {
val node = queue.removeFirst()
if (node.isPlaced && hitTest(node, x, y)) {
target = node
return node
}

queue.addAll(node.zSortedChildren.asMutableList())
}
return target
return null
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At first glance, this appears to be a semantic change. Previously, the code would keep adding children and walking the queue until it found the "last" one that matched -- which I think means that it potentially got more specific. So was this change intentional, and if so, why?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes this change was intentional. For me it seems to be a bug to take the last node.

In my test application when a compose component consists of multiple nodes (i.e. i'm using some UI components from some 3rd party library), this code caused to take the node from the library, but not the node that I define in my application.

In my opinion it should get the top most node.


// Test-only stand-in for the private Compose TestTagElement.
// Must have a private field named `tag` so reflection in the production code finds it.
class TestTagElement(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is interesting. Are users supposed to be able to consume this, because I don't think that this would be published in any consumable artifacts. Maybe it should just be in the main src tree, under some test package, rather than test source?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is for internal unit test of opentelemetry-android compose-click module


every { nodeList[0].zSortedChildren } returns mutableVectorOf(nodeList[1], nodeList[2])
every { nodeList[1].zSortedChildren } returns mutableVectorOf(nodeList[4], nodeList[3])
every { nodeList[1].zSortedChildren } returns mutableVectorOf(nodeList[3], nodeList[4])
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wondering what triggered this change because the idea is that 3 is higher than 4 in z-order and swapping them means 4 is now on top and the assertion on lines 194-199 should fail?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let me check the unit tests again

public static final field VIEW_CLICK_EVENT_NAME Ljava/lang/String;
}

public final class io/opentelemetry/instrumentation/compose/click/OpentelemetryModifierKt {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could this be internal to avoid exposing it to anybody using this module, or does it need to be public?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It has to be public as this is meant to be used on jetpack compose elements defined by application

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants