Skip to content

Commit 5746370

Browse files
authored
refresh subscription plan features on app fresh launch (#6460)
Task/Issue URL: https://app.asana.com/1/137249556945/project/72649045549333/task/1210887464493316?focus=true ### Description Refreshes subscriptions plans included feature on fresh launch. ### Steps to test this PR _Feature 1_ - [x] change debug package so it doesn't include `.debug` (to make subscriptions work) - [x] install the branch - [x] Check in the logs "Subscription features for base plan $basePlanId fetched: $features" - [x] Kill the app and start it again - [x] You should see in the logs again "Subscription features for base plan $basePlanId fetched: $features", which indicates we have fetched again the list of features for a planId ### UI changes | Before | After | | ------ | ----- | !(Upload before screenshot)|(Upload after screenshot)|
1 parent 0184484 commit 5746370

File tree

3 files changed

+45
-7
lines changed

3 files changed

+45
-7
lines changed

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,9 @@ interface PrivacyProFeature {
213213

214214
@Toggle.DefaultValue(DefaultFeatureValue.INTERNAL)
215215
fun subscriptionRebranding(): Toggle
216+
217+
@Toggle.DefaultValue(DefaultFeatureValue.TRUE)
218+
fun refreshSubscriptionPlanFeatures(): Toggle
216219
}
217220

218221
@ContributesBinding(AppScope::class)

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

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,16 @@ class SubscriptionFeaturesFetcher @Inject constructor(
6969
?.find { it.productId == BASIC_SUBSCRIPTION }
7070
?.subscriptionOfferDetails
7171
?.map { it.basePlanId }
72-
?.filter { authRepository.getFeatures(it).isEmpty() }
72+
?.distinct()
73+
?.let { basePlanIds ->
74+
if (privacyProFeature.refreshSubscriptionPlanFeatures().isEnabled()) {
75+
basePlanIds
76+
} else {
77+
basePlanIds.filter {
78+
authRepository.getFeatures(it).isEmpty()
79+
}
80+
}
81+
}
7382
?.forEach { basePlanId ->
7483
val features = subscriptionsService.features(basePlanId).features
7584
logcat { "Subscription features for base plan $basePlanId fetched: $features" }

subscriptions/subscriptions-impl/src/test/java/com/duckduckgo/subscriptions/impl/SubscriptionFeaturesFetcherTest.kt

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import com.android.billingclient.api.ProductDetails.SubscriptionOfferDetails
1212
import com.duckduckgo.common.test.CoroutineTestRule
1313
import com.duckduckgo.feature.toggles.api.FakeFeatureToggleFactory
1414
import com.duckduckgo.feature.toggles.api.Toggle.State
15+
import com.duckduckgo.subscriptions.impl.SubscriptionsConstants.DUCK_AI
1516
import com.duckduckgo.subscriptions.impl.SubscriptionsConstants.ITR
1617
import com.duckduckgo.subscriptions.impl.SubscriptionsConstants.MONTHLY_PLAN_US
1718
import com.duckduckgo.subscriptions.impl.SubscriptionsConstants.NETP
@@ -76,15 +77,15 @@ class SubscriptionFeaturesFetcherTest {
7677
val productDetails = mockProductDetails()
7778
whenever(playBillingManager.productsFlow).thenReturn(flowOf(productDetails))
7879
whenever(authRepository.getFeatures(any())).thenReturn(emptySet())
79-
whenever(subscriptionsService.features(any())).thenReturn(FeaturesResponse(listOf(NETP, ITR)))
80+
whenever(subscriptionsService.features(any())).thenReturn(FeaturesResponse(listOf(NETP, ITR, DUCK_AI)))
8081

8182
processLifecycleOwner.currentState = CREATED
8283

8384
verify(playBillingManager).productsFlow
84-
verify(authRepository).getFeatures(MONTHLY_PLAN_US)
85-
verify(authRepository).getFeatures(YEARLY_PLAN_US)
86-
verify(authRepository).setFeatures(MONTHLY_PLAN_US, setOf(NETP, ITR))
87-
verify(authRepository).setFeatures(YEARLY_PLAN_US, setOf(NETP, ITR))
85+
verify(subscriptionsService).features(MONTHLY_PLAN_US)
86+
verify(subscriptionsService).features(YEARLY_PLAN_US)
87+
verify(authRepository).setFeatures(MONTHLY_PLAN_US, setOf(NETP, ITR, DUCK_AI))
88+
verify(authRepository).setFeatures(YEARLY_PLAN_US, setOf(NETP, ITR, DUCK_AI))
8889
}
8990

9091
@Test
@@ -100,11 +101,13 @@ class SubscriptionFeaturesFetcherTest {
100101
}
101102

102103
@Test
103-
fun `when features already stored then does not fetch again`() = runTest {
104+
fun `when features already stored and refresh features FF Disabled then does not fetch again`() = runTest {
105+
givenRefreshSubscriptionPlanFeaturesEnabled(false)
104106
givenIsFeaturesApiEnabled(true)
105107
val productDetails = mockProductDetails()
106108
whenever(playBillingManager.productsFlow).thenReturn(flowOf(productDetails))
107109
whenever(authRepository.getFeatures(any())).thenReturn(setOf(NETP, ITR))
110+
whenever(subscriptionsService.features(any())).thenReturn(FeaturesResponse(listOf(NETP, ITR)))
108111

109112
processLifecycleOwner.currentState = CREATED
110113

@@ -115,11 +118,34 @@ class SubscriptionFeaturesFetcherTest {
115118
verifyNoInteractions(subscriptionsService)
116119
}
117120

121+
@Test
122+
fun `when features already stored and refresh features FF enabled then does fetch again`() = runTest {
123+
givenRefreshSubscriptionPlanFeaturesEnabled(true)
124+
givenIsFeaturesApiEnabled(true)
125+
val productDetails = mockProductDetails()
126+
whenever(playBillingManager.productsFlow).thenReturn(flowOf(productDetails))
127+
whenever(authRepository.getFeatures(any())).thenReturn(setOf(NETP, ITR))
128+
whenever(subscriptionsService.features(any())).thenReturn(FeaturesResponse(listOf(NETP, ITR, DUCK_AI)))
129+
130+
processLifecycleOwner.currentState = CREATED
131+
132+
verify(playBillingManager).productsFlow
133+
verify(subscriptionsService).features(MONTHLY_PLAN_US)
134+
verify(subscriptionsService).features(YEARLY_PLAN_US)
135+
verify(authRepository).setFeatures(MONTHLY_PLAN_US, setOf(NETP, ITR, DUCK_AI))
136+
verify(authRepository).setFeatures(YEARLY_PLAN_US, setOf(NETP, ITR, DUCK_AI))
137+
}
138+
118139
@SuppressLint("DenyListedApi")
119140
private fun givenIsFeaturesApiEnabled(value: Boolean) {
120141
privacyProFeature.featuresApi().setRawStoredState(State(value))
121142
}
122143

144+
@SuppressLint("DenyListedApi")
145+
private fun givenRefreshSubscriptionPlanFeaturesEnabled(value: Boolean) {
146+
privacyProFeature.refreshSubscriptionPlanFeatures().setRawStoredState(State(value))
147+
}
148+
123149
private fun mockProductDetails(): List<ProductDetails> {
124150
val productDetails: ProductDetails = mock { productDetails ->
125151
whenever(productDetails.productId).thenReturn(SubscriptionsConstants.BASIC_SUBSCRIPTION)

0 commit comments

Comments
 (0)