diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 3bb3cf3..915fffb 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -12,7 +12,7 @@
-
+
@@ -156,7 +156,7 @@
+ android:foregroundServiceType="specialUse">
diff --git a/app/src/main/java/io/nekohasekai/sfa/bg/BoxService.kt b/app/src/main/java/io/nekohasekai/sfa/bg/BoxService.kt
index 27343ce..fe7f1d8 100644
--- a/app/src/main/java/io/nekohasekai/sfa/bg/BoxService.kt
+++ b/app/src/main/java/io/nekohasekai/sfa/bg/BoxService.kt
@@ -5,6 +5,7 @@ import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
+import android.content.pm.PackageManager
import android.os.Build
import android.os.IBinder
import android.os.ParcelFileDescriptor
@@ -169,6 +170,23 @@ class BoxService(
}
newService.start()
+
+ if (newService.needWIFIState()) {
+ val wifiPermission = if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
+ android.Manifest.permission.ACCESS_FINE_LOCATION
+ } else {
+ android.Manifest.permission.ACCESS_BACKGROUND_LOCATION
+ }
+ if (ContextCompat.checkSelfPermission(
+ service, wifiPermission
+ ) != PackageManager.PERMISSION_GRANTED
+ ) {
+ newService.close()
+ stopAndAlert(Alert.RequestLocationPermission)
+ return
+ }
+ }
+
boxService = newService
commandServer?.setService(boxService)
status.postValue(Status.Started)
diff --git a/app/src/main/java/io/nekohasekai/sfa/constant/Alert.kt b/app/src/main/java/io/nekohasekai/sfa/constant/Alert.kt
index 2c2b439..ce0c418 100644
--- a/app/src/main/java/io/nekohasekai/sfa/constant/Alert.kt
+++ b/app/src/main/java/io/nekohasekai/sfa/constant/Alert.kt
@@ -3,6 +3,7 @@ package io.nekohasekai.sfa.constant
enum class Alert {
RequestVPNPermission,
RequestNotificationPermission,
+ RequestLocationPermission,
EmptyConfiguration,
StartCommandServer,
CreateService,
diff --git a/app/src/main/java/io/nekohasekai/sfa/ui/MainActivity.kt b/app/src/main/java/io/nekohasekai/sfa/ui/MainActivity.kt
index 5a27f92..7b520e7 100644
--- a/app/src/main/java/io/nekohasekai/sfa/ui/MainActivity.kt
+++ b/app/src/main/java/io/nekohasekai/sfa/ui/MainActivity.kt
@@ -4,12 +4,13 @@ import android.Manifest
import android.annotation.SuppressLint
import android.content.Context
import android.content.Intent
-import android.content.pm.PackageManager
+import android.net.Uri
import android.net.VpnService
+import android.os.Build
import android.os.Bundle
+import android.os.Process
import androidx.activity.result.contract.ActivityResultContract
import androidx.activity.result.contract.ActivityResultContracts
-import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.lifecycleScope
@@ -188,38 +189,12 @@ class MainActivity : AbstractActivity(), ServiceConnection.Callback {
}
@SuppressLint("NewApi")
- fun startService(skipRequestLocation: Boolean = false) {
+ fun startService() {
if (!ServiceNotification.checkPermission()) {
notificationPermissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS)
return
}
- // MIUI always return false for shouldShowRequestPermissionRationale
- if (!skipRequestLocation && ContextCompat.checkSelfPermission(
- this, Manifest.permission.ACCESS_FINE_LOCATION
- ) != PackageManager.PERMISSION_GRANTED
- ) {
- if (!ActivityCompat.shouldShowRequestPermissionRationale(
- this, Manifest.permission.ACCESS_FINE_LOCATION
- )
- ) {
- MaterialAlertDialogBuilder(this)
- .setTitle(R.string.location_permission_title)
- .setMessage(R.string.location_permission_description)
- .setPositiveButton(R.string.ok) { _, _ ->
- locationPermissionLauncher.launch(
- arrayOf(
- Manifest.permission.ACCESS_COARSE_LOCATION,
- Manifest.permission.ACCESS_FINE_LOCATION,
- )
- )
- }
- .setCancelable(false)
- .show()
- return
- }
- }
-
lifecycleScope.launch(Dispatchers.IO) {
if (Settings.rebuildServiceMode()) {
reconnect()
@@ -246,11 +221,8 @@ class MainActivity : AbstractActivity(), ServiceConnection.Callback {
}
}
- private val locationPermissionLauncher = registerForActivityResult(
- ActivityResultContracts.RequestMultiplePermissions()
- ) {
- startService(true)
- }
+ private val locationPermissionLauncher =
+ registerForActivityResult(ActivityResultContracts.RequestPermission()) {}
private val prepareLauncher = registerForActivityResult(PrepareService()) {
if (it) {
@@ -290,6 +262,14 @@ class MainActivity : AbstractActivity(), ServiceConnection.Callback {
}
override fun onServiceAlert(type: Alert, message: String?) {
+ when (type) {
+ Alert.RequestLocationPermission -> {
+ return requestLocationPermission()
+ }
+
+ else -> {}
+ }
+
val builder = MaterialAlertDialogBuilder(this)
builder.setPositiveButton(R.string.ok, null)
when (type) {
@@ -320,10 +300,62 @@ class MainActivity : AbstractActivity(), ServiceConnection.Callback {
builder.setMessage(message)
}
+
+ else -> {}
}
builder.show()
}
+ private fun requestLocationPermission() {
+ MaterialAlertDialogBuilder(this)
+ .setTitle(R.string.location_permission_title)
+ .setMessage(R.string.location_permission_description)
+ .setPositiveButton(R.string.ok) { _, _ ->
+ requestLocationPermission0()
+ }
+ .setCancelable(false)
+ .show()
+ }
+
+ private fun requestLocationPermission0() {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
+ locationPermissionLauncher.launch(Manifest.permission.ACCESS_FINE_LOCATION)
+ } else {
+ openPermissionSettings()
+ }
+ }
+
+ private fun openPermissionSettings() {
+ if (!getSystemProperty("ro.miui.ui.version.name").isNullOrBlank()) {
+ val intent = Intent("miui.intent.action.APP_PERM_EDITOR")
+ intent.putExtra("extra_package_uid", Process.myUid())
+ intent.putExtra("extra_pkgname", packageName)
+ try {
+ startActivity(intent)
+ return
+ } catch (ignored: Exception) {
+ }
+ }
+
+ try {
+ val intent = Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
+ intent.data = Uri.parse("package:$packageName")
+ startActivity(intent)
+ } catch (e: Exception) {
+ errorDialogBuilder(e).show()
+ }
+ }
+
+ @SuppressLint("PrivateApi")
+ fun getSystemProperty(key: String?): String? {
+ try {
+ return Class.forName("android.os.SystemProperties").getMethod("get", String::class.java)
+ .invoke(null, key) as String
+ } catch (ignored: Exception) {
+ }
+ return null
+ }
+
private var paused = false
override fun onPause() {
super.onPause()
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index f0c5846..b96d2f0 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -146,6 +146,6 @@
Other methods
Start
Location permission
- sing-box uses the location permission to provide `wifi_ssid` and `wifi_bssid` routing rule entries, deny it if you don\'t need this feature.
+ sing-box uses the **background location** permission to implement the `wifi_ssid` and `wifi_bssid` routing rule items that **you are using**.
\ No newline at end of file