You've already forked MicroPythonOS
mirror of
https://github.com/m5stack/MicroPythonOS.git
synced 2026-05-20 11:51:27 -07:00
PackageManager: refresh applist after (un)install, reduce parse_manifest() calls
This commit is contained in:
@@ -83,7 +83,7 @@ class Launcher(mpos.apps.Activity):
|
||||
label.set_width(iconcont_width)
|
||||
label.align(lv.ALIGN.BOTTOM_MID, 0, 0)
|
||||
label.set_style_text_align(lv.TEXT_ALIGN.CENTER, 0)
|
||||
app_cont.add_event_cb(lambda e, path=app_dir_fullpath: mpos.apps.start_app(path), lv.EVENT.CLICKED, None)
|
||||
app_cont.add_event_cb(lambda e, fullname=app.fullname: mpos.apps.start_app(fullname), lv.EVENT.CLICKED, None)
|
||||
app_cont.add_event_cb(lambda e, app_cont=app_cont: self.focus_app_cont(app_cont),lv.EVENT.FOCUSED,None)
|
||||
app_cont.add_event_cb(lambda e, app_cont=app_cont: self.defocus_app_cont(app_cont),lv.EVENT.DEFOCUSED,None)
|
||||
if focusgroup:
|
||||
|
||||
@@ -105,31 +105,25 @@ def execute_script_new_thread(scriptname, is_file):
|
||||
except Exception as e:
|
||||
print("main.py: execute_script_new_thread(): error starting new thread thread: ", e)
|
||||
|
||||
def start_app_by_name(app_name, is_launcher=False):
|
||||
mpos.ui.set_foreground_app(app_name)
|
||||
custom_app_dir=f"apps/{app_name}"
|
||||
builtin_app_dir=f"builtin/apps/{app_name}"
|
||||
try:
|
||||
stat = uos.stat(custom_app_dir)
|
||||
start_app(custom_app_dir, is_launcher)
|
||||
except OSError:
|
||||
start_app(builtin_app_dir, is_launcher)
|
||||
|
||||
def start_app(app_dir, is_launcher=False):
|
||||
print(f"main.py start_app({app_dir},{is_launcher})")
|
||||
def start_app(fullname):
|
||||
mpos.ui.set_foreground_app(fullname)
|
||||
import utime
|
||||
start_time = utime.ticks_ms()
|
||||
mpos.ui.set_foreground_app(app_dir) # would be better to store only the app name...
|
||||
app = mpos.apps.parse_manifest(app_dir)
|
||||
print(f"start_app parsed manifest and got: {str(app)}")
|
||||
main_launcher_activity = find_main_launcher_activity(app)
|
||||
if not main_launcher_activity:
|
||||
print(f"WARNING: can't start {app_dir} because no main_launcher_activity was found.")
|
||||
app = PackageManager.get(fullname)
|
||||
if not app:
|
||||
print(f"Warning: start_app could not find app {fullname}, aborting...")
|
||||
return
|
||||
start_script_fullpath = f"{app_dir}/{main_launcher_activity.get('entrypoint')}"
|
||||
execute_script(start_script_fullpath, True, app_dir + "/assets/", main_launcher_activity.get("classname"))
|
||||
if not app.installed_path:
|
||||
print(f"Warning: start_app could not find installed_path for {fullname}, aborting...")
|
||||
return
|
||||
main_launcher_activity = PackageManager.find_main_launcher_activity(app)
|
||||
if not main_launcher_activity:
|
||||
print(f"WARNING: can't start {fullname} because no main_launcher_activity was found.")
|
||||
return
|
||||
start_script_fullpath = f"{app.installed_path}/{main_launcher_activity.get('entrypoint')}"
|
||||
execute_script(start_script_fullpath, True, app.installed_path + "/assets/", main_launcher_activity.get("classname"))
|
||||
# Launchers have the bar, other apps don't have it
|
||||
if is_launcher:
|
||||
if PackageManager.is_launcher(fullname):
|
||||
mpos.ui.topmenu.open_bar()
|
||||
else:
|
||||
mpos.ui.topmenu.close_bar()
|
||||
@@ -143,29 +137,9 @@ def restart_launcher():
|
||||
# No need to stop the other launcher first, because it exits after building the screen
|
||||
for app in mpos.package_manager.PackageManager.get_app_list():
|
||||
#print(f"checking {app}")
|
||||
if app.category == "launcher" and find_main_launcher_activity(app):
|
||||
if app.category == "launcher" and PackageManager.find_main_launcher_activity(app):
|
||||
print(f"Found launcher, starting {app.fullname}")
|
||||
start_app_by_name(app.fullname, True)
|
||||
|
||||
def find_main_launcher_activity(app):
|
||||
result = None
|
||||
for activity in app.activities:
|
||||
if not activity.get("entrypoint") or not activity.get("classname"):
|
||||
print(f"Warning: activity {activity} has no entrypoint and classname, skipping...")
|
||||
continue
|
||||
print("checking activity's intent_filters...")
|
||||
for intent_filter in activity.get("intent_filters"):
|
||||
print("checking intent_filter...")
|
||||
if intent_filter.get("action") == "main" and intent_filter.get("category") == "launcher":
|
||||
print("found main_launcher!")
|
||||
result = activity
|
||||
break
|
||||
return result
|
||||
|
||||
def is_launcher(app_name):
|
||||
print(f"checking is_launcher for {app_name}")
|
||||
# Simple check, could be more elaborate by checking the MANIFEST.JSON for the app...
|
||||
return "launcher" in app_name or len(mpos.ui.screen_stack) < 2 # assumes the first one on the stack is the launcher
|
||||
start_app(app.fullname)
|
||||
|
||||
|
||||
class App:
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import os
|
||||
import mpos.apps
|
||||
import mpos.ui # wont be needed after improving is_launcher()
|
||||
|
||||
try:
|
||||
import zipfile
|
||||
@@ -52,7 +53,7 @@ class PackageManager:
|
||||
@classmethod
|
||||
def get_app_list(cls):
|
||||
if not cls._app_list:
|
||||
cls.find_apps()
|
||||
cls.refresh_apps()
|
||||
return cls._app_list
|
||||
|
||||
# --------------------------------------------------------------------- #
|
||||
@@ -71,13 +72,23 @@ class PackageManager:
|
||||
def get(cls, fullname):
|
||||
return cls._by_fullname.get(fullname)
|
||||
|
||||
# --------------------------------------------------------------------- #
|
||||
# Clear everything – useful when you want to force a full rescan
|
||||
# --------------------------------------------------------------------- #
|
||||
@classmethod
|
||||
def clear(cls):
|
||||
"""Empty the internal caches. Call ``get_app_list()`` afterwards to repopulate."""
|
||||
cls._app_list = []
|
||||
cls._by_fullname = {}
|
||||
|
||||
# --------------------------------------------------------------------- #
|
||||
# discovery & population
|
||||
# --------------------------------------------------------------------- #
|
||||
@classmethod
|
||||
def find_apps(cls):
|
||||
print("\n\n\nPackageManager finding apps...")
|
||||
def refresh_apps(cls):
|
||||
print("PackageManager finding apps...")
|
||||
|
||||
cls.clear() # <-- this guarantees both containers are empty
|
||||
seen = set() # avoid processing the same fullname twice
|
||||
apps_dir = "apps"
|
||||
apps_dir_builtin = "builtin/apps"
|
||||
@@ -127,15 +138,14 @@ class PackageManager:
|
||||
# ---- sort the list by display name (case-insensitive) ------------
|
||||
cls._app_list.sort(key=lambda a: a.name.lower())
|
||||
|
||||
|
||||
@staticmethod
|
||||
def uninstall_app(app_fullname):
|
||||
try:
|
||||
import shutil
|
||||
shutil.rmtree(f"apps/{app_fullname}") # never in builtin/apps because those can't be uninstalled
|
||||
# TODO: also remove it from the app_list
|
||||
except Exception as e:
|
||||
print(f"Removing app_folder {app_folder} got error: {e}")
|
||||
PackageManager.refresh_apps()
|
||||
|
||||
@staticmethod
|
||||
def install_mpk(temp_zip_path, dest_folder):
|
||||
@@ -151,6 +161,7 @@ class PackageManager:
|
||||
except Exception as e:
|
||||
print(f"Unzip and cleanup failed: {e}")
|
||||
# Would be good to show error message here if it fails...
|
||||
PackageManager.refresh_apps()
|
||||
|
||||
@staticmethod
|
||||
def compare_versions(ver1: str, ver2: str) -> bool:
|
||||
@@ -186,14 +197,8 @@ class PackageManager:
|
||||
def is_update_available(app_fullname, new_version):
|
||||
appdir = f"apps/{app_fullname}"
|
||||
builtinappdir = f"builtin/apps/{app_fullname}"
|
||||
installed_app=None
|
||||
if PackageManager.is_installed_by_path(appdir):
|
||||
print(f"{appdir} found, getting version...")
|
||||
installed_app = mpos.apps.parse_manifest(appdir) # probably no need to re-parse the manifest
|
||||
elif PackageManager.is_installed_by_path(builtinappdir):
|
||||
print(f"{builtinappdir} found, getting version...")
|
||||
installed_app = mpos.apps.parse_manifest(builtinappdir) # probably no need to re-parse the manifest
|
||||
if not installed_app or installed_app.version == "0.0.0": # special case, if the installed app doesn't have a version number then there's no update
|
||||
installed_app=PackageManager.get(app_fullname)
|
||||
if not installed_app:
|
||||
return False
|
||||
return PackageManager.compare_versions(new_version, installed_app.version)
|
||||
|
||||
@@ -215,3 +220,24 @@ class PackageManager:
|
||||
print(f"Checking if app {app_fullname} is installed...")
|
||||
return PackageManager.is_installed_by_path(f"apps/{app_fullname}") or PackageManager.is_installed_by_path(f"builtin/apps/{app_fullname}")
|
||||
|
||||
@staticmethod
|
||||
def find_main_launcher_activity(app):
|
||||
result = None
|
||||
for activity in app.activities:
|
||||
if not activity.get("entrypoint") or not activity.get("classname"):
|
||||
print(f"Warning: activity {activity} has no entrypoint and classname, skipping...")
|
||||
continue
|
||||
print("checking activity's intent_filters...")
|
||||
for intent_filter in activity.get("intent_filters"):
|
||||
print("checking intent_filter...")
|
||||
if intent_filter.get("action") == "main" and intent_filter.get("category") == "launcher":
|
||||
print("found main_launcher!")
|
||||
result = activity
|
||||
break
|
||||
return result
|
||||
|
||||
@staticmethod
|
||||
def is_launcher(app_name):
|
||||
print(f"checking is_launcher for {app_name}")
|
||||
# Simple check, could be more elaborate by checking the MANIFEST.JSON for the app...
|
||||
return "launcher" in app_name or len(mpos.ui.screen_stack) < 2 # assumes the first one on the stack is the launcher
|
||||
|
||||
@@ -253,7 +253,7 @@ def create_drawer(display=None):
|
||||
wifi_label.center()
|
||||
def wifi_event(e):
|
||||
close_drawer()
|
||||
mpos.apps.start_app_by_name("com.micropythonos.wifi")
|
||||
mpos.apps.start_app("com.micropythonos.wifi")
|
||||
wifi_btn.add_event_cb(wifi_event,lv.EVENT.CLICKED,None)
|
||||
settings_btn=lv.button(drawer)
|
||||
settings_btn.set_size(lv.pct(drawer_button_pct),lv.pct(20))
|
||||
@@ -263,7 +263,7 @@ def create_drawer(display=None):
|
||||
settings_label.center()
|
||||
def settings_event(e):
|
||||
close_drawer()
|
||||
mpos.apps.start_app_by_name("com.micropythonos.settings")
|
||||
mpos.apps.start_app("com.micropythonos.settings")
|
||||
settings_btn.add_event_cb(settings_event,lv.EVENT.CLICKED,None)
|
||||
launcher_btn=lv.button(drawer)
|
||||
launcher_btn.set_size(lv.pct(drawer_button_pct),lv.pct(20))
|
||||
|
||||
Reference in New Issue
Block a user