@@ -423,6 +423,10 @@ class Permission:
423
423
)
424
424
425
425
426
+ PERMISSION_GRANTED = 0
427
+ PERMISSION_DENIED = - 1
428
+
429
+
426
430
class _onRequestPermissionsCallback (PythonJavaClass ):
427
431
"""Callback class for registering a Python callback from
428
432
onRequestPermissionsResult in PythonActivity.
@@ -441,8 +445,7 @@ def onRequestPermissionsResult(self, requestCode,
441
445
442
446
443
447
class _RequestPermissionsManager :
444
- """Internal class for requesting Android permissions via
445
- requestPermissions, including registering callbacks to requestPermissions.
448
+ """Internal class for requesting Android permissions.
446
449
447
450
Permissions are requested through the method 'request_permissions' which
448
451
accepts a list of permissions and an optional callback.
@@ -465,10 +468,18 @@ class _RequestPermissionsManager:
465
468
onRequestPermissionsCallback, which allows the Java callback to be
466
469
propagated to the class method 'python_callback'. This is then, in turn,
467
470
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.
468
477
"""
469
478
_java_callback = None
470
479
_callbacks = {1 : None }
471
480
_callback_id = 1
481
+ # Lock to prevent multiple calls to request_permissions being handled
482
+ # simultaneously (as incrementing _callback_id is not atomic)
472
483
_lock = threading .Lock ()
473
484
474
485
@classmethod
@@ -484,7 +495,7 @@ def request_permissions(cls, permissions, callback=None):
484
495
If 'callback' is supplied, the request is made with a new requestCode
485
496
and the callback is stored in the _callbacks dict. When a Java callback
486
497
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 '.
488
499
"""
489
500
with cls ._lock :
490
501
if not cls ._java_callback :
@@ -502,13 +513,54 @@ def request_permissions(cls, permissions, callback=None):
502
513
def python_callback (cls , requestCode , permissions , grantResults ):
503
514
"""Calls the relevant callback with arguments of 'permissions'
504
515
and 'grantResults'."""
516
+ # Convert from Android codes to True/False
517
+ grant_results = [x == PERMISSION_GRANTED for x in grantResults ]
505
518
if cls ._callbacks .get (requestCode ):
506
- cls ._callbacks [requestCode ](permissions , grantResults )
519
+ cls ._callbacks [requestCode ](permissions , grant_results )
507
520
508
521
509
522
# Public API methods for requesting permissions
510
523
511
524
def 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
+ """
512
564
_RequestPermissionsManager .request_permissions (permissions , callback )
513
565
514
566
@@ -517,6 +569,14 @@ def request_permission(permission, callback=None):
517
569
518
570
519
571
def 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
+ """
520
580
python_activity = autoclass ('org.kivy.android.PythonActivity' )
521
581
result = bool (python_activity .checkCurrentPermission (
522
582
permission + ""
0 commit comments