diff --git a/app/build.gradle b/app/build.gradle
index 26063d0..2edad42 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -8,12 +8,10 @@ android {
defaultConfig {
applicationId "mw.gri.android"
- minSdk 28
+ minSdk 27
targetSdk 33
versionCode 1
versionName "1.0"
-
- testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
@@ -23,10 +21,7 @@ android {
}
debug {
minifyEnabled false
- //packagingOptions {
- // doNotStrip '**/*.so'
- //}
- //debuggable true
+ debuggable true
}
}
compileOptions {
@@ -40,10 +35,6 @@ dependencies {
implementation 'androidx.appcompat:appcompat:1.4.1'
implementation 'com.google.android.material:material:1.5.0'
- implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
- testImplementation 'junit:junit:4.13.2'
- androidTestImplementation 'androidx.test.ext:junit:1.1.3'
- androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
// To use the Android Frame Pacing library
//implementation "androidx.games:games-frame-pacing:1.9.1"
diff --git a/app/src/main/java/mw/gri/android/MainActivity.java b/app/src/main/java/mw/gri/android/MainActivity.java
index da6ccb0..8e01af0 100644
--- a/app/src/main/java/mw/gri/android/MainActivity.java
+++ b/app/src/main/java/mw/gri/android/MainActivity.java
@@ -1,5 +1,6 @@
package mw.gri.android;
+import android.graphics.Color;
import android.os.Bundle;
import android.system.ErrnoException;
import android.system.Os;
@@ -18,14 +19,11 @@ public class MainActivity extends GameActivity {
} catch (ErrnoException e) {
throw new RuntimeException(e);
}
-
+// getDisplayCutouts();
super.onCreate(savedInstanceState);
-
- int navBarHeight = Utils.getNavigationBarHeight(getApplicationContext());
- findViewById(android.R.id.content).setPadding(0, 0, 0, navBarHeight);
}
- public Integer getStatusBarHeight() {
- return Utils.getStatusBarHeight(getApplicationContext());
+ public int[] getDisplayCutouts() {
+ return Utils.getDisplayCutouts(this);
}
}
\ No newline at end of file
diff --git a/app/src/main/java/mw/gri/android/Utils.java b/app/src/main/java/mw/gri/android/Utils.java
index 2725c9d..be417aa 100644
--- a/app/src/main/java/mw/gri/android/Utils.java
+++ b/app/src/main/java/mw/gri/android/Utils.java
@@ -1,75 +1,52 @@
package mw.gri.android;
-import android.annotation.SuppressLint;
+import android.app.Activity;
import android.content.Context;
-import android.content.res.Resources;
-import android.graphics.Point;
import android.os.Build;
-import android.view.Display;
+import android.view.DisplayCutout;
import android.view.WindowInsets;
import android.view.WindowManager;
+import androidx.core.graphics.Insets;
+import androidx.core.view.DisplayCutoutCompat;
+import androidx.core.view.ViewCompat;
+import androidx.core.view.WindowInsetsCompat;
public class Utils {
- public static int getStatusBarHeight(Context context) {
- WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
+ public static int[] getDisplayCutouts(Activity context) {
+ int[] cutouts = new int[]{0, 0, 0, 0};
if (Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.R) {
- return windowManager
- .getCurrentWindowMetrics()
- .getWindowInsets()
- .getInsets(WindowInsets.Type.navigationBars())
- .bottom;
+ WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
+ WindowInsets insets = windowManager.getCurrentWindowMetrics().getWindowInsets();
+ android.graphics.Insets barsInsets = insets.getInsets(WindowInsets.Type.systemBars());
+ android.graphics.Insets cutoutsInsets = insets.getInsets(WindowInsets.Type.displayCutout());
+ cutouts[0] = pxToDp(Integer.max(barsInsets.top, cutoutsInsets.top), context);
+ cutouts[1] = pxToDp(Integer.max(barsInsets.right, cutoutsInsets.right), context);
+ cutouts[2] = pxToDp(Integer.max(barsInsets.bottom, cutoutsInsets.bottom), context);
+ cutouts[3] = pxToDp(Integer.max(barsInsets.left, cutoutsInsets.left), context);
+ } else if (Build.VERSION.SDK_INT == android.os.Build.VERSION_CODES.Q) {
+ DisplayCutout displayCutout = context.getWindowManager().getDefaultDisplay().getCutout();
+ cutouts[0] = displayCutout.getSafeInsetBottom();
+ cutouts[1] = displayCutout.getSafeInsetRight();
+ cutouts[2] = displayCutout.getSafeInsetBottom();
+ cutouts[3] = displayCutout.getSafeInsetLeft();
} else {
- Resources res = context.getResources();
- int statusBarHeight = 24;
- @SuppressLint({"DiscouragedApi", "InternalInsetResource"})
- int resourceId = res.getIdentifier("status_bar_height", "dimen", "android");
- if (resourceId > 0) {
- statusBarHeight = res.getDimensionPixelSize(resourceId);
+ WindowInsetsCompat insets = ViewCompat.getRootWindowInsets(context.getWindow().getDecorView());
+ if (insets != null) {
+ DisplayCutoutCompat displayCutout = insets.getDisplayCutout();
+ Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
+ if (displayCutout != null) {
+ cutouts[0] = pxToDp(Integer.max(displayCutout.getSafeInsetTop(), systemBars.top), context);
+ cutouts[1] = pxToDp(Integer.max(displayCutout.getSafeInsetRight(), systemBars.right), context);
+ cutouts[2] = pxToDp(Integer.max(displayCutout.getSafeInsetBottom(), systemBars.bottom), context);
+ cutouts[3] = pxToDp(Integer.max(displayCutout.getSafeInsetLeft(), systemBars.left), context);
+ }
}
- return statusBarHeight;
}
+ return cutouts;
}
- public static int getNavigationBarHeight(Context context) {
- WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
- if (Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.R) {
- return windowManager
- .getCurrentWindowMetrics()
- .getWindowInsets()
- .getInsets(WindowInsets.Type.navigationBars())
- .bottom;
- } else {
- Point appUsableSize = getAppUsableScreenSize(context);
- Point realScreenSize = getRealScreenSize(context);
-
- // navigation bar on the side
- if (appUsableSize.x < realScreenSize.x) {
- return appUsableSize.y;
- }
-
- // navigation bar at the bottom
- if (appUsableSize.y < realScreenSize.y) {
- return realScreenSize.y - appUsableSize.y;
- }
-
- // navigation bar is not present
- return 0;
- }
- }
-
- private static Point getAppUsableScreenSize(Context context) {
- WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
- Point size = new Point();
- windowManager.getDefaultDisplay().getSize(size);
- return size;
- }
-
- private static Point getRealScreenSize(Context context) {
- WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
- Display display = windowManager.getDefaultDisplay();
- Point size = new Point();
- display.getRealSize(size);
- return size;
+ private static int pxToDp(int px, Context context) {
+ return (int) (px / context.getResources().getDisplayMetrics().density);
}
}
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index 554c178..f900d41 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -1,7 +1,6 @@
- #FFFEF102
- #FFFEF102
- #FF000000
#FFFFFFFF
+ #FFFEF102
+ #FF000000
\ No newline at end of file
diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml
index 19b3ae1..efc90ee 100644
--- a/app/src/main/res/values/themes.xml
+++ b/app/src/main/res/values/themes.xml
@@ -1,13 +1,17 @@
-
\ No newline at end of file
diff --git a/fonts/jura.ttf b/fonts/jura.ttf
deleted file mode 100644
index 0617e0d..0000000
Binary files a/fonts/jura.ttf and /dev/null differ
diff --git a/fonts/roboto.ttf b/fonts/roboto.ttf
new file mode 100644
index 0000000..e7307e7
Binary files /dev/null and b/fonts/roboto.ttf differ
diff --git a/src/grim.rs b/src/grim.rs
index 893debb..568f4fc 100644
--- a/src/grim.rs
+++ b/src/grim.rs
@@ -17,13 +17,13 @@ use log::LevelFilter::{Debug, Info, Trace, Warn};
#[cfg(target_os = "android")]
use winit::platform::android::activity::AndroidApp;
-use eframe::{AppCreator, CreationContext, NativeOptions, Renderer};
-use crate::gui::{MainApp};
+use eframe::{AppCreator, NativeOptions, Renderer};
+use crate::gui::PlatformApp;
#[allow(dead_code)]
#[cfg(target_os = "android")]
#[no_mangle]
-fn android_main(app: AndroidApp) {
+unsafe fn android_main(app: AndroidApp) {
#[cfg(debug_assertions)]
{
std::env::set_var("RUST_BACKTRACE", "full");
@@ -31,6 +31,7 @@ fn android_main(app: AndroidApp) {
android_logger::Config::default().with_max_level(Info).with_tag("grim"),
);
}
+ let _app = app.clone();
use winit::platform::android::EventLoopBuilderExtAndroid;
let mut options = NativeOptions::default();
@@ -38,9 +39,9 @@ fn android_main(app: AndroidApp) {
builder.with_android_app(app);
}));
- use crate::gui::AndroidUi;
- start(options, Box::new(|_cc| Box::new(MainApp::new(_cc)
- .with_status_bar_height(24.0)
+ use crate::gui::platform::app::Android;
+ start(options, Box::new(|_cc| Box::new(
+ PlatformApp::new(_cc, Android::new(_app))
)));
}
@@ -54,7 +55,7 @@ fn main() {
.init();
let options = NativeOptions::default();
- start(options, Box::new(|_cc| Box::new(MainApp::new(_cc))));
+ start(options, Box::new(|_cc| Box::new(App::new(_cc))));
}
fn start(mut options: NativeOptions, app_creator: AppCreator) {
diff --git a/src/gui/app.rs b/src/gui/app.rs
index c6cd797..dddeebe 100644
--- a/src/gui/app.rs
+++ b/src/gui/app.rs
@@ -12,55 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-use egui::FontTweak;
-
-#[derive(Default)]
-pub struct MainApp {
- root: egui_demo_lib::DemoWindows,
- status_bar_height: Option
-}
-
-impl MainApp {
- pub fn new(cc: &eframe::CreationContext<'_>) -> Self {
- setup_fonts(&cc.egui_ctx);
- Self::default()
- }
-}
-
-#[cfg(target_os = "android")]
-impl crate::gui::AndroidUi for MainApp {
- fn with_status_bar_height(mut self, value: f32) -> Self {
- self.status_bar_height = Some(value);
- self
- }
-}
-
-impl eframe::App for MainApp {
- fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
- egui::TopBottomPanel::top("top_padding_panel")
- .resizable(false)
- .exact_height(self.status_bar_height.unwrap_or(0.0))
- .show(ctx, |ui| {});
- self.root.ui(ctx);
- }
-}
-
-fn setup_fonts(ctx: &egui::Context) {
- let mut fonts = egui::FontDefinitions::default();
- fonts.font_data.insert(
- "jura".to_owned(),
- egui::FontData::from_static(include_bytes!(
- "../../fonts/jura.ttf"
- )).tweak(FontTweak {
- scale: 1.0,
- y_offset_factor: -0.25,
- y_offset: 0.0
- }),
- );
- fonts
- .families
- .entry(egui::FontFamily::Proportional)
- .or_default()
- .insert(0, "jura".to_owned());
- ctx.set_fonts(fonts);
+pub struct PlatformApp {
+ pub(crate) root: egui_demo_lib::DemoWindows,
+ // root: super::views::main
+ pub(crate) platform: Platform,
}
\ No newline at end of file
diff --git a/src/gui/mod.rs b/src/gui/mod.rs
index c0f877b..3ebb6ee 100644
--- a/src/gui/mod.rs
+++ b/src/gui/mod.rs
@@ -1,4 +1,4 @@
-// Copyright 2023 The Grin Developers
+// Copyright 2023 The Grim Developers
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -13,11 +13,7 @@
// limitations under the License.
mod app;
-pub mod root;
+pub use crate::gui::app::PlatformApp;
-pub use app::MainApp;
-
-#[cfg(target_os = "android")]
-pub trait AndroidUi {
- fn with_status_bar_height(self, value: f32) -> Self;
-}
\ No newline at end of file
+pub mod views;
+pub mod platform;
\ No newline at end of file
diff --git a/src/gui/platform/android/mod.rs b/src/gui/platform/android/mod.rs
new file mode 100644
index 0000000..d5d7f34
--- /dev/null
+++ b/src/gui/platform/android/mod.rs
@@ -0,0 +1,177 @@
+// Copyright 2023 The Grim Developers
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+use egui::{Color32, FontTweak, Visuals};
+use egui::epaint::Shadow;
+use jni::objects::{JObject, JPrimitiveArray};
+use crate::gui::PlatformApp;
+
+use winit::platform::android::activity::AndroidApp;
+
+pub struct Android {
+ pub android_app: AndroidApp,
+ pub cutouts: [i32; 4],
+ pub window_size: [f32; 2]
+}
+
+impl Android {
+ pub fn new(app: AndroidApp) -> Self {
+ Android {
+ android_app: app,
+ cutouts: Default::default(),
+ window_size: Default::default()
+ }
+ }
+}
+
+impl PlatformApp {
+ pub fn new(cc: &eframe::CreationContext<'_>, platform: Android) -> Self {
+ setup_fonts(&cc.egui_ctx);
+ // cc.egui_ctx.set_visuals(Visuals {
+ // dark_mode: false,
+ // override_text_color: None,
+ // widgets: Default::default(),
+ // selection: Default::default(),
+ // hyperlink_color: Default::default(),
+ // faint_bg_color: Default::default(),
+ // extreme_bg_color: Default::default(),
+ // code_bg_color: Default::default(),
+ // warn_fg_color: Default::default(),
+ // error_fg_color: Default::default(),
+ // window_rounding: Default::default(),
+ // window_shadow: Default::default(),
+ // window_fill: Default::default(),
+ // window_stroke: Default::default(),
+ // panel_fill: Default::default(),
+ // popup_shadow: Default::default(),
+ // resize_corner_size: 0.0,
+ // text_cursor_width: 0.0,
+ // text_cursor_preview: false,
+ // clip_rect_margin: 0.0,
+ // button_frame: false,
+ // collapsing_header_frame: false,
+ // });
+ Self {
+ root: Default::default(),
+ platform,
+ }
+ }
+}
+
+fn setup_fonts(ctx: &egui::Context) {
+ let mut fonts = egui::FontDefinitions::default();
+ fonts.font_data.insert(
+ "roboto".to_owned(),
+ egui::FontData::from_static(include_bytes!(
+ "../../../../fonts/roboto.ttf"
+ )).tweak(FontTweak {
+ scale: 1.0,
+ y_offset_factor: -0.20,
+ y_offset: 0.0
+ }),
+ );
+ fonts
+ .families
+ .entry(egui::FontFamily::Proportional)
+ .or_default()
+ .insert(0, "roboto".to_owned());
+ ctx.set_fonts(fonts);
+}
+
+impl eframe::App for PlatformApp {
+ fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) {
+ println!("12345 - X {}", frame.info().window_info.size.x);
+ println!("12345 - Y {}", frame.info().window_info.size.y);
+
+ 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 = get_display_cutouts(&self.platform.android_app);
+ }
+
+ egui::TopBottomPanel::top("top_padding_panel")
+ .frame(egui::Frame {
+ shadow: Shadow::NONE,
+ fill: Color32::TRANSPARENT,
+ ..Default::default()
+ })
+ .show_separator_line(false)
+ .resizable(false)
+ .exact_height(self.platform.cutouts[0] as f32)
+ .show(ctx, |ui| {});
+
+ egui::SidePanel::right("right_padding_panel")
+ .frame(egui::Frame {
+ shadow: Shadow::NONE,
+ fill: Color32::TRANSPARENT,
+ ..Default::default()
+ })
+ .show_separator_line(false)
+ .resizable(false)
+ .default_width(self.platform.cutouts[1] as f32)
+ .show(ctx, |ui| {});
+
+ egui::TopBottomPanel::bottom("bottom_padding_panel")
+ .frame(egui::Frame {
+ shadow: Shadow::NONE,
+ fill: Color32::TRANSPARENT,
+ ..Default::default()
+ })
+ .show_separator_line(false)
+ .resizable(false)
+ .exact_height(self.platform.cutouts[2] as f32)
+ .show(ctx, |ui| {});
+
+ egui::SidePanel::left("left_padding_panel")
+ .frame(egui::Frame {
+ shadow: Shadow::NONE,
+ fill: Color32::TRANSPARENT,
+ ..Default::default()
+ })
+ .show_separator_line(false)
+ .resizable(false)
+ .default_width(self.platform.cutouts[3] as f32)
+ .show(ctx, |ui| {});
+
+ egui::CentralPanel::default().show(ctx, |ui| {
+ self.root.ui(ctx);
+ });
+ }
+}
+
+fn get_display_cutouts(app: &AndroidApp) -> [i32; 4] {
+ 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
+}
diff --git a/src/gui/platform/desktop/mod.rs b/src/gui/platform/desktop/mod.rs
new file mode 100644
index 0000000..f816e75
--- /dev/null
+++ b/src/gui/platform/desktop/mod.rs
@@ -0,0 +1,24 @@
+// Copyright 2023 The Grim Developers
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+use crate::gui::PlatformApp;
+
+#[derive(Default)]
+pub struct Desktop;
+
+impl PlatformApp {
+ pub fn new(cc: &eframe::CreationContext<'_>) -> Self {
+ Self::default()
+ }
+}
diff --git a/src/gui/platform/mod.rs b/src/gui/platform/mod.rs
new file mode 100644
index 0000000..81f07e5
--- /dev/null
+++ b/src/gui/platform/mod.rs
@@ -0,0 +1,21 @@
+// Copyright 2023 The Grim Developers
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#[cfg(target_os = "android")]
+#[path = "android/mod.rs"]
+pub mod app;
+#[cfg(not(target_os = "android"))]
+#[path = "desktop/mod.rs"]
+pub mod app;
+
diff --git a/src/gui/root.rs b/src/gui/root.rs
deleted file mode 100644
index e69de29..0000000
diff --git a/src/gui/views/main.rs b/src/gui/views/main.rs
new file mode 100644
index 0000000..6ddbed9
--- /dev/null
+++ b/src/gui/views/main.rs
@@ -0,0 +1,14 @@
+// Copyright 2023 The Grim Developers
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
diff --git a/src/gui/views/mod.rs b/src/gui/views/mod.rs
new file mode 100644
index 0000000..81e68b2
--- /dev/null
+++ b/src/gui/views/mod.rs
@@ -0,0 +1,14 @@
+// Copyright 2023 The Grim Developers
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+pub mod main;