Skip to content

Commit e697ea6

Browse files
authored
New address bar option choice screen pixels (#6802)
Task/Issue URL: https://app.asana.com/1/137249556945/project/488551667048375/task/1211358524399131?focus=true ### Description - Adds pixels to the new address bar option choice screen ### Steps to test this PR _Search & Duck.ai_ - [x] Fresh install the app - [x] Complete onboarding (Use "I’ve been here before", **not** “Skip Onboarding”) and kill the app - [x] Verify: `m_aichat_new_address_bar_picker_displayed` - [x] Select “Search & Duck.ai" - [x] Verify pixel sent: `m_aichat_new_address_bar_picker_confirmed with params: {selection=search_and_ai}` _Search_ - [x] Fresh install the app - [x] Complete onboarding (Use "I’ve been here before", **not** “Skip Onboarding”) and kill the app - [x] Select “Search" - [x] Verify pixel sent: `m_aichat_new_address_bar_picker_confirmed with params: {selection=search_only}` _Search_ - [x] Fresh install the app - [x] Complete onboarding (Use "I’ve been here before", **not** “Skip Onboarding”) and kill the app - [x] Select “Not Now" - [x] Verify pixel sent: `m_aichat_new_address_bar_picker_not_now`
1 parent 3d20ea9 commit e697ea6

File tree

5 files changed

+150
-19
lines changed

5 files changed

+150
-19
lines changed

duckchat/duckchat-impl/src/main/java/com/duckduckgo/duckchat/impl/RealDuckChat.kt

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,16 @@ import com.duckduckgo.duckchat.api.DuckChat
3636
import com.duckduckgo.duckchat.api.DuckChatSettingsNoParams
3737
import com.duckduckgo.duckchat.impl.feature.AIChatImageUploadFeature
3838
import com.duckduckgo.duckchat.impl.feature.DuckChatFeature
39-
import com.duckduckgo.duckchat.impl.inputscreen.newaddressbaroption.ChoiceSelectionCallback
39+
import com.duckduckgo.duckchat.impl.inputscreen.newaddressbaroption.NewAddressBarCallback
4040
import com.duckduckgo.duckchat.impl.inputscreen.newaddressbaroption.NewAddressBarOptionBottomSheetDialogFactory
41+
import com.duckduckgo.duckchat.impl.inputscreen.newaddressbaroption.NewAddressBarSelection
42+
import com.duckduckgo.duckchat.impl.inputscreen.newaddressbaroption.NewAddressBarSelection.SEARCH_AND_AI
4143
import com.duckduckgo.duckchat.impl.pixel.DuckChatPixelName
44+
import com.duckduckgo.duckchat.impl.pixel.DuckChatPixelName.DUCK_CHAT_NEW_ADDRESS_BAR_PICKER_CONFIRMED
45+
import com.duckduckgo.duckchat.impl.pixel.DuckChatPixelName.DUCK_CHAT_NEW_ADDRESS_BAR_PICKER_DISPLAYED
46+
import com.duckduckgo.duckchat.impl.pixel.DuckChatPixelName.DUCK_CHAT_NEW_ADDRESS_BAR_PICKER_NOT_NOW
4247
import com.duckduckgo.duckchat.impl.pixel.DuckChatPixelParameters
48+
import com.duckduckgo.duckchat.impl.pixel.DuckChatPixelParameters.NEW_ADDRESS_BAR_SELECTION
4349
import com.duckduckgo.duckchat.impl.repository.DuckChatFeatureRepository
4450
import com.duckduckgo.duckchat.impl.ui.DuckChatWebViewActivityWithParams
4551
import com.duckduckgo.navigation.api.GlobalActivityStarter
@@ -531,11 +537,25 @@ class RealDuckChat @Inject constructor(
531537
newAddressBarOptionBottomSheetDialogFactory.create(
532538
context = context,
533539
isDarkThemeEnabled = isDarkThemeEnabled,
534-
choiceSelectionCallback = object : ChoiceSelectionCallback {
535-
override fun onSearchAndDuckAiSelected() {
536-
appCoroutineScope.launch {
537-
setInputScreenUserSetting(true)
540+
newAddressBarCallback = object : NewAddressBarCallback {
541+
override fun onDisplayed() {
542+
pixel.fire(DUCK_CHAT_NEW_ADDRESS_BAR_PICKER_DISPLAYED)
543+
}
544+
545+
override fun onConfirmed(selection: NewAddressBarSelection) {
546+
if (selection == SEARCH_AND_AI) {
547+
appCoroutineScope.launch {
548+
setInputScreenUserSetting(true)
549+
}
538550
}
551+
pixel.fire(
552+
pixel = DUCK_CHAT_NEW_ADDRESS_BAR_PICKER_CONFIRMED,
553+
parameters = mapOf(NEW_ADDRESS_BAR_SELECTION to selection.value),
554+
)
555+
}
556+
557+
override fun onNotNow() {
558+
pixel.fire(DUCK_CHAT_NEW_ADDRESS_BAR_PICKER_NOT_NOW)
539559
}
540560
},
541561
).show()

duckchat/duckchat-impl/src/main/java/com/duckduckgo/duckchat/impl/inputscreen/newaddressbaroption/NewAddressBarOptionBottomSheetDialog.kt

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,20 +30,29 @@ import com.airbnb.lottie.LottieDrawable
3030
import com.duckduckgo.common.ui.view.toPx
3131
import com.duckduckgo.duckchat.impl.R
3232
import com.duckduckgo.duckchat.impl.databinding.BottomSheetNewAddressBarOptionBinding
33+
import com.duckduckgo.duckchat.impl.inputscreen.newaddressbaroption.NewAddressBarSelection.SEARCH_AND_AI
34+
import com.duckduckgo.duckchat.impl.inputscreen.newaddressbaroption.NewAddressBarSelection.SEARCH_ONLY
3335
import com.google.android.material.bottomsheet.BottomSheetBehavior
3436
import com.google.android.material.bottomsheet.BottomSheetDialog
3537
import com.google.android.material.shape.CornerFamily
3638
import com.google.android.material.shape.MaterialShapeDrawable
3739

38-
interface ChoiceSelectionCallback {
39-
fun onSearchAndDuckAiSelected()
40+
enum class NewAddressBarSelection(val value: String) {
41+
SEARCH_ONLY("search_only"),
42+
SEARCH_AND_AI("search_and_ai"),
43+
}
44+
45+
interface NewAddressBarCallback {
46+
fun onDisplayed()
47+
fun onConfirmed(selection: NewAddressBarSelection)
48+
fun onNotNow()
4049
}
4150

4251
@SuppressLint("NoBottomSheetDialog")
4352
class NewAddressBarOptionBottomSheetDialog(
4453
private val context: Context,
4554
private val isDarkThemeEnabled: Boolean,
46-
private val choiceSelectionCallback: ChoiceSelectionCallback?,
55+
private val newAddressBarCallback: NewAddressBarCallback?,
4756
) : BottomSheetDialog(context) {
4857

4958
private val binding: BottomSheetNewAddressBarOptionBinding =
@@ -62,6 +71,7 @@ class NewAddressBarOptionBottomSheetDialog(
6271

6372
setOnShowListener {
6473
setRoundCorners()
74+
newAddressBarCallback?.onDisplayed()
6575
}
6676

6777
setOnCancelListener {
@@ -73,14 +83,14 @@ class NewAddressBarOptionBottomSheetDialog(
7383
setupSelectionLogic()
7484

7585
binding.newAddressBarOptionBottomSheetDialogPrimaryButton.setOnClickListener {
76-
if (searchAndDuckAiSelected) {
77-
choiceSelectionCallback?.onSearchAndDuckAiSelected()
78-
}
86+
val selection = if (searchAndDuckAiSelected) SEARCH_AND_AI else SEARCH_ONLY
87+
newAddressBarCallback?.onConfirmed(selection)
7988
restoreOrientation()
8089
dismiss()
8190
}
8291

8392
binding.newAddressBarOptionBottomSheetDialogGhostButton.setOnClickListener {
93+
newAddressBarCallback?.onNotNow()
8494
restoreOrientation()
8595
dismiss()
8696
}

duckchat/duckchat-impl/src/main/java/com/duckduckgo/duckchat/impl/inputscreen/newaddressbaroption/NewAddressBarOptionBottomSheetDialogFactory.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ interface NewAddressBarOptionBottomSheetDialogFactory {
2525
fun create(
2626
context: Context,
2727
isDarkThemeEnabled: Boolean,
28-
choiceSelectionCallback: ChoiceSelectionCallback?,
28+
newAddressBarCallback: NewAddressBarCallback?,
2929
): NewAddressBarOptionBottomSheetDialog
3030
}
3131

@@ -35,12 +35,12 @@ class RealNewAddressBarOptionBottomSheetDialogFactory @Inject constructor() : Ne
3535
override fun create(
3636
context: Context,
3737
isDarkThemeEnabled: Boolean,
38-
choiceSelectionCallback: ChoiceSelectionCallback?,
38+
newAddressBarCallback: NewAddressBarCallback?,
3939
): NewAddressBarOptionBottomSheetDialog {
4040
return NewAddressBarOptionBottomSheetDialog(
4141
context = context,
4242
isDarkThemeEnabled = isDarkThemeEnabled,
43-
choiceSelectionCallback = choiceSelectionCallback,
43+
newAddressBarCallback = newAddressBarCallback,
4444
)
4545
}
4646
}

duckchat/duckchat-impl/src/main/java/com/duckduckgo/duckchat/impl/pixel/DuckChatPixels.kt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,9 @@ import com.duckduckgo.duckchat.impl.pixel.DuckChatPixelName.DUCK_CHAT_IS_ENABLED
6868
import com.duckduckgo.duckchat.impl.pixel.DuckChatPixelName.DUCK_CHAT_KEYBOARD_RETURN_PRESSED
6969
import com.duckduckgo.duckchat.impl.pixel.DuckChatPixelName.DUCK_CHAT_MENU_SETTING_OFF
7070
import com.duckduckgo.duckchat.impl.pixel.DuckChatPixelName.DUCK_CHAT_MENU_SETTING_ON
71+
import com.duckduckgo.duckchat.impl.pixel.DuckChatPixelName.DUCK_CHAT_NEW_ADDRESS_BAR_PICKER_CONFIRMED
72+
import com.duckduckgo.duckchat.impl.pixel.DuckChatPixelName.DUCK_CHAT_NEW_ADDRESS_BAR_PICKER_DISPLAYED
73+
import com.duckduckgo.duckchat.impl.pixel.DuckChatPixelName.DUCK_CHAT_NEW_ADDRESS_BAR_PICKER_NOT_NOW
7174
import com.duckduckgo.duckchat.impl.pixel.DuckChatPixelName.DUCK_CHAT_OPEN
7275
import com.duckduckgo.duckchat.impl.pixel.DuckChatPixelName.DUCK_CHAT_OPEN_BROWSER_MENU
7376
import com.duckduckgo.duckchat.impl.pixel.DuckChatPixelName.DUCK_CHAT_OPEN_HISTORY
@@ -189,13 +192,17 @@ enum class DuckChatPixelName(override val pixelName: String) : Pixel.PixelName {
189192
DUCK_CHAT_EXPERIMENTAL_LEGACY_OMNIBAR_BACK_BUTTON_PRESSED("m_aichat_legacy_omnibar_back_button_pressed"),
190193
DUCK_CHAT_KEYBOARD_RETURN_PRESSED("m_aichat_duckai_keyboard_return_pressed"),
191194
DUCK_CHAT_EXPERIMENTAL_OMNIBAR_DAILY_RETENTION("m_aichat_experimental_omnibar_daily_retention"),
195+
DUCK_CHAT_NEW_ADDRESS_BAR_PICKER_DISPLAYED("m_aichat_new_address_bar_picker_displayed"),
196+
DUCK_CHAT_NEW_ADDRESS_BAR_PICKER_CONFIRMED("m_aichat_new_address_bar_picker_confirmed"),
197+
DUCK_CHAT_NEW_ADDRESS_BAR_PICKER_NOT_NOW("m_aichat_new_address_bar_picker_not_now"),
192198
}
193199

194200
object DuckChatPixelParameters {
195201
const val WAS_USED_BEFORE = "was_used_before"
196202
const val DELTA_TIMESTAMP_PARAMETERS = "delta-timestamp-minutes"
197203
const val INPUT_SCREEN_MODE = "mode"
198204
const val TEXT_LENGTH_BUCKET = "text_length_bucket"
205+
const val NEW_ADDRESS_BAR_SELECTION = "selection"
199206
}
200207

201208
@ContributesMultibinding(AppScope::class)
@@ -259,6 +266,9 @@ class DuckChatParamRemovalPlugin @Inject constructor() : PixelParamRemovalPlugin
259266
DUCK_CHAT_EXPERIMENTAL_OMNIBAR_FLOATING_RETURN_PRESSED.pixelName to PixelParameter.removeAtb(),
260267
DUCK_CHAT_EXPERIMENTAL_LEGACY_OMNIBAR_BACK_BUTTON_PRESSED.pixelName to PixelParameter.removeAtb(),
261268
DUCK_CHAT_EXPERIMENTAL_OMNIBAR_DAILY_RETENTION.pixelName to PixelParameter.removeAtb(),
269+
DUCK_CHAT_NEW_ADDRESS_BAR_PICKER_DISPLAYED.pixelName to PixelParameter.removeAtb(),
270+
DUCK_CHAT_NEW_ADDRESS_BAR_PICKER_CONFIRMED.pixelName to PixelParameter.removeAtb(),
271+
DUCK_CHAT_NEW_ADDRESS_BAR_PICKER_NOT_NOW.pixelName to PixelParameter.removeAtb(),
262272
)
263273
}
264274
}

duckchat/duckchat-impl/src/test/kotlin/com/duckduckgo/duckchat/impl/RealDuckChatTest.kt

Lines changed: 96 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,15 @@ import com.duckduckgo.common.test.CoroutineTestRule
3030
import com.duckduckgo.duckchat.api.DuckChatSettingsNoParams
3131
import com.duckduckgo.duckchat.impl.feature.AIChatImageUploadFeature
3232
import com.duckduckgo.duckchat.impl.feature.DuckChatFeature
33-
import com.duckduckgo.duckchat.impl.inputscreen.newaddressbaroption.ChoiceSelectionCallback
33+
import com.duckduckgo.duckchat.impl.inputscreen.newaddressbaroption.NewAddressBarCallback
3434
import com.duckduckgo.duckchat.impl.inputscreen.newaddressbaroption.NewAddressBarOptionBottomSheetDialog
3535
import com.duckduckgo.duckchat.impl.inputscreen.newaddressbaroption.NewAddressBarOptionBottomSheetDialogFactory
36+
import com.duckduckgo.duckchat.impl.inputscreen.newaddressbaroption.NewAddressBarSelection.SEARCH_AND_AI
37+
import com.duckduckgo.duckchat.impl.inputscreen.newaddressbaroption.NewAddressBarSelection.SEARCH_ONLY
38+
import com.duckduckgo.duckchat.impl.pixel.DuckChatPixelName.DUCK_CHAT_NEW_ADDRESS_BAR_PICKER_CONFIRMED
39+
import com.duckduckgo.duckchat.impl.pixel.DuckChatPixelName.DUCK_CHAT_NEW_ADDRESS_BAR_PICKER_DISPLAYED
40+
import com.duckduckgo.duckchat.impl.pixel.DuckChatPixelName.DUCK_CHAT_NEW_ADDRESS_BAR_PICKER_NOT_NOW
41+
import com.duckduckgo.duckchat.impl.pixel.DuckChatPixelParameters.NEW_ADDRESS_BAR_SELECTION
3642
import com.duckduckgo.duckchat.impl.repository.DuckChatFeatureRepository
3743
import com.duckduckgo.duckchat.impl.ui.DuckChatWebViewActivityWithParams
3844
import com.duckduckgo.feature.toggles.api.FakeFeatureToggleFactory
@@ -61,6 +67,7 @@ import org.mockito.Mockito.mock
6167
import org.mockito.Mockito.spy
6268
import org.mockito.kotlin.any
6369
import org.mockito.kotlin.argumentCaptor
70+
import org.mockito.kotlin.times
6471
import org.mockito.kotlin.verify
6572
import org.mockito.kotlin.whenever
6673

@@ -852,10 +859,10 @@ class RealDuckChatTest {
852859
}
853860

854861
@Test
855-
fun `when choice selection callback onSearchAndDuckAiSelected called then setInputScreenUserSetting is called`() = runTest {
856-
var capturedCallback: ChoiceSelectionCallback? = null
862+
fun `when onDisplayed called then DUCK_CHAT_NEW_ADDRESS_BAR_PICKER_DISPLAYED pixel is fired`() = runTest {
863+
var capturedCallback: NewAddressBarCallback? = null
857864
whenever(mockNewAddressBarOptionBottomSheetDialogFactory.create(any(), any(), any())).thenAnswer { invocation ->
858-
capturedCallback = invocation.getArgument<ChoiceSelectionCallback?>(2)
865+
capturedCallback = invocation.getArgument<NewAddressBarCallback?>(2)
859866
mockNewAddressBarOptionBottomSheetDialog
860867
}
861868

@@ -871,11 +878,95 @@ class RealDuckChatTest {
871878
verify(mockNewAddressBarOptionBottomSheetDialog).show()
872879

873880
assertNotNull(capturedCallback)
874-
capturedCallback!!.onSearchAndDuckAiSelected()
881+
capturedCallback!!.onDisplayed()
882+
883+
verify(mockPixel).fire(DUCK_CHAT_NEW_ADDRESS_BAR_PICKER_DISPLAYED)
884+
}
885+
886+
@Test
887+
fun `when onConfirmed called with SEARCH_AND_AI then setInputScreenUserSetting to true and pixel fired with search_and_ai`() = runTest {
888+
var capturedCallback: NewAddressBarCallback? = null
889+
whenever(mockNewAddressBarOptionBottomSheetDialogFactory.create(any(), any(), any())).thenAnswer { invocation ->
890+
capturedCallback = invocation.getArgument<NewAddressBarCallback?>(2)
891+
mockNewAddressBarOptionBottomSheetDialog
892+
}
893+
894+
val mockContext = mock<Context>()
895+
testee.showNewAddressBarOptionChoiceScreen(mockContext, true)
896+
897+
verify(mockNewAddressBarOptionBottomSheetDialogFactory).create(
898+
any(),
899+
any(),
900+
any(),
901+
)
902+
903+
verify(mockNewAddressBarOptionBottomSheetDialog).show()
904+
905+
assertNotNull(capturedCallback)
906+
capturedCallback!!.onConfirmed(SEARCH_AND_AI)
875907

876908
coroutineRule.testScope.advanceUntilIdle()
877909

878910
verify(mockDuckChatFeatureRepository).setInputScreenUserSetting(true)
911+
verify(mockPixel).fire(
912+
pixel = DUCK_CHAT_NEW_ADDRESS_BAR_PICKER_CONFIRMED,
913+
parameters = mapOf(NEW_ADDRESS_BAR_SELECTION to "search_and_ai"),
914+
)
915+
}
916+
917+
@Test
918+
fun `when onConfirmed called with SEARCH_ONLY then DUCK_CHAT_NEW_ADDRESS_BAR_PICKER_CONFIRMED pixel is fired with search_only`() = runTest {
919+
var capturedCallback: NewAddressBarCallback? = null
920+
whenever(mockNewAddressBarOptionBottomSheetDialogFactory.create(any(), any(), any())).thenAnswer { invocation ->
921+
capturedCallback = invocation.getArgument<NewAddressBarCallback?>(2)
922+
mockNewAddressBarOptionBottomSheetDialog
923+
}
924+
925+
val mockContext = mock<Context>()
926+
testee.showNewAddressBarOptionChoiceScreen(mockContext, true)
927+
928+
verify(mockNewAddressBarOptionBottomSheetDialogFactory).create(
929+
any(),
930+
any(),
931+
any(),
932+
)
933+
934+
verify(mockNewAddressBarOptionBottomSheetDialog).show()
935+
936+
assertNotNull(capturedCallback)
937+
capturedCallback!!.onConfirmed(SEARCH_ONLY)
938+
939+
verify(mockDuckChatFeatureRepository, times(0)).setInputScreenUserSetting(any())
940+
verify(mockPixel).fire(
941+
pixel = DUCK_CHAT_NEW_ADDRESS_BAR_PICKER_CONFIRMED,
942+
parameters = mapOf(NEW_ADDRESS_BAR_SELECTION to "search_only"),
943+
)
944+
}
945+
946+
@Test
947+
fun `when onNotNow called then DUCK_CHAT_NEW_ADDRESS_BAR_PICKER_NOT_NOW pixel is fired`() = runTest {
948+
var capturedCallback: NewAddressBarCallback? = null
949+
whenever(mockNewAddressBarOptionBottomSheetDialogFactory.create(any(), any(), any())).thenAnswer { invocation ->
950+
capturedCallback = invocation.getArgument<NewAddressBarCallback?>(2)
951+
mockNewAddressBarOptionBottomSheetDialog
952+
}
953+
954+
val mockContext = mock<Context>()
955+
testee.showNewAddressBarOptionChoiceScreen(mockContext, true)
956+
957+
verify(mockNewAddressBarOptionBottomSheetDialogFactory).create(
958+
any(),
959+
any(),
960+
any(),
961+
)
962+
963+
verify(mockNewAddressBarOptionBottomSheetDialog).show()
964+
965+
assertNotNull(capturedCallback)
966+
capturedCallback!!.onNotNow()
967+
968+
verify(mockDuckChatFeatureRepository, times(0)).setInputScreenUserSetting(any())
969+
verify(mockPixel).fire(DUCK_CHAT_NEW_ADDRESS_BAR_PICKER_NOT_NOW)
879970
}
880971

881972
companion object {

0 commit comments

Comments
 (0)