Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
81 changes: 62 additions & 19 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 @@ -111,6 +119,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 @@ -125,7 +136,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 @@ -180,27 +194,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));
appView.getView().setFilterTouchesWhenObscured(preferences.getBoolean("FilterTouchesWhenObscured", true));
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
15 changes: 10 additions & 5 deletions framework/src/org/apache/cordova/SplashScreenPlugin.java
Original file line number Diff line number Diff line change
Expand Up @@ -128,11 +128,11 @@ protected void pluginInitialize() {
boolean hasCustomSplashscreens = preferences.getBoolean("HasCustomSplashscreens", DEFAULT_HAS_CUSTOM_SPLASHSCREENS);
if (!showSpinner && !hasCustomSplashscreens) {
// Use only the Android Splashscreen API
behaviours.registerBehaviour(new AndroidSplashScreenBehaviour(context, autoHide, delayTime, isFadeEnabled, fadeDuration));
behaviours.registerBehaviour(new AndroidSplashScreenBehaviour(context, autoHide, delayTime, isFadeEnabled, fadeDuration, webView));

} else {
// Using the Android Splashscreen API is mandatory, so we'll try to use it as least as possible
behaviours.registerBehaviour(new AndroidSplashScreenBehaviour(context, true, 1, false, 0));
behaviours.registerBehaviour(new AndroidSplashScreenBehaviour(context, true, 1, false, 0, webView));

// And we'll use the legacy code, from cordova-plugin-splashscreen
Activity activity = cordova.getActivity();
Expand Down Expand Up @@ -237,8 +237,8 @@ private static class AndroidSplashScreenBehaviour implements SplashScreenBehavio

// Internal variables
private boolean keepOnScreen;

public AndroidSplashScreenBehaviour(Context context, boolean autoHide, int delayTime, boolean isFadeEnabled, int fadeDuration) {
CordovaWebView cordovaWebView;
public AndroidSplashScreenBehaviour(Context context, boolean autoHide, int delayTime, boolean isFadeEnabled, int fadeDuration, CordovaWebView cordovaWebView) {
// Context
this.context = context;
// Configuration variables
Expand All @@ -248,6 +248,7 @@ public AndroidSplashScreenBehaviour(Context context, boolean autoHide, int delay
this.fadeDuration = fadeDuration;
// Internal variables
this.keepOnScreen = true;
this.cordovaWebView = cordovaWebView;
}

@Override
Expand Down Expand Up @@ -322,11 +323,15 @@ public void onSplashScreenExit(@NonNull SplashScreenViewProvider splashScreenVie
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
splashScreenViewProvider.remove();
cordovaWebView.getPluginManager().postMessage("updateSystemBars", null);
}
}).start();
}
});
} else {
cordovaWebView.getPluginManager().postMessage("updateSystemBars", null);
}

}

private void attemptCloseOnPageFinished() {
Expand Down Expand Up @@ -691,4 +696,4 @@ public void run() {
});
}
}
}
}
Loading