fix(session): take down the countdown notification when the tunnel stops
Disconnecting the VPN from Android's own settings left "Revolt VPN 00:28:13" in the shade, frozen, for as long as the phone stayed up - a notification claiming a protected session over a tunnel that was gone. updateTimer() re-posts notification id 1 as ongoing and non-dismissible from the UI process, every tick. The service cancels its own foreground copy when it stops, but a tick landing just after that re-creates it as an ordinary notification nobody owns, and nothing ever cancelled it: NotificationService.reset() only clears the dedupe cache. AGENTS.md rule 31 describes the cancel this restores. _doDisconnect now cancels it, after vpnConnection.disconnect() so the service is already down - cancelling while it is still in the foreground would be swallowed by the platform. Verified on an emulator, revoking via Settings -> VPN -> Disconnect: before countdown stranded at 00:28:13 indefinitely after no live notifications User disconnect still posts no alert, and expiry still posts "Revolt VPN disconnected" with the countdown gone. Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
1 parent
eab43b0420
commit
296b087db6
3 files changed
+31
No files matched your search
@@ -75,6 +75,18 @@ class MainActivity : FlutterActivity() {
|
|||||||
RevoltAlerts.postDisconnected(this)
|
RevoltAlerts.postDisconnected(this)
|
||||||
result.success(null)
|
result.success(null)
|
||||||
}
|
}
|
||||||
|
// The countdown re-post is ongoing and non-dismissible, so
|
||||||
|
// whoever posted it last has to take it down. A tick that
|
||||||
|
// lands after the service cancelled its own foreground
|
||||||
|
// notification otherwise strands a frozen countdown that
|
||||||
|
// claims a protected session forever. Harmless while the
|
||||||
|
// service is still in the foreground - the platform keeps
|
||||||
|
// its notification regardless.
|
||||||
|
"cancelNotification" -> {
|
||||||
|
(getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager)
|
||||||
|
.cancel(NOTIFICATION_ID)
|
||||||
|
result.success(null)
|
||||||
|
}
|
||||||
else -> result.notImplemented()
|
else -> result.notImplemented()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,6 +41,21 @@ class NotificationService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Takes down the countdown notification.
|
||||||
|
///
|
||||||
|
/// [updateTimer] re-posts an ongoing, non-dismissible notification, so a tick
|
||||||
|
/// that lands after the VPN service has cancelled its own foreground copy
|
||||||
|
/// leaves a frozen countdown on screen that nobody owns. Call this once the
|
||||||
|
/// tunnel is actually down.
|
||||||
|
static Future<void> cancelTimer() async {
|
||||||
|
_lastText = null;
|
||||||
|
try {
|
||||||
|
await _channel.invokeMethod<void>('cancelNotification');
|
||||||
|
} catch (_) {
|
||||||
|
// Cosmetic.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Forces the next connect to re-post even if the countdown resumes on the
|
/// Forces the next connect to re-post even if the countdown resumes on the
|
||||||
/// same value.
|
/// same value.
|
||||||
static void reset() => _lastText = null;
|
static void reset() => _lastText = null;
|
||||||
|
|||||||
@@ -270,6 +270,10 @@ class SessionTimer extends ChangeNotifier with WidgetsBindingObserver {
|
|||||||
notifyListeners();
|
notifyListeners();
|
||||||
|
|
||||||
await vpnConnection.disconnect();
|
await vpnConnection.disconnect();
|
||||||
|
// After the service is down, so the cancel is not swallowed by a still
|
||||||
|
// foreground notification. Without it a revoke leaves the countdown on
|
||||||
|
// screen, frozen, claiming a session that no longer protects anything.
|
||||||
|
await NotificationService.cancelTimer();
|
||||||
if (endedMessage != null && postAlert) {
|
if (endedMessage != null && postAlert) {
|
||||||
unawaited(NotificationService.showDisconnectedAlert());
|
unawaited(NotificationService.showDisconnectedAlert());
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user