Reputation: 803
I am not getting permission result callback on Activity Result api as mentioned in the doc.
Getting a result from an activity
I am using implementation "androidx.activity:activity-ktx:1.2.0-alpha02"
Here is the api code :
/**
* An {@link ActivityResultContract} to {@link Activity#requestPermissions request a permission}
*/
public static class RequestPermission extends ActivityResultContract<String, Boolean> {
@NonNull
@Override
public Intent createIntent(@NonNull String input) {
return new Intent(ACTION_REQUEST_PERMISSIONS)
.putExtra(EXTRA_PERMISSIONS, new String[] { input });
}
@NonNull
@Override
public Boolean parseResult(int resultCode, @Nullable Intent intent) {
if (resultCode != Activity.RESULT_OK) return false;
if (intent == null) return false;
int[] grantResults = intent.getIntArrayExtra(EXTRA_PERMISSION_GRANT_RESULTS);
if (grantResults == null) return false;
return grantResults[0] == PackageManager.PERMISSION_GRANTED;
}
}
Here is my implementation :
private val permission = prepareCall(object : ActivityResultContracts.RequestPermission() {
override fun createIntent(input: String): Intent {
if (shouldShowRequestPermissionRationale(input)) {
Toast.makeText(
this@MainActivity,
"shouldShowRequestPermissionRationale - true",
Toast.LENGTH_SHORT
).show()
// case 2
} else {
Toast.makeText(
this@MainActivity,
"shouldShowRequestPermissionRationale - false",
Toast.LENGTH_SHORT
).show()
// case 1 and 3
}
return super.createIntent(input)
}
override fun parseResult(resultCode: Int, intent: Intent?): Boolean {
val t = super.parseResult(resultCode, intent)
Toast.makeText(this@MainActivity, "parseResult $t", Toast.LENGTH_SHORT).show()
return t
}
}) {
Log.d("permission granted?", "$it")
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
button.setOnClickListener {
permission(android.Manifest.permission.CAMERA)
}
}
As per doc, I should be getting callback inside ActivityResultCallback
but after backtracking I figure in my case, it even does not call ParseResult
function. Though I am still receiving callback inside onRequestPermissionsResult
function.
So, am I doing something wrong ?
Please refer Getting a result from an activity to understand this api.
Update
I was able to get the callback after extending my activity with ComponentActivity
but again, if the permission is already given then app wont receive callback, is there any way to directly handle here? I don't wanna check self permission.
Sample demo code - https://github.com/tasneembohra/ActivityResultApiDemo
Upvotes: 4
Views: 4241
Reputation: 111
You can easily handle your permissions callback by creating a support class extending DefaultLifecycleObserver
class PermissionHandler(
private val context: Context,
private val registry: ActivityResultRegistry
) : DefaultLifecycleObserver {
private val permissionsKey = "permissionsKey"
private lateinit var requestPermissions: ActivityResultLauncher<Array<String>>
private var onAllowed: (() -> Unit)? = null
private var onDenied: (() -> Unit)? = null
private val readExternalStorageRequest = arrayOf(
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.CAMERA
)
override fun onCreate(owner: LifecycleOwner) {
requestPermissions = registry.register(permissionsKey, owner, ActivityResultContracts.RequestMultiplePermissions()) { result ->
Log.d("PERMISSIONS", "RESULT: $result")
if (result.values.isNullOrEmpty() || result.values.contains(false)) {
Log.d("PERMISSIONS", "DENIED")
onDenied?.invoke()
}
else {
Log.d("PERMISSIONS", "ALLOWED")
onAllowed?.invoke()
}
}
}
fun checkForPermissions(permissions: Array<String> = readExternalStorageRequest, onAllowed: (() -> Unit)?, onDenied: (() -> Unit)?) {
this.onAllowed = onAllowed
this.onDenied = onDenied
val remainingPermissions = mutableListOf<String>()
remainingPermissions.clear()
for (permission in permissions) {
if (ContextCompat.checkSelfPermission(context, permission) != PackageManager.PERMISSION_GRANTED) {
remainingPermissions.add(permission)
}
}
Log.d("PERMISSIONS", "REMAINING: $remainingPermissions")
if (remainingPermissions.isNotEmpty()) {
requestPermissions.launch(remainingPermissions.toTypedArray())
}
else {
onAllowed?.invoke()
}
}
}
activity
or fragment
private lateinit var permissionHandler: PermissionHandler
override fun onCreate(savedInstanceState: Bundle?) {
permissionHandler = PermissionHandler(this, activityResultRegistry)
lifecycle.addObserver(permissionHandler)
}
fun foo() {
permissionHandler.checkForPermissions(
onAllowed = {
//on allowed stuffs...
},
onDenied = {
//on denied stuffs...
}
)
}
fragment
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
permissionHandler = PermissionHandler(requireContext(), requireActivity().activityResultRegistry)
lifecycle.addObserver(permissionHandler)
}
Upvotes: 0
Reputation: 591
Well I ran in a lot of circles trying to solve the same problem, but my solution was to simply remove the override onActivityResult
from my activity!
Upvotes: 0
Reputation: 13027
Here is my implementation, hope it helps:
val cameraPermission = prepareCall(ActivityResultContracts.RequestPermission()){
if(it){
Log.e("TAG", "permnission granted")
}else{
Log.e("TAG", "No permnission")
}
}
cameraPermission(Manifest.permission.CAMERA)
It enters Permission Granted condition, if you granted permission earlier and just open app, or grant it now.
P.S. My Activity extends AppCompatActivity
Upvotes: 1