-
-
Notifications
You must be signed in to change notification settings - Fork 32
Legacy Usage [2.x]
This page will help you to discover all the supported features of this library before the version 3.x. The main sections are the following:
The main method to start the creation of a request is the extension function permissionsBuilder()
that can be used from an Activity
or a Fragment
.
The only necessary configuration that must be provided to create a new PermissionRequest
is the permission's set that must be requested. Depending on your needs, you can provide one or more permissions for each request.
Example:
// This is the most basic request.
val request = permissionsBuilder(Manifest.permission.CAMERA).build()
You can define also a few others customizations that are optional. If not specified, the defaults are used.
Example:
// This is the most customized request.
val request = permissionsBuilder(Manifest.permission.CAMERA, Manifest.permission.SEND_SMS)
// Specifies a custom RuntimePermissionHandlerProvider.
.runtimeHandlerProvider(MyRuntimePermissionHandlerProvider())
// Specifies a custom PermissionNonceGenerator.
.nonceGenerator(MyPermissionNonceGenerator())
// Build the request
.build()
To find more information about RuntimePermissionHandlerProvider
, go here.
To find more information about PermissionNonceGenerator
, go here.
You can receive the callbacks on these permissions' events:
- accepted → notified when some permissions are accepted.
- denied → notified when some permissions are denied.
- permanently denied → notified when some permissions are permanently denied. This can happen only since Android M when the user checks the never ask again checkbox in the dialog managed by the OS.
-
should show rationale → notified when some permissions needs a rationale that must be displayed to the user. This can happen only since Android M when the user denies the permissions. In this callback it's provided also a
PermissionNonce
that can be used to interact one more time with theRuntimePermissionHandler
. By default thePermissionNonce
requests the permissions again when used.
None of the callbacks are strictly necessary, use the ones you need.
There are different ways to receive callbacks about permissions' events that are equally managed, so choose the one you prefer most.
Recommended if you need different callbacks and you haven't a centralized management of the events.
request.listeners {
onAccepted { permissions -> /* Execute your code. */ }
onDenied { permissions -> /* Execute your code. */ }
onPermanentlyDenied { permissions -> /* Execute your code. */ }
onShouldShowRationale { permissions, nonce -> /* Execute your code. */ }
}
Recommended if you need only few callbacks and you haven't a centralized management of the events.
request.onAccepted { permissions -> /* Execute your code. */ }
.onDenied { permissions -> /* Execute your code. */ }
.onPermanentlyDenied { permissions -> /* Execute your code. */ }
.onShouldShowRationale { permissions, nonce -> /* Execute your code. */ }
Recommended if you have a centralized management of the events.
// It must implement [PermissionListener.AcceptedListener].
request.acceptedListener(this)
// It must implement [PermissionListener.DeniedListener].
request.deniedListener(this)
// It must implement [PermissionListener.PermanentlyDeniedListener].
request.permanentlyDeniedListener(this)
// It must implement [PermissionListener.RationaleListener].
request.rationaleListener(this)
You can also combine these styles if you need a more complex configuration.
Example:
// In this case you can use a specific callback when a group of permissions are
// accepted and a shared callback when a group of permissions are permanently denied.
request.onAccepted { permissions -> /* Execute your code. */ }
.permanentlyDeniedListener(MySharedPermanentlyDeniedListener())
All the listeners can be detached with a single method or with a specific method based on the type of the listener.
Example:
// Detach only the listeners that you need.
request.detachAcceptedListener()
request.detachDeniedListener()
request.detachPermanentlyDeniedListener()
request.detachRationaleListener()
// Detach all the listeners.
request.detachAllListeners()
To manage the runtime permissions since Android M there are two main components:
RuntimePermissionHandlerProvider
RuntimePermissionHandler
This provider is used to provide an instance of RuntimePermissionHandler
when the request is built. The provided instance of RuntimePermissionHandler
must be available instantly.
You can cache the instance of RuntimePermissionHandler
to use it for all the requests, but you need to manage its lifecycle manually.
Used to handle the runtime permissions since Android M. This component must persist across configuration changes or save its state because the permissions' request is partially handled by the OS. The entire lifecycle of the runtime permissions is specified inside this component, so, in order to implement a custom lifecycle, you need to specify a custom RuntimePermissionHandlerProvider
that will provide your custom RuntimePermissionHandler
.
Considering a lifecycle the group of phases that passes from RuntimePermissionHandler.requestPermissions()
till the end
of RuntimePermissionHandler.onRequestPermissionsResult()
, the default handler notifies the RuntimePermissionHandler.Listener
for maximum one event during the lifecycle.
For example if a permission's request contains two permissions and the user accepts only one of
them, the RuntimePermissionHandler.Listener
won't be notified on the accepted permissions, but
only on the denied one.
This is done following the consideration that a permissions' request must contain only the permissions that are related to a single functionality, so the functionality mustn't be available if the user doesn't "resolve" the permissions.
Every state needs a PermissionRequest
's listener attached to be handled, otherwise the
application will proceed to the next state, if any.
The available states are the following.
- rationale: happens when a permission is denied and a rationale is needed. It can be notified before the request is sent and after the result is received.
- denied: happens when a permission is denied and the rationale state isn't handled. It can be notified after the result is received.
- permanently denied: happens when the user selects the "never ask again" checkbox and the rationale/denied state isn't handled. It can be notified after the result is received.
- accepted: happens when the user accepts all the permissions. It can be notified before the request is sent or after the result is received.
A nonce is an object that can be used to interact one more time with the RuntimePermissionHandler
.
There are two main components regarding the handling of the nonce:
PermissionNonceGenerator
PermissionNonce
Used to generate a PermissionNonce
. The instance of the provided PermissionNonce
mustn't be cached because it must be used only one time.
When used, it interacts only one time with the RuntimePermissionHandler
. If you use a PermissionNonce
more than once, a PermissionNonceUsedException
is thrown.
By default, when a PermissionNonce
is used, the same set of permissions is requested again to the RuntimePermissionHandler
.
Example
request.onShouldShowRationale { permissions, nonce ->
// Show a dialog that permits the usage of the nonce.
AlertDialog.Builder(this)
.setTitle("Request again the permissions")
.setPositiveButton(android.R.string.ok) { _, _ ->
// Use the nonce when the user presses on the positive button.
// By default, the [permissions] are requested again.
nonce.use()
}
.show()
}
This library is built also to easily inject the PermissionRequest
instances inside the components which uses them.
Example
If you use Dagger, you can provide the implementation of a PermissionRequest
and use that request inside of a presenter without relying on the Android framework.
In this way, the permissions' management can be easily mocked and tested.
By default, the attached listeners are retained during orientation change. This could bring to a potential memory leak if you don't manage your listeners properly.
To avoid memory leaks, it's recommended to remove the attached listeners when the instance that holds the PermissionRequest
is destroyed or to attach the listeners in a method always executed during the the instance's lifecycle.
Example
Considering an Activity
that wants to check the status of a permission when an action is done by the user, it's recommended to build the request and attach its listeners at Activity.onCreate()
and send it when the action is done. This avoids a potential memory leak when the Activity
is rotated and doesn't require the detaching of the listeners.
By default this library uses ContextCompat
APIs to check the permissions below Android M and a Fragment
to check the runtime permissions since Android M.
The Fragment
is used to filter the callbacks to onRequestPermissionsResult()
.
The usage of a Fragment
has not a real performance impact because:
- it's light-weight
- it hasn't no UI at all
- it's shared between permissions' requests
- it's retained across configuration changes