11import os
22import mpos .apps
3+ import mpos .ui # wont be needed after improving is_launcher()
34
45try :
56import zipfile
@@ -52,7 +53,7 @@ class PackageManager:
5253@classmethod
5354def get_app_list (cls ):
5455if not cls ._app_list :
55- cls .find_apps ()
56+ cls .refresh_apps ()
5657return cls ._app_list
5758
5859# --------------------------------------------------------------------- #
@@ -71,13 +72,23 @@ def __class_getitem__(cls, fullname):
7172def get (cls ,fullname ):
7273return 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 \n PackageManager finding apps..." )
88+ def refresh_apps (cls ):
89+ print ("PackageManager finding apps..." )
8090
91+ cls .clear ()# <-- this guarantees both containers are empty
8192seen = set ()# avoid processing the same fullname twice
8293apps_dir = "apps"
8394apps_dir_builtin = "builtin/apps"
@@ -127,15 +138,14 @@ def find_apps(cls):
127138# ---- sort the list by display name (case-insensitive) ------------
128139cls ._app_list .sort (key = lambda a :a .name .lower ())
129140
130-
131141@staticmethod
132142def uninstall_app (app_fullname ):
133143try :
134144import shutil
135145shutil .rmtree (f"apps/{ app_fullname } " )# never in builtin/apps because those can't be uninstalled
136- # TODO: also remove it from the app_list
137146except Exception as e :
138147print (f"Removing app_folder{ app_folder } got error:{ e } " )
148+ PackageManager .refresh_apps ()
139149
140150@staticmethod
141151def install_mpk (temp_zip_path ,dest_folder ):
@@ -151,6 +161,7 @@ def install_mpk(temp_zip_path, dest_folder):
151161except Exception as e :
152162print (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
156167def compare_versions (ver1 :str ,ver2 :str )-> bool :
@@ -186,14 +197,8 @@ def is_overridden_builtin_app(app_fullname):
186197def is_update_available (app_fullname ,new_version ):
187198appdir = f"apps/{ app_fullname } "
188199builtinappdir = 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 :
197202return False
198203return PackageManager .compare_versions (new_version ,installed_app .version )
199204
@@ -215,3 +220,24 @@ def is_installed_by_name(app_fullname):
215220print (f"Checking if app{ app_fullname } is installed..." )
216221return 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