1 #![cfg(target_os = "android")] 2 3 extern crate android_glue; 4 5 mod ffi; 6 7 use std::cell::RefCell; 8 use std::collections::VecDeque; 9 use std::fmt; 10 use std::os::raw::c_void; 11 use std::sync::mpsc::{Receiver, channel}; 12 13 use { 14 CreationError, 15 Event, 16 LogicalPosition, 17 LogicalSize, 18 MouseCursor, 19 PhysicalPosition, 20 PhysicalSize, 21 WindowAttributes, 22 WindowEvent, 23 WindowId as RootWindowId, 24 }; 25 use CreationError::OsError; 26 use events::{Touch, TouchPhase}; 27 use window::MonitorId as RootMonitorId; 28 29 pub struct EventsLoop { 30 event_rx: Receiver<android_glue::Event>, 31 suspend_callback: RefCell<Option<Box<Fn(bool) -> ()>>>, 32 } 33 34 #[derive(Clone)] 35 pub struct EventsLoopProxy; 36 37 impl EventsLoop { new() -> EventsLoop38 pub fn new() -> EventsLoop { 39 let (tx, rx) = channel(); 40 android_glue::add_sender(tx); 41 EventsLoop { 42 event_rx: rx, 43 suspend_callback: Default::default(), 44 } 45 } 46 47 #[inline] get_available_monitors(&self) -> VecDeque<MonitorId>48 pub fn get_available_monitors(&self) -> VecDeque<MonitorId> { 49 let mut rb = VecDeque::with_capacity(1); 50 rb.push_back(MonitorId); 51 rb 52 } 53 54 #[inline] get_primary_monitor(&self) -> MonitorId55 pub fn get_primary_monitor(&self) -> MonitorId { 56 MonitorId 57 } 58 poll_events<F>(&mut self, mut callback: F) where F: FnMut(::Event)59 pub fn poll_events<F>(&mut self, mut callback: F) 60 where F: FnMut(::Event) 61 { 62 while let Ok(event) = self.event_rx.try_recv() { 63 let e = match event{ 64 android_glue::Event::EventMotion(motion) => { 65 let dpi_factor = MonitorId.get_hidpi_factor(); 66 let location = LogicalPosition::from_physical( 67 (motion.x as f64, motion.y as f64), 68 dpi_factor, 69 ); 70 Some(Event::WindowEvent { 71 window_id: RootWindowId(WindowId), 72 event: WindowEvent::Touch(Touch { 73 phase: match motion.action { 74 android_glue::MotionAction::Down => TouchPhase::Started, 75 android_glue::MotionAction::Move => TouchPhase::Moved, 76 android_glue::MotionAction::Up => TouchPhase::Ended, 77 android_glue::MotionAction::Cancel => TouchPhase::Cancelled, 78 }, 79 location, 80 id: motion.pointer_id as u64, 81 device_id: DEVICE_ID, 82 }), 83 }) 84 }, 85 android_glue::Event::InitWindow => { 86 // The activity went to foreground. 87 if let Some(cb) = self.suspend_callback.borrow().as_ref() { 88 (*cb)(false); 89 } 90 Some(Event::Suspended(false)) 91 }, 92 android_glue::Event::TermWindow => { 93 // The activity went to background. 94 if let Some(cb) = self.suspend_callback.borrow().as_ref() { 95 (*cb)(true); 96 } 97 Some(Event::Suspended(true)) 98 }, 99 android_glue::Event::WindowResized | 100 android_glue::Event::ConfigChanged => { 101 // Activity Orientation changed or resized. 102 let native_window = unsafe { android_glue::get_native_window() }; 103 if native_window.is_null() { 104 None 105 } else { 106 let dpi_factor = MonitorId.get_hidpi_factor(); 107 let physical_size = MonitorId.get_dimensions(); 108 let size = LogicalSize::from_physical(physical_size, dpi_factor); 109 Some(Event::WindowEvent { 110 window_id: RootWindowId(WindowId), 111 event: WindowEvent::Resized(size), 112 }) 113 } 114 }, 115 android_glue::Event::WindowRedrawNeeded => { 116 // The activity needs to be redrawn. 117 Some(Event::WindowEvent { 118 window_id: RootWindowId(WindowId), 119 event: WindowEvent::Refresh, 120 }) 121 } 122 android_glue::Event::Wake => { 123 Some(Event::Awakened) 124 } 125 _ => { 126 None 127 } 128 }; 129 130 if let Some(event) = e { 131 callback(event); 132 } 133 }; 134 } 135 set_suspend_callback(&self, cb: Option<Box<Fn(bool) -> ()>>)136 pub fn set_suspend_callback(&self, cb: Option<Box<Fn(bool) -> ()>>) { 137 *self.suspend_callback.borrow_mut() = cb; 138 } 139 run_forever<F>(&mut self, mut callback: F) where F: FnMut(::Event) -> ::ControlFlow,140 pub fn run_forever<F>(&mut self, mut callback: F) 141 where F: FnMut(::Event) -> ::ControlFlow, 142 { 143 // Yeah that's a very bad implementation. 144 loop { 145 let mut control_flow = ::ControlFlow::Continue; 146 self.poll_events(|e| { 147 if let ::ControlFlow::Break = callback(e) { 148 control_flow = ::ControlFlow::Break; 149 } 150 }); 151 if let ::ControlFlow::Break = control_flow { 152 break; 153 } 154 ::std::thread::sleep(::std::time::Duration::from_millis(5)); 155 } 156 } 157 create_proxy(&self) -> EventsLoopProxy158 pub fn create_proxy(&self) -> EventsLoopProxy { 159 EventsLoopProxy 160 } 161 } 162 163 impl EventsLoopProxy { wakeup(&self) -> Result<(), ::EventsLoopClosed>164 pub fn wakeup(&self) -> Result<(), ::EventsLoopClosed> { 165 android_glue::wake_event_loop(); 166 Ok(()) 167 } 168 } 169 170 #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] 171 pub struct WindowId; 172 173 impl WindowId { dummy() -> Self174 pub unsafe fn dummy() -> Self { 175 WindowId 176 } 177 } 178 179 #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] 180 pub struct DeviceId; 181 182 impl DeviceId { dummy() -> Self183 pub unsafe fn dummy() -> Self { 184 DeviceId 185 } 186 } 187 188 pub struct Window { 189 native_window: *const c_void, 190 } 191 192 #[derive(Clone)] 193 pub struct MonitorId; 194 195 impl fmt::Debug for MonitorId { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result196 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 197 #[derive(Debug)] 198 struct MonitorId { 199 name: Option<String>, 200 dimensions: PhysicalSize, 201 position: PhysicalPosition, 202 hidpi_factor: f64, 203 } 204 205 let monitor_id_proxy = MonitorId { 206 name: self.get_name(), 207 dimensions: self.get_dimensions(), 208 position: self.get_position(), 209 hidpi_factor: self.get_hidpi_factor(), 210 }; 211 212 monitor_id_proxy.fmt(f) 213 } 214 } 215 216 impl MonitorId { 217 #[inline] get_name(&self) -> Option<String>218 pub fn get_name(&self) -> Option<String> { 219 Some("Primary".to_string()) 220 } 221 222 #[inline] get_dimensions(&self) -> PhysicalSize223 pub fn get_dimensions(&self) -> PhysicalSize { 224 unsafe { 225 let window = android_glue::get_native_window(); 226 ( 227 ffi::ANativeWindow_getWidth(window) as f64, 228 ffi::ANativeWindow_getHeight(window) as f64, 229 ).into() 230 } 231 } 232 233 #[inline] get_position(&self) -> PhysicalPosition234 pub fn get_position(&self) -> PhysicalPosition { 235 // Android assumes single screen 236 (0, 0).into() 237 } 238 239 #[inline] get_hidpi_factor(&self) -> f64240 pub fn get_hidpi_factor(&self) -> f64 { 241 1.0 242 } 243 } 244 245 #[derive(Clone, Default)] 246 pub struct PlatformSpecificWindowBuilderAttributes; 247 #[derive(Clone, Default)] 248 pub struct PlatformSpecificHeadlessBuilderAttributes; 249 250 impl Window { new(_: &EventsLoop, win_attribs: WindowAttributes, _: PlatformSpecificWindowBuilderAttributes) -> Result<Window, CreationError>251 pub fn new(_: &EventsLoop, win_attribs: WindowAttributes, 252 _: PlatformSpecificWindowBuilderAttributes) 253 -> Result<Window, CreationError> 254 { 255 let native_window = unsafe { android_glue::get_native_window() }; 256 if native_window.is_null() { 257 return Err(OsError(format!("Android's native window is null"))); 258 } 259 260 android_glue::set_multitouch(win_attribs.multitouch); 261 262 Ok(Window { 263 native_window: native_window as *const _, 264 }) 265 } 266 267 #[inline] get_native_window(&self) -> *const c_void268 pub fn get_native_window(&self) -> *const c_void { 269 self.native_window 270 } 271 272 #[inline] set_title(&self, _: &str)273 pub fn set_title(&self, _: &str) { 274 // N/A 275 } 276 277 #[inline] show(&self)278 pub fn show(&self) { 279 // N/A 280 } 281 282 #[inline] hide(&self)283 pub fn hide(&self) { 284 // N/A 285 } 286 287 #[inline] get_position(&self) -> Option<LogicalPosition>288 pub fn get_position(&self) -> Option<LogicalPosition> { 289 // N/A 290 None 291 } 292 293 #[inline] get_inner_position(&self) -> Option<LogicalPosition>294 pub fn get_inner_position(&self) -> Option<LogicalPosition> { 295 // N/A 296 None 297 } 298 299 #[inline] set_position(&self, _position: LogicalPosition)300 pub fn set_position(&self, _position: LogicalPosition) { 301 // N/A 302 } 303 304 #[inline] set_min_dimensions(&self, _dimensions: Option<LogicalSize>)305 pub fn set_min_dimensions(&self, _dimensions: Option<LogicalSize>) { 306 // N/A 307 } 308 309 #[inline] set_max_dimensions(&self, _dimensions: Option<LogicalSize>)310 pub fn set_max_dimensions(&self, _dimensions: Option<LogicalSize>) { 311 // N/A 312 } 313 314 #[inline] set_resizable(&self, _resizable: bool)315 pub fn set_resizable(&self, _resizable: bool) { 316 // N/A 317 } 318 319 #[inline] get_inner_size(&self) -> Option<LogicalSize>320 pub fn get_inner_size(&self) -> Option<LogicalSize> { 321 if self.native_window.is_null() { 322 None 323 } else { 324 let dpi_factor = self.get_hidpi_factor(); 325 let physical_size = self.get_current_monitor().get_dimensions(); 326 Some(LogicalSize::from_physical(physical_size, dpi_factor)) 327 } 328 } 329 330 #[inline] get_outer_size(&self) -> Option<LogicalSize>331 pub fn get_outer_size(&self) -> Option<LogicalSize> { 332 self.get_inner_size() 333 } 334 335 #[inline] set_inner_size(&self, _size: LogicalSize)336 pub fn set_inner_size(&self, _size: LogicalSize) { 337 // N/A 338 } 339 340 #[inline] get_hidpi_factor(&self) -> f64341 pub fn get_hidpi_factor(&self) -> f64 { 342 self.get_current_monitor().get_hidpi_factor() 343 } 344 345 #[inline] set_cursor(&self, _: MouseCursor)346 pub fn set_cursor(&self, _: MouseCursor) { 347 // N/A 348 } 349 350 #[inline] grab_cursor(&self, _grab: bool) -> Result<(), String>351 pub fn grab_cursor(&self, _grab: bool) -> Result<(), String> { 352 Err("Cursor grabbing is not possible on Android.".to_owned()) 353 } 354 355 #[inline] hide_cursor(&self, _hide: bool)356 pub fn hide_cursor(&self, _hide: bool) { 357 // N/A 358 } 359 360 #[inline] set_cursor_position(&self, _position: LogicalPosition) -> Result<(), String>361 pub fn set_cursor_position(&self, _position: LogicalPosition) -> Result<(), String> { 362 Err("Setting cursor position is not possible on Android.".to_owned()) 363 } 364 365 #[inline] set_maximized(&self, _maximized: bool)366 pub fn set_maximized(&self, _maximized: bool) { 367 // N/A 368 // Android has single screen maximized apps so nothing to do 369 } 370 371 #[inline] set_fullscreen(&self, _monitor: Option<RootMonitorId>)372 pub fn set_fullscreen(&self, _monitor: Option<RootMonitorId>) { 373 // N/A 374 // Android has single screen maximized apps so nothing to do 375 } 376 377 #[inline] set_decorations(&self, _decorations: bool)378 pub fn set_decorations(&self, _decorations: bool) { 379 // N/A 380 } 381 382 #[inline] set_always_on_top(&self, _always_on_top: bool)383 pub fn set_always_on_top(&self, _always_on_top: bool) { 384 // N/A 385 } 386 387 #[inline] set_window_icon(&self, _icon: Option<::Icon>)388 pub fn set_window_icon(&self, _icon: Option<::Icon>) { 389 // N/A 390 } 391 392 #[inline] set_ime_spot(&self, _spot: LogicalPosition)393 pub fn set_ime_spot(&self, _spot: LogicalPosition) { 394 // N/A 395 } 396 397 #[inline] get_current_monitor(&self) -> RootMonitorId398 pub fn get_current_monitor(&self) -> RootMonitorId { 399 RootMonitorId { inner: MonitorId } 400 } 401 402 #[inline] get_available_monitors(&self) -> VecDeque<MonitorId>403 pub fn get_available_monitors(&self) -> VecDeque<MonitorId> { 404 let mut rb = VecDeque::with_capacity(1); 405 rb.push_back(MonitorId); 406 rb 407 } 408 409 #[inline] get_primary_monitor(&self) -> MonitorId410 pub fn get_primary_monitor(&self) -> MonitorId { 411 MonitorId 412 } 413 414 #[inline] id(&self) -> WindowId415 pub fn id(&self) -> WindowId { 416 WindowId 417 } 418 } 419 420 unsafe impl Send for Window {} 421 unsafe impl Sync for Window {} 422 423 // Constant device ID, to be removed when this backend is updated to report real device IDs. 424 const DEVICE_ID: ::DeviceId = ::DeviceId(DeviceId); 425