Skip to content
4 changes: 4 additions & 0 deletions cordova-js-src/platform.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ module.exports = {
// Core Splash Screen
modulemapper.clobbers('cordova/plugin/android/splashscreen', 'navigator.splashscreen');

// Attach the internal statusBar utility to window.statusbar
// see the file under plugin/android/statusbar.js
modulemapper.clobbers('cordova/plugin/android/statusbar', 'window.statusbar');

var APP_PLUGIN_NAME = Number(cordova.platformVersion.split('.')[0]) >= 4 ? 'CoreAndroid' : 'App';

// Inject a listener for the backbutton on the document.
Expand Down
86 changes: 86 additions & 0 deletions cordova-js-src/plugin/android/statusbar.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/

var exec = require('cordova/exec');

var statusBarVisible = true;
var statusBar = {};

Object.defineProperty(statusBar, 'visible', {
configurable: false,
enumerable: true,
get: function () {
if (window.StatusBar) {
// try to let the StatusBar plugin handle it
return window.StatusBar.isVisible;
}

return statusBarVisible;
},
set: function (value) {
if (window.StatusBar) {
// try to let the StatusBar plugin handle it
if (value) {
window.StatusBar.show();
} else {
window.StatusBar.hide();
}
} else {
statusBarVisible = value;
exec(null, null, 'SystemBarPlugin', 'setStatusBarVisible', [!!value]);
}
}
});

Object.defineProperty(statusBar, 'setBackgroundColor', {
configurable: false,
enumerable: false,
writable: false,
value: function (value) {
var script = document.querySelector('script[src$="cordova.js"]');
script.style.color = value;
var rgbStr = window.getComputedStyle(script).getPropertyValue('color');

if (!rgbStr.match(/^rgb/)) { return; }

var rgbVals = rgbStr.match(/\d+/g).map(function (v) { return parseInt(v, 10); });

if (rgbVals.length < 3) {
return;
} else if (rgbVals.length === 3) {
rgbVals = [255].concat(rgbVals);
}

const padRgb = (val) => val.toString(16).padStart(2, '0');
const a = padRgb(rgbVals[0]);
const r = padRgb(rgbVals[1]);
const g = padRgb(rgbVals[2]);
const b = padRgb(rgbVals[3]);
const hexStr = '#' + a + r + g + b;

if (window.StatusBar) {
window.StatusBar.backgroundColorByHexString(hexStr);
} else {
exec(null, null, 'SystemBarPlugin', 'setStatusBarBackgroundColor', rgbVals);
}
}
});

module.exports = statusBar;
8 changes: 8 additions & 0 deletions framework/src/org/apache/cordova/ConfigXmlParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,14 @@ public void parse(Context action) {
)
);

pluginEntries.add(
new PluginEntry(
SystemBarPlugin.PLUGIN_NAME,
"org.apache.cordova.SystemBarPlugin",
true
)
);

pluginEntries.add(
new PluginEntry(
SplashScreenPlugin.PLUGIN_NAME,
Expand Down
80 changes: 62 additions & 18 deletions framework/src/org/apache/cordova/CordovaActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,10 @@ Licensed to the Apache Software Foundation (ASF) under one
import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.Configuration;
import android.graphics.Color;
import android.media.AudioManager;
import android.os.Build;
import android.os.Bundle;
import android.view.Gravity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
Expand All @@ -42,7 +43,11 @@ Licensed to the Apache Software Foundation (ASF) under one
import android.widget.FrameLayout;

import androidx.appcompat.app.AppCompatActivity;
import androidx.core.graphics.Insets;
import androidx.core.splashscreen.SplashScreen;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowCompat;
import androidx.core.view.WindowInsetsCompat;

/**
* This class is the main Android activity that represents the Cordova
Expand Down Expand Up @@ -100,6 +105,9 @@ public class CordovaActivity extends AppCompatActivity {

private SplashScreen splashScreen;

private boolean canEdgeToEdge = false;
private boolean isFullScreen = false;

/**
* Called when the activity is first created.
*/
Expand All @@ -113,6 +121,9 @@ public void onCreate(Bundle savedInstanceState) {
// need to activate preferences before super.onCreate to avoid "requestFeature() must be called before adding content" exception
loadConfig();

canEdgeToEdge = preferences.getBoolean("AndroidEdgeToEdge", false)
&& Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM;

String logLevel = preferences.getString("loglevel", "ERROR");
LOG.setLogLevel(logLevel);

Expand All @@ -127,7 +138,10 @@ public void onCreate(Bundle savedInstanceState) {
LOG.d(TAG, "The SetFullscreen configuration is deprecated in favor of Fullscreen, and will be removed in a future version.");
preferences.set("Fullscreen", true);
}
if (preferences.getBoolean("Fullscreen", false)) {

isFullScreen = preferences.getBoolean("Fullscreen", false);

if (isFullScreen) {
// NOTE: use the FullscreenNotImmersive configuration key to set the activity in a REAL full screen
// (as was the case in previous cordova versions)
if (!preferences.getBoolean("FullscreenNotImmersive", false)) {
Expand Down Expand Up @@ -184,26 +198,56 @@ protected void loadConfig() {
//Suppressing warnings in AndroidStudio
@SuppressWarnings({"deprecation", "ResourceType"})
protected void createViews() {
//Why are we setting a constant as the ID? This should be investigated
appView.getView().setId(100);
appView.getView().setLayoutParams(new FrameLayout.LayoutParams(
WindowCompat.setDecorFitsSystemWindows(getWindow(), false);

// Root FrameLayout
FrameLayout rootLayout = new FrameLayout(this);
rootLayout.setLayoutParams(new FrameLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT));
ViewGroup.LayoutParams.MATCH_PARENT
));

setContentView(appView.getView());
// WebView
View webView = appView.getView();
webView.setLayoutParams(new FrameLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
));

// Create StatusBar view that will overlay the top inset
View statusBarView = new View(this);
statusBarView.setTag("statusBarView");

// Handle Window Insets
ViewCompat.setOnApplyWindowInsetsListener(rootLayout, (v, insets) -> {
Insets bars = insets.getInsets(
WindowInsetsCompat.Type.systemBars() | WindowInsetsCompat.Type.displayCutout()
);

boolean isStatusBarVisible = statusBarView.getVisibility() != View.GONE;
int top = isStatusBarVisible && !canEdgeToEdge && !isFullScreen ? bars.top : 0;
int bottom = !canEdgeToEdge && !isFullScreen ? bars.bottom : 0;

FrameLayout.LayoutParams webViewParams = (FrameLayout.LayoutParams) webView.getLayoutParams();
webViewParams.setMargins(bars.left, top, bars.right, bottom);
webView.setLayoutParams(webViewParams);

FrameLayout.LayoutParams statusBarParams = new FrameLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
top,
Gravity.TOP
);
statusBarView.setLayoutParams(statusBarParams);

return insets;
});

if (preferences.contains("BackgroundColor")) {
try {
int backgroundColor = preferences.getInteger("BackgroundColor", Color.BLACK);
// Background of activity:
appView.getView().setBackgroundColor(backgroundColor);
}
catch (NumberFormatException e){
e.printStackTrace();
}
}
rootLayout.addView(webView);
rootLayout.addView(statusBarView);

appView.getView().requestFocusFromTouch();
setContentView(rootLayout);
rootLayout.post(() -> ViewCompat.requestApplyInsets(rootLayout));
webView.requestFocusFromTouch();
}

/**
Expand Down
3 changes: 3 additions & 0 deletions framework/src/org/apache/cordova/SplashScreenPlugin.java
Original file line number Diff line number Diff line change
Expand Up @@ -155,10 +155,13 @@ public void onSplashScreenExit(@NonNull SplashScreenViewProvider splashScreenVie
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
splashScreenViewProvider.remove();
webView.getPluginManager().postMessage("updateSystemBars", null);
}
}).start();
}
});
} else {
webView.getPluginManager().postMessage("updateSystemBars", null);
}
}

Expand Down
Loading
Loading