diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index fd920c020e..e54f89f97d 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -35,6 +35,7 @@
+
()
private val observeMailFeature = mockk()
+ private val npsEnabled = mockk>()
- private val sut = ObserveNPSEligibility(
- observePrimaryUser,
- observeMailFeature
- )
+ private val sut: ObserveNPSEligibility
+ get() = ObserveNPSEligibility(
+ observePrimaryUser,
+ observeMailFeature,
+ npsEnabled.get()
+ )
private val user = UserSample.Primary
@Test
fun `should emit false when primary user is null`() = runTest {
every { observePrimaryUser() } returns flowOf(null)
+ expectNPSEnabled(true)
sut().test {
assertEquals(false, awaitItem())
awaitComplete()
@@ -53,9 +58,20 @@ internal class ObserveNPSEligibilityTest {
}
@Test
- fun `should emit false when mail feature flag is disabled`() = runTest {
+ fun `should emit false when FF disabled`() = runTest {
every { observePrimaryUser() } returns flowOf(user)
- isFFEnabled(false)
+ expectNPSEnabled(false)
+ sut().test {
+ assertEquals(false, awaitItem())
+ awaitComplete()
+ }
+ }
+
+ @Test
+ fun `should emit false when per-user feature flag is disabled`() = runTest {
+ every { observePrimaryUser() } returns flowOf(user)
+ expectPerUserFlagEnabled(false)
+ expectNPSEnabled(true)
sut().test {
assertEquals(false, awaitItem())
@@ -66,7 +82,8 @@ internal class ObserveNPSEligibilityTest {
@Test
fun `should emit true when feature enabled`() = runTest {
every { observePrimaryUser() } returns flowOf(user)
- isFFEnabled(true)
+ expectPerUserFlagEnabled(true)
+ expectNPSEnabled(true)
sut().test {
assertEquals(true, awaitItem())
@@ -74,8 +91,12 @@ internal class ObserveNPSEligibilityTest {
}
}
- private fun isFFEnabled(enabled: Boolean) {
+ private fun expectPerUserFlagEnabled(enabled: Boolean) {
every { observeMailFeature(user.userId, MailFeatureId.NPSFeedback) } returns
flowOf(FeatureFlag.default("ff1", defaultValue = enabled))
}
+
+ private fun expectNPSEnabled(value: Boolean) {
+ every { npsEnabled.get() } returns value
+ }
}
diff --git a/mail-upselling/dagger/src/main/kotlin/ch/protonmail/android/mailupselling/dagger/UpsellingModule.kt b/mail-upselling/dagger/src/main/kotlin/ch/protonmail/android/mailupselling/dagger/UpsellingModule.kt
index fec4a147cf..5385305bc0 100644
--- a/mail-upselling/dagger/src/main/kotlin/ch/protonmail/android/mailupselling/dagger/UpsellingModule.kt
+++ b/mail-upselling/dagger/src/main/kotlin/ch/protonmail/android/mailupselling/dagger/UpsellingModule.kt
@@ -29,6 +29,7 @@ import ch.protonmail.android.mailupselling.domain.annotations.DriveSpotlightEnab
import ch.protonmail.android.mailupselling.domain.annotations.ForceOneClickUpsellingDetailsOverride
import ch.protonmail.android.mailupselling.domain.annotations.HeaderUpsellSocialProofLayoutEnabled
import ch.protonmail.android.mailupselling.domain.annotations.HeaderUpsellVariantLayoutEnabled
+import ch.protonmail.android.mailupselling.domain.annotations.NPSEnabled
import ch.protonmail.android.mailupselling.domain.annotations.OneClickUpsellingAlwaysShown
import ch.protonmail.android.mailupselling.domain.annotations.OneClickUpsellingTelemetryEnabled
import ch.protonmail.android.mailupselling.domain.annotations.SidebarUpsellingEnabled
@@ -48,6 +49,7 @@ import ch.protonmail.android.mailupselling.domain.usecase.featureflags.AlwaysSho
import ch.protonmail.android.mailupselling.domain.usecase.featureflags.IsDriveSpotlightEnabled
import ch.protonmail.android.mailupselling.domain.usecase.featureflags.IsHeaderUpsellSocialProofLayoutEnabled
import ch.protonmail.android.mailupselling.domain.usecase.featureflags.IsHeaderUpsellVariantLayoutEnabled
+import ch.protonmail.android.mailupselling.domain.usecase.featureflags.IsNPSEnabled
import ch.protonmail.android.mailupselling.domain.usecase.featureflags.IsOneClickUpsellingTelemetryEnabled
import ch.protonmail.android.mailupselling.domain.usecase.featureflags.IsSidebarUpsellingEnabled
import ch.protonmail.android.mailupselling.domain.usecase.featureflags.IsSignupPaidPlanSupportEnabled
@@ -101,6 +103,10 @@ object UpsellingModule {
@DriveSpotlightEnabled
fun provideDriveSpotlightEnabled(isEnabled: IsDriveSpotlightEnabled) = isEnabled(null)
+ @Provides
+ @NPSEnabled
+ fun provideNPSEnabled(isEnabled: IsNPSEnabled) = isEnabled(null)
+
@Provides
@HeaderUpsellSocialProofLayoutEnabled
fun provideUpsellSocialProofLayoutEnabled(isEnabled: IsHeaderUpsellSocialProofLayoutEnabled) = isEnabled(null)
diff --git a/mail-upselling/domain/src/main/kotlin/ch/protonmail/android/mailupselling/domain/annotations/NPSEnabled.kt b/mail-upselling/domain/src/main/kotlin/ch/protonmail/android/mailupselling/domain/annotations/NPSEnabled.kt
new file mode 100644
index 0000000000..7b9934c7a6
--- /dev/null
+++ b/mail-upselling/domain/src/main/kotlin/ch/protonmail/android/mailupselling/domain/annotations/NPSEnabled.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2022 Proton Technologies AG
+ * This file is part of Proton Technologies AG and Proton Mail.
+ *
+ * Proton Mail is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Proton Mail is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Proton Mail. If not, see .
+ */
+
+package ch.protonmail.android.mailupselling.domain.annotations
+
+import javax.inject.Qualifier
+
+/**
+ * Indicates whether the NPS is enabled. If disabled, individual user' feature flags will not be checked further.
+ */
+@Qualifier
+annotation class NPSEnabled
diff --git a/mail-upselling/domain/src/main/kotlin/ch/protonmail/android/mailupselling/domain/repository/GetInstalledProtonApps.kt b/mail-upselling/domain/src/main/kotlin/ch/protonmail/android/mailupselling/domain/repository/GetInstalledProtonApps.kt
index fc9eba87b1..56a1689c5c 100644
--- a/mail-upselling/domain/src/main/kotlin/ch/protonmail/android/mailupselling/domain/repository/GetInstalledProtonApps.kt
+++ b/mail-upselling/domain/src/main/kotlin/ch/protonmail/android/mailupselling/domain/repository/GetInstalledProtonApps.kt
@@ -57,5 +57,6 @@ private val ProtonPackages = listOf(
"me.proton.android.drive",
"me.proton.android.calendar",
"proton.android.pass",
- "me.proton.wallet.android"
+ "me.proton.wallet.android",
+ "me.proton.android.lumo"
)
diff --git a/mail-upselling/domain/src/main/kotlin/ch/protonmail/android/mailupselling/domain/usecase/featureflags/IsNPSEnabled.kt b/mail-upselling/domain/src/main/kotlin/ch/protonmail/android/mailupselling/domain/usecase/featureflags/IsNPSEnabled.kt
new file mode 100644
index 0000000000..cf9d5584d6
--- /dev/null
+++ b/mail-upselling/domain/src/main/kotlin/ch/protonmail/android/mailupselling/domain/usecase/featureflags/IsNPSEnabled.kt
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2022 Proton Technologies AG
+ * This file is part of Proton Technologies AG and Proton Mail.
+ *
+ * Proton Mail is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Proton Mail is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Proton Mail. If not, see .
+ */
+
+package ch.protonmail.android.mailupselling.domain.usecase.featureflags
+
+import me.proton.core.domain.entity.UserId
+import me.proton.core.featureflag.domain.ExperimentalProtonFeatureFlag
+import me.proton.core.featureflag.domain.FeatureFlagManager
+import me.proton.core.featureflag.domain.entity.FeatureId
+import javax.inject.Inject
+
+class IsNPSEnabled @Inject constructor(
+ private val featureFlagManager: FeatureFlagManager
+) {
+
+ @OptIn(ExperimentalProtonFeatureFlag::class)
+ operator fun invoke(userId: UserId?) = featureFlagManager.getValue(userId, FeatureId(FeatureFlagId))
+
+ private companion object {
+
+ const val FeatureFlagId = "MailAndroidNpsFeedback"
+ }
+}
diff --git a/mail-upselling/domain/src/test/kotlin/ch/protonmail/android/mailupselling/domain/repository/GetInstalledProtonAppsTest.kt b/mail-upselling/domain/src/test/kotlin/ch/protonmail/android/mailupselling/domain/repository/GetInstalledProtonAppsTest.kt
index d4e07bc130..bd07060b54 100644
--- a/mail-upselling/domain/src/test/kotlin/ch/protonmail/android/mailupselling/domain/repository/GetInstalledProtonAppsTest.kt
+++ b/mail-upselling/domain/src/test/kotlin/ch/protonmail/android/mailupselling/domain/repository/GetInstalledProtonAppsTest.kt
@@ -121,7 +121,8 @@ internal class GetInstalledProtonAppsTest {
"me.proton.android.drive" to "v2",
"me.proton.android.calendar" to "v3",
"proton.android.pass" to "v4",
- "me.proton.wallet.android" to "v5"
+ "me.proton.wallet.android" to "v5",
+ "me.proton.android.lumo" to "v6"
)
mockInstalled(*all.toTypedArray())
diff --git a/mail-upselling/presentation/src/main/kotlin/ch/protonmail/android/mailupselling/presentation/usecase/ObserveNPSEligibility.kt b/mail-upselling/presentation/src/main/kotlin/ch/protonmail/android/mailupselling/presentation/usecase/ObserveNPSEligibility.kt
index a4ddeb93bd..2fe3f3c658 100644
--- a/mail-upselling/presentation/src/main/kotlin/ch/protonmail/android/mailupselling/presentation/usecase/ObserveNPSEligibility.kt
+++ b/mail-upselling/presentation/src/main/kotlin/ch/protonmail/android/mailupselling/presentation/usecase/ObserveNPSEligibility.kt
@@ -21,6 +21,7 @@ package ch.protonmail.android.mailupselling.presentation.usecase
import ch.protonmail.android.mailcommon.domain.MailFeatureId
import ch.protonmail.android.mailcommon.domain.usecase.ObserveMailFeature
import ch.protonmail.android.mailcommon.domain.usecase.ObservePrimaryUser
+import ch.protonmail.android.mailupselling.domain.annotations.DriveSpotlightEnabled
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.flatMapLatest
@@ -30,12 +31,14 @@ import javax.inject.Inject
class ObserveNPSEligibility @Inject constructor(
private val observePrimaryUser: ObservePrimaryUser,
- private val observeMailFeature: ObserveMailFeature
+ private val observeMailFeature: ObserveMailFeature,
+ @DriveSpotlightEnabled private val driveSpotlightEnabled: Boolean
) {
operator fun invoke(): Flow = observePrimaryUser()
.distinctUntilChanged()
.flatMapLatest { user ->
if (user == null) return@flatMapLatest flowOf(false)
+ if (!driveSpotlightEnabled) return@flatMapLatest flowOf(false)
observeMailFeature(user.userId, MailFeatureId.NPSFeedback).map { npsFeatureFlag ->
npsFeatureFlag.value
}