From 4c1c57a8cf962585bb4601b4f5d954f3c293521f Mon Sep 17 00:00:00 2001 From: Jonatan Rhodin Date: Wed, 17 Jan 2024 09:38:35 +0100 Subject: [PATCH] Bind to the service in a coroutine to avoid a crash --- .../net/mullvad/mullvadvpn/ui/MainActivity.kt | 44 +++++++++---------- 1 file changed, 21 insertions(+), 23 deletions(-) diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/MainActivity.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/MainActivity.kt index 4298fa17fa22..a0841c0746a7 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/MainActivity.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/MainActivity.kt @@ -9,8 +9,12 @@ import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.activity.result.contract.ActivityResultContracts import androidx.core.view.WindowCompat +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.lifecycleScope +import androidx.lifecycle.repeatOnLifecycle import kotlinx.coroutines.flow.filterIsInstance import kotlinx.coroutines.flow.first +import kotlinx.coroutines.launch import net.mullvad.mullvadvpn.compose.screen.MullvadApp import net.mullvad.mullvadvpn.di.paymentModule import net.mullvad.mullvadvpn.di.uiModule @@ -60,46 +64,40 @@ class MainActivity : ComponentActivity() { super.onCreate(savedInstanceState) setContent { AppTheme { MullvadApp() } } - } - fun initializeStateHandlerAndServiceConnection() { - requestNotificationPermissionIfMissing(requestNotificationPermissionLauncher) - serviceConnectionManager.bind( - vpnPermissionRequestHandler = ::requestVpnPermission, - apiEndpointConfiguration = intent?.getApiEndpointConfigurationExtras() - ) + // We use lifecycleScope here to get less start service in background exceptions + // Se this article for more information: + // https://medium.com/@lepicekmichal/android-background-service-without-hiccup-501e4479110f + lifecycleScope.launch { + repeatOnLifecycle(Lifecycle.State.STARTED) { + if (privacyDisclaimerRepository.hasAcceptedPrivacyDisclosure()) { + startServiceSuspend(waitForConnectedReady = false) + } + } + } } - suspend fun startServiceSuspend() { + suspend fun startServiceSuspend(waitForConnectedReady: Boolean = true) { requestNotificationPermissionIfMissing(requestNotificationPermissionLauncher) serviceConnectionManager.bind( vpnPermissionRequestHandler = ::requestVpnPermission, apiEndpointConfiguration = intent?.getApiEndpointConfigurationExtras() ) - // Ensure we wait until the service is ready - serviceConnectionManager.connectionState - .filterIsInstance() - .first() + if (waitForConnectedReady) { + // Ensure we wait until the service is ready + serviceConnectionManager.connectionState + .filterIsInstance() + .first() + } } override fun onActivityResult(requestCode: Int, resultCode: Int, resultData: Intent?) { serviceConnectionManager.onVpnPermissionResult(resultCode == Activity.RESULT_OK) } - override fun onStart() { - super.onStart() - - if (privacyDisclaimerRepository.hasAcceptedPrivacyDisclosure()) { - initializeStateHandlerAndServiceConnection() - } - } - override fun onStop() { Log.d("mullvad", "Stopping main activity") super.onStop() - - // NOTE: `super.onStop()` must be called before unbinding due to the fragment state handling - // otherwise the fragments will believe there was an unexpected disconnect. serviceConnectionManager.unbind() }