pull/913/head
parent
e74a7cdb4f
commit
59cb14f0a1
@ -0,0 +1,20 @@ |
|||||||
|
package io.legado.app.help.permission |
||||||
|
|
||||||
|
import android.content.Context |
||||||
|
import android.content.Intent |
||||||
|
import androidx.appcompat.app.AppCompatActivity |
||||||
|
|
||||||
|
import java.lang.ref.WeakReference |
||||||
|
|
||||||
|
internal class ActivitySource(activity: AppCompatActivity) : RequestSource { |
||||||
|
|
||||||
|
private val actRef: WeakReference<AppCompatActivity> = WeakReference(activity) |
||||||
|
|
||||||
|
override val context: Context? |
||||||
|
get() = actRef.get() |
||||||
|
|
||||||
|
override fun startActivity(intent: Intent) { |
||||||
|
actRef.get()?.startActivity(intent) |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,19 @@ |
|||||||
|
package io.legado.app.help.permission |
||||||
|
|
||||||
|
import android.content.Context |
||||||
|
import android.content.Intent |
||||||
|
import androidx.fragment.app.Fragment |
||||||
|
|
||||||
|
import java.lang.ref.WeakReference |
||||||
|
|
||||||
|
internal class FragmentSource(fragment: Fragment) : RequestSource { |
||||||
|
|
||||||
|
private val fragRef: WeakReference<Fragment> = WeakReference(fragment) |
||||||
|
|
||||||
|
override val context: Context? |
||||||
|
get() = fragRef.get()?.requireContext() |
||||||
|
|
||||||
|
override fun startActivity(intent: Intent) { |
||||||
|
fragRef.get()?.startActivity(intent) |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,7 @@ |
|||||||
|
package io.legado.app.help.permission |
||||||
|
|
||||||
|
interface OnPermissionsDeniedCallback { |
||||||
|
|
||||||
|
fun onPermissionsDenied(requestCode: Int, deniedPermissions: Array<String>) |
||||||
|
|
||||||
|
} |
@ -0,0 +1,7 @@ |
|||||||
|
package io.legado.app.help.permission |
||||||
|
|
||||||
|
interface OnPermissionsGrantedCallback { |
||||||
|
|
||||||
|
fun onPermissionsGranted(requestCode: Int) |
||||||
|
|
||||||
|
} |
@ -0,0 +1,9 @@ |
|||||||
|
package io.legado.app.help.permission |
||||||
|
|
||||||
|
interface OnPermissionsResultCallback { |
||||||
|
|
||||||
|
fun onPermissionsGranted(requestCode: Int) |
||||||
|
|
||||||
|
fun onPermissionsDenied(requestCode: Int, deniedPermissions: Array<String>) |
||||||
|
|
||||||
|
} |
@ -0,0 +1,14 @@ |
|||||||
|
package io.legado.app.help.permission |
||||||
|
|
||||||
|
import android.content.Intent |
||||||
|
|
||||||
|
interface OnRequestPermissionsResultCallback { |
||||||
|
|
||||||
|
fun onRequestPermissionsResult( |
||||||
|
requestCode: Int, |
||||||
|
permissions: Array<String>, |
||||||
|
grantResults: IntArray |
||||||
|
) |
||||||
|
|
||||||
|
fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) |
||||||
|
} |
@ -0,0 +1,84 @@ |
|||||||
|
package io.legado.app.help.permission |
||||||
|
|
||||||
|
import android.content.Intent |
||||||
|
import android.net.Uri |
||||||
|
import android.os.Bundle |
||||||
|
import android.provider.Settings |
||||||
|
import android.view.KeyEvent |
||||||
|
import androidx.appcompat.app.AppCompatActivity |
||||||
|
import androidx.core.app.ActivityCompat |
||||||
|
import io.legado.app.R |
||||||
|
import io.legado.app.utils.toastOnUi |
||||||
|
|
||||||
|
class PermissionActivity : AppCompatActivity() { |
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) { |
||||||
|
super.onCreate(savedInstanceState) |
||||||
|
|
||||||
|
when (intent.getIntExtra(KEY_INPUT_REQUEST_TYPE, Request.TYPE_REQUEST_PERMISSION)) { |
||||||
|
Request.TYPE_REQUEST_PERMISSION//权限请求 |
||||||
|
-> { |
||||||
|
val requestCode = intent.getIntExtra(KEY_INPUT_PERMISSIONS_CODE, 1000) |
||||||
|
val permissions = intent.getStringArrayExtra(KEY_INPUT_PERMISSIONS) |
||||||
|
if (permissions != null) { |
||||||
|
ActivityCompat.requestPermissions(this, permissions, requestCode) |
||||||
|
} else { |
||||||
|
finish() |
||||||
|
} |
||||||
|
} |
||||||
|
Request.TYPE_REQUEST_SETTING//跳转到设置界面 |
||||||
|
-> try { |
||||||
|
val settingIntent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS) |
||||||
|
settingIntent.data = Uri.fromParts("package", packageName, null) |
||||||
|
startActivityForResult(settingIntent, Request.TYPE_REQUEST_SETTING) |
||||||
|
} catch (e: Exception) { |
||||||
|
toastOnUi(R.string.tip_cannot_jump_setting_page) |
||||||
|
finish() |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
override fun onRequestPermissionsResult( |
||||||
|
requestCode: Int, |
||||||
|
permissions: Array<String>, |
||||||
|
grantResults: IntArray |
||||||
|
) { |
||||||
|
super.onRequestPermissionsResult(requestCode, permissions, grantResults) |
||||||
|
RequestPlugins.sRequestCallback?.onRequestPermissionsResult( |
||||||
|
requestCode, |
||||||
|
permissions, |
||||||
|
grantResults |
||||||
|
) |
||||||
|
finish() |
||||||
|
} |
||||||
|
|
||||||
|
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { |
||||||
|
super.onActivityResult(requestCode, resultCode, data) |
||||||
|
RequestPlugins.sRequestCallback?.onActivityResult(requestCode, resultCode, data) |
||||||
|
finish() |
||||||
|
} |
||||||
|
|
||||||
|
override fun startActivity(intent: Intent) { |
||||||
|
super.startActivity(intent) |
||||||
|
overridePendingTransition(0, 0) |
||||||
|
} |
||||||
|
|
||||||
|
override fun finish() { |
||||||
|
super.finish() |
||||||
|
overridePendingTransition(0, 0) |
||||||
|
} |
||||||
|
|
||||||
|
override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean { |
||||||
|
return if (keyCode == KeyEvent.KEYCODE_BACK) { |
||||||
|
true |
||||||
|
} else super.onKeyDown(keyCode, event) |
||||||
|
} |
||||||
|
|
||||||
|
companion object { |
||||||
|
|
||||||
|
const val KEY_INPUT_REQUEST_TYPE = "KEY_INPUT_REQUEST_TYPE" |
||||||
|
const val KEY_INPUT_PERMISSIONS_CODE = "KEY_INPUT_PERMISSIONS_CODE" |
||||||
|
const val KEY_INPUT_PERMISSIONS = "KEY_INPUT_PERMISSIONS" |
||||||
|
} |
||||||
|
} |
@ -1,4 +1,4 @@ |
|||||||
package io.legado.app.constant |
package io.legado.app.help.permission |
||||||
|
|
||||||
@Suppress("unused") |
@Suppress("unused") |
||||||
object Permissions { |
object Permissions { |
@ -0,0 +1,94 @@ |
|||||||
|
package io.legado.app.help.permission |
||||||
|
|
||||||
|
import androidx.annotation.StringRes |
||||||
|
import androidx.appcompat.app.AppCompatActivity |
||||||
|
import androidx.fragment.app.Fragment |
||||||
|
import java.util.* |
||||||
|
|
||||||
|
@Suppress("unused") |
||||||
|
class PermissionsCompat private constructor() { |
||||||
|
|
||||||
|
private var request: Request? = null |
||||||
|
|
||||||
|
fun request() { |
||||||
|
RequestManager.pushRequest(request) |
||||||
|
} |
||||||
|
|
||||||
|
companion object { |
||||||
|
// 检查权限, 如果已经拥有返回 true |
||||||
|
fun check(activity: AppCompatActivity, vararg permissions: String): Boolean { |
||||||
|
val request = Request(activity) |
||||||
|
val pers = ArrayList<String>() |
||||||
|
pers.addAll(listOf(*permissions)) |
||||||
|
val data = request.getDeniedPermissions(pers.toTypedArray()) |
||||||
|
return data == null |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
class Builder { |
||||||
|
private val request: Request |
||||||
|
|
||||||
|
constructor(activity: AppCompatActivity) { |
||||||
|
request = Request(activity) |
||||||
|
} |
||||||
|
|
||||||
|
constructor(fragment: Fragment) { |
||||||
|
request = Request(fragment) |
||||||
|
} |
||||||
|
|
||||||
|
fun addPermissions(vararg permissions: String): Builder { |
||||||
|
request.addPermissions(*permissions) |
||||||
|
return this |
||||||
|
} |
||||||
|
|
||||||
|
fun requestCode(requestCode: Int): Builder { |
||||||
|
request.setRequestCode(requestCode) |
||||||
|
return this |
||||||
|
} |
||||||
|
|
||||||
|
fun onGranted(callback: (requestCode: Int) -> Unit): Builder { |
||||||
|
request.setOnGrantedCallback(object : OnPermissionsGrantedCallback { |
||||||
|
override fun onPermissionsGranted(requestCode: Int) { |
||||||
|
callback(requestCode) |
||||||
|
} |
||||||
|
}) |
||||||
|
return this |
||||||
|
} |
||||||
|
|
||||||
|
fun onDenied(callback: (requestCode: Int, deniedPermissions: Array<String>) -> Unit): Builder { |
||||||
|
request.setOnDeniedCallback(object : OnPermissionsDeniedCallback { |
||||||
|
override fun onPermissionsDenied( |
||||||
|
requestCode: Int, |
||||||
|
deniedPermissions: Array<String> |
||||||
|
) { |
||||||
|
callback(requestCode, deniedPermissions) |
||||||
|
} |
||||||
|
}) |
||||||
|
return this |
||||||
|
} |
||||||
|
|
||||||
|
fun rationale(rationale: CharSequence): Builder { |
||||||
|
request.setRationale(rationale) |
||||||
|
return this |
||||||
|
} |
||||||
|
|
||||||
|
fun rationale(@StringRes resId: Int): Builder { |
||||||
|
request.setRationale(resId) |
||||||
|
return this |
||||||
|
} |
||||||
|
|
||||||
|
fun build(): PermissionsCompat { |
||||||
|
val compat = PermissionsCompat() |
||||||
|
compat.request = request |
||||||
|
return compat |
||||||
|
} |
||||||
|
|
||||||
|
fun request(): PermissionsCompat { |
||||||
|
val compat = build() |
||||||
|
compat.request = request |
||||||
|
compat.request() |
||||||
|
return compat |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,204 @@ |
|||||||
|
package io.legado.app.help.permission |
||||||
|
|
||||||
|
import android.content.Intent |
||||||
|
import android.content.pm.PackageManager |
||||||
|
import android.os.Build |
||||||
|
import androidx.annotation.StringRes |
||||||
|
import androidx.appcompat.app.AlertDialog |
||||||
|
import androidx.appcompat.app.AppCompatActivity |
||||||
|
import androidx.core.content.ContextCompat |
||||||
|
import androidx.fragment.app.Fragment |
||||||
|
import io.legado.app.R |
||||||
|
import io.legado.app.utils.startActivity |
||||||
|
import java.util.* |
||||||
|
|
||||||
|
internal class Request : OnRequestPermissionsResultCallback { |
||||||
|
|
||||||
|
internal val requestTime: Long |
||||||
|
private var requestCode: Int = TYPE_REQUEST_PERMISSION |
||||||
|
private var source: RequestSource? = null |
||||||
|
private var permissions: ArrayList<String>? = null |
||||||
|
private var grantedCallback: OnPermissionsGrantedCallback? = null |
||||||
|
private var deniedCallback: OnPermissionsDeniedCallback? = null |
||||||
|
private var rationaleResId: Int = 0 |
||||||
|
private var rationale: CharSequence? = null |
||||||
|
|
||||||
|
private var rationaleDialog: AlertDialog? = null |
||||||
|
|
||||||
|
private val deniedPermissions: Array<String>? |
||||||
|
get() { |
||||||
|
return getDeniedPermissions(this.permissions?.toTypedArray()) |
||||||
|
} |
||||||
|
|
||||||
|
constructor(activity: AppCompatActivity) { |
||||||
|
source = ActivitySource(activity) |
||||||
|
permissions = ArrayList() |
||||||
|
requestTime = System.currentTimeMillis() |
||||||
|
} |
||||||
|
|
||||||
|
constructor(fragment: Fragment) { |
||||||
|
source = FragmentSource(fragment) |
||||||
|
permissions = ArrayList() |
||||||
|
requestTime = System.currentTimeMillis() |
||||||
|
} |
||||||
|
|
||||||
|
fun addPermissions(vararg permissions: String) { |
||||||
|
this.permissions?.addAll(listOf(*permissions)) |
||||||
|
} |
||||||
|
|
||||||
|
fun setRequestCode(requestCode: Int) { |
||||||
|
this.requestCode = requestCode |
||||||
|
} |
||||||
|
|
||||||
|
fun setOnGrantedCallback(callback: OnPermissionsGrantedCallback) { |
||||||
|
grantedCallback = callback |
||||||
|
} |
||||||
|
|
||||||
|
fun setOnDeniedCallback(callback: OnPermissionsDeniedCallback) { |
||||||
|
deniedCallback = callback |
||||||
|
} |
||||||
|
|
||||||
|
fun setRationale(@StringRes resId: Int) { |
||||||
|
rationaleResId = resId |
||||||
|
rationale = null |
||||||
|
} |
||||||
|
|
||||||
|
fun setRationale(rationale: CharSequence) { |
||||||
|
this.rationale = rationale |
||||||
|
rationaleResId = 0 |
||||||
|
} |
||||||
|
|
||||||
|
fun start() { |
||||||
|
RequestPlugins.setOnRequestPermissionsCallback(this) |
||||||
|
|
||||||
|
val deniedPermissions = deniedPermissions |
||||||
|
|
||||||
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { |
||||||
|
if (deniedPermissions == null) { |
||||||
|
onPermissionsGranted(requestCode) |
||||||
|
} else { |
||||||
|
val rationale = |
||||||
|
if (rationaleResId != 0) source?.context?.getText(rationaleResId) else rationale |
||||||
|
if (rationale != null) { |
||||||
|
showSettingDialog(rationale) { |
||||||
|
onPermissionsDenied( |
||||||
|
requestCode, |
||||||
|
deniedPermissions |
||||||
|
) |
||||||
|
} |
||||||
|
} else { |
||||||
|
onPermissionsDenied(requestCode, deniedPermissions) |
||||||
|
} |
||||||
|
} |
||||||
|
} else { |
||||||
|
if (deniedPermissions != null) { |
||||||
|
source?.context?.startActivity<PermissionActivity> { |
||||||
|
putExtra(PermissionActivity.KEY_INPUT_REQUEST_TYPE, TYPE_REQUEST_PERMISSION) |
||||||
|
putExtra(PermissionActivity.KEY_INPUT_PERMISSIONS_CODE, requestCode) |
||||||
|
putExtra(PermissionActivity.KEY_INPUT_PERMISSIONS, deniedPermissions) |
||||||
|
} |
||||||
|
} else { |
||||||
|
onPermissionsGranted(requestCode) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
fun clear() { |
||||||
|
grantedCallback = null |
||||||
|
deniedCallback = null |
||||||
|
} |
||||||
|
|
||||||
|
fun getDeniedPermissions(permissions: Array<String>?): Array<String>? { |
||||||
|
if (permissions != null) { |
||||||
|
val deniedPermissionList = ArrayList<String>() |
||||||
|
for (permission in permissions) { |
||||||
|
if (source?.context?.let { |
||||||
|
ContextCompat.checkSelfPermission( |
||||||
|
it, |
||||||
|
permission |
||||||
|
) |
||||||
|
} != PackageManager.PERMISSION_GRANTED |
||||||
|
) { |
||||||
|
deniedPermissionList.add(permission) |
||||||
|
} |
||||||
|
} |
||||||
|
val size = deniedPermissionList.size |
||||||
|
if (size > 0) { |
||||||
|
return deniedPermissionList.toTypedArray() |
||||||
|
} |
||||||
|
} |
||||||
|
return null |
||||||
|
} |
||||||
|
|
||||||
|
private fun showSettingDialog(rationale: CharSequence, cancel: () -> Unit) { |
||||||
|
rationaleDialog?.dismiss() |
||||||
|
source?.context?.let { |
||||||
|
runCatching { |
||||||
|
rationaleDialog = AlertDialog.Builder(it) |
||||||
|
.setTitle(R.string.dialog_title) |
||||||
|
.setMessage(rationale) |
||||||
|
.setPositiveButton(R.string.dialog_setting) { _, _ -> |
||||||
|
it.startActivity<PermissionActivity> { |
||||||
|
putExtra( |
||||||
|
PermissionActivity.KEY_INPUT_REQUEST_TYPE, |
||||||
|
TYPE_REQUEST_SETTING |
||||||
|
) |
||||||
|
} |
||||||
|
} |
||||||
|
.setNegativeButton(R.string.dialog_cancel) { _, _ -> cancel() } |
||||||
|
.show() |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private fun onPermissionsGranted(requestCode: Int) { |
||||||
|
try { |
||||||
|
grantedCallback?.onPermissionsGranted(requestCode) |
||||||
|
} catch (ignore: Exception) { |
||||||
|
} |
||||||
|
|
||||||
|
RequestPlugins.sResultCallback?.onPermissionsGranted(requestCode) |
||||||
|
} |
||||||
|
|
||||||
|
private fun onPermissionsDenied(requestCode: Int, deniedPermissions: Array<String>) { |
||||||
|
try { |
||||||
|
deniedCallback?.onPermissionsDenied(requestCode, deniedPermissions) |
||||||
|
} catch (ignore: Exception) { |
||||||
|
} |
||||||
|
|
||||||
|
RequestPlugins.sResultCallback?.onPermissionsDenied(requestCode, deniedPermissions) |
||||||
|
} |
||||||
|
|
||||||
|
override fun onRequestPermissionsResult( |
||||||
|
requestCode: Int, |
||||||
|
permissions: Array<String>, |
||||||
|
grantResults: IntArray |
||||||
|
) { |
||||||
|
val deniedPermissions = getDeniedPermissions(permissions) |
||||||
|
if (deniedPermissions != null) { |
||||||
|
val rationale = |
||||||
|
if (rationaleResId != 0) source?.context?.getText(rationaleResId) else rationale |
||||||
|
if (rationale != null) { |
||||||
|
showSettingDialog(rationale) { onPermissionsDenied(requestCode, deniedPermissions) } |
||||||
|
} else { |
||||||
|
onPermissionsDenied(requestCode, deniedPermissions) |
||||||
|
} |
||||||
|
} else { |
||||||
|
onPermissionsGranted(requestCode) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { |
||||||
|
val deniedPermissions = deniedPermissions |
||||||
|
if (deniedPermissions == null) { |
||||||
|
onPermissionsGranted(this.requestCode) |
||||||
|
} else { |
||||||
|
onPermissionsDenied(this.requestCode, deniedPermissions) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
companion object { |
||||||
|
const val TYPE_REQUEST_PERMISSION = 1 |
||||||
|
const val TYPE_REQUEST_SETTING = 2 |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,69 @@ |
|||||||
|
package io.legado.app.help.permission |
||||||
|
|
||||||
|
import android.os.Handler |
||||||
|
import android.os.Looper |
||||||
|
import java.util.* |
||||||
|
|
||||||
|
internal object RequestManager : OnPermissionsResultCallback { |
||||||
|
|
||||||
|
private var requests: Stack<Request>? = null |
||||||
|
private var request: Request? = null |
||||||
|
|
||||||
|
private val handler = Handler(Looper.getMainLooper()) |
||||||
|
|
||||||
|
private val requestRunnable = Runnable { |
||||||
|
request?.start() |
||||||
|
} |
||||||
|
|
||||||
|
private val isCurrentRequestInvalid: Boolean |
||||||
|
get() = request?.let { System.currentTimeMillis() - it.requestTime > 5 * 1000L } ?: true |
||||||
|
|
||||||
|
init { |
||||||
|
RequestPlugins.setOnPermissionsResultCallback(this) |
||||||
|
} |
||||||
|
|
||||||
|
fun pushRequest(request: Request?) { |
||||||
|
if (request == null) return |
||||||
|
|
||||||
|
if (requests == null) { |
||||||
|
requests = Stack() |
||||||
|
} |
||||||
|
|
||||||
|
requests?.let { |
||||||
|
val index = it.indexOf(request) |
||||||
|
if (index >= 0) { |
||||||
|
val to = it.size - 1 |
||||||
|
if (index != to) { |
||||||
|
@Suppress("NULLABILITY_MISMATCH_BASED_ON_JAVA_ANNOTATIONS") |
||||||
|
Collections.swap(requests, index, to) |
||||||
|
} |
||||||
|
} else { |
||||||
|
it.push(request) |
||||||
|
} |
||||||
|
|
||||||
|
if (!it.empty() && isCurrentRequestInvalid) { |
||||||
|
this.request = it.pop() |
||||||
|
handler.post(requestRunnable) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private fun startNextRequest() { |
||||||
|
request?.clear() |
||||||
|
request = null |
||||||
|
|
||||||
|
requests?.let { |
||||||
|
request = if (it.empty()) null else it.pop() |
||||||
|
request?.let { handler.post(requestRunnable) } |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
override fun onPermissionsGranted(requestCode: Int) { |
||||||
|
startNextRequest() |
||||||
|
} |
||||||
|
|
||||||
|
override fun onPermissionsDenied(requestCode: Int, deniedPermissions: Array<String>) { |
||||||
|
startNextRequest() |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,20 @@ |
|||||||
|
package io.legado.app.help.permission |
||||||
|
|
||||||
|
internal object RequestPlugins { |
||||||
|
|
||||||
|
@Volatile |
||||||
|
var sRequestCallback: OnRequestPermissionsResultCallback? = null |
||||||
|
|
||||||
|
@Volatile |
||||||
|
var sResultCallback: OnPermissionsResultCallback? = null |
||||||
|
|
||||||
|
fun setOnRequestPermissionsCallback(callback: OnRequestPermissionsResultCallback) { |
||||||
|
sRequestCallback = callback |
||||||
|
} |
||||||
|
|
||||||
|
fun setOnPermissionsResultCallback(callback: OnPermissionsResultCallback) { |
||||||
|
sResultCallback = callback |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
} |
@ -0,0 +1,12 @@ |
|||||||
|
package io.legado.app.help.permission |
||||||
|
|
||||||
|
import android.content.Context |
||||||
|
import android.content.Intent |
||||||
|
|
||||||
|
interface RequestSource { |
||||||
|
|
||||||
|
val context: Context? |
||||||
|
|
||||||
|
fun startActivity(intent: Intent) |
||||||
|
|
||||||
|
} |
Loading…
Reference in new issue