Compare commits

..

1 Commits

Author SHA1 Message Date
dependabot[bot] e15a7c5627 build(deps): bump androidGradlePlugin from 8.6.0-rc01 to 8.7.0-alpha06
Bumps `androidGradlePlugin` from 8.6.0-rc01 to 8.7.0-alpha06.

Updates `com.android.application` from 8.6.0-rc01 to 8.7.0-alpha06

Updates `com.android.library` from 8.6.0-rc01 to 8.7.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-08-14 13:35:03 +00:00
31 changed files with 229 additions and 367 deletions
-17
View File
@@ -167,16 +167,6 @@
android:stopWithTask="false" android:stopWithTask="false"
tools:node="merge" /> tools:node="merge" />
<service
android:name=".service.foreground.TunnelBackgroundService"
android:exported="false"
android:foregroundServiceType="systemExempted"
android:permission="android.permission.BIND_VPN_SERVICE">
<intent-filter>
<action android:name="android.net.VpnService" />
</intent-filter>
</service>
<receiver <receiver
android:name=".receiver.BootReceiver" android:name=".receiver.BootReceiver"
android:enabled="true" android:enabled="true"
@@ -194,13 +184,6 @@
android:name=".receiver.BackgroundActionReceiver" android:name=".receiver.BackgroundActionReceiver"
android:enabled="true" android:enabled="true"
android:exported="false"/> android:exported="false"/>
<receiver
android:name=".receiver.AppUpdateReceiver"
android:exported="false">
<intent-filter>
<action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
</intent-filter>
</receiver>
<receiver <receiver
android:name=".receiver.KernelReceiver" android:name=".receiver.KernelReceiver"
android:exported="false" android:exported="false"
@@ -3,15 +3,10 @@ package com.zaneschepke.wireguardautotunnel
import android.app.Application import android.app.Application
import android.os.StrictMode import android.os.StrictMode
import android.os.StrictMode.ThreadPolicy import android.os.StrictMode.ThreadPolicy
import com.zaneschepke.logcatter.LocalLogCollector
import com.zaneschepke.wireguardautotunnel.module.ApplicationScope import com.zaneschepke.wireguardautotunnel.module.ApplicationScope
import com.zaneschepke.wireguardautotunnel.module.IoDispatcher
import com.zaneschepke.wireguardautotunnel.util.ReleaseTree import com.zaneschepke.wireguardautotunnel.util.ReleaseTree
import com.zaneschepke.wireguardautotunnel.util.extensions.isRunningOnTv
import dagger.hilt.android.HiltAndroidApp import dagger.hilt.android.HiltAndroidApp
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import timber.log.Timber import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
@@ -22,13 +17,6 @@ class WireGuardAutoTunnel : Application() {
@ApplicationScope @ApplicationScope
lateinit var applicationScope: CoroutineScope lateinit var applicationScope: CoroutineScope
@Inject
lateinit var localLogCollector: LocalLogCollector
@Inject
@IoDispatcher
lateinit var ioDispatcher: CoroutineDispatcher
override fun onCreate() { override fun onCreate() {
super.onCreate() super.onCreate()
instance = this instance = this
@@ -45,11 +33,6 @@ class WireGuardAutoTunnel : Application() {
} else { } else {
Timber.plant(ReleaseTree()) Timber.plant(ReleaseTree())
} }
if (!isRunningOnTv()) {
applicationScope.launch(ioDispatcher) {
localLogCollector.start()
}
}
} }
companion object { companion object {
@@ -1,47 +0,0 @@
package com.zaneschepke.wireguardautotunnel.receiver
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import com.zaneschepke.wireguardautotunnel.data.repository.AppDataRepository
import com.zaneschepke.wireguardautotunnel.module.ApplicationScope
import com.zaneschepke.wireguardautotunnel.service.foreground.ServiceManager
import com.zaneschepke.wireguardautotunnel.service.tunnel.TunnelService
import com.zaneschepke.wireguardautotunnel.util.extensions.startTunnelBackground
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import timber.log.Timber
import javax.inject.Inject
@AndroidEntryPoint
class AppUpdateReceiver : BroadcastReceiver() {
@Inject
@ApplicationScope
lateinit var applicationScope: CoroutineScope
@Inject
lateinit var appDataRepository: AppDataRepository
@Inject
lateinit var serviceManager: ServiceManager
@Inject
lateinit var tunnelService: TunnelService
override fun onReceive(context: Context, intent: Intent) {
if (intent.action != Intent.ACTION_MY_PACKAGE_REPLACED) return
applicationScope.launch {
val settings = appDataRepository.settings.getSettings()
if (settings.isAutoTunnelEnabled) {
Timber.i("Restarting services after upgrade")
serviceManager.startWatcherServiceForeground(context)
}
if (!settings.isAutoTunnelEnabled || settings.isAutoTunnelPaused) {
val tunnels = appDataRepository.tunnels.getAll().filter { it.isActive }
if (tunnels.isNotEmpty()) context.startTunnelBackground(tunnels.first().id)
}
}
}
}
@@ -5,12 +5,10 @@ import android.content.Context
import android.content.Intent import android.content.Intent
import com.zaneschepke.wireguardautotunnel.data.repository.TunnelConfigRepository import com.zaneschepke.wireguardautotunnel.data.repository.TunnelConfigRepository
import com.zaneschepke.wireguardautotunnel.module.ApplicationScope import com.zaneschepke.wireguardautotunnel.module.ApplicationScope
import com.zaneschepke.wireguardautotunnel.service.foreground.ServiceManager
import com.zaneschepke.wireguardautotunnel.service.tunnel.TunnelService import com.zaneschepke.wireguardautotunnel.service.tunnel.TunnelService
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Provider import javax.inject.Provider
@@ -27,19 +25,14 @@ class BackgroundActionReceiver : BroadcastReceiver() {
@Inject @Inject
lateinit var tunnelConfigRepository: TunnelConfigRepository lateinit var tunnelConfigRepository: TunnelConfigRepository
@Inject
lateinit var serviceManager: ServiceManager
override fun onReceive(context: Context, intent: Intent) { override fun onReceive(context: Context, intent: Intent) {
val id = intent.getIntExtra(TUNNEL_ID_EXTRA_KEY, 0) val id = intent.getIntExtra(TUNNEL_ID_EXTRA_KEY, 0)
if (id == 0) return if (id == 0) return
when (intent.action) { when (intent.action) {
ACTION_CONNECT -> { ACTION_CONNECT -> {
Timber.d("Connect actions")
applicationScope.launch { applicationScope.launch {
val tunnel = tunnelConfigRepository.getById(id) val tunnel = tunnelConfigRepository.getById(id)
tunnel?.let { tunnel?.let {
serviceManager.startTunnelBackgroundService(context)
tunnelService.get().startTunnel(it) tunnelService.get().startTunnel(it)
} }
} }
@@ -48,7 +41,6 @@ class BackgroundActionReceiver : BroadcastReceiver() {
applicationScope.launch { applicationScope.launch {
val tunnel = tunnelConfigRepository.getById(id) val tunnel = tunnelConfigRepository.getById(id)
tunnel?.let { tunnel?.let {
serviceManager.stopTunnelBackgroundService(context)
tunnelService.get().stopTunnel(it) tunnelService.get().stopTunnel(it)
} }
} }
@@ -7,7 +7,6 @@ import com.zaneschepke.wireguardautotunnel.data.repository.AppDataRepository
import com.zaneschepke.wireguardautotunnel.module.ApplicationScope import com.zaneschepke.wireguardautotunnel.module.ApplicationScope
import com.zaneschepke.wireguardautotunnel.service.foreground.ServiceManager import com.zaneschepke.wireguardautotunnel.service.foreground.ServiceManager
import com.zaneschepke.wireguardautotunnel.service.tunnel.TunnelService import com.zaneschepke.wireguardautotunnel.service.tunnel.TunnelService
import com.zaneschepke.wireguardautotunnel.util.extensions.startTunnelBackground
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@@ -36,7 +35,7 @@ class BootReceiver : BroadcastReceiver() {
val settings = appDataRepository.settings.getSettings() val settings = appDataRepository.settings.getSettings()
if (settings.isRestoreOnBootEnabled) { if (settings.isRestoreOnBootEnabled) {
appDataRepository.getStartTunnelConfig()?.let { appDataRepository.getStartTunnelConfig()?.let {
context.startTunnelBackground(it.id) tunnelService.get().startTunnel(it)
} }
} }
if (settings.isAutoTunnelEnabled) { if (settings.isAutoTunnelEnabled) {
@@ -50,20 +50,4 @@ class ServiceManager {
AutoTunnelService::class.java, AutoTunnelService::class.java,
) )
} }
fun startTunnelBackgroundService(context: Context) {
actionOnService(
Action.START_FOREGROUND,
context,
TunnelBackgroundService::class.java,
)
}
fun stopTunnelBackgroundService(context: Context) {
actionOnService(
Action.STOP,
context,
TunnelBackgroundService::class.java,
)
}
} }
@@ -1,41 +0,0 @@
package com.zaneschepke.wireguardautotunnel.service.foreground
import android.app.Notification
import android.os.Bundle
import com.zaneschepke.wireguardautotunnel.R
import com.zaneschepke.wireguardautotunnel.service.notification.NotificationService
import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject
@AndroidEntryPoint
class TunnelBackgroundService : ForegroundService() {
@Inject
lateinit var notificationService: NotificationService
private val foregroundId = 123
override fun onCreate() {
super.onCreate()
startForeground(foregroundId, createNotification())
}
override fun startService(extras: Bundle?) {
super.startService(extras)
startForeground(foregroundId, createNotification())
}
override fun stopService() {
super.stopService()
stopForeground(STOP_FOREGROUND_REMOVE)
}
private fun createNotification(): Notification {
return notificationService.createNotification(
getString(R.string.vpn_channel_id),
getString(R.string.vpn_channel_name),
getString(R.string.tunnel_start_text),
description = "",
)
}
}
@@ -7,8 +7,6 @@ import com.zaneschepke.wireguardautotunnel.module.ApplicationScope
import com.zaneschepke.wireguardautotunnel.service.foreground.Action import com.zaneschepke.wireguardautotunnel.service.foreground.Action
import com.zaneschepke.wireguardautotunnel.service.foreground.AutoTunnelService import com.zaneschepke.wireguardautotunnel.service.foreground.AutoTunnelService
import com.zaneschepke.wireguardautotunnel.service.tunnel.TunnelService import com.zaneschepke.wireguardautotunnel.service.tunnel.TunnelService
import com.zaneschepke.wireguardautotunnel.util.extensions.startTunnelBackground
import com.zaneschepke.wireguardautotunnel.util.extensions.stopTunnelBackground
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@@ -44,8 +42,8 @@ class ShortcutsActivity : ComponentActivity() {
Timber.d("Shortcut action on name: ${tunnelConfig?.name}") Timber.d("Shortcut action on name: ${tunnelConfig?.name}")
tunnelConfig?.let { tunnelConfig?.let {
when (intent.action) { when (intent.action) {
Action.START.name -> this@ShortcutsActivity.startTunnelBackground(it.id) Action.START.name -> tunnelService.get().startTunnel(it)
Action.STOP.name -> this@ShortcutsActivity.stopTunnelBackground(it.id) Action.STOP.name -> tunnelService.get().stopTunnel(it)
else -> Unit else -> Unit
} }
} }
@@ -68,7 +68,6 @@ class TunnelControlTile : TileService(), LifecycleOwner {
override fun onClick() { override fun onClick() {
super.onClick() super.onClick()
unlockAndRun { unlockAndRun {
Timber.d("Click")
lifecycleScope.launch { lifecycleScope.launch {
val context = this@TunnelControlTile val context = this@TunnelControlTile
val lastActive = appDataRepository.getStartTunnelConfig() val lastActive = appDataRepository.getStartTunnelConfig()
@@ -14,7 +14,4 @@ interface TunnelService : Tunnel, org.amnezia.awg.backend.Tunnel {
suspend fun runningTunnelNames(): Set<String> suspend fun runningTunnelNames(): Set<String>
suspend fun getState(): TunnelState suspend fun getState(): TunnelState
fun cancelStatsJob()
fun startStatsJob()
} }
@@ -14,6 +14,7 @@ import com.zaneschepke.wireguardautotunnel.service.tunnel.statistics.TunnelStati
import com.zaneschepke.wireguardautotunnel.service.tunnel.statistics.WireGuardStatistics import com.zaneschepke.wireguardautotunnel.service.tunnel.statistics.WireGuardStatistics
import com.zaneschepke.wireguardautotunnel.util.Constants import com.zaneschepke.wireguardautotunnel.util.Constants
import com.zaneschepke.wireguardautotunnel.util.extensions.requestTunnelTileServiceStateUpdate import com.zaneschepke.wireguardautotunnel.util.extensions.requestTunnelTileServiceStateUpdate
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
@@ -55,17 +56,8 @@ constructor(
return runCatching { return runCatching {
when (val backend = backend()) { when (val backend = backend()) {
is Backend -> backend.setState(this, tunnelState.toWgState(), TunnelConfig.configFromWgQuick(tunnelConfig.wgQuick)).let { TunnelState.from(it) } is Backend -> backend.setState(this, tunnelState.toWgState(), TunnelConfig.configFromWgQuick(tunnelConfig.wgQuick)).let { TunnelState.from(it) }
is org.amnezia.awg.backend.Backend -> { is org.amnezia.awg.backend.Backend -> backend.setState(this, tunnelState.toAmState(), TunnelConfig.configFromAmQuick(tunnelConfig.amQuick)).let {
val config = if (tunnelConfig.amQuick.isBlank()) { TunnelState.from(it)
TunnelConfig.configFromAmQuick(
tunnelConfig.wgQuick,
)
} else {
TunnelConfig.configFromAmQuick(tunnelConfig.amQuick)
}
backend.setState(this, tunnelState.toAmState(), config).let {
TunnelState.from(it)
}
} }
else -> throw NotImplementedError() else -> throw NotImplementedError()
} }
@@ -152,14 +144,6 @@ constructor(
} }
} }
override fun cancelStatsJob() {
statsJob?.cancel()
}
override fun startStatsJob() {
statsJob = startTunnelStatisticsJob()
}
override fun getName(): String { override fun getName(): String {
return _vpnState.value.tunnelConfig?.name ?: "" return _vpnState.value.tunnelConfig?.name ?: ""
} }
@@ -171,9 +155,15 @@ constructor(
private fun handleStateChange(state: TunnelState) { private fun handleStateChange(state: TunnelState) {
emitTunnelState(state) emitTunnelState(state)
WireGuardAutoTunnel.instance.requestTunnelTileServiceStateUpdate() WireGuardAutoTunnel.instance.requestTunnelTileServiceStateUpdate()
when (state) { if (state == TunnelState.UP) {
TunnelState.UP -> startStatsJob() statsJob = startTunnelStatisticsJob()
else -> cancelStatsJob() }
if (state == TunnelState.DOWN) {
try {
statsJob?.cancel()
} catch (e: CancellationException) {
Timber.i("Stats job cancelled")
}
} }
} }
@@ -5,9 +5,6 @@ import androidx.activity.SystemBarStyle
import androidx.activity.compose.setContent import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.compose.animation.core.tween
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.foundation.focusable import androidx.compose.foundation.focusable
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
@@ -18,7 +15,6 @@ import androidx.compose.material3.SnackbarDuration
import androidx.compose.material3.SnackbarHost import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.SnackbarResult import androidx.compose.material3.SnackbarResult
import androidx.compose.material3.Surface
import androidx.compose.material3.surfaceColorAtElevation import androidx.compose.material3.surfaceColorAtElevation
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
@@ -39,7 +35,8 @@ import androidx.navigation.compose.currentBackStackEntryAsState
import androidx.navigation.compose.rememberNavController import androidx.navigation.compose.rememberNavController
import androidx.navigation.navArgument import androidx.navigation.navArgument
import com.zaneschepke.wireguardautotunnel.data.repository.AppStateRepository import com.zaneschepke.wireguardautotunnel.data.repository.AppStateRepository
import com.zaneschepke.wireguardautotunnel.service.tunnel.TunnelService import com.zaneschepke.wireguardautotunnel.data.repository.SettingsRepository
import com.zaneschepke.wireguardautotunnel.service.foreground.ServiceManager
import com.zaneschepke.wireguardautotunnel.ui.common.navigation.BottomNavBar import com.zaneschepke.wireguardautotunnel.ui.common.navigation.BottomNavBar
import com.zaneschepke.wireguardautotunnel.ui.common.prompt.CustomSnackBar import com.zaneschepke.wireguardautotunnel.ui.common.prompt.CustomSnackBar
import com.zaneschepke.wireguardautotunnel.ui.screens.config.ConfigScreen import com.zaneschepke.wireguardautotunnel.ui.screens.config.ConfigScreen
@@ -51,7 +48,6 @@ import com.zaneschepke.wireguardautotunnel.ui.screens.settings.SettingsScreen
import com.zaneschepke.wireguardautotunnel.ui.screens.support.SupportScreen import com.zaneschepke.wireguardautotunnel.ui.screens.support.SupportScreen
import com.zaneschepke.wireguardautotunnel.ui.screens.support.logs.LogsScreen import com.zaneschepke.wireguardautotunnel.ui.screens.support.logs.LogsScreen
import com.zaneschepke.wireguardautotunnel.ui.theme.WireguardAutoTunnelTheme import com.zaneschepke.wireguardautotunnel.ui.theme.WireguardAutoTunnelTheme
import com.zaneschepke.wireguardautotunnel.util.Constants
import com.zaneschepke.wireguardautotunnel.util.StringValue import com.zaneschepke.wireguardautotunnel.util.StringValue
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
@@ -64,7 +60,10 @@ class MainActivity : AppCompatActivity() {
lateinit var appStateRepository: AppStateRepository lateinit var appStateRepository: AppStateRepository
@Inject @Inject
lateinit var tunnelService: TunnelService lateinit var settingsRepository: SettingsRepository
@Inject
lateinit var serviceManager: ServiceManager
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
@@ -73,6 +72,13 @@ class MainActivity : AppCompatActivity() {
enableEdgeToEdge(navigationBarStyle = SystemBarStyle.dark(Color.Transparent.toArgb())) enableEdgeToEdge(navigationBarStyle = SystemBarStyle.dark(Color.Transparent.toArgb()))
lifecycleScope.launch {
val settings = settingsRepository.getSettings()
if (settings.isAutoTunnelEnabled) {
serviceManager.startWatcherService(application.applicationContext)
}
}
setContent { setContent {
val appViewModel = hiltViewModel<AppViewModel>() val appViewModel = hiltViewModel<AppViewModel>()
val appUiState by appViewModel.appUiState.collectAsStateWithLifecycle() val appUiState by appViewModel.appUiState.collectAsStateWithLifecycle()
@@ -121,7 +127,7 @@ class MainActivity : AppCompatActivity() {
) )
} }
}, },
containerColor = MaterialTheme.colorScheme.background, // TODO refactor
modifier = modifier =
Modifier Modifier
.focusable() .focusable()
@@ -142,97 +148,92 @@ class MainActivity : AppCompatActivity() {
) )
}, },
) { padding -> ) { padding ->
Surface(modifier = Modifier.fillMaxSize().padding(padding)) { NavHost(
NavHost( navController,
navController, startDestination = (if (isPinLockEnabled == true) Screen.Lock.route else Screen.Main.route),
enterTransition = { fadeIn(tween(Constants.TRANSITION_ANIMATION_TIME)) }, modifier =
exitTransition = { fadeOut(tween(Constants.TRANSITION_ANIMATION_TIME)) }, Modifier
startDestination = (if (isPinLockEnabled == true) Screen.Lock.route else Screen.Main.route), .padding(padding)
.fillMaxSize(),
) {
composable(
Screen.Main.route,
) { ) {
composable( MainScreen(
Screen.Main.route, focusRequester = focusRequester,
) { appViewModel = appViewModel,
MainScreen( navController = navController,
focusRequester = focusRequester, )
appViewModel = appViewModel, }
composable(
Screen.Settings.route,
) {
SettingsScreen(
appViewModel = appViewModel,
navController = navController,
focusRequester = focusRequester,
)
}
composable(
Screen.Support.route,
) {
SupportScreen(
focusRequester = focusRequester,
navController = navController,
)
}
composable(Screen.Support.Logs.route) {
LogsScreen()
}
composable(
"${Screen.Config.route}/{id}?configType={configType}",
arguments =
listOf(
navArgument("id") {
type = NavType.StringType
defaultValue = "0"
},
navArgument("configType") {
type = NavType.StringType
defaultValue = ConfigType.WIREGUARD.name
},
),
) {
val id = it.arguments?.getString("id")
val configType =
ConfigType.valueOf(
it.arguments?.getString("configType") ?: ConfigType.WIREGUARD.name,
)
if (!id.isNullOrBlank()) {
ConfigScreen(
navController = navController, navController = navController,
tunnelId = id,
appViewModel = appViewModel,
focusRequester = focusRequester,
configType = configType,
) )
} }
composable( }
Screen.Settings.route, composable("${Screen.Option.route}/{id}") {
) { val id = it.arguments?.getString("id")
SettingsScreen( if (!id.isNullOrBlank()) {
appViewModel = appViewModel, OptionsScreen(
navController = navController, navController = navController,
tunnelId = id,
appViewModel = appViewModel,
focusRequester = focusRequester, focusRequester = focusRequester,
) )
} }
composable( }
Screen.Support.route, composable(Screen.Lock.route) {
) { PinLockScreen(
SupportScreen( navController = navController,
focusRequester = focusRequester, appViewModel = appViewModel,
navController = navController, )
)
}
composable(Screen.Support.Logs.route) {
LogsScreen()
}
composable(
"${Screen.Config.route}/{id}?configType={configType}",
arguments =
listOf(
navArgument("id") {
type = NavType.StringType
defaultValue = "0"
},
navArgument("configType") {
type = NavType.StringType
defaultValue = ConfigType.WIREGUARD.name
},
),
) {
val id = it.arguments?.getString("id")
val configType =
ConfigType.valueOf(
it.arguments?.getString("configType") ?: ConfigType.WIREGUARD.name,
)
if (!id.isNullOrBlank()) {
ConfigScreen(
navController = navController,
tunnelId = id,
appViewModel = appViewModel,
focusRequester = focusRequester,
configType = configType,
)
}
}
composable("${Screen.Option.route}/{id}") {
val id = it.arguments?.getString("id")
if (!id.isNullOrBlank()) {
OptionsScreen(
navController = navController,
tunnelId = id,
appViewModel = appViewModel,
focusRequester = focusRequester,
)
}
}
composable(Screen.Lock.route) {
PinLockScreen(
navController = navController,
appViewModel = appViewModel,
)
}
} }
} }
} }
} }
} }
} }
override fun onDestroy() {
super.onDestroy()
tunnelService.cancelStatsJob()
}
} }
@@ -9,16 +9,21 @@ import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
import androidx.lifecycle.Lifecycle import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle import androidx.lifecycle.repeatOnLifecycle
import com.zaneschepke.logcatter.LocalLogCollector
import com.zaneschepke.wireguardautotunnel.WireGuardAutoTunnel import com.zaneschepke.wireguardautotunnel.WireGuardAutoTunnel
import com.zaneschepke.wireguardautotunnel.data.repository.AppDataRepository import com.zaneschepke.wireguardautotunnel.data.repository.AppDataRepository
import com.zaneschepke.wireguardautotunnel.data.repository.AppStateRepository import com.zaneschepke.wireguardautotunnel.data.repository.AppStateRepository
import com.zaneschepke.wireguardautotunnel.service.foreground.ServiceManager import com.zaneschepke.wireguardautotunnel.module.ApplicationScope
import com.zaneschepke.wireguardautotunnel.service.tunnel.TunnelService import com.zaneschepke.wireguardautotunnel.service.tunnel.TunnelService
import com.zaneschepke.wireguardautotunnel.service.tunnel.TunnelState import com.zaneschepke.wireguardautotunnel.util.Constants
import com.zaneschepke.wireguardautotunnel.util.extensions.isRunningOnTv
import com.zaneschepke.wireguardautotunnel.util.extensions.requestAutoTunnelTileServiceUpdate import com.zaneschepke.wireguardautotunnel.util.extensions.requestAutoTunnelTileServiceUpdate
import com.zaneschepke.wireguardautotunnel.util.extensions.requestTunnelTileServiceStateUpdate import com.zaneschepke.wireguardautotunnel.util.extensions.requestTunnelTileServiceStateUpdate
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import timber.log.Timber
import xyz.teamgravity.pin_lock_compose.PinManager import xyz.teamgravity.pin_lock_compose.PinManager
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Provider import javax.inject.Provider
@@ -36,7 +41,11 @@ class SplashActivity : ComponentActivity() {
lateinit var tunnelService: Provider<TunnelService> lateinit var tunnelService: Provider<TunnelService>
@Inject @Inject
lateinit var serviceManager: ServiceManager lateinit var localLogCollector: LocalLogCollector
@Inject
@ApplicationScope
lateinit var applicationScope: CoroutineScope
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
@@ -45,17 +54,29 @@ class SplashActivity : ComponentActivity() {
} }
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
applicationScope.launch {
if (!this@SplashActivity.isRunningOnTv()) localLogCollector.start()
}
lifecycleScope.launch { lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.CREATED) { repeatOnLifecycle(Lifecycle.State.CREATED) {
val pinLockEnabled = appStateRepository.isPinLockEnabled() val pinLockEnabled = appStateRepository.isPinLockEnabled()
if (pinLockEnabled) { if (pinLockEnabled) {
PinManager.initialize(WireGuardAutoTunnel.instance) PinManager.initialize(WireGuardAutoTunnel.instance)
} }
// TODO eventually make this support multi-tunnel
Timber.d("Check for active tunnels")
val settings = appDataRepository.settings.getSettings() val settings = appDataRepository.settings.getSettings()
if (settings.isAutoTunnelEnabled) serviceManager.startWatcherService(application.applicationContext) if (settings.isKernelEnabled) {
if (tunnelService.get().getState() == TunnelState.UP) tunnelService.get().startStatsJob() // delay in case state change is underway while app is opened
val tunnels = appDataRepository.tunnels.getActive() delay(Constants.FOCUS_REQUEST_DELAY)
if (tunnels.isNotEmpty() && tunnelService.get().getState() == TunnelState.DOWN) tunnelService.get().startTunnel(tunnels.first()) val activeTunnels = appDataRepository.tunnels.getActive()
Timber.d("Kernel mode enabled, seeing if we need to start a tunnel")
activeTunnels.firstOrNull()?.let {
Timber.d("Trying to start active kernel tunnel: ${it.name}")
tunnelService.get().startTunnel(it)
}
}
requestTunnelTileServiceStateUpdate() requestTunnelTileServiceStateUpdate()
requestAutoTunnelTileServiceUpdate() requestAutoTunnelTileServiceUpdate()
@@ -10,29 +10,37 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.navigation.NavController import androidx.navigation.NavController
import androidx.navigation.NavGraph.Companion.findStartDestination import androidx.navigation.NavGraph.Companion.findStartDestination
import androidx.navigation.compose.currentBackStackEntryAsState import androidx.navigation.compose.currentBackStackEntryAsState
import com.zaneschepke.wireguardautotunnel.ui.Screen
@Composable @Composable
fun BottomNavBar(navController: NavController, bottomNavItems: List<BottomNavItem>) { fun BottomNavBar(navController: NavController, bottomNavItems: List<BottomNavItem>) {
val backStackEntry = navController.currentBackStackEntryAsState()
var showBottomBar by rememberSaveable { mutableStateOf(true) } var showBottomBar by rememberSaveable { mutableStateOf(true) }
val navBackStackEntry by navController.currentBackStackEntryAsState() val navBackStackEntry by navController.currentBackStackEntryAsState()
showBottomBar = bottomNavItems.firstOrNull { navBackStackEntry?.destination?.route?.contains(it.route) == true } != null // TODO find a better way to hide nav bar
showBottomBar =
when (navBackStackEntry?.destination?.route) {
Screen.Lock.route -> false
else -> true
}
if (showBottomBar) { NavigationBar(
NavigationBar( containerColor = if (!showBottomBar) Color.Transparent else MaterialTheme.colorScheme.background,
containerColor = MaterialTheme.colorScheme.surface, ) {
) { if (showBottomBar) {
bottomNavItems.forEach { item -> bottomNavItems.forEach { item ->
val selected = navBackStackEntry?.destination?.route?.contains(item.route) == true val selected = item.route == backStackEntry.value?.destination?.route
NavigationBarItem( NavigationBarItem(
selected = selected, selected = selected,
onClick = { onClick = {
if (navBackStackEntry?.destination?.route == item.route) return@NavigationBarItem
navController.navigate(item.route) { navController.navigate(item.route) {
// Pop up to the start destination of the graph to // Pop up to the start destination of the graph to
// avoid building up a large stack of destinations // avoid building up a large stack of destinations
@@ -110,12 +110,7 @@ fun ConfigScreen(
LaunchedEffect(uiState.loading) { LaunchedEffect(uiState.loading) {
if (!uiState.loading && context.isRunningOnTv()) { if (!uiState.loading && context.isRunningOnTv()) {
delay(Constants.FOCUS_REQUEST_DELAY) delay(Constants.FOCUS_REQUEST_DELAY)
kotlin.runCatching { focusRequester.requestFocus()
focusRequester.requestFocus()
}.onFailure {
delay(Constants.FOCUS_REQUEST_DELAY)
focusRequester.requestFocus()
}
} }
} }
@@ -296,7 +296,7 @@ constructor(
val wgQuick = buildConfig().toWgQuickString(true) val wgQuick = buildConfig().toWgQuickString(true)
val amQuick = val amQuick =
if (configType == ConfigType.AMNEZIA) { if (configType == ConfigType.AMNEZIA) {
buildAmConfig().toAwgQuickString(true) buildAmConfig().toAwgQuickString()
} else { } else {
TunnelConfig.AM_QUICK_DEFAULT TunnelConfig.AM_QUICK_DEFAULT
} }
@@ -4,6 +4,9 @@ import android.annotation.SuppressLint
import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity.RESULT_OK import androidx.appcompat.app.AppCompatActivity.RESULT_OK
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.focusable import androidx.compose.foundation.focusable
import androidx.compose.foundation.gestures.ScrollableDefaults import androidx.compose.foundation.gestures.ScrollableDefaults
@@ -144,12 +147,7 @@ fun MainScreen(
LaunchedEffect(Unit) { LaunchedEffect(Unit) {
if (context.isRunningOnTv()) { if (context.isRunningOnTv()) {
delay(Constants.FOCUS_REQUEST_DELAY) delay(Constants.FOCUS_REQUEST_DELAY)
kotlin.runCatching { focusRequester.requestFocus()
focusRequester.requestFocus()
}.onFailure {
delay(Constants.FOCUS_REQUEST_DELAY)
focusRequester.requestFocus()
}
} }
} }
@@ -267,8 +265,12 @@ fun MainScreen(
reverseLayout = false, reverseLayout = false,
flingBehavior = ScrollableDefaults.flingBehavior(), flingBehavior = ScrollableDefaults.flingBehavior(),
) { ) {
if (uiState.tunnels.isEmpty()) { item {
item { AnimatedVisibility(
uiState.tunnels.isEmpty(),
exit = fadeOut(),
enter = fadeIn(),
) {
GettingStartedLabel(onClick = { context.openWebUrl(it) }) GettingStartedLabel(onClick = { context.openWebUrl(it) })
} }
} }
@@ -179,7 +179,7 @@ constructor(
when (type) { when (type) {
ConfigType.AMNEZIA -> { ConfigType.AMNEZIA -> {
val config = org.amnezia.awg.config.Config.parse(it) val config = org.amnezia.awg.config.Config.parse(it)
amQuick = config.toAwgQuickString(true) amQuick = config.toAwgQuickString()
config.toWgQuickString() config.toWgQuickString()
} }
@@ -252,7 +252,7 @@ constructor(
org.amnezia.awg.config.Config.parse( org.amnezia.awg.config.Config.parse(
zip, zip,
) )
amQuick = config.toAwgQuickString(true) amQuick = config.toAwgQuickString()
config.toWgQuickString() config.toWgQuickString()
} }
@@ -88,12 +88,7 @@ fun OptionsScreen(
optionsViewModel.init(tunnelId) optionsViewModel.init(tunnelId)
if (context.isRunningOnTv()) { if (context.isRunningOnTv()) {
delay(Constants.FOCUS_REQUEST_DELAY) delay(Constants.FOCUS_REQUEST_DELAY)
kotlin.runCatching { focusRequester.requestFocus()
focusRequester.requestFocus()
}.onFailure {
delay(Constants.FOCUS_REQUEST_DELAY)
focusRequester.requestFocus()
}
} }
} }
@@ -12,6 +12,7 @@ import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.ActivityResult import androidx.activity.result.ActivityResult
import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity.RESULT_OK import androidx.appcompat.app.AppCompatActivity.RESULT_OK
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
@@ -66,6 +67,7 @@ import com.google.accompanist.permissions.isGranted
import com.google.accompanist.permissions.rememberPermissionState import com.google.accompanist.permissions.rememberPermissionState
import com.zaneschepke.wireguardautotunnel.R import com.zaneschepke.wireguardautotunnel.R
import com.zaneschepke.wireguardautotunnel.WireGuardAutoTunnel import com.zaneschepke.wireguardautotunnel.WireGuardAutoTunnel
import com.zaneschepke.wireguardautotunnel.data.domain.TunnelConfig
import com.zaneschepke.wireguardautotunnel.service.tunnel.TunnelState import com.zaneschepke.wireguardautotunnel.service.tunnel.TunnelState
import com.zaneschepke.wireguardautotunnel.ui.AppViewModel import com.zaneschepke.wireguardautotunnel.ui.AppViewModel
import com.zaneschepke.wireguardautotunnel.ui.Screen import com.zaneschepke.wireguardautotunnel.ui.Screen
@@ -82,7 +84,9 @@ import com.zaneschepke.wireguardautotunnel.util.extensions.isRunningOnTv
import com.zaneschepke.wireguardautotunnel.util.extensions.launchAppSettings import com.zaneschepke.wireguardautotunnel.util.extensions.launchAppSettings
import com.zaneschepke.wireguardautotunnel.util.extensions.showToast import com.zaneschepke.wireguardautotunnel.util.extensions.showToast
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import timber.log.Timber
import xyz.teamgravity.pin_lock_compose.PinManager import xyz.teamgravity.pin_lock_compose.PinManager
import java.io.File
@OptIn( @OptIn(
ExperimentalPermissionsApi::class, ExperimentalPermissionsApi::class,
@@ -151,6 +155,43 @@ fun SettingsScreen(
}, },
) )
fun exportAllConfigs() {
try {
val wgFiles =
uiState.tunnels.map { config ->
val file = File(context.cacheDir, "${config.name}-wg.conf")
file.outputStream().use {
it.write(config.wgQuick.toByteArray())
}
file
}
val amFiles =
uiState.tunnels.mapNotNull { config ->
if (config.amQuick != TunnelConfig.AM_QUICK_DEFAULT) {
val file = File(context.cacheDir, "${config.name}-am.conf")
file.outputStream().use {
it.write(config.amQuick.toByteArray())
}
file
} else {
null
}
}
scope.launch {
viewModel.onExportTunnels(wgFiles + amFiles).onFailure {
appViewModel.showSnackbarMessage(it.getMessage(context))
}.onSuccess {
didExportFiles = true
appViewModel.showSnackbarMessage(
context.getString(R.string.exported_configs_message),
)
}
}
} catch (e: Exception) {
Timber.e(e)
}
}
fun isBatteryOptimizationsDisabled(): Boolean { fun isBatteryOptimizationsDisabled(): Boolean {
val pm = context.getSystemService(POWER_SERVICE) as PowerManager val pm = context.getSystemService(POWER_SERVICE) as PowerManager
return pm.isIgnoringBatteryOptimizations(context.packageName) return pm.isIgnoringBatteryOptimizations(context.packageName)
@@ -228,7 +269,7 @@ fun SettingsScreen(
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.P) { if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.P) {
checkFineLocationGranted() checkFineLocationGranted()
} }
if (!uiState.isLocationDisclosureShown) { if(!uiState.isLocationDisclosureShown) {
BackgroundLocationDisclosure( BackgroundLocationDisclosure(
onDismiss = { viewModel.setLocationDisclosureShown() }, onDismiss = { viewModel.setLocationDisclosureShown() },
onAttest = { onAttest = {
@@ -241,6 +282,7 @@ fun SettingsScreen(
return return
} }
BackgroundLocationDialog( BackgroundLocationDialog(
showLocationDialog, showLocationDialog,
onDismiss = { showLocationDialog = false }, onDismiss = { showLocationDialog = false },
@@ -259,13 +301,7 @@ fun SettingsScreen(
AuthorizationPrompt( AuthorizationPrompt(
onSuccess = { onSuccess = {
showAuthPrompt = false showAuthPrompt = false
scope.launch { exportAllConfigs()
viewModel.exportAllConfigs().onSuccess {
appViewModel.showSnackbarMessage(context.getString(R.string.exported_configs_message))
}.onFailure {
appViewModel.showSnackbarMessage(context.getString(R.string.export_configs_failed))
}
}
}, },
onError = { _ -> onError = { _ ->
showAuthPrompt = false showAuthPrompt = false
@@ -344,7 +380,7 @@ fun SettingsScreen(
.focusRequester(focusRequester) .focusRequester(focusRequester)
}, },
) )
if (uiState.settings.isTunnelOnWifiEnabled) { AnimatedVisibility(visible = uiState.settings.isTunnelOnWifiEnabled) {
Column { Column {
FlowRow( FlowRow(
modifier = modifier =
@@ -594,7 +630,7 @@ fun SettingsScreen(
Modifier Modifier
.fillMaxWidth(fillMaxWidth) .fillMaxWidth(fillMaxWidth)
.padding(vertical = 10.dp) .padding(vertical = 10.dp)
.padding(bottom = 10.dp), .padding(bottom = 140.dp),
) { ) {
Column( Column(
horizontalAlignment = Alignment.Start, horizontalAlignment = Alignment.Start,
@@ -248,13 +248,4 @@ constructor(
onSuccess() onSuccess()
} }
} }
suspend fun exportAllConfigs(): Result<Unit> {
return kotlin.runCatching {
val tunnels = appDataRepository.tunnels.getAll()
val wgFiles = fileUtils.createWgFiles(tunnels)
val amFiles = fileUtils.createAmFiles(tunnels)
onExportTunnels(wgFiles + amFiles)
}
}
} }
@@ -28,7 +28,12 @@ import com.zaneschepke.wireguardautotunnel.R
import com.zaneschepke.wireguardautotunnel.util.extensions.isRunningOnTv import com.zaneschepke.wireguardautotunnel.util.extensions.isRunningOnTv
@Composable @Composable
fun BackgroundLocationDisclosure(onDismiss: () -> Unit, onAttest: () -> Unit, scrollState: ScrollState, focusRequester: FocusRequester) { fun BackgroundLocationDisclosure(
onDismiss: () -> Unit,
onAttest: () -> Unit,
scrollState: ScrollState,
focusRequester: FocusRequester,
) {
val context = LocalContext.current val context = LocalContext.current
Column( Column(
horizontalAlignment = Alignment.CenterHorizontally, horizontalAlignment = Alignment.CenterHorizontally,
@@ -20,10 +20,9 @@ private val DarkColorScheme =
darkColorScheme( darkColorScheme(
// primary = Purple80, // primary = Purple80,
primary = virdigris, primary = virdigris,
secondary = PurpleGrey40, secondary = virdigris,
// secondary = PurpleGrey80, // secondary = PurpleGrey80,
tertiary = Pink40, tertiary = virdigris,
surfaceTint = Pink80,
// tertiary = Pink80 // tertiary = Pink80
) )
@@ -32,7 +31,6 @@ private val LightColorScheme =
primary = Purple40, primary = Purple40,
secondary = PurpleGrey40, secondary = PurpleGrey40,
tertiary = Pink40, tertiary = Pink40,
surfaceTint = Pink80,
/* Other default colors to override /* Other default colors to override
background = Color(0xFFFFFBFE), background = Color(0xFFFFFBFE),
surface = Color(0xFFFFFBFE), surface = Color(0xFFFFFBFE),
@@ -7,7 +7,7 @@ object Constants {
const val MANUAL_TUNNEL_CONFIG_ID = "0" const val MANUAL_TUNNEL_CONFIG_ID = "0"
const val BATTERY_SAVER_WATCHER_WAKE_LOCK_TIMEOUT = 10 * 60 * 1_000L // 10 minutes const val BATTERY_SAVER_WATCHER_WAKE_LOCK_TIMEOUT = 10 * 60 * 1_000L // 10 minutes
const val VPN_STATISTIC_CHECK_INTERVAL = 1_000L const val VPN_STATISTIC_CHECK_INTERVAL = 1_000L
const val WATCHER_COLLECTION_DELAY = 3_000L const val WATCHER_COLLECTION_DELAY = 1_000L
const val CONF_FILE_EXTENSION = ".conf" const val CONF_FILE_EXTENSION = ".conf"
const val ZIP_FILE_EXTENSION = ".zip" const val ZIP_FILE_EXTENSION = ".zip"
const val URI_CONTENT_SCHEME = "content" const val URI_CONTENT_SCHEME = "content"
@@ -24,8 +24,6 @@ object Constants {
const val SUBSCRIPTION_TIMEOUT = 5_000L const val SUBSCRIPTION_TIMEOUT = 5_000L
const val FOCUS_REQUEST_DELAY = 500L const val FOCUS_REQUEST_DELAY = 500L
const val TRANSITION_ANIMATION_TIME = 200
const val DEFAULT_PING_IP = "1.1.1.1" const val DEFAULT_PING_IP = "1.1.1.1"
const val PING_TIMEOUT = 5_000L const val PING_TIMEOUT = 5_000L
const val VPN_RESTART_DELAY = 1_000L const val VPN_RESTART_DELAY = 1_000L
@@ -6,8 +6,6 @@ import android.os.Build
import android.os.Environment import android.os.Environment
import android.provider.MediaStore import android.provider.MediaStore
import android.provider.MediaStore.MediaColumns import android.provider.MediaStore.MediaColumns
import com.zaneschepke.wireguardautotunnel.data.domain.TunnelConfig
import com.zaneschepke.wireguardautotunnel.util.extensions.TunnelConfigs
import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import timber.log.Timber import timber.log.Timber
@@ -41,26 +39,6 @@ class FileUtils(
} }
} }
fun createWgFiles(tunnels: TunnelConfigs): List<File> {
return tunnels.map { config ->
val file = File(context.cacheDir, "${config.name}-wg.conf")
file.outputStream().use {
it.write(config.wgQuick.toByteArray())
}
file
}
}
fun createAmFiles(tunnels: TunnelConfigs): List<File> {
return tunnels.filter { it.amQuick != TunnelConfig.AM_QUICK_DEFAULT }.map { config ->
val file = File(context.cacheDir, "${config.name}-am.conf")
file.outputStream().use {
it.write(config.amQuick.toByteArray())
}
file
}
}
suspend fun saveByteArrayToDownloads(content: ByteArray, fileName: String): Result<Unit> { suspend fun saveByteArrayToDownloads(content: ByteArray, fileName: String): Result<Unit> {
return withContext(ioDispatcher) { return withContext(ioDispatcher) {
try { try {
@@ -29,7 +29,7 @@ fun TunnelStatistics.PeerStats.handshakeStatus(): HandshakeStatus {
} }
fun Config.toWgQuickString(): String { fun Config.toWgQuickString(): String {
val amQuick = toAwgQuickString(true) val amQuick = toAwgQuickString()
val lines = amQuick.lines().toMutableList() val lines = amQuick.lines().toMutableList()
val linesIterator = lines.iterator() val linesIterator = lines.iterator()
while (linesIterator.hasNext()) { while (linesIterator.hasNext()) {
+2 -2
View File
@@ -1,7 +1,7 @@
object Constants { object Constants {
const val VERSION_NAME = "3.5.1" const val VERSION_NAME = "3.5.0"
const val JVM_TARGET = "17" const val JVM_TARGET = "17"
const val VERSION_CODE = 35100 const val VERSION_CODE = 35001
const val TARGET_SDK = 34 const val TARGET_SDK = 34
const val MIN_SDK = 26 const val MIN_SDK = 26
const val APP_ID = "com.zaneschepke.wireguardautotunnel" const val APP_ID = "com.zaneschepke.wireguardautotunnel"
@@ -1,5 +0,0 @@
What's new:
- Fixes for tunnels not launching from background
- Add support for restart services after update
- UI animation speed improvements
- Other optimizations
+3 -3
View File
@@ -1,7 +1,7 @@
[versions] [versions]
accompanist = "0.34.0" accompanist = "0.34.0"
activityCompose = "1.9.1" activityCompose = "1.9.1"
amneziawgAndroid = "1.2.2" amneziawgAndroid = "1.2.1"
androidx-junit = "1.2.1" androidx-junit = "1.2.1"
appcompat = "1.7.0" appcompat = "1.7.0"
biometricKtx = "1.2.0-alpha05" biometricKtx = "1.2.0-alpha05"
@@ -16,13 +16,13 @@ junit = "4.13.2"
kotlinx-serialization-json = "1.7.1" kotlinx-serialization-json = "1.7.1"
lifecycle-runtime-compose = "2.8.4" lifecycle-runtime-compose = "2.8.4"
material3 = "1.2.1" material3 = "1.2.1"
multifabVersion = "1.1.1" multifabVersion = "1.1.0"
navigationCompose = "2.7.7" navigationCompose = "2.7.7"
pinLockCompose = "1.0.3" pinLockCompose = "1.0.3"
roomVersion = "2.6.1" roomVersion = "2.6.1"
timber = "5.0.1" timber = "5.0.1"
tunnel = "1.2.1" tunnel = "1.2.1"
androidGradlePlugin = "8.6.0-rc01" androidGradlePlugin = "8.7.0-alpha06"
kotlin = "2.0.10" kotlin = "2.0.10"
ksp = "2.0.10-1.0.24" ksp = "2.0.10-1.0.24"
composeBom = "2024.06.00" composeBom = "2024.06.00"
@@ -5,7 +5,7 @@ import kotlinx.coroutines.flow.Flow
import java.io.File import java.io.File
interface LocalLogCollector { interface LocalLogCollector {
suspend fun start(onLogMessage: ((message: LogMessage) -> Unit)? = null) fun start(onLogMessage: ((message: LogMessage) -> Unit)? = null)
fun stop() fun stop()
@@ -69,7 +69,7 @@ object LogcatUtil {
internal object Logcat : LocalLogCollector { internal object Logcat : LocalLogCollector {
private var logcatReader: LogcatReader? = null private var logcatReader: LogcatReader? = null
override suspend fun start(onLogMessage: ((message: LogMessage) -> Unit)?) { override fun start(onLogMessage: ((message: LogMessage) -> Unit)?) {
logcatReader ?: run { logcatReader ?: run {
logcatReader = logcatReader =
LogcatReader( LogcatReader(
@@ -78,7 +78,9 @@ object LogcatUtil {
onLogMessage, onLogMessage,
) )
} }
logcatReader?.run() logcatReader?.let { logReader ->
if (!logReader.isAlive) logReader.start()
}
} }
override fun stop() { override fun stop() {
@@ -140,7 +142,7 @@ object LogcatUtil {
pID: String, pID: String,
private val logcatPath: String, private val logcatPath: String,
private val callback: ((input: LogMessage) -> Unit)?, private val callback: ((input: LogMessage) -> Unit)?,
) { ) : Thread() {
private var logcatProc: Process? = null private var logcatProc: Process? = null
private var reader: BufferedReader? = null private var reader: BufferedReader? = null
private var mRunning = true private var mRunning = true
@@ -175,7 +177,7 @@ object LogcatUtil {
}.let { last -> findIpv4AddressRegex.replace(last, "<ipv4-address>") } }.let { last -> findIpv4AddressRegex.replace(last, "<ipv4-address>") }
} }
fun run() { override fun run() {
if (outputStream == null) return if (outputStream == null) return
try { try {
clear() clear()