mirror of
https://github.com/wgtunnel/android.git
synced 2026-07-03 14:07:49 +02:00
Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e81066f508 | |||
| 64bb9f3b82 | |||
| c1b560e822 | |||
| 14fe5821cc | |||
| 9d9b7bebca | |||
| 12d1ccc084 |
@@ -13,6 +13,7 @@ WG Tunnel
|
|||||||
|
|
||||||
|
|
||||||
[](https://play.google.com/store/apps/details?id=com.zaneschepke.wireguardautotunnel)
|
[](https://play.google.com/store/apps/details?id=com.zaneschepke.wireguardautotunnel)
|
||||||
|
[](https://www.amazon.com/gp/product/B0CFGGL7WK)
|
||||||
|
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
@@ -50,8 +51,10 @@ The inspiration for this app came from the inconvenience of constantly having to
|
|||||||
|
|
||||||
* Add tunnels via .conf file
|
* Add tunnels via .conf file
|
||||||
* Auto connect to VPN based on Wi-Fi SSID
|
* Auto connect to VPN based on Wi-Fi SSID
|
||||||
* Split tunneling by application
|
* Split tunneling by application with search
|
||||||
* Always-on VPN for Android support
|
* Always-on VPN for Android support
|
||||||
|
* Quick tile support for vpn toggling
|
||||||
|
* Dynamic shortcuts support for automation integration
|
||||||
* Configurable Trusted Network list
|
* Configurable Trusted Network list
|
||||||
* Optional auto connect on mobile data
|
* Optional auto connect on mobile data
|
||||||
* Automatic service restart after reboot
|
* Automatic service restart after reboot
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ android {
|
|||||||
|
|
||||||
val versionMajor = 2
|
val versionMajor = 2
|
||||||
val versionMinor = 4
|
val versionMinor = 4
|
||||||
val versionPatch = 1
|
val versionPatch = 4
|
||||||
val versionBuild = 0
|
val versionBuild = 0
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import android.app.Application
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
import com.google.firebase.crashlytics.FirebaseCrashlytics
|
import com.google.firebase.crashlytics.FirebaseCrashlytics
|
||||||
|
import com.google.mlkit.common.MlKit
|
||||||
import com.zaneschepke.wireguardautotunnel.repository.Repository
|
import com.zaneschepke.wireguardautotunnel.repository.Repository
|
||||||
import com.zaneschepke.wireguardautotunnel.service.tunnel.model.Settings
|
import com.zaneschepke.wireguardautotunnel.service.tunnel.model.Settings
|
||||||
import dagger.hilt.android.HiltAndroidApp
|
import dagger.hilt.android.HiltAndroidApp
|
||||||
@@ -22,6 +23,11 @@ class WireGuardAutoTunnel : Application() {
|
|||||||
FirebaseCrashlytics.getInstance().setCrashlyticsCollectionEnabled(false);
|
FirebaseCrashlytics.getInstance().setCrashlyticsCollectionEnabled(false);
|
||||||
Timber.plant(Timber.DebugTree())
|
Timber.plant(Timber.DebugTree())
|
||||||
}
|
}
|
||||||
|
try {
|
||||||
|
MlKit.initialize(this)
|
||||||
|
} catch (e : Exception) {
|
||||||
|
Timber.e(e.message)
|
||||||
|
}
|
||||||
settingsRepo.init()
|
settingsRepo.init()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,5 +2,6 @@ package com.zaneschepke.wireguardautotunnel.service.foreground
|
|||||||
|
|
||||||
enum class Action {
|
enum class Action {
|
||||||
START,
|
START,
|
||||||
|
START_FOREGROUND,
|
||||||
STOP
|
STOP
|
||||||
}
|
}
|
||||||
+1
-1
@@ -22,7 +22,7 @@ open class ForegroundService : Service() {
|
|||||||
val action = intent.action
|
val action = intent.action
|
||||||
Timber.d("using an intent with action $action")
|
Timber.d("using an intent with action $action")
|
||||||
when (action) {
|
when (action) {
|
||||||
Action.START.name -> startService(intent.extras)
|
Action.START.name, Action.START_FOREGROUND.name -> startService(intent.extras)
|
||||||
Action.STOP.name -> stopService(intent.extras)
|
Action.STOP.name -> stopService(intent.extras)
|
||||||
"android.net.VpnService" -> {
|
"android.net.VpnService" -> {
|
||||||
Timber.d("Always-on VPN starting service")
|
Timber.d("Always-on VPN starting service")
|
||||||
|
|||||||
+30
-2
@@ -1,7 +1,6 @@
|
|||||||
package com.zaneschepke.wireguardautotunnel.service.foreground
|
package com.zaneschepke.wireguardautotunnel.service.foreground
|
||||||
|
|
||||||
import android.app.ActivityManager
|
import android.app.ActivityManager
|
||||||
import android.app.Application
|
|
||||||
import android.app.Service
|
import android.app.Service
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Context.ACTIVITY_SERVICE
|
import android.content.Context.ACTIVITY_SERVICE
|
||||||
@@ -35,7 +34,12 @@ object ServiceManager {
|
|||||||
intent.component?.javaClass
|
intent.component?.javaClass
|
||||||
try {
|
try {
|
||||||
when(action) {
|
when(action) {
|
||||||
Action.START -> context.startForegroundService(intent)
|
Action.START_FOREGROUND -> {
|
||||||
|
context.startForegroundService(intent)
|
||||||
|
}
|
||||||
|
Action.START -> {
|
||||||
|
context.startService(intent)
|
||||||
|
}
|
||||||
Action.STOP -> context.startService(intent)
|
Action.STOP -> context.startService(intent)
|
||||||
}
|
}
|
||||||
} catch (e : Exception) {
|
} catch (e : Exception) {
|
||||||
@@ -58,6 +62,22 @@ object ServiceManager {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun startVpnServiceForeground(context : Context, tunnelConfig : String) {
|
||||||
|
actionOnService(
|
||||||
|
Action.START_FOREGROUND,
|
||||||
|
context,
|
||||||
|
WireGuardTunnelService::class.java,
|
||||||
|
mapOf(context.getString(R.string.tunnel_extras_key) to tunnelConfig))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun startWatcherServiceForeground(context : Context, tunnelConfig : String) {
|
||||||
|
actionOnService(
|
||||||
|
Action.START, context,
|
||||||
|
WireGuardConnectivityWatcherService::class.java, mapOf(context.
|
||||||
|
getString(R.string.tunnel_extras_key) to
|
||||||
|
tunnelConfig))
|
||||||
|
}
|
||||||
|
|
||||||
fun startWatcherService(context : Context, tunnelConfig : String) {
|
fun startWatcherService(context : Context, tunnelConfig : String) {
|
||||||
actionOnService(
|
actionOnService(
|
||||||
Action.START, context,
|
Action.START, context,
|
||||||
@@ -79,4 +99,12 @@ object ServiceManager {
|
|||||||
ServiceState.STOPPED -> startWatcherService(context, tunnelConfig)
|
ServiceState.STOPPED -> startWatcherService(context, tunnelConfig)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun toggleWatcherServiceForeground(context: Context, tunnelConfig : String) {
|
||||||
|
when(getServiceState( context,
|
||||||
|
WireGuardConnectivityWatcherService::class.java,)) {
|
||||||
|
ServiceState.STARTED -> stopWatcherService(context)
|
||||||
|
ServiceState.STOPPED -> startWatcherServiceForeground(context, tunnelConfig)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+9
-2
@@ -59,8 +59,16 @@ class WireGuardConnectivityWatcherService : ForegroundService() {
|
|||||||
private val tag = this.javaClass.name;
|
private val tag = this.javaClass.name;
|
||||||
|
|
||||||
|
|
||||||
|
override fun onCreate() {
|
||||||
|
super.onCreate()
|
||||||
|
CoroutineScope(Dispatchers.Main).launch {
|
||||||
|
launchWatcherNotification()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun startService(extras: Bundle?) {
|
override fun startService(extras: Bundle?) {
|
||||||
super.startService(extras)
|
super.startService(extras)
|
||||||
|
launchWatcherNotification()
|
||||||
val tunnelId = extras?.getString(getString(R.string.tunnel_extras_key))
|
val tunnelId = extras?.getString(getString(R.string.tunnel_extras_key))
|
||||||
if (tunnelId != null) {
|
if (tunnelId != null) {
|
||||||
this.tunnelConfig = tunnelId
|
this.tunnelConfig = tunnelId
|
||||||
@@ -68,7 +76,6 @@ class WireGuardConnectivityWatcherService : ForegroundService() {
|
|||||||
// we need this lock so our service gets not affected by Doze Mode
|
// we need this lock so our service gets not affected by Doze Mode
|
||||||
initWakeLock()
|
initWakeLock()
|
||||||
cancelWatcherJob()
|
cancelWatcherJob()
|
||||||
launchWatcherNotification()
|
|
||||||
if(this::tunnelConfig.isInitialized) {
|
if(this::tunnelConfig.isInitialized) {
|
||||||
startWatcherJob()
|
startWatcherJob()
|
||||||
} else {
|
} else {
|
||||||
@@ -181,7 +188,7 @@ class WireGuardConnectivityWatcherService : ForegroundService() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun manageVpn() {
|
private suspend fun manageVpn() {
|
||||||
while(watcherJob.isActive) {
|
while(true) {
|
||||||
if(setting.isTunnelOnMobileDataEnabled &&
|
if(setting.isTunnelOnMobileDataEnabled &&
|
||||||
!isWifiConnected &&
|
!isWifiConnected &&
|
||||||
isMobileDataConnected
|
isMobileDataConnected
|
||||||
|
|||||||
+21
-1
@@ -37,8 +37,16 @@ class WireGuardTunnelService : ForegroundService() {
|
|||||||
|
|
||||||
private var tunnelName : String = ""
|
private var tunnelName : String = ""
|
||||||
|
|
||||||
|
override fun onCreate() {
|
||||||
|
super.onCreate()
|
||||||
|
CoroutineScope(Dispatchers.Main).launch {
|
||||||
|
launchVpnStartingNotification()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun startService(extras : Bundle?) {
|
override fun startService(extras : Bundle?) {
|
||||||
super.startService(extras)
|
super.startService(extras)
|
||||||
|
launchVpnStartingNotification()
|
||||||
val tunnelConfigString = extras?.getString(getString(R.string.tunnel_extras_key))
|
val tunnelConfigString = extras?.getString(getString(R.string.tunnel_extras_key))
|
||||||
cancelJob()
|
cancelJob()
|
||||||
job = CoroutineScope(Dispatchers.IO).launch {
|
job = CoroutineScope(Dispatchers.IO).launch {
|
||||||
@@ -98,7 +106,7 @@ class WireGuardTunnelService : ForegroundService() {
|
|||||||
|
|
||||||
override fun stopService(extras : Bundle?) {
|
override fun stopService(extras : Bundle?) {
|
||||||
super.stopService(extras)
|
super.stopService(extras)
|
||||||
CoroutineScope(Dispatchers.IO).launch() {
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
vpnService.stopTunnel()
|
vpnService.stopTunnel()
|
||||||
}
|
}
|
||||||
cancelJob()
|
cancelJob()
|
||||||
@@ -117,6 +125,18 @@ class WireGuardTunnelService : ForegroundService() {
|
|||||||
super.startForeground(foregroundId, notification)
|
super.startForeground(foregroundId, notification)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun launchVpnStartingNotification() {
|
||||||
|
val notification = notificationService.createNotification(
|
||||||
|
channelId = getString(R.string.vpn_channel_id),
|
||||||
|
channelName = getString(R.string.vpn_channel_name),
|
||||||
|
title = getString(R.string.vpn_starting),
|
||||||
|
onGoing = false,
|
||||||
|
showTimestamp = true,
|
||||||
|
description = getString(R.string.attempt_connection)
|
||||||
|
)
|
||||||
|
super.startForeground(foregroundId, notification)
|
||||||
|
}
|
||||||
|
|
||||||
private fun launchVpnConnectionFailedNotification(message : String) {
|
private fun launchVpnConnectionFailedNotification(message : String) {
|
||||||
val notification = notificationService.createNotification(
|
val notification = notificationService.createNotification(
|
||||||
channelId = getString(R.string.vpn_channel_id),
|
channelId = getString(R.string.vpn_channel_id),
|
||||||
|
|||||||
+2
-2
@@ -66,7 +66,7 @@ class TunnelControlTile : TileService() {
|
|||||||
if(vpnService.getState() == Tunnel.State.UP) {
|
if(vpnService.getState() == Tunnel.State.UP) {
|
||||||
ServiceManager.stopVpnService(this@TunnelControlTile)
|
ServiceManager.stopVpnService(this@TunnelControlTile)
|
||||||
} else {
|
} else {
|
||||||
ServiceManager.startVpnService(this@TunnelControlTile, tunnel.toString())
|
ServiceManager.startVpnServiceForeground(this@TunnelControlTile, tunnel.toString())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e : Exception) {
|
} catch (e : Exception) {
|
||||||
@@ -100,7 +100,7 @@ class TunnelControlTile : TileService() {
|
|||||||
if (!settings.isNullOrEmpty()) {
|
if (!settings.isNullOrEmpty()) {
|
||||||
val setting = settings.first()
|
val setting = settings.first()
|
||||||
if(setting.isAutoTunnelEnabled) {
|
if(setting.isAutoTunnelEnabled) {
|
||||||
ServiceManager.toggleWatcherService(this@TunnelControlTile, tunnelConfig)
|
ServiceManager.toggleWatcherServiceForeground(this@TunnelControlTile, tunnelConfig)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+12
-8
@@ -1,6 +1,7 @@
|
|||||||
package com.zaneschepke.wireguardautotunnel.ui.screens.main
|
package com.zaneschepke.wireguardautotunnel.ui.screens.main
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
|
import android.content.Intent
|
||||||
import androidx.activity.compose.rememberLauncherForActivityResult
|
import androidx.activity.compose.rememberLauncherForActivityResult
|
||||||
import androidx.activity.result.contract.ActivityResultContracts
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
import androidx.compose.animation.AnimatedVisibility
|
import androidx.compose.animation.AnimatedVisibility
|
||||||
@@ -17,7 +18,6 @@ import androidx.compose.foundation.layout.fillMaxSize
|
|||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.foundation.lazy.items
|
|
||||||
import androidx.compose.foundation.lazy.itemsIndexed
|
import androidx.compose.foundation.lazy.itemsIndexed
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
@@ -103,6 +103,7 @@ fun MainScreen(
|
|||||||
val state by viewModel.state.collectAsStateWithLifecycle(Tunnel.State.DOWN)
|
val state by viewModel.state.collectAsStateWithLifecycle(Tunnel.State.DOWN)
|
||||||
val tunnelName by viewModel.tunnelName.collectAsStateWithLifecycle("")
|
val tunnelName by viewModel.tunnelName.collectAsStateWithLifecycle("")
|
||||||
|
|
||||||
|
|
||||||
// Nested scroll for control FAB
|
// Nested scroll for control FAB
|
||||||
val nestedScrollConnection = remember {
|
val nestedScrollConnection = remember {
|
||||||
object : NestedScrollConnection {
|
object : NestedScrollConnection {
|
||||||
@@ -135,11 +136,9 @@ fun MainScreen(
|
|||||||
}
|
}
|
||||||
|
|
||||||
val pickFileLauncher = rememberLauncherForActivityResult(
|
val pickFileLauncher = rememberLauncherForActivityResult(
|
||||||
ActivityResultContracts.GetContent()
|
ActivityResultContracts.StartActivityForResult()
|
||||||
) { file ->
|
) { result ->
|
||||||
if (file != null) {
|
result.data?.data?.let { viewModel.onTunnelFileSelected(it) }
|
||||||
viewModel.onTunnelFileSelected(file)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Scaffold(
|
Scaffold(
|
||||||
@@ -196,7 +195,11 @@ fun MainScreen(
|
|||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.clickable {
|
.clickable {
|
||||||
showBottomSheet = false
|
showBottomSheet = false
|
||||||
pickFileLauncher.launch("*/*")
|
val fileSelectionIntent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
|
||||||
|
addCategory(Intent.CATEGORY_OPENABLE)
|
||||||
|
type = "*/*"
|
||||||
|
}
|
||||||
|
pickFileLauncher.launch(fileSelectionIntent)
|
||||||
}
|
}
|
||||||
.padding(10.dp)
|
.padding(10.dp)
|
||||||
) {
|
) {
|
||||||
@@ -242,7 +245,8 @@ fun MainScreen(
|
|||||||
) {
|
) {
|
||||||
|
|
||||||
LazyColumn(
|
LazyColumn(
|
||||||
modifier = Modifier.fillMaxSize()
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
.nestedScroll(nestedScrollConnection),
|
.nestedScroll(nestedScrollConnection),
|
||||||
) {
|
) {
|
||||||
itemsIndexed(tunnels.toList()) { index, tunnel ->
|
itemsIndexed(tunnels.toList()) { index, tunnel ->
|
||||||
|
|||||||
@@ -89,4 +89,6 @@
|
|||||||
<string name="hint_search_packages">Search packages</string>
|
<string name="hint_search_packages">Search packages</string>
|
||||||
<string name="clear_icon">Clear Icon</string>
|
<string name="clear_icon">Clear Icon</string>
|
||||||
<string name="search_icon">Search Icon</string>
|
<string name="search_icon">Search Icon</string>
|
||||||
|
<string name="attempt_connection">Attempting connection..</string>
|
||||||
|
<string name="vpn_starting">VPN Starting</string>
|
||||||
</resources>
|
</resources>
|
||||||
+1
-1
@@ -13,7 +13,7 @@ buildscript {
|
|||||||
}
|
}
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id("com.android.application") version "8.2.0-beta01" apply false
|
id("com.android.application") version "8.2.0-beta03" apply false
|
||||||
id("org.jetbrains.kotlin.android") version "1.8.22" apply false
|
id("org.jetbrains.kotlin.android") version "1.8.22" apply false
|
||||||
id("com.google.dagger.hilt.android") version "2.44" apply false
|
id("com.google.dagger.hilt.android") version "2.44" apply false
|
||||||
kotlin("plugin.serialization") version "1.8.22" apply false
|
kotlin("plugin.serialization") version "1.8.22" apply false
|
||||||
|
|||||||
Reference in New Issue
Block a user