Skip to content

Commit

Permalink
feat!: android 12 splash screen (#1441)
Browse files Browse the repository at this point in the history
* chore!: remove old splashscreen logic
* feat(splashscreen): add backwards compatibility
* chore: remove unused method
* chore: prefix splashscreen_background with cdv_
* feat: support android 12 splashscreen api configs
* feat: improve & refactor the logic for android splashscreen api 12
* feat: splashscreen copy image resources
* feat: splashscreen branding image & xml cleanup
* fix: splashscreen cleanup & branding conditions
* fix: splashscreen @color usage
* feat: update default Apache Cordova splash screen
* chore: add missing asf header
* fix: splashscreen image size
* chore: use Theme.SplashScreen.IconBackground as default parent to support windowSplashScreenIconBackgroundColor
* fix: center default test image by correct pivot
* fix: fs-extra copySync
* feat: re-add AutoHideSplashScreen and SplashScreenDelay preference support
* chore: move splashscreen into CordovaActivity
* feat: support splashscreen.hide & centralize to SplashScreenPlugin
* chore: cleanup SplashScreenPlugin
* feat: support fade, default auto hide on onPageFinished, support delays, refactor
* refactor: cleanup splash screen
* refactor: cleanup remove unused import
* chore: add show method as unsupported
* test: create a spy on updateProjectSplashScreen
* style: add ending new line
* chore: improve logging to warn when image path is missing
* chore: split windowSplashScreenAnimatedIcon and windowSplashScreenBrandingImage case and added branding warning
* chore: improve when to display warning
* fix: add splashscreen dependency to app as well
* chore: move the core-splashscreen dep lower

Co-authored-by: Niklas Merz <niklasmerz@linux.com>
  • Loading branch information
erisu and NiklasMerz authored Jun 30, 2022
1 parent 2d2ad4c commit 606e9c4
Show file tree
Hide file tree
Showing 30 changed files with 605 additions and 221 deletions.
3 changes: 3 additions & 0 deletions cordova-js-src/platform.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ module.exports = {
// TODO: Extract this as a proper plugin.
modulemapper.clobbers('cordova/plugin/android/app', 'navigator.app');

// Core Splash Screen
modulemapper.clobbers('cordova/plugin/android/splashscreen', 'navigator.splashscreen');

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

// Inject a listener for the backbutton on the document.
Expand Down
33 changes: 33 additions & 0 deletions cordova-js-src/plugin/android/splashscreen.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
*
* 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 splashscreen = {
show: function () {
console.log('"navigator.splashscreen.show()" is unsupported on Android.');
},
hide: function () {
exec(null, null, 'CordovaSplashScreenPlugin', 'hide', []);
}
};

module.exports = splashscreen;
1 change: 1 addition & 0 deletions framework/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ android {
dependencies {
implementation "androidx.appcompat:appcompat:${cordovaConfig.ANDROIDX_APP_COMPAT_VERSION}"
implementation "androidx.webkit:webkit:${cordovaConfig.ANDROIDX_WEBKIT_VERSION}"
implementation "androidx.core:core-splashscreen:${cordovaConfig.ANDROIDX_CORE_SPLASHSCREEN_VERSION}"
}

/**
Expand Down
1 change: 1 addition & 0 deletions framework/cdv-gradle-config-defaults.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"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
Expand Down
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 @@ -76,6 +76,14 @@ public void parse(Context action) {
)
);

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

parse(action.getResources().getXml(id));
}

Expand Down
12 changes: 9 additions & 3 deletions framework/src/org/apache/cordova/CordovaActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ Licensed to the Apache Software Foundation (ASF) under one
import android.widget.FrameLayout;

import androidx.appcompat.app.AppCompatActivity;
import androidx.core.splashscreen.SplashScreen;

/**
* This class is the main Android activity that represents the Cordova
Expand Down Expand Up @@ -98,11 +99,16 @@ public class CordovaActivity extends AppCompatActivity {
protected ArrayList<PluginEntry> pluginEntries;
protected CordovaInterfaceImpl cordovaInterface;

private SplashScreen splashScreen;

/**
* Called when the activity is first created.
*/
@Override
public void onCreate(Bundle savedInstanceState) {
// Handle the splash screen transition.
splashScreen = SplashScreen.installSplashScreen(this);

// need to activate preferences before super.onCreate to avoid "requestFeature() must be called before adding content" exception
loadConfig();

Expand All @@ -125,8 +131,6 @@ public void onCreate(Bundle savedInstanceState) {
// (as was the case in previous cordova versions)
if (!preferences.getBoolean("FullscreenNotImmersive", false)) {
immersiveMode = true;
// The splashscreen plugin needs the flags set before we're focused to prevent
// the nav and title bars from flashing in.
setImmersiveUiVisibility();
} else {
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
Expand All @@ -153,6 +157,9 @@ protected void init() {
}
cordovaInterface.onCordovaInit(appView.getPluginManager());

// Setup the splash screen based on preference settings
cordovaInterface.pluginManager.postMessage("setupSplashScreen", splashScreen);

// Wire the hardware volume controls to control media if desired.
String volumePref = preferences.getString("DefaultVolumeStream", "");
if ("media".equals(volumePref.toLowerCase(Locale.ENGLISH))) {
Expand Down Expand Up @@ -526,5 +533,4 @@ public void onRequestPermissionsResult(int requestCode, String permissions[],
}

}

}
168 changes: 168 additions & 0 deletions framework/src/org/apache/cordova/SplashScreenPlugin.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
/*
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.
*/

package org.apache.cordova;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.annotation.SuppressLint;
import android.os.Handler;
import android.view.View;
import android.view.animation.AccelerateInterpolator;

import androidx.annotation.NonNull;
import androidx.core.splashscreen.SplashScreen;
import androidx.core.splashscreen.SplashScreenViewProvider;

import org.json.JSONArray;
import org.json.JSONException;

@SuppressLint("LongLogTag")
public class SplashScreenPlugin extends CordovaPlugin {
static final String PLUGIN_NAME = "CordovaSplashScreenPlugin";

// Default config preference values
private static final boolean DEFAULT_AUTO_HIDE = true;
private static final int DEFAULT_DELAY_TIME = -1;
private static final boolean DEFAULT_FADE = true;
private static final int DEFAULT_FADE_TIME = 500;

// Config preference values
/**
* @param boolean autoHide to auto splash screen (default=true)
*/
private boolean autoHide;
/**
* @param int delayTime in milliseconds (default=-1)
*/
private int delayTime;
/**
* @param int fade to fade out splash screen (default=true)
*/
private boolean isFadeEnabled;
/**
* @param int fadeDuration fade out duration in milliseconds (default=500)
*/
private int fadeDuration;

// Internal variables
/**
* @param boolean keepOnScreen flag to determine if the splash screen remains visible.
*/
private boolean keepOnScreen = true;

@Override
protected void pluginInitialize() {
// Auto Hide & Delay Settings
autoHide = preferences.getBoolean("AutoHideSplashScreen", DEFAULT_AUTO_HIDE);
delayTime = preferences.getInteger("SplashScreenDelay", DEFAULT_DELAY_TIME);
LOG.d(PLUGIN_NAME, "Auto Hide: " + autoHide);
if (delayTime != DEFAULT_DELAY_TIME) {
LOG.d(PLUGIN_NAME, "Delay: " + delayTime + "ms");
}

// Fade & Fade Duration
isFadeEnabled = preferences.getBoolean("FadeSplashScreen", DEFAULT_FADE);
fadeDuration = preferences.getInteger("FadeSplashScreenDuration", DEFAULT_FADE_TIME);
LOG.d(PLUGIN_NAME, "Fade: " + isFadeEnabled);
if (isFadeEnabled) {
LOG.d(PLUGIN_NAME, "Fade Duration: " + fadeDuration + "ms");
}
}

@Override
public boolean execute(
String action,
JSONArray args,
CallbackContext callbackContext
) throws JSONException {
if (action.equals("hide") && autoHide == false) {
/*
* The `.hide()` method can only be triggered if the `splashScreenAutoHide`
* is set to `false`.
*/
keepOnScreen = false;
} else {
return false;
}

callbackContext.success();
return true;
}

@Override
public Object onMessage(String id, Object data) {
switch (id) {
case "setupSplashScreen":
setupSplashScreen((SplashScreen) data);
break;

case "onPageFinished":
attemptCloseOnPageFinished();
break;
}

return null;
}

private void setupSplashScreen(SplashScreen splashScreen) {
// Setup Splash Screen Delay
splashScreen.setKeepOnScreenCondition(() -> keepOnScreen);

// auto hide splash screen when custom delay is defined.
if (autoHide && delayTime != DEFAULT_DELAY_TIME) {
Handler splashScreenDelayHandler = new Handler();
splashScreenDelayHandler.postDelayed(() -> keepOnScreen = false, delayTime);
}

// auto hide splash screen with default delay (-1) delay is controlled by the
// `onPageFinished` message.

// If auto hide is disabled (false), the hiding of the splash screen must be determined &
// triggered by the front-end code with the `navigator.splashscreen.hide()` method.

// Setup the fade
splashScreen.setOnExitAnimationListener(new SplashScreen.OnExitAnimationListener() {
@Override
public void onSplashScreenExit(@NonNull SplashScreenViewProvider splashScreenViewProvider) {
View splashScreenView = splashScreenViewProvider.getView();

splashScreenView
.animate()
.alpha(0.0f)
.setDuration(isFadeEnabled ? fadeDuration : 0)
.setStartDelay(isFadeEnabled ? 0 : fadeDuration)
.setInterpolator(new AccelerateInterpolator())
.setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
splashScreenViewProvider.remove();
}
}).start();
}
});
}

private void attemptCloseOnPageFinished() {
if (autoHide && delayTime == DEFAULT_DELAY_TIME) {
keepOnScreen = false;
}
}
}
2 changes: 2 additions & 0 deletions lib/Api.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ class Api {
configXml: path.join(appRes, 'xml', 'config.xml'),
defaultConfigXml: path.join(this.root, 'cordova', 'defaults.xml'),
strings: path.join(appRes, 'values', 'strings.xml'),
themes: path.join(appRes, 'values', 'themes.xml'),
colors: path.join(appRes, 'values', 'colors.xml'),
manifest: path.join(appMain, 'AndroidManifest.xml'),
build: path.join(this.root, 'build'),
javaSrc: path.join(appMain, 'java')
Expand Down
Loading

0 comments on commit 606e9c4

Please sign in to comment.