@@ -36,6 +36,8 @@ import kotlinx.coroutines.CoroutineScope
36
36
import kotlinx.coroutines.Dispatchers
37
37
import kotlinx.coroutines.SupervisorJob
38
38
import kotlinx.coroutines.cancel
39
+ import kotlinx.coroutines.flow.combine
40
+ import kotlinx.coroutines.flow.first
39
41
import kotlinx.coroutines.launch
40
42
import kotlinx.serialization.encodeToString
41
43
import kotlinx.serialization.json.Json
@@ -141,17 +143,32 @@ class App : UninitializedApp(), libtailscale.AppContext, ViewModelStoreOwner {
141
143
initViewModels()
142
144
applicationScope.launch {
143
145
Notifier .state.collect { state ->
144
- val ableToStartVPN = state > Ipn .State .NeedsMachineAuth
145
- // If VPN is stopped, show a disconnected notification. If it is running as a foregrround
146
- // service, IPNService will show a connected notification.
147
- if (state == Ipn .State .Stopped ) {
148
- notifyStatus(false )
149
- }
150
- val vpnRunning = state == Ipn .State .Starting || state == Ipn .State .Running
151
- updateConnStatus(ableToStartVPN)
152
- QuickToggleService .setVPNRunning(vpnRunning)
146
+ combine(Notifier .state, MDMSettings .forceEnabled.flow) { state, forceEnabled ->
147
+ Pair (state, forceEnabled)
148
+ }
149
+ .collect { (state, hideDisconnectAction) ->
150
+ val ableToStartVPN = state > Ipn .State .NeedsMachineAuth
151
+ // If VPN is stopped, show a disconnected notification. If it is running as a
152
+ // foreground
153
+ // service, IPNService will show a connected notification.
154
+ if (state == Ipn .State .Stopped ) {
155
+ notifyStatus(vpnRunning = false , hideDisconnectAction = hideDisconnectAction.value)
156
+ }
157
+
158
+ val vpnRunning = state == Ipn .State .Starting || state == Ipn .State .Running
159
+ updateConnStatus(ableToStartVPN)
160
+ QuickToggleService .setVPNRunning(vpnRunning)
161
+
162
+ // Update notification status when VPN is running
163
+ if (vpnRunning) {
164
+ notifyStatus(vpnRunning = true , hideDisconnectAction = hideDisconnectAction.value)
165
+ }
166
+ }
153
167
}
154
168
}
169
+ applicationScope.launch {
170
+ val hideDisconnectAction = MDMSettings .forceEnabled.flow.first()
171
+ }
155
172
}
156
173
157
174
private fun initViewModels () {
@@ -419,8 +436,8 @@ open class UninitializedApp : Application() {
419
436
notificationManager.createNotificationChannel(channel)
420
437
}
421
438
422
- fun notifyStatus (vpnRunning : Boolean ) {
423
- notifyStatus(buildStatusNotification(vpnRunning))
439
+ fun notifyStatus (vpnRunning : Boolean , hideDisconnectAction : Boolean ) {
440
+ notifyStatus(buildStatusNotification(vpnRunning, hideDisconnectAction ))
424
441
}
425
442
426
443
fun notifyStatus (notification : Notification ) {
@@ -438,7 +455,7 @@ open class UninitializedApp : Application() {
438
455
notificationManager.notify(STATUS_NOTIFICATION_ID , notification)
439
456
}
440
457
441
- fun buildStatusNotification (vpnRunning : Boolean ): Notification {
458
+ fun buildStatusNotification (vpnRunning : Boolean , hideDisconnectAction : Boolean ): Notification {
442
459
val message = getString(if (vpnRunning) R .string.connected else R .string.not_connected)
443
460
val icon = if (vpnRunning) R .drawable.ic_notification else R .drawable.ic_notification_disabled
444
461
val action =
@@ -460,19 +477,22 @@ open class UninitializedApp : Application() {
460
477
PendingIntent .getActivity(
461
478
this , 1 , intent, PendingIntent .FLAG_UPDATE_CURRENT or PendingIntent .FLAG_IMMUTABLE )
462
479
463
- return NotificationCompat .Builder (this , STATUS_CHANNEL_ID )
464
- .setSmallIcon(icon)
465
- .setContentTitle(" Tailscale" )
466
- .setContentText(message)
467
- .setAutoCancel(! vpnRunning)
468
- .setOnlyAlertOnce(! vpnRunning)
469
- .setOngoing(vpnRunning)
470
- .setSilent(true )
471
- .setOngoing(false )
472
- .setPriority(NotificationCompat .PRIORITY_DEFAULT )
473
- .addAction(NotificationCompat .Action .Builder (0 , actionLabel, pendingButtonIntent).build())
474
- .setContentIntent(pendingIntent)
475
- .build()
480
+ val builder =
481
+ NotificationCompat .Builder (this , STATUS_CHANNEL_ID )
482
+ .setSmallIcon(icon)
483
+ .setContentTitle(getString(R .string.app_name))
484
+ .setContentText(message)
485
+ .setAutoCancel(! vpnRunning)
486
+ .setOnlyAlertOnce(! vpnRunning)
487
+ .setOngoing(vpnRunning)
488
+ .setSilent(true )
489
+ .setPriority(NotificationCompat .PRIORITY_DEFAULT )
490
+ .setContentIntent(pendingIntent)
491
+ if (! vpnRunning || ! hideDisconnectAction) {
492
+ builder.addAction(
493
+ NotificationCompat .Action .Builder (0 , actionLabel, pendingButtonIntent).build())
494
+ }
495
+ return builder.build()
476
496
}
477
497
478
498
fun addUserDisallowedPackageName (packageName : String ) {
0 commit comments