parent
514dd5173a
commit
2c8a0c330a
@ -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,5 @@ |
||||
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,11 @@ |
||||
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,77 @@ |
||||
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 org.jetbrains.anko.toast |
||||
|
||||
class PermissionActivity : AppCompatActivity() { |
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) { |
||||
super.onCreate(savedInstanceState) |
||||
val intent = intent |
||||
|
||||
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) { |
||||
toast(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" |
||||
} |
||||
} |
@ -0,0 +1,72 @@ |
||||
package io.legado.app.help.permission |
||||
|
||||
object Permissions { |
||||
|
||||
const val READ_CALENDAR = "android.permission.READ_CALENDAR" |
||||
const val WRITE_CALENDAR = "android.permission.WRITE_CALENDAR" |
||||
|
||||
const val CAMERA = "android.permission.CAMERA" |
||||
|
||||
const val READ_CONTACTS = "android.permission.READ_CONTACTS" |
||||
const val WRITE_CONTACTS = "android.permission.WRITE_CONTACTS" |
||||
const val GET_ACCOUNTS = "android.permission.GET_ACCOUNTS" |
||||
|
||||
const val ACCESS_FINE_LOCATION = "android.permission.ACCESS_FINE_LOCATION" |
||||
const val ACCESS_COARSE_LOCATION = "android.permission.ACCESS_COARSE_LOCATION" |
||||
|
||||
const val RECORD_AUDIO = "android.permission.RECORD_AUDIO" |
||||
|
||||
const val READ_PHONE_STATE = "android.permission.READ_PHONE_STATE" |
||||
const val CALL_PHONE = "android.permission.CALL_PHONE" |
||||
const val READ_CALL_LOG = "android.permission.READ_CALL_LOG" |
||||
const val WRITE_CALL_LOG = "android.permission.WRITE_CALL_LOG" |
||||
const val ADD_VOICEMAIL = "com.android.voicemail.permission.ADD_VOICEMAIL" |
||||
const val USE_SIP = "android.permission.USE_SIP" |
||||
const val PROCESS_OUTGOING_CALLS = "android.permission.PROCESS_OUTGOING_CALLS" |
||||
|
||||
const val BODY_SENSORS = "android.permission.BODY_SENSORS" |
||||
|
||||
const val SEND_SMS = "android.permission.SEND_SMS" |
||||
const val RECEIVE_SMS = "android.permission.RECEIVE_SMS" |
||||
const val READ_SMS = "android.permission.READ_SMS" |
||||
const val RECEIVE_WAP_PUSH = "android.permission.RECEIVE_WAP_PUSH" |
||||
const val RECEIVE_MMS = "android.permission.RECEIVE_MMS" |
||||
|
||||
const val READ_EXTERNAL_STORAGE = "android.permission.READ_EXTERNAL_STORAGE" |
||||
const val WRITE_EXTERNAL_STORAGE = "android.permission.WRITE_EXTERNAL_STORAGE" |
||||
|
||||
object Group { |
||||
val CALENDAR = arrayOf(READ_CALENDAR, WRITE_CALENDAR) |
||||
|
||||
val CAMERA = arrayOf(Permissions.CAMERA) |
||||
|
||||
val CONTACTS = arrayOf(READ_CONTACTS, WRITE_CONTACTS, GET_ACCOUNTS) |
||||
|
||||
val LOCATION = arrayOf(ACCESS_FINE_LOCATION, ACCESS_COARSE_LOCATION) |
||||
|
||||
val MICROPHONE = arrayOf(RECORD_AUDIO) |
||||
|
||||
val PHONE = arrayOf( |
||||
READ_PHONE_STATE, |
||||
CALL_PHONE, |
||||
READ_CALL_LOG, |
||||
WRITE_CALL_LOG, |
||||
ADD_VOICEMAIL, |
||||
USE_SIP, |
||||
PROCESS_OUTGOING_CALLS |
||||
) |
||||
|
||||
val SENSORS = arrayOf(BODY_SENSORS) |
||||
|
||||
val SMS = arrayOf( |
||||
SEND_SMS, |
||||
RECEIVE_SMS, |
||||
READ_SMS, |
||||
RECEIVE_WAP_PUSH, |
||||
RECEIVE_MMS |
||||
) |
||||
|
||||
val STORAGE = arrayOf(READ_EXTERNAL_STORAGE, WRITE_EXTERNAL_STORAGE) |
||||
} |
||||
|
||||
} |
@ -0,0 +1,78 @@ |
||||
package io.legado.app.help.permission |
||||
|
||||
import androidx.annotation.StringRes |
||||
import androidx.appcompat.app.AppCompatActivity |
||||
import androidx.fragment.app.Fragment |
||||
|
||||
class PermissionsCompat private constructor() { |
||||
|
||||
private var mRequest: Request? = null |
||||
|
||||
fun request() { |
||||
RequestManager.pushRequest(mRequest) |
||||
} |
||||
|
||||
class Builder { |
||||
private val mRequest: Request |
||||
|
||||
constructor(activity: AppCompatActivity) { |
||||
mRequest = Request(activity) |
||||
} |
||||
|
||||
constructor(fragment: Fragment) { |
||||
mRequest = Request(fragment) |
||||
} |
||||
|
||||
fun addPermissions(vararg permissions: String): Builder { |
||||
mRequest.addPermissions(*permissions) |
||||
return this |
||||
} |
||||
|
||||
fun requestCode(requestCode: Int): Builder { |
||||
mRequest.setRequestCode(requestCode) |
||||
return this |
||||
} |
||||
|
||||
fun onGranted(callback: (requestCode: Int) -> Unit): Builder { |
||||
mRequest.setOnGrantedCallback(object : OnPermissionsGrantedCallback { |
||||
override fun onPermissionsGranted(requestCode: Int) { |
||||
callback(requestCode) |
||||
} |
||||
}) |
||||
return this |
||||
} |
||||
|
||||
fun onDenied(callback: (requestCode: Int, deniedPermissions: Array<String>) -> Unit): Builder { |
||||
mRequest.setOnDeniedCallback(object : OnPermissionsDeniedCallback { |
||||
override fun onPermissionsDenied(requestCode: Int, deniedPermissions: Array<String>) { |
||||
callback(requestCode, deniedPermissions) |
||||
} |
||||
}) |
||||
return this |
||||
} |
||||
|
||||
fun rationale(rationale: CharSequence): Builder { |
||||
mRequest.setRationale(rationale) |
||||
return this |
||||
} |
||||
|
||||
fun rationale(@StringRes resId: Int): Builder { |
||||
mRequest.setRationale(resId) |
||||
return this |
||||
} |
||||
|
||||
fun build(): PermissionsCompat { |
||||
val compat = PermissionsCompat() |
||||
compat.mRequest = mRequest |
||||
return compat |
||||
} |
||||
|
||||
fun request(): PermissionsCompat { |
||||
val compat = build() |
||||
compat.mRequest = mRequest |
||||
compat.request() |
||||
return compat |
||||
} |
||||
} |
||||
|
||||
} |
@ -0,0 +1,199 @@ |
||||
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 org.jetbrains.anko.startActivity |
||||
import java.util.* |
||||
|
||||
internal class Request : OnRequestPermissionsResultCallback { |
||||
|
||||
var startTime: Long = 0 |
||||
private set |
||||
private var requestCode: Int = 0 |
||||
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() { |
||||
val permissions: Array<String>? |
||||
val size = this.permissions?.size ?: 0 |
||||
if (size > 0) { |
||||
permissions = this.permissions?.toTypedArray() |
||||
} else { |
||||
permissions = null |
||||
} |
||||
return getDeniedPermissions(permissions) |
||||
} |
||||
|
||||
constructor(activity: AppCompatActivity) { |
||||
source = ActivitySource(activity) |
||||
permissions = ArrayList() |
||||
} |
||||
|
||||
constructor(fragment: Fragment) { |
||||
source = FragmentSource(fragment) |
||||
permissions = ArrayList() |
||||
} |
||||
|
||||
fun addPermissions(vararg permissions: String) { |
||||
this.permissions?.addAll(Arrays.asList(*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>( |
||||
Pair(PermissionActivity.KEY_INPUT_REQUEST_TYPE, TYPE_REQUEST_PERMISSION), |
||||
Pair(PermissionActivity.KEY_INPUT_PERMISSIONS_CODE, requestCode), |
||||
Pair(PermissionActivity.KEY_INPUT_PERMISSIONS, deniedPermissions) |
||||
) |
||||
} else { |
||||
onPermissionsGranted(requestCode) |
||||
} |
||||
} |
||||
|
||||
startTime = System.currentTimeMillis() |
||||
} |
||||
|
||||
fun clear() { |
||||
grantedCallback = null |
||||
deniedCallback = null |
||||
} |
||||
|
||||
private 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 { |
||||
rationaleDialog = AlertDialog.Builder(it) |
||||
.setTitle(R.string.dialog_title) |
||||
.setMessage(rationale) |
||||
.setPositiveButton(R.string.dialog_setting) { _, _ -> |
||||
it.startActivity<PermissionActivity>( |
||||
Pair( |
||||
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,67 @@ |
||||
package io.legado.app.help.permission |
||||
|
||||
import android.os.Handler |
||||
import java.util.* |
||||
|
||||
internal object RequestManager : OnPermissionsResultCallback { |
||||
|
||||
private var requests: Stack<Request>? = null |
||||
private var request: Request? = null |
||||
|
||||
private val handler = Handler() |
||||
|
||||
private val requestRunnable = Runnable { |
||||
request?.start() |
||||
} |
||||
|
||||
private val isCurrentRequestInvalid: Boolean |
||||
get() = request?.let { System.currentTimeMillis() - it.startTime > 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) { |
||||
Collections.swap(requests, index, to) |
||||
} |
||||
} else { |
||||
it.push(request) |
||||
} |
||||
|
||||
if (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,13 @@ |
||||
package io.legado.app.help.permission |
||||
|
||||
import android.content.Context |
||||
import android.content.Intent |
||||
import androidx.fragment.app.FragmentManager |
||||
|
||||
interface RequestSource { |
||||
|
||||
val context: Context? |
||||
|
||||
fun startActivity(intent: Intent) |
||||
|
||||
} |
Loading…
Reference in new issue