Skip to content

Commit

Permalink
android: Forward suspended() and resumed() events and patch up pl…
Browse files Browse the repository at this point in the history
…atform-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
  • Loading branch information
MarijnS95 committed Sep 2, 2024
1 parent 39a7d5b commit 8eaaf98
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 51 deletions.
68 changes: 42 additions & 26 deletions src/application.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,21 @@ pub trait ApplicationHandler {
/// [`pageshow`]: https://developer.mozilla.org/en-US/docs/Web/API/Window/pageshow_event
/// [`bfcache`]: https://web.dev/bfcache/
///
/// ### Android
///
/// On Android, the [`resumed()`] method is called when the `Activity` is (again, if after a
/// prior [`suspended()`]) being displayed to the user. This is a good place to begin drawing
/// visual elements, running animations, etc. It is driven by Android's [`onStart()`] method.
///
/// [`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
/// [`resumed()`]: Self::resumed()
/// [`suspended()`]: Self::suspended()
/// [`exiting()`]: Self::exiting()
fn resumed(&mut self, event_loop: &ActiveEventLoop) {
let _ = event_loop;
}
Expand All @@ -72,25 +82,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()`].
Expand Down Expand Up @@ -235,18 +242,30 @@ 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
///
/// On Android, the [`suspended()`] method is called when the `Activity` is no longer visible to
/// the user. This is a good place to stop refreshing UI, running animations and other visual
/// things. It is driven by Android's [`onStop()`] method.
///
/// After this event the application either receives [`resumed()`] again, or [`exiting()`].
///
/// [`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
/// [`resumed()`]: Self::resumed()
/// [`suspended()`]: Self::suspended()
/// [`exiting()`]: Self::exiting()
fn suspended(&mut self, event_loop: &ActiveEventLoop) {
let _ = event_loop;
}
Expand All @@ -260,32 +279,29 @@ 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
///
/// ### Others
///
/// - **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;
}
Expand Down
6 changes: 3 additions & 3 deletions src/changelog/unreleased.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
36 changes: 18 additions & 18 deletions src/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
8 changes: 4 additions & 4 deletions src/platform_impl/android/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand All @@ -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
Expand Down

0 comments on commit 8eaaf98

Please sign in to comment.