@@ -75,6 +75,10 @@ class MainActivity : ComponentActivity(), CoroutineScope by MainScope() {
7575 } else if (intent.action == VPN_STOPPED_BROADCAST ) {
7676 mainState = ConnectionState .DISCONNECTED
7777 currentProxyConfig = null
78+
79+ if (intent.getBooleanExtra(IntentExtras .VPN_FAILED_EXTRA , false )) {
80+ showActiveVpnFailureAlert()
81+ }
7882 }
7983 }
8084 }
@@ -88,10 +92,6 @@ class MainActivity : ComponentActivity(), CoroutineScope by MainScope() {
8892 private var interceptedAppCount: Int by mutableIntStateOf(0 )
8993 private var interceptedPorts: Set <Int > by mutableStateOf(emptySet())
9094
91- // Used to track extremely fast VPN setup failures, indicating setup issues (rather than
92- // manual user cancellation). Doesn't matter that it's not properly persistent.
93- private var lastPauseTime = - 1L
94-
9595 val pickAppsContract = registerForActivityResult(ActivityResultContracts .StartActivityForResult ()) { result ->
9696 if (result.resultCode == RESULT_OK ) {
9797 Log .i(TAG , " Pick apps result: OK" )
@@ -260,7 +260,6 @@ class MainActivity : ComponentActivity(), CoroutineScope by MainScope() {
260260 override fun onPause () {
261261 super .onPause()
262262 Log .d(TAG , " onPause" )
263- this .lastPauseTime = System .currentTimeMillis()
264263 }
265264
266265 override fun onDestroy () {
@@ -548,18 +547,6 @@ class MainActivity : ComponentActivity(), CoroutineScope by MainScope() {
548547 Log .i(TAG , " Notifications OK, starting VPN..." )
549548 startVpn()
550549 }
551- } else if (
552- requestCode == START_VPN_REQUEST &&
553- System .currentTimeMillis() - lastPauseTime < 200 && // On Pixel 4a it takes < 50ms
554- resultCode == RESULT_CANCELED
555- ) {
556- // If another always-on VPN is active, VPN start requests fail instantly as cancelled.
557- // We can't check that the VPN is always-on, but given an instant failure that's
558- // the likely cause, so we warn about it:
559- showActiveVpnFailureAlert()
560-
561- // Then go back to the disconnected state:
562- mainState = ConnectionState .DISCONNECTED
563550 } else if (
564551 requestCode == INSTALL_CERT_REQUEST &&
565552 Build .VERSION .SDK_INT >= Build .VERSION_CODES .Q // Required for promptToManuallyInstallCert
@@ -1016,15 +1003,18 @@ class MainActivity : ComponentActivity(), CoroutineScope by MainScope() {
10161003 }
10171004
10181005 private fun showActiveVpnFailureAlert () {
1006+ // The VPN service can report failures while we're in the background:
1007+ if (isFinishing || isDestroyed) return
1008+
10191009 MaterialAlertDialogBuilder (this )
10201010 .setTitle(" VPN setup failed" )
10211011 .setIcon(R .drawable.ic_exclamation_triangle)
10221012 .setMessage(
10231013 " HTTP Toolkit could not be configured as a VPN on your device." +
10241014 " \n\n " +
1025- " This usually means you have an always-on VPN configured , which blocks " +
1026- " installation of other VPNs. To activate HTTP Toolkit you'll need to " +
1027- " deactivate that VPN first ."
1015+ " This usually means another VPN is active , which blocks HTTP Toolkit's VPN. To " +
1016+ " activate HTTP Toolkit you'll need to deactivate that VPN first, including any " +
1017+ " always-on or auto-reconnect options ."
10281018 )
10291019 .setNegativeButton(" Cancel" ) { _, _ -> }
10301020 .setPositiveButton(" Open VPN Settings" ) { _, _ ->
0 commit comments