oligazar
6/22/2017 - 6:46 AM

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