diff --git a/cmd/tailscale/callbacks.go b/cmd/tailscale/callbacks.go index 0fa5fe5..2a94edd 100644 --- a/cmd/tailscale/callbacks.go +++ b/cmd/tailscale/callbacks.go @@ -22,6 +22,8 @@ var ( // onVPNClosed is notified when VpnService.prepare fails, or when // the a running VPN connection is closed. onVPNClosed = make(chan struct{}, 1) + // onVPNRevoked is notified whenever the VPN service is revoked. + onVPNRevoked = make(chan struct{}, 1) // onConnect receives global IPNService references when // a VPN connection is requested. @@ -69,6 +71,13 @@ func notifyVPNPrepared() { } } +func notifyVPNRevoked() { + select { + case onVPNRevoked <- struct{}{}: + default: + } +} + func notifyVPNClosed() { select { case onVPNClosed <- struct{}{}: @@ -125,6 +134,7 @@ func Java_com_tailscale_ipn_Peer_onActivityResult0(env *C.JNIEnv, cls C.jclass, notifyVPNPrepared() } else { notifyVPNClosed() + notifyVPNRevoked() } } } diff --git a/cmd/tailscale/main.go b/cmd/tailscale/main.go index 3804a67..3ae0939 100644 --- a/cmd/tailscale/main.go +++ b/cmd/tailscale/main.go @@ -559,6 +559,9 @@ func (a *App) runUI() error { return err } } + case <-onVPNRevoked: + ui.NotifyRevoked() + w.Invalidate() case e := <-w.Events(): switch e := e.(type) { case app.ViewEvent: diff --git a/cmd/tailscale/ui.go b/cmd/tailscale/ui.go index 3f5a58a..b4fdecb 100644 --- a/cmd/tailscale/ui.go +++ b/cmd/tailscale/ui.go @@ -286,7 +286,7 @@ func (ui *UI) layout(gtx layout.Context, sysIns system.Insets, state *clientStat }) }) - // "Copied" message. + // Popup messages. ui.layoutMessage(gtx, sysIns) // 3-dots menu. @@ -306,6 +306,11 @@ func (ui *UI) layout(gtx layout.Context, sysIns system.Insets, state *clientStat return ui.events } +func (ui *UI) NotifyRevoked() { + ui.message.text = "VPN access denied or another VPN service is always-on" + ui.message.t0 = time.Now() +} + // Dismiss is a widget that detects pointer presses. type Dismiss struct { }