• Hi,

    I'm testing to combine BW Clock and Desktop Launcher in one app to cut down the time switching between them.

    To try it out:
    EDIT 2: It's now possible to test it via my app loader here. Swipe left/right to move between BW Clock and Desktop Launcher, or use the physical button. The code is here.

    I wanted to do this as a proof of concept of how loading times could be cut (I'd say dramatically) in some of the actions I do most often.

    EDIT: Here's a video comparing loading times as described here.

    Search tags: app switching, app loading, unload, unload().


    1 Attachment

  • Quite interesting -- do you have some measurements?

  • Moving from clock to launcher feels instant. Moving from launcher to clock feels like it takes 0.5-1 second. For me going either direction usually takes 2-2.5 seconds, counting in my head - very scientific ๐Ÿ˜…๐Ÿ˜‹

  • I can't seem to make it work with switching between clock and launcher if just installing via app loader.

    What doesn't work that you expect to work?

    I'd be really interested to hear timings too - it can have a reasonably big effect not having to reload everything between apps, but it does need the apps to be built in such a way that it can be done (eg allowing themselves to be 'unloaded', and having all apps use widgets) or you'll end up with memory leaks or strange behaviour...

    Rather than building apps together, there would be ways to do this directly. For instance an app could define an unload function. And if that function existed then Bangle.showLauncher() could just call unload() and then load up the launcher without going through the whole reset process.

  • What doesn't work that you expect to work?

    If I install via the app loader I'm not able to swipe left/right to move back and forth between clock and launcher, but when uploading via web ide I am. (It never works when opening it from my usual launcher, even when having overwritten the app code via the web ide)

    EDIT:

    I'd be really interested to hear timings too

    I recorded a video (attached) of me:

    1. uploading the clocknlauncher app.js-code to clocknlaunch.app.js via app loader.
    2. swiping to move between clock and launcher.
    3. Long pressing physical button to load the original BW Clock.
    4. Pressing physical button to load Desktop Launcher and BW Clock respectively.

    Btw, I'm in favor of the unload functionality you propose if it's not self evident (without completely understanding it :p). Could there be a variable you set in Bangle.setUI() similar to how "clock : 1" is set, so maybe "unload : 1", to indicate the app is "unload-compatible"? This way it would not be mandatory to update every app (?!) for them to continue working even after adding "unload-functionality"...


    1 Attachment

  • Wow, yes - that's a big improvement!

    It's a good point about setUI - that could be a much cleaner way of handling it than just checking for a global function in showLauncher. Either way it would be pretty straightforward to just default to calling load if there was no 'unload' function.

    About the swipe not working: do you see any errors when you connect with the IDE? I guess it could be related to minification messing the code up somehow?

  • About the swipe not working: do you see any errors when you connect with the IDE? I guess it could be related to minification messing the code up somehow?

    No error messages except for "error: No http method found" (which I see on most loads for most apps). I've tried toggling pretokenization on the app loader before upload.

    Also, when setting minification options to "Simple Optimizations", or "Esprima", (also for modules) and turning on pretokenization for the web ide, swiping still works after uploading the code that way. "Advanced optimizations" don't work at all.

  • No error messages except for "error: No http method found" (which I see on most loads for most apps). I've tried toggling pretokenization on the app loader before upload.

    Hmm - this must be some code you've got using http accesses, when it should use Bangle.http or maybe you just need Gadgetbridge installed? Do you get any clue what file the error is in?

    I guess maybe the error is actually stopping execution of some code which comes after it, and that could be causing your problems?

  • Ok, will do a backup and factory reset and try clocknlauncher after that and see if swiping works then. ๐Ÿ‘

    I have a nightly of Gadgetbridge Bangle.js flavor installed which I have built myself with the most recent changes to the intents-functionality that's yet to be merged to the main project (although it's name on the phone is "Gadgetbridge (nightly)" instead of "Bangle.js Gadgetbridge (nightly)").

    Don't know right now what file the http-error is in.

  • I tried a factory reset and installed clocknlauncher with the same result as earlier with not being able to swipe between clock and launcher. I then tried flashing latest cutting edge firmware 2v15.14 with no change either. Still works if I upload via the Web IDE. The http-error is gone after the factory reset.

    EDIT:

    I had A-GPS Data installed. After removing it the http-error disappeared.

  • I set another clock as my default one. This led me to realize that what happens when I try to open 'clocknlauncher' via my regular launcher is that my currently selected clock (in Settings app) is loaded. Don't understand why that is though. The code is 1106 lines long, can that be a problem? But why does it work via the Web IDE in that case? Also, it's not that much longer than just the BW Clock-code.

  • I got this as a build error on github earlier.

    build: apps/clocknlauncher/metadata.json#L1
    App clocknlauncher has no entrypoint

    Is that a hint about my problem?

  • I got it working now. Kind of embarrassing, I hadn't made sure id and filenames in storage matched... Sorry about that ๐Ÿ˜….

    It's now possible to test it directly via my app loader here.

    Edit: The code is here.

  • @Gordon How prioritized would you say implementing something like unload() is? Do you want to implement it yourself or rather have someone else do a PR?

    Personally it feels a bit out of my depth but I do think it would be very beneficial for everyone with a Bangle as well as for making the watch even more appealing to potential customers.

    Also, do you think it can be as quick as what've been demonstrated with combining the apps here? or will it sit somewhere between load() and merging apps?

  • It's not super high priority for me because there's a high likelihood it'll affect stability (all it takes is a clock author not managing to free all memory in the unload function and the clock will break after a few trips to the launcher).

    However, I have made some changes in the latest cutting edge builds. There was already a Bangle.uiRemove handler so I've hooked onto that, and I've updated Antonclock and the launcher in the development app loader. If you run the latest firmware with those, you should see a pretty fast flip between the launcher and back.

    It's not as fast as if the two apps were integrated (because then you could have pre-loaded the apps list) but it's not that bad.

  • Cool, will check the latest cutting edge build out! ๐Ÿ‘ Thank you for that and for the clarifications ๐Ÿ™‚

  • That solution works quite well - nice one! I have been trying to imitate that remove-functionality to latest versions of Desktop Launcher and BW Clock but haven't got it working as smooth as you did with Anton Clock and Launcher. Two main problems I had so far is (1) having it work together with code that imports other modules (e.g. clock_info in this case), and (2) I get ram filling up slowly when switching between clock and launcher - as you anticipated ๐Ÿ˜…. I think the ram-issue is related to Desktop Launcher's app list but I'm not sure. There are also some other small quirks I will not detail now. I attached the app codes with my changes to this comment.

    Thinking out loud: Could an alternative to manually merging apps be to use the require-function? So similarly to how clocks now can require clock_info they could also require the installed launcher which then is merged in with the clock app code while loading the clock from the app loader. I haven't read up on this or tested it yet.


    2 Attachments

  • This is absolutely awesome. I had to try with Imageclock and Iconlaunch and hacked some things together to make it somewhat work with this new mechanism.
    Cleanup is not yet complete, Imageclock uses a lot of timeouts and intervals and sometimes still comes back over the launcher, but the fast switch between launcher and clock is great. Drawing the widgets also does not yet work correctly.
    I think the next question is how to check during development that nothing is left over ;)

    Edit: Got it mostly working now. There seems to be some state left with regard to the widgets which causes them not to be rendered after switching back and forth with them visible. The rest seems to be working pretty well.
    https://github.com/halemmerich/BangleAppยญs/tree/unload


    2 Attachments

  • (1) having it work together with code that imports other modules (e.g. clock_info in this case)

    Yes... Modules like that will end up staying in RAM. BUT they will only be loaded once, so they're not going to end up using more and more RAM each time. If the module is designed well it shouldn't actually use up too many vars (less than 20) so I wouldn't worry too much about those.

    There seems to be some state left with regard to the widgets which causes them not to be rendered after switching back and forth with them visible

    This really only makes sense if the widgets are kept visible on both cases. If you have to remove them then every widget would have to support unloading too - and also reloading them will add to the time required to change apps, so it's less of a win.

    Otherwise the widgets should still be fine I think...

  • Actually I got the widgets to render and behave mostly as expected. There is still something strange going on. Imageclock always loads the widgets and then replaces the draw functions with functions doing nothing and restores them as needed (showing the widgets/switching to launcher). Essentially that hinges on a showWidgets variable, which should be false on every initialization, but the widgets visibility survives the switch between clock and launcher. Widgets shown on clock are still shown after switching to launcher and back.
    I would expect the showWidgets variable to be removed and reinitialized to false, since it lives in the block scope. The memory after GC is always the same for launcher and clock, so probably no major leaks. Launcher uses less memory than clock, as expected.
    The behaviour is actually quite nice, but I don't understand why it works that way. Printing the showWidgets variable at the top of the block does not work, as it is not yet defined.

  • Imageclock always loads the widgets and then replaces the draw functions with functions doing nothing and restores them as needed

    Ahh, yes, that'd do it! That would all need undoing... It's the kind of thing that (IMO) we should turn into a library and then maybe the library could handle it automatically.

  • Would this be a good time to mention the Hidable Widget Bar? I haven't tried it with this fast app switching yet, but I can't see why it wouldn't work.
    Would it be helpful to add some settings? Always Show Widgets, Always Hide Widgets, Swipe to show or hide? Or pick a gesture to show and hide? I have no idea how to make it a library though!

  • This seems very cool. Does this clash with other apps using the setLCDOverlay or would the widgets just no longer be displayed if for example another app shows notification with this method?

  • Yes, the hideable widget bar is exactly the kind of thing we need. It could be added to https://github.com/espruino/BangleApps/tยญree/master/modules and required...

    Does this clash with other apps using the setLCDOverlay or would the widgets just no longer be displayed if for example another app shows notification with this method?

    Yes, it's just be the last call to setLCDOverlay. Hopefully after a while the widget bar would auto-hide and things would reset though

  • I have tried your code @Sir_Indy with Imageclock and Iconlauncher and like it a lot. Much better than my own swiping-to-show-widgets hack.
    Some things still to consider:
    setUI currently does not clean up the Bangle.CLOCK marker variable, so Bangle.CLOCK stays once there was a setUI with a clock mode.
    Just deleting this in setUI does not solve the problem though, since there are widgets, that differentiate their behaviour during loadWidgets. An example would be the widclk, which just does nothing in case of Bangle.CLOCK.

    I have done the change to delete Bangle.CLOCK in the Espruino repo, but could not find documentation on how to create the minimized variants of the scripts.

    Those widgets need some kind of way to be selectively reloaded on change of Bangle.CLOCK.
    Some ideas of the top of my head:

    1. Remove the check and once again load all widgets on every call to loadWidgets. Slow and not great, but easy and backwards compatible.
    2. Change widgets using this style to check during draw for Bangle.CLOCK and just hide themselves on clocks. Fast, but uses more memory on clocks since the widget will be loaded.
      2b. Have widgets have an update method to be called by setUI if available to notify them to check for changes as Bangle.CLOCK.
    3. Somehow identify widgets not used on clocks during the initial load. Then after change of Bangle.CLOCK load only the missing widgets during loadWidgets. Maybe widgets could be un/loaded depending on some metadata.json entry to match the current Bangle.CLOCK state?


  • Post a reply
    • Bold
    • Italics
    • Link
    • Image
    • List
    • Quote
    • code
    • Preview
About

POC - Combining BW Clock and Desktop Launcher to spend less time "Loading..."

Posted by Avatar for Ganblejs @Ganblejs

Actions