Integrating swaylock-mobile with Sxmo 1/?
I have been trying to introduce my touchscreen based screenlocker to Sxmo for over a week now. Turns out it is not as easy as I thought. In this part of the sersies I'll try to describe what sxmo does for screenlocking and what changes with the 1.9.0 release. The actual implementation will be discussed in part 2.
Table of Contents
What I have tried so far
My first approach was to try out the desktop screensaver, the problem was, that it tried to interact with the newer version of Sxmo, so I reverted to messing with the default screenlock hook.
This at first seemed simple, just insert the screenlocker after the service starting and stopping foo, lock my phone, the screenlocker comes up as expected, I try to enter my pin and … nothing, I forgot that Sxmo turns off the touch input for the locked mode, so I'm not able to enter my pin on the touchscreen. Ok easy fix turn the touch back on after starting the screenlocker … and yes I'm successfully able to unlock my phone, but for some reason the screenlocker comes up very soon and after coming Up my phone won't go to sleep …
The reason turns out to be that the sxmo_screenlock.sh script figures out the current state by looking at what it turned off. That means, I broke that by messing with the touchscreen state, which brings us to the present.
Where I'm now
This is the "legacy" script that still runs on my phone which will be removed when Sxmo updates to 1.9.0. See the next section for the new solution.
This script seems to be the pint where everything related to locking and sleeping goes through.
Setting state
It defines the following functions for setting state:
- lock
- Turns touch input off
- unlock
- Turns both touch input and the screen back on
- off
- Turns the screen off
- crust
- Sends the phone to deep sleep and determines why it woke up
I probably want to to add some semantics here to find out why the locking/screenoff happened and launch my screenlocker if the reason is an idle session or a power button event.
These functions get called from a few places:
- core/sxmo_inputhandler.sh
- Has a lock_screen_action() function for when the screen is locked to tun it off, into locked and back into unlocked.
- Also calls the lock function when you swipe away from the bottom left corner.
- core/sxmo_screenlock_deeper.sh
- Similar to the the lock_screen_action() above but is intended for being called after a few seconds of idle time and it won't move to an unlocked state.
- core/sxmo_proximitylock.sh
- This script periodically checks if the distance sensor is covered and then makes the decision to call the unlock or the off function, also based on the state of the screenlocker.
- core/sxmo_rtcwake.sh
- This script seems to be called by nothing … it calls the crust function on sxmo_screenlock.sh
- default_hooks/contextmenu
- Calls lock, off and crust with the intention of explicitly locking the screen.
- notifications/sxmo_notificationwrite.sh
- Calls the lock function if the screen is off, probably with the intention to make the screen light up when there is a notification.
Idea from wiring that: start the screenlocker as a sxmo_service from a blocking-hook and make the unlock function refuse to work as long as it is running, execute the unlock when it returns, if no lockscreen hook is specified, fallback to turning off the touchscreen.
Querying state
These states from above can also be queried with the getCurState function, it returns:
- unlock
- When unlocked, this is returned if the touchscreen is on
- lock
- When locked with the screen on, this is returned if touch is off but the screen is on
- off
- When locked with screen off, this is returned when both touch and screen are off
This will need some modifications as I'm breaking the assumption that touch state equals locked state.
Quite a few scripts rely on this one:
- notifications/sxmo_notificationwrite.sh
- Tests for the off state to turn he screen on to get attention.
- core/sxmo_inputhandler.sh
- Uses this to cycle states.
- core/sxmo_screenlock_deeper.sh
- Uses this to determine the next deeper lock/sleep state.
- core/sxmo_proximitylock.sh
- (Ab)uses this to avoid unnecessary calls to unlock and off. But is not really context aware. It probably gets stopped elsewhere.
- core/sxmo_rtcwake.sh
- Cronjob, Only goes to crust if not in an unlocked state. (It has other factor too, but not being unlocked is a requirement)
Looking at this I'm not really willing to break this function, maybe some kind of soft/hard lock mechanism for just turning off touch and having a proper lockscreen up would be useful.
The new screenlock / suspend mechanism
To understand the new mechanism you first have to understand sxmo_mutex.sh. (It is documented in it's first commit.)
Diff from previous, old mechanism:
- The is_idle and can_suspend hooks were replaced by mutex locks called from various sources.
- The crust part of sxmo_screenlock.sh was replaced by sxmo_suspend.sh and sxmo_hook_suspend.sh.
- The hacky detect locked state approach was moved to a much cleaner have a file which holds the state approach.
- The rest of sxmo_screenlock.sh was replaces by hook scripts which makes my journey much easier.
Suspending
This suspend part consists of a few files:
- default_hooks/sxmo_hook_suspend.sh
- Does the actual suspending.
- default_hooks/sxmo_hook_mnc.sh
- Figures out how long it is until the next Chronjob with sxmo_rtcwake in its name is scheduled.
- default_hooks/sxmo_hook_presuspend.sh
- Called before suspending, does cleanup like pausing media and turning off screen.
- default_hooks/sxmo_hook_postwake.sh
- Called after waking up with the reason for the wakeup as the first argument.
- core/sxmo_suspend.sh
- When called fires off the whole suspend hook firework, goes too sleep, wakes up again and does a bit of housekeeping.
- ore/sxmo_rtcwake.sh
- Cronjob wrapper (I assume) that does some housekeeping with locks to make sure the cronjobs don't get interrupted.
The whole thing is triggered from the screenoff hook which starts a sxmo_periodically which runs sxmo_hook_check_state_mutexes.sh and if there is no good reason to stay awake goes to sleep using sxmo_suspend.sh with a sxmo_mutex.sh and a holdexec. (At least for touchscreens with three buttons which is the category my pinephone falls into)
Locking
Sxmo still has the three states, but they were moved to their own hooks.
This means that …
- The unlock script is now responsible for calling sxmo_hook_lock.sh
- The lock script is responsible for turning the screen off
- The screenoff script is responsible for going to deep sleep
- Unlocking still happens through the lockstate cycling in the inputhandler
- The unlock script is called by the start hook
The proximitylock script calls the screenoff hook to lock and the unlock hook, so a screenlocker can actually be placed in the lock hook without having to worry about the proximitylock interfering, the postwake hook would have to unlock the touchscreen from the screenoff hook, which it already does and the lock hook shouldn't turn off the touchscreen (that's a beautiful hook fallback), the only "problem" with this approach would be that the state would say unlocked while the lockscreen is up. (interactive would be a better identifier)
To be continued
Note 2022-05-07: there was a previous version of this article that said: this little diff will do it, just use the lock hook … Nope, that won't work …
Most of the above is still true for the released version (good enough as a little guide for myself at least).