fondesa / kpermissions Goto Github PK
View Code? Open in Web Editor NEWA Kotlin library which helps to request runtime permissions in Android.
License: Apache License 2.0
A Kotlin library which helps to request runtime permissions in Android.
License: Apache License 2.0
The attachListener
method is called with an array of 3 string permission names as a key, but when an explicit permission is granted (such as Manifest.permission.ACCESS_FINE_LOCATION
), method managePermissionsResult
is called with an array of only one permission name, so the method listenerOf
doesn't match the existing listener and returns null, so the listener is not called.
KPermissions version: 3.1.3
API level: 30
How to reproduce it:
Request multiple permissions, including some permissions which may be implicit, such as:
Manifest.permission.ACCESS_FINE_LOCATION
Manifest.permission.BLUETOOTH,
Manifest.permission.BLUETOOTH_ADMIN
Sample code:
fun checkCallback(activity: Activity?, callback: (Boolean) -> Unit) {
val bluetoothRequest = (activity as? FragmentActivity)?.permissionsBuilder(
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.BLUETOOTH,
Manifest.permission.BLUETOOTH_ADMIN
)?.build()
bluetoothRequest?.addListener { status -> callback(status.allGranted()) }
bluetoothRequest?.send()
}
New permission https://developer.android.com/reference/android/Manifest.permission#POST_NOTIFICATIONS not handled.
Wrong message is shown about allowing access to device storage and that's the end
Hello, Thank you for this library.
Could you explain why I need RuntimePermissionHandlerProvider and RuntimePermissionHandler? It would be nice if you give a case when I need to use it. I read wiki, but it is not clear for me what it is for. Thank you!
This is the code that I wrote for handling permission:
request.addListener {
when {
it.allGranted() -> onPermissionAccepted()
it.anyShouldShowRationale() -> showRationaleDialog() { request.send() }
it.anyPermanentlyDenied() -> showNeverAskAgainDialog()
it.anyDenied() -> onPermissionDenied?.invoke()
}
}
When I call request.send()
for the first time and after that I press Deny button, inside the listener I get shouldShowRationale()
as true
and because of that immediately my RationaleDialog
shows up. And even If I dismiss that dialog and call request.send()
again, instead of getting anyShouldShowRationale
as true
(to show RationaleDialog
before the system permission dialog) it shows the system permission dialog. Is this an expected behavior or am I missing something?
KPermissions version:
3.2.1
API level:
All
Expected Behavior:
request.send()
gets calledanyShouldShowRationale()
as true
and it must return anyDenied()
as true
request.send()
againanyShouldShowRationale()
as true
so that we can show rationale dialog and after user clicks on OK
button inside that dialog we have to show system dialog.This should also unlock the updates of Dokka.
Currently this repo runs the Robolectric tests using 28 as the max SDK since it's the max one supported with Java 8.
The library is not working in coroutine scope
KPermissions version:
V3.2.1
API level:
30
Sample code:
private fun checkPermissionAndProceed() = lifecycleScope.launchWhenStarted {
val result = permissionsBuilder(CAMERA, MICROPHONE, STORAGE).build().sendSuspend()
if (result.allGranted()) {
joinChannel(binding.etChannel.text.toString())
}
}
Stack trace:
D/ResultLauncherRuntimePermissionHandler: requesting permissions: android.permission.CAMERA, android.permission-group.MICROPHONE, android.permission-group.STORAGE
2021-07-29 09:07:50.948 16593-16593/com.bolder.programbuilder I/Choreographer: Skipped 283 frames! The application may be doing too much work on its main thread.
1.0.0
works well. However, 2.0.0
causes an error. Code is same.
Language: kotlin
KPermissions version: 2.0.0
Android version: 8.0.0
Android device: Samsung Galaxy S7 edge
How to reproduce it: request any permission
Block of code:
// permissionsBuilder(Manifest.permission.CAMERA)
permissionsBuilder(Manifest.permission.WRITE_EXTERNAL_STORAGE)
.build()
.onAccepted { startScan() }
.send()
Stack trace:
java.lang.RuntimeException: Unable to start activity ComponentInfo{kr.susemi99/kr.susemi99.ui.unlock.UnlockActivity}: java.lang.IllegalStateException: FragmentManager is already executing transactions
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2957)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3032)
at android.app.ActivityThread.-wrap11(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1696)
at android.os.Handler.dispatchMessage(Handler.java:105)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6944)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:327)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1374)
Caused by: java.lang.IllegalStateException: FragmentManager is already executing transactions
at androidx.fragment.app.FragmentManagerImpl.ensureExecReady(FragmentManagerImpl.java:1650)
at androidx.fragment.app.FragmentManagerImpl.execSingleAction(FragmentManagerImpl.java:1682)
at androidx.fragment.app.BackStackRecord.commitNowAllowingStateLoss(BackStackRecord.java:299)
at com.fondesa.kpermissions.request.runtime.FragmentRuntimePermissionHandlerProvider.provideHandler(FragmentRuntimePermissionHandlerProvider.kt:51)
at com.fondesa.kpermissions.builder.CompatPermissionRequestBuilder.createRequest(CompatPermissionRequestBuilder.kt:49)
at com.fondesa.kpermissions.builder.BasePermissionRequestBuilder.build(BasePermissionRequestBuilder.kt:66)
at kr.susemi99.ui.unlock.scan.UnlockScanFragment.requestPermission(UnlockScanFragment.kt:85)
at kr.susemi99.ui.unlock.scan.UnlockScanFragment.onActivityCreated(UnlockScanFragment.kt:53)
at androidx.fragment.app.Fragment.performActivityCreated(Fragment.java:2633)
at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:897)
at androidx.fragment.app.FragmentManagerImpl.addAddedFragments(FragmentManagerImpl.java:2087)
at androidx.fragment.app.FragmentManagerImpl.executeOpsTogether(FragmentManagerImpl.java:1861)
at androidx.fragment.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManagerImpl.java:1817)
at androidx.fragment.app.FragmentManagerImpl.execPendingActions(FragmentManagerImpl.java:1717)
at androidx.fragment.app.FragmentManagerImpl.dispatchStateChange(FragmentManagerImpl.java:2650)
at androidx.fragment.app.FragmentManagerImpl.dispatchActivityCreated(FragmentManagerImpl.java:2600)
at androidx.fragment.app.Fragment.performActivityCreated(Fragment.java:2639)
at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:897)
at androidx.fragment.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManagerImpl.java:1228)
at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.java:1293)
at androidx.fragment.app.FragmentManagerImpl.dispatchStateChange(FragmentManagerImpl.java:2646)
at androidx.fragment.app.FragmentManagerImpl.dispatchActivityCreated(FragmentManagerImpl.java:2600)
at androidx.fragment.app.FragmentController.dispatchActivityCreated(FragmentController.java:246)
at androidx.fragment.app.FragmentActivity.onStart(FragmentActivity.java:542)
at androidx.appcompat.app.AppCompatActivity.onStart(AppCompatActivity.java:201)
at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1340)
at android.app.Activity.performStart(Activity.java:7200)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2920)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3032)
at android.app.ActivityThread.-wrap11(Unknown Source:0)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1696)
at android.os.Handler.dispatchMessage(Handler.java:105)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6944)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:327)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1374)
It would be great if there is a way to hold listener on configuration change (maybe orientation change) and dispatch event after restoration, also destroy itself after dispatch. Default setListener(context) with PermissionRequest.Listener implementation works as expected, but extension function send { result -> } sets anonymous object as listener, which is killed on configuration change and there is no events on result
I haven't decided to use it but would like to ask if its possible to check permission in a foreground service (location service and location permission).
The update to AndroidX Fragment 1.4.0 added the following bug: https://issuetracker.google.com/issues/206855622
When a new version of AndroidX Fragment is released, the ignored lint check ObsoleteLintCustomCheck
should not be ignored anymore.
private fun checkCameraPermission() {
// Build the request with the permissions you would like to request and send it.
permissionsBuilder(Manifest.permission.CAMERA).build().send { result ->
// Handle the result, for example check if all the requested permissions are granted.
if (result.first().isGranted()) {
// All the permissions are granted.
} else {
showPermissionError()
}
}
}
After checking permission inside androidx.fragment in onResume I get an infinity loop.
onResume is called every time I request permission. And even if permission is granted and there is no popup dialog showing.
Is this an expected behaviour? Or how to avoid it?
All plugin versions older than v3.2.0 will stop working since Nov 30, 2022
More info here: https://blog.dipien.com/releases-hub-gradle-plugin-v4-0-0-32cfca1d0de1
KPermissions version: 1.0.0
Android version: 7.1.2
Android device: OnePlus One
How to reproduce it: I have used dsl listeners on sample app provided by you. I am not getting any error. Just nothing happens when I click the button.
Block of code:
class MainActivity : AppCompatActivity() {
private val request by lazy {
permissionsBuilder(Manifest.permission.CAMERA)
.build()
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setupPermissionRequestListeners()
findViewById<View>(R.id.btn_test_activity_permissions).setOnClickListener {
request.send()
}
supportFragmentManager.beginTransaction()
.add(R.id.fragment_container, DummyFragment())
.commit()
}
private fun setupPermissionRequestListeners() {
request.listeners {
onAccepted { permissions ->
// Notified when the permissions are accepted.
toastOf(R.string.accepted_permissions, permissions)
}
onDenied { permissions ->
// Notified when the permissions are denied.
toastOf(R.string.denied_permissions, permissions)
}
onPermanentlyDenied { permissions ->
// Notified when the permissions are permanently denied.
DialogPermanentlyDeniedListener(this@MainActivity)
}
onShouldShowRationale { permissions, nonce ->
// Notified when the permissions should show a rationale.
// The nonce can be used to request the permissions again.
DialogRationaleListener(this@MainActivity)
}
}
}
private fun toastOf(@StringRes format: Int, permissions: Array<out String>) {
val msg = String.format(getString(format), permissions.flatString())
Toast.makeText(this, msg, Toast.LENGTH_SHORT).show()
}
}
I this section: Injection you mentioned that we can use the permission request inside our presenter. I've looked into the library and I saw that permissionBuilder
function is a ktx function on Fragment
and Activity
.
I there a sample code for this? I wanna know how can I use this lib inside my ViewModel
s.
KPermissions version:
2.0.2
API level:
28 (Android 9)
Stack trace:
Caused by java.lang.IllegalArgumentException: You need a listener for the key android.permission.ACCESS_FINE_LOCATION.
at com.fondesa.kpermissions.request.runtime.FragmentRuntimePermissionHandler.listenerOf(FragmentRuntimePermissionHandler.java:111)
at com.fondesa.kpermissions.request.runtime.DefaultFragmentRuntimePermissionHandler.managePermissionsResult(DefaultFragmentRuntimePermissionHandler.java:76)
at com.fondesa.kpermissions.request.runtime.FragmentRuntimePermissionHandler.onRequestPermissionsResult(FragmentRuntimePermissionHandler.java:58)
at androidx.fragment.app.FragmentActivity.onRequestPermissionsResult(FragmentActivity.java:768)
at android.app.Activity.dispatchRequestPermissionsResult(Activity.java:7981)
at android.app.Activity.dispatchActivityResult(Activity.java:7803)
at android.app.ActivityThread.deliverResults(ActivityThread.java:4610)
at android.app.ActivityThread.handleSendResult(ActivityThread.java:4659)
at android.app.servertransaction.ActivityResultItem.execute(ActivityResultItem.java:49)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1955)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7078)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:494)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:964)
Let's say I want to request ACCES_FINE_LOCATION permission on click to button1, and WRITE_EXTERNAL_STORAGE permission on click to button2. Do I need to declare, attach and detach 2 separate PermissionRequest in order to achieve this?
Hello, first of all, thanks for library. I am reading code base till now & I am not ready to contribute this feature request on my own yet. What about supporting Android 11? Some "important" methods were deprecated & the new recommended ways were changed (for example, requestPermissions, google recommends to use registerForActivityResult)
Hi, I think I found a race condition between checking and requesting permissions.
I have the following setup:
In my opinion is the reason here in the RuntimePermissionRequest
init block. It overwrites the listeners in ResultLauncherRuntimePermissionHandler
. I know you described in ResultLauncherRuntimePermissionHandler
that it can only handle one request at a time, but I think a simple check for permissions should act in a different way.
What do you think about this behavior? Thank you in advance.
KPermissions version:
3.3.0
API level:
33
Im trying to request for permission WRITE_CALL_LOG with this code:
val request = permissionsBuilder(Manifest.permission.WRITE_CALL_LOG).build()
request.liveData().observe(this) { result ->
if (result.allGranted()) {
deleteSelections()
} else {
showToast()
}
}
request.send()
But it doesn't show me the permission dialog and returns PermanentlyDenied even in the first install.
KPermissions version:
3.2.1
API level:
29
How to reproduce it:
Request the permission with above code.
Because the extension function on Fragment is basically a delegation to FragmentActivity ktx function with requireActivity()
, when Im trying to declare the request in fragment as a property and send the request whenever I need, it throws this Exception: IllegalStateException("Fragment SearchFragment not attached to an activity.")
.
KPermissions version:
3.2.1
API level:
All
How to reproduce it:
request.send()
Sample code:
class SearchFragment : Fragment() {
private val permission = permissionsBuilder(Manifest.permission.CAMERA).build().apply {
addListener {
handlePermission(it)
}
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
button.setOnClickListener {
permission.send()
}
}
}
Using version 3.2.0, after given Location Permissions, sendSuspend()
doesn't return, in other words, my app freezes the UI (it doesn't get rendered because it needs location permission and since sendSuspend()
doesn't complete I can't query result.allGranted()
and proceed with logic.
If I navigate back and then forward it works (the permission wore granted and no pop-up is shown, I can query result.allGranted()
happily and carry on).
If I downgrade to 3.1.3 it works as expected.
KPermissions version:
3.2.0
API level:
SDK 30, Google Pixel 3a Android 11
How to reproduce it:
Clear app cache and run it so that permissions are prompt again.
Sample code:
lifecycleScope.launchWhenResumed {
val result =
permissionsBuilder(Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION).build().sendSuspend()
if (result.allGranted()) { ... }
}
This is dependent from this JaCoCo issue: jacoco/jacoco#654
Are they compatible with Kotlin without breaking the usages of the current APIs?
Are they compatible with Java without breaking the usages of the current APIs?
Unfortunately, currently allWarningsAsErrors
is set to false
for :buildSrc
because the Gradle Wrapper uses internally an old version of Kotlin.
I am using kPermissions of version 1.0.0 and using DSL for listeners. But the onAccepted is not getting called if the permission is already granted. and is there any way to know if the permission is denied already
When the permission dialog pops up, if user touches outside of the permission dialog, it.anyPermanentlyDenied()
returns true
while user didn't pressed Don't ask again checkbox/
KPermissions version:
3.2.1
API level:
30
How to reproduce it:
Sample code:
val p = permissionsBuilder(Manifest.permission.CAMERA)
.build()
.apply {
addListener {
when {
it.allGranted() -> {
Logger.d("askForPermission::onPermissionAccepted")
onPermissionAccepted()
}
it.anyShouldShowRationale() -> {
Logger.d("askForPermission::onShowRationale")
onShowRationale?.invoke()
}
it.anyPermanentlyDenied() -> {
Logger.d("askForPermission::onNeverAskAgain")
onNeverAskAgain?.invoke()
}
it.anyDenied() -> {
Logger.d("askForPermission::onPermissionDenied")
onPermissionDenied?.invoke()
}
}
}
}
p.send()
My main goal is to auto open the gallery after the user clicks allow in case the permissions are not allowed.
The usage sample in README.md doesn't achieve this, because after I click allow, the dialog dismisses but the gallery doesn't open unless I click on the button again.
I tried to solve the problem using listener and based on this Issue #27 But it didn't work.
KPermissions version: 3.1.2
API level: 29
Sample code:
val kPermission = permissionsBuilder(
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_EXTERNAL_STORAGE
).build()
kPermission.addListener {
if (it.allGranted()) getContent.launch("image/*")
}
binding.editButtton.setOnClickListener {
kPermission.send()
}
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.