Skip to content

Commit 056db40

Browse files
PackageManager: refresh applist after (un)install, reduce parse_manifest() calls
1 parent cea4e59 commit 056db40

File tree

4 files changed

+58
-58
lines changed

4 files changed

+58
-58
lines changed

internal_filesystem/builtin/apps/com.micropythonos.launcher/assets/launcher.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ def onResume(self, screen):
8383
label.set_width(iconcont_width)
8484
label.align(lv.ALIGN.BOTTOM_MID, 0, 0)
8585
label.set_style_text_align(lv.TEXT_ALIGN.CENTER, 0)
86-
app_cont.add_event_cb(lambda e, path=app_dir_fullpath: mpos.apps.start_app(path), lv.EVENT.CLICKED, None)
86+
app_cont.add_event_cb(lambda e, fullname=app.fullname: mpos.apps.start_app(fullname), lv.EVENT.CLICKED, None)
8787
app_cont.add_event_cb(lambda e, app_cont=app_cont: self.focus_app_cont(app_cont),lv.EVENT.FOCUSED,None)
8888
app_cont.add_event_cb(lambda e, app_cont=app_cont: self.defocus_app_cont(app_cont),lv.EVENT.DEFOCUSED,None)
8989
if focusgroup:

internal_filesystem/lib/mpos/apps.py

Lines changed: 16 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -105,31 +105,25 @@ def execute_script_new_thread(scriptname, is_file):
105105
except Exception as e:
106106
print("main.py: execute_script_new_thread(): error starting new thread thread: ", e)
107107

108-
def start_app_by_name(app_name, is_launcher=False):
109-
mpos.ui.set_foreground_app(app_name)
110-
custom_app_dir=f"apps/{app_name}"
111-
builtin_app_dir=f"builtin/apps/{app_name}"
112-
try:
113-
stat = uos.stat(custom_app_dir)
114-
start_app(custom_app_dir, is_launcher)
115-
except OSError:
116-
start_app(builtin_app_dir, is_launcher)
117-
118-
def start_app(app_dir, is_launcher=False):
119-
print(f"main.py start_app({app_dir},{is_launcher})")
108+
def start_app(fullname):
109+
mpos.ui.set_foreground_app(fullname)
120110
import utime
121111
start_time = utime.ticks_ms()
122-
mpos.ui.set_foreground_app(app_dir) # would be better to store only the app name...
123-
app = mpos.apps.parse_manifest(app_dir)
124-
print(f"start_app parsed manifest and got: {str(app)}")
125-
main_launcher_activity = find_main_launcher_activity(app)
112+
app = PackageManager.get(fullname)
113+
if not app:
114+
print(f"Warning: start_app could not find app {fullname}, aborting...")
115+
return
116+
if not app.installed_path:
117+
print(f"Warning: start_app could not find installed_path for {fullname}, aborting...")
118+
return
119+
main_launcher_activity = PackageManager.find_main_launcher_activity(app)
126120
if not main_launcher_activity:
127-
print(f"WARNING: can't start {app_dir} because no main_launcher_activity was found.")
121+
print(f"WARNING: can't start {fullname} because no main_launcher_activity was found.")
128122
return
129-
start_script_fullpath = f"{app_dir}/{main_launcher_activity.get('entrypoint')}"
130-
execute_script(start_script_fullpath, True, app_dir + "/assets/", main_launcher_activity.get("classname"))
123+
start_script_fullpath = f"{app.installed_path}/{main_launcher_activity.get('entrypoint')}"
124+
execute_script(start_script_fullpath, True, app.installed_path + "/assets/", main_launcher_activity.get("classname"))
131125
# Launchers have the bar, other apps don't have it
132-
if is_launcher:
126+
if PackageManager.is_launcher(fullname):
133127
mpos.ui.topmenu.open_bar()
134128
else:
135129
mpos.ui.topmenu.close_bar()
@@ -143,29 +137,9 @@ def restart_launcher():
143137
# No need to stop the other launcher first, because it exits after building the screen
144138
for app in mpos.package_manager.PackageManager.get_app_list():
145139
#print(f"checking {app}")
146-
if app.category == "launcher" and find_main_launcher_activity(app):
140+
if app.category == "launcher" and PackageManager.find_main_launcher_activity(app):
147141
print(f"Found launcher, starting {app.fullname}")
148-
start_app_by_name(app.fullname, True)
149-
150-
def find_main_launcher_activity(app):
151-
result = None
152-
for activity in app.activities:
153-
if not activity.get("entrypoint") or not activity.get("classname"):
154-
print(f"Warning: activity {activity} has no entrypoint and classname, skipping...")
155-
continue
156-
print("checking activity's intent_filters...")
157-
for intent_filter in activity.get("intent_filters"):
158-
print("checking intent_filter...")
159-
if intent_filter.get("action") == "main" and intent_filter.get("category") == "launcher":
160-
print("found main_launcher!")
161-
result = activity
162-
break
163-
return result
164-
165-
def is_launcher(app_name):
166-
print(f"checking is_launcher for {app_name}")
167-
# Simple check, could be more elaborate by checking the MANIFEST.JSON for the app...
168-
return "launcher" in app_name or len(mpos.ui.screen_stack) < 2 # assumes the first one on the stack is the launcher
142+
start_app(app.fullname)
169143

170144

171145
class App:

internal_filesystem/lib/mpos/package_manager.py

Lines changed: 39 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import os
22
import mpos.apps
3+
import mpos.ui # wont be needed after improving is_launcher()
34

45
try:
56
import zipfile
@@ -52,7 +53,7 @@ class PackageManager:
5253
@classmethod
5354
def get_app_list(cls):
5455
if not cls._app_list:
55-
cls.find_apps()
56+
cls.refresh_apps()
5657
return cls._app_list
5758

5859
# --------------------------------------------------------------------- #
@@ -71,13 +72,23 @@ def __class_getitem__(cls, fullname):
7172
def get(cls, fullname):
7273
return cls._by_fullname.get(fullname)
7374

75+
# --------------------------------------------------------------------- #
76+
# Clear everything – useful when you want to force a full rescan
77+
# --------------------------------------------------------------------- #
78+
@classmethod
79+
def clear(cls):
80+
"""Empty the internal caches. Call ``get_app_list()`` afterwards to repopulate."""
81+
cls._app_list = []
82+
cls._by_fullname = {}
83+
7484
# --------------------------------------------------------------------- #
7585
# discovery & population
7686
# --------------------------------------------------------------------- #
7787
@classmethod
78-
def find_apps(cls):
79-
print("\n\n\nPackageManager finding apps...")
88+
def refresh_apps(cls):
89+
print("PackageManager finding apps...")
8090

91+
cls.clear() # <-- this guarantees both containers are empty
8192
seen = set() # avoid processing the same fullname twice
8293
apps_dir = "apps"
8394
apps_dir_builtin = "builtin/apps"
@@ -127,15 +138,14 @@ def find_apps(cls):
127138
# ---- sort the list by display name (case-insensitive) ------------
128139
cls._app_list.sort(key=lambda a: a.name.lower())
129140

130-
131141
@staticmethod
132142
def uninstall_app(app_fullname):
133143
try:
134144
import shutil
135145
shutil.rmtree(f"apps/{app_fullname}") # never in builtin/apps because those can't be uninstalled
136-
# TODO: also remove it from the app_list
137146
except Exception as e:
138147
print(f"Removing app_folder {app_folder} got error: {e}")
148+
PackageManager.refresh_apps()
139149

140150
@staticmethod
141151
def install_mpk(temp_zip_path, dest_folder):
@@ -151,6 +161,7 @@ def install_mpk(temp_zip_path, dest_folder):
151161
except Exception as e:
152162
print(f"Unzip and cleanup failed: {e}")
153163
# Would be good to show error message here if it fails...
164+
PackageManager.refresh_apps()
154165

155166
@staticmethod
156167
def compare_versions(ver1: str, ver2: str) -> bool:
@@ -186,14 +197,8 @@ def is_overridden_builtin_app(app_fullname):
186197
def is_update_available(app_fullname, new_version):
187198
appdir = f"apps/{app_fullname}"
188199
builtinappdir = f"builtin/apps/{app_fullname}"
189-
installed_app=None
190-
if PackageManager.is_installed_by_path(appdir):
191-
print(f"{appdir} found, getting version...")
192-
installed_app = mpos.apps.parse_manifest(appdir) # probably no need to re-parse the manifest
193-
elif PackageManager.is_installed_by_path(builtinappdir):
194-
print(f"{builtinappdir} found, getting version...")
195-
installed_app = mpos.apps.parse_manifest(builtinappdir) # probably no need to re-parse the manifest
196-
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
200+
installed_app=PackageManager.get(app_fullname)
201+
if not installed_app:
197202
return False
198203
return PackageManager.compare_versions(new_version, installed_app.version)
199204

@@ -215,3 +220,24 @@ def is_installed_by_name(app_fullname):
215220
print(f"Checking if app {app_fullname} is installed...")
216221
return PackageManager.is_installed_by_path(f"apps/{app_fullname}") or PackageManager.is_installed_by_path(f"builtin/apps/{app_fullname}")
217222

223+
@staticmethod
224+
def find_main_launcher_activity(app):
225+
result = None
226+
for activity in app.activities:
227+
if not activity.get("entrypoint") or not activity.get("classname"):
228+
print(f"Warning: activity {activity} has no entrypoint and classname, skipping...")
229+
continue
230+
print("checking activity's intent_filters...")
231+
for intent_filter in activity.get("intent_filters"):
232+
print("checking intent_filter...")
233+
if intent_filter.get("action") == "main" and intent_filter.get("category") == "launcher":
234+
print("found main_launcher!")
235+
result = activity
236+
break
237+
return result
238+
239+
@staticmethod
240+
def is_launcher(app_name):
241+
print(f"checking is_launcher for {app_name}")
242+
# Simple check, could be more elaborate by checking the MANIFEST.JSON for the app...
243+
return "launcher" in app_name or len(mpos.ui.screen_stack) < 2 # assumes the first one on the stack is the launcher

internal_filesystem/lib/mpos/ui/topmenu.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,7 @@ def brightness_slider_released(e):
253253
wifi_label.center()
254254
def wifi_event(e):
255255
close_drawer()
256-
mpos.apps.start_app_by_name("com.micropythonos.wifi")
256+
mpos.apps.start_app("com.micropythonos.wifi")
257257
wifi_btn.add_event_cb(wifi_event,lv.EVENT.CLICKED,None)
258258
settings_btn=lv.button(drawer)
259259
settings_btn.set_size(lv.pct(drawer_button_pct),lv.pct(20))
@@ -263,7 +263,7 @@ def wifi_event(e):
263263
settings_label.center()
264264
def settings_event(e):
265265
close_drawer()
266-
mpos.apps.start_app_by_name("com.micropythonos.settings")
266+
mpos.apps.start_app("com.micropythonos.settings")
267267
settings_btn.add_event_cb(settings_event,lv.EVENT.CLICKED,None)
268268
launcher_btn=lv.button(drawer)
269269
launcher_btn.set_size(lv.pct(drawer_button_pct),lv.pct(20))

0 commit comments

Comments
 (0)