android_ndk/
android_app.rs1use crate::configuration::Configuration;
7use crate::input_queue::InputQueue;
8use crate::looper::ForeignLooper;
9use crate::native_activity::NativeActivity;
10
11use num_enum::{IntoPrimitive, TryFromPrimitive};
12use std::convert::TryInto;
13use std::fmt;
14use std::marker::PhantomData;
15use std::mem::ManuallyDrop;
16use std::ops::Deref;
17use std::ptr::NonNull;
18
19#[derive(Debug)]
21pub struct AndroidApp {
22 ptr: NonNull<ffi::native_app_glue::android_app>,
23}
24
25unsafe impl Send for AndroidApp {}
27unsafe impl Sync for AndroidApp {}
28
29impl AndroidApp {
31 pub unsafe fn from_ptr(ptr: NonNull<ffi::native_app_glue::android_app>) -> Self {
32 Self { ptr }
33 }
34
35 pub fn ptr(&self) -> NonNull<ffi::native_app_glue::android_app> {
36 self.ptr
37 }
38
39 pub fn activity(&self) -> NativeActivity {
41 unsafe { NativeActivity::from_ptr(NonNull::new(self.ptr.as_ref().activity).unwrap()) }
42 }
43
44 pub fn input_queue(&self) -> Ref<'_, InputQueue> {
45 unsafe {
46 Ref::new(InputQueue::from_ptr(
47 NonNull::new(self.ptr.as_ref().inputQueue).unwrap(),
48 ))
49 }
50 }
51
52 pub fn config(&self) -> Ref<'_, Configuration> {
53 unsafe {
54 Ref::new(Configuration::from_ptr(
55 NonNull::new(self.ptr.as_ref().config).unwrap(),
56 ))
57 }
58 }
59
60 fn read_cmd(&mut self) -> Cmd {
62 unsafe {
63 ffi::native_app_glue::android_app_read_cmd(self.ptr.as_ptr())
64 .try_into()
65 .unwrap()
66 }
67 }
68
69 fn pre_exec(&mut self, cmd: Cmd) {
71 unsafe {
72 ffi::native_app_glue::android_app_pre_exec_cmd(self.ptr.as_ptr(), cmd.into());
73 }
74 }
75
76 fn post_exec(&mut self, cmd: Cmd) {
78 unsafe {
79 ffi::native_app_glue::android_app_post_exec_cmd(self.ptr.as_ptr(), cmd.into());
80 }
81 }
82
83 pub fn handle_cmd<T>(&mut self, f: impl FnOnce(&mut Self, Cmd) -> T) -> T {
84 let cmd = self.read_cmd();
85 self.pre_exec(cmd);
86 let res = f(self, cmd);
87 self.post_exec(cmd);
88 res
89 }
90
91 pub fn saved_state(&self) -> Option<&[u8]> {
92 unsafe {
93 let ptr = self.ptr.as_ref().savedState;
94 if ptr.is_null() {
95 None
96 } else {
97 Some(std::slice::from_raw_parts(
98 ptr as *mut u8,
99 self.ptr.as_ref().savedStateSize,
100 ))
101 }
102 }
103 }
104
105 pub fn content_rect(&self) -> ffi::ARect {
106 unsafe { self.ptr.as_ref().contentRect }
107 }
108
109 pub fn looper(&self) -> ForeignLooper {
111 unsafe { ForeignLooper::from_ptr(NonNull::new(self.ptr.as_ref().looper).unwrap()) }
112 }
113
114 }
116
117#[derive(Debug, Clone, Copy, PartialEq, Eq, TryFromPrimitive, IntoPrimitive)]
121#[repr(i8)]
122pub enum Cmd {
123 InputChanged = ffi::native_app_glue::APP_CMD_INPUT_CHANGED,
124 InitWindow = ffi::native_app_glue::APP_CMD_INIT_WINDOW,
125 TermWindow = ffi::native_app_glue::APP_CMD_TERM_WINDOW,
126 WindowResized = ffi::native_app_glue::APP_CMD_WINDOW_RESIZED,
127 WindowRedrawNeeded = ffi::native_app_glue::APP_CMD_WINDOW_REDRAW_NEEDED,
128 ContentRectChanged = ffi::native_app_glue::APP_CMD_CONTENT_RECT_CHANGED,
129 GainedFocus = ffi::native_app_glue::APP_CMD_GAINED_FOCUS,
130 LostFocus = ffi::native_app_glue::APP_CMD_LOST_FOCUS,
131 ConfigChanged = ffi::native_app_glue::APP_CMD_CONFIG_CHANGED,
132 LowMemory = ffi::native_app_glue::APP_CMD_LOW_MEMORY,
133 Start = ffi::native_app_glue::APP_CMD_START,
134 Resume = ffi::native_app_glue::APP_CMD_RESUME,
135 SaveState = ffi::native_app_glue::APP_CMD_SAVE_STATE,
136 Pause = ffi::native_app_glue::APP_CMD_PAUSE,
137 Stop = ffi::native_app_glue::APP_CMD_STOP,
138 Destroy = ffi::native_app_glue::APP_CMD_DESTROY,
139}
140
141pub struct Ref<'a, T> {
145 _marker: PhantomData<&'a T>,
146 data: ManuallyDrop<T>,
147}
148
149impl<'a, T: fmt::Debug> fmt::Debug for Ref<'a, T> {
150 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
151 write!(f, "Ref {{ {:?} }}", &*self)
152 }
153}
154
155impl<'a, T> Deref for Ref<'a, T> {
156 type Target = T;
157
158 fn deref(&self) -> &T {
159 &*self.data
160 }
161}
162
163impl<'a, T> Ref<'a, T> {
164 fn new(data: T) -> Self {
165 Self {
166 _marker: PhantomData,
167 data: ManuallyDrop::new(data),
168 }
169 }
170}