From d330726ba147bb7463b7182affa468019cdb7443 Mon Sep 17 00:00:00 2001 From: kari-ts <135075563+kari-ts@users.noreply.github.com> Date: Wed, 1 May 2024 12:04:30 -0700 Subject: [PATCH] android: fix Quick Settings tailscale (#358) -Get rid of unused stopVPN() function -Get rid of unused ACTION_STOP_VPN intent handling; this is redundant with DISCONNECT_VPN intent -Tile active state should only depend on ipn state, and not the results of editing the prefs with wantRunning set. It should be active iff ipn.State > Stopped Fixes tailscale/tailscale#11920 Signed-off-by: kari-ts --- .../src/main/java/com/tailscale/ipn/App.kt | 25 ++++++------------- .../main/java/com/tailscale/ipn/IPNService.kt | 13 +--------- .../com/tailscale/ipn/QuickToggleService.java | 13 ++-------- .../com/tailscale/ipn/StartVPNWorker.java | 4 --- .../com/tailscale/ipn/ui/notifier/Notifier.kt | 4 +-- 5 files changed, 13 insertions(+), 46 deletions(-) diff --git a/android/src/main/java/com/tailscale/ipn/App.kt b/android/src/main/java/com/tailscale/ipn/App.kt index 2b84994..fec6b92 100644 --- a/android/src/main/java/com/tailscale/ipn/App.kt +++ b/android/src/main/java/com/tailscale/ipn/App.kt @@ -87,8 +87,6 @@ class App : Application(), libtailscale.AppContext { } val dns = DnsConfig() - var autoConnect = false - var vpnReady = false private lateinit var connectivityManager: ConnectivityManager private lateinit var app: libtailscale.Application @@ -124,7 +122,7 @@ class App : Application(), libtailscale.AppContext { FILE_CHANNEL_ID, "File transfers", NotificationManagerCompat.IMPORTANCE_DEFAULT) appInstance = this applicationScope.launch { - Notifier.tileReady.collect { isTileReady -> setTileReady(isTileReady) } + Notifier.tileActive.collect { isTileReadyToBeActive -> setTileActive(isTileReadyToBeActive) } } } @@ -137,7 +135,7 @@ class App : Application(), libtailscale.AppContext { fun setWantRunning(wantRunning: Boolean) { val callback: (Result) -> Unit = { result -> result.fold( - onSuccess = { _ -> setTileStatus(wantRunning) }, + onSuccess = { }, onFailure = { error -> Log.d("TAG", "Set want running: failed to update preferences: ${error.message}") }) @@ -187,11 +185,6 @@ class App : Application(), libtailscale.AppContext { startService(intent) } - fun stopVPN() { - val intent = Intent(this, IPNService::class.java) - intent.setAction(IPNService.ACTION_STOP_VPN) - startService(intent) - } // encryptToPref a byte array of data using the Jetpack Security // library and writes it to a global encrypted preference store. @@ -219,19 +212,17 @@ class App : Application(), libtailscale.AppContext { EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM) } - fun setTileReady(ready: Boolean) { + fun setTileActive(ready: Boolean) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) { + return + } QuickToggleService.setReady(this, ready) - Log.d("App", "Set Tile Ready: ready=$ready, autoConnect=$autoConnect") - vpnReady = ready - if (ready && autoConnect) { + Log.d("App", "Set Tile Ready: $ready") + if (ready){ startVPN() } } - fun setTileStatus(status: Boolean) { - QuickToggleService.setStatus(this, status) - } - fun getHostname(): String { val userConfiguredDeviceName = getUserConfiguredDeviceName() if (!userConfiguredDeviceName.isNullOrEmpty()) return userConfiguredDeviceName diff --git a/android/src/main/java/com/tailscale/ipn/IPNService.kt b/android/src/main/java/com/tailscale/ipn/IPNService.kt index f67b800..c00a66c 100644 --- a/android/src/main/java/com/tailscale/ipn/IPNService.kt +++ b/android/src/main/java/com/tailscale/ipn/IPNService.kt @@ -21,11 +21,6 @@ open class IPNService : VpnService(), libtailscale.IPNService { } override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { - if (intent != null && ACTION_STOP_VPN == intent.action) { - (applicationContext as App).autoConnect = false - close() - return START_NOT_STICKY - } val app = applicationContext as App if (intent != null && "android.net.VpnService" == intent.action) { // Start VPN and connect to it due to Always-on VPN @@ -33,14 +28,9 @@ open class IPNService : VpnService(), libtailscale.IPNService { i.setPackage(packageName) i.setClass(applicationContext, IPNReceiver::class.java) sendBroadcast(i) - Libtailscale.requestVPN(this) - app.setWantRunning(true) - return START_STICKY } Libtailscale.requestVPN(this) - if (app.vpnReady && app.autoConnect) { - app.setWantRunning(true) - } + app.setWantRunning(true) return START_STICKY } @@ -134,6 +124,5 @@ open class IPNService : VpnService(), libtailscale.IPNService { companion object { const val ACTION_REQUEST_VPN = "com.tailscale.ipn.REQUEST_VPN" - const val ACTION_STOP_VPN = "com.tailscale.ipn.STOP_VPN" } } diff --git a/android/src/main/java/com/tailscale/ipn/QuickToggleService.java b/android/src/main/java/com/tailscale/ipn/QuickToggleService.java index 39dc4c3..addf1dd 100644 --- a/android/src/main/java/com/tailscale/ipn/QuickToggleService.java +++ b/android/src/main/java/com/tailscale/ipn/QuickToggleService.java @@ -13,8 +13,6 @@ import android.service.quicksettings.TileService; public class QuickToggleService extends TileService { // lock protects the static fields below it. private static final Object lock = new Object(); - // Active tracks whether the VPN is active. - private static boolean active; // Ready tracks whether the tailscale backend is // ready to switch on/off. private static boolean ready; @@ -28,7 +26,7 @@ public class QuickToggleService extends TileService { boolean act; synchronized (lock) { t = currentTile; - act = active && ready; + act = ready; } if (t == null) { return; @@ -48,13 +46,6 @@ public class QuickToggleService extends TileService { updateTile(ctx); } - static void setStatus(Context ctx, boolean act) { - synchronized (lock) { - active = act; - } - updateTile(ctx); - } - @Override public void onStartListening() { synchronized (lock) { @@ -92,7 +83,7 @@ public class QuickToggleService extends TileService { private void onTileClick() { boolean act; synchronized (lock) { - act = active && ready; + act = ready; } Intent i = new Intent(act ? IPNReceiver.INTENT_DISCONNECT_VPN : IPNReceiver.INTENT_CONNECT_VPN); i.setPackage(getPackageName()); diff --git a/android/src/main/java/com/tailscale/ipn/StartVPNWorker.java b/android/src/main/java/com/tailscale/ipn/StartVPNWorker.java index 4179151..11dde35 100644 --- a/android/src/main/java/com/tailscale/ipn/StartVPNWorker.java +++ b/android/src/main/java/com/tailscale/ipn/StartVPNWorker.java @@ -25,11 +25,7 @@ public final class StartVPNWorker extends Worker { @Override public Result doWork() { App app = ((App) getApplicationContext()); - - // We will start the VPN from the background - app.setAutoConnect(true); // We need to make sure we prepare the VPN Service, just in case it isn't prepared. - Intent intent = VpnService.prepare(app); if (intent == null) { // If null then the VPN is already prepared and/or it's just been prepared because we have permission diff --git a/android/src/main/java/com/tailscale/ipn/ui/notifier/Notifier.kt b/android/src/main/java/com/tailscale/ipn/ui/notifier/Notifier.kt index ad038f7..1a58475 100644 --- a/android/src/main/java/com/tailscale/ipn/ui/notifier/Notifier.kt +++ b/android/src/main/java/com/tailscale/ipn/ui/notifier/Notifier.kt @@ -31,7 +31,7 @@ object Notifier { private val decoder = Json { ignoreUnknownKeys = true } // Global App State - val tileReady: StateFlow = MutableStateFlow(false) + val tileActive: StateFlow = MutableStateFlow(false) val readyToPrepareVPN: StateFlow = MutableStateFlow(false) // General IPN Bus State @@ -82,7 +82,7 @@ object Notifier { } state.collect { currstate -> readyToPrepareVPN.set(currstate > Ipn.State.Stopped) - tileReady.set(currstate >= Ipn.State.Stopped) + tileActive.set(currstate > Ipn.State.Stopped) } } }