From c0ec2547148e49fc7d071084e30043c4159f08ad Mon Sep 17 00:00:00 2001 From: David Craven Date: Sun, 9 Feb 2020 20:49:01 +0100 Subject: [PATCH] Add android-glue. --- Cargo.toml | 2 +- android-glue/Cargo.toml | 14 +++ android-glue/src/lib.rs | 225 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 240 insertions(+), 1 deletion(-) create mode 100644 android-glue/Cargo.toml create mode 100644 android-glue/src/lib.rs diff --git a/Cargo.toml b/Cargo.toml index aa152d79..53b09b55 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [workspace] - members = [ + "android-glue", "android-ndk-sys", "android-ndk", ] diff --git a/android-glue/Cargo.toml b/android-glue/Cargo.toml new file mode 100644 index 00000000..db679590 --- /dev/null +++ b/android-glue/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "android-glue" +version = "0.1.0" +authors = ["David Craven "] +edition = "2018" + +[dependencies] +android_logger = "0.8.6" +android-ndk-sys = { path = "../android-ndk-sys", default-features = false } +android-ndk = { path = "../android-ndk", default-features = false } +crossbeam = "0.7.3" +lazy_static = "1.4.0" +libc = "0.2.66" +log = "0.4.8" diff --git a/android-glue/src/lib.rs b/android-glue/src/lib.rs new file mode 100644 index 00000000..245e0da4 --- /dev/null +++ b/android-glue/src/lib.rs @@ -0,0 +1,225 @@ +use android_logger::Config; +use android_ndk::input_queue::InputQueue; +use android_ndk::native_activity::NativeActivity; +use android_ndk::native_window::NativeWindow; +use android_ndk_sys::{AInputQueue, ANativeActivity, ANativeWindow, ARect}; +use crossbeam::queue::SegQueue; +use lazy_static::lazy_static; +use log::Level; +use std::fs::File; +use std::io::{BufRead, BufReader}; +use std::os::raw; +use std::os::unix::prelude::*; +use std::ptr::NonNull; +use std::sync::Mutex; +use std::thread; + +lazy_static! { + static ref NATIVE_WINDOW: Mutex> = Default::default(); + static ref INPUT_QUEUE: Mutex> = Default::default(); + static ref EVENT_QUEUE: SegQueue = Default::default(); +} + +static mut NATIVE_ACTIVITY: Option = None; + +pub fn native_activity() -> &'static NativeActivity { + unsafe { NATIVE_ACTIVITY.as_ref().unwrap() } +} + +pub fn native_window() -> &'static Mutex> { + &NATIVE_WINDOW +} + +pub fn input_queue() -> &'static Mutex> { + &INPUT_QUEUE +} + +pub fn poll_events() -> Option { + EVENT_QUEUE.pop().ok() +} + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum Event { + Start, + Resume, + //SaveInstanceState, + Pause, + Stop, + Destroy, + ConfigChanged, + LowMemory, + WindowFocusChanged, + WindowCreated, + WindowResized, + WindowRedrawNeeded, + WindowDestroyed, + InputQueueCreated, + InputQueueDestroyed, + ContentRectChanged, +} + +pub unsafe fn init( + activity: *mut ANativeActivity, + _saved_state: *mut u8, + _saved_state_size: usize, + main: fn(), +) { + let mut activity = NonNull::new(activity).unwrap(); + let mut callbacks = activity.as_mut().callbacks.as_mut().unwrap(); + callbacks.onStart = Some(on_start); + callbacks.onResume = Some(on_resume); + callbacks.onSaveInstanceState = Some(on_save_instance_state); + callbacks.onPause = Some(on_pause); + callbacks.onStop = Some(on_stop); + callbacks.onDestroy = Some(on_destroy); + callbacks.onWindowFocusChanged = Some(on_window_focus_changed); + callbacks.onNativeWindowCreated = Some(on_window_created); + callbacks.onNativeWindowResized = Some(on_window_resized); + callbacks.onNativeWindowRedrawNeeded = Some(on_window_redraw_needed); + callbacks.onNativeWindowDestroyed = Some(on_window_destroyed); + callbacks.onInputQueueCreated = Some(on_input_queue_created); + callbacks.onInputQueueDestroyed = Some(on_input_queue_destroyed); + callbacks.onContentRectChanged = Some(on_content_rect_changed); + callbacks.onConfigurationChanged = Some(on_configuration_changed); + callbacks.onLowMemory = Some(on_low_memory); + let activity = NativeActivity::from_ptr(activity); + NATIVE_ACTIVITY = Some(activity); + + let mut logpipe: [RawFd; 2] = Default::default(); + libc::pipe(logpipe.as_mut_ptr()); + libc::dup2(logpipe[1], libc::STDOUT_FILENO); + libc::dup2(logpipe[1], libc::STDERR_FILENO); + thread::spawn(move || { + android_logger::init_once( + Config::default() + .with_min_level(Level::Trace) + .with_tag("RustStdoutStderr"), + ); + let file = File::from_raw_fd(logpipe[0]); + let mut reader = BufReader::new(file); + let mut buffer = String::new(); + loop { + buffer.clear(); + if let Ok(len) = reader.read_line(&mut buffer) { + if len == 0 { + break; + } else { + log::info!("{}", buffer); + } + } + } + }); + + thread::spawn(main); +} + +unsafe extern "C" fn on_start(_activity: *mut ANativeActivity) { + log::trace!("on_start"); + EVENT_QUEUE.push(Event::Start); +} + +unsafe extern "C" fn on_resume(_activity: *mut ANativeActivity) { + log::trace!("on_resume"); + EVENT_QUEUE.push(Event::Resume); +} + +unsafe extern "C" fn on_save_instance_state( + _activity: *mut ANativeActivity, + _out_size: *mut usize, +) -> *mut raw::c_void { + log::trace!("on_save_instance_state"); + // TODO + //EVENT_QUEUE.push(Event::Resume); + std::ptr::null_mut() +} + +unsafe extern "C" fn on_pause(_activity: *mut ANativeActivity) { + log::trace!("on_pause"); + EVENT_QUEUE.push(Event::Pause); +} + +unsafe extern "C" fn on_stop(_activity: *mut ANativeActivity) { + log::trace!("on_stop"); + EVENT_QUEUE.push(Event::Stop); +} + +unsafe extern "C" fn on_destroy(_activity: *mut ANativeActivity) { + log::trace!("on_destroy"); + EVENT_QUEUE.push(Event::Destroy); +} + +unsafe extern "C" fn on_configuration_changed(_activity: *mut ANativeActivity) { + log::trace!("on_configuration_changed"); + EVENT_QUEUE.push(Event::ConfigChanged); +} + +unsafe extern "C" fn on_low_memory(_activity: *mut ANativeActivity) { + log::trace!("on_low_memory"); + EVENT_QUEUE.push(Event::LowMemory); +} + +unsafe extern "C" fn on_window_focus_changed( + _activity: *mut ANativeActivity, + _has_focus: raw::c_int, +) { + log::trace!("on_window_focus_changed"); + EVENT_QUEUE.push(Event::WindowFocusChanged); +} + +unsafe extern "C" fn on_window_created( + _activity: *mut ANativeActivity, + window: *mut ANativeWindow, +) { + log::trace!("on_window_created"); + *NATIVE_WINDOW.lock().unwrap() = Some(NativeWindow::from_ptr(NonNull::new(window).unwrap())); + EVENT_QUEUE.push(Event::WindowCreated); +} + +unsafe extern "C" fn on_window_resized( + _activity: *mut ANativeActivity, + _window: *mut ANativeWindow, +) { + log::trace!("on_window_resized"); + EVENT_QUEUE.push(Event::WindowResized); +} + +unsafe extern "C" fn on_window_redraw_needed( + _activity: *mut ANativeActivity, + _window: *mut ANativeWindow, +) { + log::trace!("on_window_redraw_needed"); + EVENT_QUEUE.push(Event::WindowRedrawNeeded); +} + +unsafe extern "C" fn on_window_destroyed( + _activity: *mut ANativeActivity, + _window: *mut ANativeWindow, +) { + log::trace!("on_window_destroyed"); + EVENT_QUEUE.push(Event::WindowDestroyed); + *NATIVE_WINDOW.lock().unwrap() = None; +} + +unsafe extern "C" fn on_input_queue_created( + _activity: *mut ANativeActivity, + queue: *mut AInputQueue, +) { + log::trace!("on_input_queue_created"); + *INPUT_QUEUE.lock().unwrap() = Some(InputQueue::from_ptr(NonNull::new(queue).unwrap())); + EVENT_QUEUE.push(Event::InputQueueCreated); +} + +unsafe extern "C" fn on_input_queue_destroyed( + _activity: *mut ANativeActivity, + _queue: *mut AInputQueue, +) { + log::trace!("on_input_queue_destroyed"); + EVENT_QUEUE.push(Event::InputQueueDestroyed); + *INPUT_QUEUE.lock().unwrap() = None; +} + +unsafe extern "C" fn on_content_rect_changed(_activity: *mut ANativeActivity, _rect: *const ARect) { + log::trace!("on_content_rect_changed"); + EVENT_QUEUE.push(Event::ContentRectChanged); + // TODO +}