Просмотр исходного кода

Merge pull request #108557 from syntaxerror247/Fix-system-bar-regression

Android: Fix system bar regression
Thaddeus Crews 1 месяц назад
Родитель
Сommit
ec8e6aeb82

+ 3 - 0
platform/android/doc_classes/EditorExportPlatformAndroid.xml

@@ -598,6 +598,9 @@
 		<member name="permissions/write_user_dictionary" type="bool" setter="" getter="">
 			Allows an application to write to the user dictionary.
 		</member>
+		<member name="screen/background_color" type="Color" setter="" getter="">
+			The background color used for the root window. Default is [code]black[/code].
+		</member>
 		<member name="screen/edge_to_edge" type="bool" setter="" getter="">
 			If [code]true[/code], this makes the navigation and status bars translucent and allows the application content to extend edge to edge.
 			[b]Note:[/b] You should ensure that none of the application content is occluded by system elements by using the [method DisplayServer.get_display_safe_area] and [method DisplayServer.get_display_cutouts] methods.

+ 10 - 0
platform/android/export/export_plugin.cpp

@@ -1070,6 +1070,8 @@ void EditorExportPlatformAndroid::_fix_themes_xml(const Ref<EditorExportPreset>
 	main_theme_attributes["android:windowIsTranslucent"] = bool_to_string(transparency_allowed);
 	if (transparency_allowed) {
 		main_theme_attributes["android:windowBackground"] = "@android:color/transparent";
+	} else {
+		main_theme_attributes["android:windowBackground"] = "#" + p_preset->get("screen/background_color").operator Color().to_html(false);
 	}
 
 	Dictionary splash_theme_attributes;
@@ -2179,6 +2181,7 @@ void EditorExportPlatformAndroid::get_export_options(List<ExportOption> *r_optio
 	r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "screen/support_large"), true));
 	r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "screen/support_xlarge"), true));
 	r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "screen/edge_to_edge"), false));
+	r_options->push_back(ExportOption(PropertyInfo(Variant::COLOR, "screen/background_color", PROPERTY_HINT_COLOR_NO_ALPHA), Color()));
 
 	r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "user_data_backup/allow"), false));
 
@@ -3099,6 +3102,13 @@ void EditorExportPlatformAndroid::get_command_line_flags(const Ref<EditorExportP
 		command_line_strings.push_back("--edge_to_edge");
 	}
 
+	String background_color = "#" + p_preset->get("screen/background_color").operator Color().to_html(false);
+	if (_is_transparency_allowed(p_preset) && p_preset->get("gradle_build/use_gradle_build")) {
+		background_color = "#00000000";
+	}
+	command_line_strings.push_back("--background_color");
+	command_line_strings.push_back(background_color);
+
 	bool debug_opengl = p_preset->get("graphics/opengl_debug");
 	if (debug_opengl) {
 		command_line_strings.push_back("--debug_opengl");

+ 4 - 3
platform/android/java/app/src/com/godot/game/GodotApp.java

@@ -56,11 +56,12 @@ public class GodotApp extends GodotActivity {
 		}
 	}
 
-	private final Runnable updateImmersiveAndEdgeToEdgeModes = () -> {
+	private final Runnable updateWindowAppearance = () -> {
 		Godot godot = getGodot();
 		if (godot != null) {
 			godot.enableImmersiveMode(godot.isInImmersiveMode(), true);
 			godot.enableEdgeToEdge(godot.isInEdgeToEdgeMode(), true);
+			godot.setSystemBarsAppearance();
 		}
 	};
 
@@ -74,12 +75,12 @@ public class GodotApp extends GodotActivity {
 	@Override
 	public void onResume() {
 		super.onResume();
-		updateImmersiveAndEdgeToEdgeModes.run();
+		updateWindowAppearance.run();
 	}
 
 	@Override
 	public void onGodotMainLoopStarted() {
 		super.onGodotMainLoopStarted();
-		runOnUiThread(updateImmersiveAndEdgeToEdgeModes);
+		runOnUiThread(updateWindowAppearance);
 	}
 }

+ 4 - 3
platform/android/java/editor/src/main/java/org/godotengine/editor/BaseGodotEditor.kt

@@ -324,12 +324,13 @@ abstract class BaseGodotEditor : GodotActivity(), GameMenuFragment.GameMenuListe
 		}
 	}
 
-	private fun updateImmersiveAndEdgeToEdgeModes() {
+	private fun updateWindowAppearance() {
 		val editorWindowInfo = getEditorWindowInfo()
 		if (editorWindowInfo == EDITOR_MAIN_INFO || editorWindowInfo == RUN_GAME_INFO) {
 			godot?.apply {
 				enableImmersiveMode(isInImmersiveMode(), true)
 				enableEdgeToEdge(isInEdgeToEdgeMode(), true)
+				setSystemBarsAppearance()
 			}
 		}
 	}
@@ -339,13 +340,13 @@ abstract class BaseGodotEditor : GodotActivity(), GameMenuFragment.GameMenuListe
 		runOnUiThread {
 			// Hide the loading indicator
 			editorLoadingIndicator?.visibility = View.GONE
-			updateImmersiveAndEdgeToEdgeModes()
+			updateWindowAppearance()
 		}
 	}
 
 	override fun onResume() {
 		super.onResume()
-		updateImmersiveAndEdgeToEdgeModes()
+		updateWindowAppearance()
 
 		if (getEditorWindowInfo() == EDITOR_MAIN_INFO &&
 			godot?.isEditorHint() == true &&

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

@@ -38,6 +38,7 @@ import android.content.pm.PackageManager
 import android.content.res.Configuration
 import android.content.res.Resources
 import android.graphics.Color
+import android.graphics.drawable.ColorDrawable
 import android.hardware.Sensor
 import android.hardware.SensorManager
 import android.os.*
@@ -47,6 +48,8 @@ import android.view.*
 import android.widget.FrameLayout
 import androidx.annotation.Keep
 import androidx.annotation.StringRes
+import androidx.core.graphics.ColorUtils
+import androidx.core.graphics.toColorInt
 import androidx.core.view.ViewCompat
 import androidx.core.view.WindowCompat
 import androidx.core.view.WindowInsetsAnimationCompat
@@ -187,6 +190,7 @@ class Godot private constructor(val context: Context) {
 	private val isEdgeToEdge = AtomicBoolean(false)
 	private var useDebugOpengl = false
 	private var darkMode = false
+	private var backgroundColor: Int = Color.BLACK
 
 	internal var containerLayout: FrameLayout? = null
 	var renderView: GodotRenderView? = null
@@ -255,6 +259,17 @@ class Godot private constructor(val context: Context) {
 				} else if (commandLine[i] == "--fullscreen") {
 					useImmersive.set(true)
 					newArgs.add(commandLine[i])
+				} else if (commandLine[i] == "--background_color") {
+					val colorStr = commandLine[i + 1]
+					try {
+						backgroundColor = colorStr.toColorInt()
+						Log.d(TAG, "background color = $backgroundColor")
+					} catch (e: java.lang.IllegalArgumentException) {
+						Log.d(TAG, "Failed to parse background color: $colorStr")
+					}
+					runOnHostThread {
+						getActivity()?.window?.decorView?.setBackgroundColor(backgroundColor)
+					}
 				} else if (commandLine[i] == "--use_apk_expansion") {
 					useApkExpansion = true
 				} else if (hasExtra && commandLine[i] == "--apk_expansion_md5") {
@@ -459,6 +474,24 @@ class Godot private constructor(val context: Context) {
 	@Keep
 	fun isInEdgeToEdgeMode() = isEdgeToEdge.get()
 
+	fun setSystemBarsAppearance() {
+		val window = getActivity()?.window ?: return
+		val isLight = ColorUtils.calculateLuminance(getWindowBackgroundColor(window)) > 0.5
+
+		val controller = WindowInsetsControllerCompat(window, window.decorView)
+		controller.isAppearanceLightNavigationBars = isLight
+		controller.isAppearanceLightStatusBars = isLight
+	}
+
+	private fun getWindowBackgroundColor(window: Window): Int {
+		val background = window.decorView.background
+		return if (background is ColorDrawable) {
+			background.color
+		} else {
+			backgroundColor
+		}
+	}
+
 	/**
 	 * Used to complete initialization of the view used by the engine for rendering.
 	 *