Skip to content

Commit d37c5f7

Browse files
committed
Merge branch 'release/5.217.0' into main
2 parents b3918b5 + e496633 commit d37c5f7

File tree

83 files changed

+6834
-5465
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

83 files changed

+6834
-5465
lines changed

anvil/anvil-compiler/src/main/java/com/duckduckgo/anvil/compiler/ContributesRemoteFeatureCodeGenerator.kt

+58
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ class ContributesRemoteFeatureCodeGenerator : CodeGenerator {
117117
.flavorNameProvider({ appBuildConfig.flavor.name })
118118
.featureName(%S)
119119
.appVariantProvider({ appBuildConfig.variantName })
120+
.localeProvider({ appBuildConfig.deviceLocale })
120121
// save empty variants will force the default variant to be set
121122
.forceDefaultVariantProvider({ variantManager.updateVariants(emptyList()) })
122123
.build()
@@ -353,6 +354,7 @@ class ContributesRemoteFeatureCodeGenerator : CodeGenerator {
353354
.addType(createJsonRolloutDataClass(generatedPackage, module))
354355
.addType(createJsonRolloutStepDataClass(generatedPackage, module))
355356
.addType(createJsonToggleTargetDataClass(generatedPackage, module))
357+
.addType(createJsonToggleCohortDataClass(generatedPackage, module))
356358
.addType(createJsonToggleDataClass(generatedPackage, module))
357359
.addType(createJsonFeatureDataClass(generatedPackage, module))
358360
.addType(createJsonExceptionDataClass(generatedPackage, module))
@@ -493,6 +495,7 @@ class ContributesRemoteFeatureCodeGenerator : CodeGenerator {
493495
enable = isEnabled,
494496
minSupportedVersion = feature.minSupportedVersion,
495497
targets = emptyList(),
498+
cohorts = emptyList(),
496499
)
497500
)
498501
@@ -508,20 +511,33 @@ class ContributesRemoteFeatureCodeGenerator : CodeGenerator {
508511
val previousStateValue = previousState?.enable ?: this.feature.get().invokeMethod(subfeature.key).isEnabled()
509512
510513
val previousRolloutThreshold = previousState?.rolloutThreshold
514+
val previousAssignedCohort = previousState?.assignedCohort
511515
val newStateValue = (jsonToggle.state == "enabled" || (appBuildConfig.flavor == %T && jsonToggle.state == "internal"))
512516
val targets = jsonToggle?.targets?.map { target ->
513517
Toggle.State.Target(
514518
variantKey = target.variantKey,
519+
localeCountry = target.localeCountry,
520+
localeLanguage = target.localeLanguage,
515521
)
516522
} ?: emptyList()
523+
val cohorts = jsonToggle?.cohorts?.map { cohort ->
524+
Toggle.State.Cohort(
525+
name = cohort.name,
526+
weight = cohort.weight,
527+
)
528+
} ?: emptyList()
529+
val config = jsonToggle?.config ?: emptyMap()
517530
this.feature.get().invokeMethod(subfeature.key).setRawStoredState(
518531
Toggle.State(
519532
remoteEnableState = newStateValue,
520533
enable = previousStateValue,
521534
minSupportedVersion = jsonToggle.minSupportedVersion?.toInt(),
522535
rollout = jsonToggle?.rollout?.steps?.map { it.percent },
523536
rolloutThreshold = previousRolloutThreshold,
537+
assignedCohort = previousAssignedCohort,
524538
targets = targets,
539+
cohorts = cohorts,
540+
config = config,
525541
),
526542
)
527543
} catch(e: Throwable) {
@@ -706,9 +722,31 @@ class ContributesRemoteFeatureCodeGenerator : CodeGenerator {
706722
.primaryConstructor(
707723
FunSpec.constructorBuilder()
708724
.addParameter("variantKey", String::class.asClassName())
725+
.addParameter("localeCountry", String::class.asClassName())
726+
.addParameter("localeLanguage", String::class.asClassName())
709727
.build(),
710728
)
711729
.addProperty(PropertySpec.builder("variantKey", String::class.asClassName()).initializer("variantKey").build())
730+
.addProperty(PropertySpec.builder("localeCountry", String::class.asClassName()).initializer("localeCountry").build())
731+
.addProperty(PropertySpec.builder("localeLanguage", String::class.asClassName()).initializer("localeLanguage").build())
732+
.build()
733+
}
734+
735+
private fun createJsonToggleCohortDataClass(
736+
generatedPackage: String,
737+
module: ModuleDescriptor,
738+
): TypeSpec {
739+
return TypeSpec.classBuilder(FqName("$generatedPackage.JsonToggleCohort").asClassName(module))
740+
.addModifiers(KModifier.PRIVATE)
741+
.addModifiers(KModifier.DATA)
742+
.primaryConstructor(
743+
FunSpec.constructorBuilder()
744+
.addParameter("name", String::class.asClassName())
745+
.addParameter("weight", Int::class.asClassName())
746+
.build(),
747+
)
748+
.addProperty(PropertySpec.builder("name", String::class.asClassName()).initializer("name").build())
749+
.addProperty(PropertySpec.builder("weight", Int::class.asClassName()).initializer("weight").build())
712750
.build()
713751
}
714752

@@ -737,6 +775,14 @@ class ContributesRemoteFeatureCodeGenerator : CodeGenerator {
737775
"targets",
738776
List::class.asClassName().parameterizedBy(FqName("JsonToggleTarget").asClassName(module)),
739777
)
778+
.addParameter(
779+
"cohorts",
780+
List::class.asClassName().parameterizedBy(FqName("JsonToggleCohort").asClassName(module)),
781+
)
782+
.addParameter(
783+
"config",
784+
Map::class.asClassName().parameterizedBy(String::class.asClassName(), String::class.asClassName()),
785+
)
740786
.build(),
741787
)
742788
.addProperty(
@@ -763,6 +809,18 @@ class ContributesRemoteFeatureCodeGenerator : CodeGenerator {
763809
.initializer("targets")
764810
.build(),
765811
)
812+
.addProperty(
813+
PropertySpec
814+
.builder("cohorts", List::class.asClassName().parameterizedBy(FqName("JsonToggleCohort").asClassName(module)))
815+
.initializer("cohorts")
816+
.build(),
817+
)
818+
.addProperty(
819+
PropertySpec
820+
.builder("config", Map::class.asClassName().parameterizedBy(String::class.asClassName(), String::class.asClassName()))
821+
.initializer("config")
822+
.build(),
823+
)
766824
.build()
767825
}
768826

app/src/androidTest/java/com/duckduckgo/app/browser/BrowserTabViewModelTest.kt

+25
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ import com.duckduckgo.app.browser.newtab.FavoritesQuickAccessAdapter.QuickAccess
104104
import com.duckduckgo.app.browser.omnibar.OmnibarEntryConverter
105105
import com.duckduckgo.app.browser.omnibar.model.OmnibarPosition.BOTTOM
106106
import com.duckduckgo.app.browser.omnibar.model.OmnibarPosition.TOP
107+
import com.duckduckgo.app.browser.refreshpixels.RefreshPixelSender
107108
import com.duckduckgo.app.browser.remotemessage.RemoteMessagingModel
108109
import com.duckduckgo.app.browser.session.WebViewSessionStorage
109110
import com.duckduckgo.app.browser.viewstate.BrowserViewState
@@ -468,6 +469,8 @@ class BrowserTabViewModelTest {
468469

469470
private val subscriptions: Subscriptions = mock()
470471

472+
private val refreshPixelSender: RefreshPixelSender = mock()
473+
471474
private val privacyProtectionsPopupExperimentExternalPixels: PrivacyProtectionsPopupExperimentExternalPixels = mock {
472475
runBlocking { whenever(mock.getPixelParams()).thenReturn(emptyMap()) }
473476
}
@@ -638,6 +641,7 @@ class BrowserTabViewModelTest {
638641
duckPlayer = mockDuckPlayer,
639642
duckPlayerJSHelper = DuckPlayerJSHelper(mockDuckPlayer, mockAppBuildConfig, mockPixel, mockDuckDuckGoUrlDetector),
640643
loadingBarExperimentManager = loadingBarExperimentManager,
644+
refreshPixelSender = refreshPixelSender,
641645
)
642646

643647
testee.loadData("abc", null, false, false)
@@ -5917,6 +5921,27 @@ class BrowserTabViewModelTest {
59175921
testee.omnibarViewState.removeObserver { observer(it) }
59185922
}
59195923

5924+
@Test
5925+
fun whenHandleMenuRefreshActionThenSendMenuRefreshPixels() {
5926+
testee.handleMenuRefreshAction()
5927+
5928+
verify(refreshPixelSender).sendMenuRefreshPixels()
5929+
}
5930+
5931+
@Test
5932+
fun whenHandlePullToRefreshActionThenSendPullToRefreshPixels() {
5933+
testee.handlePullToRefreshAction()
5934+
5935+
verify(refreshPixelSender).sendPullToRefreshPixels()
5936+
}
5937+
5938+
@Test
5939+
fun whenFireCustomTabRefreshPixelThenSendCustomTabRefreshPixel() {
5940+
testee.fireCustomTabRefreshPixel()
5941+
5942+
verify(refreshPixelSender).sendCustomTabRefreshPixel()
5943+
}
5944+
59205945
private fun aCredential(): LoginCredentials {
59215946
return LoginCredentials(domain = null, username = null, password = null)
59225947
}

app/src/androidTest/java/com/duckduckgo/app/browser/BrowserWebViewClientTest.kt

+24
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ import com.duckduckgo.experiments.api.loadingbarexperiment.LoadingBarExperimentM
7575
import com.duckduckgo.history.api.NavigationHistory
7676
import com.duckduckgo.privacy.config.api.AmpLinks
7777
import com.duckduckgo.subscriptions.api.Subscriptions
78+
import com.duckduckgo.user.agent.api.ClientBrandHintProvider
7879
import java.math.BigInteger
7980
import java.security.cert.X509Certificate
8081
import java.security.interfaces.RSAPublicKey
@@ -90,6 +91,7 @@ import org.junit.Test
9091
import org.mockito.ArgumentMatchers.anyString
9192
import org.mockito.kotlin.any
9293
import org.mockito.kotlin.argumentCaptor
94+
import org.mockito.kotlin.doNothing
9395
import org.mockito.kotlin.eq
9496
import org.mockito.kotlin.mock
9597
import org.mockito.kotlin.never
@@ -139,6 +141,7 @@ class BrowserWebViewClientTest {
139141
private val mockDuckPlayer: DuckPlayer = mock()
140142
private val navigationHistory: NavigationHistory = mock()
141143
private val loadingBarExperimentManager: LoadingBarExperimentManager = mock()
144+
private val mockDuckDuckGoUrlDetector: DuckDuckGoUrlDetector = mock()
142145

143146
@UiThreadTest
144147
@Before
@@ -173,6 +176,7 @@ class BrowserWebViewClientTest {
173176
subscriptions,
174177
mockDuckPlayer,
175178
loadingBarExperimentManager,
179+
mockDuckDuckGoUrlDetector,
176180
)
177181
testee.webViewClientListener = listener
178182
whenever(webResourceRequest.url).thenReturn(Uri.EMPTY)
@@ -395,6 +399,26 @@ class BrowserWebViewClientTest {
395399
verify(subscriptions).launchPrivacyPro(any(), any())
396400
}
397401

402+
@UiThreadTest
403+
@Test
404+
fun whenShouldOverrideWithShouldNavigateToDuckPlayerFromSerpThenAddQueryParam() {
405+
val urlType = SpecialUrlDetector.UrlType.ShouldLaunchDuckPlayerLink("duck://player/1234".toUri())
406+
whenever(specialUrlDetector.determineType(initiatingUrl = any(), uri = any())).thenReturn(urlType)
407+
whenever(webResourceRequest.isForMainFrame).thenReturn(true)
408+
whenever(webResourceRequest.isRedirect).thenReturn(false)
409+
whenever(webResourceRequest.url).thenReturn("www.youtube.com/watch?v=1234".toUri())
410+
whenever(mockDuckDuckGoUrlDetector.isDuckDuckGoUrl(any())).thenReturn(true)
411+
val mockClientProvider: ClientBrandHintProvider = mock()
412+
whenever(mockClientProvider.shouldChangeBranding(any())).thenReturn(false)
413+
testee.clientProvider = mockClientProvider
414+
doNothing().whenever(listener).willOverrideUrl(any())
415+
val mockWebView = getImmediatelyInvokedMockWebView()
416+
whenever(mockWebView.url).thenReturn("www.duckduckgo.com")
417+
418+
assertTrue(testee.shouldOverrideUrlLoading(mockWebView, webResourceRequest))
419+
verify(mockWebView).loadUrl("www.youtube.com/watch?v=1234&origin=serp_auto")
420+
}
421+
398422
@UiThreadTest
399423
@Test
400424
fun whenAppLinkDetectedAndIsHandledThenReturnTrue() {

0 commit comments

Comments
 (0)