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