Skip to content

Commit 9cc81c1

Browse files
committed
Merge branch 'release/5.48.0'
2 parents 0c8187d + 095011a commit 9cc81c1

File tree

38 files changed

+317
-11
lines changed

38 files changed

+317
-11
lines changed

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

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,11 +50,13 @@ import com.duckduckgo.app.browser.model.LongPressTarget
5050
import com.duckduckgo.app.browser.omnibar.OmnibarEntryConverter
5151
import com.duckduckgo.app.browser.session.WebViewSessionStorage
5252
import com.duckduckgo.app.cta.db.DismissedCtaDao
53+
import com.duckduckgo.app.cta.model.CtaId
5354
import com.duckduckgo.app.cta.model.DismissedCta
5455
import com.duckduckgo.app.cta.ui.CtaViewModel
5556
import com.duckduckgo.app.cta.ui.DaxBubbleCta
5657
import com.duckduckgo.app.cta.ui.DaxDialogCta
5758
import com.duckduckgo.app.cta.ui.HomePanelCta
59+
import com.duckduckgo.app.cta.ui.HomeTopPanelCta
5860
import com.duckduckgo.app.global.db.AppDatabase
5961
import com.duckduckgo.app.global.install.AppInstallStore
6062
import com.duckduckgo.app.global.model.SiteFactory
@@ -64,6 +66,7 @@ import com.duckduckgo.app.privacy.model.PrivacyPractices
6466
import com.duckduckgo.app.privacy.model.TestEntity
6567
import com.duckduckgo.app.privacy.store.PrivacySettingsStore
6668
import com.duckduckgo.app.settings.db.SettingsDataStore
69+
import com.duckduckgo.app.statistics.Variant
6770
import com.duckduckgo.app.statistics.VariantManager
6871
import com.duckduckgo.app.statistics.VariantManager.Companion.DEFAULT_VARIANT
6972
import com.duckduckgo.app.statistics.api.StatisticsUpdater
@@ -1357,6 +1360,7 @@ class BrowserTabViewModelTest {
13571360

13581361
@Test
13591362
fun whenScheduledSurveyChangesAndInstalledDaysDontMatchThenCtaIsNull() {
1363+
setCovidCtaShown()
13601364
testee.onSurveyChanged(Survey("abc", "http://example.com", daysInstalled = 2, status = Survey.Status.SCHEDULED))
13611365
assertNull(testee.ctaViewState.value!!.cta)
13621366
}
@@ -1369,11 +1373,19 @@ class BrowserTabViewModelTest {
13691373

13701374
@Test
13711375
fun whenSurveyCtaDismissedAndNoOtherCtaPossibleCtaIsNull() {
1376+
setCovidCtaShown()
13721377
testee.onSurveyChanged(Survey("abc", "http://example.com", daysInstalled = 1, status = Survey.Status.SCHEDULED))
13731378
testee.onUserDismissedCta(testee.ctaViewState.value!!.cta!!)
13741379
assertNull(testee.ctaViewState.value!!.cta)
13751380
}
13761381

1382+
@Test
1383+
fun whenSurveyCtaDismissedAndWidgetNotCompatibleAndCovidCtaNotShownThenCtaIsCovid() {
1384+
testee.onSurveyChanged(Survey("abc", "http://example.com", daysInstalled = 1, status = Survey.Status.SCHEDULED))
1385+
testee.onUserDismissedCta(testee.ctaViewState.value!!.cta!!)
1386+
assertEquals(HomeTopPanelCta.CovidCta(), testee.ctaViewState.value!!.cta)
1387+
}
1388+
13771389
@Test
13781390
fun whenSurveyCtaDismissedAndWidgetCtaIsPossibleThenNextCtaIsWidget() {
13791391
whenever(mockWidgetCapabilities.supportsStandardWidgetAdd).thenReturn(true)
@@ -1396,6 +1408,7 @@ class BrowserTabViewModelTest {
13961408

13971409
@Test
13981410
fun whenCtaRefreshedAndAutoAddSupportedAndWidgetAlreadyInstalledThenCtaIsNull() = ruleRunBlockingTest {
1411+
setCovidCtaShown()
13991412
whenever(mockWidgetCapabilities.supportsStandardWidgetAdd).thenReturn(true)
14001413
whenever(mockWidgetCapabilities.supportsAutomaticWidgetAdd).thenReturn(true)
14011414
whenever(mockWidgetCapabilities.hasInstalledWidgets).thenReturn(true)
@@ -1412,6 +1425,7 @@ class BrowserTabViewModelTest {
14121425

14131426
@Test
14141427
fun whenCtaRefreshedAndOnlyStandardAddSupportedAndWidgetAlreadyInstalledThenCtaIsNull() = ruleRunBlockingTest {
1428+
setCovidCtaShown()
14151429
whenever(mockWidgetCapabilities.supportsStandardWidgetAdd).thenReturn(true)
14161430
whenever(mockWidgetCapabilities.supportsAutomaticWidgetAdd).thenReturn(false)
14171431
whenever(mockWidgetCapabilities.hasInstalledWidgets).thenReturn(true)
@@ -1421,6 +1435,7 @@ class BrowserTabViewModelTest {
14211435

14221436
@Test
14231437
fun whenCtaRefreshedAndStandardAddNotSupportedAndWidgetNotInstalledThenCtaIsNull() = ruleRunBlockingTest {
1438+
setCovidCtaShown()
14241439
whenever(mockWidgetCapabilities.supportsStandardWidgetAdd).thenReturn(false)
14251440
whenever(mockWidgetCapabilities.supportsAutomaticWidgetAdd).thenReturn(false)
14261441
whenever(mockWidgetCapabilities.hasInstalledWidgets).thenReturn(false)
@@ -1430,6 +1445,7 @@ class BrowserTabViewModelTest {
14301445

14311446
@Test
14321447
fun whenCtaRefreshedAndStandardAddNotSupportedAndWidgetAlreadyInstalledThenCtaIsNull() = ruleRunBlockingTest {
1448+
setCovidCtaShown()
14331449
whenever(mockWidgetCapabilities.supportsStandardWidgetAdd).thenReturn(false)
14341450
whenever(mockWidgetCapabilities.supportsAutomaticWidgetAdd).thenReturn(false)
14351451
whenever(mockWidgetCapabilities.hasInstalledWidgets).thenReturn(true)
@@ -1561,6 +1577,25 @@ class BrowserTabViewModelTest {
15611577
verify(mockSurveyDao).cancelScheduledSurveys()
15621578
}
15631579

1580+
@Test
1581+
fun whenUserDismissedHomeTopPanelCtaAndVariantIsNotConceptTestThenRefreshCta() {
1582+
val cta = HomeTopPanelCta.CovidCta()
1583+
whenever(mockDismissedCtaDao.exists(cta.ctaId)).thenReturn(true)
1584+
testee.onUserDismissedCta(cta)
1585+
verify(mockDismissedCtaDao).insert(DismissedCta(cta.ctaId))
1586+
assertNotEquals(HomeTopPanelCta.CovidCta, testee.ctaViewState.value!!.cta)
1587+
}
1588+
1589+
@Test
1590+
fun whenUserDismissedHomeTopPanelCtaAndVariantIsConceptTestThenReturnEmptyCta() {
1591+
whenever(mockVariantManager.getVariant()).thenReturn(
1592+
Variant("test", features = listOf(VariantManager.VariantFeature.ConceptTest), filterBy = { true })
1593+
)
1594+
val cta = HomeTopPanelCta.CovidCta()
1595+
testee.onUserDismissedCta(cta)
1596+
assertNull(testee.ctaViewState.value!!.cta)
1597+
}
1598+
15641599
@Test
15651600
fun whenUserFailedSettingDdgAsDefaultBrowserFromSettingsThenFirePixelAndUpdateInstallStore() {
15661601
whenever(mockDefaultBrowserDetector.isDefaultBrowser()).thenReturn(false)
@@ -1775,6 +1810,13 @@ class BrowserTabViewModelTest {
17751810
assertEquals("surrogate.com", brokenSiteFeedback.surrogates)
17761811
}
17771812

1813+
@Test
1814+
fun whenUserClickedTopCtaButtonAndCtaIsCovidCtaThenSubmitQuery() {
1815+
val cta = HomeTopPanelCta.CovidCta()
1816+
testee.onUserClickTopCta(cta)
1817+
assertEquals(cta.searchTerm, omnibarViewState().omnibarText)
1818+
}
1819+
17781820
private inline fun <reified T : Command> assertCommandIssued(instanceAssertions: T.() -> Unit = {}) {
17791821
verify(mockCommandObserver, atLeastOnce()).onChanged(commandCaptor.capture())
17801822
val issuedCommand = commandCaptor.allValues.find { it is T }
@@ -1824,6 +1866,10 @@ class BrowserTabViewModelTest {
18241866
testee.navigationStateChanged(buildWebNavigation(originalUrl = originalUrl, currentUrl = currentUrl))
18251867
}
18261868

1869+
private fun setCovidCtaShown() {
1870+
whenever(mockDismissedCtaDao.exists(CtaId.COVID)).thenReturn(true)
1871+
}
1872+
18271873
private fun setupNavigation(
18281874
skipHome: Boolean = false,
18291875
isBrowsing: Boolean,

app/src/androidTest/java/com/duckduckgo/app/cta/ui/CtaViewModelTest.kt

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,7 @@ class CtaViewModelTest {
292292
@Test
293293
fun whenRefreshCtaOnHomeTabAndNoFeaturesActiveThenReturnNull() = runBlockingTest {
294294
setNoFeatures()
295+
setCovidCtaShown()
295296
val value = testee.refreshCta(coroutineRule.testDispatcher, isBrowserShowing = false)
296297
assertNull(value)
297298
}
@@ -347,6 +348,7 @@ class CtaViewModelTest {
347348
@Test
348349
fun whenRefreshCtaOnHomeTabAndSuppressWidgetCtaFeatureActiveThenReturnNullWhenTryngToShowWidgetCta() = runBlockingTest {
349350
setSuppressHomeTabWidgetCtaFeature()
351+
setCovidCtaShown()
350352
whenever(mockSettingsDataStore.hideTips).thenReturn(true)
351353
whenever(mockWidgetCapabilities.supportsStandardWidgetAdd).thenReturn(true)
352354
whenever(mockWidgetCapabilities.supportsAutomaticWidgetAdd).thenReturn(true)
@@ -357,8 +359,9 @@ class CtaViewModelTest {
357359
}
358360

359361
@Test
360-
fun whenRefreshCtaOnHomeTabAndSuppressWidgetCtaFeatureActiveThenReturnNullWhenTryngToShowWidgetInstructionsCta() = runBlockingTest {
362+
fun whenRefreshCtaOnHomeTabAndSuppressWidgetCtaFeatureActiveThenReturnNullWhenTryingToShowWidgetInstructionsCta() = runBlockingTest {
361363
setSuppressHomeTabWidgetCtaFeature()
364+
setCovidCtaShown()
362365
whenever(mockSettingsDataStore.hideTips).thenReturn(true)
363366
whenever(mockWidgetCapabilities.supportsStandardWidgetAdd).thenReturn(true)
364367
whenever(mockWidgetCapabilities.supportsAutomaticWidgetAdd).thenReturn(false)
@@ -463,6 +466,52 @@ class CtaViewModelTest {
463466
assertTrue(value !is DaxBubbleCta.DaxEndCta)
464467
}
465468

469+
@Test
470+
fun whenRefreshCtaOnHomeTabAndConceptTestFeatureActiveAndIntroCtaWasNotPreviouslyShownThenCovidCtaNotShown() = runBlockingTest {
471+
setConceptTestFeature()
472+
whenever(mockDismissedCtaDao.exists(CtaId.DAX_INTRO)).thenReturn(false)
473+
whenever(mockDismissedCtaDao.exists(CtaId.COVID)).thenReturn(false)
474+
475+
val value = testee.refreshCta(coroutineRule.testDispatcher, isBrowserShowing = false)
476+
assertFalse(value is HomeTopPanelCta.CovidCta)
477+
}
478+
479+
@Test
480+
fun whenRefreshCtaOnHomeTabAndConceptTestFeatureActiveAndIntroCtaWasNotPreviouslyShownThenDaxIntroCtaShown() = runBlockingTest {
481+
setConceptTestFeature()
482+
whenever(mockDismissedCtaDao.exists(CtaId.DAX_INTRO)).thenReturn(false)
483+
whenever(mockDismissedCtaDao.exists(CtaId.COVID)).thenReturn(false)
484+
485+
val value = testee.refreshCta(coroutineRule.testDispatcher, isBrowserShowing = false)
486+
assertTrue(value is DaxBubbleCta.DaxIntroCta)
487+
}
488+
489+
@Test
490+
fun whenRefreshCtaOnHomeTabAndCovidCtaNotShownThenWidgetCtaTakesPrecedenceOverCovidCta() = runBlockingTest {
491+
setNoFeatures()
492+
whenever(mockWidgetCapabilities.supportsStandardWidgetAdd).thenReturn(true)
493+
whenever(mockWidgetCapabilities.hasInstalledWidgets).thenReturn(false)
494+
whenever(mockDismissedCtaDao.exists(CtaId.ADD_WIDGET)).thenReturn(false)
495+
whenever(mockDismissedCtaDao.exists(CtaId.COVID)).thenReturn(false)
496+
497+
val value = testee.refreshCta(coroutineRule.testDispatcher, isBrowserShowing = false)
498+
assertTrue(value is HomePanelCta.AddWidgetInstructions)
499+
}
500+
501+
@Test
502+
fun whenRefreshCtaOnHomeTabAndConceptTestFeatureActiveAndDaxEndCtaWasPreviouslyShownThenCovidCtaShown() = runBlockingTest {
503+
setConceptTestFeature()
504+
whenever(mockDismissedCtaDao.exists(CtaId.DAX_INTRO)).thenReturn(true)
505+
whenever(mockDismissedCtaDao.exists(CtaId.DAX_END)).thenReturn(true)
506+
507+
val value = testee.refreshCta(coroutineRule.testDispatcher, isBrowserShowing = false)
508+
assertTrue(value is HomeTopPanelCta.CovidCta)
509+
}
510+
511+
private fun setCovidCtaShown() {
512+
whenever(mockDismissedCtaDao.exists(CtaId.COVID)).thenReturn(true)
513+
}
514+
466515
private fun setNoFeatures() {
467516
whenever(mockVariantManager.getVariant()).thenReturn(Variant("test", features = emptyList(), filterBy = { true }))
468517
}

app/src/main/java/com/duckduckgo/app/browser/BrowserTabFragment.kt

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ import kotlinx.android.synthetic.main.include_find_in_page.*
101101
import kotlinx.android.synthetic.main.include_new_browser_tab.*
102102
import kotlinx.android.synthetic.main.include_omnibar_toolbar.*
103103
import kotlinx.android.synthetic.main.include_omnibar_toolbar.view.*
104+
import kotlinx.android.synthetic.main.include_top_cta.view.*
104105
import kotlinx.android.synthetic.main.popup_window_browser_menu.view.*
105106
import kotlinx.coroutines.*
106107
import org.jetbrains.anko.longToast
@@ -1405,6 +1406,7 @@ class BrowserTabFragment : Fragment(), FindListener, CoroutineScope {
14051406
} else {
14061407
hideHomeCta()
14071408
hideDaxCta()
1409+
hideHomeTopCta()
14081410
}
14091411
}
14101412
}
@@ -1414,6 +1416,7 @@ class BrowserTabFragment : Fragment(), FindListener, CoroutineScope {
14141416
is HomePanelCta -> showHomeCta(configuration)
14151417
is DaxBubbleCta -> showDaxCta(configuration)
14161418
is DaxDialogCta -> showDaxDialogCta(configuration)
1419+
is HomeTopPanelCta -> showHomeTopCta(configuration)
14171420
}
14181421

14191422
viewModel.onCtaShown()
@@ -1479,11 +1482,28 @@ class BrowserTabFragment : Fragment(), FindListener, CoroutineScope {
14791482
private fun showDaxCta(configuration: DaxBubbleCta) {
14801483
ddgLogo.hide()
14811484
hideHomeCta()
1485+
hideHomeTopCta()
14821486
configuration.showCta(daxCtaContainer)
14831487
}
14841488

1489+
private fun showHomeTopCta(configuration: HomeTopPanelCta) {
1490+
hideDaxCta()
1491+
hideHomeCta()
1492+
1493+
logoHidingListener.callToActionView = ctaTopContainer
1494+
1495+
configuration.showCta(ctaTopContainer)
1496+
ctaTopContainer.setOnClickListener {
1497+
viewModel.onUserClickTopCta(configuration)
1498+
}
1499+
ctaTopContainer.closeButton.setOnClickListener {
1500+
viewModel.onUserDismissedCta(configuration)
1501+
}
1502+
}
1503+
14851504
private fun showHomeCta(configuration: HomePanelCta) {
14861505
hideDaxCta()
1506+
hideHomeTopCta()
14871507
if (ctaContainer.isEmpty()) {
14881508
renderHomeCta()
14891509
} else {
@@ -1500,6 +1520,10 @@ class BrowserTabFragment : Fragment(), FindListener, CoroutineScope {
15001520
ctaContainer.gone()
15011521
}
15021522

1523+
private fun hideHomeTopCta() {
1524+
ctaTopContainer.gone()
1525+
}
1526+
15031527
fun renderHomeCta() {
15041528
val context = context ?: return
15051529
val cta = lastSeenCtaViewState?.cta ?: return

app/src/main/java/com/duckduckgo/app/browser/BrowserTabViewModel.kt

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -933,6 +933,12 @@ class BrowserTabViewModel(
933933
ctaViewModel.registerDaxBubbleCtaDismissed(cta)
934934
}
935935

936+
fun onUserClickTopCta(cta: HomeTopPanelCta) {
937+
if (cta is HomeTopPanelCta.CovidCta) {
938+
onUserSubmittedQuery(cta.searchTerm)
939+
}
940+
}
941+
936942
fun onUserClickCtaOkButton(cta: Cta) {
937943
ctaViewModel.onUserClickCtaOkButton(cta)
938944
viewModelScope.launch {
@@ -949,10 +955,16 @@ class BrowserTabViewModel(
949955

950956
fun onUserDismissedCta(dismissedCta: Cta) {
951957
ctaViewModel.onUserDismissedCta(dismissedCta)
952-
if (dismissedCta is HomePanelCta) {
953-
refreshCta()
954-
} else {
955-
ctaViewState.value = currentCtaViewState().copy(cta = null)
958+
when (dismissedCta) {
959+
is HomeTopPanelCta -> {
960+
if (!variantManager.getVariant().hasFeature(VariantManager.VariantFeature.ConceptTest)) {
961+
refreshCta()
962+
} else {
963+
ctaViewState.value = currentCtaViewState().copy(cta = null)
964+
}
965+
}
966+
is HomePanelCta -> refreshCta()
967+
else -> ctaViewState.value = currentCtaViewState().copy(cta = null)
956968
}
957969
}
958970

app/src/main/java/com/duckduckgo/app/cta/model/DismissedCta.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@ enum class CtaId {
3131
DAX_DIALOG_TRACKERS_FOUND,
3232
DAX_DIALOG_NETWORK,
3333
DAX_DIALOG_OTHER,
34-
DAX_END
34+
DAX_END,
35+
COVID
3536
}
3637

3738
@Entity(

app/src/main/java/com/duckduckgo/app/cta/ui/Cta.kt

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ import com.duckduckgo.app.widget.ui.WidgetCapabilities
3838
import kotlinx.android.synthetic.main.include_cta_buttons.view.*
3939
import kotlinx.android.synthetic.main.include_cta_content.view.*
4040
import kotlinx.android.synthetic.main.include_dax_dialog_cta.view.*
41+
import kotlinx.android.synthetic.main.include_top_cta.view.*
4142

4243
interface DialogCta {
4344
fun createCta(activity: FragmentActivity): DaxDialog
@@ -470,6 +471,32 @@ sealed class HomePanelCta(
470471
)
471472
}
472473

474+
sealed class HomeTopPanelCta(
475+
override val ctaId: CtaId,
476+
override val shownPixel: Pixel.PixelName?,
477+
override val okPixel: Pixel.PixelName?,
478+
override val cancelPixel: Pixel.PixelName?,
479+
@StringRes open val description: Int
480+
) : Cta, ViewCta {
481+
482+
override fun pixelCancelParameters(): Map<String, String> = emptyMap()
483+
484+
override fun pixelOkParameters(): Map<String, String> = emptyMap()
485+
486+
override fun pixelShownParameters(): Map<String, String> = emptyMap()
487+
488+
override fun showCta(view: View) {
489+
view.upperCtaTitle.text = view.context.getString(description)
490+
view.show()
491+
}
492+
493+
data class CovidCta(val searchTerm: String = COVID_SEARCH_TERM) : HomeTopPanelCta(CtaId.COVID, null, null, null, R.string.covidCtaText) {
494+
companion object {
495+
private const val COVID_SEARCH_TERM = "covid 19"
496+
}
497+
}
498+
}
499+
473500
fun DaxCta.addCtaToHistory(newCta: String): String {
474501
val param = onboardingStore.onboardingDialogJourney?.split("-").orEmpty().toMutableList()
475502
val daysInstalled = minOf(appInstallStore.daysInstalled().toInt(), MAX_DAYS_ALLOWED)

app/src/main/java/com/duckduckgo/app/cta/ui/CtaViewModel.kt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,9 @@ class CtaViewModel @Inject constructor(
144144
canShowWidgetCta() -> {
145145
if (widgetCapabilities.supportsAutomaticWidgetAdd) AddWidgetAuto else AddWidgetInstructions
146146
}
147+
canShowCovidCta() -> {
148+
HomeTopPanelCta.CovidCta()
149+
}
147150
else -> null
148151
}
149152
}
@@ -267,6 +270,15 @@ class CtaViewModel @Inject constructor(
267270
daxNonSerpDialogShown()
268271
}
269272

273+
@WorkerThread
274+
private fun canShowCovidCta(): Boolean {
275+
return if (variantManager.getVariant().hasFeature(ConceptTest)) {
276+
daxDialogEndShown() && !covidCtaShown()
277+
} else {
278+
!covidCtaShown()
279+
}
280+
}
281+
270282
private fun hasTrackersInformation(events: List<TrackingEvent>): Boolean =
271283
events.asSequence()
272284
.filter { it.entity?.isMajor == true }
@@ -298,5 +310,7 @@ class CtaViewModel @Inject constructor(
298310

299311
private fun daxSearchWidgetShown(): Boolean = dismissedCtaDao.exists(CtaId.DAX_DIALOG_SEARCH_WIDGET)
300312

313+
private fun covidCtaShown(): Boolean = dismissedCtaDao.exists(CtaId.COVID)
314+
301315
private fun isSerpUrl(url: String): Boolean = url.contains(DaxDialogCta.SERP)
302316
}

0 commit comments

Comments
 (0)