Skip to content

Releases: agentsco-lab/surfaceduo-droidian

0.22.0 - flatpak runs again, a phone shut sleeps

Choose a tag to compare

@iverbovoy iverbovoy released this 09 Oct 05:59

Flatpak works again, and a phone shut sleeps with Wi-Fi up. Since 0.20.0 every flatpak run on the port ended with bwrap: Can't mount proc on /newroot/proc: Device or resource busy - reported by a Duo owner on 0.21 (2026-10-09), who found that 0.18 still ran them. The port's /usr/local/bin/bwrap (the file that spares GTK programs glycin's 1.3-1.8 s sandbox) hid the setuid bit of Droidian's bubblewrap from flatpak, which then asked for a user namespace this 4.14 kernel cannot mount proc in. The file now carries the bit flatpak looks for (the kernel ignores it on a script) and flatpak runs its sandboxes as it did on 0.18.

What is new

Flatpak

  • flatpak run works (see above). A phone on 0.20.0-0.21.4 can be mended without this package too: sudo chmod 4755 /usr/local/bin/bwrap.

Sleep and connectivity, measured lid shut, the whole night

  • NetworkManager leaves Wi-Fi up after a resume (sfduo-nm-wake-fix, a one-branch patch of its binary, applied by postinst and again on its updates): it took WoWLAN Wi-Fi down belatedly at each resume, and a phone shut slept again before Wi-Fi was back - no Wi-Fi all night, mobile data up.
  • Mobile data is off while on Wi-Fi and comes back only after 90 s awake without it (90-sfduo-mobile-data, NetworkManager's dispatcher). With mobile data up, the modem woke the phone every ~80 s all night; without it the phone sleeps until opened.
  • Mobile data is no longer brought straight back up as the phone suspends: ofono2mm's bearers are let go together (sfduo-ofono2mm-fix). Before: 1342 resumes a night, 66 % to 30 % in 7.5 h.
  • Sleep without a cable: the USB gadget is left unbound after a resume until a cable comes (sfduo-usb-plug, from udev, one at a time) - rebound at every resume it made rndis0 anew, and its netlink events broke the next suspend.
  • sensorfw 0.14.8+itemae3: a client gone without a word loses its session - it streamed into a dead socket all night.

The hinge

  • sfduo-posture reads the hinge from the lid's opening (logind's LidClosed), not only once the display is lit a second or two later; and tells Gravity - the accelerometer's x, y, z in g, smoothed - while the display is lit.

ssh

  • A password only from the USB link (the 4-digit PIN), keys elsewhere; sshd listens on Wi-Fi and mobile data too.

Releases

  • Releases can carry the port's boot image and vbmeta for phones coming from stock Android (tools/release-add-boot.sh, tools/build-release-image.sh); item/grid RAM-boots it on the new phone and writes it to the slots only once it booted Linux there. docs/STOCK-ANDROID.md has the way back to stock Android.

Kernel and boot image changes since 0.21.0 (the lid as a wake source in the DTB, the spcom fix for fingerprint enrolment) are not part of this package.

Upgrading from 0.20.x or 0.21.x: sudo apt install ./adaptation-droidian-surfaceduo_0.22.0_arm64.deb, then reboot. Flatpak works at once; the sleep changes take the reboot.

Tested on the owner's phone as an upgrade from 0.21.4: GNOME Calculator from Flathub runs with this package's bwrap and fails with the old one's; after the reboot the Wi-Fi, WoWLAN, lid, USB and sensorfw services are up, nothing failed, the lid reads right. The sleep changes ran a night on 0.21.4 (lid shut, Wi-Fi radio on, bluetooth and mobile data off): 1.27 % an hour, 0.16 W.

0.21.2 - the port whole in an image built offline

Choose a tag to compare

@iverbovoy iverbovoy released this 04 Oct 11:43

The port installs whole into an image built offline. The package enables the same services whether it goes onto a running phone or into a system image built in a chroot. Built offline before, an image came up with no Wi-Fi, bluetooth restarting in a loop for want of an address, and froze some ten minutes in: Wi-Fi, WoWLAN, the lid, wake-up, the composer watchdog, writeback and bluetooth had been left off. This is what makes a ready-made system image possible (tools/build-release-image.sh in this repository).

  • The hinge and Microsoft's posture sensor through sensorfw, with the posture's values read on the device (closed, as a book, flat, closing, turning, back to back with either panel facing you). The hinge's value no longer freezes after ten seconds - sensorfw's data socket is drained - and at rest nothing wakes for it.
  • Rotation and the light sensor come back after sensorfw restarts (iio-sensor-proxy is started with it again).
  • The journal is capped at 500 MB (it kept 10 % of the filesystem, 1.5 GB seen).
  • nfcd and lxc-net are masked: they failed at every boot - the Duo has no NFC, and the Android container uses the host's network.
  • Sleep: the wakeup count is saved before sleeping, so a lid or a wakelock on the way in gives the sleep up; fewer Wi-Fi wakes (mDNS stopped while the lid is shut); the USB address back after a resume.

Kernel and boot image changes since 0.21.0 (the lid as a wake source in the DTB, the spcom fix for fingerprint enrolment) are not part of this package.

Upgrading from 0.21.x: sudo apt install ./adaptation-droidian-surfaceduo_0.21.2_arm64.deb, then reboot.

Tested on the owner's phone as an upgrade, and inside a system image built from a fresh Droidian 102 nightly (2026-09-29) with the Wi-Fi, bluetooth, audio and lid services checked after its first start.

0.21.0

Choose a tag to compare

@iverbovoy iverbovoy released this 29 Sep 22:35

Droidian's own shell on two panels. From 0.21 the port runs the shell Droidian ships, with only the fixes the hinge's seam needs; the two-panel shell - the dock, tiling, the system screen - is now its own package, item-shell, from agentsco-lab/item.

  • The free panel beside a window is a desktop. Open an app on one panel and the app grid stands on the other, in three columns; start a second app from it and each panel has its window. The move happens at the tap, with a fade. A handle under the window pulls up the overview to switch or close.
  • A window on each panel shows both. phoc drew nothing under a maximized window, and maximized is one panel here.
  • The shell no longer drops out when the overview wants a window's picture (thumbnails were offered in a format this GPU's shared memory does not have).
  • A top bar and a shade per half, the keyboard, notification banners, the volume bubble and the launch splash on one panel, the app grid clear of the hinge.

Upgrading from 0.20.x with the two-panel shell: 0.21 no longer carries it. Install item-shell as well to keep it: sudo apt install ./adaptation-droidian-surfaceduo_0.21.0_arm64.deb ./item-shell_0.1.0_arm64.deb, then sudo systemctl restart phosh. Without item-shell you get Droidian's shell as above.

Tested on a fresh Droidian 102 nightly (2026-09-29) and as an upgrade.

0.20.1

Choose a tag to compare

@iverbovoy iverbovoy released this 28 Sep 17:00

Faster to open apps, half the boot, a closed phone that stays asleep. Hardware and speed fixes for Droidian 102 (the two-panel shell is as in 0.20; its development continues at agentsco-lab/item).

  • Apps open 7-21 % faster. For 1.5 s after a tap the launch boost now does what Android's perf HAL does: every cluster's frequency floor at its top, the memory-bus and L3 floors raised, the cores kept out of deep idle. Settings 794 -> 704 ms, Calculator 687 -> 573.
  • The lock screen 22 s after the kernel starts, instead of 48. No search for an LVM volume the phone never has (11 s), and no serial console: the Duo has no UART, and every kernel message waited for it at 115200 baud (the kernel now reaches the initramfs at 1.6 s instead of 9.7). Rebuild your boot image with tools/make-boot-image.sh to get this - the command line comes from kernel-packaging/debian/kernel-info.mk - and, as always, RAM-boot it first (docs/SAFETY.md).
  • A closed phone draws 46-48 mA again. Droidian's mobile-power-saver asked the modem for 5G, which the Duo 1 does not have; the modem sat on 3G and never slept (74 mA). The port now puts it back to LTE.
  • phosh no longer fails to start now and then at boot (a VT switch raced it); the slot guard really marks the boot good; flash-safely no longer stops on a slot b stock Android left unbootable.
  • No line of wallpaper beside a window scaled to fit its panel (phoc 0027).

Install over 0.20: sudo apt install ./adaptation-droidian-surfaceduo_0.20.1_arm64.deb, then reboot. All the numbers: docs/SPEED.md.

0.20.0 - Droidian 102, the pen, and the last release here

Choose a tag to compare

@iverbovoy iverbovoy released this 27 Sep 10:01

The port moves to Droidian 102. This is the last feature release in this repository: fixes for the hardware and for speed will keep coming here, promptly, as long as they work on Droidian as it ships; the two-panel shell and new work continue at agentsco-lab/item.

0.20 is built and tested on the Droidian 102 nightly. It still carries 0.18's phoc, phosh and keyboard for Droidian 101 (#222), but was not tested there: on 101, 0.18.0 is the release to use.

Installing

A clean install was run end to end on an untouched 102 nightly (2026-09-27) with this package; docs/PORT-GUIDE.md follows it step by step:

  1. From the nightly zip take only data/rootfs.img - never flash the zip, its installer writes boot, dtbo and vbmeta - and grow it to 8 GB.
  2. Push it from TWRP, put this .deb in out/ and run adaptation/ssh/inject-ssh-twrp.sh.
  3. RAM-boot the port's boot image. The first boot installs the package and reboots once, into fastboot; RAM-boot the image again.
  4. Connect to Wi-Fi, run sudo sfduo-shell-setup, reboot: the dock, the pen and the full-size root filesystem.
  5. In Settings, check the time zone (the image starts on UTC) and enrol a fingerprint.

Going back to stock Android and coming from it: docs/STOCK-ANDROID.md, new.

What is new

Droidian 102 (#217)

  • The port comes up on 102's Android container wait and session; phoc 0.47, phosh 0.55 and phosh-osk-stevia rebuilt for 102 with the port's patches (phoc 0001-0026, phosh 0001-0022, keyboard 0001-0005).
  • Images load without glycin's sandbox, which costs 1.3-1.8 s per process on this kernel: phosh is ready in 3.3 s instead of 6.9.
  • The port's Settings in the dock again, back from a page opened directly returns to the port's list (#223, #225).
  • GNOME Web is the browser (#241).

Battery and modem

  • A closed phone draws 35-65 mA again instead of ~150 mA (101: 58 mAh/h over six hours): mobile-power-saver no longer lifts the NPU's memory vote (#230).
  • The modem stays on LTE when Wi-Fi comes and goes (#231), and there is one mobile data connection, not two (#228).
  • The dock no longer wakes logind every 2 s with the lid closed (#235).

The two-panel shell

  • An app restored from the dock shows in ~60 ms instead of ~450: phoc now runs the work queued for its idle at once (phoc 0026).
  • A move to the other panel turns like a page about the hinge (#239), and Firefox slides instead of jumping (#237).
  • The wallpaper fills the strip where the status bar was (#208); the 1 px line over windows is gone.
  • phosh keeps one wallpaper, only as large as the panels: 100 MB less memory (#173).
  • phoc's pending_layer_configures assertions are gone (#240).
  • The power button's keyboard types into the window, not the shell.

Pen

  • The pen is a stylus: sfduo-pen-split splits the digitizer into a touchscreen and a pen with pressure (#24, #227), and a sheet to draw on comes in from the right edge. See docs/PEN.md.

Setup

  • The login keyring is opened without a password (the fingerprint unlocks the phone).
  • The first boot's one reboot goes to fastboot: a plain reboot after a RAM-boot starts the kernel on the slot, stock Android's on a phone new to the port.
  • Clean-install fixes: the old openssh bundle no longer downgrades 102's openssh; the root filesystem grows only when resize2fs is there; the pen's python3-evdev comes with sfduo-shell-setup.
  • The clock is 24-hour with the automatic time zone by default.

Measurements

The same Duo 1, book posture, screen on, on USB power; medians of 10. Android: am start -W (first frame the app drew); the port: launch request to the window's first frame.

Launch, ms Duo 1 stock Android 12L Duo 2 stock Android 12L 0.20 on 102 0.18 on 101
Settings 368 398 794 1166
Calculator 340 404 687 1045
Contacts 413 260 649 1022
Camera 308 - 935 1332
Browser 507 (Edge) 1132 (Edge) 1289 (Web) 2339 (Firefox)
Calendar, first start 584 (Outlook) 636 (Outlook) 1747 2038
Clock / Phone / Messages, running 92 / 92 / 121 74 / 69 / 86 59 / 59 / 133 135 / 303 / 242
Restore from the dock - - 59 444-491

Launches are about a third faster than on 101; Android still starts apps about twice as fast.

Known issues

  • A reboot on battery can stay on a black screen until USB power is connected (#234).
  • The calendar takes 1.7 s to open (#242).
  • The first opening of the app grid after the dock starts drops frames (#186).

0.18.0 - apps open at a tap, a closed phone that sleeps

Choose a tag to compare

@iverbovoy iverbovoy released this 24 Sep 18:01

Everything in the 0.17.0 notes and those before it applies; the two-panel shell is still experimental and in development. This release covers 0.17.0 to 0.18.0: opening, moving and closing apps rebuilt and measured, a closed phone that drains much less, the system screen, and the root filesystem grown into the phone's free space. It needs the patched phosh and phoc it carries (phoc patches 0013-0019 and phosh 0016-0019 are new) - on a stock phosh most of what follows falls back to the 0.15 behaviour.

Opening an app

Every launch was taken apart frame by frame with a new measuring tool (below), and put back together:

0.17 0.18
from the tap to something on the screen 110-140 ms 8-20 ms
a strip at the top showing the app underneath always never
another app's window flashing during the launch whenever one was open never
the window moving or growing after it appeared 13 launches of 27 0 of 30
black frames before Camera's picture always never
  • The tap answers at once. The launch curtain - black, with the app's icon - comes up within a frame of the tap. It used to wait for the app to be started and for itself to be drawn from scratch; it now stays ready below the screen and is moved into place.
  • What you see next is the app, in place. The curtain lifts when the compositor shows the new window, drawn at its panel's size - not on a timer that sometimes lifted it too soon (and showed whatever was underneath) or too late. A window that keeps animating as it opens (Calculator, Messages, Weather) no longer waits for it to stop.
  • Windows land in their panel's corner. Contacts, which opens wider than a panel, used to stand 40 px into the hinge with the app underneath showing beside it.

Moving, closing, bringing back

  • Moving an app to the other panel (its icon in the other panel's dock) is smooth: 0-1 frames lost in a move. At the start of every move the panel it left redrew its swipe area whole and the folded shade redrew its list of windows - frames of 40 and 60 ms; neither is redrawn now.
  • Closing an app loses 0-4 frames, for the same two reasons, and no longer redraws phosh's home surface two or three times over as the last window goes.
  • A window put away and brought back from the dock is shown as it was, at its first frame, rather than after redrawing itself.
  • The dock follows a window in one motion; it used to move a beat after it, and again.

The shell does not restart by itself any more

Now and then, opening an app ended the whole session - every app gone, the phone locked. The compositor was disconnecting phosh over a thumbnail of a window, taken for the overview, in a buffer format it would not take. On this phone the overview is never shown, and the thumbnails are no longer taken: that was also 2-3 full-window copies from the GPU in the middle of every launch.

The app grid

A flick of the grid runs at the display's rate, up and down: it redrew itself whole at the start and end of every slide, and the shade and the back strips redrew with it. The dock's two halves meet on the other panel with the grid open.

A closed phone that drains less

With the phone closed and the display off, a set of things kept waking it all night. They stop now:

  • the hinge sensor was read 25 times a second through the system bus, display off or not;
  • the location service was restarted every 95 s, and the modem wrote 2 MB to its storage each time - about 460 MB a night;
  • Android's mDNS responder and avahi fought over the phone's name every 20 s;
  • Android's log daemon spent 16 % of a core keeping its full buffers pruned (now 1 MiB instead of 16, from the next boot);
  • the dock and the brightness keeper polled every half second and every 2 s.

With the display off, the whole phone went from about 40 % of a core to about 11 %. A closed phone lit up by a call now goes dark again. The overnight drain with all of this is still to be measured (closed overnight before these changes: 58 mAh an hour, about 1.8 % of the battery).

The system screen

A swipe right on the left panel's desktop slides in the system screen, a page of cards: a greeting with the owner's picture, the battery (level, time left, power, the last day's graph), load, memory and storage, the network (Wi-Fi, operator and signal, data used today), what's next (the next alarm and calendar event), the device (the hinge's angle live, uptime, the port's version and whether a newer one is out), and the weather for the day. A swipe left, on either panel, takes it back. It is a first version.

The desktop

  • An empty panel takes the swipes from anywhere, not only from its edges: right for the system screen, up for the app grid, down for its shade - which follows the finger.
  • The desktop clock stays under the windows; it blinked over them during a launch.
  • Location is asked for only when an app wants it - a blue dot while it does - rather than all day. Night Light keeps a fixed schedule and needs none.

The root filesystem grows (once, at the next boot)

Droidian lives in a file, /userdata/rootfs.img, made 8 GB by the installer - and everything you keep lives in it, with the rest of the phone's storage free beside it. At the first boot with this package it grows to all of /userdata's free space but 10 GB (kept for a backup or a second image), while the system runs. The space is taken at once. It cannot be shrunk back from the running system - only from recovery. Partitions are not touched: a Windows installed beside Droidian is not affected. To keep the 8 GB image, run sudo mkdir -p /var/lib/sfduo && sudo touch /var/lib/sfduo/rootfs-grown before rebooting.

A leaner system

Turned off (left installed): printing (CUPS and its notifications), IPsec VPN (strongSwan; WireGuard and OpenVPN are separate), vnstat, the Wacom and smart-card plugins of the settings daemon. X11 support (Xwayland, 73 MB) now starts only for an X11 app, and leaves after it. Anything turned off can be turned back on with sudo systemctl enable --now <unit> (for the settings daemon's plugins, sudo systemctl --global unmask org.gnome.SettingsDaemon.<Name>.service), and stays on through upgrades.

A fresh install gets the port's display settings

On a fresh Droidian the package could come up with Droidian's own display settings - everything at scale 3, too large for these panels, and windows tiled with no gap for the hinge - because dpkg kept the settings file Droidian had already put there. The package now puts its own in place (scale 2, the hinge) over Droidian's, which it keeps as /etc/phosh/phoc.ini.droidian. A settings file of the port's that you changed yourself is left alone. If your phone looks large after an earlier install, this fixes it at the upgrade; restart the shell afterwards.

Measured

sudo sfduo-perfcheck on the development device with this package installed: every dock and grid animation 16.0-16.6 ms a frame, a launch 0.8 s from signal to window, the lock screen's unlock swipe 16.6 ms median and 18.1 ms p90 (0.17: 18.6 and 25.2). All ten within thresholds.

The repository now carries bench/sfduo-bench, which measures the port the same way every time - launches (timed, and recorded at 60 fps and checked against what a launch must do), the app grid, moving, closing, launching beside another app, bringing one back - and is meant to be run on stock Android too, for a baseline to compare against. Its protocol is bench/README.md.

Kernel

A change to the display driver - its idle power collapse turned off, which cost a frame at the start of many animations - is in the kernel sources (kernel-packaging/patches/0006). The kernel's boot image is not part of this package; build and flash it as described in the porting guide to have it.

Known limitations

  • A page open in Settings can be lost when Settings is moved to the other panel (#201).
  • Settings opens on an intermediate screen before its content (#195).
  • The wallpaper leaves a strip where the status bar was (#208).
  • Bringing back a minimized app takes about half a second (#210).
  • Messages keeps redrawing itself while open, which also slows its launch (#189).
  • The first opening of the app grid after the shell starts loses a few frames (#186).
  • The dock's pinned apps cannot be changed on the device yet (#203); an app cannot be spread across both panels (#204).
  • Two windows of the same app are tracked as one by the dock. The fold effect is not included.

Upgrading

sudo dpkg -i adaptation-droidian-surfaceduo_0.18.0_arm64.deb over 0.17.0, then reboot: the root filesystem grows at that boot (see above - create /var/lib/sfduo/rootfs-grown first to keep it as it is), and Android's smaller log buffers take effect. The patched phosh and phoc are installed only beside the exact package versions they were built for. The status bar and the stock shell are still one command away: sudo sfduo-shell --stock.

0.17.0 - no status bar, a dark fold

Choose a tag to compare

@iverbovoy iverbovoy released this 23 Sep 01:21

Everything in the 0.16.0 notes and those before it applies; the two-panel shell is still experimental and in development. This release covers 0.16.0 to 0.17.0: the status bar retires, closing the phone turns its screen off, and Settings gets its own switches. It needs the patched phosh and phoc it carries - on a stock phosh most of what follows falls back to the 0.15 behaviour.

Closing the phone turns the screen off

Folding the Duo shut locked it, and nothing more: with idle blanking off, both panels stayed lit behind the closed lid on the lock screen - all night, if it was left that way - and Droidian's power saver, which saves only on a blanked screen, never started. Now closing turns the display off and opening turns it back on at once, at the level it had. Measured closed, on battery:

current per hour
0.16: closed, panels lit 126-184 mA 4-6 % of the battery
0.17: closed, display off 33-55 mA 1-1.7 %

A 4-hour measurement closed on battery after the release (4 h 14 min, display off): 97 % to 89 %.

It also stops the lock screen's clock from standing still on the OLED panels for hours. The phone still does not suspend when closed (suspend is off in the session, as since 0.13).

No status bar

Outside the lock screen there is no top bar any more: a strip of fixed icons lit in the same pixels all day is the classic OLED burn-in, and its height came out of every window. A swipe down from the top edge of either panel still opens that half's shade. What the bar said went where it belongs:

  • The time, the date and the weather stand on the free panel - the right one when nothing is open, the other one when a window takes a panel, gone when both are taken. Grey and thin, and each minute it steps a few pixels from its place. The weather is the first city chosen in GNOME Weather, refreshed every half hour; with no city there is no weather line.
  • Signal, Wi-Fi and battery are in the right-hand shade's head, under its clock and date.
  • A microphone or a camera in use shows as a dot in the right panel's top corner: orange while something records, green while the camera app is open. It is there over windows and on the lock screen.
  • A low battery is GNOME's own notification, at 20 % and 5 %.

The lock screen keeps its bar.

Settings for this device, continued

  • The Surface Duo page has its switches: the two-panel shell on or off (off is Droidian's own phone shell - the stock phosh, phoc and keyboard, no dock), the output scale (2, 2.5 or 3) and turning the screen off when idle. The first two ask for your password and offer a Restart row while the running shell differs from what is set. Over ssh the same is sudo sfduo-shell --duo | --stock | --scale S | --restart.
  • One way back: the arrow in the corner under the thumb, on either panel. The pages' own arrows at the top are gone - on the right panel they were against the hinge - and so are the chevrons at the ends of rows. In GNOME Settings the corner arrow steps back through a panel's own pages (Accessibility > Seeing > back > Accessibility) and puts the window away only on the panel's first page.
  • A page opens in the program already running: 280-300 ms instead of about 1.2 s, the same page again in 190 ms.
  • The password prompt and phosh's other system dialogs come up on the left panel instead of across the hinge; the keyboard has the right one.

Windows

  • A swipe up over a window puts it away, and nothing more; closing is the shade's list and the app's own way out.
  • A new window is drawn once, where it belongs - not first across both panels and then moved.
  • A window sliding to the other panel carries no shadow and leaves no trace.
  • A window put away stays away when a shade is pulled down and let go; it used to come back, on the other panel.
  • The bottom of a window and of the dock line up: phosh no longer keeps 15 px for a home bar the dock replaces.
  • A Settings page is listed once in the shade's list of windows, not as a second Settings.
  • The dock's back arrow comes with Settings every time; now and then it did not.

Brightness

The panels' last brightness is written back while they are still dark, before the session's own keeper can answer, which cuts the flash of full brightness on opening the phone. The driver still lights them at full first; that part is open (#87).

Measured

sudo sfduo-perfcheck on the development device with this package installed (no reboot): every dock and grid animation 16.2-16.4 ms a frame, a launch 0.9 s from tap to window, the lock screen's unlock swipe 18.6 ms median, 25.2 ms p90. All nine within thresholds.

Known limitations

  • A window sometimes opens shifted up and left, its header above the edge (#94).
  • With the app grid open, the dock's two halves stand apart on the other panel instead of meeting (#104).
  • Location is in use all the time here, so it has no mark yet (#102).
  • Two windows of the same app are tracked as one by the dock.
  • The fold effect is not included.

Upgrading

sudo dpkg -i adaptation-droidian-surfaceduo_0.17.0_arm64.deb over 0.16.0, then restart the shell (sudo sfduo-shell --restart) or reboot. The patched phosh and phoc are installed only beside the exact package versions they were built for. The status bar comes back with the stock shell: sudo sfduo-shell --stock.

0.16.0 - two panels, one phone

Choose a tag to compare

@iverbovoy iverbovoy released this 19 Sep 22:28

Everything in the 0.15.4 notes and those before it applies; the two-panel shell is still experimental and in development. This release covers 0.15.5 to 0.16.0: it is mostly about the shell behaving like one phone across two panels. It needs the patched phosh and phoc it carries - on a stock phosh most of what follows falls back to the 0.15 behaviour.

A shade per half, each with its own job

Pull down on either panel and that half's shade opens - on its half only, dimming only it. The left one holds the settings: brightness, volume, the quick settings, the torch, lock and power. The right one holds what is going on: the media player, the open windows (each with a close button and the panel it is on) and the notifications. On the lock screen both stay whole.

  • A shade folds with a swipe up from anywhere on it, not only from its handle. While the notification list can still scroll, a swipe up scrolls it; at its end the next one folds the shade. The sliders keep working.
  • A new notification drops in on the right half, where the notifications are, instead of across the hinge.
  • Both shades' brightness sliders show the brightness (the second one sat at zero).
  • The bar's contents are dealt out: signal and clock on the left half, indicators on the right, nothing under the hinge.

One window, the whole panel

With one app open and the other panel free, the status bar moves to the free panel - signal, clock and indicators - and the app's window runs to the top edge of its panel (900 px instead of 867). Open a second app and the two bars come back. The busy half's shade still opens from its top edge.

Settings for this device

"Settings" in the grid and the dock is the port's own now: one list grouped for a phone with two panels - Connections, Screen, Sound and Notifications, Surface Duo, Security, Apps and Accounts, System, For Developers - whose rows open the pages of GNOME Settings and Mobile Settings. Both stay installed and leave the grid.

  • Everything happens on the panel Settings was opened on: a page slides in at once and the other program's window lands on it; back closes it and slides back to the list. Back at the list puts Settings away.
  • GNOME Settings and Mobile Settings go one step at a time on a single panel, list then page, instead of two cramped columns.
  • Left out on purpose: Displays (a scale set there overrides the port's), Printers, NFC (no working NFC stack), Waydroid (not installed), Remote Desktop, Thunderbolt, Device Security, Encryption (untested with this boot chain), Mobile Settings' alerts and convergence.
  • The Surface Duo page says what is installed; its switches come in a later release.

Back, from the edge

A swipe in from a busy panel's outer edge is "back", as on Android: an arrow comes out of the edge with the finger and turns blue past the point of no return. It works in Settings, Mobile Settings, the GNOME apps and Firefox; terminals are left out. The app grid's and a busy panel's bottom-band gestures are unchanged.

Windows open, close, minimize and move

  • A closed window fades and shrinks away (200 ms); a minimized one drops to the bottom edge of its panel, towards the dock (280 ms). phoc had no minimize at all - every minimize request was dropped, the dock's short swipe included; it has one now, and an app is brought back from the dock.
  • The dock learns of a window coming or going the moment it happens and moves half-way through the window's motion (about 200 ms after, measured), not up to half a second after it.
  • An app already open on one panel, tapped in the dock on the other, comes to that panel, sliding across (260 ms), with the dock taking the panel it left. 24-37 ms from the tap to both moving, measured.

Unlocking

  • The fingerprint unlocks whenever the phone is locked and the screen is on. Droidian's fpd-unlockd asks the reader to listen only when the session leaves idle, and since 0.14.1 the port's idle-delay of 0 keeps the session from ever going idle: on the development device the reader listened for the first 30 s after the session started and then not again. sfduo-fingerprint replaces it (fpd-unlockd is masked while the package is installed) and buzzes on an unlock - 150 ms, where fpd-unlockd's 12 ms buzz went unnoticed. Enrol a finger in Settings, Security, Fingerprint.
  • The lock screen fades away (300 ms) and the dock's halves come in from the sides once it has.

The hinge

The hinge-angle sensor's rebuilt sensorfw is carried in the package and installed by sfduo-sensorfw-install; sfduo-posture reads the hinge once and publishes the angle and posture on the session bus (org.sfduo.Posture). Nothing in this release uses it visibly: the fold effect built on it is experimental and not in the package.

A new install starts ready

Installed on a clean image, this release sets the things a phone should not
have to be told:

  • Mobile data works from the first boot. A fresh image has no mobile
    connection at all - the modem registers on LTE and nothing uses it. The
    port makes one when there is none, with the APN NetworkManager picks for
    the SIM, and only at home: roaming stays off.
  • GNOME's first-run wizard does not run. It wants about 1024 px where a
    panel is 675, so it stood across the hinge. Its pages - language,
    keyboard, time zone, privacy - are all in Settings.
  • The screen starts at 40 %, once, for a new user; whatever you set is
    yours after that. It used to start at whatever the first reboot happened
    to save, which on one install was all but dark.
  • Windows keep to a panel. Maximized means one panel now, as on the
    Duo's own Android, and a window too wide for a panel is scaled down to
    fit it rather than laid across the hinge. Until sudo sfduo-shell-setup
    has installed what the dock needs, windows are maximized as on any phosh.

Measured

sudo sfduo-perfcheck on the development device, with this package installed and after a reboot: every dock and grid animation 16.1-16.4 ms a frame, the lock screen's unlock swipe 19.9 ms median, 24.5 ms p90, a launch 0.9 s from tap to window. All nine within thresholds.

Known limitations

  • Back at the first page puts the app away only in Settings: other apps give no sign of being at their first page, so a swipe there does nothing.
  • Two windows of the same app are tracked as one by the dock.
  • A page of Settings takes about a second the first time it opens (the other program's cold start); the page slides in at once and the content lands on it.
  • The fold effect is not included.

Upgrading

sudo dpkg -i adaptation-droidian-surfaceduo_0.16.0_arm64.deb over 0.15.x. The patched phosh and phoc are installed only beside the exact package versions they were built for; sudo sfduo-phosh-install --restore and sudo sfduo-phoc-install --restore put the stock ones back and keep them there. A dock configured before keeps its apps; its old Settings entry is replaced by the new one.

0.15.4

Choose a tag to compare

@iverbovoy iverbovoy released this 18 Sep 19:30

Everything in the 0.13.0, 0.14.0 and 0.14.2 notes applies; the two-panel shell is still experimental and in development. This release covers 0.15.0 to 0.15.4, and it is the first with the kernel built without Microsoft's debugging.

The keyboard takes one panel

phosh-osk-stub anchored its surface to both edges, so the keyboard ran across the bezel with half the keys on each panel. The package now carries a patched one (osk-patches/0001, sfduo-osk-install, the same version lock, marker and --restore as the patched phosh and phoc): with a tiling-seam in phoc.ini and the output in landscape, it takes the right panel. In portrait it spans the output as before.

The applications

The grid loses what a phone does not need - a second browser, a second image viewer, vim's entry, the tour, the archiver, Usage, GNOME Software. They are hidden, not removed: every one is a dependency of the droidian-phosh-full metapackage, and purging one would let the next apt autoremove take half the system. sudo sfduo-apps --purge does remove them, after protecting the rest.

sudo sfduo-apps (once online) installs what a fresh image lacks: Telegram, cool-retro-term as the dock's terminal (its CRT shaders render through hybris on this device; the port's look is seeded for a user without settings, and the menu bar is on so Settings can be reached by touch), what Claude Code needs and Claude Code itself from npm, fastfetch and htop. The dock defaults to Camera, Maps, Settings on the left and Telegram, Firefox, cool-retro-term on the right - a default; ~/.config/sfduo/dock.json and your own phosh favourites win. No Spotify: there is no client for arm64 Linux, and the web player needs Widevine, which Firefox lacks here.

The grid opens on the panel that was swiped

Swipe up on a free panel and every application is there, four to a row at the dock's icon size, alphabetical and scrolling; the other panel keeps what it was showing and stays touchable. The open grid counts as a window on its panel, so the dock crosses to the other one as it does for an application, and it crosses the moment an icon is tapped rather than when the window lands.

Animations that move surfaces instead of repainting them

The grid's slide ran at 8-17 frames a second, and profiling put the cost where no rewrite would reach it: cairo painting the window on the CPU at scale 3, and the compositor copying every committed buffer into a texture. So the shell now animates by moving surfaces the compositor already holds - each panel's grid and launch curtain are layer surfaces of their own, a slide is a margin change sent straight to the compositor, and the dock's crossing is a dip below the edge, a swap while nothing is visible and a return on the other panel. Measured after: the slide 16-17 ms a frame, the crossing 18-29 ms. The launch curtain covers the launched-onto panel only. docs/PERF.md has the measurements, and why a rewrite in another language would not have changed them.

The package also carries a second phoc patch (phoc-patches/0002): a new window on an output with a tiling-seam opens centred on the panel touched last and no wider than it, so it no longer maps across the hinge before the dock tiles it.

The dock in two halves, at the outer edges, crossing in a straight line

Each half of the dock is a surface of its own now, standing at its panel's outer edge - under the thumbs - and rounded on all sides. When a panel is taken the halves slide towards each other onto the free panel and join as one bar, square where they meet; when the other panel is taken instead they travel together across the hinge; from both panels to none they part again. Nothing is repainted on the way: 16 ms a frame on every crossing, measured. During a swipe up for the app grid the halves follow the finger at the grid's own pace and park with its ease-out. Closing the grid by a slow swipe no longer launches the app under the finger (three GTK touch subtleties, in the commit).

The halves stand at the outer edges of the panels - where the thumbs of two hands holding the open device rest - and the app grid has five columns. While the on-screen keyboard is up the dock keeps out of its way. Closing the grid by a slow swipe no longer launches the app under the finger.

Output scale 2

The port's output scale is 2 now (1392x900 logical; the hinge at 675-717), where 0.14.1-0.15.3 had 2.5. 2.5 is Android's density for these panels, but GTK3 has no fractional scale: it drew at 3 into a 27 MB buffer per frame and phoc scaled it down, and the lock screen's unlock swipe ran at 40 fps that way. At 2 the same swipe runs at 55-60 fps and every GTK3 surface is 2.25x cheaper to paint (docs/PERF.md, "The lock screen, measured"). Elements are 20 % smaller than at 2.5; the app grid has five columns. /etc/phosh/phoc.ini is a conffile: 2.5 is a line away if you prefer it, then sudo sfduo-shell-css and a restart of the shell.

Measured, and kept that way

Every number above is in docs/PERF.md, with the method. sudo sfduo-perfcheck on the device runs the same scenarios - a launch and its dock crossing, the grid by signal and by a flick of a synthetic finger, a 2 s unlock swipe with phosh's frames counted - and prints ms per frame against thresholds; it exits 1 on a miss. On this release, on the development device: every dock and grid animation 16.1-16.3 ms a frame, the lock screen's swipe 18.6 ms median, a launch 1.3 s from tap to window.

Every boot ran at the lowest CPU clocks - and not only boots

Droidian's mobile-power-saver puts every core on the powersave governor while the screen is off and restores schedutil when it comes on. At boot the screen is off until phosh has drawn, so the saver starts in its off state and the first "on" never reaches it: the device ran at 576-826 MHz of 2.8 GHz until the screen had been turned off and on once by hand - and with idle blanking off since 0.14.1, for the whole session. sfduo-cpufreq.service waits for the shell and sets schedutil once. Measured on the debug kernel: systemctl daemon-reload 30 s that way, 2.2 s after; a root login 26 s against 2 s.

Then it turned out the saver does the same in the middle of a session: its StopDozing method - meant for a client that needs the device awake for a moment - restarts its dozing cycle without looking at the screen, and Droidian's headphone-manager calls it on every headset-jack event, which on the Duo is every USB-C plug. From then on every core sits on powersave for 300 s out of every 330 s, screen on, until the next screen-off/on; the first frames after picking the device up are drawn at 576 MHz. Since 0.15.3 sfduo-cpufreq.service watches the whole session and puts schedutil back whenever the screen is on and the governor says otherwise. If the device ever felt slow for no reason, this was probably it.

Which means the numbers earlier notes pinned on Microsoft's debug kernel config were mostly this. Corrected everywhere; see below for what the debugging really costs.

The kernel without Microsoft's debugging

kernel-packaging/droidian/surfaceduo-perf.config turns off the debugging in Microsoft's defconfig - slab and page poisoning, page owner, debug objects, kmemleak, lock debugging, fault injection, the irq-off/preempt-off tracers; 92 config lines, all of them debug options, nothing else touched. Measured the same way on both kernels, screen on, schedutil: 3000 fork+exec in 11 s against 26 s, a boot to ssh in about half the time, Slab 182 MB against 605 MB. The release string is 4.14-190-perf-microsoft-surfaceduo; the module ABI differs from the 4.14-190 builds, and the adaptation package carries wlan and audio modules for both.

It has been RAM-booted, confirmed, and is flashed on the development device. The assets are the kernel (Image.gz-4.14-190-perf-microsoft-surfaceduo) and its Debian packages; no boot image: a boot image for the Duo has to carry the generic SoC DTB from your own stock boot backup (tools/extract-stock-dtb.sh) and the Droidian ramdisk, assembled with tools/make-boot-image.sh - the port does not redistribute device blobs. Then RAM-boot it (tools/flash-safely.sh ram-boot), and read docs/SAFETY.md before anything else: on this device fastboot flash boot_a answers "Device Error" and writes nothing; the sequence that works is described there. Install the adaptation package before booting the new kernel - without its modules for that kernel the ADSP never starts and the system freezes minutes in.

The keyboard's keys, and the dock under it

The on-screen keyboard's key rows are 60 logical px on this display instead of the stub's 50 (osk-patches/0002): the scale is chosen for the whole display, and 50 px rows came out a fifth lower than at 2.5. And the dock now knows when the keyboard is up (it is a layer surface, not a window, so it did not) and keeps off its panel.

The hinge angle (added after the release)

On a fresh 101 image the hinge-angle sensor is missing: it is a rebuilt sensorfw (sensorfw-hinge-patch/), and the package only configured it. sensorfw-hinge-0.14.8+itemae1_arm64.tar here has the debs; unpack and sudo apt install ./*.deb (all of them - the qt6 ones and the qt5 stubs together), then append hingeadaptor = hybrishingeadaptor under [plugins] in /etc/sensorfw/sensord-hybris.conf and sudo systemctl restart sensorfwd. The next release carries them in ...

Read more

v0.14.2: a bigger screen, and tiled windows stop at the hinge

Choose a tag to compare

@iverbovoy iverbovoy released this 18 Sep 10:19

Everything in the 0.13.0 notes and 0.14.0 applies; the two-panel shell is still experimental and in development. This release covers 0.14.1 and 0.14.2.

The screen is bigger

Droidian's generic phoc.ini scales every phone's output by 3, which made the Duo's two panels 928x600 logical - a phone's worth of space, in which GNOME Calculator loses its bottom row. Android runs these panels at 400 dpi, a scale of 2.5, and so does the port now: the package ships /etc/phosh/phoc.ini (Droidian's file with that one line changed; a conffile, yours to edit) and the output is 1113x720 logical. Everything in the shell follows the scale: the dock asks the compositor for the output's size, and the stylesheet is generated for the scale in phoc.ini (sudo sfduo-shell-css after changing it, then restart the shell).

Tiled windows stop at the hinge

phoc tiles a window to exactly half the output, and the middle of the output is the middle of the hinge, so every tiled window reached half the hinge into the bezel and lost its inner edge. The package now carries a patched phoc (phoc-patches/0001: a tiling-seam in the output's section of phoc.ini, and the halves stop short of it), installed by sfduo-phoc-install beside exactly the phoc version it was built for - the same version lock, --restore and marker as the patched phosh. Without the patch phoc warns about the key and tiles as before.

An open device stays on

The screen no longer blanks and locks on its own: an open Duo on a desk is being looked at, and closing it is how it is put away. The backlight still dims after idle, the power button locks as before. (A default, not a lock: a value you set yourself wins.) Found on the way: Droidian's mobile-power-saver ties its hard saving to the blanked screen - the CPU governor goes to powersave and processes are frozen - so anything measured over ssh with the screen off measured that; the READMEs say so now.

Upgrading

sudo dpkg -i adaptation-droidian-surfaceduo_0.14.2_arm64.deb, then restart the shell or reboot. If you had made your own /etc/phosh/phoc.ini, dpkg asks about it; the package's one is what the shell's stylesheet is generated for. ssh-debs-droidian-101.tar is unchanged from 0.13.0 and only needed for a fresh image without an ssh server.