Files
firestar5683 a82935f326 User interfaces and Android Auto
Integrate onroad views, configurable widgets, local settings, steering-profile contracts, Bluetooth and Android Auto with their device and runtime services.

Co-authored-by: Adeeb Shihadeh <adeebshihadeh@gmail.com>
Co-authored-by: Daniel Koepping <elkoled@gmail.com>
Co-authored-by: Danny <dannyirwin31@yahoo.com>
Co-authored-by: DimitriChrysafis <Dimitri.chrysafis@gmail.com>
Co-authored-by: Dom <168790843+firestar5683@users.noreply.github.com>
Co-authored-by: Harald Schäfer <harald.the.engineer@gmail.com>
Co-authored-by: Prabhaav Pillai <prabhaav@msu.edu>
Co-authored-by: Shane Smiskol <shane@smiskol.com>
Co-authored-by: dirwin31 <83434411+dirwin31@users.noreply.github.com>
Co-authored-by: firestarsdog <229254897+firestarsdog@users.noreply.github.com>
Co-authored-by: stef <19478336+stefpi@users.noreply.github.com>
Co-authored-by: whoisdomi <dcantu83@gmail.com>

Co-authored-by: Intelli <contact@intelli.software>
Co-authored-by: pharmacomaniac <blittle65@gmail.com>

Co-authored-by: prabhaavp <prabhaav@msu.edu>
2026-10-14 20:02:39 -05:00

74 lines
3.4 KiB
Python

"""Read-only native view of the single parked offline-map operation owner."""
from collections.abc import Callable
from concurrent.futures import Future, ThreadPoolExecutor
import time
from openpilot.starpilot.ui.feature_settings_state import FeatureRow, FeatureSettingsState
def map_page(status: dict | None) -> FeatureSettingsState:
if not isinstance(status, dict) or status.get("schemaVersion") != 1:
rows = (FeatureRow("", "Map manager", "Unavailable", reason="Open Galaxy when the parked map manager is available"),)
else:
state = status.get("state")
if state not in ("idle", "transferring", "validating", "selecting", "completed", "canceled", "failed", "interrupted", "unavailable"):
return map_page(None)
generation = status.get("selectedGeneration")
if not isinstance(generation, str) or generation and (len(generation) != 64 or any(c not in "0123456789abcdef" for c in generation)):
return map_page(None)
rows = (FeatureRow("", "Operation", state.replace("_", " ").title()),
FeatureRow("", "Selected map", generation[:12] + "…" if generation else "None",
reason="Selection applies on the next map service start; it does not prove an active map"),)
if state in ("transferring", "validating", "selecting"):
completed, total = status.get("completedGroups"), status.get("totalGroups")
if type(completed) is int and type(total) is int and 0 <= completed <= total:
rows += (FeatureRow("", "Progress", f"{completed} / {total} groups"),)
if state in ("failed", "interrupted", "unavailable"):
rows += (FeatureRow("", "Recovery", "Open Galaxy", reason="Review the parked map operation"),)
rows += (FeatureRow("", "Manage regions", "Open Galaxy", reason="Parked downloads and cancellation are managed there"),)
return FeatureSettingsState(title="Offline Maps", subtitle="Selected region and parked operation status.", rows=rows)
def _request_status() -> dict:
from openpilot.starpilot.maps.operation_owner import request_operation
response = request_operation({"version": 1, "op": "status"}, timeout_s=0.75)
if (type(response) is not dict or response.get("version") != 1 or response.get("ok") is not True or
type(response.get("result")) is not dict):
raise ValueError("Map owner unavailable")
return response["result"]
class MapStatusSource:
"""Bounded background socket read: no render-frame I/O or download authority."""
REFRESH_NS = 3_000_000_000
def __init__(self, request: Callable[[], dict] = _request_status, clock: Callable[[], int] = time.monotonic_ns):
self.request = request
self.clock = clock
self.executor = ThreadPoolExecutor(max_workers=1, thread_name_prefix="map-status")
self.pending: Future | None = None
self.next_read_ns = 0
self.status: dict | None = None
self.closed = False
def snapshot(self) -> FeatureSettingsState:
if self.closed:
return map_page(None)
now = self.clock()
if self.pending is not None and self.pending.done():
try:
self.status = self.pending.result()
except (OSError, RuntimeError, ValueError):
self.status = None
self.pending = None
if self.pending is None and now >= self.next_read_ns:
self.pending = self.executor.submit(self.request)
self.next_read_ns = now + self.REFRESH_NS
return map_page(self.status)
def close(self) -> None:
self.closed = True
self.executor.shutdown(wait=False, cancel_futures=True)