From ec2270b88fff77d137885648d877d597b2b4888d Mon Sep 17 00:00:00 2001 From: Marcel Admiraal Date: Sun, 24 Apr 2022 19:04:05 +0200 Subject: [PATCH] Add a method for obtaining display cutouts on Android --- core/bind/core_bind.cpp | 5 ++++ core/bind/core_bind.h | 1 + core/os/os.h | 1 + doc/classes/OS.xml | 7 ++++++ .../src/org/godotengine/godot/GodotIO.java | 21 ++++++++++++++++ platform/android/java_godot_io_wrapper.cpp | 25 +++++++++++++++++++ platform/android/java_godot_io_wrapper.h | 2 ++ platform/android/os_android.cpp | 5 ++++ platform/android/os_android.h | 1 + 9 files changed, 68 insertions(+) diff --git a/core/bind/core_bind.cpp b/core/bind/core_bind.cpp index d57f457143e..84e594b95e2 100644 --- a/core/bind/core_bind.cpp +++ b/core/bind/core_bind.cpp @@ -355,6 +355,10 @@ Rect2 _OS::get_window_safe_area() const { return OS::get_singleton()->get_window_safe_area(); } +Array _OS::get_display_cutouts() const { + return OS::get_singleton()->get_display_cutouts(); +} + void _OS::set_window_fullscreen(bool p_enabled) { OS::get_singleton()->set_window_fullscreen(p_enabled); } @@ -1281,6 +1285,7 @@ void _OS::_bind_methods() { ClassDB::bind_method(D_METHOD("set_min_window_size", "size"), &_OS::set_min_window_size); ClassDB::bind_method(D_METHOD("set_window_size", "size"), &_OS::set_window_size); ClassDB::bind_method(D_METHOD("get_window_safe_area"), &_OS::get_window_safe_area); + ClassDB::bind_method(D_METHOD("get_display_cutouts"), &_OS::get_display_cutouts); ClassDB::bind_method(D_METHOD("set_window_fullscreen", "enabled"), &_OS::set_window_fullscreen); ClassDB::bind_method(D_METHOD("is_window_fullscreen"), &_OS::is_window_fullscreen); ClassDB::bind_method(D_METHOD("set_window_resizable", "enabled"), &_OS::set_window_resizable); diff --git a/core/bind/core_bind.h b/core/bind/core_bind.h index cd20f687a18..694e70de712 100644 --- a/core/bind/core_bind.h +++ b/core/bind/core_bind.h @@ -199,6 +199,7 @@ public: virtual Size2 get_window_size() const; virtual Size2 get_real_window_size() const; virtual Rect2 get_window_safe_area() const; + virtual Array get_display_cutouts() const; virtual void set_max_window_size(const Size2 &p_size); virtual void set_min_window_size(const Size2 &p_size); virtual void set_window_size(const Size2 &p_size); diff --git a/core/os/os.h b/core/os/os.h index 688ac26d766..b25b81967e4 100644 --- a/core/os/os.h +++ b/core/os/os.h @@ -275,6 +275,7 @@ public: Size2 window_size = get_window_size(); return Rect2(0, 0, window_size.width, window_size.height); } + virtual Array get_display_cutouts() const { return Array(); } virtual void set_borderless_window(bool p_borderless) {} virtual bool get_borderless_window() { return false; } diff --git a/doc/classes/OS.xml b/doc/classes/OS.xml index 6e3dae55c3d..ce94a95e40e 100644 --- a/doc/classes/OS.xml +++ b/doc/classes/OS.xml @@ -217,6 +217,13 @@ The returned Dictionary's values will be the same as [method get_datetime], with the exception of Daylight Savings Time as it cannot be determined from the epoch. + + + + Returns an [Array] of [Rect2], each of which is the bounding rectangle for a display cutout or notch. These are non-functional areas on edge-to-edge screens used by cameras and sensors. Returns an empty array if the device does not have cutouts. See also [method get_window_safe_area]. + [b]Note:[/b] Currently only implemented on Android. Other platforms will return an empty array even if they do have display cutouts or notches. + + diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotIO.java b/platform/android/java/lib/src/org/godotengine/godot/GodotIO.java index e3418af26bb..9f2310f2411 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/GodotIO.java +++ b/platform/android/java/lib/src/org/godotengine/godot/GodotIO.java @@ -38,6 +38,7 @@ import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.res.AssetManager; import android.graphics.Point; +import android.graphics.Rect; import android.net.Uri; import android.os.Build; import android.os.Environment; @@ -51,6 +52,7 @@ import android.view.DisplayCutout; import android.view.WindowInsets; import java.io.IOException; +import java.util.List; import java.util.Locale; // Wrapper for native library @@ -260,6 +262,25 @@ public class GodotIO { return result; } + public int[] getDisplayCutouts() { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) + return new int[0]; + DisplayCutout cutout = activity.getWindow().getDecorView().getRootWindowInsets().getDisplayCutout(); + if (cutout == null) + return new int[0]; + List rects = cutout.getBoundingRects(); + int cutouts = rects.size(); + int[] result = new int[cutouts * 4]; + int index = 0; + for (Rect rect : rects) { + result[index++] = rect.left; + result[index++] = rect.top; + result[index++] = rect.width(); + result[index++] = rect.height(); + } + return result; + } + public void showKeyboard(String p_existing_text, boolean p_multiline, int p_max_input_length, int p_cursor_start, int p_cursor_end) { if (edit != null) edit.showKeyboard(p_existing_text, p_multiline, p_max_input_length, p_cursor_start, p_cursor_end); diff --git a/platform/android/java_godot_io_wrapper.cpp b/platform/android/java_godot_io_wrapper.cpp index 5ef5e791580..afc2dc4fa36 100644 --- a/platform/android/java_godot_io_wrapper.cpp +++ b/platform/android/java_godot_io_wrapper.cpp @@ -29,7 +29,10 @@ /*************************************************************************/ #include "java_godot_io_wrapper.h" +#include "core/array.h" #include "core/error_list.h" +#include "core/math/rect2.h" +#include "core/variant.h" // JNIEnv is only valid within the thread it belongs to, in a multi threading environment // we can't cache it. @@ -50,6 +53,7 @@ GodotIOJavaWrapper::GodotIOJavaWrapper(JNIEnv *p_env, jobject p_godot_io_instanc _open_URI = p_env->GetMethodID(cls, "openURI", "(Ljava/lang/String;)I"); _get_cache_dir = p_env->GetMethodID(cls, "getCacheDir", "()Ljava/lang/String;"); _get_data_dir = p_env->GetMethodID(cls, "getDataDir", "()Ljava/lang/String;"); + _get_display_cutouts = p_env->GetMethodID(cls, "getDisplayCutouts", "()[I"), _get_locale = p_env->GetMethodID(cls, "getLocale", "()Ljava/lang/String;"); _get_model = p_env->GetMethodID(cls, "getModel", "()Ljava/lang/String;"); _get_screen_DPI = p_env->GetMethodID(cls, "getScreenDPI", "()I"); @@ -175,6 +179,27 @@ void GodotIOJavaWrapper::get_window_safe_area(int (&p_rect_xywh)[4]) { } } +Array GodotIOJavaWrapper::get_display_cutouts() { + Array result; + ERR_FAIL_NULL_V(_get_display_cutouts, result); + JNIEnv *env = get_jni_env(); + ERR_FAIL_NULL_V(env, result); + jintArray returnArray = (jintArray)env->CallObjectMethod(godot_io_instance, _get_display_cutouts); + jint arrayLength = env->GetArrayLength(returnArray); + jint *arrayBody = env->GetIntArrayElements(returnArray, JNI_FALSE); + int cutouts = arrayLength / 4; + for (int i = 0; i < cutouts; i++) { + int x = arrayBody[i * 4]; + int y = arrayBody[i * 4 + 1]; + int width = arrayBody[i * 4 + 2]; + int height = arrayBody[i * 4 + 3]; + Rect2 cutout(x, y, width, height); + result.append(cutout); + } + env->ReleaseIntArrayElements(returnArray, arrayBody, 0); + return result; +} + String GodotIOJavaWrapper::get_unique_id() { if (_get_unique_id) { JNIEnv *env = get_jni_env(); diff --git a/platform/android/java_godot_io_wrapper.h b/platform/android/java_godot_io_wrapper.h index 95643bf3c82..411cf163baf 100644 --- a/platform/android/java_godot_io_wrapper.h +++ b/platform/android/java_godot_io_wrapper.h @@ -48,6 +48,7 @@ private: jmethodID _open_URI = 0; jmethodID _get_cache_dir = 0; jmethodID _get_data_dir = 0; + jmethodID _get_display_cutouts = 0; jmethodID _get_locale = 0; jmethodID _get_model = 0; jmethodID _get_screen_DPI = 0; @@ -75,6 +76,7 @@ public: int get_screen_dpi(); float get_scaled_density(); void get_window_safe_area(int (&p_rect_xywh)[4]); + Array get_display_cutouts(); float get_screen_refresh_rate(float p_fallback); String get_unique_id(); bool has_vk(); diff --git a/platform/android/os_android.cpp b/platform/android/os_android.cpp index 9372b79025c..7deee81f180 100644 --- a/platform/android/os_android.cpp +++ b/platform/android/os_android.cpp @@ -30,6 +30,7 @@ #include "os_android.h" +#include "core/array.h" #include "core/project_settings.h" #include "drivers/gles2/rasterizer_gles2.h" #include "drivers/gles3/rasterizer_gles3.h" @@ -302,6 +303,10 @@ Rect2 OS_Android::get_window_safe_area() const { return Rect2(xywh[0], xywh[1], xywh[2], xywh[3]); } +Array OS_Android::get_display_cutouts() const { + return godot_io_java->get_display_cutouts(); +} + String OS_Android::get_name() const { return "Android"; } diff --git a/platform/android/os_android.h b/platform/android/os_android.h index 2c79078fe09..ecf4097074c 100644 --- a/platform/android/os_android.h +++ b/platform/android/os_android.h @@ -116,6 +116,7 @@ public: virtual Size2 get_window_size() const; virtual Rect2 get_window_safe_area() const; + virtual Array get_display_cutouts() const; virtual String get_name() const; virtual MainLoop *get_main_loop() const;