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 <kari@tailscale.com>
pull/362/head
kari-ts 3 weeks ago committed by GitHub
parent 0c0853a962
commit d330726ba1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -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<Ipn.Prefs>) -> 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

@ -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"
}
}

@ -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());

@ -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

@ -31,7 +31,7 @@ object Notifier {
private val decoder = Json { ignoreUnknownKeys = true }
// Global App State
val tileReady: StateFlow<Boolean> = MutableStateFlow(false)
val tileActive: StateFlow<Boolean> = MutableStateFlow(false)
val readyToPrepareVPN: StateFlow<Boolean> = 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)
}
}
}

Loading…
Cancel
Save