From 9b4974aca1a08e855655e7d10d1d40ba10603577 Mon Sep 17 00:00:00 2001 From: Percy Wegmann Date: Thu, 9 May 2024 14:37:50 -0500 Subject: [PATCH] android: persistently store flag indicating whether VPN can be started by quick settings tile This allows us to start the VPN from the quick settings tile even when the application was previously stopped. Updates tailscale/tailscale#11920 Signed-off-by: Percy Wegmann --- .../src/main/java/com/tailscale/ipn/App.kt | 2 +- .../com/tailscale/ipn/QuickToggleService.java | 40 ++++++++++++++----- 2 files changed, 31 insertions(+), 11 deletions(-) diff --git a/android/src/main/java/com/tailscale/ipn/App.kt b/android/src/main/java/com/tailscale/ipn/App.kt index 43d529808e..90f8666cba 100644 --- a/android/src/main/java/com/tailscale/ipn/App.kt +++ b/android/src/main/java/com/tailscale/ipn/App.kt @@ -231,7 +231,7 @@ class App : Application(), libtailscale.AppContext { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) { return } - QuickToggleService.setReady(this, ableToStartVPN) + QuickToggleService.setAbleToStartVPN(this, ableToStartVPN) Log.d("App", "Set Tile Ready: $ableToStartVPN") val action = if (ableToStartVPN) IPNReceiver.INTENT_DISCONNECT_VPN else IPNReceiver.INTENT_CONNECT_VPN diff --git a/android/src/main/java/com/tailscale/ipn/QuickToggleService.java b/android/src/main/java/com/tailscale/ipn/QuickToggleService.java index d0a8753595..61087fdc9a 100644 --- a/android/src/main/java/com/tailscale/ipn/QuickToggleService.java +++ b/android/src/main/java/com/tailscale/ipn/QuickToggleService.java @@ -6,6 +6,7 @@ import android.app.PendingIntent; import android.content.Context; import android.content.Intent; +import android.content.SharedPreferences; import android.os.Build; import android.service.quicksettings.Tile; import android.service.quicksettings.TileService; @@ -13,13 +14,17 @@ public class QuickToggleService extends TileService { // lock protects the static fields below it. private static final Object lock = new Object(); + // isRunning tracks whether the VPN is running. private static boolean isRunning; - // Ready tracks whether the tailscale backend is - // ready to switch on/off. - private static boolean ready; + + // Key for shared preference that tracks whether or not we're able to start + // the VPN (i.e. we're logged in and machine is authorized). + public static String ABLE_TO_START_VPN_KEY = "ableToStartVPN"; + // currentTile tracks getQsTile while service is listening. private static Tile currentTile; + // Request code for opening activity. private static int reqCode = 0; @@ -28,7 +33,7 @@ private static void updateTile(Context ctx) { boolean act; synchronized (lock) { t = currentTile; - act = isRunning && ready; + act = isRunning && getAbleToStartVPN(ctx); } if (t == null) { return; @@ -41,13 +46,26 @@ private static void updateTile(Context ctx) { t.updateTile(); } - static void setReady(Context ctx, boolean rdy) { - synchronized (lock) { - ready = rdy; - } + /* + * setAbleToStartVPN remembers whether or not we're able to start the VPN + * by storing this in a shared preference. This allows us to check this + * value without needing a fully initialized instance of the application. + */ + static void setAbleToStartVPN(Context ctx, boolean rdy) { + SharedPreferences prefs = getSharedPreferences(ctx); + prefs.edit().putBoolean(ABLE_TO_START_VPN_KEY, rdy).apply(); updateTile(ctx); } + static boolean getAbleToStartVPN(Context ctx) { + SharedPreferences prefs = getSharedPreferences(ctx); + return prefs.getBoolean(ABLE_TO_START_VPN_KEY, false); + } + + static SharedPreferences getSharedPreferences(Context ctx) { + return ctx.getSharedPreferences("quicktoggle", Context.MODE_PRIVATE); + } + static void setVPNRunning(Context ctx, boolean running) { synchronized (lock) { isRunning = running; @@ -74,9 +92,11 @@ public void onStopListening() { public void onClick() { boolean r; synchronized (lock) { - r = ready; + r = getAbleToStartVPN(this); } if (r) { + // Get the application to make sure it initializes + App.getApplication(); onTileClick(); } else { // Start main activity. @@ -92,7 +112,7 @@ public void onClick() { private void onTileClick() { boolean act; synchronized (lock) { - act = ready && isRunning; + act = getAbleToStartVPN(this) && isRunning; } Intent i = new Intent(act ? IPNReceiver.INTENT_DISCONNECT_VPN : IPNReceiver.INTENT_CONNECT_VPN); i.setPackage(getPackageName());