fix(android): avoid duplicate foreground notifications (#2559)

This commit is contained in:
Zhengqi Zhang
2026-09-10 11:39:34 +08:00
committed by GitHub
parent 993640b1dd
commit 44a0a17f68
3 changed files with 30 additions and 9 deletions
@@ -3,7 +3,6 @@
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_SPECIAL_USE" />
<application
@@ -35,9 +34,12 @@
</activity-alias>
<service
android:name=".MainForegroundService"
android:foregroundServiceType="dataSync"
android:foregroundServiceType="specialUse"
android:enabled="true"
android:exported="false">
<property
android:name="android.app.PROPERTY_SPECIAL_USE_FGS_SUBTYPE"
android:value="Maintains EasyTier background connectivity when no VPN service is active." />
</service>
<provider
@@ -1,5 +1,4 @@
package com.kkrainbow.easytier
import android.app.Notification
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.Service
@@ -24,15 +23,15 @@ class MainForegroundService : Service() {
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
createNotificationChannel()
val notification = NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle("easytier Running")
.setContentText("easytier is available on localhost")
.setContentTitle("EasyTier is running")
.setContentText("EasyTier background service is active")
.setSmallIcon(android.R.drawable.ic_menu_manage)
.build()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
startForeground(
NOTIFICATION_ID,
notification,
ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC
ServiceInfo.FOREGROUND_SERVICE_TYPE_SPECIAL_USE
)
} else {
startForeground(NOTIFICATION_ID, notification)
@@ -52,7 +51,7 @@ class MainForegroundService : Service() {
val channel = NotificationChannel(
CHANNEL_ID,
"easytier notice",
NotificationManager.IMPORTANCE_DEFAULT
NotificationManager.IMPORTANCE_LOW
)
val manager = getSystemService(NotificationManager::class.java)
manager?.createNotificationChannel(channel)
@@ -61,4 +60,4 @@ class MainForegroundService : Service() {
}
}
}
}
}
@@ -63,6 +63,7 @@ class TauriVpnService : VpnService() {
override fun onDestroy() {
println("vpn on destroy")
disconnect()
setMainForegroundServiceEnabled(true)
stopForeground(STOP_FOREGROUND_REMOVE)
self = null
EasyTierVpnTileService.requestStateUpdate(this)
@@ -72,6 +73,7 @@ class TauriVpnService : VpnService() {
override fun onRevoke() {
println("vpn on revoke")
disconnect()
setMainForegroundServiceEnabled(true)
stopForeground(STOP_FOREGROUND_REMOVE)
self = null
EasyTierVpnTileService.requestStateUpdate(this)
@@ -126,6 +128,24 @@ class TauriVpnService : VpnService() {
} else {
startForeground(NOTIFICATION_ID, notification)
}
// A TUN-backed network is now protected by this foreground service, so the
// no-TUN keepalive service is redundant and would show a second notification.
setMainForegroundServiceEnabled(false)
}
private fun setMainForegroundServiceEnabled(enabled: Boolean) {
val intent = Intent().setClassName(packageName, "$packageName.MainForegroundService")
if (!enabled) {
stopService(intent)
return
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
startForegroundService(intent)
} else {
startService(intent)
}
}
private fun createNotificationChannel() {