diff options
| author | Jonatan Rhodin <jonatan.rhodin@mullvad.net> | 2023-11-16 00:53:05 +0100 |
|---|---|---|
| committer | Jonatan Rhodin <jonatan.rhodin@mullvad.net> | 2023-11-16 09:34:26 +0100 |
| commit | 5c5c2a95d676648ffbd953b5f9e8587a8a80bf66 (patch) | |
| tree | 8610db64ed64b1291a64f47581dbf8ef7006ecae /android | |
| parent | 4d70ef4349550ba88878ae17ee792af636fb2412 (diff) | |
| download | mullvadvpn-5c5c2a95d676648ffbd953b5f9e8587a8a80bf66.tar.xz mullvadvpn-5c5c2a95d676648ffbd953b5f9e8587a8a80bf66.zip | |
Add play purchasing android ipc calls
Diffstat (limited to 'android')
10 files changed, 123 insertions, 11 deletions
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/di/UiModule.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/di/UiModule.kt index bfd3f061d5..5be527ac0c 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/di/UiModule.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/di/UiModule.kt @@ -11,18 +11,22 @@ import net.mullvad.mullvadvpn.applist.ApplicationsIconManager import net.mullvad.mullvadvpn.applist.ApplicationsProvider import net.mullvad.mullvadvpn.dataproxy.MullvadProblemReport import net.mullvad.mullvadvpn.lib.ipc.EventDispatcher +import net.mullvad.mullvadvpn.lib.ipc.MessageHandler +import net.mullvad.mullvadvpn.lib.payment.PaymentProvider import net.mullvad.mullvadvpn.repository.AccountRepository import net.mullvad.mullvadvpn.repository.ChangelogRepository import net.mullvad.mullvadvpn.repository.DeviceRepository import net.mullvad.mullvadvpn.repository.InAppNotificationController import net.mullvad.mullvadvpn.repository.PrivacyDisclaimerRepository import net.mullvad.mullvadvpn.repository.SettingsRepository -import net.mullvad.mullvadvpn.ui.serviceconnection.MessageHandler import net.mullvad.mullvadvpn.ui.serviceconnection.RelayListListener import net.mullvad.mullvadvpn.ui.serviceconnection.ServiceConnectionManager import net.mullvad.mullvadvpn.ui.serviceconnection.SplitTunneling import net.mullvad.mullvadvpn.usecase.AccountExpiryNotificationUseCase +import net.mullvad.mullvadvpn.usecase.EmptyPaymentUseCase import net.mullvad.mullvadvpn.usecase.NewDeviceNotificationUseCase +import net.mullvad.mullvadvpn.usecase.PaymentUseCase +import net.mullvad.mullvadvpn.usecase.PlayPaymentUseCase import net.mullvad.mullvadvpn.usecase.PortRangeUseCase import net.mullvad.mullvadvpn.usecase.RelayListUseCase import net.mullvad.mullvadvpn.usecase.TunnelStateNotificationUseCase @@ -100,8 +104,20 @@ val uiModule = module { single { RelayListListener(get()) } + // Will be resolved using from either of the two PaymentModule.kt classes. + single { PaymentProvider(get()) } + + single<PaymentUseCase> { + val paymentRepository = get<PaymentProvider>().paymentRepository + if (paymentRepository != null) { + PlayPaymentUseCase(paymentRepository = paymentRepository) + } else { + EmptyPaymentUseCase() + } + } + // View models - viewModel { AccountViewModel(get(), get(), get()) } + viewModel { AccountViewModel(get(), get(), get(), get()) } viewModel { ChangelogViewModel(get(), BuildConfig.VERSION_CODE, BuildConfig.ALWAYS_SHOW_CHANGELOG) } @@ -114,10 +130,10 @@ val uiModule = module { viewModel { SettingsViewModel(get(), get()) } viewModel { VoucherDialogViewModel(get(), get()) } viewModel { VpnSettingsViewModel(get(), get(), get(), get(), get()) } - viewModel { WelcomeViewModel(get(), get(), get()) } + viewModel { WelcomeViewModel(get(), get(), get(), get()) } viewModel { ReportProblemViewModel(get()) } viewModel { ViewLogsViewModel(get()) } - viewModel { OutOfTimeViewModel(get(), get(), get()) } + viewModel { OutOfTimeViewModel(get(), get(), get(), get()) } } const val SELF_PACKAGE_NAME = "SELF_PACKAGE_NAME" diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/repository/AccountRepository.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/repository/AccountRepository.kt index 1d8c49224a..eb618ea0f8 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/repository/AccountRepository.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/repository/AccountRepository.kt @@ -17,13 +17,13 @@ import kotlinx.coroutines.flow.shareIn import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.withContext import net.mullvad.mullvadvpn.lib.ipc.Event +import net.mullvad.mullvadvpn.lib.ipc.MessageHandler import net.mullvad.mullvadvpn.lib.ipc.Request +import net.mullvad.mullvadvpn.lib.ipc.events import net.mullvad.mullvadvpn.model.AccountCreationResult import net.mullvad.mullvadvpn.model.AccountExpiry import net.mullvad.mullvadvpn.model.AccountHistory import net.mullvad.mullvadvpn.model.LoginResult -import net.mullvad.mullvadvpn.ui.serviceconnection.MessageHandler -import net.mullvad.mullvadvpn.ui.serviceconnection.events class AccountRepository( private val messageHandler: MessageHandler, diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/serviceconnection/RelayListListener.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/serviceconnection/RelayListListener.kt index 0a1767624c..30b8540bf9 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/serviceconnection/RelayListListener.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/serviceconnection/RelayListListener.kt @@ -9,7 +9,9 @@ import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.flow.stateIn import net.mullvad.mullvadvpn.lib.ipc.Event +import net.mullvad.mullvadvpn.lib.ipc.MessageHandler import net.mullvad.mullvadvpn.lib.ipc.Request +import net.mullvad.mullvadvpn.lib.ipc.events import net.mullvad.mullvadvpn.model.Constraint import net.mullvad.mullvadvpn.model.GeographicLocationConstraint import net.mullvad.mullvadvpn.model.Ownership diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/serviceconnection/ServiceConnectionManager.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/serviceconnection/ServiceConnectionManager.kt index 556d69ecfe..7f44b0c7d4 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/serviceconnection/ServiceConnectionManager.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/serviceconnection/ServiceConnectionManager.kt @@ -17,6 +17,7 @@ import net.mullvad.mullvadvpn.lib.endpoint.ApiEndpointConfiguration import net.mullvad.mullvadvpn.lib.endpoint.BuildConfig import net.mullvad.mullvadvpn.lib.endpoint.putApiEndpointConfigurationExtra import net.mullvad.mullvadvpn.lib.ipc.Event +import net.mullvad.mullvadvpn.lib.ipc.MessageHandler import net.mullvad.mullvadvpn.lib.ipc.Request import net.mullvad.mullvadvpn.service.MullvadVpnService import net.mullvad.mullvadvpn.util.flatMapReadyConnectionOrDefault diff --git a/android/lib/billing/src/main/kotlin/net/mullvad/mullvadvpn/lib/billing/PlayPurchaseRepository.kt b/android/lib/billing/src/main/kotlin/net/mullvad/mullvadvpn/lib/billing/PlayPurchaseRepository.kt new file mode 100644 index 0000000000..ac71372f76 --- /dev/null +++ b/android/lib/billing/src/main/kotlin/net/mullvad/mullvadvpn/lib/billing/PlayPurchaseRepository.kt @@ -0,0 +1,33 @@ +package net.mullvad.mullvadvpn.lib.billing + +import kotlinx.coroutines.flow.first +import net.mullvad.mullvadvpn.lib.ipc.Event +import net.mullvad.mullvadvpn.lib.ipc.MessageHandler +import net.mullvad.mullvadvpn.lib.ipc.Request +import net.mullvad.mullvadvpn.lib.ipc.events +import net.mullvad.mullvadvpn.model.PlayPurchase +import net.mullvad.mullvadvpn.model.PlayPurchaseInitError +import net.mullvad.mullvadvpn.model.PlayPurchaseInitResult +import net.mullvad.mullvadvpn.model.PlayPurchaseVerifyError +import net.mullvad.mullvadvpn.model.PlayPurchaseVerifyResult + +class PlayPurchaseRepository(private val messageHandler: MessageHandler) { + suspend fun initializePlayPurchase(): PlayPurchaseInitResult { + val result = messageHandler.trySendRequest(Request.InitPlayPurchase) + + return if (result) { + messageHandler.events<Event.PlayPurchaseInitResultEvent>().first().result + } else { + PlayPurchaseInitResult.Error(PlayPurchaseInitError.OtherError) + } + } + + suspend fun verifyPlayPurchase(purchase: PlayPurchase): PlayPurchaseVerifyResult { + val result = messageHandler.trySendRequest(Request.VerifyPlayPurchase(purchase)) + return if (result) { + messageHandler.events<Event.PlayPurchaseVerifyResultEvent>().first().result + } else { + PlayPurchaseVerifyResult.Error(PlayPurchaseVerifyError.OtherError) + } + } +} diff --git a/android/lib/ipc/src/main/kotlin/net/mullvad/mullvadvpn/lib/ipc/Event.kt b/android/lib/ipc/src/main/kotlin/net/mullvad/mullvadvpn/lib/ipc/Event.kt index c5ede20327..e1079807f1 100644 --- a/android/lib/ipc/src/main/kotlin/net/mullvad/mullvadvpn/lib/ipc/Event.kt +++ b/android/lib/ipc/src/main/kotlin/net/mullvad/mullvadvpn/lib/ipc/Event.kt @@ -5,16 +5,16 @@ import kotlinx.parcelize.Parcelize import net.mullvad.mullvadvpn.model.AccountCreationResult import net.mullvad.mullvadvpn.model.AccountExpiry import net.mullvad.mullvadvpn.model.AccountHistory -import net.mullvad.mullvadvpn.model.AppVersionInfo import net.mullvad.mullvadvpn.model.DeviceListEvent import net.mullvad.mullvadvpn.model.DeviceState import net.mullvad.mullvadvpn.model.GeoIpLocation import net.mullvad.mullvadvpn.model.LoginResult +import net.mullvad.mullvadvpn.model.PlayPurchaseInitResult +import net.mullvad.mullvadvpn.model.PlayPurchaseVerifyResult import net.mullvad.mullvadvpn.model.RelayList import net.mullvad.mullvadvpn.model.RemoveDeviceResult import net.mullvad.mullvadvpn.model.Settings import net.mullvad.mullvadvpn.model.TunnelState -import net.mullvad.mullvadvpn.model.VoucherSubmissionResult // Events that can be sent from the service sealed class Event : Message.EventMessage() { @@ -61,6 +61,11 @@ sealed class Event : Message.EventMessage() { val result: net.mullvad.mullvadvpn.model.VoucherSubmissionResult ) : Event() + @Parcelize data class PlayPurchaseInitResultEvent(val result: PlayPurchaseInitResult) : Event() + + @Parcelize + data class PlayPurchaseVerifyResultEvent(val result: PlayPurchaseVerifyResult) : Event() + @Parcelize object VpnPermissionRequest : Event() companion object { diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/serviceconnection/MessageHandler.kt b/android/lib/ipc/src/main/kotlin/net/mullvad/mullvadvpn/lib/ipc/MessageHandler.kt index 3bbcae9361..04de35e3bd 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/serviceconnection/MessageHandler.kt +++ b/android/lib/ipc/src/main/kotlin/net/mullvad/mullvadvpn/lib/ipc/MessageHandler.kt @@ -1,9 +1,7 @@ -package net.mullvad.mullvadvpn.ui.serviceconnection +package net.mullvad.mullvadvpn.lib.ipc import kotlin.reflect.KClass import kotlinx.coroutines.flow.Flow -import net.mullvad.mullvadvpn.lib.ipc.Event -import net.mullvad.mullvadvpn.lib.ipc.Request interface MessageHandler { fun <R : Event> events(klass: KClass<R>): Flow<R> diff --git a/android/lib/ipc/src/main/kotlin/net/mullvad/mullvadvpn/lib/ipc/Request.kt b/android/lib/ipc/src/main/kotlin/net/mullvad/mullvadvpn/lib/ipc/Request.kt index 38237e84b3..511c57494c 100644 --- a/android/lib/ipc/src/main/kotlin/net/mullvad/mullvadvpn/lib/ipc/Request.kt +++ b/android/lib/ipc/src/main/kotlin/net/mullvad/mullvadvpn/lib/ipc/Request.kt @@ -10,6 +10,7 @@ import net.mullvad.mullvadvpn.model.GeographicLocationConstraint import net.mullvad.mullvadvpn.model.ObfuscationSettings import net.mullvad.mullvadvpn.model.Ownership import net.mullvad.mullvadvpn.model.Providers +import net.mullvad.mullvadvpn.model.PlayPurchase import net.mullvad.mullvadvpn.model.QuantumResistantState import net.mullvad.mullvadvpn.model.WireguardConstraints @@ -83,6 +84,10 @@ sealed class Request : Message.RequestMessage() { @Parcelize data class SubmitVoucher(val voucher: String) : Request() + @Parcelize data object InitPlayPurchase : Request() + + @Parcelize data class VerifyPlayPurchase(val playPurchase: PlayPurchase) : Request() + @Parcelize data class UnregisterListener(val listenerId: Int) : Request() @Parcelize data class VpnPermissionResponse(val isGranted: Boolean) : Request() diff --git a/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/endpoint/PlayPurchaseHandler.kt b/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/endpoint/PlayPurchaseHandler.kt new file mode 100644 index 0000000000..9a1e34b62a --- /dev/null +++ b/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/endpoint/PlayPurchaseHandler.kt @@ -0,0 +1,49 @@ +package net.mullvad.mullvadvpn.service.endpoint + +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.cancel +import kotlinx.coroutines.flow.filterIsInstance +import kotlinx.coroutines.launch +import net.mullvad.mullvadvpn.lib.ipc.Event +import net.mullvad.mullvadvpn.lib.ipc.Request +import net.mullvad.mullvadvpn.model.PlayPurchase + +class PlayPurchaseHandler( + private val endpoint: ServiceEndpoint, + dispatcher: CoroutineDispatcher = Dispatchers.IO +) { + private val scope: CoroutineScope = CoroutineScope(SupervisorJob() + dispatcher) + private val daemon + get() = endpoint.intermittentDaemon + + init { + scope.launch { + endpoint.dispatcher.parsedMessages + .filterIsInstance<Request.InitPlayPurchase>() + .collect { initializePurchase() } + } + + scope.launch { + endpoint.dispatcher.parsedMessages + .filterIsInstance<Request.VerifyPlayPurchase>() + .collect { verifyPlayPurchase(it.playPurchase) } + } + } + + fun onDestroy() { + scope.cancel() + } + + private suspend fun initializePurchase() { + val result = daemon.await().initPlayPurchase() + endpoint.sendEvent(Event.PlayPurchaseInitResultEvent(result)) + } + + private suspend fun verifyPlayPurchase(playPurchase: PlayPurchase) { + val result = daemon.await().verifyPlayPurchase(playPurchase) + endpoint.sendEvent(Event.PlayPurchaseVerifyResultEvent(result)) + } +} diff --git a/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/endpoint/ServiceEndpoint.kt b/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/endpoint/ServiceEndpoint.kt index c4a733d919..70e7807ff9 100644 --- a/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/endpoint/ServiceEndpoint.kt +++ b/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/endpoint/ServiceEndpoint.kt @@ -51,6 +51,8 @@ class ServiceEndpoint( val splitTunneling = SplitTunneling(SplitTunnelingPersistence(context), this) val voucherRedeemer = VoucherRedeemer(this, accountCache) + private val playPurchaseHandler = PlayPurchaseHandler(this) + private val deviceRepositoryBackend = DaemonDeviceDataSource(this) init { @@ -80,6 +82,7 @@ class ServiceEndpoint( settingsListener.onDestroy() splitTunneling.onDestroy() voucherRedeemer.onDestroy() + playPurchaseHandler.onDestroy() } internal fun sendEvent(event: Event) { |
