Skip to content

native-activity: opt-in non-blocking lifecycle callbacks, and let the activity own the IME - #255

Open
Hawaii-005 wants to merge 1 commit into
rust-mobile:mainfrom
Hawaii-005:nonblocking-callbacks-and-ime-host
Open

Hawaii-005 wants to merge 1 commit into
rust-mobile:mainfrom
Hawaii-005:nonblocking-callbacks-and-ime-host

Conversation

@Hawaii-005

Copy link
Copy Markdown

Two opt-ins, both for activities that are more than a bare NativeActivity. They come from a real app (SolidCraft, a CAD editor with a native Android port), where both of these were blocking.

Non-blocking lifecycle callbacks. The JVM-thread callbacks (set_input, set_window, set_activity_state, request_save_state) wait on a condvar until the Rust main thread runs poll_events. If the main thread is parked inside a modal operation — in practice startActivityForResult for a Storage Access Framework pick — the callback waits for it, and the system ANRs the app after about five seconds. set_nonblocking_callbacks(true) makes those callbacks deliver their command to the pipe and wait at most 100 ms instead, so the main thread picks the pending state up when it resumes pumping. InputQueueChanged and InitWindow commands are coalesced while pending, so the pipe does not fill while nobody drains it.

The activity owning the IME. A bare NativeActivity has no editable view, so showSoftInput() on the decor view is unreliable and typed text never arrives. show_soft_input / hide_soft_input now first call imeShow() / imeHide() on the activity object when it has those methods, and fall through to the existing decor-view path when it does not — an activity generated by the app can host a real EditText and forward the IME output.

Both are opt-in and default to the current behaviour: existing users see no change.

Compiled here: cargo check -p android-activity --features native-activity --target aarch64-linux-android. The app that motivated this ships with both patches and uses both paths, but the hardware they target (a drawing tablet) is not at hand, so I have not re-verified the SAF/IME paths on a device in this round — what I can vouch for is that it compiles for the target and that the app runs with it.

If either half is unwelcome here, I am happy to split it: the ANR fix stands on its own, and the IME hook is the more opinionated of the two.

Hawaii-005 pushed a commit to Hawaii-005/solidcraft that referenced this pull request Oct 24, 2026
…ot from vendored copies

The two crates were vendored whole (~100k lines) to carry two small changes to their Android
backends. Both changes are now proposed upstream instead, and the build takes them as
[patch.crates-io] git dependencies:

- rust-windowing/winit#4793: a stylus hovering above the glass is a pointer move, and a palm resting
  next to the pen is not a second finger (it was read as a pinch, so a stroke zoomed the view).
- rust-mobile/android-activity#255: opt-in non-blocking lifecycle callbacks, so a blocking SAF pick
  does not park android_main and ANR the app, and an activity can host its own IME view.

Both entries go back to crates.io once a release carries them. This takes the diff of the port from
~100k lines to ~2.5k and leaves the two patches where they can be reviewed on their own.
Hawaii-005 pushed a commit to Hawaii-005/solidcraft that referenced this pull request Oct 24, 2026
…ot from vendored copies

The two crates were vendored whole (~100k lines) to carry two small changes to their Android
backends. Both changes are now proposed upstream instead, and the build takes them as
[patch.crates-io] git dependencies:

- rust-windowing/winit#4793: a stylus hovering above the glass is a pointer move, and a palm resting
  next to the pen is not a second finger (it was read as a pinch, so a stroke zoomed the view).
- rust-mobile/android-activity#255: opt-in non-blocking lifecycle callbacks, so a blocking SAF pick
  does not park android_main and ANR the app, and an activity can host its own IME view.

Both entries go back to crates.io once a release carries them. This takes the diff of the port from
~100k lines to ~2.5k and leaves the two patches where they can be reviewed on their own.
… activity own the IME

Both are for activities that do more than a bare NativeActivity:

`set_nonblocking_callbacks(true)` covers a main thread that is parked inside a modal
operation (a SAF file picker via startActivityForResult, in practice). The JVM-thread
lifecycle callbacks block on a condvar until `poll_events` runs; if the main thread is
parked in that pick, the system ANRs the app after ~5s. With the flag on, a callback
delivers its command to the pipe and waits at most 100ms, and the main thread picks the
state up when it resumes pumping. Duplicate InputQueueChanged/InitWindow commands are
coalesced so the pipe does not fill while nobody drains it.

`show_soft_input`/`hide_soft_input` first call `imeShow()`/`imeHide()` on the activity
when it has them. A bare NativeActivity has no editable view, so `showSoftInput` on the
decor view is unreliable and text never arrives; an activity generated for the app can
host a real EditText and forward the IME result. Activities without the methods fall
through to the existing decor-view path.
@Hawaii-005
Hawaii-005 force-pushed the nonblocking-callbacks-and-ime-host branch from e554052 to 4ea6cdc Compare October 24, 2026 04:55
Hawaii-005 pushed a commit to Hawaii-005/solidcraft that referenced this pull request Oct 24, 2026
…ot from vendored copies

The two crates were vendored whole (~100k lines) to carry two small changes to their Android
backends. Both changes are now proposed upstream instead, and the build takes them as
[patch.crates-io] git dependencies:

- rust-windowing/winit#4793: a stylus hovering above the glass is a pointer move, and a palm resting
  next to the pen is not a second finger (it was read as a pinch, so a stroke zoomed the view).
- rust-mobile/android-activity#255: opt-in non-blocking lifecycle callbacks, so a blocking SAF pick
  does not park android_main and ANR the app, and an activity can host its own IME view.

Both entries go back to crates.io once a release carries them. This takes the diff of the port from
~100k lines to ~2.5k and leaves the two patches where they can be reviewed on their own.
Hawaii-005 pushed a commit to Hawaii-005/solidcraft that referenced this pull request Oct 27, 2026
…ot from vendored copies

The two crates were vendored whole (~100k lines) to carry two small changes to their Android
backends. Both changes are now proposed upstream instead, and the build takes them as
[patch.crates-io] git dependencies:

- rust-windowing/winit#4793: a stylus hovering above the glass is a pointer move, and a palm resting
  next to the pen is not a second finger (it was read as a pinch, so a stroke zoomed the view).
- rust-mobile/android-activity#255: opt-in non-blocking lifecycle callbacks, so a blocking SAF pick
  does not park android_main and ANR the app, and an activity can host its own IME view.

Both entries go back to crates.io once a release carries them. This takes the diff of the port from
~100k lines to ~2.5k and leaves the two patches where they can be reviewed on their own.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant