Refactor permission handling with PermissionRequester
This commit is contained in:
1 parent
2c47abc219
commit
8600fdba35
9 files changed
+163
-199
No files matched your search
@@ -0,0 +1,44 @@
|
||||
package com.v2ray.ang.dto
|
||||
|
||||
import android.Manifest
|
||||
import android.os.Build
|
||||
import androidx.annotation.RequiresApi
|
||||
|
||||
/**
|
||||
* Permission types used in the app, handling API level differences.
|
||||
*/
|
||||
enum class PermissionType {
|
||||
/** Camera permission (used for scanning QR codes) */
|
||||
CAMERA {
|
||||
override fun getPermission(): String = Manifest.permission.CAMERA
|
||||
},
|
||||
|
||||
/** Read storage / media permission (adapts to Android version) */
|
||||
READ_STORAGE {
|
||||
override fun getPermission(): String {
|
||||
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
Manifest.permission.READ_MEDIA_IMAGES
|
||||
} else {
|
||||
Manifest.permission.READ_EXTERNAL_STORAGE
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/** Notification permission (Android 13+) */
|
||||
POST_NOTIFICATIONS {
|
||||
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
|
||||
override fun getPermission(): String = Manifest.permission.POST_NOTIFICATIONS
|
||||
};
|
||||
|
||||
/** Return the actual Android permission string */
|
||||
abstract fun getPermission(): String
|
||||
|
||||
/** Return a human-readable label for the permission */
|
||||
fun getLabel(): String {
|
||||
return when (this) {
|
||||
CAMERA -> "Camera"
|
||||
READ_STORAGE -> "Storage"
|
||||
POST_NOTIFICATIONS -> "Notification"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,11 @@
|
||||
package com.v2ray.ang.ui
|
||||
|
||||
import android.Manifest
|
||||
import android.app.AlertDialog
|
||||
import android.content.ActivityNotFoundException
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.content.FileProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.tencent.mmkv.MMKV
|
||||
@@ -26,6 +22,7 @@ import com.v2ray.ang.extension.toastSuccess
|
||||
import com.v2ray.ang.handler.MmkvManager
|
||||
import com.v2ray.ang.handler.SettingsChangeManager
|
||||
import com.v2ray.ang.handler.WebDavManager
|
||||
import com.v2ray.ang.dto.PermissionType
|
||||
import com.v2ray.ang.util.ZipUtil
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
@@ -41,19 +38,6 @@ class BackupActivity : BaseActivity() {
|
||||
resources.getStringArray(R.array.config_backup_options)
|
||||
}
|
||||
|
||||
private val requestPermissionLauncher =
|
||||
registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted ->
|
||||
if (isGranted) {
|
||||
try {
|
||||
showFileChooser()
|
||||
} catch (e: Exception) {
|
||||
Log.e(AppConfig.TAG, "Failed to show file chooser", e)
|
||||
}
|
||||
} else {
|
||||
toast(R.string.toast_permission_denied)
|
||||
}
|
||||
}
|
||||
|
||||
private val createBackupFile =
|
||||
registerForActivityResult(ActivityResultContracts.CreateDocument("application/zip")) { uri ->
|
||||
if (uri != null) {
|
||||
@@ -219,20 +203,8 @@ class BackupActivity : BaseActivity() {
|
||||
}
|
||||
|
||||
private fun restoreViaLocal() {
|
||||
val permission =
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
Manifest.permission.READ_MEDIA_IMAGES
|
||||
} else {
|
||||
Manifest.permission.READ_EXTERNAL_STORAGE
|
||||
}
|
||||
if (ContextCompat.checkSelfPermission(this, permission) == PackageManager.PERMISSION_GRANTED) {
|
||||
try {
|
||||
showFileChooser()
|
||||
} catch (e: Exception) {
|
||||
Log.e(AppConfig.TAG, "Failed to show file chooser", e)
|
||||
}
|
||||
} else {
|
||||
requestPermissionLauncher.launch(permission)
|
||||
checkAndRequestPermission(PermissionType.READ_STORAGE) {
|
||||
showFileChooser()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,9 @@ import com.v2ray.ang.R
|
||||
import com.v2ray.ang.handler.SettingsManager
|
||||
import com.v2ray.ang.helper.CustomDividerItemDecoration
|
||||
import com.v2ray.ang.util.MyContextWrapper
|
||||
import com.v2ray.ang.dto.PermissionType
|
||||
import com.v2ray.ang.util.Utils
|
||||
import com.v2ray.ang.util.permissionRequester
|
||||
|
||||
|
||||
/**
|
||||
@@ -36,7 +38,7 @@ import com.v2ray.ang.util.Utils
|
||||
abstract class BaseActivity : AppCompatActivity() {
|
||||
// Progress indicator that sits at the bottom of the toolbar
|
||||
private var progressBar: LinearProgressIndicator? = null
|
||||
|
||||
protected val permissionRequester = permissionRequester()
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
supportActionBar?.setDisplayHomeAsUpEnabled(true)
|
||||
@@ -213,4 +215,18 @@ abstract class BaseActivity : AppCompatActivity() {
|
||||
return progressBar?.visibility == View.VISIBLE
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if permission is granted and request it if not.
|
||||
* Convenience method that delegates to permissionRequester.
|
||||
*
|
||||
* @param permissionType The type of permission to check and request
|
||||
* @param onGranted Callback to execute when permission is granted
|
||||
*/
|
||||
protected fun checkAndRequestPermission(
|
||||
permissionType: PermissionType,
|
||||
onGranted: () -> Unit
|
||||
) {
|
||||
permissionRequester.request(permissionType, onGranted)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,12 +1,9 @@
|
||||
package com.v2ray.ang.ui
|
||||
|
||||
import android.Manifest
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.content.res.ColorStateList
|
||||
import android.net.Uri
|
||||
import android.net.VpnService
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.KeyEvent
|
||||
@@ -35,6 +32,7 @@ import com.v2ray.ang.handler.MmkvManager
|
||||
import com.v2ray.ang.handler.SettingsChangeManager
|
||||
import com.v2ray.ang.handler.SettingsManager
|
||||
import com.v2ray.ang.handler.V2RayServiceManager
|
||||
import com.v2ray.ang.dto.PermissionType
|
||||
import com.v2ray.ang.util.Utils
|
||||
import com.v2ray.ang.viewmodel.MainViewModel
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
@@ -65,40 +63,6 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
|
||||
}
|
||||
}
|
||||
|
||||
// register activity result for requesting permission
|
||||
private val requestPermissionLauncher =
|
||||
registerForActivityResult(
|
||||
ActivityResultContracts.RequestPermission()
|
||||
) { isGranted: Boolean ->
|
||||
if (isGranted) {
|
||||
when (pendingAction) {
|
||||
Action.IMPORT_QR_CODE_CONFIG ->
|
||||
scanQRCodeForConfig.launch(Intent(this, ScannerActivity::class.java))
|
||||
|
||||
Action.READ_CONTENT_FROM_URI ->
|
||||
chooseFileForCustomConfig.launch(Intent.createChooser(Intent(Intent.ACTION_GET_CONTENT).apply {
|
||||
type = "*/*"
|
||||
addCategory(Intent.CATEGORY_OPENABLE)
|
||||
}, getString(R.string.title_file_chooser)))
|
||||
|
||||
Action.POST_NOTIFICATIONS -> {}
|
||||
else -> {}
|
||||
}
|
||||
} else {
|
||||
toast(R.string.toast_permission_denied)
|
||||
}
|
||||
pendingAction = Action.NONE
|
||||
}
|
||||
|
||||
private var pendingAction: Action = Action.NONE
|
||||
|
||||
enum class Action {
|
||||
NONE,
|
||||
IMPORT_QR_CODE_CONFIG,
|
||||
READ_CONTENT_FROM_URI,
|
||||
POST_NOTIFICATIONS
|
||||
}
|
||||
|
||||
private val chooseFileForCustomConfig = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
|
||||
val uri = it.data?.data
|
||||
if (it.resultCode == RESULT_OK && uri != null) {
|
||||
@@ -148,11 +112,7 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
|
||||
setupViewModel()
|
||||
mainViewModel.reloadServerList()
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
if (ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) {
|
||||
pendingAction = Action.POST_NOTIFICATIONS
|
||||
requestPermissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS)
|
||||
}
|
||||
checkAndRequestPermission(PermissionType.POST_NOTIFICATIONS) {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -416,12 +376,8 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
|
||||
* import config from qrcode
|
||||
*/
|
||||
private fun importQRcode(): Boolean {
|
||||
val permission = Manifest.permission.CAMERA
|
||||
if (ContextCompat.checkSelfPermission(this, permission) == PackageManager.PERMISSION_GRANTED) {
|
||||
checkAndRequestPermission(PermissionType.CAMERA) {
|
||||
scanQRCodeForConfig.launch(Intent(this, ScannerActivity::class.java))
|
||||
} else {
|
||||
pendingAction = Action.IMPORT_QR_CODE_CONFIG
|
||||
requestPermissionLauncher.launch(permission)
|
||||
}
|
||||
return true
|
||||
}
|
||||
@@ -475,7 +431,9 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
|
||||
*/
|
||||
private fun importConfigLocal(): Boolean {
|
||||
try {
|
||||
showFileChooser()
|
||||
checkAndRequestPermission(PermissionType.READ_STORAGE) {
|
||||
showFileChooser()
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.e(AppConfig.TAG, "Failed to import config from local file", e)
|
||||
return false
|
||||
@@ -596,40 +554,19 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
|
||||
intent.type = "*/*"
|
||||
intent.addCategory(Intent.CATEGORY_OPENABLE)
|
||||
|
||||
val permission = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
Manifest.permission.READ_MEDIA_IMAGES
|
||||
} else {
|
||||
Manifest.permission.READ_EXTERNAL_STORAGE
|
||||
}
|
||||
|
||||
if (ContextCompat.checkSelfPermission(this, permission) == PackageManager.PERMISSION_GRANTED) {
|
||||
pendingAction = Action.READ_CONTENT_FROM_URI
|
||||
chooseFileForCustomConfig.launch(Intent.createChooser(intent, getString(R.string.title_file_chooser)))
|
||||
} else {
|
||||
requestPermissionLauncher.launch(permission)
|
||||
}
|
||||
chooseFileForCustomConfig.launch(Intent.createChooser(intent, getString(R.string.title_file_chooser)))
|
||||
}
|
||||
|
||||
/**
|
||||
* read content from uri
|
||||
*/
|
||||
private fun readContentFromUri(uri: Uri) {
|
||||
val permission = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
Manifest.permission.READ_MEDIA_IMAGES
|
||||
} else {
|
||||
Manifest.permission.READ_EXTERNAL_STORAGE
|
||||
}
|
||||
|
||||
if (ContextCompat.checkSelfPermission(this, permission) == PackageManager.PERMISSION_GRANTED) {
|
||||
try {
|
||||
contentResolver.openInputStream(uri).use { input ->
|
||||
importBatchConfig(input?.bufferedReader()?.readText())
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.e(AppConfig.TAG, "Failed to read content from URI", e)
|
||||
try {
|
||||
contentResolver.openInputStream(uri).use { input ->
|
||||
importBatchConfig(input?.bufferedReader()?.readText())
|
||||
}
|
||||
} else {
|
||||
requestPermissionLauncher.launch(permission)
|
||||
} catch (e: Exception) {
|
||||
Log.e(AppConfig.TAG, "Failed to read content from URI", e)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package com.v2ray.ang.ui
|
||||
|
||||
import android.Manifest
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
@@ -16,13 +15,13 @@ import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import com.v2ray.ang.AppConfig
|
||||
import com.v2ray.ang.R
|
||||
import com.v2ray.ang.databinding.ActivityRoutingSettingBinding
|
||||
import com.v2ray.ang.extension.toast
|
||||
import com.v2ray.ang.extension.toastError
|
||||
import com.v2ray.ang.extension.toastSuccess
|
||||
import com.v2ray.ang.handler.MmkvManager
|
||||
import com.v2ray.ang.handler.SettingsManager
|
||||
import com.v2ray.ang.helper.SimpleItemTouchHelperCallback
|
||||
import com.v2ray.ang.util.JsonUtil
|
||||
import com.v2ray.ang.dto.PermissionType
|
||||
import com.v2ray.ang.util.Utils
|
||||
import com.v2ray.ang.viewmodel.RoutingSettingsViewModel
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
@@ -43,16 +42,6 @@ class RoutingSettingActivity : BaseActivity() {
|
||||
resources.getStringArray(R.array.preset_rulesets)
|
||||
}
|
||||
|
||||
private val requestCameraPermissionLauncher = registerForActivityResult(
|
||||
ActivityResultContracts.RequestPermission()
|
||||
) { isGranted: Boolean ->
|
||||
if (isGranted) {
|
||||
scanQRcodeForRulesets.launch(Intent(this, ScannerActivity::class.java))
|
||||
} else {
|
||||
toast(R.string.toast_permission_denied)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
//setContentView(binding.root)
|
||||
@@ -88,7 +77,7 @@ class RoutingSettingActivity : BaseActivity() {
|
||||
R.id.add_rule -> startActivity(Intent(this, RoutingEditActivity::class.java)).let { true }
|
||||
R.id.import_predefined_rulesets -> importPredefined().let { true }
|
||||
R.id.import_rulesets_from_clipboard -> importFromClipboard().let { true }
|
||||
R.id.import_rulesets_from_qrcode -> requestCameraPermissionLauncher.launch(Manifest.permission.CAMERA).let { true }
|
||||
R.id.import_rulesets_from_qrcode -> importQRcode()
|
||||
R.id.export_rulesets_to_clipboard -> export2Clipboard().let { true }
|
||||
else -> super.onOptionsItemSelected(item)
|
||||
}
|
||||
@@ -160,6 +149,13 @@ class RoutingSettingActivity : BaseActivity() {
|
||||
.show()
|
||||
}
|
||||
|
||||
private fun importQRcode(): Boolean {
|
||||
checkAndRequestPermission(PermissionType.CAMERA) {
|
||||
scanQRcodeForRulesets.launch(Intent(this, ScannerActivity::class.java))
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
private fun export2Clipboard() {
|
||||
val rulesetList = MmkvManager.decodeRoutingRulesets()
|
||||
if (rulesetList.isNullOrEmpty()) {
|
||||
|
||||
@@ -1,28 +1,16 @@
|
||||
package com.v2ray.ang.ui
|
||||
|
||||
import android.Manifest
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import com.v2ray.ang.R
|
||||
import com.v2ray.ang.extension.toast
|
||||
import com.v2ray.ang.extension.toastError
|
||||
import com.v2ray.ang.extension.toastSuccess
|
||||
import com.v2ray.ang.handler.AngConfigManager
|
||||
import com.v2ray.ang.dto.PermissionType
|
||||
|
||||
class ScScannerActivity : BaseActivity() {
|
||||
|
||||
private val requestCameraPermissionLauncher = registerForActivityResult(
|
||||
ActivityResultContracts.RequestPermission()
|
||||
) { isGranted: Boolean ->
|
||||
if (isGranted) {
|
||||
scanQRCode.launch(Intent(this, ScannerActivity::class.java))
|
||||
} else {
|
||||
toast(R.string.toast_permission_denied)
|
||||
finish()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentView(R.layout.activity_none)
|
||||
@@ -30,7 +18,9 @@ class ScScannerActivity : BaseActivity() {
|
||||
}
|
||||
|
||||
private fun importQRcode(): Boolean {
|
||||
requestCameraPermissionLauncher.launch(Manifest.permission.CAMERA)
|
||||
checkAndRequestPermission(PermissionType.CAMERA) {
|
||||
scanQRCode.launch(Intent(this, ScannerActivity::class.java))
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
@@ -1,21 +1,18 @@
|
||||
package com.v2ray.ang.ui
|
||||
|
||||
import android.Manifest
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.graphics.BitmapFactory
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.v2ray.ang.AppConfig
|
||||
import com.v2ray.ang.R
|
||||
import com.v2ray.ang.databinding.ActivityNoneBinding
|
||||
import com.v2ray.ang.extension.toast
|
||||
import com.v2ray.ang.handler.MmkvManager
|
||||
import com.v2ray.ang.dto.PermissionType
|
||||
import com.v2ray.ang.util.QRCodeDecoder
|
||||
import io.github.g00fy2.quickie.QRResult
|
||||
import io.github.g00fy2.quickie.ScanCustomCode
|
||||
@@ -47,17 +44,6 @@ class ScannerActivity : BaseActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
private val requestPermissionLauncher =
|
||||
registerForActivityResult(
|
||||
ActivityResultContracts.RequestPermission()
|
||||
) { isGranted: Boolean ->
|
||||
if (isGranted) {
|
||||
showFileChooser()
|
||||
} else {
|
||||
toast(R.string.toast_permission_denied)
|
||||
}
|
||||
}
|
||||
|
||||
public override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
@@ -106,16 +92,8 @@ class ScannerActivity : BaseActivity() {
|
||||
}
|
||||
|
||||
R.id.select_photo -> {
|
||||
val permission = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
Manifest.permission.READ_MEDIA_IMAGES
|
||||
} else {
|
||||
Manifest.permission.READ_EXTERNAL_STORAGE
|
||||
}
|
||||
|
||||
if (ContextCompat.checkSelfPermission(this, permission) == PackageManager.PERMISSION_GRANTED) {
|
||||
checkAndRequestPermission(PermissionType.READ_STORAGE) {
|
||||
showFileChooser()
|
||||
} else {
|
||||
requestPermissionLauncher.launch(permission)
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
package com.v2ray.ang.ui
|
||||
|
||||
import android.Manifest
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.AlertDialog
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.provider.OpenableColumns
|
||||
import android.util.Log
|
||||
@@ -24,6 +22,7 @@ import com.v2ray.ang.extension.toastError
|
||||
import com.v2ray.ang.extension.toastSuccess
|
||||
import com.v2ray.ang.handler.MmkvManager
|
||||
import com.v2ray.ang.handler.SettingsManager
|
||||
import com.v2ray.ang.dto.PermissionType
|
||||
import com.v2ray.ang.util.Utils
|
||||
import com.v2ray.ang.viewmodel.UserAssetViewModel
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
@@ -40,39 +39,6 @@ class UserAssetActivity : BaseActivity() {
|
||||
|
||||
val extDir by lazy { File(Utils.userAssetPath(this)) }
|
||||
|
||||
private val requestStoragePermissionLauncher = registerForActivityResult(
|
||||
ActivityResultContracts.RequestPermission()
|
||||
) { isGranted: Boolean ->
|
||||
if (isGranted) {
|
||||
val intent = Intent(Intent.ACTION_GET_CONTENT)
|
||||
intent.type = "*/*"
|
||||
intent.addCategory(Intent.CATEGORY_OPENABLE)
|
||||
|
||||
try {
|
||||
chooseFile.launch(
|
||||
Intent.createChooser(
|
||||
intent,
|
||||
getString(R.string.title_file_chooser)
|
||||
)
|
||||
)
|
||||
} catch (ex: android.content.ActivityNotFoundException) {
|
||||
toast(R.string.toast_require_file_manager)
|
||||
}
|
||||
} else {
|
||||
toast(R.string.toast_permission_denied)
|
||||
}
|
||||
}
|
||||
|
||||
private val requestCameraPermissionLauncher = registerForActivityResult(
|
||||
ActivityResultContracts.RequestPermission()
|
||||
) { isGranted: Boolean ->
|
||||
if (isGranted) {
|
||||
scanQRCodeForAssetURL.launch(Intent(this, ScannerActivity::class.java))
|
||||
} else {
|
||||
toast(R.string.toast_permission_denied)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
setContentViewWithToolbar(binding.root, showHomeAsUp = true, title = getString(R.string.title_user_asset_setting))
|
||||
@@ -125,14 +91,29 @@ class UserAssetActivity : BaseActivity() {
|
||||
}
|
||||
|
||||
private fun showFileChooser() {
|
||||
val permission = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
Manifest.permission.READ_MEDIA_IMAGES
|
||||
} else {
|
||||
Manifest.permission.READ_EXTERNAL_STORAGE
|
||||
checkAndRequestPermission(PermissionType.READ_STORAGE) {
|
||||
showFileChooser2()
|
||||
}
|
||||
requestStoragePermissionLauncher.launch(permission)
|
||||
}
|
||||
|
||||
private fun showFileChooser2() {
|
||||
val intent = Intent(Intent.ACTION_GET_CONTENT)
|
||||
intent.type = "*/*"
|
||||
intent.addCategory(Intent.CATEGORY_OPENABLE)
|
||||
|
||||
try {
|
||||
chooseFile.launch(
|
||||
Intent.createChooser(
|
||||
intent,
|
||||
getString(R.string.title_file_chooser)
|
||||
)
|
||||
)
|
||||
} catch (ex: android.content.ActivityNotFoundException) {
|
||||
toast(R.string.toast_require_file_manager)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private val chooseFile = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
|
||||
val uri = result.data?.data
|
||||
if (result.resultCode == RESULT_OK && uri != null) {
|
||||
@@ -182,7 +163,9 @@ class UserAssetActivity : BaseActivity() {
|
||||
}
|
||||
|
||||
private fun importAssetFromQRcode(): Boolean {
|
||||
requestCameraPermissionLauncher.launch(Manifest.permission.CAMERA)
|
||||
checkAndRequestPermission(PermissionType.CAMERA) {
|
||||
scanQRCodeForAssetURL.launch(Intent(this, ScannerActivity::class.java))
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
package com.v2ray.ang.util
|
||||
|
||||
import android.content.pm.PackageManager
|
||||
import androidx.activity.result.ActivityResultLauncher
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.v2ray.ang.R
|
||||
import com.v2ray.ang.dto.PermissionType
|
||||
import com.v2ray.ang.extension.toast
|
||||
|
||||
/**
|
||||
* Helper for requesting permissions.
|
||||
*/
|
||||
class PermissionRequester(private val activity: AppCompatActivity) {
|
||||
private var permissionCallback: ((Boolean) -> Unit)? = null
|
||||
|
||||
private val permissionLauncher: ActivityResultLauncher<String> =
|
||||
activity.registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted ->
|
||||
permissionCallback?.invoke(isGranted)
|
||||
permissionCallback = null
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the permission and request it if not granted.
|
||||
*
|
||||
* @param permissionType the type of permission
|
||||
* @param onGranted called when permission is granted (called immediately if already granted)
|
||||
*/
|
||||
fun request(permissionType: PermissionType, onGranted: () -> Unit) {
|
||||
val permission = permissionType.getPermission()
|
||||
if (ContextCompat.checkSelfPermission(activity, permission) == PackageManager.PERMISSION_GRANTED) {
|
||||
onGranted()
|
||||
} else {
|
||||
permissionCallback = { isGranted ->
|
||||
if (isGranted) {
|
||||
onGranted()
|
||||
} else {
|
||||
val message = "${activity.getString(R.string.toast_permission_denied)} ${permissionType.getLabel()}"
|
||||
activity.toast(message)
|
||||
}
|
||||
}
|
||||
permissionLauncher.launch(permission)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun AppCompatActivity.permissionRequester() = PermissionRequester(this)
|
||||
Reference in new issue
Block a user