From aa0f7f8b82557d3ba0f110dfdccff42b8342334c Mon Sep 17 00:00:00 2001 From: Cris Barreiro Date: Tue, 15 Jul 2025 14:33:02 +0200 Subject: [PATCH 1/2] Add support for reportMetric --- .../app/browser/duckplayer/DuckPlayerJSHelper.kt | 14 ++++++++++++++ .../java/com/duckduckgo/app/pixels/AppPixelName.kt | 1 + .../impl/DuckPlayerScriptsJsMessaging.kt | 1 + 3 files changed, 16 insertions(+) diff --git a/app/src/main/java/com/duckduckgo/app/browser/duckplayer/DuckPlayerJSHelper.kt b/app/src/main/java/com/duckduckgo/app/browser/duckplayer/DuckPlayerJSHelper.kt index 29cdf357bd0b..921b7c843f25 100644 --- a/app/src/main/java/com/duckduckgo/app/browser/duckplayer/DuckPlayerJSHelper.kt +++ b/app/src/main/java/com/duckduckgo/app/browser/duckplayer/DuckPlayerJSHelper.kt @@ -27,6 +27,7 @@ import com.duckduckgo.app.browser.commands.Command.SendResponseToJs import com.duckduckgo.app.browser.commands.Command.SendSubscriptions import com.duckduckgo.app.browser.commands.NavigationCommand.Navigate import com.duckduckgo.app.pixels.AppPixelName +import com.duckduckgo.app.pixels.AppPixelName.DUCK_PLAYER_JS_ERROR import com.duckduckgo.app.pixels.AppPixelName.DUCK_PLAYER_SETTING_ALWAYS_DUCK_PLAYER import com.duckduckgo.app.pixels.AppPixelName.DUCK_PLAYER_SETTING_ALWAYS_OVERLAY_YOUTUBE import com.duckduckgo.app.pixels.AppPixelName.DUCK_PLAYER_SETTING_ALWAYS_SERP @@ -291,6 +292,19 @@ class DuckPlayerJSHelper @Inject constructor( pixel.fire(impressionPixelName) pixel.fire(dailyPixelName, emptyMap(), emptyMap(), Daily()) } + "reportMetric" -> { + try { + val params = data?.getJSONObject("params") ?: return null + val message = params.getString("message") ?: return null + val kind = params.getString("kind") ?: return null + pixel.fire( + DUCK_PLAYER_JS_ERROR, + mapOf("message" to message, "kind" to kind, "origin" to featureName), + ) + } catch (e: Exception) { + logcat { "Error reporting metric: $e" } + } + } else -> { return null } diff --git a/app/src/main/java/com/duckduckgo/app/pixels/AppPixelName.kt b/app/src/main/java/com/duckduckgo/app/pixels/AppPixelName.kt index fa799920915b..a804b5737947 100644 --- a/app/src/main/java/com/duckduckgo/app/pixels/AppPixelName.kt +++ b/app/src/main/java/com/duckduckgo/app/pixels/AppPixelName.kt @@ -408,6 +408,7 @@ enum class AppPixelName(override val pixelName: String) : Pixel.PixelName { DUCK_PLAYER_YOUTUBE_ERROR_AGE_RESTRICTED_DAILY_UNIQUE("duckplayer_youtube-age-restricted-error_daily-unique"), DUCK_PLAYER_YOUTUBE_ERROR_NO_EMBED_DAILY_UNIQUE("duckplayer_youtube-no-embed-error_daily-unique"), DUCK_PLAYER_YOUTUBE_ERROR_UNKNOWN_DAILY_UNIQUE("duckplayer_youtube-unknown-error_daily-unique"), + DUCK_PLAYER_JS_ERROR("duckplayer_js-error"), MALICIOUS_SITE_PROTECTION_SETTING_TOGGLED("m_malicious-site-protection_feature-toggled"), MALICIOUS_SITE_PROTECTION_VISIT_SITE("m_malicious-site-protection_visit-site"), diff --git a/duckplayer/duckplayer-impl/src/main/java/com/duckduckgo/duckplayer/impl/DuckPlayerScriptsJsMessaging.kt b/duckplayer/duckplayer-impl/src/main/java/com/duckduckgo/duckplayer/impl/DuckPlayerScriptsJsMessaging.kt index 601effde7955..cc1ed8cafba5 100644 --- a/duckplayer/duckplayer-impl/src/main/java/com/duckduckgo/duckplayer/impl/DuckPlayerScriptsJsMessaging.kt +++ b/duckplayer/duckplayer-impl/src/main/java/com/duckduckgo/duckplayer/impl/DuckPlayerScriptsJsMessaging.kt @@ -129,6 +129,7 @@ class DuckPlayerScriptsJsMessaging @Inject constructor( "openSettings", "openInfo", "setUserValues", + "reportMetric", "reportPageException", "reportInitException", "reportYouTubeError", From 61f96229a07d741210a5325f92ac04d170b7ffb3 Mon Sep 17 00:00:00 2001 From: Cris Barreiro Date: Thu, 17 Jul 2025 16:44:38 +0200 Subject: [PATCH 2/2] Extract handler --- .../browser/duckplayer/DuckPlayerJSHelper.kt | 14 -------- .../com/duckduckgo/app/pixels/AppPixelName.kt | 1 - .../duckplayer/impl/DuckPlayerPixelName.kt | 1 + .../impl/DuckPlayerScriptsJsMessaging.kt | 34 ++++++++++++++++++- 4 files changed, 34 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/com/duckduckgo/app/browser/duckplayer/DuckPlayerJSHelper.kt b/app/src/main/java/com/duckduckgo/app/browser/duckplayer/DuckPlayerJSHelper.kt index 921b7c843f25..29cdf357bd0b 100644 --- a/app/src/main/java/com/duckduckgo/app/browser/duckplayer/DuckPlayerJSHelper.kt +++ b/app/src/main/java/com/duckduckgo/app/browser/duckplayer/DuckPlayerJSHelper.kt @@ -27,7 +27,6 @@ import com.duckduckgo.app.browser.commands.Command.SendResponseToJs import com.duckduckgo.app.browser.commands.Command.SendSubscriptions import com.duckduckgo.app.browser.commands.NavigationCommand.Navigate import com.duckduckgo.app.pixels.AppPixelName -import com.duckduckgo.app.pixels.AppPixelName.DUCK_PLAYER_JS_ERROR import com.duckduckgo.app.pixels.AppPixelName.DUCK_PLAYER_SETTING_ALWAYS_DUCK_PLAYER import com.duckduckgo.app.pixels.AppPixelName.DUCK_PLAYER_SETTING_ALWAYS_OVERLAY_YOUTUBE import com.duckduckgo.app.pixels.AppPixelName.DUCK_PLAYER_SETTING_ALWAYS_SERP @@ -292,19 +291,6 @@ class DuckPlayerJSHelper @Inject constructor( pixel.fire(impressionPixelName) pixel.fire(dailyPixelName, emptyMap(), emptyMap(), Daily()) } - "reportMetric" -> { - try { - val params = data?.getJSONObject("params") ?: return null - val message = params.getString("message") ?: return null - val kind = params.getString("kind") ?: return null - pixel.fire( - DUCK_PLAYER_JS_ERROR, - mapOf("message" to message, "kind" to kind, "origin" to featureName), - ) - } catch (e: Exception) { - logcat { "Error reporting metric: $e" } - } - } else -> { return null } diff --git a/app/src/main/java/com/duckduckgo/app/pixels/AppPixelName.kt b/app/src/main/java/com/duckduckgo/app/pixels/AppPixelName.kt index a804b5737947..fa799920915b 100644 --- a/app/src/main/java/com/duckduckgo/app/pixels/AppPixelName.kt +++ b/app/src/main/java/com/duckduckgo/app/pixels/AppPixelName.kt @@ -408,7 +408,6 @@ enum class AppPixelName(override val pixelName: String) : Pixel.PixelName { DUCK_PLAYER_YOUTUBE_ERROR_AGE_RESTRICTED_DAILY_UNIQUE("duckplayer_youtube-age-restricted-error_daily-unique"), DUCK_PLAYER_YOUTUBE_ERROR_NO_EMBED_DAILY_UNIQUE("duckplayer_youtube-no-embed-error_daily-unique"), DUCK_PLAYER_YOUTUBE_ERROR_UNKNOWN_DAILY_UNIQUE("duckplayer_youtube-unknown-error_daily-unique"), - DUCK_PLAYER_JS_ERROR("duckplayer_js-error"), MALICIOUS_SITE_PROTECTION_SETTING_TOGGLED("m_malicious-site-protection_feature-toggled"), MALICIOUS_SITE_PROTECTION_VISIT_SITE("m_malicious-site-protection_visit-site"), diff --git a/duckplayer/duckplayer-impl/src/main/java/com/duckduckgo/duckplayer/impl/DuckPlayerPixelName.kt b/duckplayer/duckplayer-impl/src/main/java/com/duckduckgo/duckplayer/impl/DuckPlayerPixelName.kt index 0a902cc3fbaf..3202d63f8ecf 100644 --- a/duckplayer/duckplayer-impl/src/main/java/com/duckduckgo/duckplayer/impl/DuckPlayerPixelName.kt +++ b/duckplayer/duckplayer-impl/src/main/java/com/duckduckgo/duckplayer/impl/DuckPlayerPixelName.kt @@ -33,4 +33,5 @@ enum class DuckPlayerPixelName(override val pixelName: String) : Pixel.PixelName DUCK_PLAYER_SETTINGS_PRESSED("duckplayer_setting_pressed"), DUCK_PLAYER_NEWTAB_SETTING_ON("duckplayer_newtab_setting-on"), DUCK_PLAYER_NEWTAB_SETTING_OFF("duckplayer_newtab_setting-off"), + DUCK_PLAYER_JS_ERROR("duckplayer_js-error"), } diff --git a/duckplayer/duckplayer-impl/src/main/java/com/duckduckgo/duckplayer/impl/DuckPlayerScriptsJsMessaging.kt b/duckplayer/duckplayer-impl/src/main/java/com/duckduckgo/duckplayer/impl/DuckPlayerScriptsJsMessaging.kt index cc1ed8cafba5..18c1771e9424 100644 --- a/duckplayer/duckplayer-impl/src/main/java/com/duckduckgo/duckplayer/impl/DuckPlayerScriptsJsMessaging.kt +++ b/duckplayer/duckplayer-impl/src/main/java/com/duckduckgo/duckplayer/impl/DuckPlayerScriptsJsMessaging.kt @@ -19,9 +19,11 @@ package com.duckduckgo.duckplayer.impl import android.webkit.JavascriptInterface import android.webkit.WebView import androidx.core.net.toUri +import com.duckduckgo.app.statistics.pixels.Pixel import com.duckduckgo.common.utils.DispatcherProvider import com.duckduckgo.common.utils.extensions.toTldPlusOne import com.duckduckgo.di.scopes.ActivityScope +import com.duckduckgo.duckplayer.impl.DuckPlayerPixelName.DUCK_PLAYER_JS_ERROR import com.duckduckgo.js.messaging.api.JsCallbackData import com.duckduckgo.js.messaging.api.JsMessage import com.duckduckgo.js.messaging.api.JsMessageCallback @@ -44,6 +46,7 @@ class DuckPlayerScriptsJsMessaging @Inject constructor( private val jsMessageHelper: JsMessageHelper, private val dispatcherProvider: DispatcherProvider, private val duckPlayer: DuckPlayerInternal, + pixel: Pixel, ) : JsMessaging { private val moshi = Moshi.Builder().add(JSONObjectAdapter()).build() @@ -52,6 +55,8 @@ class DuckPlayerScriptsJsMessaging @Inject constructor( private val handlers = listOf( DuckPlayerPageHandler(), + DuckPlayerReportMetricHandler(pixel), + DuckPlayerPageReportMetricHandler(pixel), ) @JavascriptInterface @@ -129,10 +134,37 @@ class DuckPlayerScriptsJsMessaging @Inject constructor( "openSettings", "openInfo", "setUserValues", - "reportMetric", "reportPageException", "reportInitException", "reportYouTubeError", ) } + + internal interface GenericDuckPlayerReportMetricHandler : JsMessageHandler { + val pixel: Pixel + + override fun process(jsMessage: JsMessage, secret: String, jsMessageCallback: JsMessageCallback?) { + try { + val params = jsMessage.params.getJSONObject("params") + val message = params.getString("message") ?: return + val kind = params.getString("kind") ?: return + pixel.fire(DUCK_PLAYER_JS_ERROR, mapOf("message" to message, "kind" to kind, "origin" to featureName)) + } catch (e: Exception) { + logcat { "Error reporting metric: $e" } + } + } + } + + inner class DuckPlayerReportMetricHandler(override val pixel: Pixel) : GenericDuckPlayerReportMetricHandler { + + override val allowedDomains: List = listOf(runBlocking { duckPlayer.getYouTubeEmbedUrl() }) + override val featureName: String = "duckPlayer" + override val methods: List = listOf("reportMetric") + } + + inner class DuckPlayerPageReportMetricHandler(override val pixel: Pixel) : GenericDuckPlayerReportMetricHandler { + override val allowedDomains: List = listOf(runBlocking { duckPlayer.getYouTubeEmbedUrl() }) + override val featureName: String = "duckPlayerPage" + override val methods: List = listOf("reportMetric") + } }