mirror of
https://github.com/wgtunnel/android.git
synced 2026-07-03 14:07:49 +02:00
fix: android 17 local devices/network permission requirement
closes #1299
This commit is contained in:
@@ -1,12 +1,14 @@
|
||||
package com.zaneschepke.wireguardautotunnel
|
||||
|
||||
import ProxySettingsScreen
|
||||
import android.Manifest
|
||||
import android.content.Intent
|
||||
import android.graphics.Color
|
||||
import android.net.Uri
|
||||
import android.net.VpnService
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.provider.Settings
|
||||
import android.view.WindowManager
|
||||
import androidx.activity.SystemBarStyle
|
||||
import androidx.activity.compose.rememberLauncherForActivityResult
|
||||
@@ -50,6 +52,7 @@ import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
@@ -61,6 +64,7 @@ import androidx.compose.ui.text.intl.Locale
|
||||
import androidx.compose.ui.unit.IntOffset
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.zIndex
|
||||
import androidx.core.app.ActivityCompat
|
||||
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.lifecycle.viewmodel.navigation3.rememberViewModelStoreNavEntryDecorator
|
||||
@@ -83,6 +87,7 @@ import com.zaneschepke.wireguardautotunnel.ui.LocalIsAndroidTV
|
||||
import com.zaneschepke.wireguardautotunnel.ui.LocalNavController
|
||||
import com.zaneschepke.wireguardautotunnel.ui.common.banner.AppAlertBanner
|
||||
import com.zaneschepke.wireguardautotunnel.ui.common.dialog.InfoDialog
|
||||
import com.zaneschepke.wireguardautotunnel.ui.common.dialog.LocalNetworkPermissionDialog
|
||||
import com.zaneschepke.wireguardautotunnel.ui.common.dialog.VpnDeniedDialog
|
||||
import com.zaneschepke.wireguardautotunnel.ui.navigation.Route
|
||||
import com.zaneschepke.wireguardautotunnel.ui.navigation.SecureRoute
|
||||
@@ -132,6 +137,7 @@ import com.zaneschepke.wireguardautotunnel.util.extensions.installApk
|
||||
import com.zaneschepke.wireguardautotunnel.util.extensions.isRunningOnTv
|
||||
import com.zaneschepke.wireguardautotunnel.util.extensions.openWebUrl
|
||||
import com.zaneschepke.wireguardautotunnel.util.extensions.restartApp
|
||||
import com.zaneschepke.wireguardautotunnel.util.permission.LocalNetworkPermissionHelper
|
||||
import com.zaneschepke.wireguardautotunnel.viewmodel.ConfigEditViewModel
|
||||
import com.zaneschepke.wireguardautotunnel.viewmodel.SharedAppViewModel
|
||||
import com.zaneschepke.wireguardautotunnel.viewmodel.SplitTunnelViewModel
|
||||
@@ -202,6 +208,68 @@ class MainActivity : AppCompatActivity() {
|
||||
var requestingTunnelMode by remember {
|
||||
mutableStateOf<Pair<TunnelMode?, TunnelConfig?>>(Pair(null, null))
|
||||
}
|
||||
var showLocalNetworkRationale by remember { mutableStateOf(false) }
|
||||
var hasPromptedLocalNetwork by rememberSaveable { mutableStateOf(false) }
|
||||
|
||||
val localNetworkPermissionLauncher =
|
||||
rememberLauncherForActivityResult(
|
||||
contract = ActivityResultContracts.RequestPermission()
|
||||
) { isGranted ->
|
||||
if (!isGranted) {
|
||||
val canAskAgain =
|
||||
ActivityCompat.shouldShowRequestPermissionRationale(
|
||||
this,
|
||||
Manifest.permission.ACCESS_LOCAL_NETWORK,
|
||||
)
|
||||
|
||||
if (!canAskAgain) {
|
||||
val intent =
|
||||
Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply {
|
||||
data = Uri.fromParts("package", packageName, null)
|
||||
}
|
||||
startActivity(intent)
|
||||
} else {
|
||||
toaster.show(
|
||||
message =
|
||||
context.getString(R.string.local_network_permission_denied),
|
||||
type = ToastType.Warning,
|
||||
duration = 6000.milliseconds,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LaunchedEffect(uiState.isAppLoaded) {
|
||||
if (
|
||||
uiState.isAppLoaded &&
|
||||
!hasPromptedLocalNetwork &&
|
||||
LocalNetworkPermissionHelper.shouldRequestPermission() &&
|
||||
!LocalNetworkPermissionHelper.isPermissionGranted(context)
|
||||
) {
|
||||
hasPromptedLocalNetwork = true
|
||||
showLocalNetworkRationale = true
|
||||
}
|
||||
}
|
||||
|
||||
if (showLocalNetworkRationale) {
|
||||
LocalNetworkPermissionDialog(
|
||||
onDismiss = {
|
||||
showLocalNetworkRationale = false
|
||||
toaster.show(
|
||||
message = context.getString(R.string.local_network_permission_denied),
|
||||
type = ToastType.Warning,
|
||||
duration = 6000.milliseconds,
|
||||
)
|
||||
},
|
||||
onContinue = {
|
||||
showLocalNetworkRationale = false
|
||||
|
||||
localNetworkPermissionLauncher.launch(
|
||||
Manifest.permission.ACCESS_LOCAL_NETWORK
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
val startingStack = buildList {
|
||||
add(Route.Tunnels)
|
||||
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
package com.zaneschepke.wireguardautotunnel.ui.common.dialog
|
||||
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.zaneschepke.wireguardautotunnel.R
|
||||
|
||||
@Composable
|
||||
fun LocalNetworkPermissionDialog(onDismiss: () -> Unit, onContinue: () -> Unit) {
|
||||
AlertDialog(
|
||||
onDismissRequest = onDismiss,
|
||||
title = { Text(text = stringResource(R.string.local_network_permission_title)) },
|
||||
text = {
|
||||
Column {
|
||||
Text(
|
||||
text = stringResource(R.string.local_network_permission_intro),
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
|
||||
Text(
|
||||
text = stringResource(R.string.local_network_permission_issues_intro),
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
fontWeight = FontWeight.Medium,
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(4.dp))
|
||||
|
||||
Text(
|
||||
text = stringResource(R.string.local_network_permission_feature_tunnels),
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
)
|
||||
Text(
|
||||
text = stringResource(R.string.local_network_permission_feature_autotunnel),
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
)
|
||||
Text(
|
||||
text = stringResource(R.string.local_network_permission_feature_proxy),
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
|
||||
Text(
|
||||
text = stringResource(R.string.local_network_permission_nearby_devices),
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
|
||||
Text(
|
||||
text = stringResource(R.string.local_network_permission_recommendation),
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
fontWeight = FontWeight.Medium,
|
||||
)
|
||||
}
|
||||
},
|
||||
confirmButton = {
|
||||
TextButton(onClick = onContinue) { Text(text = stringResource(R.string._continue)) }
|
||||
},
|
||||
dismissButton = {
|
||||
TextButton(onClick = onDismiss) { Text(text = stringResource(R.string.not_now)) }
|
||||
},
|
||||
)
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
package com.zaneschepke.wireguardautotunnel.util.permission
|
||||
|
||||
import android.Manifest
|
||||
import android.content.Context
|
||||
import android.content.pm.PackageManager
|
||||
import android.os.Build
|
||||
import androidx.core.content.ContextCompat
|
||||
|
||||
object LocalNetworkPermissionHelper {
|
||||
|
||||
fun shouldRequestPermission(): Boolean {
|
||||
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.CINNAMON_BUN
|
||||
}
|
||||
|
||||
fun isPermissionGranted(context: Context): Boolean {
|
||||
return if (shouldRequestPermission()) {
|
||||
ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_LOCAL_NETWORK) ==
|
||||
PackageManager.PERMISSION_GRANTED
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -537,4 +537,21 @@
|
||||
<string name="restore_failed_wrong_password">Restore failed. Wrong password</string>
|
||||
<string name="restore_failed_invalid_file">Restore failed. Select a valid backup file (.sqlite3 or .sqlite3.aes)</string>
|
||||
<string name="error_invalid_config_url">This link returned an invalid config file. Make sure you are using a direct download link</string>
|
||||
|
||||
<string name="local_network_permission_title">Local Network Access Needed</string>
|
||||
|
||||
<string name="local_network_permission_intro">WG Tunnel needs access to your local network for several features to work properly.</string>
|
||||
|
||||
<string name="local_network_permission_issues_intro">Without this permission, you may experience issues with:</string>
|
||||
|
||||
<string name="local_network_permission_feature_tunnels">- Connecting to certain tunnels</string>
|
||||
<string name="local_network_permission_feature_autotunnel">- Auto-tunneling and split tunneling features</string>
|
||||
<string name="local_network_permission_feature_proxy">- Local proxy and bypass functionality</string>
|
||||
|
||||
<string name="local_network_permission_recommendation">Granting this permission is strongly recommended.</string>
|
||||
<string name="local_network_permission_nearby_devices">Note: Android labels this permission as “nearby devices”.</string>
|
||||
|
||||
<string name="not_now">Not now</string>
|
||||
|
||||
<string name="local_network_permission_denied">Local network access denied. Some features may not work properly</string>
|
||||
</resources>
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import com.ncorti.ktfmt.gradle.tasks.KtfmtFormatTask
|
||||
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
||||
|
||||
plugins {
|
||||
alias(libs.plugins.android.application) apply false
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
|
||||
<uses-permission android:name="android.permission.ACCESS_LOCAL_NETWORK" />
|
||||
<!--foreground service special use for non VPN service tunnels, android 14-->
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_SPECIAL_USE" />
|
||||
<!--foreground service special use for VPN service tunnels, android 14-->
|
||||
|
||||
Reference in New Issue
Block a user