From cab29459300bb9087b4cb3cf90ab9c57f15d99e6 Mon Sep 17 00:00:00 2001 From: Zane Schepke Date: Thu, 7 Nov 2024 23:03:00 -0500 Subject: [PATCH] fix: auto tunnel bugs Fixes auto tunnel bug that can happen on startup Fixes auto tunnel bug that didn't allow manual toggle override of tunnel while auto tunnel is active Add basic foreground persistent notifications (optionally turned off via android settings) --- .../module/BackendQualifiers.kt | 8 ++ .../module/TunnelModule.kt | 15 ++- .../service/foreground/AutoTunnelService.kt | 99 ++++++++++--------- .../service/foreground/ServiceManager.kt | 14 +-- .../foreground/TunnelBackgroundService.kt | 2 +- .../service/tunnel/WireGuardTunnel.kt | 13 ++- .../ui/screens/main/MainScreen.kt | 4 +- .../ui/screens/settings/SettingsViewModel.kt | 3 +- .../autotunnel/AutoTunnelViewModel.kt | 3 +- .../wireguardautotunnel/util/Constants.kt | 1 - .../util/extensions/TunnelExtensions.kt | 6 -- app/src/main/res/values/strings.xml | 2 + 12 files changed, 100 insertions(+), 70 deletions(-) diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/module/BackendQualifiers.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/module/BackendQualifiers.kt index 88d74432..6612356f 100644 --- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/module/BackendQualifiers.kt +++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/module/BackendQualifiers.kt @@ -9,3 +9,11 @@ annotation class Kernel @Qualifier @Retention(AnnotationRetention.BINARY) annotation class Userspace + +@Qualifier +@Retention(AnnotationRetention.BINARY) +annotation class TunnelShell + +@Qualifier +@Retention(AnnotationRetention.BINARY) +annotation class AppShell diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/module/TunnelModule.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/module/TunnelModule.kt index dc19286d..5c9ceff4 100644 --- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/module/TunnelModule.kt +++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/module/TunnelModule.kt @@ -25,9 +25,18 @@ import javax.inject.Singleton @Module @InstallIn(SingletonComponent::class) class TunnelModule { + + @Provides + @Singleton + @TunnelShell + fun provideTunnelRootShell(@ApplicationContext context: Context): RootShell { + return RootShell(context) + } + @Provides @Singleton - fun provideRootShell(@ApplicationContext context: Context): RootShell { + @AppShell + fun provideAppRootShell(@ApplicationContext context: Context): RootShell { return RootShell(context) } @@ -40,14 +49,14 @@ class TunnelModule { @Provides @Singleton @Userspace - fun provideUserspaceBackend(@ApplicationContext context: Context, rootShell: RootShell): Backend { + fun provideUserspaceBackend(@ApplicationContext context: Context, @TunnelShell rootShell: RootShell): Backend { return GoBackend(context, RootTunnelActionHandler(rootShell)) } @Provides @Singleton @Kernel - fun provideKernelBackend(@ApplicationContext context: Context, rootShell: RootShell): Backend { + fun provideKernelBackend(@ApplicationContext context: Context, @TunnelShell rootShell: RootShell): Backend { return WgQuickBackend(context, rootShell, ToolsInstaller(context, rootShell), RootTunnelActionHandler(rootShell)) } diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/service/foreground/AutoTunnelService.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/service/foreground/AutoTunnelService.kt index 994ce539..a606a37e 100644 --- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/service/foreground/AutoTunnelService.kt +++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/service/foreground/AutoTunnelService.kt @@ -12,6 +12,7 @@ import com.zaneschepke.wireguardautotunnel.R import com.zaneschepke.wireguardautotunnel.data.domain.Settings import com.zaneschepke.wireguardautotunnel.data.domain.TunnelConfig import com.zaneschepke.wireguardautotunnel.data.repository.AppDataRepository +import com.zaneschepke.wireguardautotunnel.module.AppShell import com.zaneschepke.wireguardautotunnel.module.IoDispatcher import com.zaneschepke.wireguardautotunnel.module.MainImmediateDispatcher import com.zaneschepke.wireguardautotunnel.service.network.EthernetService @@ -25,7 +26,6 @@ import com.zaneschepke.wireguardautotunnel.service.tunnel.TunnelState import com.zaneschepke.wireguardautotunnel.util.Constants import com.zaneschepke.wireguardautotunnel.util.extensions.cancelWithMessage import com.zaneschepke.wireguardautotunnel.util.extensions.getCurrentWifiName -import com.zaneschepke.wireguardautotunnel.util.extensions.isDown import com.zaneschepke.wireguardautotunnel.util.extensions.isReachable import com.zaneschepke.wireguardautotunnel.util.extensions.onNotRunning import dagger.hilt.android.AndroidEntryPoint @@ -34,7 +34,6 @@ import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.Job import kotlinx.coroutines.delay import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.update @@ -50,6 +49,7 @@ class AutoTunnelService : LifecycleService() { private val foregroundId = 122 @Inject + @AppShell lateinit var rootShell: Provider @Inject @@ -143,7 +143,7 @@ class AutoTunnelService : LifecycleService() { super.onDestroy() } - private fun launchWatcherNotification(description: String = getString(R.string.watcher_notification_text_active)) { + private fun launchWatcherNotification(description: String = getString(R.string.monitoring_state_changes)) { val notification = notificationService.createNotification( channelId = getString(R.string.watcher_channel_id), @@ -209,28 +209,16 @@ class AutoTunnelService : LifecycleService() { when (status) { is NetworkStatus.Available -> { Timber.i("Gained Mobile data connection") - autoTunnelStateFlow.update { - it.copy( - isMobileDataConnected = true, - ) - } + emitMobileDataConnected(true) } is NetworkStatus.CapabilitiesChanged -> { - autoTunnelStateFlow.update { - it.copy( - isMobileDataConnected = true, - ) - } + emitMobileDataConnected(true) Timber.i("Mobile data capabilities changed") } is NetworkStatus.Unavailable -> { - autoTunnelStateFlow.update { - it.copy( - isMobileDataConnected = false, - ) - } + emitMobileDataConnected(false) Timber.i("Lost mobile data connection") } } @@ -283,6 +271,7 @@ class AutoTunnelService : LifecycleService() { old.map { it.isActive } != new.map { it.isActive } }, ) { settings, tunnels -> + Timber.d("Tunnels or settings changed!") autoTunnelStateFlow.value.copy( settings = settings, tunnels = tunnels, @@ -299,7 +288,7 @@ class AutoTunnelService : LifecycleService() { Timber.i("Starting vpn state watcher") withContext(ioDispatcher) { tunnelService.get().vpnState.distinctUntilChanged { old, new -> - old.tunnelConfig == new.tunnelConfig && old.status == new.status + old.tunnelConfig?.id == new.tunnelConfig?.id }.collect { state -> autoTunnelStateFlow.update { it.copy(vpnState = state) @@ -367,7 +356,7 @@ class AutoTunnelService : LifecycleService() { mobileDataJob = null } - private fun updateEthernet(connected: Boolean) { + private fun emitEthernetConnected(connected: Boolean) { autoTunnelStateFlow.update { it.copy( isEthernetConnected = connected, @@ -375,7 +364,7 @@ class AutoTunnelService : LifecycleService() { } } - private fun updateWifi(connected: Boolean) { + private fun emitWifiConnected(connected: Boolean) { autoTunnelStateFlow.update { it.copy( isWifiConnected = connected, @@ -383,6 +372,22 @@ class AutoTunnelService : LifecycleService() { } } + private fun emitWifiSSID(ssid: String) { + autoTunnelStateFlow.update { + it.copy( + currentNetworkSSID = ssid, + ) + } + } + + private fun emitMobileDataConnected(connected: Boolean) { + autoTunnelStateFlow.update { + it.copy( + isMobileDataConnected = connected, + ) + } + } + private suspend fun watchForEthernetConnectivityChanges() { withContext(ioDispatcher) { Timber.i("Starting ethernet data watcher") @@ -390,16 +395,16 @@ class AutoTunnelService : LifecycleService() { when (status) { is NetworkStatus.Available -> { Timber.i("Gained Ethernet connection") - updateEthernet(true) + emitEthernetConnected(true) } is NetworkStatus.CapabilitiesChanged -> { Timber.i("Ethernet capabilities changed") - updateEthernet(true) + emitEthernetConnected(true) } is NetworkStatus.Unavailable -> { - updateEthernet(false) + emitEthernetConnected(false) Timber.i("Lost Ethernet connection") } } @@ -414,12 +419,12 @@ class AutoTunnelService : LifecycleService() { when (status) { is NetworkStatus.Available -> { Timber.i("Gained Wi-Fi connection") - updateWifi(true) + emitWifiConnected(true) } is NetworkStatus.CapabilitiesChanged -> { Timber.i("Wifi capabilities changed") - updateWifi(true) + emitWifiConnected(true) val ssid = getWifiSSID(status.networkCapabilities) ssid?.let { name -> if (name.contains(Constants.UNREADABLE_SSID)) { @@ -428,16 +433,12 @@ class AutoTunnelService : LifecycleService() { Timber.i("Detected valid SSID") } appDataRepository.appState.setCurrentSsid(name) - autoTunnelStateFlow.update { - it.copy( - currentNetworkSSID = name, - ) - } + emitWifiSSID(name) } ?: Timber.w("Failed to read ssid") } is NetworkStatus.Unavailable -> { - updateWifi(false) + emitWifiConnected(false) Timber.i("Lost Wi-Fi connection") } } @@ -461,17 +462,17 @@ class AutoTunnelService : LifecycleService() { private suspend fun handleNetworkEventChanges() { withContext(ioDispatcher) { Timber.i("Starting network event watcher") - autoTunnelStateFlow.collectLatest { watcherState -> + autoTunnelStateFlow.collect { watcherState -> val autoTunnel = "Auto-tunnel watcher" - Timber.d("New watcher state!") // delay for rapid network state changes and then collect latest delay(Constants.WATCHER_COLLECTION_DELAY) val activeTunnel = watcherState.vpnState.tunnelConfig val defaultTunnel = appDataRepository.getPrimaryOrFirstTunnel() + val isTunnelDown = tunnelService.get().getState() == TunnelState.DOWN when { watcherState.isEthernetConditionMet() -> { Timber.i("$autoTunnel - tunnel on on ethernet condition met") - if (watcherState.vpnState.isDown()) { + if (isTunnelDown) { defaultTunnel?.let { tunnelService.get().startTunnel(it) } @@ -483,7 +484,7 @@ class AutoTunnelService : LifecycleService() { val mobileDataTunnel = getMobileDataTunnel() val tunnel = mobileDataTunnel ?: defaultTunnel - if (watcherState.vpnState.isDown() || activeTunnel?.isMobileDataTunnel == false) { + if (isTunnelDown || activeTunnel?.isMobileDataTunnel == false) { tunnel?.let { tunnelService.get().startTunnel(it) } @@ -492,7 +493,7 @@ class AutoTunnelService : LifecycleService() { watcherState.isTunnelOffOnMobileDataConditionMet() -> { Timber.i("$autoTunnel - tunnel off on mobile data met, turning vpn off") - if (!watcherState.vpnState.isDown()) { + if (!isTunnelDown) { activeTunnel?.let { tunnelService.get().stopTunnel(it) } @@ -502,20 +503,20 @@ class AutoTunnelService : LifecycleService() { watcherState.isUntrustedWifiConditionMet() -> { Timber.i("Untrusted wifi condition met") if (activeTunnel == null || watcherState.isCurrentSSIDActiveTunnelNetwork() == false || - watcherState.vpnState.isDown() + isTunnelDown ) { Timber.i( "$autoTunnel - tunnel on ssid not associated with current tunnel condition met", ) watcherState.getTunnelWithMatchingTunnelNetwork()?.let { Timber.i("Found tunnel associated with this SSID, bringing tunnel up: ${it.name}") - if (watcherState.vpnState.isDown() || activeTunnel?.id != it.id) { + if (isTunnelDown || activeTunnel?.id != it.id) { tunnelService.get().startTunnel(it) } } ?: suspend { Timber.i("No tunnel associated with this SSID, using defaults") val default = appDataRepository.getPrimaryOrFirstTunnel() - if (default?.name != tunnelService.get().name || watcherState.vpnState.isDown()) { + if (default?.name != tunnelService.get().name || isTunnelDown) { default?.let { tunnelService.get().startTunnel(it) } @@ -528,22 +529,22 @@ class AutoTunnelService : LifecycleService() { Timber.i( "$autoTunnel - tunnel off on trusted wifi condition met, turning vpn off", ) - if (!watcherState.vpnState.isDown()) activeTunnel?.let { tunnelService.get().stopTunnel(it) } + if (!isTunnelDown) activeTunnel?.let { tunnelService.get().stopTunnel(it) } } watcherState.isTunnelOffOnWifiConditionMet() -> { Timber.i( "$autoTunnel - tunnel off on wifi condition met, turning vpn off", ) - if (!watcherState.vpnState.isDown()) activeTunnel?.let { tunnelService.get().stopTunnel(it) } - } - - watcherState.isTunnelOffOnNoConnectivityMet() -> { - Timber.i( - "$autoTunnel - tunnel off on no connectivity met, turning vpn off", - ) - if (!watcherState.vpnState.isDown()) activeTunnel?.let { tunnelService.get().stopTunnel(it) } + if (!isTunnelDown) activeTunnel?.let { tunnelService.get().stopTunnel(it) } } +// TODO disable for this now +// watcherState.isTunnelOffOnNoConnectivityMet() -> { +// Timber.i( +// "$autoTunnel - tunnel off on no connectivity met, turning vpn off", +// ) +// if (!isTunnelDown) activeTunnel?.let { tunnelService.get().stopTunnel(it) } +// } else -> { Timber.i("$autoTunnel - no condition met") diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/service/foreground/ServiceManager.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/service/foreground/ServiceManager.kt index 08180c18..2b4c005f 100644 --- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/service/foreground/ServiceManager.kt +++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/service/foreground/ServiceManager.kt @@ -27,12 +27,14 @@ class ServiceManager companion object : SingletonHolder(::ServiceManager) private fun startService(cls: Class, background: Boolean) { - val intent = Intent(context, cls) - if (background) { - context.startForegroundService(intent) - } else { - context.startService(intent) - } + runCatching { + val intent = Intent(context, cls) + if (background) { + context.startForegroundService(intent) + } else { + context.startService(intent) + } + }.onFailure { Timber.e(it) } } suspend fun startAutoTunnel(background: Boolean) { diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/service/foreground/TunnelBackgroundService.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/service/foreground/TunnelBackgroundService.kt index 620631b4..7bec3d50 100644 --- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/service/foreground/TunnelBackgroundService.kt +++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/service/foreground/TunnelBackgroundService.kt @@ -62,7 +62,7 @@ class TunnelBackgroundService : LifecycleService() { return notificationService.createNotification( getString(R.string.vpn_channel_id), getString(R.string.vpn_channel_name), - getString(R.string.tunnel_start_text), + getString(R.string.tunnel_running), description = "", ) } diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/service/tunnel/WireGuardTunnel.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/service/tunnel/WireGuardTunnel.kt index a500bb34..98982f65 100644 --- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/service/tunnel/WireGuardTunnel.kt +++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/service/tunnel/WireGuardTunnel.kt @@ -25,6 +25,7 @@ import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import org.amnezia.awg.backend.Tunnel import timber.log.Timber +import java.util.concurrent.atomic.AtomicBoolean import javax.inject.Inject import javax.inject.Provider @@ -52,6 +53,8 @@ constructor( private var statsJob: Job? = null + private val runningHandle = AtomicBoolean(false) + private suspend fun backend(): Any { val settings = appDataRepository.settings.getSettings() if (settings.isKernelEnabled) return kernelBackend.get() @@ -91,8 +94,14 @@ constructor( override suspend fun startTunnel(tunnelConfig: TunnelConfig, background: Boolean): Result { return withContext(ioDispatcher) { + if (runningHandle.get() == true && tunnelConfig == vpnState.value.tunnelConfig) { + Timber.w("Tunnel already running") + return@withContext Result.success(vpnState.value.status) + } + runningHandle.set(true) onBeforeStart(tunnelConfig) - if (background) startBackgroundService() + val settings = appDataRepository.settings.getSettings() + if (background || settings.isKernelEnabled) startBackgroundService() setState(tunnelConfig, TunnelState.UP).onSuccess { emitTunnelState(it) }.onFailure { @@ -112,6 +121,7 @@ constructor( onStopFailed() }.also { stopBackgroundService() + runningHandle.set(false) } } } @@ -146,6 +156,7 @@ constructor( } cancelStatsJob() resetBackendStatistics() + runningHandle.set(false) } private suspend fun shutDownActiveTunnel(config: TunnelConfig) { diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/main/MainScreen.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/main/MainScreen.kt index eeffcc86..2177f5c5 100644 --- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/main/MainScreen.kt +++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/main/MainScreen.kt @@ -39,6 +39,7 @@ import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel import com.zaneschepke.wireguardautotunnel.R import com.zaneschepke.wireguardautotunnel.data.domain.TunnelConfig @@ -60,6 +61,7 @@ import com.zaneschepke.wireguardautotunnel.util.Constants import com.zaneschepke.wireguardautotunnel.util.extensions.isBatteryOptimizationsDisabled import com.zaneschepke.wireguardautotunnel.util.extensions.isRunningOnTv import com.zaneschepke.wireguardautotunnel.util.extensions.openWebUrl +import com.zaneschepke.wireguardautotunnel.util.extensions.scaledHeight @OptIn(ExperimentalFoundationApi::class) @Composable @@ -213,7 +215,7 @@ fun MainScreen(viewModel: MainViewModel = hiltViewModel(), uiState: AppUiState) ) LazyColumn( horizontalAlignment = Alignment.Start, - verticalArrangement = Arrangement.Top, + verticalArrangement = Arrangement.spacedBy(5.dp.scaledHeight(), Alignment.Top), modifier = Modifier .fillMaxSize().padding(it) diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/settings/SettingsViewModel.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/settings/SettingsViewModel.kt index d3ce4e98..4de62be6 100644 --- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/settings/SettingsViewModel.kt +++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/settings/SettingsViewModel.kt @@ -9,6 +9,7 @@ import com.wireguard.android.util.RootShell import com.zaneschepke.wireguardautotunnel.R import com.zaneschepke.wireguardautotunnel.data.domain.Settings import com.zaneschepke.wireguardautotunnel.data.repository.AppDataRepository +import com.zaneschepke.wireguardautotunnel.module.AppShell import com.zaneschepke.wireguardautotunnel.module.IoDispatcher import com.zaneschepke.wireguardautotunnel.ui.common.snackbar.SnackbarController import com.zaneschepke.wireguardautotunnel.util.FileUtils @@ -29,7 +30,7 @@ class SettingsViewModel @Inject constructor( private val appDataRepository: AppDataRepository, - private val rootShell: Provider, + @AppShell private val rootShell: Provider, private val fileUtils: FileUtils, @IoDispatcher private val ioDispatcher: CoroutineDispatcher, ) : ViewModel() { diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/settings/autotunnel/AutoTunnelViewModel.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/settings/autotunnel/AutoTunnelViewModel.kt index 55c787c7..83104ba2 100644 --- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/settings/autotunnel/AutoTunnelViewModel.kt +++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/ui/screens/settings/autotunnel/AutoTunnelViewModel.kt @@ -6,6 +6,7 @@ import com.wireguard.android.util.RootShell import com.zaneschepke.wireguardautotunnel.R import com.zaneschepke.wireguardautotunnel.data.domain.Settings import com.zaneschepke.wireguardautotunnel.data.repository.AppDataRepository +import com.zaneschepke.wireguardautotunnel.module.AppShell import com.zaneschepke.wireguardautotunnel.module.IoDispatcher import com.zaneschepke.wireguardautotunnel.ui.common.snackbar.SnackbarController import com.zaneschepke.wireguardautotunnel.util.StringValue @@ -23,7 +24,7 @@ class AutoTunnelViewModel @Inject constructor( private val appDataRepository: AppDataRepository, - private val rootShell: Provider, + @AppShell private val rootShell: Provider, @IoDispatcher private val ioDispatcher: CoroutineDispatcher, ) : ViewModel() { diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/util/Constants.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/util/Constants.kt index 03375d1e..89a15fc9 100644 --- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/util/Constants.kt +++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/util/Constants.kt @@ -21,7 +21,6 @@ object Constants { const val SYSTEM_EXEMPT_SERVICE_TYPE_ID = 1024 const val SUBSCRIPTION_TIMEOUT = 5_000L - const val FOCUS_REQUEST_DELAY = 500L const val TRANSITION_ANIMATION_TIME = 200 diff --git a/app/src/main/java/com/zaneschepke/wireguardautotunnel/util/extensions/TunnelExtensions.kt b/app/src/main/java/com/zaneschepke/wireguardautotunnel/util/extensions/TunnelExtensions.kt index 34405a98..d3cdc281 100644 --- a/app/src/main/java/com/zaneschepke/wireguardautotunnel/util/extensions/TunnelExtensions.kt +++ b/app/src/main/java/com/zaneschepke/wireguardautotunnel/util/extensions/TunnelExtensions.kt @@ -4,8 +4,6 @@ import androidx.compose.ui.graphics.Color import com.wireguard.android.util.RootShell import com.wireguard.config.Peer import com.zaneschepke.wireguardautotunnel.service.tunnel.HandshakeStatus -import com.zaneschepke.wireguardautotunnel.service.tunnel.TunnelState -import com.zaneschepke.wireguardautotunnel.service.tunnel.VpnState import com.zaneschepke.wireguardautotunnel.service.tunnel.statistics.TunnelStatistics import com.zaneschepke.wireguardautotunnel.ui.theme.SilverTree import com.zaneschepke.wireguardautotunnel.ui.theme.Straw @@ -23,10 +21,6 @@ fun TunnelStatistics.PeerStats.latestHandshakeSeconds(): Long? { return NumberUtils.getSecondsBetweenTimestampAndNow(this.latestHandshakeEpochMillis) } -fun VpnState.isDown(): Boolean { - return this.status == TunnelState.DOWN -} - fun TunnelStatistics.PeerStats.handshakeStatus(): HandshakeStatus { // TODO add never connected status after duration return this.latestHandshakeSeconds().let { diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 17771250..04e744ed 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -225,4 +225,6 @@ Kernel not supported Start auto-tunnel Stop auto-tunnel + Tunnel running + Monitoring state changes