mirror of
https://github.com/wgtunnel/android.git
synced 2026-06-02 00:29:08 +02:00
fix: tunnel and auto-tunnel state sync
This commit is contained in:
+3
@@ -10,6 +10,7 @@ import com.zaneschepke.wireguardautotunnel.R
|
||||
import com.zaneschepke.wireguardautotunnel.core.notification.AndroidNotificationService
|
||||
import com.zaneschepke.wireguardautotunnel.core.notification.NotificationService
|
||||
import com.zaneschepke.wireguardautotunnel.core.orchestration.TunnelCoordinator
|
||||
import com.zaneschepke.wireguardautotunnel.core.service.tile.AutoTunnelTileRefresher
|
||||
import com.zaneschepke.wireguardautotunnel.di.Dispatcher
|
||||
import com.zaneschepke.wireguardautotunnel.domain.enums.NotificationAction
|
||||
import com.zaneschepke.wireguardautotunnel.domain.enums.TunnelActionSource
|
||||
@@ -113,6 +114,7 @@ class AutoTunnelService : LifecycleService() {
|
||||
|
||||
fun start() {
|
||||
stateHolder.setActive(true)
|
||||
AutoTunnelTileRefresher.refresh(this)
|
||||
launchWatcherNotification()
|
||||
autoTunnelJob?.cancel()
|
||||
autoTunnelJob = startAutoTunnelStateJob()
|
||||
@@ -130,6 +132,7 @@ class AutoTunnelService : LifecycleService() {
|
||||
override fun onDestroy() {
|
||||
ServiceCompat.stopForeground(this, ServiceCompat.STOP_FOREGROUND_REMOVE)
|
||||
stateHolder.setActive(false)
|
||||
AutoTunnelTileRefresher.refresh(this)
|
||||
super.onDestroy()
|
||||
}
|
||||
|
||||
|
||||
+22
-2
@@ -7,6 +7,7 @@ import com.zaneschepke.wireguardautotunnel.core.service.autotunnel.AutoTunnelSta
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.cancel
|
||||
import kotlinx.coroutines.cancelChildren
|
||||
import kotlinx.coroutines.launch
|
||||
import org.koin.android.ext.android.inject
|
||||
@@ -18,11 +19,25 @@ class AutoTunnelControlTile : TileService() {
|
||||
|
||||
private val tileScope = CoroutineScope(SupervisorJob() + Dispatchers.Main.immediate)
|
||||
|
||||
override fun onDestroy() {
|
||||
tileScope.cancel()
|
||||
super.onDestroy()
|
||||
}
|
||||
|
||||
override fun onStartListening() {
|
||||
observeState()
|
||||
super.onStartListening()
|
||||
updateTileState()
|
||||
startObserving()
|
||||
}
|
||||
|
||||
override fun onTileAdded() {
|
||||
super.onTileAdded()
|
||||
updateTileState()
|
||||
startObserving()
|
||||
}
|
||||
|
||||
override fun onStopListening() {
|
||||
super.onStopListening()
|
||||
tileScope.coroutineContext.cancelChildren()
|
||||
}
|
||||
|
||||
@@ -30,7 +45,12 @@ class AutoTunnelControlTile : TileService() {
|
||||
unlockAndRun { tileScope.launch { autoTunnelCoordinator.toggle() } }
|
||||
}
|
||||
|
||||
private fun observeState() {
|
||||
private fun updateTileState() {
|
||||
val isActive = autoTunnelStateHolder.active.value
|
||||
if (isActive) setActive() else setInactive()
|
||||
}
|
||||
|
||||
private fun startObserving() {
|
||||
tileScope.launch {
|
||||
autoTunnelStateHolder.active.collect { active ->
|
||||
if (active) setActive() else setInactive()
|
||||
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
package com.zaneschepke.wireguardautotunnel.core.service.tile
|
||||
|
||||
import android.content.ComponentName
|
||||
import android.content.Context
|
||||
import android.service.quicksettings.TileService
|
||||
|
||||
object AutoTunnelTileRefresher : TileRefresher {
|
||||
override fun refresh(context: Context) {
|
||||
TileService.requestListeningState(
|
||||
context,
|
||||
ComponentName(context, AutoTunnelControlTile::class.java),
|
||||
)
|
||||
}
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
package com.zaneschepke.wireguardautotunnel.core.service.tile
|
||||
|
||||
import android.content.Context
|
||||
|
||||
interface TileRefresher {
|
||||
fun refresh(context: Context)
|
||||
}
|
||||
+23
@@ -1,5 +1,6 @@
|
||||
package com.zaneschepke.wireguardautotunnel.core.service.tile
|
||||
|
||||
import android.os.Build
|
||||
import android.service.quicksettings.Tile
|
||||
import android.service.quicksettings.TileService
|
||||
import com.zaneschepke.wireguardautotunnel.core.orchestration.TunnelCoordinator
|
||||
@@ -27,8 +28,15 @@ class TunnelControlTile : TileService() {
|
||||
super.onDestroy()
|
||||
}
|
||||
|
||||
override fun onTileAdded() {
|
||||
super.onTileAdded()
|
||||
updateTileState()
|
||||
startObserving()
|
||||
}
|
||||
|
||||
override fun onStartListening() {
|
||||
super.onStartListening()
|
||||
updateTileState()
|
||||
startObserving()
|
||||
}
|
||||
|
||||
@@ -109,7 +117,12 @@ class TunnelControlTile : TileService() {
|
||||
|
||||
qsTile?.apply {
|
||||
state = Tile.STATE_ACTIVE
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
subtitle = label
|
||||
}
|
||||
contentDescription = label
|
||||
|
||||
updateTile()
|
||||
}
|
||||
}
|
||||
@@ -117,7 +130,12 @@ class TunnelControlTile : TileService() {
|
||||
private fun setInactive() {
|
||||
qsTile?.apply {
|
||||
state = Tile.STATE_INACTIVE
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
subtitle = ""
|
||||
}
|
||||
contentDescription = ""
|
||||
|
||||
updateTile()
|
||||
}
|
||||
}
|
||||
@@ -125,7 +143,12 @@ class TunnelControlTile : TileService() {
|
||||
private fun setUnavailable() {
|
||||
qsTile?.apply {
|
||||
state = Tile.STATE_UNAVAILABLE
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
subtitle = ""
|
||||
}
|
||||
contentDescription = ""
|
||||
|
||||
updateTile()
|
||||
}
|
||||
}
|
||||
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
package com.zaneschepke.wireguardautotunnel.core.service.tile
|
||||
|
||||
import android.content.ComponentName
|
||||
import android.content.Context
|
||||
import android.service.quicksettings.TileService
|
||||
|
||||
object TunnelTileRefresher : TileRefresher {
|
||||
override fun refresh(context: Context) {
|
||||
TileService.requestListeningState(
|
||||
context,
|
||||
ComponentName(context, TunnelControlTile::class.java),
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.zaneschepke.wireguardautotunnel.di
|
||||
|
||||
import android.app.Notification
|
||||
import android.content.Context
|
||||
import com.zaneschepke.networkmonitor.AndroidNetworkMonitor
|
||||
import com.zaneschepke.networkmonitor.NetworkMonitor
|
||||
import com.zaneschepke.networkmonitor.StableNetworkEngine
|
||||
@@ -15,6 +16,7 @@ import com.zaneschepke.wireguardautotunnel.core.notification.NotificationService
|
||||
import com.zaneschepke.wireguardautotunnel.core.notification.NotificationService.Companion.PROXY_GROUP_KEY
|
||||
import com.zaneschepke.wireguardautotunnel.core.notification.NotificationService.Companion.VPN_GROUP_KEY
|
||||
import com.zaneschepke.wireguardautotunnel.core.notification.TunnelNotificationService
|
||||
import com.zaneschepke.wireguardautotunnel.core.service.tile.TunnelTileRefresher
|
||||
import com.zaneschepke.wireguardautotunnel.core.tunnel.TunnelBackendProvider
|
||||
import com.zaneschepke.wireguardautotunnel.core.tunnel.TunnelProvider
|
||||
import com.zaneschepke.wireguardautotunnel.domain.repository.AutoTunnelSettingsRepository
|
||||
@@ -62,6 +64,10 @@ val tunnelBackendProviderModule = module {
|
||||
|
||||
override val proxyNotificationId: Int
|
||||
get() = NotificationService.PROXY_NOTIFICATION_ID
|
||||
|
||||
override fun refreshTile(context: Context) {
|
||||
TunnelTileRefresher.refresh(context)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
package com.zaneschepke.tunnel
|
||||
|
||||
import android.app.Notification
|
||||
import android.content.Context
|
||||
|
||||
interface NotificationProvider {
|
||||
val vpnInitNotification: Notification
|
||||
val proxyInitNotification: Notification
|
||||
val vpnNotificationId: Int
|
||||
val proxyNotificationId: Int
|
||||
|
||||
fun refreshTile(context: Context)
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.asSharedFlow
|
||||
import timber.log.Timber
|
||||
|
||||
internal class ServiceHolder(private val context: Context) {
|
||||
internal class ServiceHolder(val context: Context) {
|
||||
|
||||
internal val uapiPath = context.dataDir.absolutePath
|
||||
|
||||
|
||||
@@ -58,6 +58,8 @@ class TunnelBackend(
|
||||
var hadVpnTunnels = false
|
||||
var hadProxyTunnels = false
|
||||
|
||||
var lastActiveTunnelIds: Set<Int> = emptySet()
|
||||
|
||||
actor.state.collect { actorState ->
|
||||
val hasVpnNow =
|
||||
actorState.byTunnelId.values.any { it.running.mode is BackendMode.Vpn }
|
||||
@@ -69,6 +71,14 @@ class TunnelBackend(
|
||||
|
||||
_status.update { current -> current.copy(activeTunnels = activeTunnels) }
|
||||
|
||||
val currentTunnelIds = activeTunnels.keys
|
||||
|
||||
// update tile
|
||||
if (currentTunnelIds != lastActiveTunnelIds) {
|
||||
notificationProvider.refreshTile(serviceHolder.context)
|
||||
lastActiveTunnelIds = currentTunnelIds
|
||||
}
|
||||
|
||||
// VPN cleanup
|
||||
if (hadVpnTunnels && !hasVpnNow) {
|
||||
|
||||
@@ -281,10 +291,14 @@ class TunnelBackend(
|
||||
|
||||
override fun emergencyStopAllOfTypeSync(modeClass: KClass<out BackendMode>) {
|
||||
actor.emergencyStopAllOfType(modeClass)
|
||||
_status.update { it.copy(activeTunnels = emptyMap()) }
|
||||
notificationProvider.refreshTile(serviceHolder.context)
|
||||
}
|
||||
|
||||
override suspend fun stopAllActiveTunnels(): Result<Unit> = runCatching {
|
||||
_status.value.activeTunnels.forEach { (id, _) -> stop(id) }
|
||||
_status.update { it.copy(activeTunnels = emptyMap()) }
|
||||
notificationProvider.refreshTile(serviceHolder.context)
|
||||
}
|
||||
|
||||
private fun startSystemDnsMonitoring() {
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
package com.zaneschepke.tunnel.backend
|
||||
|
||||
import com.zaneschepke.tunnel.StatusCallback
|
||||
import com.zaneschepke.tunnel.VpnBackend
|
||||
import com.zaneschepke.tunnel.state.NativeTunnelStatus
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
import kotlinx.coroutines.flow.receiveAsFlow
|
||||
|
||||
object TunnelEventBus {
|
||||
|
||||
private val channel = Channel<NativeTunnelStatus>(Channel.BUFFERED)
|
||||
val flow = channel.receiveAsFlow()
|
||||
|
||||
private val callback = StatusCallback { handle, code ->
|
||||
val status = NativeTunnelStatus.NativeTunnelStatusCode.from(code) ?: return@StatusCallback
|
||||
|
||||
channel.trySend(NativeTunnelStatus(handle = handle, code = status))
|
||||
}
|
||||
|
||||
fun start() {
|
||||
VpnBackend.setStatusCallback(callback)
|
||||
}
|
||||
|
||||
fun stop() {
|
||||
VpnBackend.setStatusCallback(null)
|
||||
channel.close()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user