Skip to content

Commit

Permalink
Merge pull request #82230 from zaevi/dark-mode-android-ios
Browse files Browse the repository at this point in the history
Support dark mode on Android and iOS.
  • Loading branch information
akien-mga committed Sep 26, 2023
2 parents 446c1fa + 428eb13 commit 4443b8f
Show file tree
Hide file tree
Showing 8 changed files with 84 additions and 2 deletions.
4 changes: 2 additions & 2 deletions doc/classes/DisplayServer.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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">
Expand Down
14 changes: 14 additions & 0 deletions platform/android/display_server_android.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
3 changes: 3 additions & 0 deletions platform/android/display_server_android.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,9 @@ class DisplayServerAndroid : public DisplayServer {
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;
Expand Down
20 changes: 20 additions & 0 deletions platform/android/java/lib/src/org/godotengine/godot/Godot.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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()
}
Expand Down
22 changes: 22 additions & 0 deletions platform/android/java_godot_wrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down Expand Up @@ -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;
}
Expand Down
4 changes: 4 additions & 0 deletions platform/android/java_godot_wrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ class GodotJavaWrapper {
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;
Expand Down Expand Up @@ -86,6 +88,8 @@ class GodotJavaWrapper {
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();
Expand Down
3 changes: 3 additions & 0 deletions platform/ios/display_server_ios.h
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,9 @@ class DisplayServerIOS : public DisplayServer {
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;
Expand Down
16 changes: 16 additions & 0 deletions platform/ios/display_server_ios.mm
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,22 @@
[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;
Expand Down

0 comments on commit 4443b8f

Please sign in to comment.