Skip to content

Capture click events for non-compose views#953

Merged
breedx-splk merged 5 commits into
open-telemetry:mainfrom
cleverchuk:cc/view-click
May 6, 2025
Merged

Capture click events for non-compose views#953
breedx-splk merged 5 commits into
open-telemetry:mainfrom
cleverchuk:cc/view-click

Conversation

@cleverchuk
Copy link
Copy Markdown
Contributor

Fixes #930

Adds android.view.View click capture instrumentation. This instrumentation uses the Window.Callback API to intercept window motion events. During the interception, it walks the view tree to figure out which view was clicked by doing a boundary overlap check of the each view position against the touch position. ComposeView aren't eligible for click capturing in this approach.

@cleverchuk cleverchuk requested a review from a team as a code owner April 17, 2025 16:22
Comment thread instrumentation/view-click/build.gradle.kts Outdated
Comment thread instrumentation/view-click/build.gradle.kts Outdated
return !(x < vx || x > vx + w || y < vy || y > vy + h)
}

private fun isJetpackComposeView(view: View): Boolean = view::class.java.name.startsWith("androidx.compose.ui.platform.ComposeView")
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

if minify is enabled, this might fail? is androidx.compose.ui.platform.ComposeView minified or an exception (Added to proguard etc?)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

yea, the test will fail and result in traversing compose view tree. however, i don't see how an exception will result here.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

that's good, let's just add this to the consumer-rules exception then so we can validate isJetpackComposeView even if minify is enabled?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Not sure, I understand what you're asking. However, it sounds like you're saying I should create a consumer rules with this as the content?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

yes otherwise androidx.compose.ui.platform.ComposeView is gonna be minified and this condition will always return false

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

What if there's another class that implements AbstractComposeView directly?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@bidetofevil it looks like that doesn't exist in the Android compose framework yet and we can address them when that changes?

Comment on lines +73 to +74
builder.put(xCoordinateAttr, view.x.toDouble())
builder.put(yCoordinateAttr, view.y.toDouble())
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

should we also call getLocationInWindow or getLocationOnScreen here?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

i don't think it's necessary here because we're not doing bound checks here.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

ok, i'm not sure if view.x and view.y are relative to the parent or absolute to the window, if its relative to the parent, you'd need getLocationInWindow right otherwise the position will be wrong

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

From what i understand from the doc, it's absolute.

return target
}

private fun isValidClickTarget(view: View): Boolean = view.isClickable && view.isVisible
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

no need for that.

) {
private var windowRef: WeakReference<Window>? = null

private val viewCoordinates = IntArray(2)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The underlying coordinates are Longs - why not go with a Pair<Long, Long>?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

view.getLocationInWindow API demands it.

import android.view.Window.Callback
import androidx.annotation.RequiresApi

class WindowCallbackWrapper(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

You may just be able to annotate the class rather than the methods so it'll detect the creation

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I remember trying that and it not appeasing the sniffer 🤷‍♂️

Copy link
Copy Markdown
Contributor

@bidetofevil bidetofevil left a comment

Choose a reason for hiding this comment

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

LGTM. Some non-blocking comments, but the one about using a data structure that stores Longs instead of Ints for the coordinates is probably a good idea to do before merging.

Copy link
Copy Markdown
Contributor

@breedx-splk breedx-splk left a comment

Choose a reason for hiding this comment

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

Thanks for the contribution!

@breedx-splk breedx-splk merged commit 109de7a into open-telemetry:main May 6, 2025
6 checks passed
@cleverchuk cleverchuk deleted the cc/view-click branch June 17, 2025 14:40
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.

Capture click events for non-compose views

6 participants