Skip to content

Commit bae7fb0

Browse files
Add auto_start_app setting
1 parent f8788cc commit bae7fb0

File tree

7 files changed

+86
-22
lines changed

7 files changed

+86
-22
lines changed

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,13 @@ def __init__(self):
3636
("Turquoise", "40e0d0")
3737
]
3838
self.settings = [
39+
# Novice settings, alphabetically:
3940
{"title": "Light/Dark Theme", "key": "theme_light_dark", "value_label": None, "cont": None, "ui": "radiobuttons", "ui_options": [("Light", "light"), ("Dark", "dark")]},
4041
{"title": "Theme Color", "key": "theme_primary_color", "value_label": None, "cont": None, "placeholder": "HTML hex color, like: EC048C", "ui": "dropdown", "ui_options": theme_colors},
41-
{"title": "Restart to Bootloader", "key": "boot_mode", "value_label": None, "cont": None, "ui": "radiobuttons", "ui_options": [("Normal", "normal"), ("Bootloader", "bootloader")]}, # special that doesn't get saved
4242
{"title": "Timezone", "key": "timezone", "value_label": None, "cont": None, "ui": "dropdown", "ui_options": self.get_timezone_tuples(), "changed_callback": lambda : mpos.time.refresh_timezone_preference()},
43+
# Advanced settings, alphabetically:
44+
{"title": "Auto Start App", "key": "auto_start_app", "value_label": None, "cont": None, "ui": "radiobuttons", "ui_options": [("Launcher", "com.micropythonos.launcher"), ("LightningPiggy", "com.lightningpiggy.displaywallet")]},
45+
{"title": "Restart to Bootloader", "key": "boot_mode", "value_label": None, "cont": None, "ui": "radiobuttons", "ui_options": [("Normal", "normal"), ("Bootloader", "bootloader")]}, # special that doesn't get saved
4346
# This is currently only in the drawer but would make sense to have it here for completeness:
4447
#{"title": "Display Brightness", "key": "display_brightness", "value_label": None, "cont": None, "placeholder": "A value from 0 to 100."},
4548
# Maybe also add font size (but ideally then all fonts should scale up/down)

internal_filesystem/lib/mpos/apps.py

Lines changed: 22 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ def good_stack_size():
1717
return stacksize
1818

1919
# Run the script in the current thread:
20+
# Returns True if successful
2021
def execute_script(script_source, is_file, cwd=None, classname=None):
2122
import utime # for timing read and compile
2223
thread_id = _thread.get_ident()
@@ -55,26 +56,32 @@ def execute_script(script_source, is_file, cwd=None, classname=None):
5556
#print("Classes:", classes.keys())
5657
#print("Functions:", functions.keys())
5758
#print("Variables:", variables.keys())
58-
if classname:
59-
main_activity = script_globals.get(classname)
60-
if main_activity:
61-
start_time = utime.ticks_ms()
62-
Activity.startActivity(None, Intent(activity_class=main_activity))
63-
end_time = utime.ticks_diff(utime.ticks_ms(), start_time)
64-
print(f"execute_script: Activity.startActivity took {end_time}ms")
65-
else:
66-
print("Warning: could not find main_activity")
59+
if not classname:
60+
print("Running without a classname isn't supported right now.")
61+
return False
62+
main_activity = script_globals.get(classname)
63+
if main_activity:
64+
start_time = utime.ticks_ms()
65+
Activity.startActivity(None, Intent(activity_class=main_activity))
66+
end_time = utime.ticks_diff(utime.ticks_ms(), start_time)
67+
print(f"execute_script: Activity.startActivity took {end_time}ms")
68+
else:
69+
print(f"Warning: could not find app's main_activity {main_activity}")
70+
return False
6771
except Exception as e:
6872
print(f"Thread {thread_id}: exception during execution:")
6973
# Print stack trace with exception type, value, and traceback
7074
tb = getattr(e, '__traceback__', None)
7175
traceback.print_exception(type(e), e, tb)
72-
print(f"Thread {thread_id}: script {compile_name} finished")
76+
return False
77+
print(f"Thread {thread_id}: script {compile_name} finished, restoring sys.path to {sys.path}")
7378
sys.path = path_before
79+
return True
7480
except Exception as e:
7581
print(f"Thread {thread_id}: error:")
7682
tb = getattr(e, '__traceback__', None)
7783
traceback.print_exception(type(e), e, tb)
84+
return False
7885

7986
""" Unused:
8087
# Run the script in a new thread:
@@ -104,6 +111,7 @@ def execute_script_new_thread(scriptname, is_file):
104111
print("main.py: execute_script_new_thread(): error starting new thread thread: ", e)
105112
"""
106113

114+
# Returns True if successful
107115
def start_app(fullname):
108116
mpos.ui.set_foreground_app(fullname)
109117
import utime
@@ -119,24 +127,22 @@ def start_app(fullname):
119127
print(f"WARNING: start_app can't start {fullname} because it doesn't have a main_launcher_activity")
120128
return
121129
start_script_fullpath = f"{app.installed_path}/{app.main_launcher_activity.get('entrypoint')}"
122-
execute_script(start_script_fullpath, True, app.installed_path + "/assets/", app.main_launcher_activity.get("classname"))
130+
result = execute_script(start_script_fullpath, True, app.installed_path + "/assets/", app.main_launcher_activity.get("classname"))
123131
# Launchers have the bar, other apps don't have it
124132
if app.is_valid_launcher():
125133
mpos.ui.topmenu.open_bar()
126134
else:
127135
mpos.ui.topmenu.close_bar()
128136
end_time = utime.ticks_diff(utime.ticks_ms(), start_time)
129137
print(f"start_app() took {end_time}ms")
138+
return result
139+
130140

131141
# Starts the first launcher that's found
132142
def restart_launcher():
133143
print("restart_launcher")
134144
# Stop all apps
135145
mpos.ui.remove_and_stop_all_activities()
136146
# No need to stop the other launcher first, because it exits after building the screen
137-
for app in PackageManager.get_app_list():
138-
if app.is_valid_launcher():
139-
print(f"Found launcher, starting {app.fullname}")
140-
start_app(app.fullname)
141-
break
147+
return start_app(PackageManager.get_launcher().fullname)
142148

internal_filesystem/lib/mpos/content/package_manager.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,17 @@ def __class_getitem__(cls, fullname):
7373

7474
@classmethod
7575
def get(cls, fullname):
76+
if not cls._app_list:
77+
cls.refresh_apps()
7678
return cls._by_fullname.get(fullname)
7779

80+
@classmethod
81+
def get_launcher(cls):
82+
for app in cls.get_app_list():
83+
if app.is_valid_launcher():
84+
print(f"Found launcher {app.fullname}")
85+
return app
86+
7887
@classmethod
7988
def clear(cls):
8089
"""Empty the internal caches. Call ``get_app_list()`` afterwards to repopulate."""
@@ -223,4 +232,3 @@ def is_installed_by_name(app_fullname):
223232
print(f"Checking if app {app_fullname} is installed...")
224233
return PackageManager.is_installed_by_path(f"apps/{app_fullname}") or PackageManager.is_installed_by_path(f"builtin/apps/{app_fullname}")
225234

226-

internal_filesystem/lib/mpos/ui/topmenu.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -271,10 +271,10 @@ def settings_event(e):
271271
launcher_btn.set_size(lv.pct(drawer_button_pct),lv.pct(20))
272272
launcher_btn.align(lv.ALIGN.CENTER,0,0)
273273
launcher_label=lv.label(launcher_btn)
274-
launcher_label.set_text(lv.SYMBOL.HOME+" Home")
274+
launcher_label.set_text(lv.SYMBOL.HOME+" Launch")
275275
launcher_label.center()
276276
def launcher_event(e):
277-
print("Home button pressed!")
277+
print("Launch button pressed!")
278278
close_drawer(True)
279279
mpos.apps.restart_launcher()
280280
launcher_btn.add_event_cb(launcher_event,lv.EVENT.CLICKED,None)

internal_filesystem/main.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import mpos.ui
1313
import mpos.ui.topmenu
1414
from mpos.ui.display import init_rootscreen
15+
from mpos.content.package_manager import PackageManager
1516

1617
prefs = mpos.config.SharedPreferences("com.micropythonos.settings")
1718

@@ -71,7 +72,13 @@ def custom_exception_handler(e):
7172
except Exception as e:
7273
print(f"Couldn't start mpos.wifi.WifiService.auto_connect thread because: {e}")
7374

74-
mpos.apps.restart_launcher()
75+
# Start launcher so it's always at bottom of stack
76+
launcher_app = PackageManager.get_launcher()
77+
mpos.apps.start_app(launcher_app.fullname)
78+
# Then start another app if configured
79+
auto_start_app = prefs.get_string("auto_start_app", None)
80+
if auto_start_app and launcher_app.fullname != auto_start_app:
81+
mpos.apps.start_app(auto_start_app)
7582

7683
# If we got this far without crashing, then no need to rollback the update:
7784
try:

scripts/bundle_apps.sh

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,10 @@ mkdir -p "$output"
1414
#rm "$output"/*.png
1515
rm "$outputjson"
1616

17-
blacklist="com.micropythonos.filemanager com.example.bla"
17+
# These apps are for testing, or aren't ready yet:
18+
# com.quasikili.quasidoodle doesn't work on touch screen devices
19+
# com.micropythonos.filemanager doesn't do anything other than let you browse the filesystem, so it's confusing
20+
blacklist="com.micropythonos.filemanager com.quasikili.quasidoodle"
1821

1922
echo "[" | tee -a "$outputjson"
2023

tests/test_start_app.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import unittest
2+
3+
import sdl_display
4+
import lcd_bus
5+
import lvgl as lv
6+
import mpos.ui
7+
import task_handler
8+
import mpos.apps
9+
import mpos.ui.topmenu
10+
import mpos.config
11+
from mpos.ui.display import init_rootscreen
12+
13+
class TestStartApp(unittest.TestCase):
14+
15+
def __init__(self):
16+
17+
TFT_HOR_RES=320
18+
TFT_VER_RES=240
19+
20+
bus = lcd_bus.SDLBus(flags=0)
21+
buf1 = bus.allocate_framebuffer(320 * 240 * 2, 0)
22+
display = sdl_display.SDLDisplay(data_bus=bus,display_width=TFT_HOR_RES,display_height=TFT_VER_RES,frame_buffer1=buf1,color_space=lv.COLOR_FORMAT.RGB565)
23+
display.init()
24+
init_rootscreen()
25+
mpos.ui.topmenu.create_notification_bar()
26+
mpos.ui.topmenu.create_drawer(display)
27+
mpos.ui.th = task_handler.TaskHandler(duration=5) # 5ms is recommended for MicroPython+LVGL on desktop (less results in lower framerate)
28+
29+
30+
def test_normal(self):
31+
self.assertTrue(mpos.apps.start_app("com.micropythonos.launcher"), "com.micropythonos.launcher should start")
32+
33+
def test_nonexistent(self):
34+
self.assertFalse(mpos.apps.start_app("com.micropythonos.nonexistent"), "com.micropythonos.nonexistent should not start")
35+
36+
def test_restart_launcher(self):
37+
self.assertTrue(mpos.apps.restart_launcher(), "restart_launcher() should succeed")

0 commit comments

Comments
 (0)