apache / cordova-plugin-statusbar

Apache Cordova Status Bar Plugin
https://cordova.apache.org/
Apache License 2.0
618 stars 480 forks source link

Plugin not working on Android 13 with cordova Android@11.0.0 #256

Closed nijakobius closed 1 year ago

nijakobius commented 1 year ago

Bug Report

First of all, a big thank you to everybody contributing to Cordova <3

Problem

If I add the android platform via cordova platform add android@11.0.0, the plugin does not work on Android Studio's Simulator with Android 13.

What is expected to happen?

I am using the following code in index.js to get a transparent status bar that randomly changes text color every 1s (just to test the plugin):

document.addEventListener('deviceready', () => {
  StatusBar.overlaysWebView(true); // For some reason <preference name="StatusBarOverlaysWebView" value="true" /> in config.xml doesn't work
  setInterval(() => {
    if(Math.random() > .5) { StatusBar.styleDefault(); } else { StatusBar.styleLightContent(); }
  }, 1000);
}, false);

This works in the simulator for the following Android versions: API 32 - Android 12 API 30 - Android 11 API 29 - Android 10 API 28 - Android 9 API 27 - Android 8.1 API 25 - Android 7.1.1

What does actually happen?

..but it doesn't work for "API 33 - Android 13". Instead the status bar just stays the default white text on black background.

Information

I'm in a 100% clean project from cordova create hello com.example.hello HelloWorld as per the Docs.

If I add android@10.1.2 instead of android@11.0.0, the plugin works on Android 13 just like on the other virtual device.

Environment, Platform, Device, Version information

cordova-plugin-statusbar 3.0.0 Cordova Android 11.0.0 Cordova CLI 11.0.0 Android Studio Dolphin | 2021.3.1 macOS Monterrey 12.6

Some more info from cdv-gradle-config.json:

{
  "MIN_SDK_VERSION": 22,
  "SDK_VERSION": 32,
  "COMPILE_SDK_VERSION": null,
  "GRADLE_VERSION": "7.4.2",
  "MIN_BUILD_TOOLS_VERSION": "32.0.0",
  "AGP_VERSION": "7.2.1",
  "KOTLIN_VERSION": "1.5.21",
  "ANDROIDX_APP_COMPAT_VERSION": "1.4.2",
  "ANDROIDX_WEBKIT_VERSION": "1.4.0",
  "ANDROIDX_CORE_SPLASHSCREEN_VERSION": "1.0.0-rc01",
  "GRADLE_PLUGIN_GOOGLE_SERVICES_VERSION": "4.3.10",
  "IS_GRADLE_PLUGIN_GOOGLE_SERVICES_ENABLED": false,
  "IS_GRADLE_PLUGIN_KOTLIN_ENABLED": false
}
jcesarmobile commented 1 year ago

This is fixed but not released yet, see https://github.com/apache/cordova-plugin-statusbar/pull/238

erisu commented 1 year ago

@jcesarmobile I think the main issue reported here is slightly differnet from PR #238.

I did some investigation a few weeks ago and never figured it out, until I read the in-code comment:

// For some reason in config.xml doesn't work

There is actually quit a few issues:

Issue 1: The initialize method, calls in order setStatusBarTransparent then setStatusBarBackgroundColor. I beleive setStatusBarTransparent should be placed below setStatusBarBackgroundColor

Both methods calls window.setStatusBarColor(); but in the end, if the user defines a background color or not, the statusbar will never be set to transparent based on config.xml settings.

Issue 2: Deprcated flags still used. This doesnt cause the issue, but should be fixed either way.

Issue 3: The main issue that I identified from the above comment is that none of the code from the initialize method's activity.runOnUiThread(() -> {}) block is applied.

It seems to be related to the fall back to the Android 12 Splash Screen.

new Thread(() -> {
    try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}
    activity.runOnUiThread(() -> {});
}

Basically if I wrap the code with a delay, as shown above, then it works as expectetd. The splashscreen is about 3 seconds give or take. But there are cases where people could lock the splashscreen longer during loading, or it ends faster.

Obviously a delay is not the solution.

It was just apart of the example to identify the timing issue. It seems the settings are not applied while the Spalsh Screen is visible or applied to the wrong Activity. Once the Splash Screen is hidden, the statusbar appears to be default to what was defined in @style/Theme.AppCompat.NoActionBar

I am not sure how we would go about setting the proper timing to execute the activity.runOnUiThread(() -> {});

jcesarmobile commented 1 year ago

The issue is about StatusBar.styleDefault(); not working, that is fixed in master but not released. The thing about preference not working in config.xml is just a comment, but not critical to the issue reported.

preferences not working are related to the splash screen animation listener, I sent a PR two weeks ago that would allow to disable the animation listener when FadeSplashScreen is false. https://github.com/apache/cordova-android/pull/1506

erisu commented 1 year ago

OK I just reviewed and approved the https://github.com/apache/cordova-android/pull/1506 PR.

What happens if they configure the SplashScreen fade? Wont it just cause the StatusBar preferences not working again?

jcesarmobile commented 1 year ago

yeah, it's more like a workaround than a real fix, but I don't think it can be fixed, looks like just another Android bug with the new Splash Screen that only Google can fix. My thought is that the Android source code is picking the status bar UI settings before the animation starts and restoring them when it finishes, so any change we make in between will be overwritten.

erisu commented 1 year ago

I was wonder if we could dummy down the plugin to build the xml theme overrides instead of doing things logicially?

<resources>
    <style name="Theme.Cdv" parent="Theme.AppCompat.NoActionBar">
        <item name="colorPrimary">@color/color_primary</item>
        <item name="colorPrimaryDark">@color/color_secondary</item>
        <item name="colorAccent">@color/color_accent</item>
        <item name="android:statusBarColor">@color/color_primary</item>
    </style>
</resources>

Not sure if this would work, but I had a feeling that when the Splash Screen complete, it changes the Activity theme back to the defined postSplashScreenTheme which might be where black color defined as the default.

Obviously, if the end-user decides to change the postSplashScreenTheme to something custom, they must define the statusBar information as well.

jcesarmobile commented 1 year ago

That might fix the statusbar background/text color, but the overlaysWebView does more than that, it sets the view full screen and I think the behavior is different than when you set it form a theme.

Also, I wouldn't make the statusbar plugin edit the themes, I think that should be part of cordova-android (if it isn't already) and we could document it on the splash screen preferences as Android 12+ quirks. (it also affects Android 12 when launched from the app icon)

erisu commented 1 year ago

I think that should be part of cordova-android (if it isn't already)

Yeah, I dont think the theme is ever configured by us.

Also I think we might be eventually integrating the StatusBar plugin into core of each platform... This type of change could come at that moment maybe..

nijakobius commented 1 year ago

I found a solution! ..or rather a workaround.

1. Add this to config.xml:

<platform name="android">
    <preference name="AndroidPostSplashScreenTheme" value="@style/Theme.MyCustomTheme" />
    <resource-file src="res/android/values/styles.xml" target="/app/src/main/res/values/styles.xml"/>
</platform>

2. Create res/android/values/styles.xml with the following contents:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <style name="Theme.MyCustomTheme" parent="Theme.AppCompat.NoActionBar">
        <item name="android:statusBarColor">@android:color/transparent</item>
    </style>
</resources>

Before:

Screenshot 2022-10-28 at 16 23 53

After:

Screenshot 2022-10-28 at 16 18 45
nijakobius commented 1 year ago

Okay damn, this way I cannot change the color of the status bar text via JavaScript. I use something like this:

if(theme == 'dark') {
    StatusBar.styleLightContent(); // White text if the background is light
} else {
    StatusBar.styleDefault(); // Black text if the background is dark
}

...because my app has a dark and a light mode. If the user changes the mode, the app needs to change the status bar text color via JavaScript.