From 1e1e5036fb3870e51172f02603a99cc3f02aaa7b Mon Sep 17 00:00:00 2001 From: reuk Date: Tue, 22 Jul 2025 15:18:07 +0100 Subject: [PATCH] Android: Fix bug where system bars could incorrectly become opaque after adding/removing desktop components This bug could be observed in the DemoRunner: - Enable "button" navigation mode (as opposed to "gesture" mode) on the Android device. - Remove the line enabling kiosk mode, build and install the DemoRunner. - Run the app and navigate to the Settings pane. Open a menu, or the bluetooth MIDI dialog window, then close the popup window. - Rotate the device. Previously, the steps above could result in the system painting its own backgrounds behind the system bars. With this patch in place, we reset the requested system UI colours and transparency, which seems to maintain the desired appearance. --- .../native/juce_JNIHelpers_android.h | 10 +++++- .../native/juce_Windowing_android.cpp | 36 ++++++++++++++----- 2 files changed, 37 insertions(+), 9 deletions(-) diff --git a/modules/juce_core/native/juce_JNIHelpers_android.h b/modules/juce_core/native/juce_JNIHelpers_android.h index ad2b6b950a..543a11aed0 100644 --- a/modules/juce_core/native/juce_JNIHelpers_android.h +++ b/modules/juce_core/native/juce_JNIHelpers_android.h @@ -674,11 +674,19 @@ DECLARE_JNI_CLASS (AndroidViewGroup, "android/view/ViewGroup") METHOD (getDecorView, "getDecorView", "()Landroid/view/View;") \ METHOD (getAttributes, "getAttributes", "()Landroid/view/WindowManager$LayoutParams;") \ METHOD (setFlags, "setFlags", "(II)V") \ - METHOD (clearFlags, "clearFlags", "(I)V") + METHOD (clearFlags, "clearFlags", "(I)V") \ + METHOD (setStatusBarColor, "setStatusBarColor", "(I)V") \ + METHOD (setNavigationBarColor, "setNavigationBarColor", "(I)V") \ DECLARE_JNI_CLASS (AndroidWindow, "android/view/Window") #undef JNI_CLASS_MEMBERS +#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \ + METHOD (setNavigationBarContrastEnforced, "setNavigationBarContrastEnforced", "(Z)V") \ + +DECLARE_JNI_CLASS_WITH_MIN_SDK (AndroidWindow29, "android/view/Window", 29) +#undef JNI_CLASS_MEMBERS + #define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \ METHOD (getDefaultDisplay, "getDefaultDisplay", "()Landroid/view/Display;") \ METHOD (removeViewImmediate, "removeViewImmediate", "(Landroid/view/View;)V") \ diff --git a/modules/juce_gui_basics/native/juce_Windowing_android.cpp b/modules/juce_gui_basics/native/juce_Windowing_android.cpp index b1446679de..112c01009d 100644 --- a/modules/juce_gui_basics/native/juce_Windowing_android.cpp +++ b/modules/juce_gui_basics/native/juce_Windowing_android.cpp @@ -1365,7 +1365,7 @@ public: AndroidWindowManagerLayoutParams.createDefault) }; if (Desktop::getInstance().getKioskModeComponent() != nullptr) - setNavBarsHidden (true); + refreshSystemBarsAndSetHidden (true); setUpLayoutParams (env, windowLayoutParams, physicalBounds); @@ -1428,6 +1428,7 @@ public: frontWindow = nullptr; removeView(); + setSystemBarsTransparent(); } static void removeViewFromActivity (jobject localView) @@ -1537,7 +1538,7 @@ public: jassertfalse; } - setNavBarsHidden (navBarsHidden); + refreshSystemBarsAndSetHidden (navBarsHidden); } else if (! fullScreen) { @@ -1553,7 +1554,7 @@ public: view.get(), windowLayoutParams.get()); - setNavBarsHidden (navBarsHidden); + refreshSystemBarsAndSetHidden (navBarsHidden); } else { @@ -1635,7 +1636,7 @@ public: void setFullScreen (bool shouldBeFullScreen) override { - setNavBarsHidden (shouldNavBarsBeHidden (shouldBeFullScreen)); + refreshSystemBarsAndSetHidden (shouldNavBarsBeHidden (shouldBeFullScreen)); auto newBounds = std::invoke ([&] { @@ -1832,7 +1833,7 @@ public: handled = app->backButtonPressed(); if (t.isKioskModeComponent()) - t.setNavBarsHidden (t.navBarsHidden); + t.refreshSystemBarsAndSetHidden (t.navBarsHidden); if (! handled) { @@ -1856,7 +1857,7 @@ public: static void handleAppResumedCallback (JNIEnv*, AndroidComponentPeer& t) { if (t.isKioskModeComponent()) - t.setNavBarsHidden (t.navBarsHidden); + t.refreshSystemBarsAndSetHidden (t.navBarsHidden); } static jlong handleGetFocusedTextInputTargetCallback (JNIEnv*, AndroidComponentPeer& t) @@ -2083,7 +2084,7 @@ public: void appStyleChanged() override { - setNavBarsHidden (navBarsHidden); + refreshSystemBarsAndSetHidden (navBarsHidden); } //============================================================================== @@ -2484,7 +2485,7 @@ private: return (shouldBeFullScreen && isKioskModeComponent()); } - void setNavBarsHidden (bool hidden) + void refreshSystemBarsAndSetHidden (bool hidden) { // The system may show the bars again, e.g when navigating away from the app and // back again. Therefore, we should call setSystemUiVisibilityCompat each time to @@ -2495,6 +2496,25 @@ private: activityWindow.get(), (jboolean) ! navBarsHidden, (jboolean) (getAppStyle() == Style::light)); + + setSystemBarsTransparent(); + } + + void setSystemBarsTransparent() + { + if (activityWindow == nullptr) + return; + + auto* env = getEnv(); + + constexpr jint fullyTransparent = 0; + env->CallVoidMethod (activityWindow, AndroidWindow.setStatusBarColor, fullyTransparent); + env->CallVoidMethod (activityWindow, AndroidWindow.setNavigationBarColor, fullyTransparent); + + env->CallVoidMethod (activityWindow, AndroidWindow.setFlags, FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS, FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); + + if (getAndroidSDKVersion() >= 29) + env->CallVoidMethod (activityWindow, AndroidWindow29.setNavigationBarContrastEnforced, (jboolean) false); } template