|
| 1 | +import threading |
1 | 2 |
|
2 | 3 | try:
|
3 | 4 | from jnius import autoclass, PythonJavaClass, java_method
|
@@ -428,42 +429,89 @@ class onRequestPermissionsCallback(PythonJavaClass):
|
428 | 429 | """
|
429 | 430 | __javainterfaces__ = ['org.kivy.android.PythonActivity$PermissionsCallback']
|
430 | 431 | __javacontext__ = 'app'
|
431 |
| - _callback = None # To avoid garbage collection |
432 | 432 |
|
433 | 433 | def __init__(self, func):
|
434 | 434 | self.func = func
|
435 |
| - onRequestPermissionsCallback._callback = self |
| 435 | + onRequestPermissionsCallback._java_callback = self |
436 | 436 | super().__init__()
|
437 | 437 |
|
438 | 438 | @java_method('(I[Ljava/lang/String;[I)V')
|
439 | 439 | def onRequestPermissionsResult(self, requestCode, permissions, grantResults):
|
440 | 440 | self.func(requestCode, permissions, grantResults)
|
441 | 441 |
|
442 | 442 |
|
443 |
| -def register_permissions_callback(callback): |
444 |
| - """Register a callback. This will asynchronously receive arguments from |
445 |
| - onRequestPermissionsResult on PythonActivity after request_permission(s) |
446 |
| - is called. |
| 443 | +class onRequestPermissionsManager: |
| 444 | + """Class for requesting Android permissions via requestPermissions, |
| 445 | + including registering callbacks to requestPermissions. |
447 | 446 |
|
448 |
| - The callback must accept three arguments: requestCode, permissions and |
449 |
| - grantResults. |
| 447 | + Permissions are requested through the method 'request_permissions' which |
| 448 | + accepts a list of permissions and an optional callback. |
| 449 | +
|
| 450 | + Any callback will asynchronously receive arguments from |
| 451 | + onRequestPermissionsResult on PythonActivity after requestPermissions is |
| 452 | + called. |
| 453 | +
|
| 454 | + The callback supplied must accept two arguments: 'permissions' and |
| 455 | + 'grantResults' (as supplied to onPermissionsCallbackResult). |
450 | 456 |
|
451 | 457 | Note that calling request_permission on SDK_INT < 23 will return
|
452 |
| - immediately (as run-time permissions are not required), and so this |
453 |
| - callback will never happen. |
| 458 | + immediately (as run-time permissions are not required), and so the callback |
| 459 | + will never happen. Therefore, request_permissions should only be called |
| 460 | + with a callback if calling check_permission has indicated that it is |
| 461 | + necessary. |
| 462 | +
|
| 463 | + The attribute '_java_callback' is initially None, but is set when the first |
| 464 | + permissions request is made. It is set to an instance of |
| 465 | + onRequestPermissionsCallback, which allows the Java callback to be |
| 466 | + propagated to the class method 'python_callback'. This is then, in turn, |
| 467 | + used to call an application callback if provided to request_permissions. |
454 | 468 | """
|
455 |
| - java_callback = onRequestPermissionsCallback(callback) |
456 |
| - python_activity = autoclass('org.kivy.android.PythonActivity') |
457 |
| - python_activity.addPermissionsCallback(java_callback) |
| 469 | + _java_callback = None |
| 470 | + _callbacks = {1: None} |
| 471 | + _callback_id = 1 |
| 472 | + _lock = threading.Lock() |
458 | 473 |
|
| 474 | + @classmethod |
| 475 | + def register_callback(cls): |
| 476 | + """Register Java callback for requestPermissions.""" |
| 477 | + cls._java_callback = onRequestPermissionsCallback(cls.python_callback) |
| 478 | + python_activity = autoclass('org.kivy.android.PythonActivity') |
| 479 | + python_activity.addPermissionsCallback(cls._java_callback) |
459 | 480 |
|
460 |
| -def request_permissions(permissions): |
461 |
| - python_activity = autoclass('org.kivy.android.PythonActivity') |
462 |
| - python_activity.requestPermissions(permissions) |
| 481 | + @classmethod |
| 482 | + def request_permissions(cls, permissions, callback=None): |
| 483 | + """Requests Android permissions from PythonActivity. |
| 484 | + If 'callback' is supplied, the request is made with a new requestCode |
| 485 | + and the callback is stored in the _callbacks dict. When a Java callback |
| 486 | + with the matching requestCode is received, callback will be called |
| 487 | + with arguments of 'permissions' and 'grantResults'. |
| 488 | + """ |
| 489 | + with cls._lock: |
| 490 | + if not cls._java_callback: |
| 491 | + cls.register_callback() |
| 492 | + python_activity = autoclass('org.kivy.android.PythonActivity') |
| 493 | + if not callback: |
| 494 | + python_activity.requestPermissions(permissions) |
| 495 | + else: |
| 496 | + cls._callback_id += 1 |
| 497 | + python_activity.requestPermissionsWithRequestCode( |
| 498 | + permissions, cls._callback_id) |
| 499 | + cls._callbacks[cls._callback_id] = callback |
| 500 | + |
| 501 | + @classmethod |
| 502 | + def python_callback(cls, requestCode, permissions, grantResults): |
| 503 | + """Calls the relevant callback with arguments of 'permissions' |
| 504 | + and 'grantResults'.""" |
| 505 | + if cls._callbacks.get(requestCode): |
| 506 | + cls._callbacks[requestCode](permissions, grantResults) |
| 507 | + |
| 508 | + |
| 509 | +def request_permissions(permissions, callback=None): |
| 510 | + onRequestPermissionsManager.request_permissions(permissions, callback) |
463 | 511 |
|
464 | 512 |
|
465 |
| -def request_permission(permission): |
466 |
| - request_permissions([permission]) |
| 513 | +def request_permission(permission, callback=None): |
| 514 | + request_permissions([permission], callback) |
467 | 515 |
|
468 | 516 |
|
469 | 517 | def check_permission(permission):
|
|
0 commit comments