Browse Source

Remove foreground detector due to play policy

世界 3 years ago
parent
commit
6c000181c7

+ 462 - 0
app/schemas/io.nekohasekai.sagernet.database.SagerDatabase/12.json

@@ -0,0 +1,462 @@
+{
+  "formatVersion": 1,
+  "database": {
+    "version": 12,
+    "identityHash": "90d75d8abadafbc4c5705a1907cf32c1",
+    "entities": [
+      {
+        "tableName": "proxy_groups",
+        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `userOrder` INTEGER NOT NULL, `ungrouped` INTEGER NOT NULL, `name` TEXT, `type` INTEGER NOT NULL, `subscription` BLOB, `order` INTEGER NOT NULL)",
+        "fields": [
+          {
+            "fieldPath": "id",
+            "columnName": "id",
+            "affinity": "INTEGER",
+            "notNull": true
+          },
+          {
+            "fieldPath": "userOrder",
+            "columnName": "userOrder",
+            "affinity": "INTEGER",
+            "notNull": true
+          },
+          {
+            "fieldPath": "ungrouped",
+            "columnName": "ungrouped",
+            "affinity": "INTEGER",
+            "notNull": true
+          },
+          {
+            "fieldPath": "name",
+            "columnName": "name",
+            "affinity": "TEXT",
+            "notNull": false
+          },
+          {
+            "fieldPath": "type",
+            "columnName": "type",
+            "affinity": "INTEGER",
+            "notNull": true
+          },
+          {
+            "fieldPath": "subscription",
+            "columnName": "subscription",
+            "affinity": "BLOB",
+            "notNull": false
+          },
+          {
+            "fieldPath": "order",
+            "columnName": "order",
+            "affinity": "INTEGER",
+            "notNull": true
+          }
+        ],
+        "primaryKey": {
+          "columnNames": [
+            "id"
+          ],
+          "autoGenerate": true
+        },
+        "indices": [],
+        "foreignKeys": []
+      },
+      {
+        "tableName": "proxy_entities",
+        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `groupId` INTEGER NOT NULL, `type` INTEGER NOT NULL, `userOrder` INTEGER NOT NULL, `tx` INTEGER NOT NULL, `rx` INTEGER NOT NULL, `status` INTEGER NOT NULL, `ping` INTEGER NOT NULL, `uuid` TEXT NOT NULL, `error` TEXT, `socksBean` BLOB, `httpBean` BLOB, `ssBean` BLOB, `ssrBean` BLOB, `vmessBean` BLOB, `vlessBean` BLOB, `trojanBean` BLOB, `trojanGoBean` BLOB, `naiveBean` BLOB, `ptBean` BLOB, `rbBean` BLOB, `brookBean` BLOB, `hysteriaBean` BLOB, `sshBean` BLOB, `wgBean` BLOB, `configBean` BLOB, `chainBean` BLOB, `balancerBean` BLOB)",
+        "fields": [
+          {
+            "fieldPath": "id",
+            "columnName": "id",
+            "affinity": "INTEGER",
+            "notNull": true
+          },
+          {
+            "fieldPath": "groupId",
+            "columnName": "groupId",
+            "affinity": "INTEGER",
+            "notNull": true
+          },
+          {
+            "fieldPath": "type",
+            "columnName": "type",
+            "affinity": "INTEGER",
+            "notNull": true
+          },
+          {
+            "fieldPath": "userOrder",
+            "columnName": "userOrder",
+            "affinity": "INTEGER",
+            "notNull": true
+          },
+          {
+            "fieldPath": "tx",
+            "columnName": "tx",
+            "affinity": "INTEGER",
+            "notNull": true
+          },
+          {
+            "fieldPath": "rx",
+            "columnName": "rx",
+            "affinity": "INTEGER",
+            "notNull": true
+          },
+          {
+            "fieldPath": "status",
+            "columnName": "status",
+            "affinity": "INTEGER",
+            "notNull": true
+          },
+          {
+            "fieldPath": "ping",
+            "columnName": "ping",
+            "affinity": "INTEGER",
+            "notNull": true
+          },
+          {
+            "fieldPath": "uuid",
+            "columnName": "uuid",
+            "affinity": "TEXT",
+            "notNull": true
+          },
+          {
+            "fieldPath": "error",
+            "columnName": "error",
+            "affinity": "TEXT",
+            "notNull": false
+          },
+          {
+            "fieldPath": "socksBean",
+            "columnName": "socksBean",
+            "affinity": "BLOB",
+            "notNull": false
+          },
+          {
+            "fieldPath": "httpBean",
+            "columnName": "httpBean",
+            "affinity": "BLOB",
+            "notNull": false
+          },
+          {
+            "fieldPath": "ssBean",
+            "columnName": "ssBean",
+            "affinity": "BLOB",
+            "notNull": false
+          },
+          {
+            "fieldPath": "ssrBean",
+            "columnName": "ssrBean",
+            "affinity": "BLOB",
+            "notNull": false
+          },
+          {
+            "fieldPath": "vmessBean",
+            "columnName": "vmessBean",
+            "affinity": "BLOB",
+            "notNull": false
+          },
+          {
+            "fieldPath": "vlessBean",
+            "columnName": "vlessBean",
+            "affinity": "BLOB",
+            "notNull": false
+          },
+          {
+            "fieldPath": "trojanBean",
+            "columnName": "trojanBean",
+            "affinity": "BLOB",
+            "notNull": false
+          },
+          {
+            "fieldPath": "trojanGoBean",
+            "columnName": "trojanGoBean",
+            "affinity": "BLOB",
+            "notNull": false
+          },
+          {
+            "fieldPath": "naiveBean",
+            "columnName": "naiveBean",
+            "affinity": "BLOB",
+            "notNull": false
+          },
+          {
+            "fieldPath": "ptBean",
+            "columnName": "ptBean",
+            "affinity": "BLOB",
+            "notNull": false
+          },
+          {
+            "fieldPath": "rbBean",
+            "columnName": "rbBean",
+            "affinity": "BLOB",
+            "notNull": false
+          },
+          {
+            "fieldPath": "brookBean",
+            "columnName": "brookBean",
+            "affinity": "BLOB",
+            "notNull": false
+          },
+          {
+            "fieldPath": "hysteriaBean",
+            "columnName": "hysteriaBean",
+            "affinity": "BLOB",
+            "notNull": false
+          },
+          {
+            "fieldPath": "sshBean",
+            "columnName": "sshBean",
+            "affinity": "BLOB",
+            "notNull": false
+          },
+          {
+            "fieldPath": "wgBean",
+            "columnName": "wgBean",
+            "affinity": "BLOB",
+            "notNull": false
+          },
+          {
+            "fieldPath": "configBean",
+            "columnName": "configBean",
+            "affinity": "BLOB",
+            "notNull": false
+          },
+          {
+            "fieldPath": "chainBean",
+            "columnName": "chainBean",
+            "affinity": "BLOB",
+            "notNull": false
+          },
+          {
+            "fieldPath": "balancerBean",
+            "columnName": "balancerBean",
+            "affinity": "BLOB",
+            "notNull": false
+          }
+        ],
+        "primaryKey": {
+          "columnNames": [
+            "id"
+          ],
+          "autoGenerate": true
+        },
+        "indices": [
+          {
+            "name": "groupId",
+            "unique": false,
+            "columnNames": [
+              "groupId"
+            ],
+            "createSql": "CREATE INDEX IF NOT EXISTS `groupId` ON `${TABLE_NAME}` (`groupId`)"
+          }
+        ],
+        "foreignKeys": []
+      },
+      {
+        "tableName": "rules",
+        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `name` TEXT NOT NULL, `userOrder` INTEGER NOT NULL, `enabled` INTEGER NOT NULL, `domains` TEXT NOT NULL, `ip` TEXT NOT NULL, `port` TEXT NOT NULL, `sourcePort` TEXT NOT NULL, `network` TEXT NOT NULL, `source` TEXT NOT NULL, `protocol` TEXT NOT NULL, `attrs` TEXT NOT NULL, `outbound` INTEGER NOT NULL, `reverse` INTEGER NOT NULL, `redirect` TEXT NOT NULL, `packages` TEXT NOT NULL)",
+        "fields": [
+          {
+            "fieldPath": "id",
+            "columnName": "id",
+            "affinity": "INTEGER",
+            "notNull": true
+          },
+          {
+            "fieldPath": "name",
+            "columnName": "name",
+            "affinity": "TEXT",
+            "notNull": true
+          },
+          {
+            "fieldPath": "userOrder",
+            "columnName": "userOrder",
+            "affinity": "INTEGER",
+            "notNull": true
+          },
+          {
+            "fieldPath": "enabled",
+            "columnName": "enabled",
+            "affinity": "INTEGER",
+            "notNull": true
+          },
+          {
+            "fieldPath": "domains",
+            "columnName": "domains",
+            "affinity": "TEXT",
+            "notNull": true
+          },
+          {
+            "fieldPath": "ip",
+            "columnName": "ip",
+            "affinity": "TEXT",
+            "notNull": true
+          },
+          {
+            "fieldPath": "port",
+            "columnName": "port",
+            "affinity": "TEXT",
+            "notNull": true
+          },
+          {
+            "fieldPath": "sourcePort",
+            "columnName": "sourcePort",
+            "affinity": "TEXT",
+            "notNull": true
+          },
+          {
+            "fieldPath": "network",
+            "columnName": "network",
+            "affinity": "TEXT",
+            "notNull": true
+          },
+          {
+            "fieldPath": "source",
+            "columnName": "source",
+            "affinity": "TEXT",
+            "notNull": true
+          },
+          {
+            "fieldPath": "protocol",
+            "columnName": "protocol",
+            "affinity": "TEXT",
+            "notNull": true
+          },
+          {
+            "fieldPath": "attrs",
+            "columnName": "attrs",
+            "affinity": "TEXT",
+            "notNull": true
+          },
+          {
+            "fieldPath": "outbound",
+            "columnName": "outbound",
+            "affinity": "INTEGER",
+            "notNull": true
+          },
+          {
+            "fieldPath": "reverse",
+            "columnName": "reverse",
+            "affinity": "INTEGER",
+            "notNull": true
+          },
+          {
+            "fieldPath": "redirect",
+            "columnName": "redirect",
+            "affinity": "TEXT",
+            "notNull": true
+          },
+          {
+            "fieldPath": "packages",
+            "columnName": "packages",
+            "affinity": "TEXT",
+            "notNull": true
+          }
+        ],
+        "primaryKey": {
+          "columnNames": [
+            "id"
+          ],
+          "autoGenerate": true
+        },
+        "indices": [],
+        "foreignKeys": []
+      },
+      {
+        "tableName": "stats",
+        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `packageName` TEXT NOT NULL, `tcpConnections` INTEGER NOT NULL, `udpConnections` INTEGER NOT NULL, `uplink` INTEGER NOT NULL, `downlink` INTEGER NOT NULL)",
+        "fields": [
+          {
+            "fieldPath": "id",
+            "columnName": "id",
+            "affinity": "INTEGER",
+            "notNull": true
+          },
+          {
+            "fieldPath": "packageName",
+            "columnName": "packageName",
+            "affinity": "TEXT",
+            "notNull": true
+          },
+          {
+            "fieldPath": "tcpConnections",
+            "columnName": "tcpConnections",
+            "affinity": "INTEGER",
+            "notNull": true
+          },
+          {
+            "fieldPath": "udpConnections",
+            "columnName": "udpConnections",
+            "affinity": "INTEGER",
+            "notNull": true
+          },
+          {
+            "fieldPath": "uplink",
+            "columnName": "uplink",
+            "affinity": "INTEGER",
+            "notNull": true
+          },
+          {
+            "fieldPath": "downlink",
+            "columnName": "downlink",
+            "affinity": "INTEGER",
+            "notNull": true
+          }
+        ],
+        "primaryKey": {
+          "columnNames": [
+            "id"
+          ],
+          "autoGenerate": true
+        },
+        "indices": [
+          {
+            "name": "index_stats_packageName",
+            "unique": true,
+            "columnNames": [
+              "packageName"
+            ],
+            "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_stats_packageName` ON `${TABLE_NAME}` (`packageName`)"
+          }
+        ],
+        "foreignKeys": []
+      },
+      {
+        "tableName": "KeyValuePair",
+        "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`key` TEXT NOT NULL, `valueType` INTEGER NOT NULL, `value` BLOB NOT NULL, PRIMARY KEY(`key`))",
+        "fields": [
+          {
+            "fieldPath": "key",
+            "columnName": "key",
+            "affinity": "TEXT",
+            "notNull": true
+          },
+          {
+            "fieldPath": "valueType",
+            "columnName": "valueType",
+            "affinity": "INTEGER",
+            "notNull": true
+          },
+          {
+            "fieldPath": "value",
+            "columnName": "value",
+            "affinity": "BLOB",
+            "notNull": true
+          }
+        ],
+        "primaryKey": {
+          "columnNames": [
+            "key"
+          ],
+          "autoGenerate": false
+        },
+        "indices": [],
+        "foreignKeys": []
+      }
+    ],
+    "views": [],
+    "setupQueries": [
+      "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
+      "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '90d75d8abadafbc4c5705a1907cf32c1')"
+    ]
+  }
+}

+ 0 - 13
app/src/main/AndroidManifest.xml

@@ -312,19 +312,6 @@
             </intent-filter>
         </receiver>
 
-        <service
-            android:name="io.nekohasekai.sagernet.bg.ForegroundDetectorService"
-            android:exported="true"
-            android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"
-            android:process=":bg">
-            <intent-filter>
-                <action android:name="android.accessibilityservice.AccessibilityService" />
-            </intent-filter>
-            <meta-data
-                android:name="android.accessibilityservice"
-                android:resource="@xml/foreground_detector_service" />
-        </service>
-
         <provider
             android:name="androidx.startup.InitializationProvider"
             android:authorities="${applicationId}.androidx-startup"

+ 0 - 6
app/src/main/java/io/nekohasekai/sagernet/Constants.kt

@@ -172,7 +172,6 @@ object Key {
     const val ROUTE_REVERSE = "routeReverse"
     const val ROUTE_REDIRECT = "routeRedirect"
     const val ROUTE_PACKAGES = "routePackages"
-    const val ROUTE_FOREGROUND_STATUS = "routeForegroundStatus"
 
     const val GROUP_NAME = "groupName"
     const val GROUP_TYPE = "groupType"
@@ -240,11 +239,6 @@ object GroupOrder {
     const val BY_DELAY = 2
 }
 
-object AppStatus {
-    const val FOREGROUND = "foreground"
-    const val BACKGROUND = "background"
-}
-
 object BalancerStrategy {
     const val LATEST_PING = "leastPing"
 }

+ 0 - 83
app/src/main/java/io/nekohasekai/sagernet/bg/ForegroundDetectorService.kt

@@ -1,83 +0,0 @@
-/******************************************************************************
- *                                                                            *
- * Copyright (C) 2021 by nekohasekai <[email protected]>             *
- *                                                                            *
- * This program is free software: you can redistribute it and/or modify       *
- * it under the terms of the GNU General Public License as published by       *
- * the Free Software Foundation, either version 3 of the License, or          *
- *  (at your option) any later version.                                       *
- *                                                                            *
- * This program is distributed in the hope that it will be useful,            *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of             *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the              *
- * GNU General Public License for more details.                               *
- *                                                                            *
- * You should have received a copy of the GNU General Public License          *
- * along with this program. If not, see <http://www.gnu.org/licenses/>.       *
- *                                                                            *
- ******************************************************************************/
-
-package io.nekohasekai.sagernet.bg
-
-import android.accessibilityservice.AccessibilityService
-import android.view.accessibility.AccessibilityEvent
-import android.view.inputmethod.InputMethodManager
-import io.nekohasekai.sagernet.ktx.Logs
-import io.nekohasekai.sagernet.utils.PackageCache
-import libcore.Libcore
-
-class ForegroundDetectorService : AccessibilityService() {
-
-    class NotStartedException(val routeName: String) : IllegalStateException()
-
-    val imeApps by lazy {
-        (applicationContext.getSystemService(
-            INPUT_METHOD_SERVICE
-        ) as InputMethodManager).inputMethodList.map { it.packageName }
-    }
-    var fromIme = false
-
-    override fun onCreate() {
-        super.onCreate()
-
-        Logs.i("Started")
-    }
-
-    override fun onAccessibilityEvent(event: AccessibilityEvent) {
-
-        val packageName = event.packageName?.takeIf { it.isNotBlank() }?.toString() ?: return
-        if (packageName == "com.android.systemui") return
-        if (packageName in imeApps) {
-            val uid = PackageCache[packageName] ?: return
-            PackageCache.awaitLoadSync()
-            Libcore.setForegroundImeUid(uid)
-            fromIme = true
-
-            Logs.d("Foreground IME changed to ${event.packageName}/${event.className}: uid $uid")
-            return
-        }
-
-        PackageCache.awaitLoadSync()
-        var uid = PackageCache[packageName] ?: -1
-        if (uid < 10000) {
-            uid = 1000
-        }
-
-        Libcore.setForegroundUid(uid)
-        if (fromIme) {
-            Libcore.setForegroundImeUid(0)
-            fromIme = false
-
-            Logs.d("Foreground IME changed to none")
-        }
-
-        Logs.d("Foreground changed to ${event.packageName}/${event.className}: uid $uid")
-    }
-
-    override fun onInterrupt() {
-        Logs.i("Interrupted")
-
-        Libcore.setForegroundUid(0)
-    }
-
-}

+ 0 - 1
app/src/main/java/io/nekohasekai/sagernet/database/DataStore.kt

@@ -270,7 +270,6 @@ object DataStore : OnPreferenceDataStoreChangeListener {
     var routeReverse by profileCacheStore.boolean(Key.ROUTE_REVERSE)
     var routeRedirect by profileCacheStore.string(Key.ROUTE_REDIRECT)
     var routePackages by profileCacheStore.string(Key.ROUTE_PACKAGES)
-    var routeForegroundStatus by profileCacheStore.string(Key.ROUTE_FOREGROUND_STATUS)
 
     var serverConfig by profileCacheStore.string(Key.SERVER_CONFIG)
 

+ 2 - 14
app/src/main/java/io/nekohasekai/sagernet/database/RuleEntity.kt

@@ -21,7 +21,6 @@ package io.nekohasekai.sagernet.database
 
 import android.os.Parcelable
 import androidx.room.*
-import io.nekohasekai.sagernet.AppStatus
 import io.nekohasekai.sagernet.R
 import io.nekohasekai.sagernet.ktx.app
 import kotlinx.parcelize.Parcelize
@@ -45,11 +44,10 @@ data class RuleEntity(
     var reverse: Boolean = false,
     var redirect: String = "",
     var packages: List<String> = listOf(),
-    var appStatus: List<String> = listOf(),
 ) : Parcelable {
 
     fun isBypassRule(): Boolean {
-        return (domains.isNotBlank() && ip.isBlank() || ip.isNotBlank() && domains.isBlank()) && port.isBlank() && sourcePort.isBlank() && network.isBlank() && source.isBlank() && protocol.isBlank() && attrs.isBlank() && !reverse && redirect.isBlank() && outbound == -1L && packages.isEmpty() && appStatus.isEmpty()
+        return (domains.isNotBlank() && ip.isBlank() || ip.isNotBlank() && domains.isBlank()) && port.isBlank() && sourcePort.isBlank() && network.isBlank() && source.isBlank() && protocol.isBlank() && attrs.isBlank() && !reverse && redirect.isBlank() && outbound == -1L && packages.isEmpty()
     }
 
     fun displayName(): String {
@@ -69,7 +67,6 @@ data class RuleEntity(
         if (packages.isNotEmpty()) summary += app.getString(
             R.string.apps_message, packages.size
         ) + "\n"
-        if (appStatus.isNotEmpty()) summary += displayAppStatus().joinToString("\n")
         val lines = summary.trim().split("\n")
         return if (lines.size > 3) {
             lines.subList(0, 3).joinToString("\n", postfix = "\n...")
@@ -91,19 +88,10 @@ data class RuleEntity(
         }
     }
 
-    fun displayAppStatus(): List<String> {
-        return appStatus.map {
-            when (it) {
-                AppStatus.FOREGROUND -> app.getString(R.string.foreground)
-                /*AppStatus.BACKGROUND*/ else -> app.getString(R.string.background)
-            }
-        }
-    }
-
     @androidx.room.Dao
     interface Dao {
 
-        @Query("SELECT * from rules WHERE (appStatus != '' OR packages != '') AND enabled = 1")
+        @Query("SELECT * from rules WHERE (packages != '') AND enabled = 1")
         fun checkVpnNeeded(): List<RuleEntity>
 
         @Query("SELECT * FROM rules ORDER BY userOrder")

+ 1 - 1
app/src/main/java/io/nekohasekai/sagernet/database/SagerDatabase.kt

@@ -34,7 +34,7 @@ import kotlinx.coroutines.launch
 
 @Database(
     entities = [ProxyGroup::class, ProxyEntity::class, RuleEntity::class, StatsEntity::class, KeyValuePair::class],
-    version = 11
+    version = 12
 )
 @TypeConverters(value = [KryoConverters::class, GsonConverters::class])
 @GenerateRoomMigrations

+ 1 - 9
app/src/main/java/io/nekohasekai/sagernet/fmt/ConfigBuilder.kt

@@ -28,7 +28,6 @@ import com.github.shadowsocks.plugin.PluginManager
 import com.google.gson.JsonSyntaxException
 import io.nekohasekai.sagernet.IPv6Mode
 import io.nekohasekai.sagernet.Key
-import io.nekohasekai.sagernet.bg.ForegroundDetectorService
 import io.nekohasekai.sagernet.bg.VpnService
 import io.nekohasekai.sagernet.database.DataStore
 import io.nekohasekai.sagernet.database.ProxyEntity
@@ -985,19 +984,15 @@ fun buildV2RayConfig(
         }
 
         val notVpn = DataStore.serviceMode != Key.MODE_VPN
-        val foregroundDetectorServiceStarted = ForegroundDetectorService::class.isRunning()
 
         for (rule in extraRules) {
-            if (rule.packages.isNotEmpty() || rule.appStatus.isNotEmpty()) {
+            if (rule.packages.isNotEmpty()) {
                 dumpUid = true
                 if (notVpn) {
                     alerts.add(0 to rule.displayName())
                     continue
                 }
             }
-            if (rule.appStatus.isNotEmpty() && !foregroundDetectorServiceStarted) {
-                alerts.add(1 to rule.displayName())
-            }
             routing.rules.add(RoutingObject.RuleObject().apply {
                 type = "field"
                 if (rule.packages.isNotEmpty()) {
@@ -1006,9 +1001,6 @@ fun buildV2RayConfig(
                         PackageCache[it]?.takeIf { uid -> uid >= 10000 } ?: 1000
                     }.toHashSet().toList()
                 }
-                if (rule.appStatus.isNotEmpty()) {
-                    appStatus = rule.appStatus
-                }
 
                 if (rule.domains.isNotBlank()) {
                     domain = rule.domains.split("\n")

+ 6 - 20
app/src/main/java/io/nekohasekai/sagernet/ui/MainActivity.kt

@@ -25,7 +25,6 @@ import android.content.Intent
 import android.net.Uri
 import android.os.Bundle
 import android.os.RemoteException
-import android.provider.Settings
 import android.view.KeyEvent
 import android.view.MenuItem
 import android.widget.Toast
@@ -406,30 +405,17 @@ class MainActivity : ThemedActivity(),
                     this, getString(R.string.route_need_vpn, routeName), Toast.LENGTH_SHORT
                 ).show()
             }
-            1 -> {
-                // need fds
-
-                MaterialAlertDialogBuilder(this).setTitle(R.string.foreground_detector)
-                    .setMessage(getString(R.string.route_need_fds, routeName))
-                    .setPositiveButton(R.string.enable) { _, _ ->
-                        startActivity(Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS))
-                    }
-                    .setNegativeButton(android.R.string.cancel, null)
-                    .show()
-            }
         }
     }
 
     val connection = SagerConnection(true)
-    override fun onServiceConnected(service: ISagerNetService) = changeState(
-        try {
-            BaseService.State.values()[service.state].also {
-                SagerNet.started = it.canStop
-            }
-        } catch (_: RemoteException) {
-            BaseService.State.Idle
+    override fun onServiceConnected(service: ISagerNetService) = changeState(try {
+        BaseService.State.values()[service.state].also {
+            SagerNet.started = it.canStop
         }
-    )
+    } catch (_: RemoteException) {
+        BaseService.State.Idle
+    })
 
     override fun onServiceDisconnected() = changeState(BaseService.State.Idle)
     override fun onBinderDied() {

+ 1 - 15
app/src/main/java/io/nekohasekai/sagernet/ui/RouteSettingsActivity.kt

@@ -41,7 +41,6 @@ import com.github.shadowsocks.plugin.Empty
 import com.github.shadowsocks.plugin.fragment.AlertDialogFragment
 import com.google.android.material.dialog.MaterialAlertDialogBuilder
 import com.takisoft.preferencex.PreferenceFragmentCompat
-import io.nekohasekai.sagernet.AppStatus
 import io.nekohasekai.sagernet.Key
 import io.nekohasekai.sagernet.R
 import io.nekohasekai.sagernet.database.DataStore
@@ -94,13 +93,6 @@ class RouteSettingsActivity(
         DataStore.routeReverse = reverse
         DataStore.routeRedirect = redirect
         DataStore.routePackages = packages.joinToString("\n")
-        DataStore.routeForegroundStatus = ""
-
-        for (status in appStatus) when (status) {
-            AppStatus.FOREGROUND, AppStatus.BACKGROUND -> {
-                DataStore.routeForegroundStatus = status
-            }
-        }
     }
 
     fun RuleEntity.serialize() {
@@ -122,12 +114,6 @@ class RouteSettingsActivity(
         reverse = DataStore.routeReverse
         redirect = DataStore.routeRedirect
         packages = DataStore.routePackages.split("\n").filter { it.isNotBlank() }
-        val routeForegroundStatus = DataStore.routeForegroundStatus
-        appStatus = if (routeForegroundStatus.isNotBlank()) {
-            listOf(routeForegroundStatus)
-        } else {
-            emptyList()
-        }
 
         if (DataStore.editingId == 0L) {
             enabled = true
@@ -136,7 +122,7 @@ class RouteSettingsActivity(
 
     fun needSave(): Boolean {
         if (!DataStore.dirty) return false
-        if (DataStore.routePackages.isBlank() && DataStore.routeForegroundStatus.isBlank() && DataStore.routeDomain.isBlank() && DataStore.routeIP.isBlank() && DataStore.routePort.isBlank() && DataStore.routeSourcePort.isBlank() && DataStore.routeNetwork.isBlank() && DataStore.routeSource.isBlank() && DataStore.routeProtocol.isBlank() && DataStore.routeAttrs.isBlank() && !(DataStore.routeReverse && DataStore.routeRedirect.isNotBlank())) {
+        if (DataStore.routePackages.isBlank() && DataStore.routeDomain.isBlank() && DataStore.routeIP.isBlank() && DataStore.routePort.isBlank() && DataStore.routeSourcePort.isBlank() && DataStore.routeNetwork.isBlank() && DataStore.routeSource.isBlank() && DataStore.routeProtocol.isBlank() && DataStore.routeAttrs.isBlank() && !(DataStore.routeReverse && DataStore.routeRedirect.isNotBlank())) {
             return false
         }
         return true

+ 0 - 12
app/src/main/res/values/arrays.xml

@@ -595,18 +595,6 @@
         <item>@string/group_order_by_delay</item>
     </string-array>
 
-    <string-array name="foreground_status">
-        <item tools:ignore="PrivateResource">@string/not_set</item>
-        <item>@string/foreground</item>
-        <item>@string/background</item>
-    </string-array>
-
-    <string-array name="foreground_status_value">
-        <item />
-        <item>foreground</item>
-        <item>background</item>
-    </string-array>
-
     <string-array name="ssh_auth_type">
         <item>@string/ssh_auth_type_none</item>
         <item>@string/password</item>

+ 0 - 8
app/src/main/res/values/strings.xml

@@ -429,15 +429,7 @@
     <string name="app_no_launcher">The app has no interface.</string>
     <string name="route_for">Rule for %s</string>
 
-    <string name="foreground_detector">Foreground detector</string>
-    <string name="foreground_detector_summary">This service provides support for routing rules based on the foreground state of apps. If it is not started, the result is always in the background.</string>
-
-    <string name="foreground_status">Foreground Status</string>
-    <string name="foreground">Foreground</string>
-    <string name="background">Background</string>
-
     <string name="route_need_vpn">Routing rule %s relies on the VPN to be in effect, so it is ignored.</string>
-    <string name="route_need_fds">Routing rule %s relies on the Foreground Detector Service to be in effect, but is not enabled.</string>
 
     <string name="app_traffic_statistics">App Traffic Statistics</string>
     <string name="profile_traffic_statistics">Profile Traffic Statistics</string>

+ 0 - 8
app/src/main/res/xml/foreground_detector_service.xml

@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
-    android:accessibilityEventTypes="typeWindowStateChanged"
-    android:canRetrieveWindowContent="false"
-    android:summary="@string/foreground_detector"
-    android:isAccessibilityTool="true"
-    android:settingsActivity="io.nekohasekai.sagernet.ui.MainActivity"
-    android:description="@string/foreground_detector_summary" />

+ 0 - 7
app/src/main/res/xml/route_preferences.xml

@@ -10,13 +10,6 @@
         app:icon="@drawable/ic_baseline_legend_toggle_24"
         app:key="routePackages"
         app:title="@string/apps" />
-    <com.takisoft.preferencex.SimpleMenuPreference
-        app:entries="@array/foreground_status"
-        app:entryValues="@array/foreground_status_value"
-        app:icon="@drawable/ic_baseline_low_priority_24"
-        app:key="routeForegroundStatus"
-        app:title="@string/foreground_status"
-        app:useSimpleSummaryProvider="true" />
     <PreferenceCategory app:title="@string/cag_route">
         <EditTextPreference
             app:icon="@drawable/ic_baseline_domain_24"

+ 2 - 2
sager.properties

@@ -1,6 +1,6 @@
 PACKAGE_NAME=io.nekohasekai.sagernet
-VERSION_NAME=0.6-beta09
-VERSION_CODE=127
+VERSION_NAME=0.6-beta10
+VERSION_CODE=128
 
 NAIVE_VERSION_NAME=96.0.4664.45-1
 NAIVE_VERSION=9