Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to check permission is granted in ViewModel?

I need to ask permission for contacts and when application starts I'm asking,in ViewModel part I need to call method which requires permission. I need to check permission is granted by user or not and then call, but for checking permission I need to have access Activity. while in my ViewModel I don't have a reference to Activity and don't want to have, How I can overcome, the problem?

like image 795
I.S Avatar asked Jun 14 '17 17:06

I.S


People also ask

How check permission is granted or not Android?

To check if the user has already granted your app a particular permission, pass that permission into the ContextCompat. checkSelfPermission() method. This method returns either PERMISSION_GRANTED or PERMISSION_DENIED , depending on whether your app has the permission.

How do I check camera permissions on Android?

On your phone, open the Settings app. Tap Privacy. Turn off Camera access or Microphone access.

How do I ask for runtime permission on Android?

Requesting Android Runtime PermissionscheckSelfPermission(String perm); It returns an integer value of PERMISSION_GRANTED or PERMISSION_DENIED.

How to get permissions from a ViewModel in Android?

So far in Android you can receive permission only from an Activity. In order to check and request permissions directly from the ViewModel I would suggest to introduce the following two entities: PermissionManager -- is a high-level interface for managing permissions. You are suggested to use the implementation of this interface at ViewModel level.

How do I check if a permission has been granted Android?

Runtime Permission Checks in Android 6.0 The ContextCompat.CheckSelfPermission method (available with the Android Support Library) is used to check if a specific permission has been granted. This method will return a Android.Content.PM.Permission enum which has one of two values: Permission.Granted – The specified permission has been granted.

What are permissions in Android app development?

Permissions are declared in the AndroidManifest.xml by the application developer when the app is developed. Android has two different workflows for obtaining the user's consent for those permissions: For apps that targeted Android 5.1 (API level 22) or lower, the permission request occurred when the app was installed.

Shouldshowrequestpermissionrationale return true or false in Android?

Android provides a utility method, shouldShowRequestPermissionRationale (), that returns true if the user has previously denied the request, and returns false if a user has denied a permission and selected the Don't ask again option in the permission request dialog, or if a device policy prohibits the permission.


2 Answers

I just ran into this problem, and I decided to use make use of LiveData instead.

Core concept:

  • ViewModel has a LiveData on what permission request needs to be made

  • ViewModel has a method (essentially callback) that returns if permission is granted or not

SomeViewModel.kt:

class SomeViewModel : ViewModel() {
    val permissionRequest = MutableLiveData<String>()

    fun onPermissionResult(permission: String, granted: Boolean) {
        TODO("whatever you need to do")
    }
}

FragmentOrActivity.kt

class FragmentOrActivity : FragmentOrActivity() {
    private viewModel: SomeViewModel by lazy {
        ViewModelProviders.of(this).get(SomeViewModel::class.java)
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        ......
        viewModel.permissionRequest.observe(this, Observer { permission -> 
            TODO("ask for permission, and then call viewModel.onPermissionResult aftwewards")
        })
        ......
    }
}
like image 131
Louis Tsai Avatar answered Sep 18 '22 21:09

Louis Tsai


I have reworked the solution. The PermissionRequester object is everything you need to request permissions from any point where you have at least an application context. It uses its helper PermissionRequestActivity to accomplish this job.

@Parcelize
class PermissionResult(val permission: String, val state: State) : Parcelable
enum class State { GRANTED, DENIED_TEMPORARILY, DENIED_PERMANENTLY }
typealias Cancellable = () -> Unit
private const val PERMISSIONS_ARGUMENT_KEY = "PERMISSIONS_ARGUMENT_KEY"
private const val REQUEST_CODE_ARGUMENT_KEY = "REQUEST_CODE_ARGUMENT_KEY"

object PermissionRequester {
    private val callbackMap = ConcurrentHashMap<Int, (List<PermissionResult>) -> Unit>(1)
    private var requestCode = 256
    get() {
        requestCode = field--
        return if (field < 0) 255 else field
    }

    fun requestPermissions(context: Context, vararg permissions: String, callback: (List<PermissionResult>) -> Unit): Cancellable {
        val intent = Intent(context, PermissionRequestActivity::class.java)
                .putExtra(PERMISSIONS_ARGUMENT_KEY, permissions)
                .putExtra(REQUEST_CODE_ARGUMENT_KEY, requestCode)
                .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
        context.startActivity(intent)
        callbackMap[requestCode] = callback
        return { callbackMap.remove(requestCode) }
    }

    internal fun onPermissionResult(responses: List<PermissionResult>, requestCode: Int) {
        callbackMap[requestCode]?.invoke(responses)
        callbackMap.remove(requestCode)
    }
}

class PermissionRequestActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        if (savedInstanceState == null) {
            requestPermissions()
        }
    }

    private fun requestPermissions() {
        val permissions = intent?.getStringArrayExtra(PERMISSIONS_ARGUMENT_KEY) ?: arrayOf()
        val requestCode = intent?.getIntExtra(REQUEST_CODE_ARGUMENT_KEY, -1) ?: -1
        when {
            permissions.isNotEmpty() && requestCode != -1 -> ActivityCompat.requestPermissions(this, permissions, requestCode)
            else -> finishWithResult()
        }
    }

    override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)

        val permissionResults = grantResults.zip(permissions).map { (grantResult, permission) ->
            val state =  when {
                grantResult == PackageManager.PERMISSION_GRANTED -> State.GRANTED
                ActivityCompat.shouldShowRequestPermissionRationale(this, permission) -> State.DENIED_TEMPORARILY
                else -> State.DENIED_PERMANENTLY
            }
            PermissionResult(permission, state)
        }

        finishWithResult(permissionResults)
    }

    private fun finishWithResult(permissionResult: List<PermissionResult> = listOf()) {
        val requestCode = intent?.getIntExtra(REQUEST_CODE_ARGUMENT_KEY, -1) ?: -1
        PermissionRequester.onPermissionResult(permissionResult, requestCode)
        finish()
    }
}

Usage:

class MyViewModel(application: Application) : AndroidViewModel(application) {

    private val cancelRequest: Cancellable = requestPermission()

    private fun requestPermission(): Cancellable {
        return PermissionRequester.requestPermissions(getApplication(), "android.permission.SEND_SMS") {
            if (it.firstOrNull()?.state == State.GRANTED) {
                Toast.makeText(getApplication(), "GRANTED", Toast.LENGTH_LONG).show()
            } else {
                Toast.makeText(getApplication(), "DENIED", Toast.LENGTH_LONG).show()
            }
        }
    }

    override fun onCleared() {
        super.onCleared()
        cancelRequest()
    }
}
like image 45
user1185087 Avatar answered Sep 18 '22 21:09

user1185087