winit_android/
event_loop.rs

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
35/// Returns the minimum `Option<Duration>`, taking into account that `None`
36/// equates to an infinite timeout, not a zero timeout (so can't just use
37/// `Option::min`)
38fn 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
57// Used for queuing redraws from arbitrary threads. We don't care how many
58// times a redraw is requested (so don't actually need to queue any data,
59// we just need to know at the start of a main loop iteration if a redraw
60// was queued and be able to read and clear the state atomically)
61impl 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            // Only explicitly try to wake up the main loop when the flag
95            // value changes
96            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, // Dispatched `NewEvents<Init>`
107    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
127// Android currently only supports one window
128const 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            // For better cross-platformness.
135            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                    // TODO: This is incorrect - will be solved in https://github.com/rust-windowing/winit/pull/3897
233                    self.running = true;
234                },
235                MainEvent::SaveState { .. } => {
236                    // XXX: how to forward this state to applications?
237                    // XXX: also how do we expose state restoration to apps?
238                    warn!("TODO: forward saveState notification to application");
239                },
240                MainEvent::Pause => {
241                    debug!("App Paused - stopped running");
242                    // TODO: This is incorrect - will be solved in https://github.com/rust-windowing/winit/pull/3897
243                    self.running = false;
244                },
245                MainEvent::Stop => {
246                    app.suspended(self.window_target());
247                },
248                MainEvent::Destroy => {
249                    // XXX: maybe exit mainloop to drop things before being
250                    // killed by the OS?
251                    warn!("TODO: forward onDestroy notification to application");
252                },
253                MainEvent::InsetsChanged { .. } => {
254                    // XXX: how to forward this state to applications?
255                    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        // temporarily decouple `android_app` from `self` so we aren't holding
266        // a borrow of `self` while iterating
267        let android_app = self.android_app.clone();
268
269        // Process input events
270        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        // This is always the last event we dispatch before poll again
310        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                    // TODO mouse events
340                    _ => 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                                    // TODO mouse events
368                                    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                                    // TODO mouse events
383                                    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                                    // TODO mouse events
400                                    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                                        // TODO mouse events
426                                        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                                    // TODO mouse events
442                                    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                    // Flag keys related to volume as unhandled. While winit does not have a way for
455                    // applications to configure what keys to flag as handled,
456                    // this appears to be a good default until winit
457                    // can be configured.
458                    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            // Reset the internal state for the loop as we start running to
532            // ensure consistent behaviour in case the loop runs and exits more
533            // than once
534            self.pending_redraw = false;
535            self.cause = StartCause::Init;
536
537            // run the initial loop iteration
538            self.single_iteration(None, &mut app);
539        }
540
541        // Consider the possibility that the `StartCause::Init` iteration could
542        // request to Exit
543        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            // If we already have work to do then we don't want to block on the next poll
569            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(); // Don't borrow self as part of poll expression
583        android_app.poll_events(timeout, |poll_event| {
584            let mut main_event = None;
585
586            match poll_event {
587                android_activity::PollEvent::Wake => {
588                    // In the X11 backend it's noted that too many false-positive wake ups
589                    // would cause the event loop to run continuously. They handle this by
590                    // re-checking for pending events (assuming they cover all
591                    // valid reasons for a wake up).
592                    //
593                    // For now, user_events and redraw_requests are the only reasons to expect
594                    // a wake up here so we can ignore the wake up if there are no events/requests.
595                    // We also ignore wake ups while suspended.
596                    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        // FIXME this ignores requested window attributes
768
769        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 the usage of HasRawWindowHandle inside this function
785    #[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        // no effect
857    }
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}