Skip to content

Commit 94c9202

Browse files
authored
Privacy Pro: Implement Free Trials to all users (#6165)
Task/Issue URL: https://app.asana.com/1/137249556945/project/72649045549333/task/1210327090176006 ### Description Added support for Free Trials to all users ### Steps to test this PR _Pre steps_ - Apply Privacy Pro patch attached to https://app.asana.com/1/137249556945/project/1142021229838617/task/1210426885327765?focus=true - That patch would point privacy config to `https://jsonblob.com/api/1339653006785961984` which has the `privacyProFreeTrial` enabled - It also includes staging URLs for new offers _Free Trials ROW_ - [x] Set a ROW Google account - [x] Fresh install - [x] Go to Settings, and check 'Try Privacy Pro Free' is displayed in the Settings menu - [x] Tap on Privacy Pro which will display the paywall screen - [x] Check you see the free trial products on paywall - [x] Select any product - [x] Check you can buy the free trial correctly - [x] Check Subscription Settings screen is showing status/renewal dates correctly for Free Trial - [x] Cancel subscription (when still on Free Trial) - [x] Check Subscription Settings screen is showing status/expire dates correctly for Free Trial - [x] Wait until it expires - [ ] Go to Settings and check you don't see 'Try Privacy Pro Free' anymore, but instead 'Get Privacy Pro' - [x] Check Subscription Settings screen is showing status/expired state correctly - [x] Go to Paywall again - [x] Check you are offered full price subscriptions _Free Trials (US)_ - [x] Set a US Google account - [x] Fresh install - [x] Go to Settings, and check 'Try Privacy Pro Free' is displayed in the Settings menu - [x] Tap on Privacy Pro which will display the paywall screen - [x] Check you see the free trial products on paywall - [x] Select any product - [x] Check you can buy the free trial correctly - [x] Check Subscription Settings screen is showing status/renewal dates correctly for Free Trial - [x] Cancel subscription (when still on Free Trial) - [x] Check Subscription Settings screen is showing status/expire dates correctly for Free Trial - [x] Wait until it expires - [ ] Go to Settings and check you don't see 'Try Privacy Pro Free' anymore, but instead 'Get Privacy Pro' - [x] Check Subscription Settings screen is showing status/expired state correctly - [x] Go to Paywall again - [x] Check you are offered full price subscriptions _Translations_ - [x] Set the device to a different language - [x] Use a Privacy Pro eligible Google account - [x] Follow the same steps as before, ensuring translations are available on all screens ### UI changes - See #5686
1 parent 1ae312b commit 94c9202

File tree

18 files changed

+181
-498
lines changed

18 files changed

+181
-498
lines changed

subscriptions/subscriptions-api/src/main/java/com/duckduckgo/subscriptions/api/Subscriptions.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,11 @@ interface Subscriptions {
7676
* @return `true` if the given Uri leads to the Privacy Pro page, or `false` otherwise
7777
*/
7878
fun isPrivacyProUrl(uri: Uri): Boolean
79+
80+
/**
81+
* @return `true` if a Free Trial offer is available for the user, `false` otherwise
82+
*/
83+
suspend fun isFreeTrialEligible(): Boolean
7984
}
8085

8186
enum class Product(val value: String) {

subscriptions/subscriptions-dummy-impl/src/main/java/com/duckduckgo/subscriptions/impl/SubscriptionsDummy.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,4 +52,6 @@ class SubscriptionsDummy @Inject constructor() : Subscriptions {
5252
}
5353

5454
override fun isPrivacyProUrl(uri: Uri): Boolean = false
55+
56+
override suspend fun isFreeTrialEligible(): Boolean = false
5557
}

subscriptions/subscriptions-impl/src/main/java/com/duckduckgo/subscriptions/impl/RealSubscriptions.kt

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ import com.duckduckgo.feature.toggles.api.RemoteFeatureStoreNamed
3434
import com.duckduckgo.feature.toggles.api.Toggle
3535
import com.duckduckgo.feature.toggles.api.Toggle.DefaultFeatureValue
3636
import com.duckduckgo.feature.toggles.api.Toggle.State
37-
import com.duckduckgo.feature.toggles.api.Toggle.State.CohortName
3837
import com.duckduckgo.navigation.api.GlobalActivityStarter
3938
import com.duckduckgo.subscriptions.api.Product
4039
import com.duckduckgo.subscriptions.api.SubscriptionStatus
@@ -127,6 +126,10 @@ class RealSubscriptions @Inject constructor(
127126
val path = uri.pathSegments.firstOrNull()
128127
return eTld == PRIVACY_PRO_ETLD && size == 1 && path == PRIVACY_PRO_PATH
129128
}
129+
130+
override suspend fun isFreeTrialEligible(): Boolean {
131+
return subscriptionsManager.isFreeTrialEligible()
132+
}
130133
}
131134

132135
@ContributesRemoteFeature(
@@ -162,12 +165,7 @@ interface PrivacyProFeature {
162165
fun featuresApi(): Toggle
163166

164167
@Toggle.DefaultValue(DefaultFeatureValue.FALSE)
165-
fun privacyProFreeTrialJan25(): Toggle
166-
167-
enum class Cohorts(override val cohortName: String) : CohortName {
168-
CONTROL("control"),
169-
TREATMENT("treatment"),
170-
}
168+
fun privacyProFreeTrial(): Toggle
171169
}
172170

173171
@ContributesBinding(AppScope::class)

subscriptions/subscriptions-impl/src/main/java/com/duckduckgo/subscriptions/impl/SubscriptionsConstants.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@ object SubscriptionsConstants {
3131
// List of offers
3232
const val MONTHLY_FREE_TRIAL_OFFER_US = "ddg-privacy-pro-freetrial-monthly-renews-us"
3333
const val YEARLY_FREE_TRIAL_OFFER_US = "ddg-privacy-pro-freetrial-yearly-renews-us"
34+
const val MONTHLY_FREE_TRIAL_OFFER_ROW = "ddg-privacy-pro-freetrial-monthly-renews-row"
35+
const val YEARLY_FREE_TRIAL_OFFER_ROW = "ddg-privacy-pro-freetrial-yearly-renews-row"
36+
val LIST_OF_FREE_TRIAL_OFFERS =
37+
listOf(MONTHLY_FREE_TRIAL_OFFER_US, YEARLY_FREE_TRIAL_OFFER_US, MONTHLY_FREE_TRIAL_OFFER_ROW, YEARLY_FREE_TRIAL_OFFER_ROW)
3438

3539
// List of features
3640
const val LEGACY_FE_NETP = "vpn"

subscriptions/subscriptions-impl/src/main/java/com/duckduckgo/subscriptions/impl/SubscriptionsManager.kt

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -222,11 +222,9 @@ interface SubscriptionsManager {
222222
suspend fun canSupportEncryption(): Boolean
223223

224224
/**
225-
* Checks whether the user has previously used a trial.
226-
*
227-
* @return [Boolean] indicating if the user has had a trial before.
225+
* @return `true` if a Free Trial offer is available for the user, `false` otherwise
228226
*/
229-
suspend fun hadTrial(): Boolean
227+
suspend fun isFreeTrialEligible(): Boolean
230228
}
231229

232230
@SingleInstanceIn(AppScope::class)
@@ -343,12 +341,13 @@ class RealSubscriptionsManager @Inject constructor(
343341

344342
override suspend fun canSupportEncryption(): Boolean = authRepository.canSupportEncryption()
345343

346-
override suspend fun hadTrial(): Boolean {
347-
return try {
348-
return subscriptionsService.offerStatus().hadTrial
344+
override suspend fun isFreeTrialEligible(): Boolean {
345+
val userHadFreeTrial = try {
346+
subscriptionsService.offerStatus().hadTrial
349347
} catch (e: Exception) {
350348
false
351349
}
350+
return !userHadFreeTrial && privacyProFeature.get().privacyProFreeTrial().isEnabled()
352351
}
353352

354353
override suspend fun getAccount(): Account? = authRepository.getAccount()
@@ -468,12 +467,6 @@ class RealSubscriptionsManager @Inject constructor(
468467
}
469468

470469
if (subscription.isActive()) {
471-
// Free Trial experiment metrics
472-
if (confirmationResponse.subscription.productId.contains("monthly-renews-us")) {
473-
pixelSender.reportFreeTrialOnSubscriptionStartedMonthly()
474-
} else if (confirmationResponse.subscription.productId.contains("yearly-renews-us")) {
475-
pixelSender.reportFreeTrialOnSubscriptionStartedYearly()
476-
}
477470
pixelSender.reportPurchaseSuccess()
478471
pixelSender.reportSubscriptionActivated()
479472
emitEntitlementsValues()

subscriptions/subscriptions-impl/src/main/java/com/duckduckgo/subscriptions/impl/freetrial/FreeTrialExperimentDataStore.kt

Lines changed: 0 additions & 99 deletions
This file was deleted.

subscriptions/subscriptions-impl/src/main/java/com/duckduckgo/subscriptions/impl/freetrial/FreeTrialPrivacyProMetricsPixelPlugin.kt

Lines changed: 0 additions & 138 deletions
This file was deleted.

subscriptions/subscriptions-impl/src/main/java/com/duckduckgo/subscriptions/impl/messaging/SubscriptionMessagingInterface.kt

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -230,14 +230,8 @@ class SubscriptionMessagingInterface @Inject constructor(
230230
) {
231231
appCoroutineScope.launch {
232232
when (jsMessage.method) {
233-
"subscriptionsMonthlyPriceClicked" -> {
234-
pixelSender.reportMonthlyPriceClick()
235-
pixelSender.reportFreeTrialOnStartClickedMonthly()
236-
}
237-
"subscriptionsYearlyPriceClicked" -> {
238-
pixelSender.reportYearlyPriceClick()
239-
pixelSender.reportFreeTrialOnStartClickedYearly()
240-
}
233+
"subscriptionsMonthlyPriceClicked" -> pixelSender.reportMonthlyPriceClick()
234+
"subscriptionsYearlyPriceClicked" -> pixelSender.reportYearlyPriceClick()
241235
"subscriptionsAddEmailSuccess" -> {
242236
pixelSender.reportAddEmailSuccess()
243237
subscriptionsManager.tryRefreshAccessToken()

0 commit comments

Comments
 (0)