Skip to content

Commit

Permalink
Fire SERP overlay pixels
Browse files Browse the repository at this point in the history
  • Loading branch information
CrisBarreiro committed Aug 27, 2024
1 parent 5a430ad commit 486c20c
Show file tree
Hide file tree
Showing 5 changed files with 133 additions and 23 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -420,6 +420,9 @@ class BrowserTabViewModelTest {
@Mock
private lateinit var mockAppBuildConfig: AppBuildConfig

@Mock
private lateinit var mockDuckDuckGoUrlDetector: DuckDuckGoUrlDetector

private lateinit var remoteMessagingModel: RemoteMessagingModel

private val lazyFaviconManager = Lazy { mockFaviconManager }
Expand Down Expand Up @@ -537,6 +540,7 @@ class BrowserTabViewModelTest {
whenever(mockSSLCertificatesFeature.allowBypass()).thenReturn(mockEnabledToggle)
whenever(mockExtendedOnboardingFeatureToggles.aestheticUpdates()).thenReturn(mockEnabledToggle)
whenever(subscriptions.shouldLaunchPrivacyProForUrl(any())).thenReturn(false)
whenever(mockDuckDuckGoUrlDetector.isDuckDuckGoUrl(any())).thenReturn(false)

remoteMessagingModel = givenRemoteMessagingModel(mockRemoteMessagingRepository, mockPixel, coroutineRule.testDispatcherProvider)

Expand Down Expand Up @@ -649,7 +653,7 @@ class BrowserTabViewModelTest {
newTabPixels = { mockNewTabPixels },
httpErrorPixels = { mockHttpErrorPixels },
duckPlayer = mockDuckPlayer,
duckPlayerJSHelper = DuckPlayerJSHelper(mockDuckPlayer, mockAppBuildConfig, mockPixel),
duckPlayerJSHelper = DuckPlayerJSHelper(mockDuckPlayer, mockAppBuildConfig, mockPixel, mockDuckDuckGoUrlDetector),
)

testee.loadData("abc", null, false, false)
Expand Down Expand Up @@ -4851,7 +4855,13 @@ class BrowserTabViewModelTest {
fun whenProcessJsCallbackMessageWebShareSendCommand() = runTest {
val url = "someUrl"
loadUrl(url)
testee.processJsCallbackMessage("myFeature", "webShare", "myId", JSONObject("""{ "my":"object"}"""))
testee.processJsCallbackMessage(
"myFeature",
"webShare",
"myId",
JSONObject("""{ "my":"object"}"""),
"someUrl",
)
assertCommandIssued<Command.WebShareRequest> {
assertEquals("object", this.data.params.getString("my"))
assertEquals("myFeature", this.data.featureName)
Expand All @@ -4865,7 +4875,13 @@ class BrowserTabViewModelTest {
val url = "someUrl"
loadUrl(url)
whenever(mockSitePermissionsManager.getPermissionsQueryResponse(eq(url), any(), any())).thenReturn(SitePermissionQueryResponse.Granted)
testee.processJsCallbackMessage("myFeature", "permissionsQuery", "myId", JSONObject("""{ "name":"somePermission"}"""))
testee.processJsCallbackMessage(
"myFeature",
"permissionsQuery",
"myId",
JSONObject("""{ "name":"somePermission"}"""),
"someUrl",
)
assertCommandIssued<Command.SendResponseToJs> {
assertEquals("granted", this.data.params.getString("state"))
assertEquals("myFeature", this.data.featureName)
Expand All @@ -4877,14 +4893,26 @@ class BrowserTabViewModelTest {
@Test
fun whenProcessJsCallbackMessageScreenLockNotEnabledDoNotSendCommand() = runTest {
whenever(mockEnabledToggle.isEnabled()).thenReturn(false)
testee.processJsCallbackMessage("myFeature", "screenLock", "myId", JSONObject("""{ "my":"object"}"""))
testee.processJsCallbackMessage(
"myFeature",
"screenLock",
"myId",
JSONObject("""{ "my":"object"}"""),
"someUrl",
)
assertCommandNotIssued<Command.ScreenLock>()
}

@Test
fun whenProcessJsCallbackMessageScreenLockEnabledSendCommand() = runTest {
whenever(mockEnabledToggle.isEnabled()).thenReturn(true)
testee.processJsCallbackMessage("myFeature", "screenLock", "myId", JSONObject("""{ "my":"object"}"""))
testee.processJsCallbackMessage(
"myFeature",
"screenLock",
"myId",
JSONObject("""{ "my":"object"}"""),
"someUrl",
)
assertCommandIssued<Command.ScreenLock> {
assertEquals("object", this.data.params.getString("my"))
assertEquals("myFeature", this.data.featureName)
Expand All @@ -4896,22 +4924,40 @@ class BrowserTabViewModelTest {
@Test
fun whenProcessJsCallbackMessageScreenUnlockNotEnabledDoNotSendCommand() = runTest {
whenever(mockEnabledToggle.isEnabled()).thenReturn(false)
testee.processJsCallbackMessage("myFeature", "screenUnlock", "myId", JSONObject("""{ "my":"object"}"""))
testee.processJsCallbackMessage(
"myFeature",
"screenUnlock",
"myId",
JSONObject("""{ "my":"object"}"""),
"someUrl",
)
assertCommandNotIssued<Command.ScreenUnlock>()
}

@Test
fun whenProcessJsCallbackMessageScreenUnlockEnabledSendCommand() = runTest {
whenever(mockEnabledToggle.isEnabled()).thenReturn(true)
testee.processJsCallbackMessage("myFeature", "screenUnlock", "myId", JSONObject("""{ "my":"object"}"""))
testee.processJsCallbackMessage(
"myFeature",
"screenUnlock",
"myId",
JSONObject("""{ "my":"object"}"""),
"someUrl",
)
assertCommandIssued<Command.ScreenUnlock>()
}

@Test
fun whenProcessJsCallbackMessageGetUserPreferencesFromOverlayThenSendCommand() = runTest {
whenever(mockEnabledToggle.isEnabled()).thenReturn(true)
whenever(mockDuckPlayer.getUserPreferences()).thenReturn(UserPreferences(overlayInteracted = true, privatePlayerMode = AlwaysAsk))
testee.processJsCallbackMessage(DUCK_PLAYER_FEATURE_NAME, "getUserValues", "id", data = null)
testee.processJsCallbackMessage(
DUCK_PLAYER_FEATURE_NAME,
"getUserValues",
"id",
data = null,
"someUrl",
)
assertCommandIssued<Command.SendResponseToJs>()
}

Expand All @@ -4924,6 +4970,7 @@ class BrowserTabViewModelTest {
"setUserValues",
"id",
JSONObject("""{ overlayInteracted: "true", privatePlayerMode: {disabled: {} }}"""),
"someUrl",
)
assertCommandIssued<Command.SendResponseToJs>()
verify(mockDuckPlayer).setUserPreferences(any(), any())
Expand All @@ -4939,6 +4986,7 @@ class BrowserTabViewModelTest {
"setUserValues",
"id",
JSONObject("""{ overlayInteracted: "true", privatePlayerMode: {enabled: {} }}"""),
"someUrl",
)
assertCommandIssued<Command.SendResponseToJs>()
verify(mockDuckPlayer).setUserPreferences(any(), any())
Expand All @@ -4954,6 +5002,7 @@ class BrowserTabViewModelTest {
"setUserValues",
"id",
JSONObject("""{ overlayInteracted: "true", privatePlayerMode: {enabled: {} }}"""),
"someUrl",
)
assertCommandIssued<Command.SendResponseToDuckPlayer>()
verify(mockDuckPlayer).setUserPreferences(true, "enabled")
Expand All @@ -4964,53 +5013,95 @@ class BrowserTabViewModelTest {
fun whenProcessJsCallbackMessageSendDuckPlayerPixelThenSendPixel() = runTest {
whenever(mockEnabledToggle.isEnabled()).thenReturn(true)
whenever(mockDuckPlayer.getUserPreferences()).thenReturn(UserPreferences(overlayInteracted = true, privatePlayerMode = AlwaysAsk))
testee.processJsCallbackMessage(DUCK_PLAYER_FEATURE_NAME, "sendDuckPlayerPixel", "id", JSONObject("""{ pixelName: "pixel", params: {}}"""))
testee.processJsCallbackMessage(
DUCK_PLAYER_FEATURE_NAME,
"sendDuckPlayerPixel",
"id",
JSONObject("""{ pixelName: "pixel", params: {}}"""),
"someUrl",
)
verify(mockDuckPlayer).sendDuckPlayerPixel("pixel", mapOf())
}

@Test
fun whenProcessJsCallbackMessageOpenDuckPlayerWithUrlThenNavigate() = runTest {
whenever(mockEnabledToggle.isEnabled()).thenReturn(true)
whenever(mockDuckPlayer.getUserPreferences()).thenReturn(UserPreferences(overlayInteracted = true, privatePlayerMode = AlwaysAsk))
testee.processJsCallbackMessage(DUCK_PLAYER_FEATURE_NAME, "openDuckPlayer", "id", JSONObject("""{ href: "duck://player/1234" }"""))
testee.processJsCallbackMessage(
DUCK_PLAYER_FEATURE_NAME,
"openDuckPlayer",
"id",
JSONObject("""{ href: "duck://player/1234" }"""),
"someUrl",
)
assertCommandIssued<Navigate>()
}

@Test
fun whenProcessJsCallbackMessageOpenDuckPlayerWithoutUrlThenDoNotNavigate() = runTest {
whenever(mockEnabledToggle.isEnabled()).thenReturn(true)
whenever(mockDuckPlayer.getUserPreferences()).thenReturn(UserPreferences(overlayInteracted = true, privatePlayerMode = AlwaysAsk))
testee.processJsCallbackMessage(DUCK_PLAYER_FEATURE_NAME, "openDuckPlayer", "id", null)
testee.processJsCallbackMessage(
DUCK_PLAYER_FEATURE_NAME,
"openDuckPlayer",
"id",
null,
"someUrl",
)
assertCommandNotIssued<Navigate>()
}

@Test
fun whenJsCallbackMessageInitialSetupFromOverlayThenSendResponseToJs() = runTest {
whenever(mockEnabledToggle.isEnabled()).thenReturn(true)
whenever(mockDuckPlayer.getUserPreferences()).thenReturn(UserPreferences(overlayInteracted = true, privatePlayerMode = AlwaysAsk))
testee.processJsCallbackMessage(DUCK_PLAYER_FEATURE_NAME, "initialSetup", "id", null)
testee.processJsCallbackMessage(
DUCK_PLAYER_FEATURE_NAME,
"initialSetup",
"id",
null,
"someUrl",
)
assertCommandIssued<Command.SendResponseToJs>()
}

@Test
fun whenJsCallbackMessageInitialSetupFromDuckPlayerPageThenSendResponseToDuckPlayer() = runTest {
whenever(mockEnabledToggle.isEnabled()).thenReturn(true)
whenever(mockDuckPlayer.getUserPreferences()).thenReturn(UserPreferences(overlayInteracted = true, privatePlayerMode = AlwaysAsk))
testee.processJsCallbackMessage(DUCK_PLAYER_PAGE_FEATURE_NAME, "initialSetup", "id", null)
testee.processJsCallbackMessage(
DUCK_PLAYER_PAGE_FEATURE_NAME,
"initialSetup",
"id",
null,
"someUrl",
)
assertCommandIssued<Command.SendResponseToDuckPlayer>()
}

@Test
fun whenJsCallbackMessageOpenSettingsThenOpenSettings() = runTest {
whenever(mockEnabledToggle.isEnabled()).thenReturn(true)
testee.processJsCallbackMessage(DUCK_PLAYER_PAGE_FEATURE_NAME, "openSettings", "id", null)
testee.processJsCallbackMessage(
DUCK_PLAYER_PAGE_FEATURE_NAME,
"openSettings",
"id",
null,
"someUrl",
)
assertCommandIssued<Command.OpenDuckPlayerSettings>()
}

@Test
fun whenJsCallbackMessageOpenInfoThenOpenInfo() = runTest {
whenever(mockEnabledToggle.isEnabled()).thenReturn(true)
testee.processJsCallbackMessage(DUCK_PLAYER_PAGE_FEATURE_NAME, "openInfo", "id", null)
testee.processJsCallbackMessage(
DUCK_PLAYER_PAGE_FEATURE_NAME,
"openInfo",
"id",
null,
"someUrl",
)
assertCommandIssued<Command.OpenDuckPlayerInfo>()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,6 @@ import com.duckduckgo.app.browser.webshare.WebShareChooser
import com.duckduckgo.app.browser.webview.WebContentDebugging
import com.duckduckgo.app.browser.webview.WebViewBlobDownloadFeature
import com.duckduckgo.app.browser.webview.safewebview.SafeWebViewFeature
import com.duckduckgo.app.cta.ui.*
import com.duckduckgo.app.cta.ui.Cta
import com.duckduckgo.app.cta.ui.CtaViewModel
import com.duckduckgo.app.cta.ui.DaxBubbleCta
Expand Down Expand Up @@ -2421,7 +2420,9 @@ class BrowserTabFragment :
id: String?,
data: JSONObject?,
) {
viewModel.processJsCallbackMessage(featureName, method, id, data)
appCoroutineScope.launch(dispatchers.main()) {
viewModel.processJsCallbackMessage(featureName, method, id, data, it.url)
}
}
},
)
Expand All @@ -2434,7 +2435,9 @@ class BrowserTabFragment :
id: String?,
data: JSONObject?,
) {
viewModel.processJsCallbackMessage(featureName, method, id, data)
appCoroutineScope.launch(dispatchers.main()) {
viewModel.processJsCallbackMessage(featureName, method, id, data, it.url)
}
}
},
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3153,11 +3153,12 @@ class BrowserTabViewModel @Inject constructor(
)
}

fun processJsCallbackMessage(
suspend fun processJsCallbackMessage(
featureName: String,
method: String,
id: String?,
data: JSONObject?,
url: String?,
) {
when (method) {
"webShare" -> if (id != null && data != null) {
Expand Down Expand Up @@ -3185,8 +3186,8 @@ class BrowserTabViewModel @Inject constructor(

when (featureName) {
DUCK_PLAYER_FEATURE_NAME, DUCK_PLAYER_PAGE_FEATURE_NAME -> {
viewModelScope.launch {
val response = duckPlayerJSHelper.processJsCallbackMessage(featureName, method, id, data)
withContext(dispatchers.io()) {
val response = duckPlayerJSHelper.processJsCallbackMessage(featureName, method, id, data, url)
withContext(dispatchers.main()) {
response?.let {
command.value = it
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package com.duckduckgo.app.browser.duckplayer

import androidx.core.net.toUri
import com.duckduckgo.app.browser.DuckDuckGoUrlDetector
import com.duckduckgo.app.browser.commands.Command
import com.duckduckgo.app.browser.commands.Command.OpenDuckPlayerInfo
import com.duckduckgo.app.browser.commands.Command.OpenDuckPlayerSettings
Expand All @@ -25,7 +26,9 @@ import com.duckduckgo.app.browser.commands.Command.SendResponseToJs
import com.duckduckgo.app.browser.commands.NavigationCommand.Navigate
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
import com.duckduckgo.app.pixels.AppPixelName.DUCK_PLAYER_SETTING_NEVER_OVERLAY_YOUTUBE
import com.duckduckgo.app.pixels.AppPixelName.DUCK_PLAYER_SETTING_NEVER_SERP
import com.duckduckgo.app.statistics.pixels.Pixel
import com.duckduckgo.appbuildconfig.api.AppBuildConfig
import com.duckduckgo.duckplayer.api.DuckPlayer
Expand All @@ -43,6 +46,7 @@ class DuckPlayerJSHelper @Inject constructor(
private val duckPlayer: DuckPlayer,
private val appBuildConfig: AppBuildConfig,
private val pixel: Pixel,
private val duckDuckGoUrlDetector: DuckDuckGoUrlDetector,
) {
private suspend fun getUserPreferences(featureName: String, method: String, id: String): JsCallbackData {
val userValues = duckPlayer.getUserPreferences()
Expand Down Expand Up @@ -128,6 +132,7 @@ class DuckPlayerJSHelper @Inject constructor(
method: String,
id: String?,
data: JSONObject?,
url: String?,
): Command? {
when (method) {
"getUserValues" -> if (id != null) {
Expand All @@ -140,9 +145,17 @@ class DuckPlayerJSHelper @Inject constructor(
DUCK_PLAYER_FEATURE_NAME -> {
SendResponseToJs(getUserPreferences(featureName, method, id)).also {
if (data.getJSONObject(PRIVATE_PLAYER_MODE).keys().next() == "enabled") {
pixel.fire(DUCK_PLAYER_SETTING_ALWAYS_OVERLAY_YOUTUBE)
if (url != null && duckDuckGoUrlDetector.isDuckDuckGoUrl(url)) {
pixel.fire(DUCK_PLAYER_SETTING_ALWAYS_SERP)
} else {
pixel.fire(DUCK_PLAYER_SETTING_ALWAYS_OVERLAY_YOUTUBE)
}
} else if (data.getJSONObject(PRIVATE_PLAYER_MODE).keys().next() == "disabled") {
pixel.fire(DUCK_PLAYER_SETTING_NEVER_OVERLAY_YOUTUBE)
if (url != null && duckDuckGoUrlDetector.isDuckDuckGoUrl(url)) {
pixel.fire(DUCK_PLAYER_SETTING_NEVER_SERP)
} else {
pixel.fire(DUCK_PLAYER_SETTING_NEVER_OVERLAY_YOUTUBE)
}
}
}
}
Expand Down
2 changes: 2 additions & 0 deletions app/src/main/java/com/duckduckgo/app/pixels/AppPixelName.kt
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,8 @@ enum class AppPixelName(override val pixelName: String) : Pixel.PixelName {
TAB_MANAGER_VIEW_MODE_TOGGLED_DAILY("m_tab_manager_view_mode_toggled_daily"),

DUCK_PLAYER_SETTING_ALWAYS_OVERLAY_YOUTUBE("duck-player_setting_always_overlay_youtube"),
DUCK_PLAYER_SETTING_ALWAYS_SERP("duck-player_setting_always_overlay_serp"),
DUCK_PLAYER_SETTING_NEVER_SERP("duck-player_setting_never_overlay_serp"),
DUCK_PLAYER_SETTING_NEVER_OVERLAY_YOUTUBE("duck-player_setting_never_overlay_youtube"),
DUCK_PLAYER_SETTING_ALWAYS_DUCK_PLAYER("duck-player_setting_always_duck-player"),

Expand Down

0 comments on commit 486c20c

Please sign in to comment.