Permissions https://habrahabr.ru/post/278945/
@file:JvmName("RPermission")
// https://github.com/WindSekirun/RichUtilsKt/blob/master/RichUtils/src/main/java/pyxis/uzuki/live/richutilskt/utils/RPermission.kt
import android.annotation.SuppressLint
import android.content.Context
import android.content.ContextWrapper
import android.content.pm.PackageManager
import android.os.Build
import android.support.annotation.RequiresApi
import android.support.v4.app.Fragment
import android.support.v4.app.FragmentActivity
import android.support.v4.app.FragmentManager
import android.support.v4.content.ContextCompat
inline class ReturnCode(val code: Int)
inline class PermsList(val perms: List<String>)
interface SimplePermission {
/**
* check permission is granted
*
* @param[context] context
* @param[array] array of Permission to check
*/
fun checkPermissionGranted(context: Context, array: Array<String>): Boolean
/**
* check and request Permission which given.
*
* @param[perms] list of Permission to check
* @param[callback] callback object
* @return check result
*/
fun checkPermission(context: Context, perms: List<String>, callback: (ReturnCode, PermsList) -> Unit): Boolean
}
class SPermission private constructor(): SimplePermission {
private fun getActivity(context: Context): FragmentActivity? {
var c = context
while (c is ContextWrapper) {
if (c is FragmentActivity) {
return c
}
c = c.baseContext
}
return null
}
override fun checkPermissionGranted(context: Context, array: Array<String>): Boolean {
if (Build.VERSION.SDK_INT < 23) {
return true
}
val list = List(array.size) { array[it] }
val notGranted: ArrayList<String> = ArrayList()
list.forEach {
val result = ContextCompat.checkSelfPermission(context, it)
if (result != PackageManager.PERMISSION_GRANTED)
notGranted.add(it)
}
return notGranted.isEmpty()
}
override fun checkPermission(context: Context, perms: List<String>, callback: (ReturnCode, PermsList) -> Unit): Boolean
= context.processGrantPermission(perms, callback)
@SuppressLint("NewApi")
private fun Context.processGrantPermission(perms: List<String>, callback: (ReturnCode, PermsList) -> Unit): Boolean {
if (Build.VERSION.SDK_INT < 23) {
callback(ReturnCode(PERMISSION_GRANTED), PermsList(perms))
return true
}
val notGranted: ArrayList<String> = ArrayList()
perms.forEach {
val result = ContextCompat.checkSelfPermission(this, it)
if (result != PackageManager.PERMISSION_GRANTED)
notGranted.add(it)
}
return if (notGranted.isNotEmpty()) {
requestPermission(notGranted, callback)
false
} else {
callback(ReturnCode(PERMISSION_GRANTED), PermsList(perms))
true
}
}
@RequiresApi(Build.VERSION_CODES.M)
private fun Context.requestPermission(list: List<String>, callback: (ReturnCode, PermsList) -> Unit) {
val fm = getActivity(this)?.supportFragmentManager
val fragment = RequestFragment(this, fm as FragmentManager, callback)
fm.beginTransaction().add(fragment, "FRAGMENT_TAG").commitAllowingStateLoss()
fm.executePendingTransactions()
fragment.requestPermissions(list.toTypedArray(), 72)
}
@SuppressLint("ValidFragment")
class RequestFragment() : Fragment() {
private var fm: FragmentManager? = null
private var callback: ((ReturnCode, PermsList) -> Unit)? = null
private var mContext: Context? = null
constructor(context: Context, fm: FragmentManager, callback: (ReturnCode, PermsList) -> Unit) : this() {
this.mContext = context
this.fm = fm
this.callback = callback
}
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
val grantedPermissions: ArrayList<String> = mContext?.getVerifiedPermissions(permissions) ?: arrayListOf()
val returnCode = if (verifyPermissions(grantResults)) PERMISSION_GRANTED else PERMISSION_FAILED
callback?.invoke(ReturnCode(returnCode), PermsList(grantedPermissions))
fm?.beginTransaction()?.remove(this)?.commitAllowingStateLoss()
}
private fun Context.getVerifiedPermissions(permissions: Array<String>): ArrayList<String> {
val permissionList: ArrayList<String> = ArrayList()
permissions.forEach {
if (ContextCompat.checkSelfPermission(this, it) == PackageManager.PERMISSION_GRANTED)
permissionList.add(it)
}
return permissionList
}
private fun verifyPermissions(grantResults: IntArray): Boolean =
if (grantResults.isEmpty()) false else grantResults.all { it == PackageManager.PERMISSION_GRANTED }
}
companion object {
@JvmField
var instance: SPermission = SPermission()
const val PERMISSION_GRANTED = 1
const val PERMISSION_FAILED = 2
}
}
/* Dexter. Runtime permissions */
// compile 'com.karumi:dexter:4.1.0'
private fun requestCamera() {
Dexter.withActivity(activity)
.withPermission(Manifest.permission.CAMERA)
.withListener(object : PermissionListener {
override fun onPermissionGranted(response: PermissionGrantedResponse) {
Log.d("RegistrationFragment", "requestCamera: onPermissionGranted")
mScannerView.setResultHandler(this@RegistrationFragment) // Register ourselves as a handler for scan results.
mScannerView.startCamera() // Start camera
}
override fun onPermissionDenied(response: PermissionDeniedResponse) {
Log.d("RegistrationFragment", "requestCamera: onPermissionDenied")
// Allow to go to Setting to enable permissions manually
showNoCameraDialog("onPermissionDenied")
}
override fun onPermissionRationaleShouldBeShown(permission: PermissionRequest, token: PermissionToken) {
val message = "Storage permission is needed to show files count"
Snackbar.make(view!!, message, Snackbar.LENGTH_LONG)
.setAction("GRANT") {
requestCamera()
}.show()
}
}).onSameThread()
.check()
}
fun showNoCameraDialog(title: String = "Доступ к камере") {
val builder: AlertDialog.Builder = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
AlertDialog.Builder(context, android.R.style.Theme_Material_Dialog_Alert)
} else {
AlertDialog.Builder(context)
}
builder.setTitle(title)
.setMessage("Приложение не может работать без доступа к камере")
.setPositiveButton(android.R.string.yes) { _, _ ->
openApplicationSettings()
Toast.makeText(activity.applicationContext,
"Open Permissions and grant the Storage permission",
Toast.LENGTH_SHORT)
.show()
}
.setIcon(android.R.drawable.ic_dialog_alert)
.show()
}
private val PERMISSION_REQUEST_CODE = 123
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
Log.d("RegistrationFragment", "onActivityResult")
when (requestCode) {
PERMISSION_REQUEST_CODE -> {
requestCamera()
}
}
}
private fun openApplicationSettings() {
val appSettingsIntent = Intent().apply {
action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS
data = Uri.parse("package:${activity.applicationContext.packageName}")
addCategory(Intent.CATEGORY_DEFAULT)
}
startActivityForResult(appSettingsIntent, PERMISSION_REQUEST_CODE)
}
/**
* Returns true if [grantResults] array is not empty and [index] element result is granted
*/
fun isGranted(grantResults: IntArray, index: Int): Boolean = // If request is cancelled, the result arrays are empty.
grantResults.isNotEmpty() && grantResults[index] == PackageManager.PERMISSION_GRANTED
fun Context.isGranted(permission: String) = ContextCompat.checkSelfPermission(this, permission) == PackageManager.PERMISSION_GRANTED
fun checkPerms(context: Activity, requestCode: Int, vararg permissions: String, showRationale: ((Int) -> Unit)? = null): Boolean {
Log.d("checkPerms", "permissions: $permissions, requestCode: $requestCode")
val notGrantedPermissions = ArrayList<String>()
for (index in permissions.indices) {
if (context.isNotGranted(permissions[index])) {
notGrantedPermissions.add(permissions[index])
if (ActivityCompat.shouldShowRequestPermissionRationale(context, permissions[index])) {
// show rationale (обоснование)
showRationale?.invoke(index)
}
}
}
// If we shouldn't show an explanation - then we request the permissions
return if (notGrantedPermissions.isNotEmpty()) {
ActivityCompat.requestPermissions(context, permissions, requestCode)
false
} else true
}
// Variant 1
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
when (requestCode) {
MY_CAMERA_PERM -> {
// If request is cancelled, the result arrays are empty.
if (isGranted(grantResults, 0)) {
// permission was granted!
intent = Intent(this, RegistrationActivity::class.java)
startActivityAndFinishCurrent(intent)
} else {
// permission denied, boo! Disable the
// functionality that depends on this permission.
}
return
}
// other 'case' lines to check for other
// permissions this app might request
}
}
// Variant 2
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
@NonNull int[] grantResults) {
if (requestCode == PERMISSION_REQUEST_CODE && grantResults.length == 2) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
showExtDirFilesCount();
}
if (grantResults[1] == PackageManager.PERMISSION_GRANTED) {
showUnreadSmsCount();
}
}
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
adb shell pm grant <app package> <permission name>
adb shell pm revoke <app package> <permission name>
adb shell pm reset-permissions
adb shell pm list permission-groups
adb shell pm list permissions