@@ -423,6 +423,10 @@ class Permission:
423423 )
424424
425425
426+ PERMISSION_GRANTED = 0
427+ PERMISSION_DENIED = - 1
428+
429+
426430class _onRequestPermissionsCallback (PythonJavaClass ):
427431 """Callback class for registering a Python callback from
428432 onRequestPermissionsResult in PythonActivity.
@@ -441,8 +445,7 @@ def onRequestPermissionsResult(self, requestCode,
441445
442446
443447class _RequestPermissionsManager :
444- """Internal class for requesting Android permissions via
445- requestPermissions, including registering callbacks to requestPermissions.
448+ """Internal class for requesting Android permissions.
446449
447450 Permissions are requested through the method 'request_permissions' which
448451 accepts a list of permissions and an optional callback.
@@ -465,10 +468,18 @@ class _RequestPermissionsManager:
465468 onRequestPermissionsCallback, which allows the Java callback to be
466469 propagated to the class method 'python_callback'. This is then, in turn,
467470 used to call an application callback if provided to request_permissions.
471+
472+ The attribute '_callback_id' is incremented with each call to
473+ request_permissions which has a callback (the value '1' is used for any
474+ call which does not pass a callback). This is passed to requestCode in
475+ the Java call, and used to identify (via the _callbacks dictionary)
476+ the matching call.
468477 """
469478 _java_callback = None
470479 _callbacks = {1 : None }
471480 _callback_id = 1
481+ # Lock to prevent multiple calls to request_permissions being handled
482+ # simultaneously (as incrementing _callback_id is not atomic)
472483 _lock = threading .Lock ()
473484
474485 @classmethod
@@ -484,7 +495,7 @@ def request_permissions(cls, permissions, callback=None):
484495 If 'callback' is supplied, the request is made with a new requestCode
485496 and the callback is stored in the _callbacks dict. When a Java callback
486497 with the matching requestCode is received, callback will be called
487- with arguments of 'permissions' and 'grantResults '.
498+ with arguments of 'permissions' and 'grant_results '.
488499 """
489500 with cls ._lock :
490501 if not cls ._java_callback :
@@ -502,13 +513,54 @@ def request_permissions(cls, permissions, callback=None):
502513 def python_callback (cls , requestCode , permissions , grantResults ):
503514 """Calls the relevant callback with arguments of 'permissions'
504515 and 'grantResults'."""
516+ # Convert from Android codes to True/False
517+ grant_results = [x == PERMISSION_GRANTED for x in grantResults ]
505518 if cls ._callbacks .get (requestCode ):
506- cls ._callbacks [requestCode ](permissions , grantResults )
519+ cls ._callbacks [requestCode ](permissions , grant_results )
507520
508521
509522# Public API methods for requesting permissions
510523
511524def request_permissions (permissions , callback = None ):
525+ """Requests Android permissions.
526+
527+ Args:
528+ permissions (str): A list of permissions to requests (str)
529+ callback (callable, optional): A function to call when the request
530+ is completed (callable)
531+
532+ Returns:
533+ None
534+
535+ Notes:
536+
537+ Permission strings can be imported from the 'Permission' class in this
538+ module. For example:
539+
540+ from android import Permission
541+ permissions_list = [Permission.CAMERA,
542+ Permission.WRITE_EXTERNAL_STORAGE]
543+
544+ See the p4a source file 'permissions.py' for a list of valid permission
545+ strings (pythonforandroid/recipes/android/src/android/permissions.py).
546+
547+ Any callback supplied must accept two arguments:
548+ permissions (list of str): A list of permission strings
549+ grant_results (list of bool): A list of bools indicating whether the
550+ respective permission was granted.
551+ See Android documentation for onPermissionsCallbackResult for
552+ further information.
553+
554+ Note that if the request is interupted the callback may contain an empty
555+ list of permissions, without permissions being granted; the App should
556+ check that each permission requested has been granted.
557+
558+ Also note that calling request_permission on SDK_INT < 23 will return
559+ immediately (as run-time permissions are not required), and so the callback
560+ will never happen. Therefore, request_permissions should only be called
561+ with a callback if calling check_permission has indicated that it is
562+ necessary.
563+ """
512564 _RequestPermissionsManager .request_permissions (permissions , callback )
513565
514566
@@ -517,6 +569,14 @@ def request_permission(permission, callback=None):
517569
518570
519571def check_permission (permission ):
572+ """Checks if an app holds the passed permission.
573+
574+ Args:
575+ - permission An Android permission (str)
576+
577+ Returns:
578+ bool: True if the app holds the permission given, False otherwise.
579+ """
520580 python_activity = autoclass ('org.kivy.android.PythonActivity' )
521581 result = bool (python_activity .checkCurrentPermission (
522582 permission + ""
0 commit comments