Commit Graph

5 Commits

Author SHA1 Message Date
fdbffc9f5c Fix SIGABRT on activity destroy: null view in registerFragment
Crash on device (Pixel 9 Pro, Android 17) when swiping the app away
from recents:

  JNI DETECTED ERROR: java_object == null in call to GetObjectClass
  #06 libgio.so (registerFragment+104)

Root cause: Gio's window.detach sends an EMPTY AndroidViewEvent
(View == 0) as its detach signal (os_android.go: window.detach ->
processEvent(AndroidViewEvent{})), which fires when the GioView is
destroyed — i.e. the activity going away on a recents-wipe. Our
handleEvent passed that null ref straight into registerFragment,
whose GetObjectClass(null) aborts. Pre-existing latent bug; the
emulator never delivered a detach event in testing (home keeps the
view attached, force-stop kills before the event dispatches).

Guard on both sides: handleEvent ignores the View == 0 detach
signal (a re-attach arrives as a fresh event with a live view), and
registerFragment returns early on a null view as defense in depth.

Verified on the crashing device: recents swipe now closes the app
cleanly, crash buffer empty.
2026-08-20 18:49:00 -04:00
2bdff5c8e8 Flush the session snapshot on activity onStop (Android)
The OS provides no user-space hook for a process kill, but the
activity onStop fires on every 'going away' transition the framework
still controls: entering recents (the swipe-wipe path), app switch,
and home. Recents-wipe then kills the process right after onStop
returns, so that moment is the last reliable flush.

- Logic.FlushSession (any goroutine, buffered, non-blocking) ->
  flushSessionSave on the owner: persist the snapshot now, bypassing
  the rate limit (still honoring the restore-pending suppression).
  saveSessionIfChanged's persist tail is deduplicated into writeSession.
- JNI: GioActivity.onStop (patched into the smali by the build
  scripts, in sync) now calls the static native padFlushSession, which
  maps to the pad_flush_session cgo export.

Verified on emulator: the flush fires on home/app-switch and when the
app is backgrounded into recents before a kill; a state change made
inside the 250ms rate window and then backed out of the app persists
the latest position. A hard kill while foregrounded (force-stop,
memory pressure) still has no hook — the immediate edit saves plus the
250ms rate window bound that loss.
2026-08-20 18:24:43 -04:00
275a78efaa Fix selection-handle drags, menu anchoring, and left-edge back-gesture theft
Three user-reported selection bugs, one root cause each:

1. Start handle ungrabbable at line start. Two interacting causes:
   a) The 48dp grab box straddles two visual lines; a finger in the
      lower half mapped (by y-to-line) to the neighbouring line, whose
      byte past the other handle clamped to a zero-length selection ->
      cleared on the first drag event. The cleared selection
      un-registered the drag op, so the router silently stopped
      delivering drag events (the observed 'stream cutoff'). Fix:
      handle drags now project the finger's x onto the anchor's own
      visual line (visualLineOfByte + textPosOnLineAtX); the anchor
      never crosses lines during a handle drag.
   b) A horizontal flick from the line-start handle (screen x~26px)
      started the system back gesture, which cancelled the touch
      stream. Fix: report the handle grab rects as system gesture
      exclusion rects (setSystemGestureExclusionRects, API 29+),
      marshalled to the UI thread via a PadExcl smali Runnable
      (generated identically by build_emu.sh/build_phone.sh).

2. End-handle drag downward made the menu chase the finger and cover
   the selection. Fix: the menu anchors to the STABLE end of the
   selection (the end not being dragged), so it stays parked by the
   selection start, clear of the finger and the highlighted text.

3. Menu above the selection vanished permanently when the selection
   was extended onto the top line. Fix: off-window anchors no longer
   hide the menu while any part of the selection is visible (keep-last
   rect, clamped); hiding happens only for fully off-window selections.

Also: registerDrag simplified (single shared drag path, body before
handles in z-order), debug logging removed, regression tests
(mutation-verified) for line projection and menu anchoring, docs
section 17. Verified on device: start-handle drag shrinks the word
without clearing or triggering back navigation; end-handle vertical
drag leaves menu/highlight/handles undisturbed; menu stays visible
with the selection at the top line.
2026-08-18 13:09:29 -04:00
7240b62a61 WIP baseline: Termux open-file bridge + word-wrap-aware viewport/scroll
- JNI: open_file_in_termux via ACTION_SEND intent (text/plain + file:// uri),
  global context ref kept from registerFragment
- impl_android.go: OpenFile(path) attaches current thread if needed
- NewLogic takes openfunc; State.open + ui.OpenFile now func(string)
- ChunkedBuffer.VisibleByteRange: word-wrap path using
  GlyphLayout.VisualLineStarts (+byteOffset, lineHeight, visual index param)
- GlyphLayout gains LineHeight; drawWrappedText records VisualLineStarts
- WordWrap default true; State.ByteOffset tracks first visible line
- types: VisualLineIndex
- scroll_fix_test.go (new)
- debug prints left in place (WIP; cleanup in later phase)
2026-08-16 00:31:26 -04:00
ac2e0e444d Request Android permissions. 2026-06-05 10:57:53 -04:00