feat: support Android 9
Added support for Android 9 by updating permission checks and wifi SSID logic. Fix bug where setting screen was cut off on AndroidTV by updating padding values. Bump wireguard-android library version. Closes #13, Closes #16
This commit is contained in:
parent
689c97f452
commit
2abf681d17
|
@ -17,12 +17,12 @@ android {
|
||||||
|
|
||||||
val versionMajor = 2
|
val versionMajor = 2
|
||||||
val versionMinor = 3
|
val versionMinor = 3
|
||||||
val versionPatch = 2
|
val versionPatch = 3
|
||||||
val versionBuild = 0
|
val versionBuild = 0
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId = "com.zaneschepke.wireguardautotunnel"
|
applicationId = "com.zaneschepke.wireguardautotunnel"
|
||||||
minSdk = 29
|
minSdk = 28
|
||||||
targetSdk = 34
|
targetSdk = 34
|
||||||
versionCode = versionMajor * 10000 + versionMinor * 1000 + versionPatch * 100 + versionBuild
|
versionCode = versionMajor * 10000 + versionMinor * 1000 + versionPatch * 100 + versionBuild
|
||||||
versionName = "${versionMajor}.${versionMinor}.${versionPatch}"
|
versionName = "${versionMajor}.${versionMinor}.${versionPatch}"
|
||||||
|
@ -83,7 +83,7 @@ dependencies {
|
||||||
debugImplementation("androidx.compose.ui:ui-test-manifest")
|
debugImplementation("androidx.compose.ui:ui-test-manifest")
|
||||||
|
|
||||||
//wireguard tunnel
|
//wireguard tunnel
|
||||||
implementation("com.wireguard.android:tunnel:1.0.20230427")
|
implementation("com.wireguard.android:tunnel:1.0.20230706")
|
||||||
|
|
||||||
//logging
|
//logging
|
||||||
implementation("com.jakewharton.timber:timber:5.0.1")
|
implementation("com.jakewharton.timber:timber:5.0.1")
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package com.zaneschepke.wireguardautotunnel
|
package com.zaneschepke.wireguardautotunnel
|
||||||
|
|
||||||
import android.app.Application
|
import android.app.Application
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.pm.PackageManager
|
||||||
import com.google.firebase.crashlytics.FirebaseCrashlytics
|
import com.google.firebase.crashlytics.FirebaseCrashlytics
|
||||||
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
|
||||||
|
@ -22,4 +24,10 @@ class WireGuardAutoTunnel : Application() {
|
||||||
}
|
}
|
||||||
settingsRepo.init()
|
settingsRepo.init()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun isRunningOnAndroidTv(context : Context) : Boolean {
|
||||||
|
return context.packageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -45,6 +45,7 @@ abstract class BaseNetworkService<T : BaseNetworkService<T>>(val context: Contex
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
object : ConnectivityManager.NetworkCallback() {
|
object : ConnectivityManager.NetworkCallback() {
|
||||||
|
|
||||||
|
@ -78,7 +79,7 @@ abstract class BaseNetworkService<T : BaseNetworkService<T>>(val context: Contex
|
||||||
|
|
||||||
override fun getNetworkName(networkCapabilities: NetworkCapabilities): String? {
|
override fun getNetworkName(networkCapabilities: NetworkCapabilities): String? {
|
||||||
var ssid: String? = getWifiNameFromCapabilities(networkCapabilities)
|
var ssid: String? = getWifiNameFromCapabilities(networkCapabilities)
|
||||||
if((Build.VERSION.SDK_INT == Build.VERSION_CODES.Q) || (Build.VERSION.SDK_INT == Build.VERSION_CODES.R)) {
|
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.R) {
|
||||||
val info = wifiManager.connectionInfo
|
val info = wifiManager.connectionInfo
|
||||||
if (info.supplicantState === SupplicantState.COMPLETED) {
|
if (info.supplicantState === SupplicantState.COMPLETED) {
|
||||||
ssid = info.ssid
|
ssid = info.ssid
|
||||||
|
@ -90,15 +91,16 @@ abstract class BaseNetworkService<T : BaseNetworkService<T>>(val context: Contex
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private fun getWifiNameFromCapabilities(networkCapabilities: NetworkCapabilities): String? {
|
private fun getWifiNameFromCapabilities(networkCapabilities: NetworkCapabilities): String? {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||||
val info: WifiInfo
|
val info: WifiInfo
|
||||||
if (networkCapabilities.transportInfo is WifiInfo) {
|
if (networkCapabilities.transportInfo is WifiInfo) {
|
||||||
info = networkCapabilities.transportInfo as WifiInfo
|
info = networkCapabilities.transportInfo as WifiInfo
|
||||||
} else {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
return info.ssid
|
return info.ssid
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline fun <Result> Flow<NetworkStatus>.map(
|
inline fun <Result> Flow<NetworkStatus>.map(
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
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.pm.PackageManager
|
|
||||||
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
|
||||||
|
@ -52,7 +51,6 @@ import androidx.compose.runtime.rememberCoroutineScope
|
||||||
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.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.ExperimentalComposeUiApi
|
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.focus.FocusRequester
|
import androidx.compose.ui.focus.FocusRequester
|
||||||
import androidx.compose.ui.focus.focusRequester
|
import androidx.compose.ui.focus.focusRequester
|
||||||
|
@ -73,6 +71,7 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
import androidx.navigation.NavController
|
import androidx.navigation.NavController
|
||||||
import com.wireguard.android.backend.Tunnel
|
import com.wireguard.android.backend.Tunnel
|
||||||
import com.zaneschepke.wireguardautotunnel.R
|
import com.zaneschepke.wireguardautotunnel.R
|
||||||
|
import com.zaneschepke.wireguardautotunnel.WireGuardAutoTunnel
|
||||||
import com.zaneschepke.wireguardautotunnel.service.tunnel.HandshakeStatus
|
import com.zaneschepke.wireguardautotunnel.service.tunnel.HandshakeStatus
|
||||||
import com.zaneschepke.wireguardautotunnel.service.tunnel.model.TunnelConfig
|
import com.zaneschepke.wireguardautotunnel.service.tunnel.model.TunnelConfig
|
||||||
import com.zaneschepke.wireguardautotunnel.ui.Routes
|
import com.zaneschepke.wireguardautotunnel.ui.Routes
|
||||||
|
@ -246,12 +245,12 @@ fun MainScreen(
|
||||||
.nestedScroll(nestedScrollConnection),) {
|
.nestedScroll(nestedScrollConnection),) {
|
||||||
items(tunnels.toList()) { tunnel ->
|
items(tunnels.toList()) { tunnel ->
|
||||||
RowListItem(leadingIcon = Icons.Rounded.Circle,
|
RowListItem(leadingIcon = Icons.Rounded.Circle,
|
||||||
leadingIconColor = when (handshakeStatus) {
|
leadingIconColor = if (tunnelName == tunnel.name) when (handshakeStatus) {
|
||||||
HandshakeStatus.HEALTHY -> mint
|
HandshakeStatus.HEALTHY -> mint
|
||||||
HandshakeStatus.UNHEALTHY -> brickRed
|
HandshakeStatus.UNHEALTHY -> brickRed
|
||||||
HandshakeStatus.NOT_STARTED -> Color.Gray
|
HandshakeStatus.NOT_STARTED -> Color.Gray
|
||||||
HandshakeStatus.NEVER_CONNECTED -> brickRed
|
HandshakeStatus.NEVER_CONNECTED -> brickRed
|
||||||
},
|
} else Color.Gray,
|
||||||
text = tunnel.name,
|
text = tunnel.name,
|
||||||
onHold = {
|
onHold = {
|
||||||
if (state == Tunnel.State.UP && tunnel.name == tunnelName) {
|
if (state == Tunnel.State.UP && tunnel.name == tunnelName) {
|
||||||
|
@ -264,7 +263,7 @@ fun MainScreen(
|
||||||
selectedTunnel = tunnel;
|
selectedTunnel = tunnel;
|
||||||
},
|
},
|
||||||
onClick = {
|
onClick = {
|
||||||
if(!context.packageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK)){
|
if(!WireGuardAutoTunnel.isRunningOnAndroidTv(context)){
|
||||||
navController.navigate("${Routes.Detail.name}/${tunnel.id}")
|
navController.navigate("${Routes.Detail.name}/${tunnel.id}")
|
||||||
} else {
|
} else {
|
||||||
focusRequester.requestFocus()
|
focusRequester.requestFocus()
|
||||||
|
@ -288,7 +287,7 @@ fun MainScreen(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if(context.packageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK)){
|
if(WireGuardAutoTunnel.isRunningOnAndroidTv(context)){
|
||||||
Row() {
|
Row() {
|
||||||
IconButton(modifier = Modifier.focusRequester(focusRequester),onClick = {
|
IconButton(modifier = Modifier.focusRequester(focusRequester),onClick = {
|
||||||
navController.navigate("${Routes.Detail.name}/${tunnel.id}")
|
navController.navigate("${Routes.Detail.name}/${tunnel.id}")
|
||||||
|
|
|
@ -2,8 +2,8 @@ package com.zaneschepke.wireguardautotunnel.ui.screens.settings
|
||||||
|
|
||||||
import android.Manifest
|
import android.Manifest
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.pm.PackageManager
|
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
|
import android.os.Build
|
||||||
import android.provider.Settings
|
import android.provider.Settings
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||||
|
@ -13,6 +13,7 @@ import androidx.compose.foundation.layout.ExperimentalLayoutApi
|
||||||
import androidx.compose.foundation.layout.FlowRow
|
import androidx.compose.foundation.layout.FlowRow
|
||||||
import androidx.compose.foundation.layout.PaddingValues
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.fillMaxHeight
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
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
|
||||||
|
@ -67,6 +68,7 @@ import com.google.accompanist.permissions.ExperimentalPermissionsApi
|
||||||
import com.google.accompanist.permissions.isGranted
|
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.service.tunnel.model.TunnelConfig
|
import com.zaneschepke.wireguardautotunnel.service.tunnel.model.TunnelConfig
|
||||||
import com.zaneschepke.wireguardautotunnel.ui.Routes
|
import com.zaneschepke.wireguardautotunnel.ui.Routes
|
||||||
import com.zaneschepke.wireguardautotunnel.ui.common.ClickableIconButton
|
import com.zaneschepke.wireguardautotunnel.ui.common.ClickableIconButton
|
||||||
|
@ -134,7 +136,7 @@ fun SettingsScreen(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!backgroundLocationState.status.isGranted) {
|
if(!backgroundLocationState.status.isGranted && Build.VERSION.SDK_INT > Build.VERSION_CODES.P) {
|
||||||
Column(horizontalAlignment = Alignment.CenterHorizontally,
|
Column(horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
verticalArrangement = Arrangement.Top,
|
verticalArrangement = Arrangement.Top,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
|
@ -147,7 +149,9 @@ fun SettingsScreen(
|
||||||
Text(stringResource(R.string.prominent_background_location_title), textAlign = TextAlign.Center, modifier = Modifier.padding(30.dp), fontSize = 20.sp)
|
Text(stringResource(R.string.prominent_background_location_title), textAlign = TextAlign.Center, modifier = Modifier.padding(30.dp), fontSize = 20.sp)
|
||||||
Text(stringResource(R.string.prominent_background_location_message), textAlign = TextAlign.Center, modifier = Modifier.padding(30.dp), fontSize = 15.sp)
|
Text(stringResource(R.string.prominent_background_location_message), textAlign = TextAlign.Center, modifier = Modifier.padding(30.dp), fontSize = 15.sp)
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier
|
modifier = if(WireGuardAutoTunnel.isRunningOnAndroidTv(context)) Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(10.dp) else Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(30.dp),
|
.padding(30.dp),
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
@ -209,7 +213,7 @@ fun SettingsScreen(
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if(!isLocationServicesEnabled) {
|
if(!isLocationServicesEnabled && Build.VERSION.SDK_INT > Build.VERSION_CODES.P) {
|
||||||
Column(
|
Column(
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
verticalArrangement = Arrangement.Center,
|
verticalArrangement = Arrangement.Center,
|
||||||
|
@ -237,11 +241,18 @@ fun SettingsScreen(
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
val screenPadding = if(WireGuardAutoTunnel.isRunningOnAndroidTv(context)) 5.dp else 15.dp
|
||||||
Column(
|
Column(
|
||||||
horizontalAlignment = Alignment.Start,
|
horizontalAlignment = Alignment.Start,
|
||||||
verticalArrangement = Arrangement.Top,
|
verticalArrangement = Arrangement.Top,
|
||||||
modifier = Modifier
|
modifier = if(WireGuardAutoTunnel.isRunningOnAndroidTv(context)) Modifier
|
||||||
|
.fillMaxHeight(.85f)
|
||||||
|
.fillMaxWidth()
|
||||||
|
.verticalScroll(scrollState)
|
||||||
|
.clickable(indication = null, interactionSource = interactionSource) {
|
||||||
|
focusManager.clearFocus()
|
||||||
|
}
|
||||||
|
.padding(padding) else Modifier
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
.verticalScroll(scrollState)
|
.verticalScroll(scrollState)
|
||||||
.clickable(indication = null, interactionSource = interactionSource) {
|
.clickable(indication = null, interactionSource = interactionSource) {
|
||||||
|
@ -252,7 +263,7 @@ fun SettingsScreen(
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(14.dp),
|
.padding(screenPadding),
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
horizontalArrangement = Arrangement.SpaceBetween
|
horizontalArrangement = Arrangement.SpaceBetween
|
||||||
) {
|
) {
|
||||||
|
@ -271,7 +282,7 @@ fun SettingsScreen(
|
||||||
Text(
|
Text(
|
||||||
stringResource(id = R.string.select_tunnel),
|
stringResource(id = R.string.select_tunnel),
|
||||||
textAlign = TextAlign.Center,
|
textAlign = TextAlign.Center,
|
||||||
modifier = Modifier.padding(15.dp, bottom = 5.dp, top = 5.dp)
|
modifier = Modifier.padding(screenPadding, bottom = 5.dp, top = 5.dp)
|
||||||
)
|
)
|
||||||
ExposedDropdownMenuBox(
|
ExposedDropdownMenuBox(
|
||||||
expanded = expanded,
|
expanded = expanded,
|
||||||
|
@ -319,10 +330,10 @@ fun SettingsScreen(
|
||||||
Text(
|
Text(
|
||||||
stringResource(R.string.trusted_ssid),
|
stringResource(R.string.trusted_ssid),
|
||||||
textAlign = TextAlign.Center,
|
textAlign = TextAlign.Center,
|
||||||
modifier = Modifier.padding(15.dp, bottom = 5.dp, top = 5.dp)
|
modifier = Modifier.padding(screenPadding, bottom = 5.dp, top = 5.dp)
|
||||||
)
|
)
|
||||||
FlowRow(
|
FlowRow(
|
||||||
modifier = Modifier.padding(15.dp),
|
modifier = Modifier.padding(screenPadding),
|
||||||
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||||
verticalAlignment = Alignment.CenterVertically
|
verticalAlignment = Alignment.CenterVertically
|
||||||
) {
|
) {
|
||||||
|
@ -339,7 +350,7 @@ fun SettingsScreen(
|
||||||
value = currentText,
|
value = currentText,
|
||||||
onValueChange = { currentText = it },
|
onValueChange = { currentText = it },
|
||||||
label = { Text(stringResource(R.string.add_trusted_ssid)) },
|
label = { Text(stringResource(R.string.add_trusted_ssid)) },
|
||||||
modifier = Modifier.padding(start = 15.dp, top = 5.dp),
|
modifier = Modifier.padding(start = screenPadding, top = 5.dp),
|
||||||
maxLines = 1,
|
maxLines = 1,
|
||||||
keyboardOptions = KeyboardOptions(
|
keyboardOptions = KeyboardOptions(
|
||||||
capitalization = KeyboardCapitalization.None,
|
capitalization = KeyboardCapitalization.None,
|
||||||
|
@ -365,7 +376,7 @@ fun SettingsScreen(
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(14.dp),
|
.padding(screenPadding),
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
horizontalArrangement = Arrangement.SpaceBetween
|
horizontalArrangement = Arrangement.SpaceBetween
|
||||||
) {
|
) {
|
||||||
|
@ -383,7 +394,7 @@ fun SettingsScreen(
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(14.dp),
|
.padding(screenPadding),
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
horizontalArrangement = Arrangement.SpaceBetween
|
horizontalArrangement = Arrangement.SpaceBetween
|
||||||
) {
|
) {
|
||||||
|
|
|
@ -72,11 +72,6 @@ fun SupportScreen(padding : PaddingValues, focusRequester: FocusRequester) {
|
||||||
}) {
|
}) {
|
||||||
Icon(imageVector = ImageVector.vectorResource(R.drawable.github), "Github")
|
Icon(imageVector = ImageVector.vectorResource(R.drawable.github), "Github")
|
||||||
}
|
}
|
||||||
// LaunchedEffect(Unit) {
|
|
||||||
// if(context.packageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK)) {
|
|
||||||
// focusRequester.requestFocus()
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
Spacer(modifier = Modifier.weight(1f))
|
Spacer(modifier = Modifier.weight(1f))
|
||||||
Text(stringResource(id = R.string.privacy_policy), style = TextStyle(textDecoration = TextDecoration.Underline),
|
Text(stringResource(id = R.string.privacy_policy), style = TextStyle(textDecoration = TextDecoration.Underline),
|
||||||
|
|
Loading…
Reference in New Issue