Compare commits

..

11 Commits

Author SHA1 Message Date
dependabot[bot] 23d75ff0b7 build(deps): bump androidGradlePlugin from 8.8.0-rc01 to 8.9.0-alpha06
Bumps `androidGradlePlugin` from 8.8.0-rc01 to 8.9.0-alpha06.

Updates `com.android.application` from 8.8.0-rc01 to 8.9.0-alpha06

Updates `com.android.library` from 8.8.0-rc01 to 8.9.0-alpha06

---
updated-dependencies:
- dependency-name: com.android.application
  dependency-type: direct:production
  update-type: version-update:semver-minor
- dependency-name: com.android.library
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-17 13:57:38 +00:00
GitHub Actions 11efad703c Automated build update 2024-12-15 03:44:11 +00:00
Marko Zajc b81f43c7cf fix: getting the SSID via shell (#494) 2024-12-14 11:18:35 -05:00
GitHub Actions 68865843dc Automated build update 2024-12-14 03:41:42 +00:00
Zane Schepke 62daf138dd fix: add action and tunnel name to kernel notification (#490) 2024-12-12 23:54:08 -05:00
GitHub Actions 1120a8fc81 Automated build update 2024-12-12 03:42:47 +00:00
Zane Schepke ab10be7266 chore: bump version 2024-12-11 01:37:16 -05:00
Zane Schepke 88f9d43e51 chore: add release notes 2024-12-11 01:35:17 -05:00
Zane Schepke 2877757396 fix: kernel mode toggle bug 2024-12-11 01:32:39 -05:00
Zane Schepke c657c62640 fix: shut down backend if we enter kernel mode 2024-12-11 00:18:42 -05:00
Zane Schepke d84d9df57d fix: notification channel creation bug
Fixes a crash that is caused by a typo when creating a new notification channel.

Also makes VPN kill switch visible on TVs
2024-12-11 00:03:39 -05:00
13 changed files with 135 additions and 122 deletions
@@ -73,7 +73,6 @@ class WireGuardAutoTunnel : Application() {
if (!settingsRepository.getSettings().isKernelEnabled) {
tunnelService.setBackendState(BackendState.SERVICE_ACTIVE, emptyList())
}
appStateRepository.getLocale()?.let {
LocaleUtil.changeLocale(it)
}
@@ -3,6 +3,7 @@ package com.zaneschepke.wireguardautotunnel.service.foreground
import android.app.Service
import android.content.Context
import android.content.Intent
import com.zaneschepke.wireguardautotunnel.data.domain.TunnelConfig
import com.zaneschepke.wireguardautotunnel.data.repository.AppDataRepository
import com.zaneschepke.wireguardautotunnel.service.foreground.autotunnel.AutoTunnelService
import com.zaneschepke.wireguardautotunnel.service.tile.AutoTunnelControlTile
@@ -58,12 +59,12 @@ class ServiceManager
}
}
suspend fun startBackgroundService() {
suspend fun startBackgroundService(tunnelConfig: TunnelConfig?) {
if (backgroundService.isCompleted) return
kotlin.runCatching {
startService(TunnelBackgroundService::class.java, true)
backgroundService.await()
backgroundService.getCompleted().start()
backgroundService.getCompleted().start(tunnelConfig)
}.onFailure {
Timber.e(it)
}
@@ -85,7 +86,7 @@ class ServiceManager
}
}
fun updateAutoTunnelTile() {
private fun updateAutoTunnelTile() {
if (autoTunnelTile.isCompleted) {
autoTunnelTile.getCompleted().updateTileState()
} else {
@@ -6,6 +6,8 @@ import android.os.IBinder
import androidx.core.app.ServiceCompat
import androidx.lifecycle.LifecycleService
import com.zaneschepke.wireguardautotunnel.R
import com.zaneschepke.wireguardautotunnel.data.domain.TunnelConfig
import com.zaneschepke.wireguardautotunnel.service.notification.NotificationAction
import com.zaneschepke.wireguardautotunnel.service.notification.NotificationService
import com.zaneschepke.wireguardautotunnel.service.notification.WireGuardNotification
import com.zaneschepke.wireguardautotunnel.util.Constants
@@ -24,12 +26,11 @@ class TunnelBackgroundService : LifecycleService() {
override fun onCreate() {
super.onCreate()
start()
serviceManager.backgroundService.complete(this)
}
override fun onBind(intent: Intent): IBinder? {
super.onBind(intent)
// We don't provide binding, so return null
return null
}
@@ -38,11 +39,11 @@ class TunnelBackgroundService : LifecycleService() {
return super.onStartCommand(intent, flags, startId)
}
fun start() {
fun start(tunnelConfig: TunnelConfig?) {
ServiceCompat.startForeground(
this,
NotificationService.KERNEL_SERVICE_NOTIFICATION_ID,
createNotification(),
createNotification(tunnelConfig),
Constants.SYSTEM_EXEMPT_SERVICE_TYPE_ID,
)
}
@@ -57,11 +58,13 @@ class TunnelBackgroundService : LifecycleService() {
super.onDestroy()
}
private fun createNotification(): Notification {
private fun createNotification(tunnelConfig: TunnelConfig?): Notification {
return notificationService.createNotification(
WireGuardNotification.NotificationChannels.VPN,
getString(R.string.tunnel_running),
description = "",
title = "${getString(R.string.tunnel_running)} - ${tunnelConfig?.name}",
actions = listOf(
notificationService.createNotificationAction(NotificationAction.TUNNEL_OFF),
),
)
}
}
@@ -86,13 +86,13 @@ constructor(
fun NotificationChannels.asBuilder(): NotificationCompat.Builder {
return when (this) {
NotificationChannels.VPN -> {
NotificationChannels.AUTO_TUNNEL -> {
NotificationCompat.Builder(
context,
context.getString(R.string.auto_tunnel_channel_id),
)
}
NotificationChannels.AUTO_TUNNEL -> {
NotificationChannels.VPN -> {
NotificationCompat.Builder(
context,
context.getString(R.string.vpn_channel_id),
@@ -102,6 +102,7 @@ constructor(
else -> throw NotImplementedError()
}
}.onFailure {
// TODO add better error message and comms to user
Timber.e(it)
}
}
@@ -113,26 +114,15 @@ constructor(
}
override suspend fun startTunnel(tunnelConfig: TunnelConfig?, background: Boolean) {
if (tunnelConfig == null) return
withContext(ioDispatcher) {
if (isTunnelAlreadyRunning(tunnelConfig)) return@withContext
if (tunnelConfig == null || isTunnelAlreadyRunning(tunnelConfig)) return@withContext
updateTunnelConfig(tunnelConfig) // need to update this here
withServiceActive {
onBeforeStart(background)
onBeforeStart()
tunnelControlMutex.withLock {
setState(tunnelConfig, TunnelState.UP).onSuccess {
startActiveTunnelJobs()
if (it.isUp()) appDataRepository.tunnels.save(tunnelConfig.copy(isActive = true))
with(notificationService) {
val notification = createNotification(
WireGuardNotification.NotificationChannels.VPN,
title = "${context.getString(R.string.tunnel_running)} - ${tunnelConfig.name}",
actions = listOf(
notificationService.createNotificationAction(NotificationAction.TUNNEL_OFF),
),
)
show(VPN_NOTIFICATION_ID, notification)
}
updateTunnelState(it, tunnelConfig)
onTunnelStart(tunnelConfig)
}
}.onFailure {
Timber.e(it)
@@ -148,10 +138,8 @@ constructor(
if (tunnelConfig == null) return@withContext
tunnelControlMutex.withLock {
setState(tunnelConfig, TunnelState.DOWN).onSuccess {
onTunnelStop(tunnelConfig)
updateTunnelState(it, null)
onStop(tunnelConfig)
notificationService.remove(VPN_NOTIFICATION_ID)
stopBackgroundService()
}.onFailure {
Timber.e(it)
}
@@ -216,33 +204,45 @@ constructor(
}
}
private suspend fun shutDownActiveTunnel() {
private suspend fun onBeforeStart() {
with(_vpnState.value) {
if (status.isUp()) {
stopTunnel()
}
if (status.isUp()) stopTunnel() else clearJobsAndStats()
if (isKernelBackend == true) serviceManager.startBackgroundService(tunnelConfig)
}
}
private suspend fun startBackgroundService() {
serviceManager.startBackgroundService()
serviceManager.updateTunnelTile()
private suspend fun onTunnelStart(tunnelConfig: TunnelConfig) {
startActiveTunnelJobs()
if (_vpnState.value.status.isUp()) {
appDataRepository.tunnels.save(tunnelConfig.copy(isActive = true))
}
if (isKernelBackend == false) launchUserspaceTunnelNotification()
}
private fun stopBackgroundService() {
serviceManager.stopBackgroundService()
serviceManager.updateTunnelTile()
private fun launchUserspaceTunnelNotification() {
with(notificationService) {
val notification = createNotification(
WireGuardNotification.NotificationChannels.VPN,
title = "${context.getString(R.string.tunnel_running)} - ${_vpnState.value.tunnelConfig?.name}",
actions = listOf(
notificationService.createNotificationAction(NotificationAction.TUNNEL_OFF),
),
)
show(VPN_NOTIFICATION_ID, notification)
}
}
private suspend fun onBeforeStart(background: Boolean) {
shutDownActiveTunnel()
resetBackendStatistics()
val settings = appDataRepository.settings.getSettings()
if (background || settings.isKernelEnabled) startBackgroundService()
}
private suspend fun onStop(tunnelConfig: TunnelConfig) {
private suspend fun onTunnelStop(tunnelConfig: TunnelConfig) {
appDataRepository.tunnels.save(tunnelConfig.copy(isActive = false))
if (isKernelBackend == true) {
serviceManager.stopBackgroundService()
} else {
notificationService.remove(VPN_NOTIFICATION_ID)
}
clearJobsAndStats()
}
private fun clearJobsAndStats() {
cancelActiveTunnelJobs()
resetBackendStatistics()
}
@@ -301,13 +301,11 @@ constructor(
is Backend -> updateBackendStatistics(
WireGuardStatistics(backend.getStatistics(this@WireGuardTunnel)),
)
is org.amnezia.awg.backend.Backend -> {
updateBackendStatistics(
AmneziaStatistics(
backend.getStatistics(this@WireGuardTunnel),
),
)
}
is org.amnezia.awg.backend.Backend -> updateBackendStatistics(
AmneziaStatistics(
backend.getStatistics(this@WireGuardTunnel),
),
)
}
delay(VPN_STATISTIC_CHECK_INTERVAL)
}
@@ -237,6 +237,7 @@ constructor(
if (!isKernelEnabled) {
requestRoot().onSuccess {
if (!isKernelSupported()) return@onSuccess SnackbarController.showMessage(StringValue.StringResource(R.string.kernel_not_supported))
tunnelService.get().setBackendState(BackendState.INACTIVE, emptyList())
appDataRepository.settings.save(
copy(
isKernelEnabled = true,
@@ -151,50 +151,51 @@ fun SettingsScreen(viewModel: SettingsViewModel = hiltViewModel(), appViewModel:
),
)
if (!isRunningOnTv) {
addAll(
listOf(
SelectionItem(
Icons.Outlined.VpnLock,
{
ScaledSwitch(
enabled = !(
(
uiState.settings.isTunnelOnWifiEnabled ||
uiState.settings.isTunnelOnEthernetEnabled ||
uiState.settings.isTunnelOnMobileDataEnabled
) &&
uiState.settings.isAutoTunnelEnabled
),
onClick = { appViewModel.onToggleAlwaysOnVPN() },
checked = uiState.settings.isAlwaysOnVpnEnabled,
)
},
title = {
Text(
stringResource(R.string.always_on_vpn_support),
style = MaterialTheme.typography.bodyMedium.copy(MaterialTheme.colorScheme.onSurface),
)
},
onClick = { appViewModel.onToggleAlwaysOnVPN() },
),
SelectionItem(
Icons.Outlined.VpnKeyOff,
title = {
Text(
stringResource(R.string.kill_switch_options),
style = MaterialTheme.typography.bodyMedium.copy(MaterialTheme.colorScheme.onSurface),
)
},
onClick = {
navController.navigate(Route.KillSwitch)
},
trailing = {
ForwardButton { navController.navigate(Route.KillSwitch) }
},
),
add(
SelectionItem(
Icons.Outlined.VpnLock,
{
ScaledSwitch(
enabled = !(
(
uiState.settings.isTunnelOnWifiEnabled ||
uiState.settings.isTunnelOnEthernetEnabled ||
uiState.settings.isTunnelOnMobileDataEnabled
) &&
uiState.settings.isAutoTunnelEnabled
),
onClick = { appViewModel.onToggleAlwaysOnVPN() },
checked = uiState.settings.isAlwaysOnVpnEnabled,
)
},
title = {
Text(
stringResource(R.string.always_on_vpn_support),
style = MaterialTheme.typography.bodyMedium.copy(MaterialTheme.colorScheme.onSurface),
)
},
onClick = { appViewModel.onToggleAlwaysOnVPN() },
),
)
}
add(
SelectionItem(
Icons.Outlined.VpnKeyOff,
title = {
Text(
stringResource(R.string.kill_switch_options),
style = MaterialTheme.typography.bodyMedium.copy(MaterialTheme.colorScheme.onSurface),
)
},
onClick = {
navController.navigate(Route.KillSwitch)
},
trailing = {
ForwardButton { navController.navigate(Route.KillSwitch) }
},
),
)
add(
SelectionItem(
Icons.Outlined.Restore,
@@ -25,7 +25,10 @@ import com.zaneschepke.wireguardautotunnel.ui.common.button.surface.SelectionIte
import com.zaneschepke.wireguardautotunnel.ui.common.button.surface.SurfaceSelectionGroupButton
import com.zaneschepke.wireguardautotunnel.ui.common.navigation.TopNavBar
import com.zaneschepke.wireguardautotunnel.ui.common.permission.vpn.withVpnPermission
import com.zaneschepke.wireguardautotunnel.ui.common.snackbar.SnackbarController
import com.zaneschepke.wireguardautotunnel.ui.screens.settings.components.ForwardButton
import com.zaneschepke.wireguardautotunnel.util.StringValue
import com.zaneschepke.wireguardautotunnel.util.extensions.isRunningOnTv
import com.zaneschepke.wireguardautotunnel.util.extensions.launchVpnSettings
import com.zaneschepke.wireguardautotunnel.util.extensions.scaledHeight
import com.zaneschepke.wireguardautotunnel.util.extensions.scaledWidth
@@ -38,6 +41,8 @@ fun KillSwitchScreen(uiState: AppUiState, appViewModel: AppViewModel) {
fun toggleVpnKillSwitch() {
with(uiState.settings) {
// TODO improve this error message
if (isKernelEnabled) return SnackbarController.showMessage(StringValue.StringResource(R.string.kernel_not_supported))
if (isVpnKillSwitchEnabled) {
appViewModel.onToggleVpnKillSwitch(false)
} else {
@@ -66,23 +71,25 @@ fun KillSwitchScreen(uiState: AppUiState, appViewModel: AppViewModel) {
.padding(top = 24.dp.scaledHeight())
.padding(horizontal = 24.dp.scaledWidth()),
) {
SurfaceSelectionGroupButton(
listOf(
SelectionItem(
Icons.Outlined.AdminPanelSettings,
title = {
Text(
stringResource(R.string.native_kill_switch),
style = MaterialTheme.typography.bodyMedium.copy(MaterialTheme.colorScheme.onSurface),
)
},
onClick = { context.launchVpnSettings() },
trailing = {
ForwardButton { context.launchVpnSettings() }
},
if (!context.isRunningOnTv()) {
SurfaceSelectionGroupButton(
listOf(
SelectionItem(
Icons.Outlined.AdminPanelSettings,
title = {
Text(
stringResource(R.string.native_kill_switch),
style = MaterialTheme.typography.bodyMedium.copy(MaterialTheme.colorScheme.onSurface),
)
},
onClick = { context.launchVpnSettings() },
trailing = {
ForwardButton { context.launchVpnSettings() }
},
),
),
),
)
)
}
SurfaceSelectionGroupButton(
buildList {
add(
@@ -84,8 +84,8 @@ fun Config.toWgQuickString(): String {
fun RootShell.getCurrentWifiName(): String? {
val response = mutableListOf<String>()
this.run(response, "dumpsys wifi | grep -o \"SSID: [^,]*\" | cut -d ' ' -f2- | tr -d '\"'")
return response.lastOrNull()
this.run(response, "dumpsys wifi | grep 'Supplicant state: COMPLETED' | grep -o 'SSID: [^,]*' | cut -d ' ' -f2- | tr -d '\"'")
return response.firstOrNull()
}
fun Backend.BackendState.asBackendState(): BackendState {
+2 -2
View File
@@ -1,7 +1,7 @@
object Constants {
const val VERSION_NAME = "3.6.3"
const val VERSION_NAME = "3.6.4"
const val JVM_TARGET = "17"
const val VERSION_CODE = 36300
const val VERSION_CODE = 36400
const val TARGET_SDK = 35
const val MIN_SDK = 26
const val APP_ID = "com.zaneschepke.wireguardautotunnel"
@@ -0,0 +1,3 @@
What's new:
- Fixed kernel mode toggle bug
- Fixed notification crash bug
+4 -4
View File
@@ -16,16 +16,16 @@ junit = "4.13.2"
kotlinx-serialization-json = "1.7.3"
lifecycle-runtime-compose = "2.8.7"
material3 = "1.3.1"
navigationCompose = "2.8.4"
navigationCompose = "2.8.5"
pinLockCompose = "1.0.4"
roomVersion = "2.6.1"
timber = "5.0.1"
tunnel = "1.2.1"
androidGradlePlugin = "8.8.0-rc01"
androidGradlePlugin = "8.9.0-alpha06"
kotlin = "2.1.0"
ksp = "2.1.0-1.0.29"
composeBom = "2024.11.00"
compose = "1.7.5"
composeBom = "2024.12.01"
compose = "1.7.6"
zxingAndroidEmbedded = "4.3.0"
coreSplashscreen = "1.0.1"
gradlePlugins-grgit = "5.3.0"
+1 -1
View File
@@ -1 +1 @@
13
16