- SurfaceView windows are always translucent, so adjustResize cannot
resize them: the keyboard overlapped the bottom of the window and the
top bar sat under the status bar. Consume the insets in app instead:
a smali-injected PadInsetsListener (identical block in build_emu.sh
and build_phone.sh) shrinks the GioView to statusBarBottom..keyboardTop
(or ..navBarTop) on every API 30+ insets dispatch, with
setDecorFitsSystemWindows(false) so IME insets are delivered at
targetSdk 34.
- Fix a change-detection bug in the listener: the height write skipped
the topMargin/bottomMargin checks on every IME state transition, so
the margins were never applied while the keyboard animated. All three
params are now checked with a single requestLayout on any change.
- Selection menu now re-anchors to the selected word every frame while
it is visible and hides when the word scrolls out of the viewport
(positionSelectionMenu + regression test).
- Doc: development_plan.md section 14 (invariants, geometry contract,
build-script identity invariant).
Verified on device: top bar below status bar and clickable, bottom bar
flush with keyboard top (view 128..1517 at 1080x2400), BACK dismiss +
re-tap re-raise without a show loop, typing saves, menu tracks scrolls.
Two user-reported bugs in the post-wrap build:
1. Selection 'jumped' when scrolling: frameOf's chunked branch shadowed the
outer start/end with 'start, end, winLine := cb.VisibleByteRange(...)',
leaving IMEWindowStartByte at 0 for chunked files while scrolled, so the
window-relative selection highlight (and IME commits) mis-mapped near the
file top. Fix: declare winLine outside, assign. Mutation-verified
regression tests: real_file_scroll_selection_test.go.
2. Bottom bar hidden behind the keyboard: GioView extends SurfaceView, which
unconditionally marks the window FORMAT_TRANSLUCENT; translucent windows
are never IME-resized, so adjustResize is dead. Fix (build scripts):
smali-patch a PadInsetsListener OnApplyWindowInsetsListener onto the
GioView (shrinks it by the IME inset bottom) + setDecorFitsSystemWindows
(false) on API 30+ so insets are dispatched. targetSdk kept at 34.
3. (Found while fixing 2) Keyboard could not be dismissed: TextField.Draw
issued SoftKeyboardCmd{Show:true} every frame; with insets-driven
resizes, the hide animation triggered redraws that re-showed the keyboard
mid-animation. Fix: ShowIMESeq pulse from the logic layer (open/tap/
double-tap); renderer shows only on pulse change, re-arming on focus
loss — matching widget.Editor.
On-device (emulator): BACK dismisses and stays down; tap re-shows; typing
works; bottom bar above keyboard; word selection anchored across flick
scroll. go test -race ./... green. Phone APK rebuilt with the same patch.
The Android build recipe lived at /tmp/build_pad.sh and depended on
/tmp/apktool.jar; /tmp gets wiped between sessions (both were lost once
mid-project and had to be rebuilt). Move the recipe into the repo as
scripts/build_emu.sh:
- checks prerequisites (java, gogio, apksigner, adb, debug keystore) with
actionable error messages
- auto-downloads apktool v3.0.3 to the stable ~/android-sdk/tools/ if
missing (never /tmp)
- uses a mktemp work dir cleaned via trap; no /tmp clutter
- --no-install flag; verifies an adb device is present before installing
- verifies the permission injection actually took effect
Tested end-to-end (build + install + app relaunch) and idempotent on
re-run. doc/README.md and development_plan.md now point here.