2024-02-23 15:35:18 +01:00
//! # Android
//!
//! The Android backend builds on (and exposes types from) the [`ndk`](https://docs.rs/ndk/) crate.
//!
//! Native Android applications need some form of "glue" crate that is responsible
//! for defining the main entry point for your Rust application as well as tracking
//! various life-cycle events and synchronizing with the main JVM thread.
//!
//! Winit uses the [android-activity](https://docs.rs/android-activity/) as a
//! glue crate (prior to `0.28` it used
//! [ndk-glue](https://github.com/rust-windowing/android-ndk-rs/tree/master/ndk-glue)).
//!
//! The version of the glue crate that your application depends on _must_ match the
//! version that Winit depends on because the glue crate is responsible for your
//! application's main entry point. If Cargo resolves multiple versions, they will
//! clash.
//!
//! `winit` glue compatibility table:
//!
//! | winit | ndk-glue |
//! | :---: | :--------------------------: |
2024-04-27 20:02:40 +04:00
//! | 0.30 | `android-activity = "0.6"` |
2024-02-23 15:35:18 +01:00
//! | 0.29 | `android-activity = "0.5"` |
//! | 0.28 | `android-activity = "0.4"` |
//! | 0.27 | `ndk-glue = "0.7"` |
//! | 0.26 | `ndk-glue = "0.5"` |
//! | 0.25 | `ndk-glue = "0.3"` |
//! | 0.24 | `ndk-glue = "0.2"` |
//!
//! The recommended way to avoid a conflict with the glue version is to avoid explicitly
//! depending on the `android-activity` crate, and instead consume the API that
//! is re-exported by Winit under `winit::platform::android::activity::*`
//!
//! Running on an Android device needs a dynamic system library. Add this to Cargo.toml:
//!
//! ```toml
//! [lib]
//! name = "main"
//! crate-type = ["cdylib"]
//! ```
//!
//! All Android applications are based on an `Activity` subclass, and the
//! `android-activity` crate is designed to support different choices for this base
//! class. Your application _must_ specify the base class it needs via a feature flag:
//!
//! | Base Class | Feature Flag | Notes |
//! | :--------------: | :---------------: | :-----: |
//! | `NativeActivity` | `android-native-activity` | Built-in to Android - it is possible to use without compiling any Java or Kotlin code. Java or Kotlin code may be needed to subclass `NativeActivity` to access some platform features. It does not derive from the [`AndroidAppCompat`] base class.|
//! | [`GameActivity`] | `android-game-activity` | Derives from [`AndroidAppCompat`], a defacto standard `Activity` base class that helps support a wider range of Android versions. Requires a build system that can compile Java or Kotlin and fetch Android dependencies from a [Maven repository][agdk_jetpack] (or link with an embedded [release][agdk_releases] of [`GameActivity`]) |
//!
//! [`GameActivity`]: https://developer.android.com/games/agdk/game-activity
//! [`GameTextInput`]: https://developer.android.com/games/agdk/add-support-for-text-input
//! [`AndroidAppCompat`]: https://developer.android.com/reference/androidx/appcompat/app/AppCompatActivity
//! [agdk_jetpack]: https://developer.android.com/jetpack/androidx/releases/games
//! [agdk_releases]: https://developer.android.com/games/agdk/download#agdk-libraries
//! [Gradle]: https://developer.android.com/studio/build
//!
//! For more details, refer to these `android-activity` [example applications](https://github.com/rust-mobile/android-activity/tree/main/examples).
//!
//! ## Converting from `ndk-glue` to `android-activity`
//!
//! If your application is currently based on `NativeActivity` via the `ndk-glue` crate and building
//! with `cargo apk`, then the minimal changes would be:
//! 1. Remove `ndk-glue` from your `Cargo.toml`
2025-02-06 13:26:30 +03:00
//! 2. Enable the `"android-native-activity"` feature for Winit: `winit = { version = "0.30.9",
2024-03-13 14:13:48 +04:00
//! features = [ "android-native-activity" ] }`
2024-02-23 15:35:18 +01:00
//! 3. Add an `android_main` entrypoint (as above), instead of using the '`[ndk_glue::main]` proc
//! macro from `ndk-macros` (optionally add a dependency on `android_logger` and initialize
//! logging as above).
//! 4. Pass a clone of the `AndroidApp` that your application receives to Winit when building your
//! event loop (as shown above).
2024-01-04 12:54:35 +01:00
use self ::activity ::{ AndroidApp , ConfigurationRef , Rect } ;
2024-01-31 17:29:59 +04:00
use crate ::event_loop ::{ ActiveEventLoop , EventLoop , EventLoopBuilder } ;
use crate ::window ::{ Window , WindowAttributes } ;
2022-11-10 16:55:19 +00:00
2022-06-11 18:57:19 +02:00
/// Additional methods on [`EventLoop`] that are specific to Android.
2024-07-26 21:49:32 +03:00
pub trait EventLoopExtAndroid {
/// Get the [`AndroidApp`] which was used to create this event loop.
fn android_app ( & self ) -> & AndroidApp ;
}
2018-02-15 14:09:14 +01:00
2024-07-26 21:49:32 +03:00
impl EventLoopExtAndroid for EventLoop {
fn android_app ( & self ) -> & AndroidApp {
& self . event_loop . android_app
}
}
2020-05-06 15:27:49 +02:00
2024-01-31 17:29:59 +04:00
/// Additional methods on [`ActiveEventLoop`] that are specific to Android.
2024-07-26 21:49:32 +03:00
pub trait ActiveEventLoopExtAndroid {
/// Get the [`AndroidApp`] which was used to create this event loop.
fn android_app ( & self ) -> & AndroidApp ;
}
2018-02-15 14:09:14 +01:00
2022-06-11 18:57:19 +02:00
/// Additional methods on [`Window`] that are specific to Android.
2019-02-05 10:30:33 -05:00
pub trait WindowExtAndroid {
2020-05-06 15:27:49 +02:00
fn content_rect ( & self ) -> Rect ;
2022-11-10 16:55:19 +00:00
fn config ( & self ) -> ConfigurationRef ;
2016-04-19 19:31:36 +02:00
}
2024-08-23 23:40:27 +03:00
impl WindowExtAndroid for dyn Window + '_ {
2020-05-06 15:27:49 +02:00
fn content_rect ( & self ) -> Rect {
2024-08-23 23:40:27 +03:00
let window = self . as_any ( ) . downcast_ref ::< crate ::platform_impl ::Window > ( ) . unwrap ( ) ;
window . content_rect ( )
2020-05-06 15:27:49 +02:00
}
2022-11-10 16:55:19 +00:00
fn config ( & self ) -> ConfigurationRef {
2024-08-23 23:40:27 +03:00
let window = self . as_any ( ) . downcast_ref ::< crate ::platform_impl ::Window > ( ) . unwrap ( ) ;
window . config ( )
2016-04-19 19:31:36 +02:00
}
}
2024-08-11 18:33:12 +02:00
impl ActiveEventLoopExtAndroid for dyn ActiveEventLoop + '_ {
2024-07-26 21:49:32 +03:00
fn android_app ( & self ) -> & AndroidApp {
2024-08-06 21:02:53 +03:00
let event_loop =
self . as_any ( ) . downcast_ref ::< crate ::platform_impl ::ActiveEventLoop > ( ) . unwrap ( ) ;
& event_loop . app
2024-07-26 21:49:32 +03:00
}
}
2020-05-06 15:27:49 +02:00
2024-01-31 17:29:59 +04:00
/// Additional methods on [`WindowAttributes`] that are specific to Android.
pub trait WindowAttributesExtAndroid { }
2016-04-19 19:31:36 +02:00
2024-01-31 17:29:59 +04:00
impl WindowAttributesExtAndroid for WindowAttributes { }
2022-11-10 16:55:19 +00:00
pub trait EventLoopBuilderExtAndroid {
2024-07-26 21:49:32 +03:00
/// Associates the [`AndroidApp`] that was passed to `android_main()` with the event loop
2022-11-10 16:55:19 +00:00
///
2024-07-26 21:49:32 +03:00
/// This must be called on Android since the [`AndroidApp`] is not global state.
2022-11-10 16:55:19 +00:00
fn with_android_app ( & mut self , app : AndroidApp ) -> & mut Self ;
2023-06-06 23:04:51 +02:00
/// Calling this will mark the volume keys to be manually handled by the application
///
/// Default is to let the operating system handle the volume keys
fn handle_volume_keys ( & mut self ) -> & mut Self ;
2022-11-10 16:55:19 +00:00
}
2024-06-24 13:04:55 +03:00
impl EventLoopBuilderExtAndroid for EventLoopBuilder {
2022-11-10 16:55:19 +00:00
fn with_android_app ( & mut self , app : AndroidApp ) -> & mut Self {
self . platform_specific . android_app = Some ( app ) ;
self
}
2023-06-06 23:04:51 +02:00
fn handle_volume_keys ( & mut self ) -> & mut Self {
self . platform_specific . ignore_volume_keys = false ;
self
}
2022-11-10 16:55:19 +00:00
}
/// Re-export of the `android_activity` API
///
/// Winit re-exports the `android_activity` API for convenience so that most
/// applications can rely on the Winit crate to resolve the required version of
/// `android_activity` and avoid any chance of a conflict between Winit and the
/// application crate.
///
/// Unlike most libraries there can only be a single implementation
/// of the `android_activity` glue crate linked with an application because
/// it is responsible for the application's `android_main()` entry point.
///
/// Since Winit depends on a specific version of `android_activity` the simplest
/// way to avoid creating a conflict is for applications to avoid explicitly
/// depending on the `android_activity` crate, and instead consume the API that
/// is re-exported by Winit.
///
2024-07-26 21:49:32 +03:00
/// For compatibility applications should then import the [`AndroidApp`] type for
2022-11-10 16:55:19 +00:00
/// their `android_main(app: AndroidApp)` function like:
/// ```rust
/// #[cfg(target_os = "android")]
/// use winit::platform::android::activity::AndroidApp;
/// ```
pub mod activity {
2023-11-23 08:18:05 +01:00
// We enable the `"native-activity"` feature just so that we can build the
// docs, but it'll be very confusing for users to see the docs with that
// feature enabled, so we avoid inlining it so that they're forced to view
// it on the crate's own docs.rs page.
#[ doc(no_inline) ]
2024-01-04 12:54:35 +01:00
#[ cfg(android_platform) ]
2022-11-10 16:55:19 +00:00
pub use android_activity ::* ;
2024-01-04 12:54:35 +01:00
#[ cfg(not(android_platform)) ]
#[ doc(hidden) ]
pub struct Rect ;
#[ cfg(not(android_platform)) ]
#[ doc(hidden) ]
pub struct ConfigurationRef ;
#[ cfg(not(android_platform)) ]
#[ doc(hidden) ]
pub struct AndroidApp ;
2022-11-10 16:55:19 +00:00
}