Source code for enamlnative.android.app

"""
Copyright (c) 2017-2022, CodeLV.

Distributed under the terms of the MIT License.

The full license is in the file LICENSE, distributed with this software.
"""
import nativehooks
from asyncio import Future
from atom.api import Dict, Int
from enaml.application import ProxyResolver
from enamlnative.android import factories
from enamlnative.core.app import BridgedApplication


[docs]class AndroidApplication(BridgedApplication): """An Android implementation of an Enaml Native BridgedApplication. A AndroidApplication uses the native Android widget toolkit to implement an Enaml UI that runs in the local process. """ #: Permission code increments on each request _permission_code = Int() #: Pending permission request listeners _permission_requests = Dict(int, Future) # ------------------------------------------------------------------------- # Defaults # ------------------------------------------------------------------------- def _default_resolver(self): """Return a bridge object reference to the MainActivity""" return ProxyResolver(factories=factories.ANDROID_FACTORIES) # ------------------------------------------------------------------------- # App API Implementation # -------------------------------------------------------------------------
[docs] async def has_permission(self, permission: str) -> bool: """Return a future that resolves with the result of the permission""" # Old versions of android did permissions at install time d = self.activity assert d is not None if d.api_level < 23: return True proxy = d.proxy assert proxy is not None activity = proxy.widget assert activity is not None result = await activity.checkSelfPermission(permission) return result == activity.PERMISSION_DENIED
[docs] async def request_permissions(self, *permissions) -> dict[str, bool]: """Return a future that resolves with the results of the permission requests """ # Old versions of android did permissions at install time d = self.activity assert d is not None if d.api_level < 23: return {p: True for p in permissions} request_code = self._permission_code self._permission_code += 1 #: So next call has a unique code # On first request, setup our listener, and request the permission proxy = d.proxy assert proxy is not None activity = proxy.widget assert activity is not None if request_code == 0: activity.setPermissionResultListener(activity.getId()) activity.onRequestPermissionsResult.connect(self._on_permission_result) #: Save a reference f = self.create_future() activity.requestPermissions(permissions, request_code) self._permission_requests[request_code] = f #: Send out the request code, perms, results = await f granted = activity.PERMISSION_GRANTED return {p: r == granted for p, r in zip(perms, results)}
[docs] def show_toast(self, msg: str, long: bool = True): """Show a toast message for the given duration. This is an android specific api. Parameters ----------- msg: str Text to display in the toast message long: bool Display for a long or short (system defined) duration """ if not msg: return from .android_toast import Toast async def show_toast(): toast_id = await Toast.makeText(self, msg, 1 if long else 0) t = Toast(__id__=toast_id) t.show() self.deferred_call(show_toast)
# -------------------------------------------------------------------------- # Bridge API Implementation # --------------------------------------------------------------------------
[docs] def dispatch_events(self, data): """Send the data to the Native application for processing""" nativehooks.publish(data)
# ------------------------------------------------------------------------- # Android utilities API Implementation # ------------------------------------------------------------------------- def _on_permission_result(self, code, perms, results): """Handles a permission request result by passing it to the handler with the given code. """ #: Get the handler for this request f = self._permission_requests.pop(code, None) if f is not None: #: Invoke that handler with the permission request response f.set_result((code, perms, results))
[docs] async def get_system_service(self, cls): """Wrapper for getSystemService. You MUST wrap the class with the appropriate object. """ service = cls.instance() if service: return service d = self.activity assert d is not None proxy = d.proxy assert proxy is not None activity = proxy.widget assert activity is not None service_id = await activity.getSystemService(cls.SERVICE_TYPE) return cls(__id__=service_id)
# ------------------------------------------------------------------------- # Plugin API Implementation # -------------------------------------------------------------------------
[docs] def load_plugin_factories(self): """Add any plugin toolkit widgets to the ANDROID_FACTORIES""" for plugin in self.get_plugins(group="enaml_native_android_factories"): get_factories = plugin.load() PLUGIN_FACTORIES = get_factories() factories.ANDROID_FACTORIES.update(PLUGIN_FACTORIES)