|
1 | 1 | import os |
| 2 | +import traceback |
2 | 3 |
|
3 | 4 | try: |
4 | 5 | import zipfile |
@@ -232,3 +233,115 @@ def is_installed_by_name(app_fullname): |
232 | 233 | print(f"Checking if app {app_fullname} is installed...") |
233 | 234 | return PackageManager.is_installed_by_path(f"apps/{app_fullname}") or PackageManager.is_installed_by_path(f"builtin/apps/{app_fullname}") |
234 | 235 |
|
| 236 | + @staticmethod |
| 237 | + def execute_script(script_source, is_file, classname, cwd=None): |
| 238 | + """Run the script in the current thread. Returns True if successful.""" |
| 239 | + import utime # for timing read and compile |
| 240 | + import lvgl as lv |
| 241 | + import mpos.ui |
| 242 | + import _thread |
| 243 | + thread_id = _thread.get_ident() |
| 244 | + compile_name = 'script' if not is_file else script_source |
| 245 | + print(f"Thread {thread_id}: executing script with cwd: {cwd}") |
| 246 | + try: |
| 247 | + if is_file: |
| 248 | + print(f"Thread {thread_id}: reading script from file {script_source}") |
| 249 | + with open(script_source, 'r') as f: # No need to check if it exists as exceptions are caught |
| 250 | + start_time = utime.ticks_ms() |
| 251 | + script_source = f.read() |
| 252 | + read_time = utime.ticks_diff(utime.ticks_ms(), start_time) |
| 253 | + print(f"execute_script: reading script_source took {read_time}ms") |
| 254 | + script_globals = { |
| 255 | + 'lv': lv, |
| 256 | + '__name__': "__main__" |
| 257 | + } |
| 258 | + print(f"Thread {thread_id}: starting script") |
| 259 | + import sys |
| 260 | + path_before = sys.path[:] # Make a copy, not a reference |
| 261 | + if cwd: |
| 262 | + sys.path.append(cwd) |
| 263 | + try: |
| 264 | + start_time = utime.ticks_ms() |
| 265 | + compiled_script = compile(script_source, compile_name, 'exec') |
| 266 | + compile_time = utime.ticks_diff(utime.ticks_ms(), start_time) |
| 267 | + print(f"execute_script: compiling script_source took {compile_time}ms") |
| 268 | + start_time = utime.ticks_ms() |
| 269 | + exec(compiled_script, script_globals) |
| 270 | + end_time = utime.ticks_diff(utime.ticks_ms(), start_time) |
| 271 | + print(f"apps.py execute_script: exec took {end_time}ms") |
| 272 | + # Introspect globals |
| 273 | + classes = {k: v for k, v in script_globals.items() if isinstance(v, type)} |
| 274 | + functions = {k: v for k, v in script_globals.items() if callable(v) and not isinstance(v, type)} |
| 275 | + variables = {k: v for k, v in script_globals.items() if not callable(v)} |
| 276 | + print("Classes:", classes.keys()) # This lists a whole bunch of classes, including lib/mpos/ stuff |
| 277 | + print("Functions:", functions.keys()) |
| 278 | + print("Variables:", variables.keys()) |
| 279 | + main_activity = script_globals.get(classname) |
| 280 | + if main_activity: |
| 281 | + from ..app.activity import Activity |
| 282 | + from .intent import Intent |
| 283 | + start_time = utime.ticks_ms() |
| 284 | + Activity.startActivity(None, Intent(activity_class=main_activity)) |
| 285 | + end_time = utime.ticks_diff(utime.ticks_ms(), start_time) |
| 286 | + print(f"execute_script: Activity.startActivity took {end_time}ms") |
| 287 | + else: |
| 288 | + print(f"Warning: could not find app's main_activity {classname}") |
| 289 | + return False |
| 290 | + except Exception as e: |
| 291 | + print(f"Thread {thread_id}: exception during execution:") |
| 292 | + # Print stack trace with exception type, value, and traceback |
| 293 | + tb = getattr(e, '__traceback__', None) |
| 294 | + traceback.print_exception(type(e), e, tb) |
| 295 | + return False |
| 296 | + finally: |
| 297 | + # Always restore sys.path, even if we return early or raise an exception |
| 298 | + print(f"Thread {thread_id}: script {compile_name} finished, restoring sys.path from {sys.path} to {path_before}") |
| 299 | + sys.path = path_before |
| 300 | + return True |
| 301 | + except Exception as e: |
| 302 | + print(f"Thread {thread_id}: error:") |
| 303 | + tb = getattr(e, '__traceback__', None) |
| 304 | + traceback.print_exception(type(e), e, tb) |
| 305 | + return False |
| 306 | + |
| 307 | + @staticmethod |
| 308 | + def start_app(fullname): |
| 309 | + """Start an app by fullname. Returns True if successful.""" |
| 310 | + import mpos.ui |
| 311 | + mpos.ui.set_foreground_app(fullname) |
| 312 | + import utime |
| 313 | + start_time = utime.ticks_ms() |
| 314 | + app = PackageManager.get(fullname) |
| 315 | + if not app: |
| 316 | + print(f"Warning: start_app can't find app {fullname}") |
| 317 | + return |
| 318 | + if not app.installed_path: |
| 319 | + print(f"Warning: start_app can't start {fullname} because no it doesn't have an installed_path") |
| 320 | + return |
| 321 | + entrypoint = "assets/main.py" |
| 322 | + classname = "Main" |
| 323 | + if not app.main_launcher_activity: |
| 324 | + print(f"WARNING: app {fullname} doesn't have a main_launcher_activity, defaulting to class {classname} in {entrypoint}") |
| 325 | + else: |
| 326 | + entrypoint = app.main_launcher_activity.get('entrypoint') |
| 327 | + classname = app.main_launcher_activity.get("classname") |
| 328 | + result = PackageManager.execute_script(app.installed_path + "/" + entrypoint, True, classname, app.installed_path + "/assets/") |
| 329 | + # Launchers have the bar, other apps don't have it |
| 330 | + if app.is_valid_launcher(): |
| 331 | + mpos.ui.topmenu.open_bar() |
| 332 | + else: |
| 333 | + mpos.ui.topmenu.close_bar() |
| 334 | + end_time = utime.ticks_diff(utime.ticks_ms(), start_time) |
| 335 | + print(f"start_app() took {end_time}ms") |
| 336 | + return result |
| 337 | + |
| 338 | + @staticmethod |
| 339 | + def restart_launcher(): |
| 340 | + """Restart the launcher by stopping all activities and starting the launcher app.""" |
| 341 | + import mpos.ui |
| 342 | + print("restart_launcher") |
| 343 | + # Stop all apps |
| 344 | + mpos.ui.remove_and_stop_all_activities() |
| 345 | + # No need to stop the other launcher first, because it exits after building the screen |
| 346 | + return PackageManager.start_app(PackageManager.get_launcher().fullname) |
| 347 | + |
0 commit comments