Rename PackageManager to AppManager

This commit is contained in:
Thomas Farstrike
2026-01-25 00:19:38 +01:00
parent 31dcfba683
commit c2ae169638
29 changed files with 123 additions and 124 deletions
+2 -2
View File
@@ -4,7 +4,7 @@ from .app.activity import Activity
from .content.intent import Intent
from .activity_navigator import ActivityNavigator
from .content.package_manager import PackageManager
from .content.app_manager import AppManager
from .config import SharedPreferences
from .net.connectivity_manager import ConnectivityManager
from .net.wifi_service import WifiService
@@ -65,7 +65,7 @@ __all__ = [
"Activity",
"SharedPreferences",
"ConnectivityManager", "DownloadManager", "WifiService", "AudioFlinger", "Intent",
"ActivityNavigator", "PackageManager", "TaskManager", "CameraManager",
"ActivityNavigator", "AppManager", "TaskManager", "CameraManager",
# Device and build info
"DeviceInfo", "BuildInfo",
# Common activities
@@ -2,7 +2,7 @@ import sys
import utime
from .content.intent import Intent
from .content.package_manager import PackageManager
from .content.app_manager import AppManager
import mpos.ui
@@ -13,7 +13,7 @@ class ActivityNavigator:
if not isinstance(intent, Intent):
raise ValueError("Must provide an Intent")
if intent.action: # Implicit intent: resolve handlers
handlers = PackageManager.resolve_activity(intent)
handlers = AppManager.resolve_activity(intent)
if not handlers:
print("No handler for action:", intent.action)
return
@@ -31,7 +31,7 @@ class ActivityNavigator:
if not isinstance(intent, Intent):
raise ValueError("Must provide an Intent")
if intent.action: # Implicit intent: resolve handlers
handlers = PackageManager.resolve_activity(intent)
handlers = AppManager.resolve_activity(intent)
if not handlers:
print("No handler for action:", intent.action)
return
@@ -2,7 +2,7 @@ from ..activity import Activity
# Chooser doesn't handle an action — it shows handlers
# → No registration needed
from ...content.package_manager import PackageManager
from ...content.app_manager import AppManager
class ChooserActivity(Activity):
def __init__(self):
@@ -27,7 +27,7 @@ class ChooserActivity(Activity):
self.setContentView(screen)
def _select_handler(self, handler_name, original_intent):
for handler in PackageManager.APP_REGISTRY.get(original_intent.action, []):
for handler in AppManager.APP_REGISTRY.get(original_intent.action, []):
if handler.__name__ == handler_name:
original_intent.activity_class = handler
navigator.startActivity(original_intent)
@@ -1,5 +1,5 @@
from ..activity import Activity
from ...content.package_manager import PackageManager
from ...content.app_manager import AppManager
class ShareActivity(Activity):
def __init__(self):
@@ -35,4 +35,4 @@ class ShareActivity(Activity):
else:
print("Stopped for other screen")
PackageManager.register_activity("share", ShareActivity)
AppManager.register_activity("share", ShareActivity)
@@ -1,5 +1,5 @@
from ..activity import Activity
from ...content.package_manager import PackageManager
from ...content.app_manager import AppManager
class ViewActivity(Activity):
def __init__(self):
@@ -28,4 +28,4 @@ class ViewActivity(Activity):
print("Stopped for other screen")
# Register this activity for "view" intents
PackageManager.register_activity("view", ViewActivity)
AppManager.register_activity("view", ViewActivity)
@@ -28,7 +28,7 @@ Question: does it make sense to cache the database?
'''
class PackageManager:
class AppManager:
_registry = {} # action → [ActivityClass, ...]
@@ -52,9 +52,9 @@ class PackageManager:
"""Registry of all discovered apps.
* PackageManager.get_app_list() -> list of App objects (sorted by name)
* PackageManager[fullname] -> App (raises KeyError if missing)
* PackageManager.get(fullname) -> App or None
* AppManager.get_app_list() -> list of App objects (sorted by name)
* AppManager[fullname] -> App (raises KeyError if missing)
* AppManager.get(fullname) -> App or None
"""
_app_list = [] # sorted by app.name
@@ -93,7 +93,7 @@ class PackageManager:
@classmethod
def refresh_apps(cls):
print("PackageManager finding apps...")
print("AppManager finding apps...")
cls.clear() # <-- this guarantees both containers are empty
seen = set() # avoid processing the same fullname twice
@@ -117,7 +117,7 @@ class PackageManager:
if not (st[0] & 0x4000):
continue
except Exception as e:
print("PackageManager: stat of {} got exception: {}".format(full_path, e))
print("AppManager: stat of {} got exception: {}".format(full_path, e))
continue
fullname = name
@@ -132,7 +132,7 @@ class PackageManager:
from ..app.app import App
app = App.from_manifest(full_path)
except Exception as e:
print("PackageManager: parsing {} failed: {}".format(full_path, e))
print("AppManager: parsing {} failed: {}".format(full_path, e))
continue
# ---- store in both containers ---------------------------
@@ -141,7 +141,7 @@ class PackageManager:
print("added app {}".format(app))
except Exception as e:
print("PackageManager: handling {} got exception: {}".format(base, e))
print("AppManager: handling {} got exception: {}".format(base, e))
# ---- sort the list by display name (case-insensitive) ------------
cls._app_list.sort(key=lambda a: a.name.lower())
@@ -153,7 +153,7 @@ class PackageManager:
shutil.rmtree(f"apps/{app_fullname}") # never in builtin/apps because those can't be uninstalled
except Exception as e:
print(f"Removing app_folder {app_folder} got error: {e}")
PackageManager.refresh_apps()
AppManager.refresh_apps()
@staticmethod
def install_mpk(temp_zip_path, dest_folder):
@@ -169,7 +169,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()
AppManager.refresh_apps()
@staticmethod
def compare_versions(ver1: str, ver2: str) -> bool:
@@ -200,20 +200,20 @@ class PackageManager:
@staticmethod
def is_builtin_app(app_fullname):
return PackageManager.is_installed_by_path(f"builtin/apps/{app_fullname}")
return AppManager.is_installed_by_path(f"builtin/apps/{app_fullname}")
@staticmethod
def is_overridden_builtin_app(app_fullname):
return PackageManager.is_installed_by_path(f"apps/{app_fullname}") and PackageManager.is_installed_by_path(f"builtin/apps/{app_fullname}")
return AppManager.is_installed_by_path(f"apps/{app_fullname}") and AppManager.is_installed_by_path(f"builtin/apps/{app_fullname}")
@staticmethod
def is_update_available(app_fullname, new_version):
appdir = f"apps/{app_fullname}"
builtinappdir = f"builtin/apps/{app_fullname}"
installed_app=PackageManager.get(app_fullname)
installed_app=AppManager.get(app_fullname)
if not installed_app:
return False
return PackageManager.compare_versions(new_version, installed_app.version)
return AppManager.compare_versions(new_version, installed_app.version)
@staticmethod
def is_installed_by_path(dir_path):
@@ -231,7 +231,7 @@ class PackageManager:
@staticmethod
def is_installed_by_name(app_fullname):
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}")
return AppManager.is_installed_by_path(f"apps/{app_fullname}") or AppManager.is_installed_by_path(f"builtin/apps/{app_fullname}")
@staticmethod
def execute_script(script_source, is_file, classname, cwd=None):
@@ -311,7 +311,7 @@ class PackageManager:
mpos.ui.set_foreground_app(fullname)
import utime
start_time = utime.ticks_ms()
app = PackageManager.get(fullname)
app = AppManager.get(fullname)
if not app:
print(f"Warning: start_app can't find app {fullname}")
return
@@ -325,7 +325,7 @@ class PackageManager:
else:
entrypoint = app.main_launcher_activity.get('entrypoint')
classname = app.main_launcher_activity.get("classname")
result = PackageManager.execute_script(app.installed_path + "/" + entrypoint, True, classname, app.installed_path + "/assets/")
result = AppManager.execute_script(app.installed_path + "/" + entrypoint, True, classname, app.installed_path + "/assets/")
# Launchers have the bar, other apps don't have it
if app.is_valid_launcher():
mpos.ui.topmenu.open_bar()
@@ -343,5 +343,4 @@ class PackageManager:
# Stop all apps
mpos.ui.remove_and_stop_all_activities()
# No need to stop the other launcher first, because it exits after building the screen
return PackageManager.start_app(PackageManager.get_launcher().fullname)
return AppManager.start_app(AppManager.get_launcher().fullname)
+4 -4
View File
@@ -5,7 +5,7 @@ import lvgl as lv
import mpos.ui
import mpos.ui.topmenu
from mpos import AppearanceManager, DisplayMetrics, PackageManager, SharedPreferences, TaskManager, DeviceInfo
from mpos import AppearanceManager, DisplayMetrics, AppManager, SharedPreferences, TaskManager, DeviceInfo
# White text on black logo works (for dark mode) and can be inverted (for light mode)
logo_white = "M:builtin/res/mipmap-mdpi/MicroPythonOS-logo-white-long-w296.png" # from the MPOS-logo repo
@@ -124,12 +124,12 @@ except Exception as e:
print(f"Couldn't start WifiService.auto_connect thread because: {e}")
# Start launcher so it's always at bottom of stack
launcher_app = PackageManager.get_launcher()
started_launcher = PackageManager.start_app(launcher_app.fullname)
launcher_app = AppManager.get_launcher()
started_launcher = AppManager.start_app(launcher_app.fullname)
# Then start auto_start_app if configured
auto_start_app = prefs.get_string("auto_start_app", None)
if auto_start_app and launcher_app.fullname != auto_start_app:
result = PackageManager.start_app(auto_start_app)
result = AppManager.start_app(auto_start_app)
if result is not True:
print(f"WARNING: could not run {auto_start_app} app")
@@ -815,7 +815,7 @@ class MockThread:
class MockApps:
"""
Mock mpos.apps module for testing (deprecated, use MockPackageManager instead).
Mock mpos.apps module for testing (deprecated, use MockAppManager instead).
This is kept for backward compatibility with existing tests.
@@ -839,12 +839,12 @@ class MockApps:
return True
class MockPackageManager:
class MockAppManager:
"""
Mock mpos.content.package_manager module for testing.
Mock mpos.content.app_manager module for testing.
Usage:
sys.modules['mpos.content.package_manager'] = MockPackageManager
sys.modules['mpos.content.app_manager'] = MockAppManager
"""
@staticmethod
+4 -4
View File
@@ -13,10 +13,10 @@ infrastructure are already initialized (boot.py and main.py executed).
Usage in tests:
from mpos.ui.testing import wait_for_render, capture_screenshot
from mpos import PackageManager
from mpos import AppManager
# Start your app
PackageManager.start_app("com.example.myapp")
AppManager.start_app("com.example.myapp")
# Wait for UI to render
wait_for_render()
@@ -63,8 +63,8 @@ def wait_for_render(iterations=10):
iterations: Number of task handler iterations to run (default: 10)
Example:
from mpos import PackageManager
PackageManager.start_app("com.example.myapp")
from mpos import AppManager
AppManager.start_app("com.example.myapp")
wait_for_render() # Ensure UI is ready
assert verify_text_present(lv.screen_active(), "Welcome")
"""
+5 -5
View File
@@ -7,7 +7,7 @@ from .appearance_manager import AppearanceManager
from .util import (get_foreground_app)
from . import focus_direction
from .widget_animator import WidgetAnimator
from mpos.content.package_manager import PackageManager
from mpos.content.app_manager import AppManager
CLOCK_UPDATE_INTERVAL = 1000 # 10 or even 1 ms doesn't seem to change the framerate but 100ms is enough
WIFI_ICON_UPDATE_INTERVAL = 1500
@@ -268,7 +268,7 @@ def create_drawer():
wifi_label.center()
def wifi_event(e):
close_drawer()
PackageManager.start_app("com.micropythonos.wifi")
AppManager.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))
@@ -278,7 +278,7 @@ def create_drawer():
settings_label.center()
def settings_event(e):
close_drawer()
PackageManager.start_app("com.micropythonos.settings")
AppManager.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))
@@ -289,7 +289,7 @@ def create_drawer():
def launcher_event(e):
print("Launch button pressed!")
close_drawer(True)
PackageManager.restart_launcher()
AppManager.restart_launcher()
launcher_btn.add_event_cb(launcher_event,lv.EVENT.CLICKED,None)
'''
sleep_btn=lv.button(drawer)
@@ -308,7 +308,7 @@ def create_drawer():
else: # assume unix:
# maybe do a system suspend here? or at least show a popup toast "not supported"
close_drawer(True)
PackageManager.restart_launcher()
AppManager.restart_launcher()
sleep_btn.add_event_cb(sleep_event,lv.EVENT.CLICKED,None)
'''
restart_btn=lv.button(drawer)