@ -5,12 +5,15 @@ package com.tailscale.ipn
import android.annotation.SuppressLint
import android.annotation.SuppressLint
import android.app.Activity
import android.app.Activity
import android.app.AlertDialog
import android.content.Context
import android.content.Context
import android.content.Intent
import android.content.Intent
import android.content.RestrictionsManager
import android.content.RestrictionsManager
import android.content.pm.ActivityInfo
import android.content.pm.ActivityInfo
import android.content.res.Configuration.SCREENLAYOUT_SIZE_LARGE
import android.content.res.Configuration.SCREENLAYOUT_SIZE_LARGE
import android.content.res.Configuration.SCREENLAYOUT_SIZE_MASK
import android.content.res.Configuration.SCREENLAYOUT_SIZE_MASK
import android.net.ConnectivityManager
import android.net.NetworkCapabilities
import android.os.Bundle
import android.os.Bundle
import android.provider.Settings
import android.provider.Settings
import android.util.Log
import android.util.Log
@ -129,8 +132,13 @@ class MainActivity : ComponentActivity() {
vpnViewModel . setVpnPrepared ( true )
vpnViewModel . setVpnPrepared ( true )
App . get ( ) . startVPN ( )
App . get ( ) . startVPN ( )
} else {
} else {
Log . d ( " VpnPermission " , " VPN permission denied " )
if ( isAnotherVpnActive ( this ) ) {
vpnViewModel . setVpnPrepared ( false )
Log . d ( " VpnPermission " , " Another VPN is likely active " )
showOtherVPNConflictDialog ( )
} else {
Log . d ( " VpnPermission " , " Permission was denied by the user " )
viewModel . setVpnPrepared ( false )
}
}
}
}
}
viewModel . setVpnPermissionLauncher ( vpnPermissionLauncher )
viewModel . setVpnPermissionLauncher ( vpnPermissionLauncher )
@ -285,6 +293,34 @@ class MainActivity : ComponentActivity() {
lifecycleScope . launch { Notifier . loginFinished . collect { _ -> loginQRCode . set ( null ) } }
lifecycleScope . launch { Notifier . loginFinished . collect { _ -> loginQRCode . set ( null ) } }
}
}
private fun showOtherVPNConflictDialog ( ) {
AlertDialog . Builder ( this )
. setTitle ( R . string . vpn _permission _denied )
. setMessage ( R . string . multiple _vpn _explainer )
. setPositiveButton ( R . string . go _to _settings ) { _ , _ ->
// Intent to open the VPN settings
val intent = Intent ( Settings . ACTION _VPN _SETTINGS )
startActivity ( intent )
}
. setNegativeButton ( R . string . cancel , null )
. show ( )
}
fun isAnotherVpnActive ( context : Context ) : Boolean {
val connectivityManager =
context . getSystemService ( Context . CONNECTIVITY _SERVICE ) as ConnectivityManager
val activeNetwork = connectivityManager . activeNetwork
if ( activeNetwork != null ) {
val networkCapabilities = connectivityManager . getNetworkCapabilities ( activeNetwork )
if ( networkCapabilities != null &&
networkCapabilities . hasTransport ( NetworkCapabilities . TRANSPORT _VPN ) ) {
return true
}
}
return false
}
// Returns true if we should render a QR code instead of launching a browser
// Returns true if we should render a QR code instead of launching a browser
// for login requests
// for login requests
private fun useQRCodeLogin ( ) : Boolean {
private fun useQRCodeLogin ( ) : Boolean {