neiam
/apollos_crib
It's Apollo's Crib
public · Issues · Pulls 1 · Labels · Forks · Compare · Actions failure · Badges · Packages
Log in to mark this repository.
Offer the board as a launcher's feed page
80ad3c2 · Gabriel Morell · 2026-09-02 21:05
Message
{commit_body(@commit)}
Files changed
modified
clients/android/README.md
+28
−0
| 68 | 68 | what an always-open socket costs on Android; the alternative is polling, which |
| 69 | 69 | this deliberately does not do. |
| 70 | 70 | |
| 71 | +## As a launcher's feed page | |
| 72 | + | |
| 73 | +Launchers that implement Google's "minus one" gesture -- the page to the left | |
| 74 | +of the home screen -- bind a service exposing `ILauncherOverlay` and hand it | |
| 75 | +their own window token. `feed/FeedOverlayService` is that service, so the board | |
| 76 | +is available as the feed page with nothing else installed. | |
| 77 | + | |
| 78 | +The page is read-only by construction: it draws the same board the app does and | |
| 79 | +offers no way into the settings. A page you can swipe onto by accident should | |
| 80 | +not be able to change anything. | |
| 81 | + | |
| 82 | +**Launchers check the provider's signature.** Lawnchair keeps a list in | |
| 83 | +`FeedBridge.initializeWhitelist`, keyed by package name and by | |
| 84 | +`Signature.hashCode()` -- an unlisted package is filtered out of the picker | |
| 85 | +before you ever see it. The Connection screen reports this build's hash for | |
| 86 | +that reason; it differs per keystore, so a debug build's is not a release | |
| 87 | +build's. | |
| 88 | + | |
| 89 | +Three ways past it, in the order they are worth trying: | |
| 90 | + | |
| 91 | +1. **A debug build of the launcher.** Lawnchair's `BridgeInfo.isSigned()` | |
| 92 | + returns true unconditionally when `BuildConfig.DEBUG`, so a locally built | |
| 93 | + Lawnchair accepts any provider. This is the way to test. | |
| 94 | +2. **Get listed.** One line in Lawnchair's whitelist, package plus hash. | |
| 95 | +3. **`pref_ignoreFeedWhitelist`.** Real, but it lives in Lawnchair's debug | |
| 96 | + menu, whose own enable switch lives inside the debug menu -- so there is no | |
| 97 | + way to reach it from a release build. | |
| 98 | + | |
| 71 | 99 | ## Building |
| 72 | 100 | |
| 73 | 101 | ```sh |
modified
clients/android/app/build.gradle.kts
+3
−0
| 35 | 35 | } |
| 36 | 36 | buildFeatures { |
| 37 | 37 | compose = true |
| 38 | + // The launcher overlay interface is AIDL, and AGP leaves that off by | |
| 39 | + // default now. | |
| 40 | + aidl = true | |
| 38 | 41 | } |
| 39 | 42 | testOptions { |
| 40 | 43 | unitTests.isIncludeAndroidResources = true |
modified
clients/android/app/src/main/AndroidManifest.xml
+17
−0
| 50 | 50 | android:exported="false" |
| 51 | 51 | android:foregroundServiceType="dataSync" /> |
| 52 | 52 | |
| 53 | + <!-- The board as a launcher's page to the left of the home screen. | |
| 54 | + Launchers implementing Google's "minus one" gesture look for this | |
| 55 | + action and this scheme; the api version tells the client which | |
| 56 | + attach call to use. --> | |
| 57 | + <service | |
| 58 | + android:name=".feed.FeedOverlayService" | |
| 59 | + android:exported="true" | |
| 60 | + android:enabled="true"> | |
| 61 | + <intent-filter> | |
| 62 | + <action android:name="com.android.launcher3.WINDOW_OVERLAY" /> | |
| 63 | + <data android:scheme="app" /> | |
| 64 | + </intent-filter> | |
| 65 | + <meta-data | |
| 66 | + android:name="service.api.version" | |
| 67 | + android:value="7" /> | |
| 68 | + </service> | |
| 69 | + | |
| 53 | 70 | <receiver |
| 54 | 71 | android:name=".mqtt.BootReceiver" |
| 55 | 72 | android:exported="true"> |
added
clients/android/app/src/main/aidl/com/google/android/libraries/launcherclient/ILauncherOverlay.aidl
+48
−0
| 1 | +// The launcher overlay interface, as launchers implementing the Google | |
| 2 | +// "minus one" page expect to find it. The package and method order are the | |
| 3 | +// contract -- both are fixed by the callers, not by us. | |
| 4 | +// | |
| 5 | +// Copied from Lawnchair, which carries the same declaration: | |
| 6 | +// lawnchair/aidl/com/google/android/libraries/launcherclient/ILauncherOverlay.aidl | |
| 7 | +package com.google.android.libraries.launcherclient; | |
| 8 | + | |
| 9 | +import android.view.WindowManager.LayoutParams; | |
| 10 | +import com.google.android.libraries.launcherclient.ILauncherOverlayCallback; | |
| 11 | + | |
| 12 | +interface ILauncherOverlay { | |
| 13 | + | |
| 14 | + oneway void startScroll(); | |
| 15 | + | |
| 16 | + oneway void onScroll(in float progress); | |
| 17 | + | |
| 18 | + oneway void endScroll(); | |
| 19 | + | |
| 20 | + oneway void windowAttached(in LayoutParams lp, in ILauncherOverlayCallback cb, in int flags); | |
| 21 | + | |
| 22 | + oneway void windowDetached(in boolean isChangingConfigurations); | |
| 23 | + | |
| 24 | + oneway void closeOverlay(in int flags); | |
| 25 | + | |
| 26 | + oneway void onPause(); | |
| 27 | + | |
| 28 | + oneway void onResume(); | |
| 29 | + | |
| 30 | + oneway void openOverlay(in int flags); | |
| 31 | + | |
| 32 | + oneway void requestVoiceDetection(in boolean start); | |
| 33 | + | |
| 34 | + String getVoiceSearchLanguage(); | |
| 35 | + | |
| 36 | + boolean isVoiceDetectionRunning(); | |
| 37 | + | |
| 38 | + boolean hasOverlayContent(); | |
| 39 | + | |
| 40 | + oneway void windowAttached2(in Bundle bundle, in ILauncherOverlayCallback cb); | |
| 41 | + | |
| 42 | + oneway void unusedMethod(); | |
| 43 | + | |
| 44 | + oneway void setActivityState(in int flags); | |
| 45 | + | |
| 46 | + boolean startSearch(in byte[] data, in Bundle bundle); | |
| 47 | + | |
| 48 | +} |
added
clients/android/app/src/main/aidl/com/google/android/libraries/launcherclient/ILauncherOverlayCallback.aidl
+9
−0
| 1 | +package com.google.android.libraries.launcherclient; | |
| 2 | + | |
| 3 | +interface ILauncherOverlayCallback { | |
| 4 | + | |
| 5 | + oneway void overlayScrollChanged(float progress); | |
| 6 | + | |
| 7 | + oneway void overlayStatusChanged(int status); | |
| 8 | + | |
| 9 | +} |
added
clients/android/app/src/main/java/io/neiam/apolloscrib/feed/FeedOverlayService.kt
+136
−0
Click to load diff…
added
clients/android/app/src/main/java/io/neiam/apolloscrib/feed/FeedProvider.kt
+50
−0
Click to load diff…
added
clients/android/app/src/main/java/io/neiam/apolloscrib/feed/OverlayHost.kt
+53
−0
Click to load diff…
added
clients/android/app/src/main/java/io/neiam/apolloscrib/feed/OverlayPanel.kt
+185
−0
Click to load diff…
modified
clients/android/app/src/main/java/io/neiam/apolloscrib/ui/BoardScreen.kt
+19
−14
Click to load diff…
modified
clients/android/app/src/main/java/io/neiam/apolloscrib/ui/MainActivity.kt
+11
−0
Click to load diff…
Parents: c6f2de8