This updates both the examples to Gradle 9 and AGP 9.1
The examples are identical, except that `na-mainloop` is based on
NativeActivity and the `agdk-mainloop` based on GameActivity.
The examples demonstrate:
- Using the `jni` API to define enough bindings to be able to send a Toast
- Using an `android_on_create` entry point for logging initialization
and JNI initialization
- Using `AndroidApp::run_on_java_main_thread()` to send a toast from the
Java main / UI thread
- Running an `android_main` event loop, including printing historic
pointer samples (a new 0.6.1 feature)
The examples support two input actions:
- Lifting your finger in the top-left corner of the screen will show the
onscreen keyboard
- Lifting your finger in the top-right corner of the screen will hide
the onscreen keyboard
If you edit and disable `configChanges` in `AndroidManifest.xml` then
these examples can also demonstrate that `android-activity` gracefully
handles repeated `Activity` create -> run -> destroy cycles.
The next breaking `ndk` release puts a lot of emphasis in improving
`enum`s to finally be marked `non_exhaustive`, and carry possible future
values in `__Unknown(i32)` variants. This removes the lossy conversions
that previously required `android-activity` to redefine its types, which
could all be removed again.
The `repr()` types have also been updated, as `enum` constants in C are
translated to `u32` by default in `bindgen` even though they're commonly
passed as `int` to every API function that consumes them.
With the way events are delivered via an `InputQueue` with
`NativeActivity` there is no direct access to the underlying KeyEvent
and MotionEvent Java objects and no `ndk` API that supports the
equivalent of `KeyEvent.getUnicodeChar()`
What `getUnicodeChar` does under the hood though is to do lookups into a
`KeyCharacterMap` for the corresponding `InputDevice` based on the
event's `key_code` and `meta_state` - which are things we can do via
some JNI bindings for `KeyCharacterMap`.
Although it's still awkward to expose an API like
`key_event.get_unicode_char()` we can instead provide an API that
lets you look up a `KeyCharacterMap` for any `device_id` and
applications can then use that for character mapping.
This approach is also more general than the `getUnicodeChar` utility
since it exposes other useful state, such as being able to check what
kind of keyboard input events are coming from (such as a full physical
keyboard vs a virtual / 'predictive' keyboard)
For consistency this exposes the same API through the game-activity
backend, even though the game-activity backend is technically able to
support unicode lookups via `getUnicodeChar` (since it has access to the
Java `KeyEvent` object).
This highlighted a need to be able to use other `AndroidApp` APIs while
processing input, which wasn't possible with the `.input_events()` API
design because the `AndroidApp` held a lock over the backend while
iterating events.
This changes `input_events()` to `input_events_iter()` which now returns
a form of lending iterator and instead of taking a callback that gets
called repeatedly by `input_events()` a similar callback is now passed
to `iter.next(callback)`.
The API isn't as ergonomic as I would have liked, considering that
lending iterators aren't a standard feature for Rust yet but also since
we still want to have the handling for each individual event go via a
callback that can report whether an event was "handled". I think the
slightly awkward ergonomics are acceptable though considering that
the API will generally be used as an implementation detail within
middleware frameworks like Winit.
Since this is the first example where we're creating non-trivial Java
bindings for an Android SDK API this adds some JNI utilities and
establishes a pattern for how we can implement a class binding.
It's an implementation detail but with how I wrote the binding I tried
to keep in mind the possibility of creating a procmacro later that would
generate some of the JNI boilerplate involved.
When splitting out the rust-android-examples we kept the agdk-mainloop
and na-mainloop examples in part so we would have some simple code we
can build as integration tests.
Since it's less likely that these will be referenced directly as
examples now, compared to those in rust-android-examples this removes
the lock files so we will instead always build against the latest semver
compatible dependencies.
Considering the simplicity of these examples, and minimal dependencies
these lock files probably weren't that worthwhile before either.
Most of the examples weren't strictly just demonstrating how to use the
android-activity API - rather they demonstrated using other libraries
in conjunction with android-activity.
Most of the examples have now been split into a standalone repository
under: https://github.com/rust-mobile/rust-android-examples
The na-mainloop and agdk-mainloop examples have been kept here since
they can be built against the local/in-tree version of android-activity
and are useful to keep for CI purposes.
This also runs `cargo update` for the na-mainloop and agdk-mainloop.
- Updates deps
- Some README updates considering the Winit backend based on
android-activity has been merged upstream
- runs cargo fmt over examples
- Top-level Cargo.toml simply excludes "examples" instead of
listing each sub-directory separately
The winit based examples no longer have an explicit dependency on
android-activity and they instead consume the `android-activity` API via
the Winit crate so there's no need to keep the versions synchronized.
The callback given to `AndroidApp::input_events()` is now expected to return
`InputStatus::Handled` or `InputStatus::Unhandled`.
When running with NativeActivity then if we know an input event hasn't been
handled we can notify the InputQueue which may result in fallback
handling.
Although the status is currently ignored with the GameActivity backend.
Since this is a breaking change that also affects the current Winit
backend this updates the winit based examples to stick with the 0.3
release of android-activity for now.
Fixes: #31
This provides an API to access `Configuration` state for the application
without having to make deep copies of the large `Configuration` struct.
This should avoid the need for Winit to create a global static copy of
the Configuration whenever it changes - and instead it can just get
a `ConfigurationRef` which will always reflect the latest config for
the application.
Fixes: #5
This makes a small change to the C glue code for GameActivity to send
looper wake ups when new input is received (only sending a single wake
up, until the application next handles input).
When a wake up is received and we recognise that new input is available
then an `InputAvailable` event is sent to the application - consistent
with how NativeActivity can deliver `InputAvailable` events.
This addresses a significant feature disparity between GameActivity and
NativeActivity that meant GameActivity was not practically usable for
GUI applications that wouldn't want to render continuously like a game.
Addresses #4
android_main() now takes an `app: AndroidApp` argument and has an
extern "Rust" ABI instead of "C" ABI.
This should help make it possible to run multiple native Activities in a
single process.
This leaves the InputBuffer abstraction as an implementation detail
and just exposes an API like this for processing input:
app.input_events(|event| {
// handle event
});
The main consideration here was to have an API that could also be
supported via NativeActivity to keep open the possibility of a standard
Android 'glue' API.