Add notes for this fork (type-to-search design, build, release, install)
This commit is contained in:
87
CLAUDE.md
Normal file
87
CLAUDE.md
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
# Kvaesitso (fork with type-to-search)
|
||||||
|
|
||||||
|
Fork of [Kvaesitso](https://github.com/MM2-0/Kvaesitso) that adds type-to-search for phones with a
|
||||||
|
physical keyboard. Built for, and installed on, a Unihertz Titan 2 Elite.
|
||||||
|
|
||||||
|
origin = https://gitea.haugesenspil.dk/jonas/Kvaesitso (our fork — push here)
|
||||||
|
upstream = https://github.com/MM2-0/Kvaesitso (pull upstream changes from here)
|
||||||
|
|
||||||
|
The phone also has this repository checked out in its Termux home: `~/sources/Kvaesitso`.
|
||||||
|
|
||||||
|
## The feature
|
||||||
|
|
||||||
|
Pressing a printable key on the physical keyboard while the launcher home screen is shown opens the
|
||||||
|
search page and inserts the character. Backspace deletes, enter launches the highlighted result.
|
||||||
|
Only the home screen (and the open search page) reacts; the widgets, notifications and recents
|
||||||
|
pages do not. Setting: *Settings → Search → "Search on typing"* (on by default, stored as
|
||||||
|
`searchOnTyping`).
|
||||||
|
|
||||||
|
## How it works, and why it is built this way
|
||||||
|
|
||||||
|
`SharedLauncherActivity.dispatchKeyEvent` is the only place that sees hardware key events while no
|
||||||
|
view has focus, so the handler is installed there (`launcherKeyEventHandler`, registered by
|
||||||
|
`LauncherScaffold` while it is shown). The handler itself is
|
||||||
|
`app/ui/.../ui/launcher/searchbar/TypeToSearchHandler.kt`.
|
||||||
|
|
||||||
|
Two constraints shape the design:
|
||||||
|
|
||||||
|
1. **The search bar's text field stays unfocused while the keyboard drives the search.** A focused
|
||||||
|
Compose text field makes the system show the on-screen keyboard. There is no public API to
|
||||||
|
prevent that: `View.setShowSoftInputOnFocus` is a hidden API (`TextView`'s version is public) and
|
||||||
|
reflection fails with `NoSuchMethodException`, and hiding the IME reactively makes it flash.
|
||||||
|
Leaving the field unfocused keeps the IME away completely — which is why the handler inserts and
|
||||||
|
deletes the characters itself instead of relying on the text field.
|
||||||
|
2. **No key may be lost.** Characters can arrive before the text field would have focus, so the
|
||||||
|
handler keeps handling keys until the field reports real focus
|
||||||
|
(`LauncherScaffoldState.isSearchBarTextFieldFocused`). `LauncherScaffoldState.isTypingSearch`
|
||||||
|
marks a keyboard-driven search: while it is set, `SearchComponent.onPreActivate` does not focus
|
||||||
|
the field and the handler owns the keys, including backspace and enter. Tapping the search bar
|
||||||
|
clears the flag and hands over to the normal editable field.
|
||||||
|
|
||||||
|
`SearchBar` keeps a `TextFieldValue` instead of a `String` so that changing the text from the
|
||||||
|
outside moves the cursor to the end. Without that, the next typed character landed in front of the
|
||||||
|
text.
|
||||||
|
|
||||||
|
The search is also cleared whenever the launcher is left, even for a short app switch — upstream
|
||||||
|
keeps it for returns within five seconds, which leaves a stale query on screen.
|
||||||
|
|
||||||
|
## Building
|
||||||
|
|
||||||
|
JAVA_HOME=~/jdk21 ANDROID_HOME=~/android-sdk \
|
||||||
|
./gradlew :app:app:assembleDefaultRelease
|
||||||
|
|
||||||
|
Result: `app/app/build/outputs/apk/default/release/app-default-release.apk`, applicationId
|
||||||
|
`de.mm20.launcher2.release`.
|
||||||
|
|
||||||
|
The `release` build type signs with the `local` signing config, which reads `keystore.properties`
|
||||||
|
in the repository root (git-ignored) or the `KEYSTORE_FILE`, `KEYSTORE_PASSWORD`, `KEY_ALIAS` and
|
||||||
|
`KEY_PASSWORD` environment variables. The desktop key is
|
||||||
|
`~/android-keystores/kvaesitso-release.jks`; the phone has its own copy under
|
||||||
|
`~/android-keystores/` in the Termux home. Termux itself has no Android SDK, so build there only
|
||||||
|
after installing one (or build on the desktop and copy the APK over).
|
||||||
|
|
||||||
|
## Releasing (the phone updates through Obtanium)
|
||||||
|
|
||||||
|
1. Raise `versionCode` above the installed one and set a new `versionName` in
|
||||||
|
`app/app/build.gradle.kts` (`versionName` may keep the upstream version, e.g. `1.40.2-typing.2`).
|
||||||
|
2. Build the release APK (see above) and check the signature: `apksigner verify --verbose`.
|
||||||
|
3. Tag it and push `main` and the tag to `origin` (Gitea needs a token: the desktop keeps it in
|
||||||
|
`~/.config/gitea/token`).
|
||||||
|
4. Create a Gitea release for that tag and attach the APK as `Kvaesitso-v<versionName>-Signed.apk`.
|
||||||
|
The repository is public so Obtanium can read it anonymously.
|
||||||
|
5. The phone's Obtanium entry for `de.mm20.launcher2.release` points at this Gitea repo with
|
||||||
|
`overrideSource: "Codeberg"`, `versionDetection: true` and `apkFilterRegEx: "Kvaesitso-v"`. It
|
||||||
|
picks the release up on the next check. The config file lives on the phone at
|
||||||
|
`/sdcard/Android/data/dev.imranr.obtainium.fdroid/files/app_data/de.mm20.launcher2.release.json`
|
||||||
|
(force-stop Obtanium before editing it as root).
|
||||||
|
|
||||||
|
## Installing on the phone by hand
|
||||||
|
|
||||||
|
The phone already runs this build. The official build is signed with the upstream key, so it cannot
|
||||||
|
be updated in place and Obtanium cannot install over it either. The procedure is: back up
|
||||||
|
`/data/user/0/de.mm20.launcher2.release` with root, `pm uninstall` (a `-k` uninstall keeps the
|
||||||
|
package record *and* its signature, so the next install then fails with
|
||||||
|
`INSTALL_FAILED_UPDATE_INCOMPATIBLE`), install this APK, then copy the data back — `chown` to the
|
||||||
|
new app uid and `chcon` the label that installd created for the fresh data directory. The rest of
|
||||||
|
the phone (bootloader, Magisk, microG, rescue steps) is documented in `~/titan2-elite/CLAUDE.md` on
|
||||||
|
the desktop.
|
||||||
Reference in New Issue
Block a user