Skip to content

Commit 441aa9e

Browse files
kediarovgithub-actions[bot]
authored andcommitted
[compose] Add ui framework metadata to telemetry (#14808)
Fix [MAPSAND-2787](https://mapbox.atlassian.net/browse/MAPSAND-2787) ### Summary - Add `uiFramework` field to the `map.load` telemetry event to distinguish Jetpack Compose vs. View SDK usage - Threads `uiFramework` through `MapInitOptions` → `MapTelemetryImpl` → `MapLoadEvent` so it's included in telemetry payloads - Compose extension sets `UiFramework.JETPACK_COMPOSE`; defaults to `UiFramework.ANDROID_VIEW` - The changelog is not updated as it is internal property ### Context Telemetry currently cannot distinguish whether a map was created via the Jetpack Compose extension or the traditional View API. Adding `uiFramework` to the `map.load` event enables product analytics to track Compose adoption. [MAPSAND-2787]: https://mapbox.atlassian.net/browse/MAPSAND-2787?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ cc @mapbox/maps-android GitOrigin-RevId: 5d6beacd18f8ecbec581a6de57579acf08077fd7
1 parent 3ae52f3 commit 441aa9e

20 files changed

Lines changed: 329 additions & 11 deletions

File tree

extension-compose/build.gradle.kts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,15 @@ android {
99
defaultConfig {
1010
minSdk = libs.versions.androidMinSdkVersion.get().toInt()
1111
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
12+
testInstrumentationRunnerArguments["dexmaker.share_classloader"] = "true"
1213
consumerProguardFiles("proguard-rules.pro")
1314
}
1415

16+
packaging {
17+
resources.excludes += "META-INF/LICENSE.md"
18+
resources.excludes += "META-INF/LICENSE-notice.md"
19+
}
20+
1521
testOptions {
1622
targetSdk = libs.versions.androidTargetSdkVersion.get().toInt()
1723
unitTests.apply {
@@ -79,7 +85,6 @@ dependencies {
7985
implementation(libs.compose.ui)
8086
implementation(libs.compose.material)
8187
implementation(libs.bundles.base.dependencies)
82-
8388
implementation(libs.androidx.coreKtx)
8489
debugImplementation(libs.compose.uiTestManifest)
8590

@@ -92,6 +97,8 @@ dependencies {
9297
androidTestImplementation(libs.androidx.uiAutomator)
9398
androidTestImplementation(project(":maps-sdk"))
9499
androidTestImplementation(libs.compose.uiTest)
100+
androidTestImplementation(libs.mockk.android)
101+
androidTestImplementation(libs.mapbox.annotations)
95102

96103
testImplementation(libs.bundles.base.dependenciesTests)
97104
testImplementation(project(":maps-sdk"))
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
package com.mapbox.maps.extension.compose
2+
3+
import android.os.Bundle
4+
import androidx.compose.ui.test.junit4.ComposeContentTestRule
5+
import androidx.compose.ui.test.junit4.createComposeRule
6+
import com.mapbox.common.module.provider.MapboxModuleProvider
7+
import com.mapbox.maps.module.MapTelemetry
8+
import com.mapbox.maps.module.telemetry.MapTelemetryMetadata
9+
import com.mapbox.maps.module.telemetry.UiFramework
10+
import io.mockk.every
11+
import io.mockk.mockkObject
12+
import io.mockk.unmockkObject
13+
import org.junit.After
14+
import org.junit.Assert.assertEquals
15+
import org.junit.Assert.assertTrue
16+
import org.junit.Before
17+
import org.junit.Rule
18+
import org.junit.Test
19+
20+
/**
21+
* End-to-end instrumented test: composing [MapboxMap] sets [UiFramework.JETPACK_COMPOSE]
22+
* via [com.mapbox.maps.MapInitOptions.uiFramework], and the turnstile event metadata carries
23+
* the correct value.
24+
*/
25+
public class MapboxMapTelemetryTest {
26+
27+
@get:Rule
28+
public val composeTestRule: ComposeContentTestRule = createComposeRule()
29+
30+
private val capturedMetadata = mutableListOf<MapTelemetryMetadata?>()
31+
32+
private val fakeTelemetry: MapTelemetry = object : MapTelemetry {
33+
override fun onAppUserTurnstileEvent() {}
34+
override fun onAppUserTurnstileEvent(metadata: MapTelemetryMetadata?) {
35+
capturedMetadata.add(metadata)
36+
}
37+
override fun setUserTelemetryRequestState(enabled: Boolean) {}
38+
override fun disableTelemetrySession() {}
39+
override fun onPerformanceEvent(data: Bundle?) {}
40+
}
41+
42+
@Before
43+
public fun setUp() {
44+
// MapProvider caches mapTelemetry as a singleton lateinit var. Reset it so the
45+
// MapboxModuleProvider.createModule mock below can inject fakeTelemetry.
46+
val cls = Class.forName("com.mapbox.maps.MapProvider")
47+
val instance = cls.getDeclaredField("INSTANCE").apply { isAccessible = true }.get(null)
48+
cls.getDeclaredField("mapTelemetry").apply { isAccessible = true }.set(instance, null)
49+
}
50+
51+
@After
52+
public fun tearDown() {
53+
unmockkObject(MapboxModuleProvider)
54+
capturedMetadata.clear()
55+
}
56+
57+
@Test
58+
public fun mapboxMap_composable_sends_JETPACK_COMPOSE_in_turnstile_metadata() {
59+
mockkObject(MapboxModuleProvider)
60+
every { MapboxModuleProvider.createModule<Any>(any(), any()) } returns fakeTelemetry
61+
62+
composeTestRule.setContent {
63+
MapboxMap()
64+
}
65+
composeTestRule.waitForIdle()
66+
67+
assertTrue(
68+
"Expected onAppUserTurnstileEvent to be called at least once",
69+
capturedMetadata.isNotEmpty()
70+
)
71+
assertEquals(
72+
UiFramework.JETPACK_COMPOSE,
73+
capturedMetadata.first()?.uiFramework
74+
)
75+
}
76+
}

extension-compose/src/main/java/com/mapbox/maps/extension/compose/ComposeMapInitOptions.kt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import com.mapbox.maps.MapInitOptions
66
import com.mapbox.maps.MapOptions
77
import com.mapbox.maps.MapView
88
import com.mapbox.maps.applyDefaultParams
9+
import com.mapbox.maps.module.telemetry.UiFramework
910
import com.mapbox.maps.plugin.Plugin
1011

1112
/**
@@ -56,7 +57,9 @@ public data class ComposeMapInitOptions(
5657
attrs = null,
5758
antialiasingSampleCount = antialiasingSampleCount,
5859
mapName = mapName
59-
)
60+
).apply {
61+
uiFramework = UiFramework.JETPACK_COMPOSE
62+
}
6063
}
6164

6265
/**

gradle/libs.versions.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ googleCarAppLibrary = "1.2.0"
6363
# Use kotlinCoroutines to 1.6.1 to be compatible with platform runtime.
6464
kotlinCoroutines = "1.6.1"
6565
junit = "4.13.2"
66-
mockk = "1.13.5"
66+
mockk = "1.13.7"
6767
robolectric = "4.14"
6868
robolectricEgl = "gl1.1-android-2.1_r1"
6969
lint = "30.4.2"
@@ -144,6 +144,7 @@ mapbox-gestures = { module = "com.mapbox.mapboxsdk:mapbox-android-gestures", ver
144144
mapbox-geoJSON = { module = "com.mapbox.mapboxsdk:mapbox-sdk-geojson", version.ref = "mapboxGeoJSON" }
145145

146146
mockk = { module = "io.mockk:mockk", version.ref = "mockk" }
147+
mockk-android = { module = "io.mockk:mockk-android", version.ref = "mockk" }
147148

148149
robolectric = { module = "org.robolectric:robolectric", version.ref = "robolectric" }
149150
robolectricEgl = { module = "org.khronos:opengl-api", version.ref = "robolectricEgl" }

maps-sdk/api/Release/metalava.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,13 +48,15 @@ package com.mapbox.maps {
4848
method public java.util.List<com.mapbox.maps.plugin.Plugin> getPlugins();
4949
method public String? getStyleUri();
5050
method public boolean getTextureView();
51+
method public com.mapbox.maps.module.telemetry.UiFramework getUiFramework();
5152
method public void setAntialiasingSampleCount(int);
5253
method public void setAttrs(android.util.AttributeSet?);
5354
method public void setCameraOptions(com.mapbox.maps.CameraOptions?);
5455
method public void setMapName(String);
5556
method public void setMapOptions(com.mapbox.maps.MapOptions);
5657
method public void setPlugins(java.util.List<? extends com.mapbox.maps.plugin.Plugin>);
5758
method public void setTextureView(boolean);
59+
method public void setUiFramework(com.mapbox.maps.module.telemetry.UiFramework);
5860
property public final int antialiasingSampleCount;
5961
property public final android.util.AttributeSet? attrs;
6062
property public final com.mapbox.maps.CameraOptions? cameraOptions;
@@ -64,6 +66,7 @@ package com.mapbox.maps {
6466
property public final java.util.List<com.mapbox.maps.plugin.Plugin> plugins;
6567
property public final String? styleUri;
6668
property public final boolean textureView;
69+
property public final com.mapbox.maps.module.telemetry.UiFramework uiFramework;
6770
field public static final com.mapbox.maps.MapInitOptions.Companion Companion;
6871
}
6972

maps-sdk/api/maps-sdk.api

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ public final class com/mapbox/maps/MapInitOptions {
5353
public final fun getPlugins ()Ljava/util/List;
5454
public final fun getStyleUri ()Ljava/lang/String;
5555
public final fun getTextureView ()Z
56+
public final fun getUiFramework ()Lcom/mapbox/maps/module/telemetry/UiFramework;
5657
public fun hashCode ()I
5758
public final fun setAntialiasingSampleCount (I)V
5859
public final fun setAttrs (Landroid/util/AttributeSet;)V
@@ -61,6 +62,7 @@ public final class com/mapbox/maps/MapInitOptions {
6162
public final fun setMapOptions (Lcom/mapbox/maps/MapOptions;)V
6263
public final fun setPlugins (Ljava/util/List;)V
6364
public final fun setTextureView (Z)V
65+
public final fun setUiFramework (Lcom/mapbox/maps/module/telemetry/UiFramework;)V
6466
public fun toString ()Ljava/lang/String;
6567
}
6668

maps-sdk/src/main/java/com/mapbox/maps/MapController.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,8 @@ internal class MapController : MapPluginProviderDelegate, MapControllable {
119119
mapboxMap,
120120
this,
121121
MapProvider.getMapTelemetryInstance(
122-
mapInitOptions.context
122+
mapInitOptions.context,
123+
mapInitOptions.uiFramework,
123124
),
124125
MapProvider.getMapGeofencingConsent(),
125126
)

maps-sdk/src/main/java/com/mapbox/maps/MapInitOptions.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ package com.mapbox.maps
22

33
import android.content.Context
44
import android.util.AttributeSet
5+
import androidx.annotation.RestrictTo
56
import com.mapbox.maps.MapView.Companion.DEFAULT_ANTIALIASING_SAMPLE_COUNT
7+
import com.mapbox.maps.module.telemetry.UiFramework
68
import com.mapbox.maps.plugin.*
79

810
/**
@@ -35,6 +37,9 @@ data class MapInitOptions @JvmOverloads constructor(
3537
var mapName: String = "",
3638
) {
3739

40+
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX)
41+
var uiFramework: UiFramework = UiFramework.ANDROID_VIEW
42+
3843
/**
3944
* Static methods
4045
*/

maps-sdk/src/main/java/com/mapbox/maps/MapProvider.kt

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import com.mapbox.common.module.provider.ModuleProviderArgument
1111
import com.mapbox.maps.base.BuildConfig
1212
import com.mapbox.maps.geofencing.MapGeofencingConsent
1313
import com.mapbox.maps.module.MapTelemetry
14+
import com.mapbox.maps.module.telemetry.MapTelemetryMetadata
15+
import com.mapbox.maps.module.telemetry.UiFramework
1416
import com.mapbox.maps.plugin.MapDelegateProviderImpl
1517
import com.mapbox.maps.plugin.MapPluginRegistry
1618
import kotlinx.coroutines.CoroutineName
@@ -59,15 +61,22 @@ internal object MapProvider {
5961
mapGeofencingConsent: MapGeofencingConsent,
6062
) = MapPluginRegistry(MapDelegateProviderImpl(mapboxMap, mapController, telemetry, mapGeofencingConsent))
6163

62-
fun getMapTelemetryInstance(context: Context): MapTelemetry {
64+
@JvmOverloads
65+
fun getMapTelemetryInstance(
66+
context: Context,
67+
uiFramework: UiFramework? = null,
68+
): MapTelemetry {
6369
if (!::mapTelemetry.isInitialized) {
6470
mapTelemetry = MapboxModuleProvider.createModule(MapboxModuleType.MapTelemetry) {
6571
paramsProvider(context, MapboxModuleType.MapTelemetry)
6672
}
6773
}
6874
// Schedule the turnstile event on the Main dispatcher to avoid blocking this call chain.
6975
mainScope.launch {
70-
mapTelemetry.onAppUserTurnstileEvent()
76+
val metadata = MapTelemetryMetadata.Builder()
77+
.uiFramework(uiFramework)
78+
.build()
79+
mapTelemetry.onAppUserTurnstileEvent(metadata)
7180
}
7281
return mapTelemetry
7382
}

module-telemetry/api/module-telemetry.api

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ public final class com/mapbox/maps/module/telemetry/MapTelemetryImpl : com/mapbo
22
public fun <init> (Landroid/content/Context;)V
33
public fun disableTelemetrySession ()V
44
public fun onAppUserTurnstileEvent ()V
5+
public fun onAppUserTurnstileEvent (Lcom/mapbox/maps/module/telemetry/MapTelemetryMetadata;)V
56
public fun onPerformanceEvent (Landroid/os/Bundle;)V
67
public fun setUserTelemetryRequestState (Z)V
78
}

0 commit comments

Comments
 (0)