mirror of
https://github.com/SagerNet/sing-box-for-android.git
synced 2025-04-06 13:27:38 +03:00
Improve location permission request and description
This commit is contained in:
parent
a35318ded2
commit
a4dbcd344a
3 changed files with 93 additions and 10 deletions
|
@ -5,7 +5,6 @@ import android.content.BroadcastReceiver
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.IntentFilter
|
import android.content.IntentFilter
|
||||||
import android.content.pm.PackageManager
|
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.IBinder
|
import android.os.IBinder
|
||||||
import android.os.ParcelFileDescriptor
|
import android.os.ParcelFileDescriptor
|
||||||
|
@ -27,6 +26,7 @@ import io.nekohasekai.sfa.constant.Alert
|
||||||
import io.nekohasekai.sfa.constant.Status
|
import io.nekohasekai.sfa.constant.Status
|
||||||
import io.nekohasekai.sfa.database.ProfileManager
|
import io.nekohasekai.sfa.database.ProfileManager
|
||||||
import io.nekohasekai.sfa.database.Settings
|
import io.nekohasekai.sfa.database.Settings
|
||||||
|
import io.nekohasekai.sfa.ktx.hasPermission
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.GlobalScope
|
import kotlinx.coroutines.GlobalScope
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
|
@ -174,10 +174,7 @@ class BoxService(
|
||||||
} else {
|
} else {
|
||||||
android.Manifest.permission.ACCESS_BACKGROUND_LOCATION
|
android.Manifest.permission.ACCESS_BACKGROUND_LOCATION
|
||||||
}
|
}
|
||||||
if (ContextCompat.checkSelfPermission(
|
if (!service.hasPermission(wifiPermission)) {
|
||||||
service, wifiPermission
|
|
||||||
) != PackageManager.PERMISSION_GRANTED
|
|
||||||
) {
|
|
||||||
newService.close()
|
newService.close()
|
||||||
stopAndAlert(Alert.RequestLocationPermission)
|
stopAndAlert(Alert.RequestLocationPermission)
|
||||||
return
|
return
|
||||||
|
|
9
app/src/main/java/io/nekohasekai/sfa/ktx/Context.kt
Normal file
9
app/src/main/java/io/nekohasekai/sfa/ktx/Context.kt
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
package io.nekohasekai.sfa.ktx
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.pm.PackageManager
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
|
|
||||||
|
fun Context.hasPermission(permission: String): Boolean {
|
||||||
|
return ContextCompat.checkSelfPermission(this, permission) == PackageManager.PERMISSION_GRANTED
|
||||||
|
}
|
|
@ -9,8 +9,10 @@ import android.net.VpnService
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.Process
|
import android.os.Process
|
||||||
|
import android.text.Html
|
||||||
import androidx.activity.result.contract.ActivityResultContract
|
import androidx.activity.result.contract.ActivityResultContract
|
||||||
import androidx.activity.result.contract.ActivityResultContracts
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
|
import androidx.annotation.RequiresApi
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
|
@ -34,6 +36,7 @@ import io.nekohasekai.sfa.database.Settings
|
||||||
import io.nekohasekai.sfa.database.TypedProfile
|
import io.nekohasekai.sfa.database.TypedProfile
|
||||||
import io.nekohasekai.sfa.databinding.ActivityMainBinding
|
import io.nekohasekai.sfa.databinding.ActivityMainBinding
|
||||||
import io.nekohasekai.sfa.ktx.errorDialogBuilder
|
import io.nekohasekai.sfa.ktx.errorDialogBuilder
|
||||||
|
import io.nekohasekai.sfa.ktx.hasPermission
|
||||||
import io.nekohasekai.sfa.ui.profile.NewProfileActivity
|
import io.nekohasekai.sfa.ui.profile.NewProfileActivity
|
||||||
import io.nekohasekai.sfa.ui.shared.AbstractActivity
|
import io.nekohasekai.sfa.ui.shared.AbstractActivity
|
||||||
import io.nekohasekai.sfa.vendor.Vendor
|
import io.nekohasekai.sfa.vendor.Vendor
|
||||||
|
@ -220,7 +223,26 @@ class MainActivity : AbstractActivity(), ServiceConnection.Callback {
|
||||||
}
|
}
|
||||||
|
|
||||||
private val locationPermissionLauncher =
|
private val locationPermissionLauncher =
|
||||||
registerForActivityResult(ActivityResultContracts.RequestPermission()) {}
|
registerForActivityResult(ActivityResultContracts.RequestPermission()) {
|
||||||
|
if (it) {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||||
|
requestBackgroundLocationPermission()
|
||||||
|
} else {
|
||||||
|
startService()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
showPermissionDeniedDescription()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val backgroundLocationPermissionLauncher =
|
||||||
|
registerForActivityResult(ActivityResultContracts.RequestPermission()) {
|
||||||
|
if (it) {
|
||||||
|
startService()
|
||||||
|
} else {
|
||||||
|
showPermissionDeniedDescription()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private val prepareLauncher = registerForActivityResult(PrepareService()) {
|
private val prepareLauncher = registerForActivityResult(PrepareService()) {
|
||||||
if (it) {
|
if (it) {
|
||||||
|
@ -305,24 +327,58 @@ class MainActivity : AbstractActivity(), ServiceConnection.Callback {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun requestLocationPermission() {
|
private fun requestLocationPermission() {
|
||||||
|
if (!hasPermission(Manifest.permission.ACCESS_FINE_LOCATION)) {
|
||||||
|
requestFineLocationPermission()
|
||||||
|
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||||
|
requestBackgroundLocationPermission()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun requestFineLocationPermission() {
|
||||||
|
val message = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||||
|
Html.fromHtml(
|
||||||
|
getString(R.string.location_permission_description),
|
||||||
|
Html.FROM_HTML_MODE_LEGACY
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
|
Html.fromHtml(getString(R.string.location_permission_description))
|
||||||
|
}
|
||||||
MaterialAlertDialogBuilder(this)
|
MaterialAlertDialogBuilder(this)
|
||||||
.setTitle(R.string.location_permission_title)
|
.setTitle(R.string.location_permission_title)
|
||||||
.setMessage(R.string.location_permission_description)
|
.setMessage(message)
|
||||||
.setPositiveButton(R.string.ok) { _, _ ->
|
.setPositiveButton(R.string.ok) { _, _ ->
|
||||||
requestLocationPermission0()
|
requestFineLocationPermission0()
|
||||||
}
|
}
|
||||||
.setCancelable(false)
|
.setCancelable(false)
|
||||||
.show()
|
.show()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun requestLocationPermission0() {
|
private fun requestFineLocationPermission0() {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||||
locationPermissionLauncher.launch(Manifest.permission.ACCESS_FINE_LOCATION)
|
locationPermissionLauncher.launch(Manifest.permission.ACCESS_FINE_LOCATION)
|
||||||
} else {
|
} else {
|
||||||
openPermissionSettings()
|
openPermissionSettings()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@RequiresApi(Build.VERSION_CODES.Q)
|
||||||
|
private fun requestBackgroundLocationPermission() {
|
||||||
|
MaterialAlertDialogBuilder(this)
|
||||||
|
.setTitle(R.string.location_permission_title)
|
||||||
|
.setMessage(
|
||||||
|
Html.fromHtml(
|
||||||
|
getString(R.string.location_permission_background_description),
|
||||||
|
Html.FROM_HTML_MODE_LEGACY
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.setPositiveButton(R.string.ok) { _, _ ->
|
||||||
|
backgroundLocationPermissionLauncher.launch(Manifest.permission.ACCESS_BACKGROUND_LOCATION)
|
||||||
|
}
|
||||||
|
.setCancelable(false)
|
||||||
|
.show()
|
||||||
|
}
|
||||||
|
|
||||||
private fun openPermissionSettings() {
|
private fun openPermissionSettings() {
|
||||||
if (!getSystemProperty("ro.miui.ui.version.name").isNullOrBlank()) {
|
if (!getSystemProperty("ro.miui.ui.version.name").isNullOrBlank()) {
|
||||||
val intent = Intent("miui.intent.action.APP_PERM_EDITOR")
|
val intent = Intent("miui.intent.action.APP_PERM_EDITOR")
|
||||||
|
@ -344,6 +400,27 @@ class MainActivity : AbstractActivity(), ServiceConnection.Callback {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun showPermissionDeniedDescription() {
|
||||||
|
val message = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||||
|
Html.fromHtml(
|
||||||
|
getString(R.string.location_permission_denied_description),
|
||||||
|
Html.FROM_HTML_MODE_LEGACY
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
|
Html.fromHtml(getString(R.string.location_permission_denied_description))
|
||||||
|
}
|
||||||
|
MaterialAlertDialogBuilder(this)
|
||||||
|
.setTitle(R.string.location_permission_title)
|
||||||
|
.setMessage(message)
|
||||||
|
.setPositiveButton(R.string.ok, null)
|
||||||
|
.setNeutralButton(R.string.open_settings) { _, _ ->
|
||||||
|
openPermissionSettings()
|
||||||
|
}
|
||||||
|
.setCancelable(false)
|
||||||
|
.show()
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressLint("PrivateApi")
|
@SuppressLint("PrivateApi")
|
||||||
fun getSystemProperty(key: String?): String? {
|
fun getSystemProperty(key: String?): String? {
|
||||||
try {
|
try {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue