From c3ce2973737198bdb1d06c5761b7b21c741bf9e2 Mon Sep 17 00:00:00 2001 From: ardocrat Date: Wed, 31 May 2023 21:38:27 +0300 Subject: [PATCH] android: refactor display cutouts --- .../java/mw/gri/android/MainActivity.java | 59 ++++++++------ src/gui/platform/android/mod.rs | 80 +++++++++---------- 2 files changed, 73 insertions(+), 66 deletions(-) diff --git a/app/src/main/java/mw/gri/android/MainActivity.java b/app/src/main/java/mw/gri/android/MainActivity.java index f6a7251..d6ebb08 100644 --- a/app/src/main/java/mw/gri/android/MainActivity.java +++ b/app/src/main/java/mw/gri/android/MainActivity.java @@ -1,11 +1,12 @@ package mw.gri.android; +import android.hardware.SensorManager; import android.os.Bundle; import android.os.Process; import android.system.ErrnoException; import android.system.Os; -import android.util.Log; import android.view.KeyEvent; +import android.view.OrientationEventListener; import com.google.androidgamesdk.GameActivity; public class MainActivity extends GameActivity { @@ -22,31 +23,23 @@ public class MainActivity extends GameActivity { throw new RuntimeException(e); } super.onCreate(savedInstanceState); + + OrientationEventListener orientationEventListener = new OrientationEventListener(this, + SensorManager.SENSOR_DELAY_GAME) { + @Override + public void onOrientationChanged(int orientation) { + onDisplayCutoutsChanged(Utils.getDisplayCutouts(MainActivity.this)); + } + }; + if (orientationEventListener.canDetectOrientation()) { + orientationEventListener.enable(); + } + onDisplayCutoutsChanged(Utils.getDisplayCutouts(MainActivity.this)); + BackgroundService.start(getApplicationContext()); } - @Override - protected void onDestroy() { - if (!mManualExit) { - BackgroundService.stop(getApplicationContext()); - // Temporary fix to prevent app hanging when closed from recent apps - Process.killProcess(Process.myPid()); - } - super.onDestroy(); - } - - public int[] getDisplayCutouts() { - return Utils.getDisplayCutouts(this); - } - - private boolean mManualExit = false; - - // Called from native code - public void onExit() { - mManualExit = true; - BackgroundService.stop(getApplicationContext()); - finish(); - } + native void onDisplayCutoutsChanged(int[] cutouts); @Override public boolean onKeyDown(int keyCode, KeyEvent event) { @@ -58,4 +51,24 @@ public class MainActivity extends GameActivity { } public native void onBackButtonPress(); + + @Override + protected void onDestroy() { + if (!mManualExit) { + BackgroundService.stop(getApplicationContext()); + // Temporary fix to prevent app hanging when closed from recent apps + Process.killProcess(Process.myPid()); + } + super.onDestroy(); + } + + + private boolean mManualExit = false; + + // Called from native code + public void onExit() { + mManualExit = true; + BackgroundService.stop(getApplicationContext()); + finish(); + } } \ No newline at end of file diff --git a/src/gui/platform/android/mod.rs b/src/gui/platform/android/mod.rs index 874b3c7..8b3017c 100644 --- a/src/gui/platform/android/mod.rs +++ b/src/gui/platform/android/mod.rs @@ -12,7 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. +use std::sync::atomic::{AtomicBool, AtomicI32, Ordering}; use eframe::epaint::Stroke; +use lazy_static::lazy_static; use winit::platform::android::activity::AndroidApp; use crate::gui::{App, PlatformApp}; @@ -21,16 +23,12 @@ use crate::gui::platform::PlatformCallbacks; #[derive(Clone)] pub struct Android { android_app: AndroidApp, - cutouts: [i32; 4], - window_size: [f32; 2] } impl Android { pub fn new(app: AndroidApp) -> Self { Self { android_app: app, - cutouts: Default::default(), - window_size: Default::default() } } } @@ -155,49 +153,16 @@ impl PlatformApp { ctx.set_style(style); } - - fn get_display_cutouts(app: &AndroidApp) -> [i32; 4] { - use jni::objects::{JObject, JPrimitiveArray}; - - let vm = unsafe { jni::JavaVM::from_raw(app.vm_as_ptr() as _) }.unwrap(); - let mut env = vm.attach_current_thread().unwrap(); - let activity = unsafe { - JObject::from_raw(app.activity_as_ptr() as jni::sys::jobject) - }; - let _res = env - .call_method( - activity, - "getDisplayCutouts", - "()[I", - &[], - ) - .unwrap(); - let mut array: [i32; 4] = [0; 4]; - let object: jni::sys::jobject = unsafe { _res.as_jni().l }; - unsafe { - env.get_int_array_region(JPrimitiveArray::from( - JObject::from_raw(object)), 0, array.as_mut() - ).unwrap(); - } - array - } } impl eframe::App for PlatformApp { fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) { - let _x = frame.info().window_info.size.x; - let _y = frame.info().window_info.size.y; - if _x != self.platform.window_size[0] || _y != self.platform.window_size[1] { - self.platform.window_size[0] = _x; - self.platform.window_size[1] = _y; - self.platform.cutouts = Self::get_display_cutouts(&self.platform.android_app); - } - padding_panels(self, ctx); + padding_panels(ctx); self.app.ui(ctx, frame, &self.platform); } } -fn padding_panels(app: &PlatformApp, ctx: &egui::Context) { +fn padding_panels(ctx: &egui::Context) { egui::TopBottomPanel::top("top_padding_panel") .frame(egui::Frame { inner_margin: egui::style::Margin::same(0.0), @@ -206,7 +171,7 @@ fn padding_panels(app: &PlatformApp, ctx: &egui::Context) { }) .show_separator_line(false) .resizable(false) - .exact_height(app.platform.cutouts[0] as f32) + .exact_height(DISPLAY_CUTOUT_TOP.load(Ordering::Relaxed) as f32) .show(ctx, |ui| {}); egui::TopBottomPanel::bottom("bottom_padding_panel") @@ -217,7 +182,7 @@ fn padding_panels(app: &PlatformApp, ctx: &egui::Context) { }) .show_separator_line(false) .resizable(false) - .exact_height(app.platform.cutouts[2] as f32) + .exact_height(DISPLAY_CUTOUT_BOTTOM.load(Ordering::Relaxed) as f32) .show(ctx, |ui| {}); egui::SidePanel::right("right_padding_panel") @@ -228,7 +193,7 @@ fn padding_panels(app: &PlatformApp, ctx: &egui::Context) { }) .show_separator_line(false) .resizable(false) - .max_width(app.platform.cutouts[1] as f32) + .max_width(DISPLAY_CUTOUT_RIGHT.load(Ordering::Relaxed) as f32) .show(ctx, |ui| {}); egui::SidePanel::left("left_padding_panel") @@ -239,6 +204,35 @@ fn padding_panels(app: &PlatformApp, ctx: &egui::Context) { }) .show_separator_line(false) .resizable(false) - .max_width(app.platform.cutouts[3] as f32) + .max_width(DISPLAY_CUTOUT_LEFT.load(Ordering::Relaxed) as f32) .show(ctx, |ui| {}); +} + +lazy_static! { + static ref DISPLAY_CUTOUT_TOP: AtomicI32 = AtomicI32::new(0); + static ref DISPLAY_CUTOUT_RIGHT: AtomicI32 = AtomicI32::new(0); + static ref DISPLAY_CUTOUT_BOTTOM: AtomicI32 = AtomicI32::new(0); + static ref DISPLAY_CUTOUT_LEFT: AtomicI32 = AtomicI32::new(0); +} + +#[allow(non_snake_case)] +#[no_mangle] +/// Callback from Java code to update display cutouts. +pub extern "C" fn Java_mw_gri_android_MainActivity_onDisplayCutoutsChanged( + _env: jni::JNIEnv, + _class: jni::objects::JObject, + cutouts: jni::sys::jarray +) { + use jni::objects::{JObject, JPrimitiveArray}; + + let mut array: [i32; 4] = [0; 4]; + unsafe { + let j_obj = JObject::from_raw(cutouts); + let j_arr = JPrimitiveArray::from(j_obj); + _env.get_int_array_region(j_arr, 0, array.as_mut()).unwrap(); + } + DISPLAY_CUTOUT_TOP.store(array[0], Ordering::Relaxed); + DISPLAY_CUTOUT_RIGHT.store(array[1], Ordering::Relaxed); + DISPLAY_CUTOUT_BOTTOM.store(array[2], Ordering::Relaxed); + DISPLAY_CUTOUT_LEFT.store(array[3], Ordering::Relaxed); } \ No newline at end of file