Browse Source

Add a method for obtaining display cutouts on Android

Marcel Admiraal 3 years ago
parent
commit
71ce5857ec

+ 7 - 0
doc/classes/DisplayServer.xml

@@ -104,6 +104,13 @@
 			<description>
 			<description>
 			</description>
 			</description>
 		</method>
 		</method>
+		<method name="get_display_cutouts" qualifiers="const">
+			<return type="Array" />
+			<description>
+				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 screen_get_usable_rect].
+				[b]Note:[/b] Currently only implemented on Android. Other platforms will return an empty array even if they do have display cutouts or notches.
+			</description>
+		</method>
 		<method name="get_name" qualifiers="const">
 		<method name="get_name" qualifiers="const">
 			<return type="String" />
 			<return type="String" />
 			<description>
 			<description>

+ 6 - 0
platform/android/display_server_android.cpp

@@ -106,6 +106,12 @@ bool DisplayServerAndroid::clipboard_has() const {
 	}
 	}
 }
 }
 
 
+Array DisplayServerAndroid::get_display_cutouts() const {
+	GodotIOJavaWrapper *godot_io_java = OS_Android::get_singleton()->get_godot_io_java();
+	ERR_FAIL_NULL_V(godot_io_java, Array());
+	return godot_io_java->get_display_cutouts();
+}
+
 void DisplayServerAndroid::screen_set_keep_on(bool p_enable) {
 void DisplayServerAndroid::screen_set_keep_on(bool p_enable) {
 	GodotJavaWrapper *godot_java = OS_Android::get_singleton()->get_godot_java();
 	GodotJavaWrapper *godot_java = OS_Android::get_singleton()->get_godot_java();
 	ERR_FAIL_COND(!godot_java);
 	ERR_FAIL_COND(!godot_java);

+ 2 - 0
platform/android/display_server_android.h

@@ -95,6 +95,8 @@ public:
 	virtual String clipboard_get() const override;
 	virtual String clipboard_get() const override;
 	virtual bool clipboard_has() const override;
 	virtual bool clipboard_has() const override;
 
 
+	virtual Array get_display_cutouts() const override;
+
 	virtual void screen_set_keep_on(bool p_enable) override;
 	virtual void screen_set_keep_on(bool p_enable) override;
 	virtual bool screen_is_kept_on() const override;
 	virtual bool screen_is_kept_on() const override;
 
 

+ 21 - 0
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.pm.ActivityInfo;
 import android.content.res.AssetManager;
 import android.content.res.AssetManager;
 import android.graphics.Point;
 import android.graphics.Point;
+import android.graphics.Rect;
 import android.net.Uri;
 import android.net.Uri;
 import android.os.Build;
 import android.os.Build;
 import android.os.Environment;
 import android.os.Environment;
@@ -51,6 +52,7 @@ import android.view.DisplayCutout;
 import android.view.WindowInsets;
 import android.view.WindowInsets;
 
 
 import java.io.IOException;
 import java.io.IOException;
+import java.util.List;
 import java.util.Locale;
 import java.util.Locale;
 
 
 // Wrapper for native library
 // Wrapper for native library
@@ -260,6 +262,25 @@ public class GodotIO {
 		return result;
 		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<Rect> 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) {
 	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)
 		if (edit != null)
 			edit.showKeyboard(p_existing_text, p_multiline, p_max_input_length, p_cursor_start, p_cursor_end);
 			edit.showKeyboard(p_existing_text, p_multiline, p_max_input_length, p_cursor_start, p_cursor_end);

+ 24 - 0
platform/android/java_godot_io_wrapper.cpp

@@ -31,6 +31,8 @@
 #include "java_godot_io_wrapper.h"
 #include "java_godot_io_wrapper.h"
 
 
 #include "core/error/error_list.h"
 #include "core/error/error_list.h"
+#include "core/math/rect2.h"
+#include "core/variant/variant.h"
 
 
 // JNIEnv is only valid within the thread it belongs to, in a multi threading environment
 // JNIEnv is only valid within the thread it belongs to, in a multi threading environment
 // we can't cache it.
 // we can't cache it.
@@ -51,6 +53,7 @@ GodotIOJavaWrapper::GodotIOJavaWrapper(JNIEnv *p_env, jobject p_godot_io_instanc
 		_open_URI = p_env->GetMethodID(cls, "openURI", "(Ljava/lang/String;)I");
 		_open_URI = p_env->GetMethodID(cls, "openURI", "(Ljava/lang/String;)I");
 		_get_cache_dir = p_env->GetMethodID(cls, "getCacheDir", "()Ljava/lang/String;");
 		_get_cache_dir = p_env->GetMethodID(cls, "getCacheDir", "()Ljava/lang/String;");
 		_get_data_dir = p_env->GetMethodID(cls, "getDataDir", "()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_locale = p_env->GetMethodID(cls, "getLocale", "()Ljava/lang/String;");
 		_get_model = p_env->GetMethodID(cls, "getModel", "()Ljava/lang/String;");
 		_get_model = p_env->GetMethodID(cls, "getModel", "()Ljava/lang/String;");
 		_get_screen_DPI = p_env->GetMethodID(cls, "getScreenDPI", "()I");
 		_get_screen_DPI = p_env->GetMethodID(cls, "getScreenDPI", "()I");
@@ -176,6 +179,27 @@ void GodotIOJavaWrapper::screen_get_usable_rect(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() {
 String GodotIOJavaWrapper::get_unique_id() {
 	if (_get_unique_id) {
 	if (_get_unique_id) {
 		JNIEnv *env = get_jni_env();
 		JNIEnv *env = get_jni_env();

+ 3 - 0
platform/android/java_godot_io_wrapper.h

@@ -37,6 +37,7 @@
 #include <android/log.h>
 #include <android/log.h>
 #include <jni.h>
 #include <jni.h>
 
 
+#include "core/variant/array.h"
 #include "string_android.h"
 #include "string_android.h"
 
 
 // Class that makes functions in java/src/org/godotengine/godot/GodotIO.java callable from C++
 // Class that makes functions in java/src/org/godotengine/godot/GodotIO.java callable from C++
@@ -48,6 +49,7 @@ private:
 	jmethodID _open_URI = 0;
 	jmethodID _open_URI = 0;
 	jmethodID _get_cache_dir = 0;
 	jmethodID _get_cache_dir = 0;
 	jmethodID _get_data_dir = 0;
 	jmethodID _get_data_dir = 0;
+	jmethodID _get_display_cutouts = 0;
 	jmethodID _get_locale = 0;
 	jmethodID _get_locale = 0;
 	jmethodID _get_model = 0;
 	jmethodID _get_model = 0;
 	jmethodID _get_screen_DPI = 0;
 	jmethodID _get_screen_DPI = 0;
@@ -76,6 +78,7 @@ public:
 	float get_scaled_density();
 	float get_scaled_density();
 	float get_screen_refresh_rate(float fallback);
 	float get_screen_refresh_rate(float fallback);
 	void screen_get_usable_rect(int (&p_rect_xywh)[4]);
 	void screen_get_usable_rect(int (&p_rect_xywh)[4]);
+	Array get_display_cutouts();
 	String get_unique_id();
 	String get_unique_id();
 	bool has_vk();
 	bool has_vk();
 	void show_vk(const String &p_existing, bool p_multiline, int p_max_input_length, int p_cursor_start, int p_cursor_end);
 	void show_vk(const String &p_existing, bool p_multiline, int p_max_input_length, int p_cursor_start, int p_cursor_end);

+ 2 - 0
servers/display_server.cpp

@@ -491,6 +491,8 @@ void DisplayServer::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("clipboard_set_primary", "clipboard_primary"), &DisplayServer::clipboard_set_primary);
 	ClassDB::bind_method(D_METHOD("clipboard_set_primary", "clipboard_primary"), &DisplayServer::clipboard_set_primary);
 	ClassDB::bind_method(D_METHOD("clipboard_get_primary"), &DisplayServer::clipboard_get_primary);
 	ClassDB::bind_method(D_METHOD("clipboard_get_primary"), &DisplayServer::clipboard_get_primary);
 
 
+	ClassDB::bind_method(D_METHOD("get_display_cutouts"), &DisplayServer::get_display_cutouts);
+
 	ClassDB::bind_method(D_METHOD("get_screen_count"), &DisplayServer::get_screen_count);
 	ClassDB::bind_method(D_METHOD("get_screen_count"), &DisplayServer::get_screen_count);
 	ClassDB::bind_method(D_METHOD("screen_get_position", "screen"), &DisplayServer::screen_get_position, DEFVAL(SCREEN_OF_MAIN_WINDOW));
 	ClassDB::bind_method(D_METHOD("screen_get_position", "screen"), &DisplayServer::screen_get_position, DEFVAL(SCREEN_OF_MAIN_WINDOW));
 	ClassDB::bind_method(D_METHOD("screen_get_size", "screen"), &DisplayServer::screen_get_size, DEFVAL(SCREEN_OF_MAIN_WINDOW));
 	ClassDB::bind_method(D_METHOD("screen_get_size", "screen"), &DisplayServer::screen_get_size, DEFVAL(SCREEN_OF_MAIN_WINDOW));

+ 2 - 0
servers/display_server.h

@@ -193,6 +193,8 @@ public:
 	virtual void clipboard_set_primary(const String &p_text);
 	virtual void clipboard_set_primary(const String &p_text);
 	virtual String clipboard_get_primary() const;
 	virtual String clipboard_get_primary() const;
 
 
+	virtual Array get_display_cutouts() const { return Array(); }
+
 	enum {
 	enum {
 		SCREEN_OF_MAIN_WINDOW = -1
 		SCREEN_OF_MAIN_WINDOW = -1
 	};
 	};