@@ -62,7 +62,7 @@ private fun getCertificateFingerprint(cert: X509Certificate): String {
6262class MainActivity : AppCompatActivity (), CoroutineScope by MainScope() {
6363
6464 private val TAG = MainActivity ::class .simpleName
65- private var app: HttpToolkitApplication ? = null
65+ private lateinit var app: HttpToolkitApplication
6666
6767 private var localBroadcastManager: LocalBroadcastManager ? = null
6868 private val broadcastReceiver = object : BroadcastReceiver () {
@@ -86,16 +86,14 @@ class MainActivity : AppCompatActivity(), CoroutineScope by MainScope() {
8686 override fun onCreate (savedInstanceState : Bundle ? ) {
8787 super .onCreate(savedInstanceState)
8888
89- setContentView(R .layout.main_layout)
90- updateUi()
91-
9289 localBroadcastManager = LocalBroadcastManager .getInstance(this )
9390 localBroadcastManager!! .registerReceiver(broadcastReceiver, IntentFilter ().apply {
9491 addAction(VPN_STARTED_BROADCAST )
9592 addAction(VPN_STOPPED_BROADCAST )
9693 })
9794
9895 app = this .application as HttpToolkitApplication
96+ setContentView(R .layout.main_layout)
9997 updateUi()
10098
10199 Log .i(TAG , " Main activity created" )
@@ -107,7 +105,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope by MainScope() {
107105 // If not, check if this is a post-install run, and if so configure automatically
108106 // using the install referrer
109107 launch {
110- val firstRunParams = app!! .popFirstRunParams()
108+ val firstRunParams = app.popFirstRunParams()
111109 if (
112110 firstRunParams != null &&
113111 firstRunParams.startsWith(" https://android.httptoolkit.tech/connect/" )
@@ -121,13 +119,13 @@ class MainActivity : AppCompatActivity(), CoroutineScope by MainScope() {
121119 override fun onResume () {
122120 super .onResume()
123121 Log .d(TAG , " onResume" )
124- app!! .trackScreen(" Main" )
122+ app.trackScreen(" Main" )
125123 }
126124
127125 override fun onPause () {
128126 super .onPause()
129127 Log .d(TAG , " onPause" )
130- app!! .clearScreen()
128+ app.clearScreen()
131129 }
132130
133131 override fun onDestroy () {
@@ -144,9 +142,9 @@ class MainActivity : AppCompatActivity(), CoroutineScope by MainScope() {
144142 return
145143 }
146144
147- app!! .trackEvent(" Setup" , " action-view" )
145+ app.trackEvent(" Setup" , " action-view" )
148146
149- if (app!! .lastProxy != null && isVpnConfigured()) {
147+ if (app.lastProxy != null && isVpnConfigured()) {
150148 Log .i(TAG , " Showing prompt for ACTION_VIEW intent" )
151149
152150 // If we were started from an intent (e.g. another barcode scanner/link), and we
@@ -190,7 +188,13 @@ class MainActivity : AppCompatActivity(), CoroutineScope by MainScope() {
190188
191189 buttonContainer.visibility = View .VISIBLE
192190 buttonContainer.addView(primaryButton(R .string.scan_button, ::scanCode))
193- buttonContainer.addView(secondaryButton(R .string.manual_button, { }))
191+
192+ val lastProxy = app.lastProxy
193+ if (lastProxy != null ) {
194+ buttonContainer.addView(secondaryButton(R .string.reconnect_button) {
195+ launch { reconnect(lastProxy) }
196+ })
197+ }
194198 }
195199 MainState .CONNECTING -> {
196200 statusText.setText(R .string.connecting_status)
@@ -248,7 +252,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope by MainScope() {
248252 }
249253
250254 private fun scanCode () {
251- app!! .trackEvent(" Button" , " scan-code" )
255+ app.trackEvent(" Button" , " scan-code" )
252256 startActivityForResult(Intent (this , ScanActivity ::class .java), SCAN_REQUEST )
253257 }
254258
@@ -260,7 +264,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope by MainScope() {
260264
261265 withContext(Dispatchers .Main ) { updateUi() }
262266
263- app!! .trackEvent(" Button" , " start-vpn" )
267+ app.trackEvent(" Button" , " start-vpn" )
264268 val vpnIntent = VpnService .prepare(this )
265269 Log .i(TAG , if (vpnIntent != null ) " got intent" else " no intent" )
266270
@@ -296,12 +300,37 @@ class MainActivity : AppCompatActivity(), CoroutineScope by MainScope() {
296300 mainState = MainState .DISCONNECTING
297301 updateUi()
298302
299- app!! .trackEvent(" Button" , " stop-vpn" )
303+ app.trackEvent(" Button" , " stop-vpn" )
300304 startService(Intent (this , ProxyVpnService ::class .java).apply {
301305 action = STOP_VPN_ACTION
302306 })
303307 }
304308
309+ private suspend fun reconnect (lastProxy : ProxyConfig ) {
310+ try {
311+ // Revalidates the config, to ensure the server is available (and drop retries if not)
312+ val config = getProxyConfig(
313+ ProxyInfo (
314+ listOf (lastProxy.ip),
315+ lastProxy.port,
316+ getCertificateFingerprint(lastProxy.certificate as X509Certificate )
317+ )
318+ )
319+ connectToVpn(config)
320+ } catch (e: Exception ) {
321+ app.lastProxy = null
322+
323+ Log .e(TAG , e.toString())
324+ e.printStackTrace()
325+ Sentry .capture(e)
326+ withContext(Dispatchers .Main ) {
327+ app.trackEvent(" Setup" , " reconnect-failed" )
328+ mainState = MainState .FAILED
329+ updateUi()
330+ }
331+ }
332+ }
333+
305334 private fun resetAfterFailure () {
306335 currentProxyConfig = null
307336 mainState = MainState .DISCONNECTED
@@ -381,7 +410,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope by MainScope() {
381410 e.printStackTrace()
382411 Sentry .capture(e)
383412 withContext(Dispatchers .Main ) {
384- app!! .trackEvent(" Setup" , " connect-failed" )
413+ app.trackEvent(" Setup" , " connect-failed" )
385414 mainState = MainState .FAILED
386415 updateUi()
387416 }
@@ -496,14 +525,14 @@ class MainActivity : AppCompatActivity(), CoroutineScope by MainScope() {
496525
497526 private fun ensureCertificateTrusted (proxyConfig : ProxyConfig ) {
498527 if (! isCertTrusted(proxyConfig)) {
499- app!! .trackEvent(" Setup" , " installing-cert" )
528+ app.trackEvent(" Setup" , " installing-cert" )
500529 Log .i(TAG , " Certificate not trusted, prompting to install" )
501530 val certInstallIntent = KeyChain .createInstallIntent()
502531 certInstallIntent.putExtra(EXTRA_NAME , " HTTP Toolkit CA" )
503532 certInstallIntent.putExtra(EXTRA_CERTIFICATE , proxyConfig.certificate.encoded)
504533 startActivityForResult(certInstallIntent, INSTALL_CERT_REQUEST )
505534 } else {
506- app!! .trackEvent(" Setup" , " existing-cert" )
535+ app.trackEvent(" Setup" , " existing-cert" )
507536 Log .i(TAG , " Certificate already trusted, continuing" )
508537 onActivityResult(INSTALL_CERT_REQUEST , RESULT_OK , null )
509538 }
0 commit comments