You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by pu...@apache.org on 2016/04/22 22:36:19 UTC

cordova-windows git commit: CB-8056 Implement splashscreen for Windows platform

Repository: cordova-windows
Updated Branches:
  refs/heads/master 57115182e -> d6988f5c8


CB-8056 Implement splashscreen for Windows platform

Updated version to 5.0.0


Project: http://git-wip-us.apache.org/repos/asf/cordova-windows/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-windows/commit/d6988f5c
Tree: http://git-wip-us.apache.org/repos/asf/cordova-windows/tree/d6988f5c
Diff: http://git-wip-us.apache.org/repos/asf/cordova-windows/diff/d6988f5c

Branch: refs/heads/master
Commit: d6988f5c863ec3ba5cde33a678a4b93badc64395
Parents: 5711518
Author: daserge <v-...@microsoft.com>
Authored: Wed Jan 20 22:00:56 2016 +0300
Committer: daserge <v-...@microsoft.com>
Committed: Fri Apr 22 18:17:59 2016 +0300

----------------------------------------------------------------------
 VERSION                           |   2 +-
 bin/lib/create.js                 |   4 +
 cordova-js-src/confighelper.js    |  89 +++++++
 cordova-js-src/platform.js        |  36 ++-
 cordova-js-src/splashscreen.js    | 340 +++++++++++++++++++++++++
 package.json                      |   2 +-
 template/www/cordova.js           | 441 ++++++++++++++++++++++++++++++++-
 template/www/css/splashscreen.css |  75 ++++++
 8 files changed, 978 insertions(+), 11 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-windows/blob/d6988f5c/VERSION
----------------------------------------------------------------------
diff --git a/VERSION b/VERSION
index 7075368..0062ac9 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-4.4.0-dev
+5.0.0

http://git-wip-us.apache.org/repos/asf/cordova-windows/blob/d6988f5c/bin/lib/create.js
----------------------------------------------------------------------
diff --git a/bin/lib/create.js b/bin/lib/create.js
index 899d4f4..61b84f8 100644
--- a/bin/lib/create.js
+++ b/bin/lib/create.js
@@ -59,6 +59,10 @@ module.exports.create = function (destinationDir, config, options) {
 
     // Duplicate cordova.js to platform_www otherwise it will get removed by prepare
     shell.cp('-rf', path.join(root, 'template/www/cordova.js'), path.join(projectPath, 'platform_www'));
+    // Duplicate splashscreen.css to platform_www otherwise it will get removed by prepare
+    var cssDirectory = path.join(projectPath, 'platform_www', 'css');
+    recursiveCreateDirectory(cssDirectory);
+    shell.cp('-rf', path.join(root, 'template/www/css/splashscreen.css'), cssDirectory);
 
     // Copy cordova-js-src directory
     events.emit('verbose', 'Copying cordova-js sources to platform_www');

http://git-wip-us.apache.org/repos/asf/cordova-windows/blob/d6988f5c/cordova-js-src/confighelper.js
----------------------------------------------------------------------
diff --git a/cordova-js-src/confighelper.js b/cordova-js-src/confighelper.js
new file mode 100644
index 0000000..70c878d
--- /dev/null
+++ b/cordova-js-src/confighelper.js
@@ -0,0 +1,89 @@
+/*
+ *
+ * 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.
+ *
+*/
+
+// config.xml wrapper (non-node ConfigParser analogue)
+var config;
+function Config(xhr) {
+    function loadPreferences(xhr) {
+        var parser = new DOMParser();
+        var doc = parser.parseFromString(xhr.responseText, "application/xml");
+
+        var preferences = doc.getElementsByTagName("preference");
+        return Array.prototype.slice.call(preferences);
+    }
+
+    this.xhr = xhr;
+    this.preferences = loadPreferences(this.xhr);
+}
+
+function readConfig(success, error) {
+    var xhr;
+
+    if (typeof config != 'undefined') {
+        success(config);
+    }
+
+    function fail(msg) {
+        console.error(msg);
+
+        if (error) {
+            error(msg);
+        }
+    }
+
+    var xhrStatusChangeHandler = function () {
+        if (xhr.readyState == 4) {
+            if (xhr.status == 200 || xhr.status == 304 || xhr.status == 0 /* file:// */) {
+                config = new Config(xhr);
+                success(config);
+            }
+            else {
+                fail('[Windows][cordova.js][xhrStatusChangeHandler] Could not XHR config.xml: ' + xhr.statusText);
+            }
+        }
+    };
+
+    xhr = new XMLHttpRequest();
+    xhr.addEventListener("load", xhrStatusChangeHandler);
+
+    try {
+        xhr.open("get", "../config.xml", true);
+        xhr.send();
+    } catch (e) {
+        fail('[Windows][cordova.js][readConfig] Could not XHR config.xml: ' + JSON.stringify(e));
+    }
+}
+
+/**
+ * Reads a preference value from config.xml.
+ * Returns preference value or undefined if it does not exist.
+ * @param {String} preferenceName Preference name to read */
+Config.prototype.getPreferenceValue = function getPreferenceValue(preferenceName) {
+    var preferenceItem = this.preferences && this.preferences.filter(function (item) {
+        return item.attributes['name'].value === preferenceName;
+    });
+
+    if (preferenceItem && preferenceItem[0] && preferenceItem[0].attributes && preferenceItem[0].attributes['value']) {
+        return preferenceItem[0].attributes['value'].value;
+    }
+}
+
+exports.readConfig = readConfig;

http://git-wip-us.apache.org/repos/asf/cordova-windows/blob/d6988f5c/cordova-js-src/platform.js
----------------------------------------------------------------------
diff --git a/cordova-js-src/platform.js b/cordova-js-src/platform.js
index 4350c14..f8764be 100644
--- a/cordova-js-src/platform.js
+++ b/cordova-js-src/platform.js
@@ -26,7 +26,8 @@ module.exports = {
             exec = require('cordova/exec'),
             channel = cordova.require('cordova/channel'),
             platform = require('cordova/platform'),
-            modulemapper = require('cordova/modulemapper');
+            modulemapper = require('cordova/modulemapper'),
+            configHelper = require('cordova/confighelper');
 
         modulemapper.clobbers('cordova/exec/proxy', 'cordova.commandProxy');
 
@@ -38,7 +39,11 @@ module.exports = {
         channel.onNativeReady.fire();
 
         var onWinJSReady = function () {
-            var app = WinJS.Application;
+            var app = WinJS.Application,
+                splashscreen = require('cordova/splashscreen');
+
+            modulemapper.clobbers('cordova/splashscreen', 'navigator.splashscreen');
+
             var checkpointHandler = function checkpointHandler() {
                 cordova.fireDocumentEvent('pause',null,true);
             };
@@ -54,7 +59,27 @@ module.exports = {
                 var args = e.detail.arguments;
                 var actType = e.detail.type;
                 platform.activationContext = { type: actType, args: args };
-                cordova.fireDocumentEvent('activated', platform.activationContext, true);
+
+                function makePromise(fn) {
+                    return new WinJS.Promise(function init(completeDispatch, errorDispatch) {
+                        fn(function successCb(results) {
+                            completeDispatch(results);
+                        }, function errorCb(error) {
+                            errorDispatch(error);
+                        });
+                    });
+                }
+
+                e.setPromise(makePromise(configHelper.readConfig).then(function (config) {
+                    if (e.detail.previousExecutionState !== Windows.ApplicationModel.Activation.ApplicationExecutionState.running) {
+                        splashscreen.firstShow(config, e);
+                    }
+                }).then(function () {
+                    // Avoids splashimage flicker on Windows Phone 8.1/10
+                    return WinJS.Promise.timeout();
+                }).then(function () {
+                    cordova.fireDocumentEvent('activated', platform.activationContext, true);
+                }));
             };
 
             app.addEventListener("checkpoint", checkpointHandler);
@@ -66,6 +91,11 @@ module.exports = {
             app.start();
         };
 
+        function appendScript(scriptElem, loadedCb) {
+            scriptElem.addEventListener("load", loadedCb);
+            document.head.appendChild(scriptElem);
+        }
+
         if (!window.WinJS) {
             var scriptElem = document.createElement("script");
 

http://git-wip-us.apache.org/repos/asf/cordova-windows/blob/d6988f5c/cordova-js-src/splashscreen.js
----------------------------------------------------------------------
diff --git a/cordova-js-src/splashscreen.js b/cordova-js-src/splashscreen.js
new file mode 100644
index 0000000..fcdefdf
--- /dev/null
+++ b/cordova-js-src/splashscreen.js
@@ -0,0 +1,340 @@
+/*
+ *
+ * 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 isPhone = (cordova.platformId == 'windows') && WinJS.Utilities.isPhone;
+var isWp81 = navigator.appVersion.indexOf("Windows Phone 8.1") !== -1;
+var isWp10 = navigator.appVersion.indexOf("Windows Phone 10") !== -1;
+var isWin10UWP = navigator.appVersion.indexOf('MSAppHost/3.0') !== -1;
+var isHosted = window.location.protocol.indexOf('http') === 0;
+var splashImageSrc = ((isHosted || isWin10UWP) ? 'ms-appx-web' : 'ms-appx') + ':///images/'
+    + (isPhone ? 'splashscreenphone.png' : 'splashscreen.png');
+
+var splashElement = null, extendedSplashImage = null, extendedSplashProgress = null;
+
+//// <Config and initialization>
+var DEFAULT_SPLASHSCREEN_DURATION = 3000, // in milliseconds
+    FPS = 60, // frames per second used by requestAnimationFrame
+    PROGRESSRING_HEIGHT = 40,
+    PROGRESSRING_BOTTOM_MARGIN = 10; // needed for windows 10 min height window
+
+var bgColor = "#464646",
+    autoHideSplashScreen = true,
+    splashScreenDelay = DEFAULT_SPLASHSCREEN_DURATION,
+    fadeSplashScreen = true,
+    fadeSplashScreenDuration = DEFAULT_SPLASHSCREEN_DURATION,
+    showSplashScreenSpinner = true,
+    splashScreenSpinnerColor; // defaults to system accent color
+
+var effectiveSplashDuration;
+
+function readBoolFromCfg(preferenceName, defaultValue, cfg) {
+    var value = cfg.getPreferenceValue(preferenceName);
+    if (typeof value !== 'undefined') {
+        return value === 'true';
+    } else {
+        return defaultValue;
+    }
+}
+
+function readPreferencesFromCfg(cfg) {
+    try {
+        bgColor = cfg.getPreferenceValue('SplashScreenBackgroundColor') || bgColor;
+        bgColor = bgColor.replace('0x', '#').replace('0X', '#');
+        if (bgColor.length > 7) {
+            // Remove aplha
+            bgColor = bgColor.slice(0, 1) + bgColor.slice(3, bgColor.length);
+        }
+
+        autoHideSplashScreen = readBoolFromCfg('AutoHideSplashScreen', autoHideSplashScreen, cfg);
+        splashScreenDelay = cfg.getPreferenceValue('SplashScreenDelay') || splashScreenDelay;
+
+        fadeSplashScreen = readBoolFromCfg('FadeSplashScreen', fadeSplashScreen, cfg);
+        fadeSplashScreenDuration = cfg.getPreferenceValue('FadeSplashScreenDuration') || fadeSplashScreenDuration;
+
+        showSplashScreenSpinner = readBoolFromCfg('ShowSplashScreenSpinner', showSplashScreenSpinner, cfg);
+        splashScreenSpinnerColor = cfg.getPreferenceValue('SplashScreenSpinnerColor');
+
+        effectiveSplashDuration = Math.max(splashScreenDelay - fadeSplashScreenDuration, 0);
+    } catch (e) {
+        var msg = '[Windows][SplashScreen] Error occured on loading preferences from config.xml: ' + JSON.stringify(e);
+        console.error(msg);
+    }
+}
+
+function isPortrait() {
+    return window.innerHeight > window.innerWidth;
+}
+
+// Shift down the image to be vertical centered
+function centerY() {
+    if (isPortrait()) {
+        if (window.screen.deviceYDPI === 172) { // 720p 4.7"
+            extendedSplashImage.style.transform = "translateY(22px)";
+        } else if (window.screen.deviceYDPI === 230) { // 1080p 5.5"
+            extendedSplashImage.style.transform = "translateY(25px)";
+        } else if (window.screen.deviceYDPI === 211) { // 1080p 6"
+            extendedSplashImage.style.transform = "translateY(27px)";
+        }
+    } else {
+        extendedSplashImage.style.transform = "";
+    }
+}
+
+function init(config) {
+    readPreferencesFromCfg(config);
+
+    var splashscreenStyles = document.createElement("link");
+    splashscreenStyles.rel = 'stylesheet';
+    splashscreenStyles.type = 'text/css';
+    splashscreenStyles.href = '/www/css/splashscreen.css';
+    document.head.appendChild(splashscreenStyles);
+
+    // Windows 8.1 Desktop
+    //<div id='extendedSplashScreen' class='extendedSplashScreen hidden'>
+    //    <img id='extendedSplashImage' src='/images/SplashScreen.png' alt='Splash screen image' />
+    //    <progress id='extendedSplashProgress' class='win-medium win-ring'></progress>
+    //</div>
+    splashElement = document.createElement('div');
+    splashElement.id = 'extendedSplashScreen';
+    splashElement.classList.add('extendedSplashScreen');
+    splashElement.classList.add('hidden');
+    splashElement.style.backgroundColor = bgColor;
+
+    extendedSplashImage = document.createElement('img');
+    extendedSplashImage.id = 'extendedSplashImage';
+    extendedSplashImage.alt = 'Splash screen image';
+
+    // Disabling image drag
+    var draggableAttr = document.createAttribute('draggable');
+    draggableAttr.value = 'false';
+    extendedSplashImage.attributes.setNamedItem(draggableAttr);
+
+    extendedSplashImage.style.left = '0px';
+
+    // This helps prevent flickering by making the system wait until your image has been rendered 
+    // before it switches to your extended splash screen.
+    var onloadAttr = document.createAttribute('onload');
+    onloadAttr.value = '';
+    extendedSplashImage.attributes.setNamedItem(onloadAttr);
+    extendedSplashImage.src = splashImageSrc;
+
+    extendedSplashProgress = document.createElement('progress');
+    extendedSplashProgress.id = 'extendedSplashProgress';
+    extendedSplashProgress.classList.add('win-medium');
+    extendedSplashProgress.classList.add('win-ring');
+
+    if (isWp81 || isWp10) {
+        extendedSplashImage.style.maxWidth = "100%";
+        extendedSplashImage.style.maxHeight = "100%";
+        extendedSplashImage.src = splashImageSrc;
+        // center horizontally
+        extendedSplashImage.style.margin = "0 auto";
+        extendedSplashImage.style.display = "block";
+        // center vertically
+        extendedSplashImage.style.position = "relative";
+        extendedSplashImage.style.top = "50%";
+
+        // Workaround for intial splashimage jump
+        if (isWp10) {
+            extendedSplashImage.style.transform = "translateY(-50%)";
+        } else {
+            centerY();
+        }
+    }
+
+    if (isWp81) {
+        extendedSplashProgress.classList.add('extended-splash-progress-phone');
+    } else if (isWp10) {   
+        extendedSplashProgress.classList.add('extended-splash-progress-wp10');
+    }
+
+    if (!showSplashScreenSpinner) {
+        extendedSplashProgress.classList.add('hidden');
+    }
+    if (typeof splashScreenSpinnerColor !== 'undefined') {
+        extendedSplashProgress.style.color = splashScreenSpinnerColor;
+    }
+
+    splashElement.appendChild(extendedSplashImage);
+    splashElement.appendChild(extendedSplashProgress);
+
+    document.body.appendChild(splashElement);
+}
+//// </Config and initialization>
+
+//// <UI>
+var origOverflow, origZooming;
+
+function disableUserInteraction() {
+    origOverflow = document.documentElement.style.overflow;
+    document.documentElement.style.overflow = 'hidden';
+
+    origZooming = document.body.style['-ms-content-zooming'];
+    document.body.style['-ms-content-zooming'] = 'none';
+}
+
+function enableUserInteraction() {
+    document.documentElement.style.overflow = origOverflow;
+    document.body.style['-ms-content-zooming'] = origZooming;
+}
+
+// Displays the extended splash screen. Pass the splash screen object retrieved during activation.
+function show() {
+    disableUserInteraction();
+
+    positionControls();
+
+    // Once the extended splash screen is setup, apply the CSS style that will make the extended splash screen visible.
+    WinJS.Utilities.removeClass(extendedSplashScreen, 'hidden');
+}
+
+function positionControls() {
+    if (isWp10) {
+        // Resize happens twice sometimes, ensure the image is properly positioned
+        if (splash.imageLocation.y !== 0) {
+            if (isPortrait()) {
+                extendedSplashProgress.style.top = window.innerHeight * (2/3 + 1/6) - PROGRESSRING_HEIGHT / 2 + 'px';
+            } else {
+                extendedSplashProgress.style.top = Math.min(window.innerHeight - PROGRESSRING_HEIGHT - PROGRESSRING_BOTTOM_MARGIN, splash.imageLocation.y + splash.imageLocation.height + 32) + 'px';
+            }
+        }
+        return;
+    }
+
+    // Position the extended splash screen image in the same location as the system splash screen image.
+    if (isPhone) {
+        extendedSplashImage.style.top = 0;
+        extendedSplashImage.style.left = 0;
+        centerY();
+    } else {
+        extendedSplashImage.style.top = splash.imageLocation.y + 'px';
+        extendedSplashImage.style.left = splash.imageLocation.x + 'px';
+    }
+
+    if (!isWp81) {
+        extendedSplashImage.style.height = splash.imageLocation.height + 'px';
+        extendedSplashImage.style.width = splash.imageLocation.width + 'px';
+
+        extendedSplashProgress.style.marginTop = Math.min(window.innerHeight - PROGRESSRING_HEIGHT - PROGRESSRING_BOTTOM_MARGIN, splash.imageLocation.y + splash.imageLocation.height + 32) + 'px';
+    }
+}
+
+// Updates the location of the extended splash screen image. Should be used to respond to window size changes.
+function updateImageLocation() {
+    if (isVisible()) {
+        positionControls();
+    }
+}
+
+// Checks whether the extended splash screen is visible and returns a boolean.
+function isVisible() {
+    return !(WinJS.Utilities.hasClass(extendedSplashScreen, 'hidden'));
+}
+
+function fadeOut(el, duration, finishCb) {
+    var opacityDelta = 1 / (FPS * duration / 1000);
+    el.style.opacity = 1;
+
+    (function fade() {
+        if ((el.style.opacity -= opacityDelta) < 0) {
+            finishCb();
+        } else {
+            requestAnimationFrame(fade);
+        }
+    })();
+}
+
+// Removes the extended splash screen if it is currently visible.
+function hide() {
+    if (isVisible()) {
+        var hideFinishCb = function () {
+            WinJS.Utilities.addClass(extendedSplashScreen, 'hidden');
+            extendedSplashScreen.style.opacity = 1;
+            enableUserInteraction();
+        }
+
+        if (fadeSplashScreen) {
+            fadeOut(extendedSplashScreen, fadeSplashScreenDuration, hideFinishCb);
+        } else {
+            hideFinishCb();
+        }
+    }
+}
+//// </UI>
+
+//// <Events>
+var splash = null; // Variable to hold the splash screen object. 
+var coordinates = { x: 0, y: 0, width: 0, height: 0 }; // Object to store splash screen image coordinates. It will be initialized during activation. 
+
+function activated(eventObject) {
+    if (eventObject.detail.kind === Windows.ApplicationModel.Activation.ActivationKind.launch) {
+        // Retrieve splash screen object 
+        splash = eventObject.detail.splashScreen;
+
+        // Retrieve the window coordinates of the splash screen image. 
+        coordinates = splash.imageLocation;
+
+        // Register an event handler to be executed when the splash screen has been dismissed. 
+        splash.addEventListener('dismissed', onSplashScreenDismissed, false);
+
+        // Listen for window resize events to reposition the extended splash screen image accordingly. 
+        // This is important to ensure that the extended splash screen is formatted properly in response to snapping, unsnapping, rotation, etc... 
+        window.addEventListener('resize', onResize, false);
+    }
+}
+
+function onSplashScreenDismissed() {
+    // Include code to be executed when the system has transitioned from the splash screen to the extended splash screen (application's first view). 
+    if (autoHideSplashScreen) {
+        window.setTimeout(hide, effectiveSplashDuration);
+    }
+}
+
+function onResize() {
+    // Safely update the extended splash screen image coordinates. This function will be fired in response to snapping, unsnapping, rotation, etc... 
+    if (splash) {
+        // Update the coordinates of the splash screen image. 
+        coordinates = splash.imageLocation;
+        updateImageLocation(splash);
+    }
+}
+//// </Events>
+
+module.exports = {
+    firstShow: function (config, activatedEventArgs) {
+        init(config);
+        activated(activatedEventArgs);
+
+        if (!isVisible() && (splashScreenDelay > 0 || !autoHideSplashScreen)) {
+            show();
+        }
+    },
+    show: function () {
+        if (!isVisible()) {
+            show();
+        }
+    },
+    hide: function () {
+        if (isVisible()) {
+            hide();
+        }
+    }
+};

http://git-wip-us.apache.org/repos/asf/cordova-windows/blob/d6988f5c/package.json
----------------------------------------------------------------------
diff --git a/package.json b/package.json
index ebcbe44..3991b8c 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "cordova-windows",
-  "version": "4.4.0-dev",
+  "version": "5.0.0",
   "description": "cordova-windows release",
   "bin": "bin/create",
   "main": "template/cordova/Api.js",

http://git-wip-us.apache.org/repos/asf/cordova-windows/blob/d6988f5c/template/www/cordova.js
----------------------------------------------------------------------
diff --git a/template/www/cordova.js b/template/www/cordova.js
index 906bdb8..0dd8ba5 100644
--- a/template/www/cordova.js
+++ b/template/www/cordova.js
@@ -19,7 +19,7 @@
  under the License.
 */
 ;(function() {
-var PLATFORM_VERSION_BUILD_LABEL = '4.4.0-dev';
+var PLATFORM_VERSION_BUILD_LABEL = '5.0.0';
 // file: src/scripts/require.js
 
 /*jshint -W079 */
@@ -817,7 +817,81 @@ module.exports = channel;
 
 });
 
-// file: d:/cordova/cordova-windows/cordova-js-src/exec.js
+// file: f:/coho/splash/cordova-windows/cordova-js-src/confighelper.js
+define("cordova/confighelper", function(require, exports, module) {
+
+// config.xml wrapper (non-node ConfigParser analogue)
+var config;
+function Config(xhr) {
+    function loadPreferences(xhr) {
+        var parser = new DOMParser();
+        var doc = parser.parseFromString(xhr.responseText, "application/xml");
+
+        var preferences = doc.getElementsByTagName("preference");
+        return Array.prototype.slice.call(preferences);
+    }
+
+    this.xhr = xhr;
+    this.preferences = loadPreferences(this.xhr);
+}
+
+function readConfig(success, error) {
+    var xhr;
+
+    if (typeof config != 'undefined') {
+        success(config);
+    }
+
+    function fail(msg) {
+        console.error(msg);
+
+        if (error) {
+            error(msg);
+        }
+    }
+
+    var xhrStatusChangeHandler = function () {
+        if (xhr.readyState == 4) {
+            if (xhr.status == 200 || xhr.status == 304 || xhr.status == 0 /* file:// */) {
+                config = new Config(xhr);
+                success(config);
+            }
+            else {
+                fail('[Windows][cordova.js][xhrStatusChangeHandler] Could not XHR config.xml: ' + xhr.statusText);
+            }
+        }
+    };
+
+    xhr = new XMLHttpRequest();
+    xhr.addEventListener("load", xhrStatusChangeHandler);
+
+    try {
+        xhr.open("get", "../config.xml", true);
+        xhr.send();
+    } catch (e) {
+        fail('[Windows][cordova.js][readConfig] Could not XHR config.xml: ' + JSON.stringify(e));
+    }
+}
+
+/**
+ * Reads a preference value from config.xml.
+ * Returns preference value or undefined if it does not exist.
+ * @param {String} preferenceName Preference name to read */
+Config.prototype.getPreferenceValue = function getPreferenceValue(preferenceName) {
+    var preferenceItem = this.preferences && this.preferences.filter(function (item) {
+        return item.attributes['name'].value === preferenceName;
+    });
+
+    if (preferenceItem && preferenceItem[0] && preferenceItem[0].attributes && preferenceItem[0].attributes['value']) {
+        return preferenceItem[0].attributes['value'].value;
+    }
+}
+
+exports.readConfig = readConfig;
+
+});
+
+// file: f:/coho/splash/cordova-windows/cordova-js-src/exec.js
 define("cordova/exec", function(require, exports, module) {
 
 /*jslint sloppy:true, plusplus:true*/
@@ -1394,7 +1468,7 @@ exports.reset();
 
 });
 
-// file: d:/cordova/cordova-windows/cordova-js-src/platform.js
+// file: f:/coho/splash/cordova-windows/cordova-js-src/platform.js
 define("cordova/platform", function(require, exports, module) {
 
 module.exports = {
@@ -1404,7 +1478,8 @@ module.exports = {
             exec = require('cordova/exec'),
             channel = cordova.require('cordova/channel'),
             platform = require('cordova/platform'),
-            modulemapper = require('cordova/modulemapper');
+            modulemapper = require('cordova/modulemapper'),
+            configHelper = require('cordova/confighelper');
 
         modulemapper.clobbers('cordova/exec/proxy', 'cordova.commandProxy');
 
@@ -1416,7 +1491,11 @@ module.exports = {
         channel.onNativeReady.fire();
 
         var onWinJSReady = function () {
-            var app = WinJS.Application;
+            var app = WinJS.Application,
+                splashscreen = require('cordova/splashscreen');
+
+            modulemapper.clobbers('cordova/splashscreen', 'navigator.splashscreen');
+
             var checkpointHandler = function checkpointHandler() {
                 cordova.fireDocumentEvent('pause',null,true);
             };
@@ -1432,7 +1511,27 @@ module.exports = {
                 var args = e.detail.arguments;
                 var actType = e.detail.type;
                 platform.activationContext = { type: actType, args: args };
-                cordova.fireDocumentEvent('activated', platform.activationContext, true);
+
+                function makePromise(fn) {
+                    return new WinJS.Promise(function init(completeDispatch, errorDispatch) {
+                        fn(function successCb(results) {
+                            completeDispatch(results);
+                        }, function errorCb(error) {
+                            errorDispatch(error);
+                        });
+                    });
+                }
+
+                e.setPromise(makePromise(configHelper.readConfig).then(function (config) {
+                    if (e.detail.previousExecutionState !== Windows.ApplicationModel.Activation.ApplicationExecutionState.running) {
+                        splashscreen.firstShow(config, e);
+                    }
+                }).then(function () {
+                    // Avoids splashimage flicker on Windows Phone 8.1/10
+                    return WinJS.Promise.timeout();
+                }).then(function () {
+                    cordova.fireDocumentEvent('activated', platform.activationContext, true);
+                }));
             };
 
             app.addEventListener("checkpoint", checkpointHandler);
@@ -1444,6 +1543,11 @@ module.exports = {
             app.start();
         };
 
+        function appendScript(scriptElem, loadedCb) {
+            scriptElem.addEventListener("load", loadedCb);
+            document.head.appendChild(scriptElem);
+        }
+
         if (!window.WinJS) {
             var scriptElem = document.createElement("script");
 
@@ -1677,6 +1781,331 @@ exports.load = function(callback) {
 
 });
 
+// file: f:/coho/splash/cordova-windows/cordova-js-src/splashscreen.js
+define("cordova/splashscreen", function(require, exports, module) {
+
+var isPhone = (cordova.platformId == 'windows') && WinJS.Utilities.isPhone;
+var isWp81 = navigator.appVersion.indexOf("Windows Phone 8.1") !== -1;
+var isWp10 = navigator.appVersion.indexOf("Windows Phone 10") !== -1;
+var isWin10UWP = navigator.appVersion.indexOf('MSAppHost/3.0') !== -1;
+var isHosted = window.location.protocol.indexOf('http') === 0;
+var splashImageSrc = ((isHosted || isWin10UWP) ? 'ms-appx-web' : 'ms-appx') + ':///images/'
+    + (isPhone ? 'splashscreenphone.png' : 'splashscreen.png');
+
+var splashElement = null, extendedSplashImage = null, extendedSplashProgress = null;
+
+//// <Config and initialization>
+var DEFAULT_SPLASHSCREEN_DURATION = 3000, // in milliseconds
+    FPS = 60, // frames per second used by requestAnimationFrame
+    PROGRESSRING_HEIGHT = 40,
+    PROGRESSRING_BOTTOM_MARGIN = 10; // needed for windows 10 min height window
+
+var bgColor = "#464646",
+    autoHideSplashScreen = true,
+    splashScreenDelay = DEFAULT_SPLASHSCREEN_DURATION,
+    fadeSplashScreen = true,
+    fadeSplashScreenDuration = DEFAULT_SPLASHSCREEN_DURATION,
+    showSplashScreenSpinner = true,
+    splashScreenSpinnerColor; // defaults to system accent color
+
+var effectiveSplashDuration;
+
+function readBoolFromCfg(preferenceName, defaultValue, cfg) {
+    var value = cfg.getPreferenceValue(preferenceName);
+    if (typeof value !== 'undefined') {
+        return value === 'true';
+    } else {
+        return defaultValue;
+    }
+}
+
+function readPreferencesFromCfg(cfg) {
+    try {
+        bgColor = cfg.getPreferenceValue('SplashScreenBackgroundColor') || bgColor;
+        bgColor = bgColor.replace('0x', '#').replace('0X', '#');
+        if (bgColor.length > 7) {
+            // Remove aplha
+            bgColor = bgColor.slice(0, 1) + bgColor.slice(3, bgColor.length);
+        }
+
+        autoHideSplashScreen = readBoolFromCfg('AutoHideSplashScreen', autoHideSplashScreen, cfg);
+        splashScreenDelay = cfg.getPreferenceValue('SplashScreenDelay') || splashScreenDelay;
+
+        fadeSplashScreen = readBoolFromCfg('FadeSplashScreen', fadeSplashScreen, cfg);
+        fadeSplashScreenDuration = cfg.getPreferenceValue('FadeSplashScreenDuration') || fadeSplashScreenDuration;
+
+        showSplashScreenSpinner = readBoolFromCfg('ShowSplashScreenSpinner', showSplashScreenSpinner, cfg);
+        splashScreenSpinnerColor = cfg.getPreferenceValue('SplashScreenSpinnerColor');
+
+        effectiveSplashDuration = Math.max(splashScreenDelay - fadeSplashScreenDuration, 0);
+    } catch (e) {
+        var msg = '[Windows][SplashScreen] Error occured on loading preferences from config.xml: ' + JSON.stringify(e);
+        console.error(msg);
+    }
+}
+
+function isPortrait() {
+    return window.innerHeight > window.innerWidth;
+}
+
+// Shift down the image to be vertical centered
+function centerY() {
+    if (isPortrait()) {
+        if (window.screen.deviceYDPI === 172) { // 720p 4.7"
+            extendedSplashImage.style.transform = "translateY(22px)";
+        } else if (window.screen.deviceYDPI === 230) { // 1080p 5.5"
+            extendedSplashImage.style.transform = "translateY(25px)";
+        } else if (window.screen.deviceYDPI === 211) { // 1080p 6"
+            extendedSplashImage.style.transform = "translateY(27px)";
+        }
+    } else {
+        extendedSplashImage.style.transform = "";
+    }
+}
+
+function init(config) {
+    readPreferencesFromCfg(config);
+
+    var splashscreenStyles = document.createElement("link");
+    splashscreenStyles.rel = 'stylesheet';
+    splashscreenStyles.type = 'text/css';
+    splashscreenStyles.href = '/www/css/splashscreen.css';
+    document.head.appendChild(splashscreenStyles);
+
+    // Windows 8.1 Desktop
+    //<div id='extendedSplashScreen' class='extendedSplashScreen hidden'>
+    //    <img id='extendedSplashImage' src='/images/SplashScreen.png' alt='Splash screen image' />
+    //    <progress id='extendedSplashProgress' class='win-medium win-ring'></progress>
+    //</div>
+    splashElement = document.createElement('div');
+    splashElement.id = 'extendedSplashScreen';
+    splashElement.classList.add('extendedSplashScreen');
+    splashElement.classList.add('hidden');
+    splashElement.style.backgroundColor = bgColor;
+
+    extendedSplashImage = document.createElement('img');
+    extendedSplashImage.id = 'extendedSplashImage';
+    extendedSplashImage.alt = 'Splash screen image';
+
+    // Disabling image drag
+    var draggableAttr = document.createAttribute('draggable');
+    draggableAttr.value = 'false';
+    extendedSplashImage.attributes.setNamedItem(draggableAttr);
+
+    extendedSplashImage.style.left = '0px';
+
+    // This helps prevent flickering by making the system wait until your image has been rendered 
+    // before it switches to your extended splash screen.
+    var onloadAttr = document.createAttribute('onload');
+    onloadAttr.value = '';
+    extendedSplashImage.attributes.setNamedItem(onloadAttr);
+    extendedSplashImage.src = splashImageSrc;
+
+    extendedSplashProgress = document.createElement('progress');
+    extendedSplashProgress.id = 'extendedSplashProgress';
+    extendedSplashProgress.classList.add('win-medium');
+    extendedSplashProgress.classList.add('win-ring');
+
+    if (isWp81 || isWp10) {
+        extendedSplashImage.style.maxWidth = "100%";
+        extendedSplashImage.style.maxHeight = "100%";
+        extendedSplashImage.src = splashImageSrc;
+        // center horizontally
+        extendedSplashImage.style.margin = "0 auto";
+        extendedSplashImage.style.display = "block";
+        // center vertically
+        extendedSplashImage.style.position = "relative";
+        extendedSplashImage.style.top = "50%";
+
+        // Workaround for intial splashimage jump
+        if (isWp10) {
+            extendedSplashImage.style.transform = "translateY(-50%)";
+        } else {
+            centerY();
+        }
+    }
+
+    if (isWp81) {
+        extendedSplashProgress.classList.add('extended-splash-progress-phone');
+    } else if (isWp10) {   
+        extendedSplashProgress.classList.add('extended-splash-progress-wp10');
+    }
+
+    if (!showSplashScreenSpinner) {
+        extendedSplashProgress.classList.add('hidden');
+    }
+    if (typeof splashScreenSpinnerColor !== 'undefined') {
+        extendedSplashProgress.style.color = splashScreenSpinnerColor;
+    }
+
+    splashElement.appendChild(extendedSplashImage);
+    splashElement.appendChild(extendedSplashProgress);
+
+    document.body.appendChild(splashElement);
+}
+//// </Config and initialization>
+
+//// <UI>
+var origOverflow, origZooming;
+
+function disableUserInteraction() {
+    origOverflow = document.documentElement.style.overflow;
+    document.documentElement.style.overflow = 'hidden';
+
+    origZooming = document.body.style['-ms-content-zooming'];
+    document.body.style['-ms-content-zooming'] = 'none';
+}
+
+function enableUserInteraction() {
+    document.documentElement.style.overflow = origOverflow;
+    document.body.style['-ms-content-zooming'] = origZooming;
+}
+
+// Displays the extended splash screen. Pass the splash screen object retrieved during activation.
+function show() {
+    disableUserInteraction();
+
+    positionControls();
+
+    // Once the extended splash screen is setup, apply the CSS style that will make the extended splash screen visible.
+    WinJS.Utilities.removeClass(extendedSplashScreen, 'hidden');
+}
+
+function positionControls() {
+    if (isWp10) {
+        // Resize happens twice sometimes, ensure the image is properly positioned
+        if (splash.imageLocation.y !== 0) {
+            if (isPortrait()) {
+                extendedSplashProgress.style.top = window.innerHeight * (2/3 + 1/6) - PROGRESSRING_HEIGHT / 2 + 'px';
+            } else {
+                extendedSplashProgress.style.top = Math.min(window.innerHeight - PROGRESSRING_HEIGHT - PROGRESSRING_BOTTOM_MARGIN, splash.imageLocation.y + splash.imageLocation.height + 32) + 'px';
+            }
+        }
+        return;
+    }
+
+    // Position the extended splash screen image in the same location as the system splash screen image.
+    if (isPhone) {
+        extendedSplashImage.style.top = 0;
+        extendedSplashImage.style.left = 0;
+        centerY();
+    } else {
+        extendedSplashImage.style.top = splash.imageLocation.y + 'px';
+        extendedSplashImage.style.left = splash.imageLocation.x + 'px';
+    }
+
+    if (!isWp81) {
+        extendedSplashImage.style.height = splash.imageLocation.height + 'px';
+        extendedSplashImage.style.width = splash.imageLocation.width + 'px';
+
+        extendedSplashProgress.style.marginTop = Math.min(window.innerHeight - PROGRESSRING_HEIGHT - PROGRESSRING_BOTTOM_MARGIN, splash.imageLocation.y + splash.imageLocation.height + 32) + 'px';
+    }
+}
+
+// Updates the location of the extended splash screen image. Should be used to respond to window size changes.
+function updateImageLocation() {
+    if (isVisible()) {
+        positionControls();
+    }
+}
+
+// Checks whether the extended splash screen is visible and returns a boolean.
+function isVisible() {
+    return !(WinJS.Utilities.hasClass(extendedSplashScreen, 'hidden'));
+}
+
+function fadeOut(el, duration, finishCb) {
+    var opacityDelta = 1 / (FPS * duration / 1000);
+    el.style.opacity = 1;
+
+    (function fade() {
+        if ((el.style.opacity -= opacityDelta) < 0) {
+            finishCb();
+        } else {
+            requestAnimationFrame(fade);
+        }
+    })();
+}
+
+// Removes the extended splash screen if it is currently visible.
+function hide() {
+    if (isVisible()) {
+        var hideFinishCb = function () {
+            WinJS.Utilities.addClass(extendedSplashScreen, 'hidden');
+            extendedSplashScreen.style.opacity = 1;
+            enableUserInteraction();
+        }
+
+        if (fadeSplashScreen) {
+            fadeOut(extendedSplashScreen, fadeSplashScreenDuration, hideFinishCb);
+        } else {
+            hideFinishCb();
+        }
+    }
+}
+//// </UI>
+
+//// <Events>
+var splash = null; // Variable to hold the splash screen object. 
+var coordinates = { x: 0, y: 0, width: 0, height: 0 }; // Object to store splash screen image coordinates. It will be initialized during activation. 
+
+function activated(eventObject) {
+    if (eventObject.detail.kind === Windows.ApplicationModel.Activation.ActivationKind.launch) {
+        // Retrieve splash screen object 
+        splash = eventObject.detail.splashScreen;
+
+        // Retrieve the window coordinates of the splash screen image. 
+        coordinates = splash.imageLocation;
+
+        // Register an event handler to be executed when the splash screen has been dismissed. 
+        splash.addEventListener('dismissed', onSplashScreenDismissed, false);
+
+        // Listen for window resize events to reposition the extended splash screen image accordingly. 
+        // This is important to ensure that the extended splash screen is formatted properly in response to snapping, unsnapping, rotation, etc... 
+        window.addEventListener('resize', onResize, false);
+    }
+}
+
+function onSplashScreenDismissed() {
+    // Include code to be executed when the system has transitioned from the splash screen to the extended splash screen (application's first view). 
+    if (autoHideSplashScreen) {
+        window.setTimeout(hide, effectiveSplashDuration);
+    }
+}
+
+function onResize() {
+    // Safely update the extended splash screen image coordinates. This function will be fired in response to snapping, unsnapping, rotation, etc... 
+    if (splash) {
+        // Update the coordinates of the splash screen image. 
+        coordinates = splash.imageLocation;
+        updateImageLocation(splash);
+    }
+}
+//// </Events>
+
+module.exports = {
+    firstShow: function (config, activatedEventArgs) {
+        init(config);
+        activated(activatedEventArgs);
+
+        if (!isVisible() && (splashScreenDelay > 0 || !autoHideSplashScreen)) {
+            show();
+        }
+    },
+    show: function () {
+        if (!isVisible()) {
+            show();
+        }
+    },
+    hide: function () {
+        if (isVisible()) {
+            hide();
+        }
+    }
+};
+
+});
+
 // file: src/common/urlutil.js
 define("cordova/urlutil", function(require, exports, module) {
 

http://git-wip-us.apache.org/repos/asf/cordova-windows/blob/d6988f5c/template/www/css/splashscreen.css
----------------------------------------------------------------------
diff --git a/template/www/css/splashscreen.css b/template/www/css/splashscreen.css
new file mode 100644
index 0000000..46e347a
--- /dev/null
+++ b/template/www/css/splashscreen.css
@@ -0,0 +1,75 @@
+/*
+ *
+ * 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.
+ *
+*/
+
+/* Container */
+.extendedSplashScreen {
+    background-color:#464646;
+    height: 100%;
+    width: 100%;
+    position: absolute;
+    top: 0px;
+    left: 0px;
+    text-align: center;
+    z-index: 2147483647;
+}
+
+.extendedSplashScreen.hidden {
+    display: none;
+}
+
+#extendedSplashImage {
+    position: absolute;
+}
+
+/* ProgressRing */
+.win-progress-ring.win-medium,
+.win-ring.win-medium {
+    width: 40px;
+    height: 40px;
+}
+
+.win-progress-ring:indeterminate::-ms-fill,
+.win-ring:indeterminate::-ms-fill {
+    animation-name: -ms-ring;
+}
+
+.win-progress-bar::-ms-fill,
+.win-progress-ring::-ms-fill,
+.win-ring::-ms-fill {
+    background-color: Highlight;
+}
+
+.win-ring.win-medium.extended-splash-progress-phone {
+    position: absolute;
+    width: 100%;
+    top: calc(100% - 140px);
+    text-align: center;
+}
+
+.win-ring.win-medium.extended-splash-progress-wp10 {
+    position: absolute;
+    top: calc(82.5% - 20px);
+    left: calc(50% - 20px);
+}
+
+#extendedSplashProgress.hidden {
+    display: none;
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@cordova.apache.org
For additional commands, e-mail: commits-help@cordova.apache.org