1use std::cell::Cell;
2use std::fmt;
3use std::hash::Hash;
4use std::sync::atomic::{AtomicBool, Ordering};
5use std::sync::{Arc, Mutex};
6use std::time::{Duration, Instant};
7
8use android_activity::input::{InputEvent, KeyAction, Keycode, MotionAction};
9use android_activity::{
10 AndroidApp, AndroidAppWaker, ConfigurationRef, InputStatus, MainEvent, Rect,
11};
12use dpi::{PhysicalInsets, PhysicalPosition, PhysicalSize, Position, Size};
13use tracing::{debug, trace, warn};
14use winit_core::application::ApplicationHandler;
15use winit_core::cursor::{Cursor, CustomCursor, CustomCursorSource};
16use winit_core::error::{EventLoopError, NotSupportedError, RequestError};
17use winit_core::event::{self, DeviceId, FingerId, Force, StartCause, SurfaceSizeWriter};
18use winit_core::event_loop::pump_events::PumpStatus;
19use winit_core::event_loop::{
20 ActiveEventLoop as RootActiveEventLoop, ControlFlow, DeviceEvents,
21 EventLoopProxy as CoreEventLoopProxy, EventLoopProxyProvider,
22 OwnedDisplayHandle as CoreOwnedDisplayHandle,
23};
24use winit_core::monitor::{Fullscreen, MonitorHandle as CoreMonitorHandle};
25use winit_core::window::{
26 self, CursorGrabMode, ImeCapabilities, ImePurpose, ImeRequest, ImeRequestError,
27 ResizeDirection, Theme, Window as CoreWindow, WindowAttributes, WindowButtons, WindowId,
28 WindowLevel,
29};
30
31use crate::keycodes;
32
33static HAS_FOCUS: AtomicBool = AtomicBool::new(true);
34
35fn min_timeout(a: Option<Duration>, b: Option<Duration>) -> Option<Duration> {
39 a.map_or(b, |a_timeout| b.map_or(Some(a_timeout), |b_timeout| Some(a_timeout.min(b_timeout))))
40}
41
42#[derive(Clone, Debug)]
43struct SharedFlagSetter {
44 flag: Arc<AtomicBool>,
45}
46impl SharedFlagSetter {
47 fn set(&self) -> bool {
48 self.flag.compare_exchange(false, true, Ordering::AcqRel, Ordering::Relaxed).is_ok()
49 }
50}
51
52#[derive(Debug)]
53struct SharedFlag {
54 flag: Arc<AtomicBool>,
55}
56
57impl SharedFlag {
62 fn new() -> Self {
63 Self { flag: Arc::new(AtomicBool::new(false)) }
64 }
65
66 fn setter(&self) -> SharedFlagSetter {
67 SharedFlagSetter { flag: self.flag.clone() }
68 }
69
70 fn get_and_reset(&self) -> bool {
71 self.flag.swap(false, std::sync::atomic::Ordering::AcqRel)
72 }
73}
74
75#[derive(Clone)]
76struct RedrawRequester {
77 flag: SharedFlagSetter,
78 waker: AndroidAppWaker,
79}
80
81impl fmt::Debug for RedrawRequester {
82 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
83 f.debug_struct("RedrawRequester").field("flag", &self.flag).finish_non_exhaustive()
84 }
85}
86
87impl RedrawRequester {
88 fn new(flag: &SharedFlag, waker: AndroidAppWaker) -> Self {
89 RedrawRequester { flag: flag.setter(), waker }
90 }
91
92 fn request_redraw(&self) {
93 if self.flag.set() {
94 self.waker.wake();
97 }
98 }
99}
100
101#[derive(Debug)]
102pub struct EventLoop {
103 pub android_app: AndroidApp,
104 window_target: ActiveEventLoop,
105 redraw_flag: SharedFlag,
106 loop_running: bool, running: bool,
108 pending_redraw: bool,
109 cause: StartCause,
110 primary_pointer: Option<FingerId>,
111 ignore_volume_keys: bool,
112 combining_accent: Option<char>,
113}
114
115#[derive(Debug, Clone, PartialEq, Eq, Hash)]
116pub struct PlatformSpecificEventLoopAttributes {
117 pub android_app: Option<AndroidApp>,
118 pub ignore_volume_keys: bool,
119}
120
121impl Default for PlatformSpecificEventLoopAttributes {
122 fn default() -> Self {
123 Self { android_app: Default::default(), ignore_volume_keys: true }
124 }
125}
126
127const GLOBAL_WINDOW: WindowId = WindowId::from_raw(0);
129
130impl EventLoop {
131 pub fn new(attributes: &PlatformSpecificEventLoopAttributes) -> Result<Self, EventLoopError> {
132 static EVENT_LOOP_CREATED: AtomicBool = AtomicBool::new(false);
133 if EVENT_LOOP_CREATED.swap(true, Ordering::Relaxed) {
134 return Err(EventLoopError::RecreationAttempt);
136 }
137
138 let android_app = attributes.android_app.as_ref().expect(
139 "An `AndroidApp` as passed to android_main() is required to create an `EventLoop` on \
140 Android",
141 );
142
143 let event_loop_proxy = Arc::new(EventLoopProxy::new(android_app.create_waker()));
144
145 let redraw_flag = SharedFlag::new();
146
147 Ok(Self {
148 android_app: android_app.clone(),
149 primary_pointer: None,
150 window_target: ActiveEventLoop {
151 app: android_app.clone(),
152 control_flow: Cell::new(ControlFlow::default()),
153 exit: Cell::new(false),
154 redraw_requester: RedrawRequester::new(&redraw_flag, android_app.create_waker()),
155 event_loop_proxy,
156 },
157 redraw_flag,
158 loop_running: false,
159 running: false,
160 pending_redraw: false,
161 cause: StartCause::Init,
162 ignore_volume_keys: attributes.ignore_volume_keys,
163 combining_accent: None,
164 })
165 }
166
167 pub fn window_target(&self) -> &dyn RootActiveEventLoop {
168 &self.window_target
169 }
170
171 fn single_iteration<A: ApplicationHandler>(
172 &mut self,
173 main_event: Option<MainEvent<'_>>,
174 app: &mut A,
175 ) {
176 trace!("Mainloop iteration");
177
178 let cause = self.cause;
179 let mut pending_redraw = self.pending_redraw;
180 let mut resized = false;
181
182 app.new_events(&self.window_target, cause);
183
184 if let Some(event) = main_event {
185 trace!("Handling main event {:?}", event);
186
187 match event {
188 MainEvent::InitWindow { .. } => {
189 app.can_create_surfaces(&self.window_target);
190 },
191 MainEvent::TerminateWindow { .. } => {
192 app.destroy_surfaces(&self.window_target);
193 },
194 MainEvent::WindowResized { .. } => resized = true,
195 MainEvent::RedrawNeeded { .. } => pending_redraw = true,
196 MainEvent::ContentRectChanged { .. } => {
197 warn!("TODO: find a way to notify application of content rect change");
198 },
199 MainEvent::GainedFocus => {
200 HAS_FOCUS.store(true, Ordering::Relaxed);
201 let event = event::WindowEvent::Focused(true);
202 app.window_event(&self.window_target, GLOBAL_WINDOW, event);
203 },
204 MainEvent::LostFocus => {
205 HAS_FOCUS.store(false, Ordering::Relaxed);
206 let event = event::WindowEvent::Focused(false);
207 app.window_event(&self.window_target, GLOBAL_WINDOW, event);
208 },
209 MainEvent::ConfigChanged { .. } => {
210 let old_scale_factor = scale_factor(&self.android_app);
211 let scale_factor = scale_factor(&self.android_app);
212 if (scale_factor - old_scale_factor).abs() < f64::EPSILON {
213 let new_surface_size = Arc::new(Mutex::new(screen_size(&self.android_app)));
214 let event = event::WindowEvent::ScaleFactorChanged {
215 surface_size_writer: SurfaceSizeWriter::new(Arc::downgrade(
216 &new_surface_size,
217 )),
218 scale_factor,
219 };
220
221 app.window_event(&self.window_target, GLOBAL_WINDOW, event);
222 }
223 },
224 MainEvent::LowMemory => {
225 app.memory_warning(&self.window_target);
226 },
227 MainEvent::Start => {
228 app.resumed(self.window_target());
229 },
230 MainEvent::Resume { .. } => {
231 debug!("App Resumed - is running");
232 self.running = true;
234 },
235 MainEvent::SaveState { .. } => {
236 warn!("TODO: forward saveState notification to application");
239 },
240 MainEvent::Pause => {
241 debug!("App Paused - stopped running");
242 self.running = false;
244 },
245 MainEvent::Stop => {
246 app.suspended(self.window_target());
247 },
248 MainEvent::Destroy => {
249 warn!("TODO: forward onDestroy notification to application");
252 },
253 MainEvent::InsetsChanged { .. } => {
254 warn!("TODO: handle Android InsetsChanged notification");
256 },
257 unknown => {
258 trace!("Unknown MainEvent {unknown:?} (ignored)");
259 },
260 }
261 } else {
262 trace!("No main event to handle");
263 }
264
265 let android_app = self.android_app.clone();
268
269 match android_app.input_events_iter() {
271 Ok(mut input_iter) => loop {
272 let read_event =
273 input_iter.next(|event| self.handle_input_event(&android_app, event, app));
274
275 if !read_event {
276 break;
277 }
278 },
279 Err(err) => {
280 tracing::warn!("Failed to get input events iterator: {err:?}");
281 },
282 }
283
284 if self.window_target.event_loop_proxy.wake_up.swap(false, Ordering::Relaxed) {
285 app.proxy_wake_up(&self.window_target);
286 }
287
288 if self.running {
289 if resized {
290 let size = if let Some(native_window) = self.android_app.native_window().as_ref() {
291 let width = native_window.width() as _;
292 let height = native_window.height() as _;
293 PhysicalSize::new(width, height)
294 } else {
295 PhysicalSize::new(0, 0)
296 };
297 let event = event::WindowEvent::SurfaceResized(size);
298 app.window_event(&self.window_target, GLOBAL_WINDOW, event);
299 }
300
301 pending_redraw |= self.redraw_flag.get_and_reset();
302 if pending_redraw {
303 pending_redraw = false;
304 let event = event::WindowEvent::RedrawRequested;
305 app.window_event(&self.window_target, GLOBAL_WINDOW, event);
306 }
307 }
308
309 app.about_to_wait(&self.window_target);
311
312 self.pending_redraw = pending_redraw;
313 }
314
315 fn handle_input_event<A: ApplicationHandler>(
316 &mut self,
317 android_app: &AndroidApp,
318 event: &InputEvent<'_>,
319 app: &mut A,
320 ) -> InputStatus {
321 let mut input_status = InputStatus::Handled;
322 match event {
323 InputEvent::MotionEvent(motion_event) => {
324 let device_id = Some(DeviceId::from_raw(motion_event.device_id() as i64));
325 let action = motion_event.action();
326
327 let pointers: Option<
328 Box<dyn Iterator<Item = android_activity::input::Pointer<'_>>>,
329 > = match action {
330 MotionAction::Down
331 | MotionAction::PointerDown
332 | MotionAction::Up
333 | MotionAction::PointerUp => Some(Box::new(std::iter::once(
334 motion_event.pointer_at_index(motion_event.pointer_index()),
335 ))),
336 MotionAction::Move | MotionAction::Cancel => {
337 Some(Box::new(motion_event.pointers()))
338 },
339 _ => None,
341 };
342
343 for pointer in pointers.into_iter().flatten() {
344 let tool_type = pointer.tool_type();
345 let position = PhysicalPosition { x: pointer.x() as _, y: pointer.y() as _ };
346 trace!(
347 "Input event {device_id:?}, {action:?}, loc={position:?}, \
348 pointer={pointer:?}, tool_type={tool_type:?}"
349 );
350 let finger_id = FingerId::from_raw(pointer.pointer_id() as usize);
351 let force = Some(Force::Normalized(pointer.pressure() as f64));
352
353 match action {
354 MotionAction::Down | MotionAction::PointerDown => {
355 let primary = action == MotionAction::Down;
356 if primary {
357 self.primary_pointer = Some(finger_id);
358 }
359 let event = event::WindowEvent::PointerEntered {
360 device_id,
361 primary,
362 position,
363 kind: match tool_type {
364 android_activity::input::ToolType::Finger => {
365 event::PointerKind::Touch(finger_id)
366 },
367 android_activity::input::ToolType::Mouse => continue,
369 _ => event::PointerKind::Unknown,
370 },
371 };
372 app.window_event(&self.window_target, GLOBAL_WINDOW, event);
373 let event = event::WindowEvent::PointerButton {
374 device_id,
375 primary,
376 state: event::ElementState::Pressed,
377 position,
378 button: match tool_type {
379 android_activity::input::ToolType::Finger => {
380 event::ButtonSource::Touch { finger_id, force }
381 },
382 android_activity::input::ToolType::Mouse => continue,
384 _ => event::ButtonSource::Unknown(0),
385 },
386 };
387 app.window_event(&self.window_target, GLOBAL_WINDOW, event);
388 },
389 MotionAction::Move => {
390 let primary = self.primary_pointer == Some(finger_id);
391 let event = event::WindowEvent::PointerMoved {
392 device_id,
393 primary,
394 position,
395 source: match tool_type {
396 android_activity::input::ToolType::Finger => {
397 event::PointerSource::Touch { finger_id, force }
398 },
399 android_activity::input::ToolType::Mouse => continue,
401 _ => event::PointerSource::Unknown,
402 },
403 };
404 app.window_event(&self.window_target, GLOBAL_WINDOW, event);
405 },
406 MotionAction::Up | MotionAction::PointerUp | MotionAction::Cancel => {
407 let primary = action == MotionAction::Up
408 || (action == MotionAction::Cancel
409 && self.primary_pointer == Some(finger_id));
410
411 if primary {
412 self.primary_pointer = None;
413 }
414
415 if let MotionAction::Up | MotionAction::PointerUp = action {
416 let event = event::WindowEvent::PointerButton {
417 device_id,
418 primary,
419 state: event::ElementState::Released,
420 position,
421 button: match tool_type {
422 android_activity::input::ToolType::Finger => {
423 event::ButtonSource::Touch { finger_id, force }
424 },
425 android_activity::input::ToolType::Mouse => continue,
427 _ => event::ButtonSource::Unknown(0),
428 },
429 };
430 app.window_event(&self.window_target, GLOBAL_WINDOW, event);
431 }
432
433 let event = event::WindowEvent::PointerLeft {
434 device_id,
435 primary,
436 position: Some(position),
437 kind: match tool_type {
438 android_activity::input::ToolType::Finger => {
439 event::PointerKind::Touch(finger_id)
440 },
441 android_activity::input::ToolType::Mouse => continue,
443 _ => event::PointerKind::Unknown,
444 },
445 };
446 app.window_event(&self.window_target, GLOBAL_WINDOW, event);
447 },
448 _ => unreachable!(),
449 }
450 }
451 },
452 InputEvent::KeyEvent(key) => {
453 match key.key_code() {
454 Keycode::VolumeUp | Keycode::VolumeDown | Keycode::VolumeMute
459 if self.ignore_volume_keys =>
460 {
461 input_status = InputStatus::Unhandled
462 },
463 keycode => {
464 let state = match key.action() {
465 KeyAction::Down => event::ElementState::Pressed,
466 KeyAction::Up => event::ElementState::Released,
467 _ => event::ElementState::Released,
468 };
469
470 let key_char = keycodes::character_map_and_combine_key(
471 android_app,
472 key,
473 &mut self.combining_accent,
474 );
475
476 let event = event::WindowEvent::KeyboardInput {
477 device_id: Some(DeviceId::from_raw(key.device_id() as i64)),
478 event: event::KeyEvent {
479 state,
480 physical_key: keycodes::to_physical_key(keycode),
481 logical_key: keycodes::to_logical(key_char, keycode),
482 location: keycodes::to_location(keycode),
483 repeat: key.repeat_count() > 0,
484 text: None,
485 text_with_all_modifiers: None,
486 key_without_modifiers: keycodes::to_logical(key_char, keycode),
487 },
488 is_synthetic: false,
489 };
490
491 app.window_event(&self.window_target, GLOBAL_WINDOW, event);
492 },
493 }
494 },
495 _ => {
496 warn!("Unknown android_activity input event {event:?}")
497 },
498 }
499
500 input_status
501 }
502
503 pub fn run_app_on_demand<A: ApplicationHandler>(
504 &mut self,
505 mut app: A,
506 ) -> Result<(), EventLoopError> {
507 self.window_target.clear_exit();
508 loop {
509 match self.pump_app_events(None, &mut app) {
510 PumpStatus::Exit(0) => {
511 break Ok(());
512 },
513 PumpStatus::Exit(code) => {
514 break Err(EventLoopError::ExitFailure(code));
515 },
516 _ => {
517 continue;
518 },
519 }
520 }
521 }
522
523 pub fn pump_app_events<A: ApplicationHandler>(
524 &mut self,
525 timeout: Option<Duration>,
526 mut app: A,
527 ) -> PumpStatus {
528 if !self.loop_running {
529 self.loop_running = true;
530
531 self.pending_redraw = false;
535 self.cause = StartCause::Init;
536
537 self.single_iteration(None, &mut app);
539 }
540
541 if !self.exiting() {
544 self.poll_events_with_timeout(timeout, &mut app);
545 }
546 if self.exiting() {
547 self.loop_running = false;
548
549 PumpStatus::Exit(0)
550 } else {
551 PumpStatus::Continue
552 }
553 }
554
555 fn poll_events_with_timeout<A: ApplicationHandler>(
556 &mut self,
557 mut timeout: Option<Duration>,
558 app: &mut A,
559 ) {
560 let start = Instant::now();
561
562 self.pending_redraw |= self.redraw_flag.get_and_reset();
563
564 timeout = if self.running
565 && (self.pending_redraw
566 || self.window_target.event_loop_proxy.wake_up.load(Ordering::Relaxed))
567 {
568 Some(Duration::ZERO)
570 } else {
571 let control_flow_timeout = match self.control_flow() {
572 ControlFlow::Wait => None,
573 ControlFlow::Poll => Some(Duration::ZERO),
574 ControlFlow::WaitUntil(wait_deadline) => {
575 Some(wait_deadline.saturating_duration_since(start))
576 },
577 };
578
579 min_timeout(control_flow_timeout, timeout)
580 };
581
582 let android_app = self.android_app.clone(); android_app.poll_events(timeout, |poll_event| {
584 let mut main_event = None;
585
586 match poll_event {
587 android_activity::PollEvent::Wake => {
588 self.pending_redraw |= self.redraw_flag.get_and_reset();
597 if !self.running
598 || (!self.pending_redraw
599 && !self.window_target.event_loop_proxy.wake_up.load(Ordering::Relaxed))
600 {
601 return;
602 }
603 },
604 android_activity::PollEvent::Timeout => {},
605 android_activity::PollEvent::Main(event) => {
606 main_event = Some(event);
607 },
608 unknown_event => {
609 warn!("Unknown poll event {unknown_event:?} (ignored)");
610 },
611 }
612
613 self.cause = match self.control_flow() {
614 ControlFlow::Poll => StartCause::Poll,
615 ControlFlow::Wait => StartCause::WaitCancelled { start, requested_resume: None },
616 ControlFlow::WaitUntil(deadline) => {
617 if Instant::now() < deadline {
618 StartCause::WaitCancelled { start, requested_resume: Some(deadline) }
619 } else {
620 StartCause::ResumeTimeReached { start, requested_resume: deadline }
621 }
622 },
623 };
624
625 self.single_iteration(main_event, app);
626 });
627 }
628
629 fn control_flow(&self) -> ControlFlow {
630 self.window_target.control_flow()
631 }
632
633 fn exiting(&self) -> bool {
634 self.window_target.exiting()
635 }
636}
637
638pub struct EventLoopProxy {
639 wake_up: AtomicBool,
640 waker: AndroidAppWaker,
641}
642
643impl fmt::Debug for EventLoopProxy {
644 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
645 f.debug_struct("EventLoopProxy").field("wake_up", &self.wake_up).finish_non_exhaustive()
646 }
647}
648
649impl EventLoopProxy {
650 fn new(waker: AndroidAppWaker) -> Self {
651 Self { wake_up: AtomicBool::new(false), waker }
652 }
653}
654
655impl EventLoopProxyProvider for EventLoopProxy {
656 fn wake_up(&self) {
657 self.wake_up.store(true, Ordering::Relaxed);
658 self.waker.wake();
659 }
660}
661
662#[derive(Debug)]
663pub struct ActiveEventLoop {
664 pub(crate) app: AndroidApp,
665 control_flow: Cell<ControlFlow>,
666 exit: Cell<bool>,
667 redraw_requester: RedrawRequester,
668 event_loop_proxy: Arc<EventLoopProxy>,
669}
670
671impl ActiveEventLoop {
672 fn clear_exit(&self) {
673 self.exit.set(false);
674 }
675}
676
677impl RootActiveEventLoop for ActiveEventLoop {
678 fn create_proxy(&self) -> CoreEventLoopProxy {
679 CoreEventLoopProxy::new(self.event_loop_proxy.clone())
680 }
681
682 fn create_window(
683 &self,
684 window_attributes: WindowAttributes,
685 ) -> Result<Box<dyn CoreWindow>, RequestError> {
686 Ok(Box::new(Window::new(self, window_attributes)?))
687 }
688
689 fn create_custom_cursor(
690 &self,
691 _source: CustomCursorSource,
692 ) -> Result<CustomCursor, RequestError> {
693 Err(NotSupportedError::new("create_custom_cursor is not supported").into())
694 }
695
696 fn available_monitors(&self) -> Box<dyn Iterator<Item = CoreMonitorHandle>> {
697 Box::new(std::iter::empty())
698 }
699
700 fn primary_monitor(&self) -> Option<CoreMonitorHandle> {
701 None
702 }
703
704 fn system_theme(&self) -> Option<Theme> {
705 None
706 }
707
708 fn listen_device_events(&self, _allowed: DeviceEvents) {}
709
710 fn set_control_flow(&self, control_flow: ControlFlow) {
711 self.control_flow.set(control_flow)
712 }
713
714 fn control_flow(&self) -> ControlFlow {
715 self.control_flow.get()
716 }
717
718 fn exit(&self) {
719 self.exit.set(true)
720 }
721
722 fn exiting(&self) -> bool {
723 self.exit.get()
724 }
725
726 fn owned_display_handle(&self) -> CoreOwnedDisplayHandle {
727 CoreOwnedDisplayHandle::new(Arc::new(OwnedDisplayHandle))
728 }
729
730 fn rwh_06_handle(&self) -> &dyn rwh_06::HasDisplayHandle {
731 self
732 }
733}
734
735impl rwh_06::HasDisplayHandle for ActiveEventLoop {
736 fn display_handle(&self) -> Result<rwh_06::DisplayHandle<'_>, rwh_06::HandleError> {
737 let raw = rwh_06::AndroidDisplayHandle::new();
738 Ok(unsafe { rwh_06::DisplayHandle::borrow_raw(raw.into()) })
739 }
740}
741
742#[derive(Clone, PartialEq, Eq)]
743pub(crate) struct OwnedDisplayHandle;
744
745impl rwh_06::HasDisplayHandle for OwnedDisplayHandle {
746 fn display_handle(&self) -> Result<rwh_06::DisplayHandle<'_>, rwh_06::HandleError> {
747 let raw = rwh_06::AndroidDisplayHandle::new();
748 Ok(unsafe { rwh_06::DisplayHandle::borrow_raw(raw.into()) })
749 }
750}
751
752#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
753pub struct PlatformSpecificWindowAttributes;
754
755#[derive(Debug)]
756pub struct Window {
757 app: AndroidApp,
758 ime_capabilities: Mutex<Option<ImeCapabilities>>,
759 redraw_requester: RedrawRequester,
760}
761
762impl Window {
763 pub(crate) fn new(
764 el: &ActiveEventLoop,
765 _window_attrs: window::WindowAttributes,
766 ) -> Result<Self, RequestError> {
767 Ok(Self {
770 app: el.app.clone(),
771 ime_capabilities: Default::default(),
772 redraw_requester: el.redraw_requester.clone(),
773 })
774 }
775
776 pub(crate) fn config(&self) -> ConfigurationRef {
777 self.app.config()
778 }
779
780 pub(crate) fn content_rect(&self) -> Rect {
781 self.app.content_rect()
782 }
783
784 #[allow(deprecated)]
786 fn raw_window_handle_rwh_06(&self) -> Result<rwh_06::RawWindowHandle, rwh_06::HandleError> {
787 use rwh_06::HasRawWindowHandle;
788
789 if let Some(native_window) = self.app.native_window().as_ref() {
790 native_window.raw_window_handle()
791 } else {
792 tracing::error!(
793 "Cannot get the native window, it's null and will always be null before \
794 Event::Resumed and after Event::Suspended. Make sure you only call this function \
795 between those events."
796 );
797 Err(rwh_06::HandleError::Unavailable)
798 }
799 }
800
801 fn raw_display_handle_rwh_06(&self) -> Result<rwh_06::RawDisplayHandle, rwh_06::HandleError> {
802 Ok(rwh_06::RawDisplayHandle::Android(rwh_06::AndroidDisplayHandle::new()))
803 }
804}
805
806impl rwh_06::HasDisplayHandle for Window {
807 fn display_handle(&self) -> Result<rwh_06::DisplayHandle<'_>, rwh_06::HandleError> {
808 let raw = self.raw_display_handle_rwh_06()?;
809 unsafe { Ok(rwh_06::DisplayHandle::borrow_raw(raw)) }
810 }
811}
812
813impl rwh_06::HasWindowHandle for Window {
814 fn window_handle(&self) -> Result<rwh_06::WindowHandle<'_>, rwh_06::HandleError> {
815 let raw = self.raw_window_handle_rwh_06()?;
816 unsafe { Ok(rwh_06::WindowHandle::borrow_raw(raw)) }
817 }
818}
819
820impl CoreWindow for Window {
821 fn id(&self) -> WindowId {
822 GLOBAL_WINDOW
823 }
824
825 fn primary_monitor(&self) -> Option<CoreMonitorHandle> {
826 None
827 }
828
829 fn available_monitors(&self) -> Box<dyn Iterator<Item = CoreMonitorHandle>> {
830 Box::new(std::iter::empty())
831 }
832
833 fn current_monitor(&self) -> Option<CoreMonitorHandle> {
834 None
835 }
836
837 fn scale_factor(&self) -> f64 {
838 scale_factor(&self.app)
839 }
840
841 fn request_redraw(&self) {
842 self.redraw_requester.request_redraw()
843 }
844
845 fn pre_present_notify(&self) {}
846
847 fn surface_position(&self) -> PhysicalPosition<i32> {
848 (0, 0).into()
849 }
850
851 fn outer_position(&self) -> Result<PhysicalPosition<i32>, RequestError> {
852 Err(NotSupportedError::new("outer_position is not supported").into())
853 }
854
855 fn set_outer_position(&self, _position: Position) {
856 }
858
859 fn surface_size(&self) -> PhysicalSize<u32> {
860 self.outer_size()
861 }
862
863 fn request_surface_size(&self, _size: Size) -> Option<PhysicalSize<u32>> {
864 Some(self.surface_size())
865 }
866
867 fn outer_size(&self) -> PhysicalSize<u32> {
868 screen_size(&self.app)
869 }
870
871 fn safe_area(&self) -> PhysicalInsets<u32> {
872 PhysicalInsets::new(0, 0, 0, 0)
873 }
874
875 fn set_min_surface_size(&self, _: Option<Size>) {}
876
877 fn set_max_surface_size(&self, _: Option<Size>) {}
878
879 fn surface_resize_increments(&self) -> Option<PhysicalSize<u32>> {
880 None
881 }
882
883 fn set_surface_resize_increments(&self, _increments: Option<Size>) {}
884
885 fn set_title(&self, _title: &str) {}
886
887 fn set_transparent(&self, _transparent: bool) {}
888
889 fn set_blur(&self, _blur: bool) {}
890
891 fn set_visible(&self, _visibility: bool) {}
892
893 fn is_visible(&self) -> Option<bool> {
894 None
895 }
896
897 fn set_resizable(&self, _resizeable: bool) {}
898
899 fn is_resizable(&self) -> bool {
900 false
901 }
902
903 fn set_enabled_buttons(&self, _buttons: WindowButtons) {}
904
905 fn enabled_buttons(&self) -> WindowButtons {
906 WindowButtons::all()
907 }
908
909 fn set_minimized(&self, _minimized: bool) {}
910
911 fn is_minimized(&self) -> Option<bool> {
912 None
913 }
914
915 fn set_maximized(&self, _maximized: bool) {}
916
917 fn is_maximized(&self) -> bool {
918 false
919 }
920
921 fn set_fullscreen(&self, _monitor: Option<Fullscreen>) {
922 warn!("Cannot set fullscreen on Android");
923 }
924
925 fn fullscreen(&self) -> Option<Fullscreen> {
926 None
927 }
928
929 fn set_decorations(&self, _decorations: bool) {}
930
931 fn is_decorated(&self) -> bool {
932 true
933 }
934
935 fn set_window_level(&self, _level: WindowLevel) {}
936
937 fn set_window_icon(&self, _window_icon: Option<winit_core::icon::Icon>) {}
938
939 fn set_ime_cursor_area(&self, _position: Position, _size: Size) {}
940
941 fn request_ime_update(&self, request: ImeRequest) -> Result<(), ImeRequestError> {
942 let mut current_caps = self.ime_capabilities.lock().unwrap();
943 match request {
944 ImeRequest::Enable(enable) => {
945 let (capabilities, _) = enable.into_raw();
946 if current_caps.is_some() {
947 return Err(ImeRequestError::AlreadyEnabled);
948 }
949 *current_caps = Some(capabilities);
950 self.app.show_soft_input(true);
951 },
952 ImeRequest::Update(_) => {
953 if current_caps.is_none() {
954 return Err(ImeRequestError::NotEnabled);
955 }
956 },
957 ImeRequest::Disable => {
958 *current_caps = None;
959 self.app.hide_soft_input(true);
960 },
961 }
962
963 Ok(())
964 }
965
966 fn ime_capabilities(&self) -> Option<ImeCapabilities> {
967 *self.ime_capabilities.lock().unwrap()
968 }
969
970 fn set_ime_purpose(&self, _purpose: ImePurpose) {}
971
972 fn focus_window(&self) {}
973
974 fn request_user_attention(&self, _request_type: Option<window::UserAttentionType>) {}
975
976 fn set_cursor(&self, _: Cursor) {}
977
978 fn set_cursor_position(&self, _: Position) -> Result<(), RequestError> {
979 Err(NotSupportedError::new("set_cursor_position is not supported").into())
980 }
981
982 fn set_cursor_grab(&self, _: CursorGrabMode) -> Result<(), RequestError> {
983 Err(NotSupportedError::new("set_cursor_grab is not supported").into())
984 }
985
986 fn set_cursor_visible(&self, _: bool) {}
987
988 fn drag_window(&self) -> Result<(), RequestError> {
989 Err(NotSupportedError::new("drag_window is not supported").into())
990 }
991
992 fn drag_resize_window(&self, _direction: ResizeDirection) -> Result<(), RequestError> {
993 Err(NotSupportedError::new("drag_resize_window").into())
994 }
995
996 #[inline]
997 fn show_window_menu(&self, _position: Position) {}
998
999 fn set_cursor_hittest(&self, _hittest: bool) -> Result<(), RequestError> {
1000 Err(NotSupportedError::new("set_cursor_hittest is not supported").into())
1001 }
1002
1003 fn set_theme(&self, _theme: Option<Theme>) {}
1004
1005 fn theme(&self) -> Option<Theme> {
1006 None
1007 }
1008
1009 fn set_content_protected(&self, _protected: bool) {}
1010
1011 fn has_focus(&self) -> bool {
1012 HAS_FOCUS.load(Ordering::Relaxed)
1013 }
1014
1015 fn title(&self) -> String {
1016 String::new()
1017 }
1018
1019 fn reset_dead_keys(&self) {}
1020
1021 fn rwh_06_display_handle(&self) -> &dyn rwh_06::HasDisplayHandle {
1022 self
1023 }
1024
1025 fn rwh_06_window_handle(&self) -> &dyn rwh_06::HasWindowHandle {
1026 self
1027 }
1028}
1029
1030fn screen_size(app: &AndroidApp) -> PhysicalSize<u32> {
1031 if let Some(native_window) = app.native_window() {
1032 PhysicalSize::new(native_window.width() as _, native_window.height() as _)
1033 } else {
1034 PhysicalSize::new(0, 0)
1035 }
1036}
1037
1038fn scale_factor(app: &AndroidApp) -> f64 {
1039 app.config().density().map(|dpi| dpi as f64 / 160.0).unwrap_or(1.0)
1040}