[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/pythonnative/pythonnative/main/src/pythonnative/bridge/android.py [Back]  [Original]

"""Android transport: the ``com.pythonnative.runtime.PNBridge`` class via Chaquopy.

``PNBridge`` is the only Java class Python touches. Its static methods
mirror the C entry points used on iOS (see ``docs/concepts/bridge.md``).
The reverse direction (native -> Python) is installed by the template's
``MainActivity``, which implements ``PythonHost`` by calling
[`pythonnative.bridge.native_callback`][pythonnative.bridge.native_callback]
through Chaquopy; this transport therefore has nothing to register.
"""

from __future__ import annotations

from typing import Any, Callable, Optional, Tuple

__all__ = ["AndroidTransport"]

BRIDGE_CLASS = "com.pythonnative.runtime.PNBridge"


class AndroidTransport:
    """Thin wrapper over the static ``PNBridge`` methods."""

    name = "android"
    asynchronous_commits = True

    def __init__(self, bridge_class: Any = None) -> None:
        if bridge_class is None:
            from java import jclass

            try:
                bridge_class = jclass(BRIDGE_CLASS)
            except Exception as exc:
                raise RuntimeError(
                    f"{BRIDGE_CLASS} is not on the classpath. Rebuild the app with 'pn run android' or "
                    "'pn build android' so the pythonnative Gradle module is included."
                ) from exc
        self._bridge = bridge_class

    def protocol_version(self) -> int:
        """Return the protocol version compiled into the native library."""
        return int(self._bridge.protocolVersion())

    def apply(self, transaction_json: str) -> str:
        """Apply one serialized transaction (a JSON array of ops)."""
        return str(self._bridge.apply(transaction_json))

    def measure(self, tag: int, max_width: float, max_height: float) -> Tuple[float, float]:
        """Return the intrinsic ``(width, height)`` of the view ``tag`` under the constraints."""
        packed = self._bridge.measure(int(tag), float(max_width), float(max_height))
        if not packed:
            return (0.0, 0.0)
        text = str(packed)
        w, _, h = text.partition(",")
        try:
            return (float(w), float(h))
        except ValueError:
            return (0.0, 0.0)

    def command(self, tag: int, name: str, args_json: str) -> Optional[str]:
        """Run an imperative command on one view; returns its JSON result or ``None``."""
        return _opt_str(self._bridge.command(int(tag), name, args_json))

    def animate(self, tag: int, request_json: str) -> Optional[str]:
        """Handle an animation request (``set`` / ``start`` / ``cancel``) for one view."""
        return _opt_str(self._bridge.animate(int(tag), request_json))

    def call(self, module: str, method: str, args_json: str) -> Optional[str]:
        """Call a native module method with a ``{"call_id", "args"}`` envelope."""
        return _opt_str(self._bridge.call(module, method, args_json))

    def set_callback(self, callback: Callable[[str, int, str, str], Optional[str]]) -> None:
        """No-op: the Android template installs the host through ``PNBridge.setHost``."""
        del callback


def _opt_str(value: Any) -> Optional[str]:
    if value is None:
        return None
    return str(value)

Web Proxy Viewer  |  New URL  |  Original Page