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 2 years 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() val dns = DnsConfig()
var autoConnect = false
var vpnReady = false
private lateinit var connectivityManager: ConnectivityManager private lateinit var connectivityManager: ConnectivityManager
private lateinit var app: libtailscale.Application private lateinit var app: libtailscale.Application
@ -124,7 +122,7 @@ class App : Application(), libtailscale.AppContext {
FILE_CHANNEL_ID, "File transfers", NotificationManagerCompat.IMPORTANCE_DEFAULT) FILE_CHANNEL_ID, "File transfers", NotificationManagerCompat.IMPORTANCE_DEFAULT)
appInstance = this appInstance = this
applicationScope.launch { 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) { fun setWantRunning(wantRunning: Boolean) {
val callback: (Result<Ipn.Prefs>) -> Unit = { result -> val callback: (Result<Ipn.Prefs>) -> Unit = { result ->
result.fold( result.fold(
onSuccess = { _ -> setTileStatus(wantRunning) }, onSuccess = { },
onFailure = { error -> onFailure = { error ->
Log.d("TAG", "Set want running: failed to update preferences: ${error.message}") Log.d("TAG", "Set want running: failed to update preferences: ${error.message}")
}) })
@ -187,11 +185,6 @@ class App : Application(), libtailscale.AppContext {
startService(intent) 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 // encryptToPref a byte array of data using the Jetpack Security
// library and writes it to a global encrypted preference store. // library and writes it to a global encrypted preference store.
@ -219,19 +212,17 @@ class App : Application(), libtailscale.AppContext {
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM) 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) QuickToggleService.setReady(this, ready)
Log.d("App", "Set Tile Ready: ready=$ready, autoConnect=$autoConnect") Log.d("App", "Set Tile Ready: $ready")
vpnReady = ready if (ready){
if (ready && autoConnect) {
startVPN() startVPN()
} }
} }
fun setTileStatus(status: Boolean) {
QuickToggleService.setStatus(this, status)
}
fun getHostname(): String { fun getHostname(): String {
val userConfiguredDeviceName = getUserConfiguredDeviceName() val userConfiguredDeviceName = getUserConfiguredDeviceName()
if (!userConfiguredDeviceName.isNullOrEmpty()) return userConfiguredDeviceName 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 { 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 val app = applicationContext as App
if (intent != null && "android.net.VpnService" == intent.action) { if (intent != null && "android.net.VpnService" == intent.action) {
// Start VPN and connect to it due to Always-on VPN // 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.setPackage(packageName)
i.setClass(applicationContext, IPNReceiver::class.java) i.setClass(applicationContext, IPNReceiver::class.java)
sendBroadcast(i) sendBroadcast(i)
Libtailscale.requestVPN(this)
app.setWantRunning(true)
return START_STICKY
} }
Libtailscale.requestVPN(this) Libtailscale.requestVPN(this)
if (app.vpnReady && app.autoConnect) {
app.setWantRunning(true) app.setWantRunning(true)
}
return START_STICKY return START_STICKY
} }
@ -134,6 +124,5 @@ open class IPNService : VpnService(), libtailscale.IPNService {
companion object { companion object {
const val ACTION_REQUEST_VPN = "com.tailscale.ipn.REQUEST_VPN" 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 { public class QuickToggleService extends TileService {
// lock protects the static fields below it. // lock protects the static fields below it.
private static final Object lock = new Object(); 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 tracks whether the tailscale backend is
// ready to switch on/off. // ready to switch on/off.
private static boolean ready; private static boolean ready;
@ -28,7 +26,7 @@ public class QuickToggleService extends TileService {
boolean act; boolean act;
synchronized (lock) { synchronized (lock) {
t = currentTile; t = currentTile;
act = active && ready; act = ready;
} }
if (t == null) { if (t == null) {
return; return;
@ -48,13 +46,6 @@ public class QuickToggleService extends TileService {
updateTile(ctx); updateTile(ctx);
} }
static void setStatus(Context ctx, boolean act) {
synchronized (lock) {
active = act;
}
updateTile(ctx);
}
@Override @Override
public void onStartListening() { public void onStartListening() {
synchronized (lock) { synchronized (lock) {
@ -92,7 +83,7 @@ public class QuickToggleService extends TileService {
private void onTileClick() { private void onTileClick() {
boolean act; boolean act;
synchronized (lock) { synchronized (lock) {
act = active && ready; act = ready;
} }
Intent i = new Intent(act ? IPNReceiver.INTENT_DISCONNECT_VPN : IPNReceiver.INTENT_CONNECT_VPN); Intent i = new Intent(act ? IPNReceiver.INTENT_DISCONNECT_VPN : IPNReceiver.INTENT_CONNECT_VPN);
i.setPackage(getPackageName()); i.setPackage(getPackageName());

@ -25,11 +25,7 @@ public final class StartVPNWorker extends Worker {
@Override @Override
public Result doWork() { public Result doWork() {
App app = ((App) getApplicationContext()); 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. // We need to make sure we prepare the VPN Service, just in case it isn't prepared.
Intent intent = VpnService.prepare(app); Intent intent = VpnService.prepare(app);
if (intent == null) { if (intent == null) {
// If null then the VPN is already prepared and/or it's just been prepared because we have permission // 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 } private val decoder = Json { ignoreUnknownKeys = true }
// Global App State // Global App State
val tileReady: StateFlow<Boolean> = MutableStateFlow(false) val tileActive: StateFlow<Boolean> = MutableStateFlow(false)
val readyToPrepareVPN: StateFlow<Boolean> = MutableStateFlow(false) val readyToPrepareVPN: StateFlow<Boolean> = MutableStateFlow(false)
// General IPN Bus State // General IPN Bus State
@ -82,7 +82,7 @@ object Notifier {
} }
state.collect { currstate -> state.collect { currstate ->
readyToPrepareVPN.set(currstate > Ipn.State.Stopped) readyToPrepareVPN.set(currstate > Ipn.State.Stopped)
tileReady.set(currstate >= Ipn.State.Stopped) tileActive.set(currstate > Ipn.State.Stopped)
} }
} }
} }

Loading…
Cancel
Save