Skip to content

Commit 80b7d2d

Browse files
refactor and locale support
Changes: * Refactoring, code cleanup * Added support to different locales * Improved docs
1 parent 28deee6 commit 80b7d2d

File tree

16 files changed

+184
-122
lines changed

16 files changed

+184
-122
lines changed

.idea/deploymentTargetDropDown.xml

Lines changed: 17 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/gradle.xml

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/misc.xml

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

README.md

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,32 @@
11
# Permissions
22
[![](https://jitpack.io/v/lorenzofelletti/permissions.svg)](https://jitpack.io/#lorenzofelletti/permissions)
33

4-
## Easy permissions management library for Android
4+
## Easy Permissions Management Library for Android
55

6-
An easy to use permissions management library designed to be used with Kotlin.
6+
An easy to use permissions management library written in Kotlin.
77

8-
The library is deployed on JitPack here, follow the steps indicated in the link to add it to your project.
8+
### Import the Library
9+
The library is deployed on JitPack [here](https://jitpack.io/#lorenzofelletti/permissions).
10+
To add it to your project, add to `settings.gradle`:
11+
```Groovy
12+
dependencyResolutionManagement {
13+
...
14+
repositories {
15+
...
16+
maven { url 'https://jitpack.io' }
17+
}
18+
}
19+
```
20+
And to your module level build.gradle:
21+
```Groovy
22+
dependencies {
23+
...
24+
implementation 'com.github.lorenzofelletti:permissions:0.4.2'
25+
}
26+
```
927

10-
To use it in your project, just:
28+
### Usage
29+
To use the library in your project, just:
1130
* Declare the permissions your app will use in your application's Manifest
1231
* Example: add to the app `AndroidManifest.xml`
1332
```xml
@@ -48,9 +67,7 @@ To use it in your project, just:
4867
* Call `permissionManager.checkRequestAndDispatch` where you want to check for a set of permissions (and ask them if not granted)
4968
* Example: in your Activity, where you want to check (and request) permissions add
5069
```Kotlin
51-
permissionManager.checkRequestAndDispatch(
52-
POSITION_REQUEST_CODE
53-
)
70+
permissionManager checkRequestAndDispatch POSITION_REQUEST_CODE
5471
```
5572
* Override `onRequestPermissionsResult` and call `PermissionsUtilities.dispatchOnRequestPermissionsResult` in it
5673
* Example: inside your `MainActivity`
@@ -64,3 +81,7 @@ To use it in your project, just:
6481
permissionManager.dispatchOnRequestPermissionsResult(requestCode, grantResults)
6582
}
6683
```
84+
85+
## Contributing
86+
All kinds of contributions are welcome (bug reports, feature requests, pull requests, etc.).
87+
Suggestions and improvements on documentation, tests, code quality, translations, etc. are also welcome.

build.gradle

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// Top-level build file where you can add configuration options common to all sub-projects/modules.
22
plugins {
3-
id 'com.android.application' version '7.3.1' apply false
4-
id 'com.android.library' version '7.3.1' apply false
3+
id 'com.android.application' version '7.4.1' apply false
4+
id 'com.android.library' version '7.4.1' apply false
55
id 'org.jetbrains.kotlin.android' version '1.7.20' apply false
66
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#Mon Dec 05 12:12:35 CET 2022
22
distributionBase=GRADLE_USER_HOME
3-
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip
3+
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip
44
distributionPath=wrapper/dists
55
zipStorePath=wrapper/dists
66
zipStoreBase=GRADLE_USER_HOME

permissions/src/main/java/com/lorenzofelletti/permissions/PermissionManager.kt

Lines changed: 54 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,8 @@ class PermissionManager(val activity: Activity) {
5050
*/
5151
@PermissionDispatcherDsl
5252
infix fun buildRequestResultsDispatcher(init: RequestResultsDispatcher.() -> Unit) {
53-
dispatcher = RequestResultsDispatcher(this).apply(init)
53+
dispatcher = RequestResultsDispatcher(this)
54+
dispatcher.apply(init)
5455
}
5556

5657
/**
@@ -63,35 +64,11 @@ class PermissionManager(val activity: Activity) {
6364
* [RequestResultsDispatcher] is dispatched.
6465
*
6566
* @param requestCode The request code associated to the permissions
66-
* @param comingFromRationale true if the method is called from the rationale, defaults to false
67+
*
68+
* @throws UnhandledRequestCodeException if the request code is not handled by the dispatcher
6769
*/
68-
fun checkRequestAndDispatch(requestCode: Int, comingFromRationale: Boolean = false) {
69-
val permissions =
70-
dispatcher.getPermissions(requestCode) ?: throw UnhandledRequestCodeException(
71-
requestCode
72-
)
73-
val permissionsNotGranted = permissions.filter { permission ->
74-
ActivityCompat.checkSelfPermission(
75-
activity, permission
76-
) != PackageManager.PERMISSION_GRANTED
77-
78-
}.toTypedArray()
79-
80-
if (permissionsNotGranted.isEmpty()) {
81-
// All permissions are granted
82-
dispatcher.getOnGranted(requestCode)?.invoke()
83-
} else {
84-
// Some permissions are not granted
85-
val shouldShowRationale = permissionsNotGranted.any { permission ->
86-
shouldShowRequestPermissionRationale(activity, permission)
87-
}
88-
89-
if (shouldShowRationale && !comingFromRationale) {
90-
dispatchRationale(permissionsNotGranted, requestCode)
91-
} else {
92-
ActivityCompat.requestPermissions(activity, permissionsNotGranted, requestCode)
93-
}
94-
}
70+
infix fun checkRequestAndDispatch(requestCode: Int) {
71+
checkRequestAndDispatch(requestCode, false)
9572
}
9673

9774
/**
@@ -103,41 +80,63 @@ class PermissionManager(val activity: Activity) {
10380
* If all the permissions are already granted, the action associated to onGranted in the
10481
* [RequestResultsDispatcher] is dispatched.
10582
*
106-
* @param requestCode The request code associated to the permissions
107-
*/
108-
infix fun checkRequestAndDispatch(requestCode: Int) {
109-
checkRequestAndDispatch(requestCode, false)
110-
}
111-
112-
/**
113-
* Checks whether a set of permissions is granted or not.
83+
* Note: `comingFromRationale` is used internally to avoid showing the rationale dialog in loop.
11484
*
115-
* @param permissions The permissions to be checked
85+
* @param requestCode The request code associated to the permissions
86+
* @param comingFromRationale true if the method is called from the rationale, defaults to false
11687
*
117-
* @return true if all permissions are granted, false otherwise
88+
* @throws UnhandledRequestCodeException if the request code is not handled by the dispatcher
11889
*/
119-
fun checkPermissionsGranted(permissions: Array<out String>): Boolean {
120-
for (permission in permissions) {
121-
if (!checkPermissionGranted(activity, permission)) return false
90+
internal fun checkRequestAndDispatch(requestCode: Int, comingFromRationale: Boolean = false) {
91+
val permissionsNotGranted = dispatcher.getPermissions(requestCode)?.filter { permission ->
92+
ActivityCompat.checkSelfPermission(
93+
activity, permission
94+
) != PackageManager.PERMISSION_GRANTED
95+
}?.toTypedArray() ?: throw UnhandledRequestCodeException(requestCode, activity)
96+
97+
if (permissionsNotGranted.isEmpty()) {
98+
// All permissions are granted
99+
dispatcher.dispatchOnGranted(requestCode)
100+
} else {
101+
// Some permissions are not granted
102+
dispatchSomePermissionsNotGranted(
103+
permissionsNotGranted,
104+
requestCode,
105+
comingFromRationale
106+
)
122107
}
123-
return true
124108
}
125109

126110
/**
127-
* Checks whether the permissions for a given request code are granted or not.
128-
* Throws an [UnhandledRequestCodeException] if the request code is not handled.
111+
* Dispatches the case in which some permissions are not granted
129112
*
130-
* @param requestCode The request code associated to the permissions to be checked
131-
* @return true if all permissions are granted, false otherwise
113+
* @param permissionsNotGranted
114+
* @param requestCode
115+
* @param comingFromRationale
132116
*/
133-
fun checkPermissionsGranted(requestCode: Int): Boolean {
134-
val permissions =
135-
dispatcher.getPermissions(requestCode) ?: throw UnhandledRequestCodeException(
136-
requestCode
137-
)
138-
return checkPermissionsGranted(permissions)
117+
private fun dispatchSomePermissionsNotGranted(
118+
permissionsNotGranted: Array<out String>,
119+
requestCode: Int,
120+
comingFromRationale: Boolean
121+
) {
122+
// if not coming from rationale, gets the list of permissions that require rationale to be shown
123+
val permissionsRequiringRationale =
124+
if (!comingFromRationale) getPermissionsRequiringRationale(permissionsNotGranted) else emptyList()
125+
126+
// if some permissions require rationale, show rationale, otherwise ask for permissions
127+
// Note: if coming from rationale, the list will be empty, so the else branch will be executed
128+
if (permissionsRequiringRationale.isNotEmpty()) {
129+
dispatcher.showRationale(requestCode, permissionsRequiringRationale)
130+
} else {
131+
ActivityCompat.requestPermissions(activity, permissionsNotGranted, requestCode)
132+
}
139133
}
140134

135+
private fun getPermissionsRequiringRationale(permissionsNotGranted: Array<out String>) =
136+
permissionsNotGranted.filter { permission ->
137+
shouldShowRequestPermissionRationale(activity, permission)
138+
}.toList()
139+
141140
/**
142141
* Checks the result of a permission request, and dispatches the appropriate action.
143142
* The actions can be defined by the user by using the [buildRequestResultsDispatcher] function
@@ -152,42 +151,12 @@ class PermissionManager(val activity: Activity) {
152151
dispatcher.dispatchAction(requestCode, grantResults)?.invoke()
153152
}
154153

155-
/**
156-
* Checks whether a permission is granted in the context.
157-
*
158-
* @param context The context to be used for checking the permission
159-
* @param permission The permission to be checked
160-
*
161-
* @return true if the permission is granted, false otherwise
162-
*/
163-
private fun checkPermissionGranted(context: Context, permission: String): Boolean {
164-
return ActivityCompat.checkSelfPermission(
165-
context, permission
166-
) == PackageManager.PERMISSION_GRANTED
167-
}
168-
169-
/**
170-
* Dispatches the rationale action associated to the request code, if any.
171-
*
172-
* @param permissionsNotGranted The permissions that are not granted
173-
* @param requestCode The request code associated to the permissions
174-
*/
175-
private fun dispatchRationale(permissionsNotGranted: Array<out String>, requestCode: Int) {
176-
/* if a rationale is defined, dispatch it, otherwise it calls checkRequestAndDispatch with
177-
* comingFromRationale = true */
178-
val toInvoke = dispatcher.getOnShowRationale(requestCode) ?: fun(
179-
_: List<String>, requestCode: Int
180-
) {
181-
checkRequestAndDispatch(requestCode, true)
182-
}
183-
toInvoke.invoke(permissionsNotGranted.toList(), requestCode)
184-
}
185154
}
186155

187156
/**
188157
* Exception thrown when the request code is not handled by the [RequestResultsDispatcher] object.
189158
*/
190-
class UnhandledRequestCodeException(requestCode: Int) : Throwable() {
159+
class UnhandledRequestCodeException(requestCode: Int, context: Context) : Throwable() {
191160
override val message: String =
192-
"Request code $requestCode is not handled by the RequestResultsDispatcher object. Please add a withRequestCode block to the buildRequestResultsDispatcher function."
161+
context.getString(R.string.unhandled_request_code_exception_message, requestCode)
193162
}

permissions/src/main/java/com/lorenzofelletti/permissions/dispatcher/DispatcherEntry.kt

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package com.lorenzofelletti.permissions.dispatcher
22

3-
import com.lorenzofelletti.permissions.PermissionManager
43
import com.lorenzofelletti.permissions.dispatcher.dsl.PermissionDispatcher
54

65

@@ -10,13 +9,12 @@ import com.lorenzofelletti.permissions.dispatcher.dsl.PermissionDispatcher
109
* in case the permissions are granted or denied.
1110
*/
1211
class DispatcherEntry(
13-
internal val manager: PermissionManager, val requestCode: Int
12+
internal val dispatcher: RequestResultsDispatcher, val requestCode: Int
1413
) : PermissionDispatcher() {
1514
/**
1615
* The permissions associated to this entry
1716
*/
18-
lateinit var permissions: Array<out String>
19-
internal set
17+
private lateinit var permissions: Array<out String>
2018

2119
/**
2220
* The action to be dispatched if the permissions are granted.
@@ -36,6 +34,12 @@ class DispatcherEntry(
3634
var onShowRationale: ((List<String>, requestCode: Int) -> Unit)? = null
3735
internal set
3836

37+
internal fun setPermissions(permissions: Array<out String>) {
38+
this.permissions = permissions
39+
}
40+
41+
internal fun getPermissions(): Array<out String> = permissions
42+
3943
override fun equals(other: Any?): Boolean {
4044
if (this === other) return true
4145
if (javaClass != other?.javaClass) return false

permissions/src/main/java/com/lorenzofelletti/permissions/dispatcher/RequestResultsDispatcher.kt

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,23 @@ class RequestResultsDispatcher(internal val manager: PermissionManager) : Permis
1818
}
1919

2020
internal fun getPermissions(requestCode: Int): Array<out String>? =
21-
entries[requestCode]?.permissions
21+
entries[requestCode]?.getPermissions()
2222

23-
internal fun getOnGranted(requestCode: Int): (() -> Unit)? = entries[requestCode]?.onGranted
24-
25-
internal fun getOnDenied(requestCode: Int): (() -> Unit)? = entries[requestCode]?.onDenied
23+
internal fun dispatchOnGranted(requestCode: Int) {
24+
entries[requestCode]?.onGranted?.invoke()
25+
}
2626

27-
internal fun getOnShowRationale(requestCode: Int): ((List<String>, Int) -> Unit)? =
28-
entries[requestCode]?.onShowRationale
27+
/**
28+
* Shows the rationale for the permissions associated to the given request code, otherwise
29+
* it calls [PermissionManager.checkRequestAndDispatch] with `comingFromRationale = true`.
30+
*
31+
* @param requestCode The request code associated to the permissions
32+
* @param permissions The permissions requiring a rationale
33+
*/
34+
internal fun showRationale(requestCode: Int, permissions: List<String>) {
35+
entries[requestCode]?.onShowRationale?.invoke(permissions, requestCode)
36+
?: manager.checkRequestAndDispatch(requestCode, true)
37+
}
2938

3039
/**
3140
* Checks the results of a permission request

0 commit comments

Comments
 (0)