Reorganise gesture instrumentation into separate modules#1841
Reorganise gesture instrumentation into separate modules#1841DavidGrath wants to merge 12 commits into
Conversation
…on module. Added new `OptIn` annotation for the common code
There was a problem hiding this comment.
Pull request overview
This PR reorganizes gesture-related view instrumentation by extracting shared gesture/view utilities into a new instrumentation:common-api area and introducing a dedicated instrumentation:view-scroll module, while updating existing view-click code/tests and shared test utilities accordingly.
Changes:
- Added a new
view-scrollinstrumentation module (implementation, tests, docs, and API surface). - Moved previously
view-click-local gesture/view utility code intoinstrumentation:common-apibehind a new opt-in annotation. - Centralized reusable MotionEvent/test helpers into
test-common(and updated instrumentation tests to import them).
Merge Tier (per repo guidelines): Tier 4 (public API surface changes / new .api files added/updated)
Reviewed changes
Copilot reviewed 22 out of 22 changed files in this pull request and generated 13 comments.
Show a summary per file
| File | Description |
|---|---|
| test-common/src/test/kotlin/io/opentelemetry/android/test/common/ViewTestUtilsTest.kt | Adds package + renames test class to align with new ViewTestUtils packaging. |
| test-common/src/main/kotlin/io/opentelemetry/android/test/common/ViewTestUtils.kt | Moves utilities into the io.opentelemetry.android.test.common package and tweaks formatting/imports. |
| test-common/build.gradle.kts | Adds mocking bundle dependency to support test-common implementations. |
| instrumentation/view-scroll/src/test/kotlin/io/opentelemetry/android/instrumentation/view/scroll/ViewScrollInstrumentationTest.kt | New/ported tests for scroll/fling event emission and attribute assertions. |
| instrumentation/view-scroll/src/main/kotlin/io/opentelemetry/android/instrumentation/view/scroll/WindowCallbackWrapper.kt | Callback wrapper to intercept touch events for scroll instrumentation. |
| instrumentation/view-scroll/src/main/kotlin/io/opentelemetry/android/instrumentation/view/scroll/ViewScrollInstrumentation.kt | New AutoService instrumentation entry point for view scroll. |
| instrumentation/view-scroll/src/main/kotlin/io/opentelemetry/android/instrumentation/view/scroll/ViewScrollEventGenerator.kt | New event generator that turns gesture detector callbacks into OTel log events. |
| instrumentation/view-scroll/src/main/kotlin/io/opentelemetry/android/instrumentation/view/scroll/ViewScrollActivityCallback.kt | Lifecycle callback to start/stop window tracking. |
| instrumentation/view-scroll/README.md | Documents emitted events and attributes for the new module. |
| instrumentation/view-scroll/build.gradle.kts | Declares the new published module and its dependencies. |
| instrumentation/view-scroll/api/view-scroll.api | Adds API dump for the new ViewScrollInstrumentation public surface. |
| instrumentation/view-click/src/test/kotlin/io/opentelemetry/android/instrumentation/view/click/ViewLongPressInstrumentationTest.kt | Updates imports/constants to use new shared test helpers + shared internal constants. |
| instrumentation/view-click/src/test/kotlin/io/opentelemetry/android/instrumentation/view/click/ViewClickInstrumentationTest.kt | Updates imports/constants to use new shared test helpers + shared internal constants. |
| instrumentation/view-click/src/main/kotlin/io/opentelemetry/android/instrumentation/view/click/WindowCallbackWrapper.kt | Marks wrapper with the new internal opt-in annotation. |
| instrumentation/view-click/src/main/kotlin/io/opentelemetry/android/instrumentation/view/click/ViewClickInstrumentation.kt | Switches to the new internal opt-in annotation + common-api dependency. |
| instrumentation/view-click/src/main/kotlin/io/opentelemetry/android/instrumentation/view/click/ViewClickEventGenerator.kt | Replaces in-file view traversal/helpers with common-api equivalents; removes scroll/fling logic from click generator. |
| instrumentation/view-click/src/main/kotlin/io/opentelemetry/android/instrumentation/view/click/ViewClickActivityCallback.kt | Marks lifecycle callback with the new internal opt-in annotation. |
| instrumentation/view-click/src/main/kotlin/io/opentelemetry/android/instrumentation/view/click/internal/ViewUtils.kt | Deletes old, module-local constants/helpers now moved to common-api. |
| instrumentation/view-click/build.gradle.kts | Adds dependency on instrumentation:common-api. |
| instrumentation/common-api/src/main/java/io/opentelemetry/android/instrumentation/internal/ViewUtils.kt | New shared constants, gesture model, and view hit-testing helpers (currently public ABI). |
| instrumentation/common-api/src/main/java/io/opentelemetry/android/instrumentation/internal/InternalViewApi.kt | New opt-in annotation intended to restrict cross-module “internal view” APIs. |
| instrumentation/common-api/api/common-api.api | Updates API dump to include newly added symbols from the internal view utilities. |
Comments suppressed due to low confidence (6)
test-common/src/main/kotlin/io/opentelemetry/android/test/common/ViewTestUtils.kt:240
- Minor ktlint/Spotless formatting: add a space after
if.
test-common/src/main/kotlin/io/opentelemetry/android/test/common/ViewTestUtils.kt:60 - The parameter wrapping/indentation for this function signature doesn’t match the surrounding Kotlin formatting used elsewhere in the repo (and may trip Spotless/ktlint). Consider re-wrapping using the standard multiline parameter style.
instrumentation/view-click/src/test/kotlin/io/opentelemetry/android/instrumentation/view/click/ViewLongPressInstrumentationTest.kt:52 - Use
@OptIn(InternalViewApi::class)to opt-in to the internal view APIs used in this test, rather than annotating the test class itself with@InternalViewApi. Also remove the JUnit5@ExtendWithsince it won’t be applied underAndroidJUnit4.
@InternalViewApi
@OptIn(IncubatingApi::class)
@RunWith(AndroidJUnit4::class)
@ExtendWith(MockKExtension::class)
class ViewLongPressInstrumentationTest {
instrumentation/view-scroll/src/test/kotlin/io/opentelemetry/android/instrumentation/view/scroll/ViewScrollInstrumentationTest.kt:24
- This test uses the JUnit4
AndroidJUnit4runner, so the JUnit5MockKExtensionwon’t be applied. Removing themockk-junit5import avoids misleading annotations/dependencies.
instrumentation/view-scroll/src/test/kotlin/io/opentelemetry/android/instrumentation/view/scroll/ViewScrollInstrumentationTest.kt:54 - Since this is a JUnit4 test (
@RunWith(AndroidJUnit4::class)), remove the JUnit5ExtendWithimport/annotation to keep the test configuration consistent.
instrumentation/view-scroll/src/test/kotlin/io/opentelemetry/android/instrumentation/view/scroll/ViewScrollInstrumentationTest.kt:59 - Use
@OptIn(InternalViewApi::class)to opt-in within the test, rather than marking the test class itself as an internal API via@InternalViewApi. Also drop the JUnit5@ExtendWithsince it won’t run underAndroidJUnit4.
| @InternalViewApi | ||
| const val APP_SCREEN_CLICK_EVENT_NAME = "app.screen.click" | ||
|
|
||
| @InternalViewApi | ||
| const val VIEW_CLICK_EVENT_NAME = "app.widget.click" | ||
|
|
||
| @InternalViewApi | ||
| const val APP_SCREEN_LONG_PRESS_EVENT_NAME = "app.screen.longpress" | ||
|
|
||
| @InternalViewApi | ||
| const val VIEW_LONG_PRESS_EVENT_NAME = "app.widget.longpress" | ||
|
|
||
| @InternalViewApi | ||
| const val HARDWARE_POINTER_TYPE = "hw.pointer.type" | ||
|
|
||
| @InternalViewApi | ||
| const val HARDWARE_POINTER_BUTTON = "hw.pointer.button" | ||
|
|
||
| @InternalViewApi | ||
| const val HARDWARE_POINTER_CLICKS = "hw.pointer.clicks" | ||
|
|
||
| @InternalViewApi | ||
| const val APP_SCREEN_SCROLL_EVENT_NAME = "app.screen.scroll" | ||
|
|
||
| @InternalViewApi | ||
| const val VIEW_SCROLL_EVENT_NAME = "app.widget.scroll" | ||
|
|
||
| @InternalViewApi | ||
| const val APP_SCREEN_FLING_EVENT_NAME = "app.screen.fling" | ||
|
|
||
| @InternalViewApi | ||
| const val VIEW_FLING_EVENT_NAME = "app.widget.fling" | ||
|
|
| package io.opentelemetry.android.instrumentation.internal | ||
|
|
||
| /** | ||
| * Strictly for APIs visible to the gestures module | ||
| */ | ||
| @RequiresOptIn(level = RequiresOptIn.Level.ERROR) |
| @InternalViewApi | ||
| override fun install(context: Context, openTelemetryRum: OpenTelemetryRum) { |
| @InternalViewApi | ||
| override fun install(context: Context, openTelemetryRum: OpenTelemetryRum) { |
| */ | ||
|
|
||
|
|
||
| package io.opentelemetry.android.instrumentation.view.scroll |
| @@ -27,12 +24,17 @@ import io.mockk.mockk | |||
| import io.mockk.slot | |||
| import org.junit.Before | ||
| import org.junit.Test | ||
| import org.junit.jupiter.api.extension.ExtendWith | ||
| import org.junit.runner.RunWith |
| @InternalViewApi | ||
| @RunWith(AndroidJUnit4::class) | ||
| @ExtendWith(MockKExtension::class) | ||
| @ExtendWith(MockKExtension::class) //TODO This is a Jupiter annotation. Not needed? | ||
| class ViewClickInstrumentationTest { |
| @@ -22,9 +22,10 @@ import io.mockk.mockk | |||
| import io.mockk.slot | |||
| import org.junit.Before | ||
| import org.junit.Test | ||
| import org.junit.jupiter.api.extension.ExtendWith | ||
| import org.junit.runner.RunWith |
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #1841 +/- ##
==========================================
- Coverage 64.69% 63.18% -1.51%
==========================================
Files 166 171 +5
Lines 3648 3863 +215
Branches 386 409 +23
==========================================
+ Hits 2360 2441 +81
- Misses 1178 1307 +129
- Partials 110 115 +5 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
LikeTheSalad
left a comment
There was a problem hiding this comment.
Thank you! 🙏 I like the idea in general, but I wanted to discuss more about the folder structure and where to put scoped common apis.
There was a problem hiding this comment.
If I understand correctly, this is the only file that needs to be shared across the 2 view-* modules? If that's the case, I think the common-api might be too much of a generic place for it. This is the first time we want to split a couple of instrumentations that share the same "scope", so please bear with me as we go through the process of designing how these use cases should look like.
Ideally, I think we should have a "common-view-scoped" shared module, where we put this ViewUtils type. Regarding the folder structure, what do you think about the following:
instrumentation/
├─ view/
│ ├─ click/
│ ├─ scroll/
│ ├─ common/
There was a problem hiding this comment.
I think this is a cool idea, but I'm not sure it's needed to go this far, given that the package for ViewUtils already contains internal; it should mean to any user that they shouldn't use that type because it can change at any time (we can add an explanatory comment like this one, for example).
There was a problem hiding this comment.
Thanks, I actually like this idea
My initial impression was that the module would be broken down into top-level instrumentations, but putting them under a common module as suggested above actually works better because now I can use internal exclusively. I'll work with that
7e686d4 to
70af8fd
Compare
References #1576
To solve the issue of shared code being exposed, I created a new annotation similar to
Incubating.Also left 2 TODO's to be discussed.
I tried working on the Scale gesture as well, but it became so involved that I decided it should just be a follow-up: I added another module for the sake of working with Robolectric more effectively, amongst other things