Skip to content

Commit

Permalink
Feature/david/apptp/retention engagement (#1799)
Browse files Browse the repository at this point in the history
* add measurings for the time spent in the text heave screens

* cleanup and spotless

* ensure we are counting on screen time only

* added missing pixels

* added pixels for company trackers screen

* using the proper pixel this time

* fixed failing test

* proper pixel name

* fixed test

* added missing pixels
  • Loading branch information
malmstein authored Mar 25, 2022
1 parent f117976 commit 8183280
Show file tree
Hide file tree
Showing 9 changed files with 102 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import com.duckduckgo.mobile.android.vpn.apps.TrackingProtectionAppInfo
import com.duckduckgo.mobile.android.vpn.apps.ViewState
import com.duckduckgo.mobile.android.vpn.breakage.ReportBreakageContract
import com.duckduckgo.mobile.android.vpn.databinding.ActivityTrackingProtectionExclusionListBinding
import com.duckduckgo.mobile.android.vpn.pixels.DeviceShieldPixels
import com.duckduckgo.mobile.android.vpn.service.TrackerBlockingVpnService
import com.facebook.shimmer.ShimmerFrameLayout
import com.google.android.material.snackbar.BaseTransientBottomBar.LENGTH_LONG
Expand All @@ -57,6 +58,9 @@ class TrackingProtectionExclusionListActivity :
@AppCoroutineScope
lateinit var appCoroutineScope: CoroutineScope

@Inject
lateinit var deviceShieldPixels: DeviceShieldPixels

private val binding: ActivityTrackingProtectionExclusionListBinding by viewBinding()

private val viewModel: ExcludedAppsViewModel by bindViewModel()
Expand All @@ -80,6 +84,8 @@ class TrackingProtectionExclusionListActivity :

bindViews()
observeViewModel()

deviceShieldPixels.didShowExclusionListActivity()
}

override fun onCreateOptionsMenu(menu: Menu): Boolean {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,10 @@ enum class DeviceShieldPixelNames(override val pixelName: String) : Pixel.PixelN
ATP_KILLED_VPN_REVOKED("m_atp_ev_revoke_kill_c"),

ATP_DID_SHOW_PRIVACY_REPORT_ARTICLE("m_atp_imp_article_c"),
ATP_DID_SHOW_PRIVACY_REPORT_ARTICLE_DAILY("m_atp_imp_article_d"),

ATP_DID_SHOW_ONBOARDING_FAQ("m_atp_imp_onboarding_faq_c"),
ATP_DID_SHOW_ONBOARDING_FAQ_DAILY("m_atp_imp_onboarding_faq_d"),

ATP_ESTABLISH_TUN_INTERFACE_ERROR_DAILY("m_atp_ev_establish_tun_error_d"),
ATP_ESTABLISH_TUN_INTERFACE_ERROR("m_atp_ev_establish_tun_error_c"),
Expand Down Expand Up @@ -159,8 +161,25 @@ enum class DeviceShieldPixelNames(override val pixelName: String) : Pixel.PixelN
ATP_RECEIVED_UNKNOWN_PACKET_PROTOCOL_DAILY("m_atp_ev_unknown_packet_%d_d"),

ATP_DID_SHOW_VPN_CONFLICT_DIALOG("m_atp_imp_vpn_conflict_dialog_c"),
ATP_DID_CHOOSE_DISMISS_VPN_CONFLICT_DIALOG_DAILY("m_atp_ev_vpn_conflict_dialog_dismiss_d"),
ATP_DID_CHOOSE_DISMISS_VPN_CONFLICT_DIALOG("m_atp_ev_vpn_conflict_dialog_dismiss_c"),
ATP_DID_CHOOSE_OPEN_SETTINGS_VPN_CONFLICT_DIALOG_DAILY("m_atp_ev_vpn_conflict_dialog_open_settings_d"),
ATP_DID_CHOOSE_OPEN_SETTINGS_VPN_CONFLICT_DIALOG("m_atp_ev_vpn_conflict_dialog_open_settings_c"),
ATP_DID_CHOOSE_CONTINUIE_OPEN_SETTINGS_VPN_CONFLICT_DIALOG("m_atp_ev_vpn_conflict_dialog_continue_c"),
ATP_DID_CHOOSE_CONTINUE_VPN_CONFLICT_DIALOG("m_atp_ev_vpn_conflict_dialog_continue_c"),
ATP_DID_CHOOSE_CONTINUE_VPN_CONFLICT_DIALOG_DAILY("m_atp_ev_vpn_conflict_dialog_continue_d"),

ATP_DID_OPEN_BETA_INSTRUCTIONS("m_atp_imp_beta_instructions_c"),
ATP_DID_OPEN_BETA_INSTRUCTIONS_DAILY("m_atp_imp_beta_instructions_d"),

ATP_DID_SHOW_EXCLUSION_LIST_ACTIVITY_UNIQUE("m_atp_imp_exclusion_list_activity_u"),
ATP_DID_SHOW_EXCLUSION_LIST_ACTIVITY_DAILY("m_atp_imp_exclusion_list_activity_d"),
ATP_DID_SHOW_EXCLUSION_LIST_ACTIVITY("m_atp_imp_exclusion_list_activity_c"),
ATP_DID_OPEN_EXCLUSION_LIST_ACTIVITY_FROM_TRACKERS("m_atp_ev_exclusion_list_activity_open_trackers_c"),
ATP_DID_OPEN_EXCLUSION_LIST_ACTIVITY_FROM_TRACKERS_DAILY("m_atp_ev_exclusion_list_activity_open_trackers_d"),
ATP_DID_OPEN_EXCLUSION_LIST_ACTIVITY_FROM_TRACKERS_UNIQUE("m_atp_ev_exclusion_list_activity_open_trackers_u"),

ATP_DID_SHOW_COMPANY_TRACKERS_ACTIVITY_UNIQUE("m_atp_imp_company_trackers_activity_u"),
ATP_DID_SHOW_COMPANY_TRACKERS_ACTIVITY_DAILY("m_atp_imp_company_trackers_activity_d"),
ATP_DID_SHOW_COMPANY_TRACKERS_ACTIVITY("m_atp_imp_company_trackers_activity_c"),
;
}
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,27 @@ interface DeviceShieldPixels {
* Will fire when the VPN Process is restarted as a result of bad health mitigation
*/
fun didRestartVpnProcessOnBadHealth()

/** Will fire when Beta instructions CTA is pressed */
fun didOpenBetaInstructions()

/**
* This fun will fire two pixels
* daily -> fire only once a day no matter how many times we call this fun
* count -> fire a pixel on every call
*/
fun didShowExclusionListActivity()

/**
* Will fire when the user wants to open the Exclusion List Activity from the Trackers Screen
*/
fun didOpenExclusionListActivityFromTrackersScreen()

/**
* Will fire when the user opens the Company Trackers Screen
*/
fun didOpenCompanyTrackersScreen()

}

@ContributesBinding(AppScope::class)
Expand Down Expand Up @@ -502,10 +523,12 @@ class RealDeviceShieldPixels @Inject constructor(

override fun privacyReportArticleDisplayed() {
firePixel(DeviceShieldPixelNames.ATP_DID_SHOW_PRIVACY_REPORT_ARTICLE)
tryToFireDailyPixel(DeviceShieldPixelNames.ATP_DID_SHOW_PRIVACY_REPORT_ARTICLE_DAILY)
}

override fun privacyReportOnboardingFAQDisplayed() {
firePixel(DeviceShieldPixelNames.ATP_DID_SHOW_ONBOARDING_FAQ)
tryToFireDailyPixel(DeviceShieldPixelNames.ATP_DID_SHOW_ONBOARDING_FAQ_DAILY)
}

override fun vpnEstablishTunInterfaceError() {
Expand Down Expand Up @@ -604,18 +627,18 @@ class RealDeviceShieldPixels @Inject constructor(
}

override fun didChooseToDismissVpnConflicDialog() {
tryToFireDailyPixel(DeviceShieldPixelNames.ATP_DID_CHOOSE_DISMISS_VPN_CONFLICT_DIALOG)
tryToFireDailyPixel(DeviceShieldPixelNames.ATP_DID_CHOOSE_DISMISS_VPN_CONFLICT_DIALOG_DAILY)
firePixel(DeviceShieldPixelNames.ATP_DID_CHOOSE_DISMISS_VPN_CONFLICT_DIALOG)
}

override fun didChooseToOpenSettingsFromVpnConflicDialog() {
tryToFireDailyPixel(DeviceShieldPixelNames.ATP_DID_CHOOSE_OPEN_SETTINGS_VPN_CONFLICT_DIALOG)
tryToFireDailyPixel(DeviceShieldPixelNames.ATP_DID_CHOOSE_OPEN_SETTINGS_VPN_CONFLICT_DIALOG_DAILY)
firePixel(DeviceShieldPixelNames.ATP_DID_CHOOSE_OPEN_SETTINGS_VPN_CONFLICT_DIALOG)
}

override fun didChooseToContinueFromVpnConflicDialog() {
tryToFireDailyPixel(DeviceShieldPixelNames.ATP_DID_CHOOSE_OPEN_SETTINGS_VPN_CONFLICT_DIALOG)
firePixel(DeviceShieldPixelNames.ATP_DID_CHOOSE_OPEN_SETTINGS_VPN_CONFLICT_DIALOG)
tryToFireDailyPixel(DeviceShieldPixelNames.ATP_DID_CHOOSE_CONTINUE_VPN_CONFLICT_DIALOG_DAILY)
firePixel(DeviceShieldPixelNames.ATP_DID_CHOOSE_CONTINUE_VPN_CONFLICT_DIALOG)
}

override fun didShowWaitlistDialog() {
Expand Down Expand Up @@ -665,6 +688,32 @@ class RealDeviceShieldPixels @Inject constructor(
firePixel(DeviceShieldPixelNames.ATP_DID_RESTART_VPN_PROCESS_ON_BAD_HEALTH)
}

override fun didOpenBetaInstructions() {
tryToFireDailyPixel(DeviceShieldPixelNames.ATP_DID_OPEN_BETA_INSTRUCTIONS_DAILY)
firePixel(DeviceShieldPixelNames.ATP_DID_OPEN_BETA_INSTRUCTIONS)
}

override fun didShowExclusionListActivity() {
tryToFireUniquePixel(DeviceShieldPixelNames.ATP_DID_SHOW_EXCLUSION_LIST_ACTIVITY_UNIQUE)
tryToFireDailyPixel(DeviceShieldPixelNames.ATP_DID_SHOW_EXCLUSION_LIST_ACTIVITY_DAILY)
firePixel(DeviceShieldPixelNames.ATP_DID_SHOW_EXCLUSION_LIST_ACTIVITY)
}

override fun didOpenExclusionListActivityFromTrackersScreen() {
tryToFireUniquePixel(
DeviceShieldPixelNames.ATP_DID_OPEN_EXCLUSION_LIST_ACTIVITY_FROM_TRACKERS_UNIQUE,
tag = FIRST_OPEN_ENTRY_POINT_TAG
)
tryToFireDailyPixel(DeviceShieldPixelNames.ATP_DID_OPEN_EXCLUSION_LIST_ACTIVITY_FROM_TRACKERS_DAILY)
firePixel(DeviceShieldPixelNames.ATP_DID_OPEN_EXCLUSION_LIST_ACTIVITY_FROM_TRACKERS)
}

override fun didOpenCompanyTrackersScreen() {
tryToFireUniquePixel(DeviceShieldPixelNames.ATP_DID_SHOW_COMPANY_TRACKERS_ACTIVITY_UNIQUE)
tryToFireDailyPixel(DeviceShieldPixelNames.ATP_DID_SHOW_COMPANY_TRACKERS_ACTIVITY_DAILY)
firePixel(DeviceShieldPixelNames.ATP_DID_SHOW_COMPANY_TRACKERS_ACTIVITY)
}

private fun suddenKill() {
firePixel(DeviceShieldPixelNames.ATP_KILLED)
}
Expand Down Expand Up @@ -727,6 +776,7 @@ class RealDeviceShieldPixels @Inject constructor(

companion object {
private const val FIRST_ENABLE_ENTRY_POINT_TAG = "FIRST_ENABLE_ENTRY_POINT_TAG"
private const val FIRST_OPEN_ENTRY_POINT_TAG = "FIRST_OPEN_ENTRY_POINT_TAG"

@VisibleForTesting
const val DS_PIXELS_PREF_FILE = "com.duckduckgo.mobile.android.device.shield.pixels"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ class DeviceShieldOnboardingActivity : AppCompatActivity(R.layout.activity_devic
private fun configureUI() {
viewPager.adapter = DeviceShieldOnboardingAdapter(viewModel.pages)
viewPager.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {

override fun onPageSelected(position: Int) {
showOnboardingPage(position)
super.onPageSelected(position)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,23 @@ import android.os.Bundle
import com.duckduckgo.app.global.DuckDuckGoActivity
import com.duckduckgo.mobile.android.ui.viewbinding.viewBinding
import com.duckduckgo.mobile.android.vpn.databinding.ActivityAppTrackersInfoBinding
import com.duckduckgo.mobile.android.vpn.pixels.DeviceShieldPixels
import javax.inject.Inject

class DeviceShieldAppTrackersInfo : DuckDuckGoActivity() {

@Inject
lateinit var deviceShieldPixels: DeviceShieldPixels

private val binding: ActivityAppTrackersInfoBinding by viewBinding()

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

setContentView(binding.root)
setupToolbar(binding.includeToolbar.toolbar)

deviceShieldPixels.privacyReportArticleDisplayed()
}

override fun onSupportNavigateUp(): Boolean {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,19 @@ import com.duckduckgo.mobile.android.vpn.R
import com.duckduckgo.mobile.android.vpn.breakage.ReportBreakageContract
import com.duckduckgo.mobile.android.vpn.breakage.ReportBreakageScreen
import com.duckduckgo.mobile.android.vpn.databinding.ActivityApptpCompanyTrackersActivityBinding
import com.duckduckgo.mobile.android.vpn.pixels.DeviceShieldPixels
import com.duckduckgo.mobile.android.vpn.ui.onboarding.DeviceShieldFAQActivity
import com.google.android.material.snackbar.Snackbar
import kotlinx.android.synthetic.main.include_company_trackers_toolbar.*
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
import javax.inject.Inject

class AppTPCompanyTrackersActivity : DuckDuckGoActivity() {

@Inject
lateinit var pixels: DeviceShieldPixels

private val binding: ActivityApptpCompanyTrackersActivityBinding by viewBinding()
private val viewModel: AppTPCompanyTrackersViewModel by bindViewModel()

Expand Down Expand Up @@ -74,6 +79,8 @@ class AppTPCompanyTrackersActivity : DuckDuckGoActivity() {

observeViewModel()
binding.activityRecyclerView.adapter = itemsAdapter

pixels.didOpenCompanyTrackersScreen()
}

private fun observeViewModel() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,7 @@ class DeviceShieldTrackerActivity :
}

private fun launchExcludedApps(shouldListBeEnabled: Boolean) {
deviceShieldPixels.didOpenExclusionListActivityFromTrackersScreen()
startActivity(TrackingProtectionExclusionListActivity.intent(this, shouldListBeEnabled))
}

Expand Down Expand Up @@ -258,6 +259,7 @@ class DeviceShieldTrackerActivity :
}

override fun onOpenAppProtection() {
deviceShieldPixels.didChooseToDisableOneAppFromDialog()
viewModel.onViewEvent(DeviceShieldTrackerActivityViewModel.ViewEvent.LaunchExcludedApps)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,6 @@ class DeviceShieldTrackerActivityViewModel @Inject constructor(
viewModelScope.launch(dispatcherProvider.io()) {
val vpnState = vpnStateMonitor.getState().state
sendCommand(Command.LaunchExcludedApps(vpnState == VpnRunningState.ENABLED))
deviceShieldPixels.didChooseToDisableOneAppFromDialog()
}
}

Expand All @@ -125,11 +124,11 @@ class DeviceShieldTrackerActivityViewModel @Inject constructor(
internal fun onViewEvent(viewEvent: ViewEvent) {
viewModelScope.launch {
when (viewEvent) {
ViewEvent.LaunchAppTrackersFAQ -> {
deviceShieldPixels.privacyReportArticleDisplayed()
command.send(Command.LaunchAppTrackersFAQ)
ViewEvent.LaunchAppTrackersFAQ -> command.send(Command.LaunchAppTrackersFAQ)
ViewEvent.LaunchBetaInstructions -> {
deviceShieldPixels.didOpenBetaInstructions()
command.send(Command.LaunchBetaInstructions)
}
ViewEvent.LaunchBetaInstructions -> command.send(Command.LaunchBetaInstructions)
ViewEvent.LaunchDeviceShieldFAQ -> command.send(Command.LaunchDeviceShieldFAQ)
ViewEvent.LaunchExcludedApps -> launchExcludedApps()
ViewEvent.LaunchMostRecentActivity -> command.send(Command.LaunchMostRecentActivity)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,7 @@ class RealDeviceShieldPixelsTest {
deviceShieldPixels.privacyReportArticleDisplayed()

verify(pixel, times(2)).fire(DeviceShieldPixelNames.ATP_DID_SHOW_PRIVACY_REPORT_ARTICLE.pixelName)
verify(pixel, times(1)).fire(DeviceShieldPixelNames.ATP_DID_SHOW_PRIVACY_REPORT_ARTICLE_DAILY.pixelName)
verifyNoMoreInteractions(pixel)
}

Expand Down

0 comments on commit 8183280

Please sign in to comment.