Skip to content

Commit

Permalink
add public decorators to request BLE adapter and permissions #27
Browse files Browse the repository at this point in the history
  • Loading branch information
b3b committed Aug 14, 2021
1 parent b8d0aad commit 0fa8b1d
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 20 deletions.
12 changes: 10 additions & 2 deletions able/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,11 @@ class WriteType(IntEnum):


if platform == 'android':
from able.android.dispatcher import BluetoothDispatcher
from able.android.dispatcher import (
BluetoothDispatcher,
require_bluetooth_enabled,
require_runtime_permissions,
)
else:

# mock android and PyJNIus modules usage
Expand All @@ -43,7 +47,11 @@ def __call__(self, *args, **kwargs):
jnius.autoclass = mocked_autoclass()
sys.modules['jnius'] = jnius

from able.dispatcher import BluetoothDispatcherBase
from able.dispatcher import (
BluetoothDispatcherBase,
require_bluetooth_enabled,
require_runtime_permissions,
)

class BluetoothDispatcher(BluetoothDispatcherBase):
"""Bluetooth Low Energy interface
Expand Down
54 changes: 36 additions & 18 deletions able/android/dispatcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@


def require_bluetooth_enabled(method):
"""Decorator to execute `BluetoothDispatcher` method when bluetooth adapter becomes ready."""

@wraps(method)
def wrapper(self, *args, **kwargs):
Expand All @@ -41,6 +40,21 @@ def wrapper(self, *args, **kwargs):
return wrapper


def require_runtime_permissions(method):

@wraps(method)
def wrapper(self, *args, **kwargs):
self._run_on_runtime_permissions = partial(method, self, *args, **kwargs)
if self._is_service_context or self._check_runtime_permissions():
self._run_on_runtime_permissions()
self._run_on_runtime_permissions = None
else:
Logger.debug("Request runtime permissions")
self._request_runtime_permissions()

return wrapper


class BluetoothDispatcher(BluetoothDispatcherBase):

@property
Expand Down Expand Up @@ -74,11 +88,9 @@ def _request_runtime_permissions(self):
self.on_runtime_permissions)

@require_bluetooth_enabled
@require_runtime_permissions
def start_scan(self):
if self._is_service_context or self._check_runtime_permissions():
self._ble.startScan(self.enable_ble_code)
else:
self._request_runtime_permissions()
self._ble.startScan(self.enable_ble_code)

def stop_scan(self):
self._ble.stopScan()
Expand Down Expand Up @@ -117,23 +129,29 @@ def _start_advertising(self, advertiser):
def _set_name(self, value):
self.adapter.setName(value)

def on_runtime_permissions(self, permissions, grant_results):
if permissions and all(grant_results):
self.start_scan()
else:
Logger.error(
'Permissions necessary to obtain scan results are not granted'
)
self.dispatch('on_scan_started', False)

def on_activity_result(self, requestCode, resultCode, intent):
if requestCode == self.enable_ble_code:
self.on_bluetooth_enabled(resultCode == Activity.RESULT_OK)

def on_bluetooth_enabled(self, enabled):
callback = self._run_on_bluetooth_enabled
self._run_on_bluetooth_enabled = None
if enabled:
if self._run_on_bluetooth_enabled:
self._run_on_bluetooth_enabled()
elif self._run_on_bluetooth_enabled:
if self._run_on_bluetooth_enabled.func == self.start_scan:
if callback:
callback()
elif callback:
if callback.func == self.start_scan:
self.dispatch('on_scan_started', False)

def on_runtime_permissions(self, permissions, grant_results):
callback = self._run_on_runtime_permissions
self._run_on_runtime_permissions = None
if permissions and all(grant_results):
if callback:
callback()
else:
Logger.error(
'Permissions necessary to obtain scan results are not granted'
)
if callback.func == self.start_scan:
self.dispatch('on_scan_started', False)
15 changes: 15 additions & 0 deletions able/dispatcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,21 @@ def __getattr__(self, name):
raise Exception(self.msg)


def require_bluetooth_enabled(method):
"""Decorator to start a system activity that allows the user
to turn on Bluetooth, if Bluetooth is not enabled.
Calls `BluetoothDispatcher` method when bluetooth adapter becomes ready.
"""
return method


def require_runtime_permissions(method):
"""Decorator to ask for runtime permission to access location.
Calls `BluetoothDispatcher` method when permission is granted.
"""
return method


class BluetoothDispatcherBase(EventDispatcher):
__events__ = (
'on_device', 'on_scan_started', 'on_scan_completed', 'on_services',
Expand Down
7 changes: 7 additions & 0 deletions docs/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,13 @@ BluetoothDispatcher
on_rssi_updated,
on_mtu_changed,

Decorators
""""""""""

.. autofunction:: require_bluetooth_enabled
.. autofunction:: require_runtime_permissions


Advertisement
"""""""""""""

Expand Down

0 comments on commit 0fa8b1d

Please sign in to comment.