IQ.Pilot Release Commit @ 0babf78
This commit is contained in:
@@ -26,7 +26,7 @@ from openpilot.system.hardware import HARDWARE, PC
|
||||
from openpilot.system.ui.lib.multilang import multilang
|
||||
from openpilot.common.realtime import Ratekeeper
|
||||
|
||||
from openpilot.system.ui.iqpilot.lib.application import IQAppHooks
|
||||
from openpilot.system.ui.iqwidgets.lib.application import IQAppHooks
|
||||
from openpilot.system.ui.lib.screen_recorder import ScreenRecorder
|
||||
|
||||
_DEFAULT_FPS = int(os.getenv("FPS", {'tizi': 20, 'tici': 20}.get(HARDWARE.get_device_type(), 60)))
|
||||
|
||||
@@ -33,10 +33,19 @@ EMOJI_REGEX = re.compile(
|
||||
flags=re.UNICODE
|
||||
)
|
||||
|
||||
_emoji_font_loaded = False
|
||||
|
||||
def _load_emoji_font() -> ImageFont.FreeTypeFont | None:
|
||||
global _emoji_font
|
||||
if _emoji_font is None:
|
||||
_emoji_font = ImageFont.truetype(str(FONT_DIR.joinpath("NotoColorEmoji.ttf")), 109)
|
||||
global _emoji_font, _emoji_font_loaded
|
||||
if not _emoji_font_loaded:
|
||||
_emoji_font_loaded = True
|
||||
try:
|
||||
# FONT_DIR is an importlib.resources path. Inside the setup zipapp it points into the archive,
|
||||
# so str() yields a path through the .zip that PIL can't open ("cannot open resource"). Read
|
||||
# the bytes and hand PIL a file object so it works both on disk and inside the zipapp.
|
||||
_emoji_font = ImageFont.truetype(io.BytesIO(FONT_DIR.joinpath("NotoColorEmoji.ttf").read_bytes()), 109)
|
||||
except Exception:
|
||||
_emoji_font = None # never crash the whole UI over an emoji glyph
|
||||
return _emoji_font
|
||||
|
||||
def find_emoji(text):
|
||||
@@ -44,12 +53,15 @@ def find_emoji(text):
|
||||
|
||||
def emoji_tex(emoji):
|
||||
if emoji not in _cache:
|
||||
font = _load_emoji_font()
|
||||
if font is None:
|
||||
return None
|
||||
img = Image.new("RGBA", (128, 128), (0, 0, 0, 0))
|
||||
draw = ImageDraw.Draw(img)
|
||||
draw.text((0, 0), emoji, font=_load_emoji_font(), embedded_color=True)
|
||||
draw.text((0, 0), emoji, font=font, embedded_color=True)
|
||||
with io.BytesIO() as buffer:
|
||||
img.save(buffer, format="PNG")
|
||||
l = buffer.tell()
|
||||
buffer.seek(0)
|
||||
_cache[emoji] = rl.load_texture_from_image(rl.load_image_from_memory(".png", buffer.getvalue(), l))
|
||||
return _cache[emoji]
|
||||
return _cache.get(emoji)
|
||||
|
||||
@@ -67,6 +67,9 @@ class MeteredType(IntEnum):
|
||||
NO = 2
|
||||
|
||||
|
||||
_WARNED_UNSUPPORTED_NETWORKS: set[tuple[int, int, int]] = set()
|
||||
|
||||
|
||||
def get_security_type(flags: int, wpa_flags: int, rsn_flags: int) -> SecurityType:
|
||||
wpa_props = wpa_flags | rsn_flags
|
||||
|
||||
@@ -83,7 +86,10 @@ def get_security_type(flags: int, wpa_flags: int, rsn_flags: int) -> SecurityTyp
|
||||
# WPA2, WPA2+WPA3 mixed, or WPA — all handled via WPA key_mgmt (NM negotiates SAE if available)
|
||||
return SecurityType.WPA2
|
||||
else:
|
||||
cloudlog.warning(f"Unsupported network! flags: {flags}, wpa_flags: {wpa_flags}, rsn_flags: {rsn_flags}")
|
||||
_key = (flags, wpa_flags, rsn_flags)
|
||||
if _key not in _WARNED_UNSUPPORTED_NETWORKS:
|
||||
_WARNED_UNSUPPORTED_NETWORKS.add(_key)
|
||||
cloudlog.warning(f"Unsupported network! flags: {flags}, wpa_flags: {wpa_flags}, rsn_flags: {rsn_flags}")
|
||||
return SecurityType.UNSUPPORTED
|
||||
|
||||
|
||||
@@ -630,6 +636,7 @@ class WifiManager:
|
||||
cloudlog.warning("No WiFi device found")
|
||||
return
|
||||
|
||||
self._set_device_autoconnect(True)
|
||||
self._connecting_to_ssid = ssid
|
||||
self._router_main.send(new_method_call(self._nm, 'ActivateConnection', 'ooo',
|
||||
(conn_path, self._wifi_device, "/")))
|
||||
@@ -639,6 +646,37 @@ class WifiManager:
|
||||
else:
|
||||
threading.Thread(target=worker, daemon=True).start()
|
||||
|
||||
def disconnect_connection(self, ssid: str, block: bool = False):
|
||||
def worker():
|
||||
if self._router_main is None:
|
||||
cloudlog.warning(f"WiFi not ready while disconnecting {ssid}")
|
||||
return
|
||||
|
||||
if ssid not in self._get_connections():
|
||||
return
|
||||
|
||||
# the profile stays saved and untouched; without clearing autoconnect on the device
|
||||
# NetworkManager re-associates within seconds
|
||||
self._set_device_autoconnect(False)
|
||||
self._connecting_to_ssid = ""
|
||||
self._deactivate_connection(ssid)
|
||||
self._update_networks()
|
||||
self._enqueue_callbacks(self._disconnected)
|
||||
|
||||
if block:
|
||||
worker()
|
||||
else:
|
||||
threading.Thread(target=worker, daemon=True).start()
|
||||
|
||||
def _set_device_autoconnect(self, enabled: bool) -> None:
|
||||
if self._router_main is None or self._wifi_device is None:
|
||||
return
|
||||
|
||||
dev_addr = DBusAddress(self._wifi_device, bus_name=NM, interface=NM_DEVICE_IFACE)
|
||||
reply = self._router_main.send_and_get_reply(Properties(dev_addr).set('Autoconnect', 'b', enabled))
|
||||
if reply.header.message_type == MessageType.error:
|
||||
cloudlog.warning(f'Failed to set device autoconnect={enabled}: {reply}')
|
||||
|
||||
def _deactivate_connection(self, ssid: str):
|
||||
target_conn_path = self._get_connections().get(ssid, None)
|
||||
if target_conn_path is None:
|
||||
|
||||
Reference in New Issue
Block a user