Support changing window manager params

This enables support for changing the various WindowManager
parameters documented here:
https://developer.android.com/reference/android/view/WindowManager.LayoutParams

either via NativeActivity_setWindowFlags or GameActivity_setWindowFlags

Fixes: #25
This commit is contained in:
Robert Bragg
2022-09-12 18:26:38 +01:00
parent 7d73e57364
commit 48993acf58
3 changed files with 226 additions and 3 deletions
+12 -1
View File
@@ -23,7 +23,7 @@ use ndk::asset::AssetManager;
use ndk::configuration::Configuration;
use ndk::native_window::NativeWindow;
use crate::{util, AndroidApp, ConfigurationRef, MainEvent, PollEvent, Rect};
use crate::{util, AndroidApp, ConfigurationRef, MainEvent, PollEvent, Rect, WindowManagerFlags};
mod ffi;
@@ -309,6 +309,17 @@ impl AndroidAppInner {
}
}
pub fn set_window_flags(
&self,
add_flags: WindowManagerFlags,
remove_flags: WindowManagerFlags,
) {
unsafe {
let activity = (*self.native_app.as_ptr()).activity;
ffi::GameActivity_setWindowFlags(activity, add_flags.bits(), remove_flags.bits())
}
}
pub fn enable_motion_axis(&mut self, axis: Axis) {
unsafe { ffi::GameActivityPointerAxes_enableAxis(axis as i32) }
}
+197 -1
View File
@@ -6,6 +6,8 @@ use std::time::Duration;
use ndk::asset::AssetManager;
use ndk::native_window::NativeWindow;
use bitflags::bitflags;
#[cfg(not(target_os = "android"))]
compile_error!("android-activity only supports compiling for Android");
@@ -170,9 +172,174 @@ pub enum PollEvent<'a> {
}
use activity_impl::AndroidAppInner;
pub use activity_impl::AndroidAppWaker;
bitflags! {
/// Flags for [`AndroidApp::set_window_flags`]
/// as per the [android.view.WindowManager.LayoutParams Java API](https://developer.android.com/reference/android/view/WindowManager.LayoutParams)
pub struct WindowManagerFlags: u32 {
/// As long as this window is visible to the user, allow the lock
/// screen to activate while the screen is on. This can be used
/// independently, or in combination with
/// [`Self::KEEP_SCREEN_ON`] and/or [`Self::SHOW_WHEN_LOCKED`]
const ALLOW_LOCK_WHILE_SCREEN_ON = 0x00000001;
/// Everything behind this window will be dimmed. */
const DIM_BEHIND = 0x00000002;
/// Blur everything behind this window.
#[deprecated = "Blurring is no longer supported"]
const BLUR_BEHIND = 0x00000004;
/// This window won't ever get key input focus, so the
/// user can not send key or other button events to it. Those will
/// instead go to whatever focusable window is behind it. This flag
/// will also enable [`Self::NOT_TOUCH_MODAL`] whether or not
/// that is explicitly set.
///
/// Setting this flag also implies that the window will not need to
/// interact with
/// a soft input method, so it will be Z-ordered and positioned
/// independently of any active input method (typically this means it
/// gets Z-ordered on top of the input method, so it can use the full
/// screen for its content and cover the input method if needed. You
/// can use [`Self::ALT_FOCUSABLE_IM`] to modify this
/// behavior.
const NOT_FOCUSABLE = 0x00000008;
/// This window can never receive touch events.
const NOT_TOUCHABLE = 0x00000010;
/// Even when this window is focusable (if
/// [`Self::NOT_FOCUSABLE`] is not set), allow any pointer
/// events outside of the window to be sent to the windows behind it.
/// Otherwise it will consume all pointer events itself, regardless of
/// whether they are inside of the window.
const NOT_TOUCH_MODAL = 0x00000020;
/// When set, if the device is asleep when the touch
/// screen is pressed, you will receive this first touch event. Usually
/// the first touch event is consumed by the system since the user can
/// not see what they are pressing on.
#[deprecated]
const TOUCHABLE_WHEN_WAKING = 0x00000040;
/// As long as this window is visible to the user, keep
/// the device's screen turned on and bright.
const KEEP_SCREEN_ON = 0x00000080;
/// Place the window within the entire screen, ignoring
/// decorations around the border (such as the status bar). The
/// window must correctly position its contents to take the screen
/// decoration into account.
const LAYOUT_IN_SCREEN = 0x00000100;
/// Allows the window to extend outside of the screen.
const LAYOUT_NO_LIMITS = 0x00000200;
/// Hide all screen decorations (such as the status
/// bar) while this window is displayed. This allows the window to
/// use the entire display space for itself -- the status bar will
/// be hidden when an app window with this flag set is on the top
/// layer. A fullscreen window will ignore a value of
/// [`Self::SOFT_INPUT_ADJUST_RESIZE`] the window will stay
/// fullscreen and will not resize.
const FULLSCREEN = 0x00000400;
/// Override [`Self::FULLSCREEN`] and force the
/// screen decorations (such as the status bar) to be shown.
const FORCE_NOT_FULLSCREEN = 0x00000800;
/// Turn on dithering when compositing this window to
/// the screen.
#[deprecated="This flag is no longer used"]
const DITHER = 0x00001000;
/// Treat the content of the window as secure, preventing
/// it from appearing in screenshots or from being viewed on non-secure
/// displays.
const SECURE = 0x00002000;
/// A special mode where the layout parameters are used
/// to perform scaling of the surface when it is composited to the
/// screen.
const SCALED = 0x00004000;
/// Intended for windows that will often be used when the user is
/// holding the screen against their face, it will aggressively
/// filter the event stream to prevent unintended presses in this
/// situation that may not be desired for a particular window, when
/// such an event stream is detected, the application will receive
/// a `AMOTION_EVENT_ACTION_CANCEL` to indicate this so
/// applications can handle this accordingly by taking no action on
/// the event until the finger is released.
const IGNORE_CHEEK_PRESSES = 0x00008000;
/// A special option only for use in combination with
/// [`Self::LAYOUT_IN_SCREEN`]. When requesting layout in
/// the screen your window may appear on top of or behind screen decorations
/// such as the status bar. By also including this flag, the window
/// manager will report the inset rectangle needed to ensure your
/// content is not covered by screen decorations.
const LAYOUT_INSET_DECOR = 0x00010000;
/// Invert the state of [`Self::NOT_FOCUSABLE`] with
/// respect to how this window interacts with the current method.
/// That is, if [`Self::NOT_FOCUSABLE`] is set and this flag is set,
/// then the window will behave as if it needs to interact with the
/// input method and thus be placed behind/away from it; if
/// [`Self::NOT_FOCUSABLE`] is not set and this flag is set,
/// then the window will behave as if it doesn't need to interact
/// with the input method and can be placed to use more space and
/// cover the input method.
const ALT_FOCUSABLE_IM = 0x00020000;
/// If you have set [`Self::NOT_TOUCH_MODAL`], you
/// can set this flag to receive a single special MotionEvent with
/// the action
/// `AMOTION_EVENT_ACTION_OUTSIDE` for
/// touches that occur outside of your window. Note that you will not
/// receive the full down/move/up gesture, only the location of the
/// first down as an `AMOTION_EVENT_ACTION_OUTSIDE`.
const WATCH_OUTSIDE_TOUCH = 0x00040000;
/// Special flag to let windows be shown when the screen
/// is locked. This will let application windows take precedence over
/// key guard or any other lock screens. Can be used with
/// [`Self::KEEP_SCREEN_ON`] to turn screen on and display
/// windows directly before showing the key guard window. Can be used with
/// [`Self::DISMISS_KEYGUARD`] to automatically fully
/// dismiss non-secure key guards. This flag only applies to the top-most
/// full-screen window.
const SHOW_WHEN_LOCKED = 0x00080000;
/// Ask that the system wallpaper be shown behind
/// your window. The window surface must be translucent to be able
/// to actually see the wallpaper behind it; this flag just ensures
/// that the wallpaper surface will be there if this window actually
/// has translucent regions.
const SHOW_WALLPAPER = 0x00100000;
/// When set as a window is being added or made
/// visible, once the window has been shown then the system will
/// poke the power manager's user activity (as if the user had woken
/// up the device) to turn the screen on.
const TURN_SCREEN_ON = 0x00200000;
/// When set the window will cause the key guard to
/// be dismissed, only if it is not a secure lock key guard. Because such
/// a key guard is not needed for security, it will never re-appear if
/// the user navigates to another window (in contrast to
/// [`Self::SHOW_WHEN_LOCKED`], which will only temporarily
/// hide both secure and non-secure key guards but ensure they reappear
/// when the user moves to another UI that doesn't hide them).
/// If the key guard is currently active and is secure (requires an
/// unlock pattern) then the user will still need to confirm it before
/// seeing this window, unless [`Self::SHOW_WHEN_LOCKED`] has
/// also been set.
const DISMISS_KEYGUARD = 0x00400000;
}
}
#[derive(Debug, Clone)]
pub struct AndroidApp {
pub(crate) inner: Arc<RwLock<AndroidAppInner>>,
@@ -251,6 +418,26 @@ impl AndroidApp {
self.inner.read().unwrap().asset_manager()
}
/// Change the window flags of the given activity.
///
/// Note that some flags must be set before the window decoration is created,
/// see
/// `<https://developer.android.com/reference/android/view/Window#setFlags(int,%20int)>`.
pub fn set_window_flags(
&self,
add_flags: WindowManagerFlags,
remove_flags: WindowManagerFlags,
) {
self.inner
.write()
.unwrap()
.set_window_flags(add_flags, remove_flags);
}
/// Enable additional input axis
///
/// To reduce overhead, by default only [`input::Axis::X`] and [`input::Axis::Y`] are enabled
/// and other axis should be enabled explicitly.
pub fn enable_motion_axis(&self, axis: input::Axis) {
self.inner.write().unwrap().enable_motion_axis(axis);
}
@@ -259,6 +446,15 @@ impl AndroidApp {
self.inner.write().unwrap().disable_motion_axis(axis);
}
/// Query and process all out-standing input event
///
/// Applications are generally either expected to call this in-sync with their rendering or
/// in response to a [`MainEvent::InputAvailable`] event being delivered. _Note though that your
/// application is will only be delivered a single [`MainEvent::InputAvailable`] event between calls
/// to this API._
///
/// To reduce overhead, by default only [`input::Axis::X`] and [`input::Axis::Y`] are enabled
/// and other axis should be enabled explicitly via [`Self::enable_motion_axis`].
pub fn input_events<'b, F>(&self, callback: F)
where
F: FnMut(&input::InputEvent),
+17 -1
View File
@@ -21,7 +21,7 @@ use ndk::configuration::Configuration;
use ndk::input_queue::InputQueue;
use ndk::native_window::NativeWindow;
use crate::{util, AndroidApp, ConfigurationRef, MainEvent, PollEvent, Rect};
use crate::{util, AndroidApp, ConfigurationRef, MainEvent, PollEvent, Rect, WindowManagerFlags};
mod ffi;
@@ -353,6 +353,22 @@ impl AndroidAppInner {
}
}
pub fn set_window_flags(
&self,
add_flags: WindowManagerFlags,
remove_flags: WindowManagerFlags,
) {
let na = self.native_activity();
let na_mut = na as *mut ndk_sys::ANativeActivity;
unsafe {
ffi::ANativeActivity_setWindowFlags(
na_mut.cast(),
add_flags.bits(),
remove_flags.bits(),
);
}
}
pub fn enable_motion_axis(&self, _axis: input::Axis) {
// NOP - The InputQueue API doesn't let us optimize which axis values are read
}