bevy icon indicating copy to clipboard operation
bevy copied to clipboard

Ability to hide navigation buttons on Android (immersive mode)

Open eero-lehtinen opened this issue 1 year ago • 0 comments

What problem does this solve or what need does it fill?

I think most games would prefer to have the game be full screen instead of showing the title bar and navigation buttons. It is already possible to hide the title bar through Android build configuration in cargo-apk or xbuild, but hiding the navigation buttons requires calling Java functions.

What solution would you like?

A boolean paremeter on WindowPlugin would be nice to enable or disable this feature. I think it should be on by default for games.

What alternative(s) have you considered?

You can always implement it yourself, but it's not trivial.

Additional context

I have crated this monstrosity to achieve this while being very inexperienced in Android APIs. I'm not sure if this works for all Android versions but seems to work for me. There is also WindowInsetsControllerCompat, which could have better compatibility, but I couldn't get it to work without crashing. There is an official guide on how to do this differently, but this simple way seems to be enough.

use jni::objects::{JObject, JValue};

/// Needs to be called from the main thread
pub fn enable_immersive_mode() -> anyhow::Result<()> {
	let android_app = bevy::winit::ANDROID_APP.get().unwrap();
	let vm = unsafe { jni::JavaVM::from_raw(android_app.vm_as_ptr() as *mut *const _)? };
	let activity = unsafe { JObject::from_raw(android_app.activity_as_ptr() as *mut _) };
	let mut env = vm.attach_current_thread()?;

	// getWindow()
	let window = env
		.call_method(activity, "getWindow", "()Landroid/view/Window;", &[])?
		.l()?;

	// getWindow().getInsetsController()
	let insets_controller = env
		.call_method(
			&window,
			"getInsetsController",
			"()Landroid/view/WindowInsetsController;",
			&[],
		)?
		.l()?;

	// // getWindow().getInsetsController().setSystemBarsBehavior(2)
	// // Doesn't seem to do anything
	// env.call_method(
	// 	&insets_controller,
	// 	"setSystemBarsBehavior",
	// 	"(I)V",
	// 	&[JValue::from(2)],
	// )?;

	// getWindow().getInsetsController().hide(2)
	env.call_method(&insets_controller, "hide", "(I)V", &[JValue::from(2)])?;

	Ok(())
}

eero-lehtinen avatar Jan 18 '24 10:01 eero-lehtinen