Skip to content

Commit f1772bc

Browse files
committed
Android glue.
1 parent 52c80a6 commit f1772bc

File tree

3 files changed

+292
-1
lines changed

3 files changed

+292
-1
lines changed

Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[workspace]
2-
32
members = [
3+
"android-glue",
44
"android-ndk-sys",
55
"android-ndk",
66
]

android-glue/Cargo.toml

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
[package]
2+
name = "android-glue"
3+
version = "0.1.0"
4+
authors = ["David Craven <[email protected]>"]
5+
edition = "2018"
6+
7+
[dependencies]
8+
android_log-sys = "0.1.2"
9+
android-ndk-sys = { path = "../android-ndk-sys" }
10+
android-ndk = { path = "../android-ndk" }
11+
lazy_static = "1.4.0"
12+
libc = "0.2.66"
13+
log = "0.4.8"

android-glue/src/lib.rs

+278
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,278 @@
1+
use android_ndk::input_queue::InputQueue;
2+
use android_ndk::looper::ThreadLooper;
3+
use android_ndk::native_activity::NativeActivity;
4+
use android_ndk::native_window::NativeWindow;
5+
use android_ndk_sys::{AInputQueue, ANativeActivity, ANativeWindow, ARect, ALOOPER_EVENT_INPUT};
6+
use lazy_static::lazy_static;
7+
use log::Level;
8+
use std::ffi::{CStr, CString};
9+
use std::fs::File;
10+
use std::io::{BufRead, BufReader};
11+
use std::os::raw;
12+
use std::os::unix::prelude::*;
13+
use std::ptr::NonNull;
14+
use std::sync::RwLock;
15+
use std::thread;
16+
17+
pub fn android_log(level: Level, tag: &CStr, msg: &CStr) {
18+
use android_log_sys::LogPriority;
19+
let prio = match level {
20+
Level::Error => LogPriority::ERROR,
21+
Level::Warn => LogPriority::WARN,
22+
Level::Info => LogPriority::INFO,
23+
Level::Debug => LogPriority::DEBUG,
24+
Level::Trace => LogPriority::VERBOSE,
25+
};
26+
unsafe {
27+
android_log_sys::__android_log_write(
28+
prio as _,
29+
tag.as_ptr() as *const _,
30+
msg.as_ptr() as *const _,
31+
);
32+
}
33+
}
34+
35+
lazy_static! {
36+
static ref NATIVE_WINDOW: RwLock<Option<NativeWindow>> = Default::default();
37+
static ref INPUT_QUEUE: RwLock<Option<InputQueue>> = Default::default();
38+
static ref CONTENT_RECT: RwLock<Rect> = Default::default();
39+
}
40+
41+
static mut NATIVE_ACTIVITY: Option<NativeActivity> = None;
42+
43+
pub fn native_activity() -> &'static NativeActivity {
44+
unsafe { NATIVE_ACTIVITY.as_ref().unwrap() }
45+
}
46+
47+
pub fn native_window() -> &'static RwLock<Option<NativeWindow>> {
48+
&NATIVE_WINDOW
49+
}
50+
51+
pub fn input_queue() -> &'static RwLock<Option<InputQueue>> {
52+
&INPUT_QUEUE
53+
}
54+
55+
pub fn content_rect() -> Rect {
56+
CONTENT_RECT.read().unwrap().clone()
57+
}
58+
59+
lazy_static! {
60+
static ref PIPE: [RawFd; 2] = {
61+
let mut pipe: [RawFd; 2] = Default::default();
62+
unsafe { libc::pipe(pipe.as_mut_ptr()) };
63+
pipe
64+
};
65+
}
66+
67+
pub fn poll_events() -> Option<Event> {
68+
unsafe {
69+
let size = std::mem::size_of::<Event>();
70+
let mut event = Event::Start;
71+
if libc::read(PIPE[0], &mut event as *mut _ as *mut _, size) == size as _ {
72+
Some(event)
73+
} else {
74+
None
75+
}
76+
}
77+
}
78+
79+
unsafe fn wake(_activity: *mut ANativeActivity, event: Event) {
80+
log::trace!("{:?}", event);
81+
let size = std::mem::size_of::<Event>();
82+
let res = libc::write(PIPE[1], &event as *const _ as *const _, size);
83+
assert_eq!(res, size as _);
84+
}
85+
86+
#[derive(Clone, Debug, Default, Eq, PartialEq)]
87+
pub struct Rect {
88+
pub left: u32,
89+
pub top: u32,
90+
pub right: u32,
91+
pub bottom: u32,
92+
}
93+
94+
#[derive(Clone, Debug, Eq, PartialEq)]
95+
#[repr(u8)]
96+
pub enum Event {
97+
Start,
98+
Resume,
99+
SaveInstanceState,
100+
Pause,
101+
Stop,
102+
Destroy,
103+
ConfigChanged,
104+
LowMemory,
105+
WindowLostFocus,
106+
WindowHasFocus,
107+
WindowCreated,
108+
WindowResized,
109+
WindowRedrawNeeded,
110+
WindowDestroyed,
111+
InputQueueCreated,
112+
InputQueueDestroyed,
113+
ContentRectChanged,
114+
}
115+
116+
pub unsafe fn init(
117+
activity: *mut ANativeActivity,
118+
_saved_state: *mut u8,
119+
_saved_state_size: usize,
120+
main: fn(),
121+
) {
122+
let mut activity = NonNull::new(activity).unwrap();
123+
let mut callbacks = activity.as_mut().callbacks.as_mut().unwrap();
124+
callbacks.onStart = Some(on_start);
125+
callbacks.onResume = Some(on_resume);
126+
callbacks.onSaveInstanceState = Some(on_save_instance_state);
127+
callbacks.onPause = Some(on_pause);
128+
callbacks.onStop = Some(on_stop);
129+
callbacks.onDestroy = Some(on_destroy);
130+
callbacks.onWindowFocusChanged = Some(on_window_focus_changed);
131+
callbacks.onNativeWindowCreated = Some(on_window_created);
132+
callbacks.onNativeWindowResized = Some(on_window_resized);
133+
callbacks.onNativeWindowRedrawNeeded = Some(on_window_redraw_needed);
134+
callbacks.onNativeWindowDestroyed = Some(on_window_destroyed);
135+
callbacks.onInputQueueCreated = Some(on_input_queue_created);
136+
callbacks.onInputQueueDestroyed = Some(on_input_queue_destroyed);
137+
callbacks.onContentRectChanged = Some(on_content_rect_changed);
138+
callbacks.onConfigurationChanged = Some(on_configuration_changed);
139+
callbacks.onLowMemory = Some(on_low_memory);
140+
141+
let activity = NativeActivity::from_ptr(activity);
142+
NATIVE_ACTIVITY = Some(activity);
143+
144+
let mut logpipe: [RawFd; 2] = Default::default();
145+
libc::pipe(logpipe.as_mut_ptr());
146+
libc::dup2(logpipe[1], libc::STDOUT_FILENO);
147+
libc::dup2(logpipe[1], libc::STDERR_FILENO);
148+
thread::spawn(move || {
149+
let tag = CStr::from_bytes_with_nul(b"RustStdoutStderr\0").unwrap();
150+
let file = File::from_raw_fd(logpipe[0]);
151+
let mut reader = BufReader::new(file);
152+
let mut buffer = String::new();
153+
loop {
154+
buffer.clear();
155+
if let Ok(len) = reader.read_line(&mut buffer) {
156+
if len == 0 {
157+
break;
158+
} else {
159+
if let Ok(msg) = CString::new(buffer.clone()) {
160+
android_log(Level::Info, tag, &msg);
161+
}
162+
}
163+
}
164+
}
165+
});
166+
167+
thread::spawn(move || {
168+
let looper = ThreadLooper::prepare();
169+
looper
170+
.as_foreign()
171+
.add_fd(PIPE[0], 0, ALOOPER_EVENT_INPUT as _, 0 as _)
172+
.unwrap();
173+
main()
174+
});
175+
}
176+
177+
unsafe extern "C" fn on_start(activity: *mut ANativeActivity) {
178+
wake(activity, Event::Start);
179+
}
180+
181+
unsafe extern "C" fn on_resume(activity: *mut ANativeActivity) {
182+
wake(activity, Event::Resume);
183+
}
184+
185+
unsafe extern "C" fn on_save_instance_state(
186+
activity: *mut ANativeActivity,
187+
_out_size: *mut usize,
188+
) -> *mut raw::c_void {
189+
// TODO
190+
wake(activity, Event::SaveInstanceState);
191+
std::ptr::null_mut()
192+
}
193+
194+
unsafe extern "C" fn on_pause(activity: *mut ANativeActivity) {
195+
wake(activity, Event::Pause);
196+
}
197+
198+
unsafe extern "C" fn on_stop(activity: *mut ANativeActivity) {
199+
wake(activity, Event::Stop);
200+
}
201+
202+
unsafe extern "C" fn on_destroy(activity: *mut ANativeActivity) {
203+
wake(activity, Event::Destroy);
204+
}
205+
206+
unsafe extern "C" fn on_configuration_changed(activity: *mut ANativeActivity) {
207+
wake(activity, Event::ConfigChanged);
208+
}
209+
210+
unsafe extern "C" fn on_low_memory(activity: *mut ANativeActivity) {
211+
wake(activity, Event::LowMemory);
212+
}
213+
214+
unsafe extern "C" fn on_window_focus_changed(
215+
activity: *mut ANativeActivity,
216+
has_focus: raw::c_int,
217+
) {
218+
let event = if has_focus == 0 {
219+
Event::WindowLostFocus
220+
} else {
221+
Event::WindowHasFocus
222+
};
223+
wake(activity, event);
224+
}
225+
226+
unsafe extern "C" fn on_window_created(activity: *mut ANativeActivity, window: *mut ANativeWindow) {
227+
*NATIVE_WINDOW.write().unwrap() = Some(NativeWindow::from_ptr(NonNull::new(window).unwrap()));
228+
wake(activity, Event::WindowCreated);
229+
}
230+
231+
unsafe extern "C" fn on_window_resized(
232+
activity: *mut ANativeActivity,
233+
_window: *mut ANativeWindow,
234+
) {
235+
wake(activity, Event::WindowResized);
236+
}
237+
238+
unsafe extern "C" fn on_window_redraw_needed(
239+
activity: *mut ANativeActivity,
240+
_window: *mut ANativeWindow,
241+
) {
242+
wake(activity, Event::WindowRedrawNeeded);
243+
}
244+
245+
unsafe extern "C" fn on_window_destroyed(
246+
activity: *mut ANativeActivity,
247+
_window: *mut ANativeWindow,
248+
) {
249+
*NATIVE_WINDOW.write().unwrap() = None;
250+
wake(activity, Event::WindowDestroyed);
251+
}
252+
253+
unsafe extern "C" fn on_input_queue_created(
254+
activity: *mut ANativeActivity,
255+
queue: *mut AInputQueue,
256+
) {
257+
*INPUT_QUEUE.write().unwrap() = Some(InputQueue::from_ptr(NonNull::new(queue).unwrap()));
258+
wake(activity, Event::InputQueueCreated);
259+
}
260+
261+
unsafe extern "C" fn on_input_queue_destroyed(
262+
activity: *mut ANativeActivity,
263+
_queue: *mut AInputQueue,
264+
) {
265+
*INPUT_QUEUE.write().unwrap() = None;
266+
wake(activity, Event::InputQueueDestroyed);
267+
}
268+
269+
unsafe extern "C" fn on_content_rect_changed(activity: *mut ANativeActivity, rect: *const ARect) {
270+
let rect = Rect {
271+
left: (*rect).left as _,
272+
top: (*rect).top as _,
273+
right: (*rect).right as _,
274+
bottom: (*rect).bottom as _,
275+
};
276+
*CONTENT_RECT.write().unwrap() = rect;
277+
wake(activity, Event::ContentRectChanged);
278+
}

0 commit comments

Comments
 (0)