Konubinix' opinionated web of thoughts

Android 7+ IaC Launcher and Browser

Literature

objective

I configure my NixOS box from a versioned file; I want my phone’s home screen the same way — declared once, applied reproducibly, with no tapping, dragging or dropping.

Question: on Android 7+ / LineageOS, can a home screen carrying several screens, app widgets, and PWAs — including self-hosted ones served from http://localhost — be provisioned declaratively from a version-controlled config, and at what privilege cost?

Working hypothesis (the target, held fixed for the whole note): a de-Googled LineageOS — no Google Play Services (GMS) — running a Launcher3-based launcher — on stock LineageOS that is Trebuchet, a fork of AOSP’s Launcher31 — and a Chromium-based browser.

[objective]: on a de-Googled LineageOS (Android 7+, no GMS), can a
    home screen — several screens, app widgets and PWAs — be
    provisioned declaratively from a versioned file, with no manual
    tap/drag, and at what privilege cost?

can the home screen be described in a file?

The first question is whether the workspace is even expressible as data. It is: AOSP Launcher3 ships an XML parser whose vocabulary maps one-to-one onto what I want — screens, icons, folders, and widgets at chosen grid cells.

Untitled 1
AutoInstallsLayout tags: from AutoInstallsLayout.java — `TAG_WORKSPACE = "workspace"`, `TAG_APPWIDGET = "appwidget"`, `TAG_FOLDER = "folder"`, `TAG_SHORTCUT = "shortcut"`, `ATTR_SCREEN = "screen"`, `ATTR_X = "x"`, `ATTR_Y = "y"`, `ATTR_SPAN_X = "spanX"`, `ATTR_SPAN_Y = "spanY"`, `ATTR_PACKAGE_NAME = "packageName"`, `ATTR_CLASS_NAME = "className"`.
documented observation
layout expressible
so several screens, app icons, folders and app widgets — each at a named screen and cell — are all expressible in one declarative XML; describing the workspace needs no manual placement.
documented observation
layout is expressible as a file
documented observation
Relations
support — dialectical · for
Strength
documented observation
Node border/fill = propagated strength, same scale (fill paler).

at what privilege does that file apply?

Expressible is not appliable. The tension is in where the XML comes from and when it is read: Launcher3 does not read a user file, it reads a resource baked into a system package, and only once.

Untitled 1
customization is a system-APK lookup: from AutoInstallsLayout.java — `ACTION_LAUNCHER_CUSTOMIZATION = "android.autoinstalls.config.action.PLAY_AUTO_INSTALL"`, resolved in `get(...)` via `Utilities.findSystemApk(ACTION_LAUNCHER_CUSTOMIZATION, context.getPackageManager())`, which returns null `if (customizationApkInfo == null)`.
documented observation
Untitled 2
findSystemApk requires FLAG\_SYSTEM: from Utilities.findSystemApk — `(info.activityInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0`.
documented observation
Untitled 3
loaded once, when the DB is empty: from LauncherProvider.loadDefaultFavoritesIfNecessary — `if (sp.getBoolean(EMPTY_DATABASE_CREATED, false))`.
documented observation
launcher IaC needs root or ROM
so the custom layout loads only from a system APK (installable only with root or a ROM build), and only on first run or after clearing the launcher's data — a first-boot, system-privileged artifact, not a re-appliable user-space config.
solide
the layout is a first-boot system artifact
solide
Relations
support — dialectical · for
Strength
convergent testimony
documented observation
Node border/fill = propagated strength, same scale (fill paler).

why « add to home screen » is not enough for a PWA

PWAs are the awkward third. The obvious gesture — the browser’s « add to home screen » — does not yield an installed app on a de-Googled phone, because the real install (a WebAPK) is minted by a Google server the phone cannot reach.

Untitled 1
WebAPK is minted server-side: "A WebAPK is an Android package (APK) created by a trusted provider of the user's device, typically in the cloud, on a WebAPK minting server."
documented observation
Untitled 2
minting is GMS/Samsung-gated: "This method is used by Google Chrome on devices with Google Mobile Services (GMS) installed, and by Samsung Internet browser, but only on Samsung-manufactured devices".
documented observation
Untitled 3
browsers without minting make shortcuts: "Because Firefox, Microsoft Edge, Opera, Brave, and Samsung Internet (on non-Samsung devices) don't have minting servers they trust, they'll create shortcuts."
documented observation
target has no GMS
(unsourced — from the working hypothesis) a de-Googled LineageOS has no GMS and runs a Chromium fork, so no minting server is reachable.
add-to-home is not IaC
on this target « add to home screen » can only produce a shortcut — not a standalone app, not reproducible from a file, so not the IaC path.
solide
no WebAPK without a minting server
solide
Relations
support — dialectical · for
Strength
convergent testimony
documented observation
Node border/fill = propagated strength, same scale (fill paler).

how to install a PWA declaratively

If the browser will not mint the app, the app is built ahead of time, from a file. A Trusted Web Activity (TWA) wraps the PWA in a thin APK, and Bubblewrap generates that APK from the site’s web manifest — which is exactly IaC: config in, installable artifact out.

Untitled 1
Bubblewrap wraps a PWA as a TWA: "Bubblewrap is a Command Line Interface (CLI) that helps developers to create a Project for an Android application that launches an existing Progressive Web App (PWA) using a Trusted Web Activity (TWA)."
documented observation
Untitled 2
rendered by the user's browser: "The content rendered in a Trusted Web Activity comes from the web: they're rendered by the user's browser"; "Trusted Web Activity is available in Chrome on Android, version 72 and above", and "it is also possible for other browsers to implement the same protocol".
documented observation
Untitled 3
trust via Digital Asset Links: app and site are "expected to come from the same developer. (This is verified using Digital Asset Links.)"
documented observation
declarative PWA path
so a PWA becomes IaC — Bubblewrap `init` turns the site's web manifest into a versioned `twa-manifest.json`, `build` emits `app-release-signed.apk`, and `adb install` places it; it needs a TWA-capable Chromium-based browser installed to render, and a Digital Asset Links file to verify the site. Reproducible, no manual placement.
solide
PWA as a TWA APK built from config
solide
Relations
support — dialectical · for
Strength
convergent testimony
documented observation
Node border/fill = propagated strength, same scale (fill paler).

and a PWA served from http://localhost?

One PWA does not fit the TWA path: the self-hosted one, served from the phone’s own loopback — http://localhost — with no public domain and no certificate. The browser treats it as a securely-delivered, trustworthy origin2; the trouble is proving to a Trusted Web Activity that the app and the site share one owner, when the site is every device’s own localhost.

Relations
support — dialectical · for
Strength
convergent testimony
documented observation
Node border/fill = propagated strength, same scale (fill paler).

The fix is to stop asking a Trusted Web Activity to trust a site it structurally cannot verify, and instead ship an app that never runs the check. The cleanest is our own thin WebView; forking the browser’s verification or decompiling a prebuilt TWA APK are heavier variants of the same bypass.

Relations
support — dialectical · for
Strength
convergent testimony
documented observation
Node border/fill = propagated strength, same scale (fill paler).

conclusion

Yes — but as two mechanisms, not one. The launcher layout is expressible as declarative XML (a file) yet appliable only as a first-boot system artifact — root or a ROM build, plus a data wipe. PWAs cannot be installed by the browser without GMS (only a shortcut), so they take the TWA-from-manifest path: a versioned config compiled to an APK and adb install-ed. A PWA served from http://localhost is the exception even to that path — a Trusted Web Activity cannot verify a loopback origin, so it degrades to a URL-bar Custom Tab (the localhost case); the reproducible answer there is our own thin WebView APK, not a TWA.

The no-tap/drag goal is met on both halves; the price is asymmetric — the PWA half is plain user-space tooling, the launcher half costs system privilege. See the overview map in the whole argument.

[iac feasible, split path]: home-screen-as-code is feasible on a
    de-Googled LineageOS, but along two distinct paths — the launcher
    layout as a first-boot system XML (root/ROM + data wipe), and
    PWAs as TWA APKs built from a versioned manifest and adb-installed.
    The no-tap/drag goal holds; only the launcher half costs system
    privilege. A =http://localhost= PWA is the one exception to the TWA
    route — it cannot pass Digital Asset Links verification, so it ships
    as our own WebView APK instead.

Open questions, each its own note rather than diluting this chain: a user-space alternative for the launcher half — a third-party launcher whose backup/restore file can be generated and pushed without root (Nova, Lawnchair, others) — and exactly which LineageOS Chromium-based browsers implement the TWA protocol well enough to render a Bubblewrap APK full-screen.

the whole argument

The overview: the thesis, the two positive results that carry it, and the privilege cost that qualifies it. It aggregates the chapter blocks via :argdown-include (each claim is defined once, in its chapter).

Relations
support — dialectical · for
attack — dialectical · against
Strength
convergent testimony
documented observation
Node border/fill = propagated strength, same scale (fill paler).

— LineageOS Trebuchet’s .gitupstream, which records the AOSP repository it forks (branch lineage-22.2):

https://github.com/LineageOS/android_packages_apps_Trebuchet/blob/lineage-22.2/.gitupstream

#+END_QUOTE


  1. #+BEGIN_QUOTE

    https://android.googlesource.com/platform/packages/apps/Launcher3 ↩︎

  2. Locally-delivered resources such as those with http://127.0.0.1, http://localhost, and http://*.localhost URLs (for example, http://dev.whatever.localhost/) are not delivered using HTTPS, but they can be considered to have been delivered securely because they are on the same device as the browser. They are therefore potentially trustworthy.

    https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts

     ↩︎