From d30b5fb81ae0a0b8ccd9778cc1e76fd2614ecc78 Mon Sep 17 00:00:00 2001 From: Marijn Suijten Date: Wed, 10 Jul 2024 15:16:26 +0200 Subject: [PATCH] android: Forward `suspended()` and `resumed()` events and patch up platform-specific documentation Key them off of `onStop()` and `onStart()` which seems to match the other backends most closely (TODO: more detail here in the commit message) https://developer.android.com/guide/components/activities/activity-lifecycle --- src/application.rs | 48 ++++++++++++++++---------------- src/changelog/unreleased.md | 6 ++-- src/event.rs | 36 ++++++++++++------------ src/platform_impl/android/mod.rs | 8 +++--- 4 files changed, 49 insertions(+), 49 deletions(-) diff --git a/src/application.rs b/src/application.rs index d63a777aa8..fbb4d05723 100644 --- a/src/application.rs +++ b/src/application.rs @@ -41,9 +41,12 @@ pub trait ApplicationHandler { /// [`pageshow`]: https://developer.mozilla.org/en-US/docs/Web/API/Window/pageshow_event /// [`bfcache`]: https://web.dev/bfcache/ /// + /// ### Android + /// [`onStart`]: https://developer.android.com/reference/android/app/Activity#onStart() + /// /// ### Others /// - /// **Android / macOS / Orbital / Wayland / Windows / X11:** Unsupported. + /// **macOS / Orbital / Wayland / Windows / X11:** Unsupported. /// /// [`resumed()`]: Self::resumed fn resumed(&mut self, event_loop: &ActiveEventLoop) { @@ -72,25 +75,22 @@ pub trait ApplicationHandler { /// ### Android /// /// On Android, the [`can_create_surfaces()`] method is called when a new [`SurfaceView`] has - /// been created. This is expected to closely correlate with the [`onResume`] lifecycle - /// event but there may technically be a discrepancy. + /// been created. This is expected to closely correlate with the [`onStart`] lifecycle event but + /// there may technically be a discrepancy. /// - /// [`onResume`]: https://developer.android.com/reference/android/app/Activity#onResume() + /// [`onStart`]: https://developer.android.com/reference/android/app/Activity#onStart() /// - /// Applications that need to run on Android must wait until they have been "resumed" before + /// Applications that need to run on Android must wait until they have received a surface before /// they will be able to create a render surface (such as an `EGLSurface`, [`VkSurfaceKHR`] - /// or [`wgpu::Surface`]) which depend on having a [`SurfaceView`]. Applications must also - /// assume that if they are [suspended], then their render surfaces are invalid and should - /// be dropped. + /// or [`wgpu::Surface`]) which depend on having a [`SurfaceView`]. Applications must handle + /// [`destroy_surfaces()`], where their render surfaces are invalid and should be dropped. /// - /// [suspended]: Self::destroy_surfaces /// [`SurfaceView`]: https://developer.android.com/reference/android/view/SurfaceView - /// [Activity lifecycle]: https://developer.android.com/guide/components/activities/activity-lifecycle /// [`VkSurfaceKHR`]: https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/VkSurfaceKHR.html /// [`wgpu::Surface`]: https://docs.rs/wgpu/latest/wgpu/struct.Surface.html /// - /// [`can_create_surfaces()`]: Self::can_create_surfaces - /// [`destroy_surfaces()`]: Self::destroy_surfaces + /// [`can_create_surfaces()`]: Self::can_create_surfaces() + /// [`destroy_surfaces()`]: Self::destroy_surfaces() fn can_create_surfaces(&mut self, event_loop: &ActiveEventLoop); /// Called after a wake up is requested using [`EventLoopProxy::wake_up()`]. @@ -235,16 +235,19 @@ pub trait ApplicationHandler { /// ### Web /// /// On Web, the [`suspended()`] method is called in response to a [`pagehide`] event if the - /// page is being restored from the [`bfcache`] (back/forward cache) - an in-memory cache that + /// page is being moved/stored in the [`bfcache`] (back/forward cache) - an in-memory cache that /// stores a complete snapshot of a page (including the JavaScript heap) as the user is /// navigating away. /// /// [`pagehide`]: https://developer.mozilla.org/en-US/docs/Web/API/Window/pagehide_event /// [`bfcache`]: https://web.dev/bfcache/ /// + /// ### Android + /// [`onStop`]: https://developer.android.com/reference/android/app/Activity#onStop() + /// /// ### Others /// - /// **Android / macOS / Orbital / Wayland / Windows / X11:** Unsupported. + /// **macOS / Orbital / Wayland / Windows / X11:** Unsupported. /// /// [`suspended()`]: Self::suspended fn suspended(&mut self, event_loop: &ActiveEventLoop) { @@ -260,23 +263,20 @@ pub trait ApplicationHandler { /// ### Android /// /// On Android, the [`destroy_surfaces()`] method is called when the application's associated - /// [`SurfaceView`] is destroyed. This is expected to closely correlate with the [`onPause`] + /// [`SurfaceView`] is destroyed. This is expected to closely correlate with the [`onStop`] /// lifecycle event but there may technically be a discrepancy. /// - /// [`onPause`]: https://developer.android.com/reference/android/app/Activity#onPause() + /// [`onStop`]: https://developer.android.com/reference/android/app/Activity#onStop() /// /// Applications that need to run on Android should assume their [`SurfaceView`] has been /// destroyed, which indirectly invalidates any existing render surfaces that may have been /// created outside of Winit (such as an `EGLSurface`, [`VkSurfaceKHR`] or [`wgpu::Surface`]). /// - /// After being [suspended] on Android applications must drop all render surfaces before - /// the event callback completes, which may be re-created when the application is next - /// [resumed]. + /// When receiving [`destroy_surfaces()`] Android applications must drop all render surfaces + /// before the event callback completes, which may be re-created when the application next + /// receives [`can_create_surfaces()`]. /// - /// [suspended]: Self::destroy_surfaces - /// [resumed]: Self::can_create_surfaces /// [`SurfaceView`]: https://developer.android.com/reference/android/view/SurfaceView - /// [Activity lifecycle]: https://developer.android.com/guide/components/activities/activity-lifecycle /// [`VkSurfaceKHR`]: https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/VkSurfaceKHR.html /// [`wgpu::Surface`]: https://docs.rs/wgpu/latest/wgpu/struct.Surface.html /// @@ -284,8 +284,8 @@ pub trait ApplicationHandler { /// /// - **iOS / macOS / Orbital / Wayland / Web / Windows / X11:** Unsupported. /// - /// [`can_create_surfaces()`]: Self::can_create_surfaces - /// [`destroy_surfaces()`]: Self::destroy_surfaces + /// [`can_create_surfaces()`]: Self::can_create_surfaces() + /// [`destroy_surfaces()`]: Self::destroy_surfaces() fn destroy_surfaces(&mut self, event_loop: &ActiveEventLoop) { let _ = event_loop; } diff --git a/src/changelog/unreleased.md b/src/changelog/unreleased.md index 385c1d0340..b466b2dd84 100644 --- a/src/changelog/unreleased.md +++ b/src/changelog/unreleased.md @@ -56,14 +56,14 @@ changelog entry. to send specific data to be processed on the main thread. - Changed `EventLoopProxy::send_event` to `EventLoopProxy::wake_up`, it now only wakes up the loop. -- `ApplicationHandler::create|destroy_surfaces()` was split off from +- `ApplicationHandler::can_create|destroy_surfaces()` was split off from `ApplicationHandler::resumed/suspended()`. `ApplicationHandler::can_create_surfaces()` should, for portability reasons to Android, be the only place to create render surfaces. - `ApplicationHandler::resumed/suspended()` are now only emitted by iOS and Web - and now signify actually resuming/suspending the application. + `ApplicationHandler::resumed/suspended()` are now only emitted by iOS, Web + and Android, and now signify actually resuming/suspending the application. ### Removed diff --git a/src/event.rs b/src/event.rs index 25a1f51601..cf68112d80 100644 --- a/src/event.rs +++ b/src/event.rs @@ -63,51 +63,51 @@ use crate::window::{ActivationToken, Theme, WindowId}; #[allow(dead_code)] #[derive(Debug, Clone, PartialEq)] pub(crate) enum Event { - /// See [`ApplicationHandler::new_events`] for details. + /// See [`ApplicationHandler::new_events()`] for details. /// - /// [`ApplicationHandler::new_events`]: crate::application::ApplicationHandler::new_events + /// [`ApplicationHandler::new_events()`]: crate::application::ApplicationHandler::new_events() NewEvents(StartCause), - /// See [`ApplicationHandler::window_event`] for details. + /// See [`ApplicationHandler::window_event()`] for details. /// - /// [`ApplicationHandler::window_event`]: crate::application::ApplicationHandler::window_event + /// [`ApplicationHandler::window_event()`]: crate::application::ApplicationHandler::window_event() #[allow(clippy::enum_variant_names)] WindowEvent { window_id: WindowId, event: WindowEvent }, - /// See [`ApplicationHandler::device_event`] for details. + /// See [`ApplicationHandler::device_event()`] for details. /// - /// [`ApplicationHandler::device_event`]: crate::application::ApplicationHandler::device_event + /// [`ApplicationHandler::device_event()`]: crate::application::ApplicationHandler::device_event() #[allow(clippy::enum_variant_names)] DeviceEvent { device_id: DeviceId, event: DeviceEvent }, - /// See [`ApplicationHandler::suspended`] for details. + /// See [`ApplicationHandler::suspended()`] for details. /// - /// [`ApplicationHandler::suspended`]: crate::application::ApplicationHandler::suspended + /// [`ApplicationHandler::suspended()`]: crate::application::ApplicationHandler::suspended() Suspended, - /// See [`ApplicationHandler::can_create_surfaces`] for details. + /// See [`ApplicationHandler::can_create_surfaces()`] for details. /// - /// [`ApplicationHandler::can_create_surfaces`]: crate::application::ApplicationHandler::can_create_surfaces + /// [`ApplicationHandler::can_create_surfaces()`]: crate::application::ApplicationHandler::can_create_surfaces() CreateSurfaces, - /// See [`ApplicationHandler::resumed`] for details. + /// See [`ApplicationHandler::resumed()`] for details. /// - /// [`ApplicationHandler::resumed`]: crate::application::ApplicationHandler::resumed + /// [`ApplicationHandler::resumed()`]: crate::application::ApplicationHandler::resumed() Resumed, - /// See [`ApplicationHandler::about_to_wait`] for details. + /// See [`ApplicationHandler::about_to_wait()`] for details. /// - /// [`ApplicationHandler::about_to_wait`]: crate::application::ApplicationHandler::about_to_wait + /// [`ApplicationHandler::about_to_wait()`]: crate::application::ApplicationHandler::about_to_wait() AboutToWait, - /// See [`ApplicationHandler::exiting`] for details. + /// See [`ApplicationHandler::exiting()`] for details. /// - /// [`ApplicationHandler::exiting`]: crate::application::ApplicationHandler::exiting + /// [`ApplicationHandler::exiting()`]: crate::application::ApplicationHandler::exiting() LoopExiting, - /// See [`ApplicationHandler::memory_warning`] for details. + /// See [`ApplicationHandler::memory_warning()`] for details. /// - /// [`ApplicationHandler::memory_warning`]: crate::application::ApplicationHandler::memory_warning + /// [`ApplicationHandler::memory_warning()`]: crate::application::ApplicationHandler::memory_warning() MemoryWarning, /// User requested a wake up. diff --git a/src/platform_impl/android/mod.rs b/src/platform_impl/android/mod.rs index e471a72cdc..bb9f558e5d 100644 --- a/src/platform_impl/android/mod.rs +++ b/src/platform_impl/android/mod.rs @@ -221,8 +221,7 @@ impl EventLoop { app.memory_warning(self.window_target()); }, MainEvent::Start => { - // XXX: how to forward this state to applications? - warn!("TODO: forward onStart notification to application"); + app.resumed(self.window_target()); }, MainEvent::Resume { .. } => { debug!("App Resumed - is running"); @@ -235,11 +234,12 @@ impl EventLoop { }, MainEvent::Pause => { debug!("App Paused - stopped running"); + // TODO: This doesn't seem generally true. The app can also keep rendering outside of onResume()/onPause() ?? + // https://developer.android.com/guide/components/activities/activity-lifecycle#onpause self.running = false; }, MainEvent::Stop => { - // XXX: how to forward this state to applications? - warn!("TODO: forward onStop notification to application"); + app.suspended(self.window_target()); }, MainEvent::Destroy => { // XXX: maybe exit mainloop to drop things before being