diff --git a/selfdrive/ui/mici/layouts/main.py b/selfdrive/ui/mici/layouts/main.py index d325136689..f0580f240f 100644 --- a/selfdrive/ui/mici/layouts/main.py +++ b/selfdrive/ui/mici/layouts/main.py @@ -8,6 +8,8 @@ from openpilot.selfdrive.ui.mici.layouts.onboarding import OnboardingWindow from openpilot.system.ui.widgets import Widget from openpilot.system.ui.widgets.scroller import Scroller from openpilot.system.ui.lib.application import gui_app +from openpilot.system.hardware import PC +from openpilot.system.ui.lib.wifi_manager import WifiManager ONROAD_DELAY = 2.5 # seconds @@ -23,6 +25,8 @@ class MiciMainLayout(Scroller): self._prev_standstill = False self._onroad_time_delay: float | None = None self._setup = False + # Start monitoring tethering at UI startup; settings may never be opened. + self._wifi_manager = None if PC else WifiManager(active=False) # Initialize widgets self._home_layout = MiciHomeLayout() @@ -65,7 +69,9 @@ class MiciMainLayout(Scroller): if self._settings_layout is None: from openpilot.selfdrive.ui.mici.layouts.settings.settings import SettingsLayout - self._settings_layout = SettingsLayout() + if self._wifi_manager is None: + self._wifi_manager = WifiManager(active=False) + self._settings_layout = SettingsLayout(self._wifi_manager) self._settings_layout.set_rect(rl.Rectangle(0, 0, gui_app.width, gui_app.height)) gui_app.push_widget(self._settings_layout) diff --git a/selfdrive/ui/mici/layouts/settings/network/network_layout.py b/selfdrive/ui/mici/layouts/settings/network/network_layout.py index 9f6fae4b5f..ee31406927 100644 --- a/selfdrive/ui/mici/layouts/settings/network/network_layout.py +++ b/selfdrive/ui/mici/layouts/settings/network/network_layout.py @@ -10,10 +10,10 @@ from openpilot.system.ui.lib.wifi_manager import WifiManager, Network, MeteredTy class NetworkLayoutMici(NavScroller): - def __init__(self): + def __init__(self, wifi_manager: WifiManager): super().__init__() - self._wifi_manager = WifiManager() + self._wifi_manager = wifi_manager self._wifi_manager.set_active(False) self._wifi_ui = WifiUIMici(self._wifi_manager) diff --git a/selfdrive/ui/mici/layouts/settings/settings.py b/selfdrive/ui/mici/layouts/settings/settings.py index 58e409df95..e153dc88e0 100644 --- a/selfdrive/ui/mici/layouts/settings/settings.py +++ b/selfdrive/ui/mici/layouts/settings/settings.py @@ -12,6 +12,7 @@ from openpilot.selfdrive.ui.mici.layouts.settings.driving_model import DrivingMo from openpilot.selfdrive.ui.mici.layouts.settings.galaxy import GalaxyBigButton from openpilot.selfdrive.ui.mici.layouts.settings.visuals import VisualsLayoutMici from openpilot.system.ui.lib.application import gui_app, FontWeight +from openpilot.system.ui.lib.wifi_manager import WifiManager class SettingsBigButton(BigButton): @@ -56,7 +57,7 @@ class ForceDriveStateBigButton(BigMultiToggle): class SettingsLayout(NavScroller): - def __init__(self): + def __init__(self, wifi_manager: WifiManager): super().__init__() self._params = Params() @@ -64,7 +65,7 @@ class SettingsLayout(NavScroller): toggles_btn = SettingsBigButton("toggles", "", gui_app.texture("icons_mici/settings.png", 64, 64)) toggles_btn.set_click_callback(lambda: gui_app.push_widget(toggles_panel)) - network_panel = NetworkLayoutMici() + network_panel = NetworkLayoutMici(wifi_manager) network_btn = SettingsBigButton("network", "", gui_app.texture("icons_mici/settings/network/wifi_strength_full.png", 76, 56)) network_btn.set_click_callback(lambda: gui_app.push_widget(network_panel)) diff --git a/selfdrive/ui/mici/tests/test_tethering_monitor_startup.py b/selfdrive/ui/mici/tests/test_tethering_monitor_startup.py new file mode 100644 index 0000000000..7217fb1615 --- /dev/null +++ b/selfdrive/ui/mici/tests/test_tethering_monitor_startup.py @@ -0,0 +1,38 @@ +import ast +from pathlib import Path + + +ROOT = Path(__file__).resolve().parents[4] + + +def _method(path: str, class_name: str, method_name: str) -> ast.FunctionDef: + tree = ast.parse((ROOT / path).read_text()) + cls = next(node for node in tree.body if isinstance(node, ast.ClassDef) and node.name == class_name) + return next(node for node in cls.body if isinstance(node, ast.FunctionDef) and node.name == method_name) + + +def _calls(method: ast.FunctionDef, name: str) -> list[ast.Call]: + return [node for node in ast.walk(method) if isinstance(node, ast.Call) and isinstance(node.func, ast.Name) and node.func.id == name] + + +def test_mici_starts_tethering_monitor_before_opening_settings(): + main_init = _method("selfdrive/ui/mici/layouts/main.py", "MiciMainLayout", "__init__") + manager_creation = _calls(main_init, "WifiManager") + assert any(any(keyword.arg == "active" and isinstance(keyword.value, ast.Constant) and keyword.value.value is False + for keyword in call.keywords) for call in manager_creation) + + open_settings = _method("selfdrive/ui/mici/layouts/main.py", "MiciMainLayout", "_open_settings") + settings_creation = _calls(open_settings, "SettingsLayout") + assert any(len(call.args) == 1 and isinstance(call.args[0], ast.Attribute) and call.args[0].attr == "_wifi_manager" + for call in settings_creation) + + settings_init = _method("selfdrive/ui/mici/layouts/settings/settings.py", "SettingsLayout", "__init__") + network_creation = _calls(settings_init, "NetworkLayoutMici") + assert any(len(call.args) == 1 and isinstance(call.args[0], ast.Name) and call.args[0].id == "wifi_manager" + for call in network_creation) + + network_init = _method("selfdrive/ui/mici/layouts/settings/network/network_layout.py", "NetworkLayoutMici", "__init__") + assert any(isinstance(node, ast.Assign) + and any(isinstance(target, ast.Attribute) and target.attr == "_wifi_manager" for target in node.targets) + and isinstance(node.value, ast.Name) and node.value.id == "wifi_manager" + for node in ast.walk(network_init)) diff --git a/system/ui/lib/wifi_manager.py b/system/ui/lib/wifi_manager.py index 2f5e184e88..9ceaf86565 100644 --- a/system/ui/lib/wifi_manager.py +++ b/system/ui/lib/wifi_manager.py @@ -174,9 +174,9 @@ class WifiState: class WifiManager: - def __init__(self): + def __init__(self, active: bool = True): self._networks: list[Network] = [] # an unsorted list of available Networks. a Network can be comprised of multiple APs - self._active = True # used to not run when not in settings + self._active = active # network scans only run while settings are open self._exit = False self._fake_networking = False self._nmcli_networking = False