diff --git a/android-activity/CHANGELOG.md b/android-activity/CHANGELOG.md index 34a3071..0aa349c 100644 --- a/android-activity/CHANGELOG.md +++ b/android-activity/CHANGELOG.md @@ -3,7 +3,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] - +### Changed +- *Breaking*: `input_events` callback now return whether an event was handled or not to allow for fallback handling ([#31](https://github.com/rib/android-activity/issues/31)) ## [0.3] - 2022-09-15 ### Added diff --git a/android-activity/src/game_activity/mod.rs b/android-activity/src/game_activity/mod.rs index 47e4912..21755ef 100644 --- a/android-activity/src/game_activity/mod.rs +++ b/android-activity/src/game_activity/mod.rs @@ -23,7 +23,9 @@ use ndk::asset::AssetManager; use ndk::configuration::Configuration; use ndk::native_window::NativeWindow; -use crate::{util, AndroidApp, ConfigurationRef, MainEvent, PollEvent, Rect, WindowManagerFlags}; +use crate::{ + util, AndroidApp, ConfigurationRef, InputStatus, MainEvent, PollEvent, Rect, WindowManagerFlags, +}; mod ffi; @@ -391,7 +393,7 @@ impl AndroidAppInner { pub fn input_events<'b, F>(&self, mut callback: F) where - F: FnMut(&InputEvent), + F: FnMut(&InputEvent) -> InputStatus, { let buf = unsafe { let app_ptr = self.native_app.as_ptr(); diff --git a/android-activity/src/lib.rs b/android-activity/src/lib.rs index 8e559d0..ff6aeb6 100644 --- a/android-activity/src/lib.rs +++ b/android-activity/src/lib.rs @@ -171,6 +171,12 @@ pub enum PollEvent<'a> { Main(MainEvent<'a>), } +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum InputStatus { + Handled, + Unhandled, +} + use activity_impl::AndroidAppInner; pub use activity_impl::AndroidAppWaker; @@ -473,6 +479,10 @@ impl AndroidApp { /// Query and process all out-standing input event /// + /// `callback` should return [`InputStatus::Unhandled`] for any input events that aren't directly + /// handled by the application, or else [`InputStatus::Handled`]. Unhandled events may lead to a + /// fallback interpretation of the event. + /// /// Applications are generally either expected to call this in-sync with their rendering or /// in response to a [`MainEvent::InputAvailable`] event being delivered. _Note though that your /// application is will only be delivered a single [`MainEvent::InputAvailable`] event between calls @@ -482,9 +492,9 @@ impl AndroidApp { /// and other axis should be enabled explicitly via [`Self::enable_motion_axis`]. pub fn input_events<'b, F>(&self, callback: F) where - F: FnMut(&input::InputEvent), + F: FnMut(&input::InputEvent) -> InputStatus, { - self.inner.read().unwrap().input_events(callback); + self.inner.read().unwrap().input_events(callback) } /// The user-visible SDK version of the framework diff --git a/android-activity/src/native_activity/mod.rs b/android-activity/src/native_activity/mod.rs index af2cbf2..4456001 100644 --- a/android-activity/src/native_activity/mod.rs +++ b/android-activity/src/native_activity/mod.rs @@ -21,7 +21,9 @@ use ndk::configuration::Configuration; use ndk::input_queue::InputQueue; use ndk::native_window::NativeWindow; -use crate::{util, AndroidApp, ConfigurationRef, MainEvent, PollEvent, Rect, WindowManagerFlags}; +use crate::{ + util, AndroidApp, ConfigurationRef, InputStatus, MainEvent, PollEvent, Rect, WindowManagerFlags, +}; mod ffi; @@ -415,7 +417,7 @@ impl AndroidAppInner { pub fn input_events<'b, F>(&self, mut callback: F) where - F: FnMut(&input::InputEvent), + F: FnMut(&input::InputEvent) -> InputStatus, { let queue = unsafe { let app_ptr = self.native_app.as_ptr(); @@ -444,20 +446,19 @@ impl AndroidAppInner { ndk::event::InputEvent::MotionEvent(e) => input::InputEvent::MotionEvent(e), ndk::event::InputEvent::KeyEvent(e) => input::InputEvent::KeyEvent(e), }; - callback(&event); + let handled = callback(&event); let ndk_event = match event { input::InputEvent::MotionEvent(e) => ndk::event::InputEvent::MotionEvent(e), input::InputEvent::KeyEvent(e) => ndk::event::InputEvent::KeyEvent(e), }; - - // Always report events as 'handled'. This means we won't get - // so called 'fallback' events generated (such as converting trackball - // events into emulated keypad events), but we could conceivably - // implement similar emulation somewhere else in the stack if - // necessary, and this will be more consistent with the GameActivity - // input handling that doesn't do any kind of emulation. - queue.finish_event(ndk_event, true); + queue.finish_event( + ndk_event, + match handled { + InputStatus::Handled => true, + _ => false, + }, + ); } } } diff --git a/examples/agdk-cpal/src/lib.rs b/examples/agdk-cpal/src/lib.rs index 886aac3..b69511d 100644 --- a/examples/agdk-cpal/src/lib.rs +++ b/examples/agdk-cpal/src/lib.rs @@ -1,4 +1,4 @@ -use android_activity::{AndroidApp, MainEvent, PollEvent}; +use android_activity::{AndroidApp, InputStatus, MainEvent, PollEvent}; use log::info; use cpal::traits::{DeviceTrait, HostTrait, StreamTrait}; @@ -131,6 +131,7 @@ fn android_main(app: AndroidApp) { // Handle input app.input_events(|event| { info!("Input Event: {event:?}"); + InputStatus::Unhandled }); info!("Render..."); diff --git a/examples/agdk-eframe/Cargo.lock b/examples/agdk-eframe/Cargo.lock index 006cd6b..57e4e63 100644 --- a/examples/agdk-eframe/Cargo.lock +++ b/examples/agdk-eframe/Cargo.lock @@ -75,6 +75,8 @@ dependencies = [ [[package]] name = "android-activity" version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe057899cd59c5254279b74382bf8132d683f8619ea50592c096710d65d03902" dependencies = [ "android-properties", "bitflags", diff --git a/examples/agdk-eframe/Cargo.toml b/examples/agdk-eframe/Cargo.toml index 4787542..eb1a040 100644 --- a/examples/agdk-eframe/Cargo.toml +++ b/examples/agdk-eframe/Cargo.toml @@ -38,10 +38,17 @@ winit = { git = "https://github.com/rib/winit", branch = "android-activity" } # entrypoint for a native Rust application there can only be a single # implementation of the crate linked with the application. # -# Since Winit also depends on android-activity (version = "0.2") but we'd like -# to build against the local version of android-activity in this repo then we -# use a [patch] to ensure we only end up with a single implementation. -android-activity = { path = "../../android-activity" } +# By default the Winit-based examples use released versions of android-activity +# to help keep the version in sync with the Winit backend. +# +# If you'd like to build this example against the local checkout of +# android-activity you should specify a patch here to make sure you also affect +# the version that Winit uses. +# +# Note: also check that the local android-activity/Cargo.toml version matches +# the android-activity version that Winit depends on (in case you need to check +# out a release branch locally to be compatible) +#android-activity = { path = "../../android-activity" } # Egui 0.19 is missing some fixes for Android so we need to build against # git master for now diff --git a/examples/agdk-egui/Cargo.lock b/examples/agdk-egui/Cargo.lock index 52352ec..bd3b6dc 100644 --- a/examples/agdk-egui/Cargo.lock +++ b/examples/agdk-egui/Cargo.lock @@ -76,6 +76,8 @@ dependencies = [ [[package]] name = "android-activity" version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe057899cd59c5254279b74382bf8132d683f8619ea50592c096710d65d03902" dependencies = [ "android-properties", "bitflags", diff --git a/examples/agdk-egui/Cargo.toml b/examples/agdk-egui/Cargo.toml index 52303d1..9d4637d 100644 --- a/examples/agdk-egui/Cargo.toml +++ b/examples/agdk-egui/Cargo.toml @@ -39,10 +39,17 @@ winit = { git = "https://github.com/rib/winit", branch = "android-activity" } # entrypoint for a native Rust application there can only be a single # implementation of the crate linked with the application. # -# Since Winit also depends on android-activity (version = "0.2") but we'd like -# to build against the local version of android-activity in this repo then we -# use a [patch] to ensure we only end up with a single implementation. -android-activity = { path = "../../android-activity" } +# By default the Winit-based examples use released versions of android-activity +# to help keep the version in sync with the Winit backend. +# +# If you'd like to build this example against the local checkout of +# android-activity you should specify a patch here to make sure you also affect +# the version that Winit uses. +# +# Note: also check that the local android-activity/Cargo.toml version matches +# the android-activity version that Winit depends on (in case you need to check +# out a release branch locally to be compatible) +#android-activity = { path = "../../android-activity" } [features] default = [] diff --git a/examples/agdk-mainloop/src/lib.rs b/examples/agdk-mainloop/src/lib.rs index c45f186..b043f87 100644 --- a/examples/agdk-mainloop/src/lib.rs +++ b/examples/agdk-mainloop/src/lib.rs @@ -1,4 +1,4 @@ -use android_activity::{AndroidApp, MainEvent, PollEvent}; +use android_activity::{AndroidApp, InputStatus, MainEvent, PollEvent}; use log::info; #[no_mangle] @@ -71,6 +71,7 @@ fn android_main(app: AndroidApp) { // Handle input app.input_events(|event| { info!("Input Event: {event:?}"); + InputStatus::Unhandled }); info!("Render..."); diff --git a/examples/agdk-oboe/src/audio.rs b/examples/agdk-oboe/src/audio.rs index 9cc7f34..c2a0571 100644 --- a/examples/agdk-oboe/src/audio.rs +++ b/examples/agdk-oboe/src/audio.rs @@ -43,6 +43,7 @@ impl SineGen { } /// Pause audio stream + #[allow(dead_code)] pub fn try_pause(&mut self) { if let Some(stream) = &mut self.stream { log::debug!("pause stream: {:?}", stream); @@ -92,6 +93,7 @@ impl SineParam { ); } + #[allow(dead_code)] fn set_frequency(&self, frequency: f32) { let sample_rate = self.sample_rate.load(Ordering::Relaxed); let delta = frequency * 2.0 * PI / sample_rate; @@ -100,6 +102,7 @@ impl SineParam { self.frequency.store(frequency, Ordering::Relaxed); } + #[allow(dead_code)] fn set_gain(&self, gain: f32) { self.gain.store(gain, Ordering::Relaxed); } @@ -151,7 +154,7 @@ impl AudioOutputCallback for SineWave { fn on_audio_ready( &mut self, - stream: &mut dyn AudioOutputStreamSafe, + _stream: &mut dyn AudioOutputStreamSafe, frames: &mut [f32], ) -> DataCallbackResult { for frame in frames { @@ -166,7 +169,7 @@ impl AudioOutputCallback for SineWave { fn on_audio_ready( &mut self, - stream: &mut dyn AudioOutputStreamSafe, + _stream: &mut dyn AudioOutputStreamSafe, frames: &mut [(f32, f32)], ) -> DataCallbackResult { for frame in frames { diff --git a/examples/agdk-oboe/src/lib.rs b/examples/agdk-oboe/src/lib.rs index d03d044..ee48149 100644 --- a/examples/agdk-oboe/src/lib.rs +++ b/examples/agdk-oboe/src/lib.rs @@ -1,4 +1,4 @@ -use android_activity::{AndroidApp, MainEvent, PollEvent}; +use android_activity::{AndroidApp, MainEvent, PollEvent, InputStatus}; use log::info; mod audio; @@ -75,6 +75,7 @@ fn android_main(app: AndroidApp) { // Handle input app.input_events(|event| { info!("Input Event: {event:?}"); + InputStatus::Unhandled }); info!("Render..."); diff --git a/examples/agdk-winit-wgpu/Cargo.lock b/examples/agdk-winit-wgpu/Cargo.lock index 4829f0f..9587df9 100644 --- a/examples/agdk-winit-wgpu/Cargo.lock +++ b/examples/agdk-winit-wgpu/Cargo.lock @@ -60,6 +60,8 @@ dependencies = [ [[package]] name = "android-activity" version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe057899cd59c5254279b74382bf8132d683f8619ea50592c096710d65d03902" dependencies = [ "android-properties", "bitflags", diff --git a/examples/agdk-winit-wgpu/Cargo.toml b/examples/agdk-winit-wgpu/Cargo.toml index ed8932e..e11b286 100644 --- a/examples/agdk-winit-wgpu/Cargo.toml +++ b/examples/agdk-winit-wgpu/Cargo.toml @@ -34,10 +34,17 @@ winit = { git = "https://github.com/rib/winit", branch = "android-activity-0.27" # entrypoint for a native Rust application there can only be a single # implementation of the crate linked with the application. # -# Since Winit also depends on android-activity (version = "0.2") but we'd like -# to build against the local version of android-activity in this repo then we -# use a [patch] to ensure we only end up with a single implementation. -android-activity = { path="../../android-activity" } +# By default the Winit-based examples use released versions of android-activity +# to help keep the version in sync with the Winit backend. +# +# If you'd like to build this example against the local checkout of +# android-activity you should specify a patch here to make sure you also affect +# the version that Winit uses. +# +# Note: also check that the local android-activity/Cargo.toml version matches +# the android-activity version that Winit depends on (in case you need to check +# out a release branch locally to be compatible) +#android-activity = { path = "../../android-activity" } [features] default = [] diff --git a/examples/na-mainloop/src/lib.rs b/examples/na-mainloop/src/lib.rs index c45f186..ef8e4cc 100644 --- a/examples/na-mainloop/src/lib.rs +++ b/examples/na-mainloop/src/lib.rs @@ -1,4 +1,4 @@ -use android_activity::{AndroidApp, MainEvent, PollEvent}; +use android_activity::{AndroidApp, MainEvent, PollEvent, InputStatus}; use log::info; #[no_mangle] @@ -71,6 +71,7 @@ fn android_main(app: AndroidApp) { // Handle input app.input_events(|event| { info!("Input Event: {event:?}"); + InputStatus::Unhandled }); info!("Render..."); diff --git a/examples/na-subclass-jni/src/lib.rs b/examples/na-subclass-jni/src/lib.rs index 95fcca3..748249c 100644 --- a/examples/na-subclass-jni/src/lib.rs +++ b/examples/na-subclass-jni/src/lib.rs @@ -1,4 +1,4 @@ -use android_activity::{AndroidApp, MainEvent, PollEvent}; +use android_activity::{AndroidApp, MainEvent, PollEvent, InputStatus}; use log::Level; use log::{info, trace}; use serde::{Deserialize, Serialize}; @@ -77,6 +77,7 @@ fn android_main(app: AndroidApp) { // Handle input app.input_events(|event| { info!("Input Event: {event:?}"); + InputStatus::Unhandled }); // Render... diff --git a/examples/na-winit-wgpu/Cargo.lock b/examples/na-winit-wgpu/Cargo.lock index 1cae06a..bf89815 100644 --- a/examples/na-winit-wgpu/Cargo.lock +++ b/examples/na-winit-wgpu/Cargo.lock @@ -47,6 +47,8 @@ dependencies = [ [[package]] name = "android-activity" version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe057899cd59c5254279b74382bf8132d683f8619ea50592c096710d65d03902" dependencies = [ "android-properties", "bitflags", diff --git a/examples/na-winit-wgpu/Cargo.toml b/examples/na-winit-wgpu/Cargo.toml index cf29ef6..d778f68 100644 --- a/examples/na-winit-wgpu/Cargo.toml +++ b/examples/na-winit-wgpu/Cargo.toml @@ -34,10 +34,17 @@ winit = { git = "https://github.com/rib/winit", branch = "android-activity-0.27" # entrypoint for a native Rust application there can only be a single # implementation of the crate linked with the application. # -# Since Winit also depends on android-activity (version = "0.2") but we'd like -# to build against the local version of android-activity in this repo then we -# use a [patch] to ensure we only end up with a single implementation. -android-activity = { path="../../android-activity" } +# By default the Winit-based examples use released versions of android-activity +# to help keep the version in sync with the Winit backend. +# +# If you'd like to build this example against the local checkout of +# android-activity you should specify a patch here to make sure you also affect +# the version that Winit uses. +# +# Note: also check that the local android-activity/Cargo.toml version matches +# the android-activity version that Winit depends on (in case you need to check +# out a release branch locally to be compatible) +#android-activity = { path = "../../android-activity" } [features] default = []