fix(android): ensure connectOnStart applies only to start (#9279)

A bug was introduced in #9227 where the `connectOnStart` was being read
for both resumed launches and initial launches. This PR updates that
logic so that we only check `connectOnStart` when the app is actually
launched.

On mobile platforms, this flag is not as clearcut as on desktop
platforms, but it's maintained here because ChromeOS is also used on
desktop systems.
This commit is contained in:
Jamil
2025-05-26 21:20:53 -07:00
committed by GitHub
parent 7c87adc1cc
commit 1f87469634
2 changed files with 32 additions and 3 deletions

View File

@@ -25,11 +25,16 @@ internal class SplashFragment : Fragment(R.layout.fragment_splash) {
binding = FragmentSplashBinding.bind(view)
setupActionObservers()
if (savedInstanceState == null) {
// Trigger the initial check for tunnel state
viewModel.checkTunnelState(requireContext(), isInitialLaunch = true)
}
}
override fun onResume() {
super.onResume()
viewModel.checkTunnelState(requireContext())
viewModel.checkTunnelState(requireContext(), isInitialLaunch = false)
}
private fun setupActionObservers() {

View File

@@ -28,17 +28,36 @@ internal class SplashViewModel
private val actionMutableLiveData = MutableLiveData<ViewAction>()
val actionLiveData: LiveData<ViewAction> = actionMutableLiveData
internal fun checkTunnelState(context: Context) {
// This flag is used to ensure that the initial launch check is only performed once, so
// that we can differentiate between a fresh launch and subsequent resumes for the connect
// on start logic.
private var hasPerformedInitialLaunchCheck = false
internal fun checkTunnelState(
context: Context,
isInitialLaunch: Boolean = false,
) {
viewModelScope.launch {
// Stay a while and enjoy the logo
delay(REQUEST_DELAY)
// If this is an 'initial launch' call, but we've already handled the
// initial launch logic for this ViewModel instance, then do nothing.
if (isInitialLaunch && hasPerformedInitialLaunchCheck) {
return@launch
}
if (!hasVpnPermissions(context) && applicationMode != ApplicationMode.TESTING) {
actionMutableLiveData.postValue(ViewAction.NavigateToVpnPermission)
} else {
val token = applicationRestrictions.getString("token") ?: repo.getTokenSync()
val connectOnStart = repo.getConfigSync().connectOnStart
if (!token.isNullOrBlank() && connectOnStart) {
// Determine if the tunnel should connect:
// 1. If it's an initial launch AND connectOnStart is true.
// OR
// 2. If it's NOT an initial launch (meaning it's a resume), always try to connect if a token exists.
if (!token.isNullOrBlank() && (isInitialLaunch && connectOnStart || !isInitialLaunch)) {
// token will be re-read by the TunnelService
if (!TunnelService.isRunning(context)) TunnelService.start(context)
@@ -48,6 +67,11 @@ internal class SplashViewModel
}
}
}
// Set the flag to true after the initial launch check is performed
if (isInitialLaunch) {
hasPerformedInitialLaunchCheck = true
}
}
private fun hasVpnPermissions(context: Context): Boolean = android.net.VpnService.prepare(context) == null