Releases: rust-mobile/android-activity
v0.6.1
Added
- input:
TextInputActionenum representing action button types on soft keyboards. (#216) - input:
InputEvent::TextActionevent for handling action button presses from soft keyboards. (#216) - The
ndkandndk-syscrates are now re-exported underandroid_activity::ndkandandroid_activity::ndk_sys(#194) AndroidApp::java_main_looper()gives access to theALooperfor the Java main / UI thread (#198)AndroidApp::run_on_java_main_thread()can be used to run boxed closures on the Java main / UI thread (#232)- Support for an optional
android_on_createentry point that gets called from theActivity.onCreate()callback beforeandroid_main()is called, allowing for doing some setup work on the Java main / UI thread before theandroid_mainRust code starts running.
For example:
use std::sync::OnceLock;
use android_activity::OnCreateState;
use jni::{JavaVM, refs::Global, objects::JObject};
#[unsafe(no_mangle)]
fn android_on_create(state: &OnCreateState) {
static APP_ONCE: OnceLock<()> = OnceLock::new();
APP_ONCE.get_or_init(|| {
// Initialize logging...
//
// Remember, `android_on_create` may be called multiple times but some
// logger crates will panic if initialized multiple times.
});
let vm = unsafe { JavaVM::from_raw(state.vm_as_ptr().cast()) };
let activity = state.activity_as_ptr() as jni::sys::jobject;
// Although the thread is implicitly already attached (we are inside an onCreate native method)
// using `vm.attach_current_thread` here will use the existing attachment, give us an `&Env`
// reference and also catch Java exceptions.
if let Err(err) = vm.attach_current_thread(|env| -> jni::errors::Result<()> {
// SAFETY:
// - The `Activity` reference / pointer is at least valid until we return
// - By creating a `Cast` we ensure we can't accidentally delete the reference
let activity = unsafe { env.as_cast_raw::<JObject>(&activity)? };
// Do something with the activity on the Java main thread...
Ok(())
}) {
eprintln!("Failed to interact with Android SDK on Java main thread: {err:?}");
}
}- Support for
MotionEventhistory, providing higher fidelity input data for things like stylus input (native-activity+game-activitybackends). (#218)
Changed
- rust-version bumped to 1.85.0 (#193, #219)
- GameActivity updated to 4.4.0 (#191, #240)
ndk-contextis initialized with anApplicationcontext instead of anActivitycontext (#229)
GameActivity 4.4.0 Update
Important: This release is no longer compatible with GameActivity 2.0.2
Android Packaging: Your Android application must be packaged with the corresponding androidX, GameActivity 4.x.x library from Google.
This release has been tested with the androidx.games:games-activity:4.4.0 stable
release, and is backwards
compatible with the 4.0.0 stable release.
If you use Gradle to build your Android application, you can depend on the 4.4.0 release of the GameActivity library via:
dependencies {
implementation 'androidx.appcompat:appcompat:1.7.1'
// To use the Games Activity library
implementation "androidx.games:games-activity:4.4.0"
// Note: don't include game-text-input separately, since it's integrated into game-activity
}Note: there is no guarantee that later 4.x.x releases of GameActivity will be compatible with this release of
android-activity, so please refer to the android-activity release notes for any future updates regarding
GameActivity compatibility.
Initializing ndk-context with an Application Context
ndk-context is a separate, framework-independent crate that provides a way for library crates to access a Java VM pointer and an android.content.Context JNI reference without needing to depend on android-activity directly.
ndk-context may be initialized by various framework crates, including android-activity, on behalf of library crates.
Historically android-activity has initialized ndk-context with an Activity context since that was the simplest choice considering that the entrypoint for android-activity comes from an Activity onCreate callback.
However, in retrospect it was realized that this was a short-sighted mistake when considering that:
ndk-contextonly provides a single, global context reference for the entire application that can't be updated- An Android application can have multiple
Activityinstances over its lifetime (and at times could have noActivityinstances at all, e.g. if the app is running a backgroundService) - Whatever is put into
ndk-contextneeds to leak a corresponding global reference to ensure it remains valid to access safely. This is inappropriate for anActivityreference since it can be destroyed and recreated multiple times over the lifetime of the application.
A far better choice, that aligns with the global nature of the ndk-context API is to initialize it with an Application context which is valid for the entire lifetime of the application.
Note: Although the ndk-context API only promises to provide an android.content.Context and specifically warns that user's should not assume the context is an Activity, there is still some risk that some users of ndk-context could be affected by the change made in #229.
For example, until recently the webbrowser crate (for opening URLs) was assuming it could access an Activity context via ndk-context. In preparation for making this change, webbrowser was updated to ensure it is agnostic to the type of context provided by ndk-context, see: amodm/webbrowser-rs#111
Other notable library crates that support Android (such as app_dirs2) are expected to be unaffected by this, since they already operate in terms of the android.content.Context API, not the Activity API.
_Note:: if some crate really needs an Activity reference then they should ideally be able to get one via the
AndroidApp::activity_as_ptr() API. They may need to add some Android-specific initialization API, similar to how Winit has a dedicated .with_android_app() API. An Android-specific init API that could accept a JNI reference to an Activity could avoid needing to specifically depend on android-activity.
Fixed
- Safety
AndroidApp::asset_manager()returns anAssetManagerthat has a safe'staticlifetime that's not invalidated whenandroid_main()returns (#233) - Safety The
native-activitybackend clears itsANativeActivityptr afteronDestroyandAndroidAppremains safe to access afterandroid_main()returns (#234) - Safety
AndroidApp::activity_as_ptr()returns a pointer to a global reference that remains valid untilAndroidAppis dropped, instead of theANativeActivity'sclazzpointer which is only guaranteed to be valid untilonDestroyreturns (native-activitybackend) (#234) - Safety The
game-activitybackend clears itsandroid_appptr afteronDestroyandAndroidAppremains safe to access afterandroid_main()returns (#236) - Support for
AndroidApp::show/hide_soft_input()APIs in thenative-activitybackend (#178)
Overall, some effort was made to ensure that android-activity can gracefully and safely handle cases where the Activity gets repeatedly created, destroyed and recreated (e.g due to configuration changes). Theoretically it should even be possible to run multiple Activity instances (although that's not really something that NativeActivity or GameActivity are designed for).
New Contributors
- @jb55 made their first contribution in #191
- @madsmtm made their first contribution in #199
- @atouchet made their first contribution in #220
- @markkimsal made their first contribution in #198
- @jancespivo made their first contribution in #178
Full Changelog: v0.6.0...v0.6.1
v0.6.0
What's Changed
- Bump MSRV to 1.69.0 considering we can't build cargo ndk with 1.68 by @rib in #156
- Upgrade to
ndk-sys 0.6.0andndk 0.9.0by @MarijnS95 in #155 - native-activity: Check for null
saved_state_inpointer by @skibon02 in #157 - Release 0.6.0 by @rib in #158
New Contributors
Full Changelog: v0.5.2...v0.6.0
android-activity 0.5.2
What's Changed
- native-activity/input: AND with
EVENT_ACTION_MASKwhen extracting MotionEvent action by @ArthurCose in #147
New Contributors
- @ArthurCose made their first contribution in #147
Full Changelog: v0.5.1...v0.5.2
android-activity 0.5.1
Changed
-
Avoids depending on default features for
ndkcrate to avoid pulling in anyraw-window-handledependencies (#142)Note: Technically, this could be observed as a breaking change in case you were depending on the
rwh_06feature that was enabled by default in thendkcrate. This could be observed via theNativeWindowtype (exposed viaAndroidApp::native_window()) no longer implementingrwh_06::HasWindowHandle.In the unlikely case that you were depending on the
ndk'srwh_06API being enabled by default viaandroid-activity'sndkdependency, your crate should explicitly enable therwh_06feature for thendkcrate.As far as could be seen though, it's not expected that anything was depending on this (e.g. anything based on Winit enables the
ndkfeature based on an equivalentwinitfeature).The benefit of the change is that it can help avoid a redundant
raw-window-handle 0.6dependency in projects that still need to use older (non-default)raw-window-handleversions. (Though note that this may be awkward to achieve in practice since other crates that depend on thendkare still likely to use default features and also pull inraw-window-handles 0.6) -
The IO thread now gets named
stdio-to-logcatand main thread is namedandroid_main(#145) -
Improved IO error handling in
stdio-to-logcatIO loop. (#133)
New Contributors
- @Vrixyz made their first contribution in #142
Full Changelog: v0.5.0...v0.5.1
android-activity 0.5.0
Probably the most notable (breaking) change in this release is the updated API for reading input events to better support being able to use other AndroidApp APIs while iterating input events, to support unicode character mapping for Keycodes.
The other big change with this release is the update of the game-activity backend, updating to GameActivity 2.0.2. Applications using the game-activity backend will need to ensure they pull in the corresponding 2.0.2 .aar from Google (For example, see https://github.com/rust-mobile/android-activity/blob/main/examples/agdk-mainloop/app/build.gradle)
Added
-
Added
KeyEvent::meta_state()for being able to query the state of meta keys, needed for character mapping (#102) -
Added
KeyCharacterMapJNI bindings to the corresponding Android SDK API (#102) -
Added
AndroidApp::device_key_character_map()for being able to get aKeyCharacterMapfor a givendevice_idfor unicode character mapping (#102)Click here for an example of how to handle unicode character mapping:
let mut combining_accent = None; // Snip let combined_key_char = if let Ok(map) = app.device_key_character_map(device_id) { match map.get(key_event.key_code(), key_event.meta_state()) { Ok(KeyMapChar::Unicode(unicode)) => { let combined_unicode = if let Some(accent) = combining_accent { match map.get_dead_char(accent, unicode) { Ok(Some(key)) => { info!("KeyEvent: Combined '{unicode}' with accent '{accent}' to give '{key}'"); Some(key) } Ok(None) => None, Err(err) => { log::error!("KeyEvent: Failed to combine 'dead key' accent '{accent}' with '{unicode}': {err:?}"); None } } } else { info!("KeyEvent: Pressed '{unicode}'"); Some(unicode) }; combining_accent = None; combined_unicode.map(|unicode| KeyMapChar::Unicode(unicode)) } Ok(KeyMapChar::CombiningAccent(accent)) => { info!("KeyEvent: Pressed 'dead key' combining accent '{accent}'"); combining_accent = Some(accent); Some(KeyMapChar::CombiningAccent(accent)) } Ok(KeyMapChar::None) => { info!("KeyEvent: Pressed non-unicode key"); combining_accent = None; None } Err(err) => { log::error!("KeyEvent: Failed to get key map character: {err:?}"); combining_accent = None; None } } } else { None };
-
Added
TextEventInput Method event for supporting text editing via virtual keyboards (#24) -
Added
MotionEvent::action_button()exposing the button associated with button press/release actions (#138)
Changed
-
rust-version bumped to 0.68 (#123)
-
Breaking: update to
ndk 0.8andndk-sys 0.5(#128) -
GameActivity updated to 2.0.2 (requires the corresponding 2.0.2
.aarrelease from Google) (#88) -
AndroidApp::input_events()is replaced byAndroidApp::input_events_iter()(#102)Click here for an example of how to use `input_events_iter()`:
match app.input_events_iter() { Ok(mut iter) => { loop { let read_input = iter.next(|event| { let handled = match event { InputEvent::KeyEvent(key_event) => { // Snip } InputEvent::MotionEvent(motion_event) => { // Snip } event => { // Snip } }; handled }); if !read_input { break; } } } Err(err) => { log::error!("Failed to get input events iterator: {err:?}"); } }
-
The
PointerandPointerItertypes from thendkcrate are no longer directly exposed in the public API (#122) -
All input API enums based on Android SDK enums have been made runtime extensible via hidden
__Unknown(u32)variants (#131)
New Contributors
- @lexi-the-cute made their first contribution in #88
- @daxpedda made their first contribution in #85
- @fornwall made their first contribution in #124
Full Changelog: v0.4.3...v0.5.0
android-activity 0.5.0-beta.1
This only updates the ndk and ndk-sys dependencies to pull in ndk 0.8.0-beta.0 and ndk-sys 0.5.0-beta.0
android-activity 0.5.0-beta.0
This is the first 0.5.0 beta that's aiming to be ready for the upcoming Winit 0.29 release
The main reason that a (breaking) semver bump was required was so we could update the API for reading input events to better support being able to use other AndroidApp APIs while iterating input events, to support unicode character mapping for Keycodes.
A big change with this release is the update of the game-activity backend, updating to GameActivity 2.0.2. Applications using the game-activity backend will need to ensure they pull in the corresponding 2.0.2 .aar from Google (For example, see https://github.com/rust-mobile/android-activity/blob/main/examples/agdk-mainloop/app/build.gradle)
Added
-
Added
KeyEvent::meta_state()for being able to query the state of meta keys, needed for character mapping (#102) -
Added
KeyCharacterMapJNI bindings to the corresponding Android SDK API (#102) -
Added
AndroidApp::device_key_character_map()for being able to get aKeyCharacterMapfor a givendevice_idfor unicode character mapping (#102)Click here for an example of how to handle unicode character mapping:
let mut combining_accent = None; // Snip let combined_key_char = if let Ok(map) = app.device_key_character_map(device_id) { match map.get(key_event.key_code(), key_event.meta_state()) { Ok(KeyMapChar::Unicode(unicode)) => { let combined_unicode = if let Some(accent) = combining_accent { match map.get_dead_char(accent, unicode) { Ok(Some(key)) => { info!("KeyEvent: Combined '{unicode}' with accent '{accent}' to give '{key}'"); Some(key) } Ok(None) => None, Err(err) => { log::error!("KeyEvent: Failed to combine 'dead key' accent '{accent}' with '{unicode}': {err:?}"); None } } } else { info!("KeyEvent: Pressed '{unicode}'"); Some(unicode) }; combining_accent = None; combined_unicode.map(|unicode| KeyMapChar::Unicode(unicode)) } Ok(KeyMapChar::CombiningAccent(accent)) => { info!("KeyEvent: Pressed 'dead key' combining accent '{accent}'"); combining_accent = Some(accent); Some(KeyMapChar::CombiningAccent(accent)) } Ok(KeyMapChar::None) => { info!("KeyEvent: Pressed non-unicode key"); combining_accent = None; None } Err(err) => { log::error!("KeyEvent: Failed to get key map character: {err:?}"); combining_accent = None; None } } } else { None };
-
Added
TextEventInput Method event for supporting text editing via virtual keyboards (#24)
Changed
-
GameActivity updated to 2.0.2 (requires the corresponding 2.0.2
.aarrelease from Google) (#88) -
AndroidApp::input_events()is replaced byAndroidApp::input_events_iter()(#102)Click here for an example of how to use `input_events_iter()`:
match app.input_events_iter() { Ok(mut iter) => { loop { let read_input = iter.next(|event| { let handled = match event { InputEvent::KeyEvent(key_event) => { // Snip } InputEvent::MotionEvent(motion_event) => { // Snip } event => { // Snip } }; handled }); if !read_input { break; } } } Err(err) => { log::error!("Failed to get input events iterator: {err:?}"); } }
New Contributors
- @lexi-the-cute made their first contribution in #88
- @daxpedda made their first contribution in #85
Full Changelog: v0.4.3...v0.5.0-beta.0
android-activity 0.4.3
android-activity 0.4.2
What's Changed
- Add dependabot support by @notgull in #72
- native-activity: Propagate
NativeWindowredraw/resize andContentRectChangedcallbacks to main loop by @MarijnS95 in #70 - Add MSRV policy to README and bump
rust_versionto 1.64, due tondk->raw_window_handledependency by @rib in #76 - build(deps): update num_enum requirement from 0.5 to 0.6 by @dependabot in #74
- build(deps): bump actions/checkout from 2 to 3 by @dependabot in #73
- Fix rust_version typo s/0.64/1.64/ by @rib in #77
- Add panic guards to extern "C" functions by @notgull in #68
- game_activity: Fix
pointer_index()always returning0by @yunsash in #84 - README: Add badges to CI, crates.io, docs.rs and show the MSRV by @MarijnS95 in #86
- Call Activity.finish() when android_main returns by @rib in #81
- cargo: Fix
rust_version->rust-versionproperty typo by @MarijnS95 in #87 - Release 0.4.2 by @rib in #90
New Contributors
- @notgull made their first contribution in #72
- @dependabot made their first contribution in #74 - good bot 🤖
- @yunsash made their first contribution in #84
Full Changelog: v0.4.1...v0.4.2
android-activity 0.4.1
What's Changed
Added
- Added
AndroidApp::vm_as_ptr()to expose JNIJavaVMpointer (#60) - Added
AndroidApp::activity_as_ptr()to expose AndroidActivityJNI reference as pointer (#60)
Changed
- Removed some overly-verbose logging in the
native-activitybackend (#49)
Removed
- Most of the examples were moved to https://github.com/rust-mobile/rust-android-examples (#50)
New Contributors
- @MarijnS95 made their first contribution in #47
Full Changelog: v0.4.0...v0.4.1