浏览代码

Merge pull request #82230 from zaevi/dark-mode-android-ios

Support dark mode on Android and iOS.
Rémi Verschelde 1 年之前
父节点
当前提交
4443b8f474

+ 2 - 2
doc/classes/DisplayServer.xml

@@ -776,14 +776,14 @@
 			<return type="bool" />
 			<description>
 				Returns [code]true[/code] if OS is using dark mode.
-				[b]Note:[/b] This method is implemented on macOS, Windows and Linux (X11).
+				[b]Note:[/b] This method is implemented on Android, iOS, macOS, Windows, and Linux (X11).
 			</description>
 		</method>
 		<method name="is_dark_mode_supported" qualifiers="const">
 			<return type="bool" />
 			<description>
 				Returns [code]true[/code] if OS supports dark mode.
-				[b]Note:[/b] This method is implemented on macOS, Windows and Linux (X11).
+				[b]Note:[/b] This method is implemented on Android, iOS, macOS, Windows, and Linux (X11).
 			</description>
 		</method>
 		<method name="is_touchscreen_available" qualifiers="const">

+ 14 - 0
platform/android/display_server_android.cpp

@@ -111,6 +111,20 @@ void DisplayServerAndroid::tts_stop() {
 	TTS_Android::stop();
 }
 
+bool DisplayServerAndroid::is_dark_mode_supported() const {
+	GodotJavaWrapper *godot_java = OS_Android::get_singleton()->get_godot_java();
+	ERR_FAIL_NULL_V(godot_java, false);
+
+	return godot_java->is_dark_mode_supported();
+}
+
+bool DisplayServerAndroid::is_dark_mode() const {
+	GodotJavaWrapper *godot_java = OS_Android::get_singleton()->get_godot_java();
+	ERR_FAIL_NULL_V(godot_java, false);
+
+	return godot_java->is_dark_mode();
+}
+
 void DisplayServerAndroid::clipboard_set(const String &p_text) {
 	GodotJavaWrapper *godot_java = OS_Android::get_singleton()->get_godot_java();
 	ERR_FAIL_NULL(godot_java);

+ 3 - 0
platform/android/display_server_android.h

@@ -103,6 +103,9 @@ public:
 	virtual void tts_resume() override;
 	virtual void tts_stop() override;
 
+	virtual bool is_dark_mode_supported() const override;
+	virtual bool is_dark_mode() const override;
+
 	virtual void clipboard_set(const String &p_text) override;
 	virtual String clipboard_get() const override;
 	virtual bool clipboard_has() const override;

+ 20 - 0
platform/android/java/lib/src/org/godotengine/godot/Godot.kt

@@ -35,6 +35,7 @@ import android.app.Activity
 import android.app.AlertDialog
 import android.content.*
 import android.content.pm.PackageManager
+import android.content.res.Configuration
 import android.content.res.Resources
 import android.graphics.Rect
 import android.hardware.Sensor
@@ -694,6 +695,25 @@ class Godot(private val context: Context) : SensorEventListener {
 		}
 	}
 
+	/**
+	 * Returns true if dark mode is supported, false otherwise.
+	 */
+	@Keep
+	private fun isDarkModeSupported(): Boolean {
+		return Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q
+	}
+
+	/**
+	 * Returns true if dark mode is supported and enabled, false otherwise.
+	 */
+	@Keep
+	private fun isDarkMode(): Boolean {
+		if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
+			return context.resources?.configuration?.uiMode?.and(Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES
+		}
+		return false
+	}
+
 	fun hasClipboard(): Boolean {
 		return mClipboard.hasPrimaryClip()
 	}

+ 22 - 0
platform/android/java_godot_wrapper.cpp

@@ -62,6 +62,8 @@ GodotJavaWrapper::GodotJavaWrapper(JNIEnv *p_env, jobject p_activity, jobject p_
 	_finish = p_env->GetMethodID(godot_class, "forceQuit", "(I)Z");
 	_set_keep_screen_on = p_env->GetMethodID(godot_class, "setKeepScreenOn", "(Z)V");
 	_alert = p_env->GetMethodID(godot_class, "alert", "(Ljava/lang/String;Ljava/lang/String;)V");
+	_is_dark_mode_supported = p_env->GetMethodID(godot_class, "isDarkModeSupported", "()Z");
+	_is_dark_mode = p_env->GetMethodID(godot_class, "isDarkMode", "()Z");
 	_get_clipboard = p_env->GetMethodID(godot_class, "getClipboard", "()Ljava/lang/String;");
 	_set_clipboard = p_env->GetMethodID(godot_class, "setClipboard", "(Ljava/lang/String;)V");
 	_has_clipboard = p_env->GetMethodID(godot_class, "hasClipboard", "()Z");
@@ -172,6 +174,26 @@ void GodotJavaWrapper::alert(const String &p_message, const String &p_title) {
 	}
 }
 
+bool GodotJavaWrapper::is_dark_mode_supported() {
+	if (_is_dark_mode_supported) {
+		JNIEnv *env = get_jni_env();
+		ERR_FAIL_NULL_V(env, false);
+		return env->CallBooleanMethod(godot_instance, _is_dark_mode_supported);
+	} else {
+		return false;
+	}
+}
+
+bool GodotJavaWrapper::is_dark_mode() {
+	if (_is_dark_mode) {
+		JNIEnv *env = get_jni_env();
+		ERR_FAIL_NULL_V(env, false);
+		return env->CallBooleanMethod(godot_instance, _is_dark_mode);
+	} else {
+		return false;
+	}
+}
+
 bool GodotJavaWrapper::has_get_clipboard() {
 	return _get_clipboard != nullptr;
 }

+ 4 - 0
platform/android/java_godot_wrapper.h

@@ -53,6 +53,8 @@ private:
 	jmethodID _finish = nullptr;
 	jmethodID _set_keep_screen_on = nullptr;
 	jmethodID _alert = nullptr;
+	jmethodID _is_dark_mode_supported = nullptr;
+	jmethodID _is_dark_mode = nullptr;
 	jmethodID _get_clipboard = nullptr;
 	jmethodID _set_clipboard = nullptr;
 	jmethodID _has_clipboard = nullptr;
@@ -86,6 +88,8 @@ public:
 	bool force_quit(JNIEnv *p_env = nullptr, int p_instance_id = 0);
 	void set_keep_screen_on(bool p_enabled);
 	void alert(const String &p_message, const String &p_title);
+	bool is_dark_mode_supported();
+	bool is_dark_mode();
 	bool has_get_clipboard();
 	String get_clipboard();
 	bool has_set_clipboard();

+ 3 - 0
platform/ios/display_server_ios.h

@@ -141,6 +141,9 @@ public:
 	virtual void tts_resume() override;
 	virtual void tts_stop() override;
 
+	virtual bool is_dark_mode_supported() const override;
+	virtual bool is_dark_mode() const override;
+
 	virtual Rect2i get_display_safe_area() const override;
 
 	virtual int get_screen_count() const override;

+ 16 - 0
platform/ios/display_server_ios.mm

@@ -354,6 +354,22 @@ void DisplayServerIOS::tts_stop() {
 	[tts stopSpeaking];
 }
 
+bool DisplayServerIOS::is_dark_mode_supported() const {
+	if (@available(iOS 13.0, *)) {
+		return true;
+	} else {
+		return false;
+	}
+}
+
+bool DisplayServerIOS::is_dark_mode() const {
+	if (@available(iOS 13.0, *)) {
+		return [UITraitCollection currentTraitCollection].userInterfaceStyle == UIUserInterfaceStyleDark;
+	} else {
+		return false;
+	}
+}
+
 Rect2i DisplayServerIOS::get_display_safe_area() const {
 	if (@available(iOS 11, *)) {
 		UIEdgeInsets insets = UIEdgeInsetsZero;