From 7f3be98199c4507db518f780fcf1b20b5bfc3e1c Mon Sep 17 00:00:00 2001 From: Joe Bowser Date: Mon, 25 Sep 2017 11:37:52 -0700 Subject: [PATCH] Update JS snapshot to version 6.4.0-dev (via coho) --- bin/templates/project/assets/www/cordova.js | 4115 ++++++++++--------- 1 file changed, 2069 insertions(+), 2046 deletions(-) diff --git a/bin/templates/project/assets/www/cordova.js b/bin/templates/project/assets/www/cordova.js index dc1bf5ab..e9e79c7c 100644 --- a/bin/templates/project/assets/www/cordova.js +++ b/bin/templates/project/assets/www/cordova.js @@ -1,5 +1,5 @@ // Platform: android -// 7ef9f9c03167a4dde4372d869472241b6816fee9 +// 74a4adc2d0fddb1e0cfb9be1961494ef0afc9893 /* Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file @@ -8,9 +8,9 @@ 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 @@ -18,2168 +18,2191 @@ specific language governing permissions and limitations under the License. */ +;(function() { +var PLATFORM_VERSION_BUILD_LABEL = '6.4.0-dev'; +// file: src/scripts/require.js + +/*jshint -W079 */ +/*jshint -W020 */ + +var require, + define; + (function () { - var PLATFORM_VERSION_BUILD_LABEL = '6.3.0-dev'; - // file: src/scripts/require.js - /* global prompt */ - /* global atob */ - /* eslint no-eval : 0 */ - /* eslint no-cond-assign : 0 */ - /* eslint valid-typeof : 0 */ + var modules = {}, + // Stack of moduleIds currently being built. + requireStack = [], + // Map of module ID -> index into requireStack of modules currently being built. + inProgressModules = {}, + SEPARATOR = "."; - var require; - var define; - (function () { - var modules = {}; - // Stack of moduleIds currently being built. - var requireStack = []; - // Map of module ID -> index into requireStack of modules currently being built. - var inProgressModules = {}; - var SEPARATOR = '.'; - function build (module) { - var factory = module.factory; - var localRequire = function (id) { + function build(module) { + var factory = module.factory, + localRequire = function (id) { var resultantId = id; - // Its a relative path, so lop off the last portion and add the id (minus "./") - if (id.charAt(0) === '.') { + //Its a relative path, so lop off the last portion and add the id (minus "./") + if (id.charAt(0) === ".") { resultantId = module.id.slice(0, module.id.lastIndexOf(SEPARATOR)) + SEPARATOR + id.slice(2); } return require(resultantId); }; - module.exports = {}; - delete module.factory; - factory(localRequire, module.exports, module); - return module.exports; - } - - require = function (id) { - if (!modules[id]) { - throw 'module ' + id + ' not found'; - } else if (id in inProgressModules) { - var cycle = requireStack.slice(inProgressModules[id]).join('->') + '->' + id; - throw 'Cycle in require graph: ' + cycle; - } - if (modules[id].factory) { - try { - inProgressModules[id] = requireStack.length; - requireStack.push(id); - return build(modules[id]); - } finally { - delete inProgressModules[id]; - requireStack.pop(); - } - } - return modules[id].exports; - }; - - define = function (id, factory) { - if (modules[id]) { - throw 'module ' + id + ' already defined'; - } - - modules[id] = { - id: id, - factory: factory - }; - }; - - define.remove = function (id) { - delete modules[id]; - }; - - define.moduleMap = modules; - })(); - - // Export for use in node - if (typeof module === 'object' && typeof require === 'function') { - module.exports.require = require; - module.exports.define = define; + module.exports = {}; + delete module.factory; + factory(localRequire, module.exports, module); + return module.exports; } - // file: src/cordova.js - define('cordova', function (require, exports, module) { - - // Workaround for Windows 10 in hosted environment case - // http://www.w3.org/html/wg/drafts/html/master/browsers.html#named-access-on-the-window-object - var HTMLElement; - if (window.cordova && !(window.cordova instanceof HTMLElement)) { - throw new Error('cordova already defined'); + require = function (id) { + if (!modules[id]) { + throw "module " + id + " not found"; + } else if (id in inProgressModules) { + var cycle = requireStack.slice(inProgressModules[id]).join('->') + '->' + id; + throw "Cycle in require graph: " + cycle; } - - var channel = require('cordova/channel'); - var platform = require('cordova/platform'); - - /** - * Intercept calls to addEventListener + removeEventListener and handle deviceready, - * resume, and pause events. - */ - var m_document_addEventListener = document.addEventListener; - var m_document_removeEventListener = document.removeEventListener; - var m_window_addEventListener = window.addEventListener; - var m_window_removeEventListener = window.removeEventListener; - - /** - * Houses custom event handlers to intercept on document + window event listeners. - */ - var documentEventHandlers = {}; - var windowEventHandlers = {}; - - document.addEventListener = function (evt, handler, capture) { - var e = evt.toLowerCase(); - if (typeof documentEventHandlers[e] !== 'undefined') { - documentEventHandlers[e].subscribe(handler); - } else { - m_document_addEventListener.call(document, evt, handler, capture); - } - }; - - window.addEventListener = function (evt, handler, capture) { - var e = evt.toLowerCase(); - if (typeof windowEventHandlers[e] !== 'undefined') { - windowEventHandlers[e].subscribe(handler); - } else { - m_window_addEventListener.call(window, evt, handler, capture); - } - }; - - document.removeEventListener = function (evt, handler, capture) { - var e = evt.toLowerCase(); - // If unsubscribing from an event that is handled by a plugin - if (typeof documentEventHandlers[e] !== 'undefined') { - documentEventHandlers[e].unsubscribe(handler); - } else { - m_document_removeEventListener.call(document, evt, handler, capture); - } - }; - - window.removeEventListener = function (evt, handler, capture) { - var e = evt.toLowerCase(); - // If unsubscribing from an event that is handled by a plugin - if (typeof windowEventHandlers[e] !== 'undefined') { - windowEventHandlers[e].unsubscribe(handler); - } else { - m_window_removeEventListener.call(window, evt, handler, capture); - } - }; - - function createEvent (type, data) { - var event = document.createEvent('Events'); - event.initEvent(type, false, false); - if (data) { - for (var i in data) { - if (data.hasOwnProperty(i)) { - event[i] = data[i]; - } - } - } - return event; - } - - var cordova = { - define: define, - require: require, - version: PLATFORM_VERSION_BUILD_LABEL, - platformVersion: PLATFORM_VERSION_BUILD_LABEL, - platformId: platform.id, - /** - * Methods to add/remove your own addEventListener hijacking on document + window. - */ - addWindowEventHandler: function (event) { - return (windowEventHandlers[event] = channel.create(event)); - }, - addStickyDocumentEventHandler: function (event) { - return (documentEventHandlers[event] = channel.createSticky(event)); - }, - addDocumentEventHandler: function (event) { - return (documentEventHandlers[event] = channel.create(event)); - }, - removeWindowEventHandler: function (event) { - delete windowEventHandlers[event]; - }, - removeDocumentEventHandler: function (event) { - delete documentEventHandlers[event]; - }, - /** - * Retrieve original event handlers that were replaced by Cordova - * - * @return object - */ - getOriginalHandlers: function () { - return {'document': {'addEventListener': m_document_addEventListener, 'removeEventListener': m_document_removeEventListener}, - 'window': {'addEventListener': m_window_addEventListener, 'removeEventListener': m_window_removeEventListener}}; - }, - /** - * Method to fire event from native code - * bNoDetach is required for events which cause an exception which needs to be caught in native code - */ - fireDocumentEvent: function (type, data, bNoDetach) { - var evt = createEvent(type, data); - if (typeof documentEventHandlers[type] !== 'undefined') { - if (bNoDetach) { - documentEventHandlers[type].fire(evt); - } else { - setTimeout(function () { - // Fire deviceready on listeners that were registered before cordova.js was loaded. - if (type === 'deviceready') { - document.dispatchEvent(evt); - } - documentEventHandlers[type].fire(evt); - }, 0); - } - } else { - document.dispatchEvent(evt); - } - }, - fireWindowEvent: function (type, data) { - var evt = createEvent(type, data); - if (typeof windowEventHandlers[type] !== 'undefined') { - setTimeout(function () { - windowEventHandlers[type].fire(evt); - }, 0); - } else { - window.dispatchEvent(evt); - } - }, - - /** - * Plugin callback mechanism. - */ - // Randomize the starting callbackId to avoid collisions after refreshing or navigating. - // This way, it's very unlikely that any new callback would get the same callbackId as an old callback. - callbackId: Math.floor(Math.random() * 2000000000), - callbacks: {}, - callbackStatus: { - NO_RESULT: 0, - OK: 1, - CLASS_NOT_FOUND_EXCEPTION: 2, - ILLEGAL_ACCESS_EXCEPTION: 3, - INSTANTIATION_EXCEPTION: 4, - MALFORMED_URL_EXCEPTION: 5, - IO_EXCEPTION: 6, - INVALID_ACTION: 7, - JSON_EXCEPTION: 8, - ERROR: 9 - }, - - /** - * Called by native code when returning successful result from an action. - */ - callbackSuccess: function (callbackId, args) { - cordova.callbackFromNative(callbackId, true, args.status, [args.message], args.keepCallback); - }, - - /** - * Called by native code when returning error result from an action. - */ - callbackError: function (callbackId, args) { - // TODO: Deprecate callbackSuccess and callbackError in favour of callbackFromNative. - // Derive success from status. - cordova.callbackFromNative(callbackId, false, args.status, [args.message], args.keepCallback); - }, - - /** - * Called by native code when returning the result from an action. - */ - callbackFromNative: function (callbackId, isSuccess, status, args, keepCallback) { - try { - var callback = cordova.callbacks[callbackId]; - if (callback) { - if (isSuccess && status === cordova.callbackStatus.OK) { - callback.success && callback.success.apply(null, args); - } else if (!isSuccess) { - callback.fail && callback.fail.apply(null, args); - } - /* - else - Note, this case is intentionally not caught. - this can happen if isSuccess is true, but callbackStatus is NO_RESULT - which is used to remove a callback from the list without calling the callbacks - typically keepCallback is false in this case - */ - // Clear callback if not expecting any more results - if (!keepCallback) { - delete cordova.callbacks[callbackId]; - } - } - } catch (err) { - var msg = 'Error in ' + (isSuccess ? 'Success' : 'Error') + ' callbackId: ' + callbackId + ' : ' + err; - console && console.log && console.log(msg); - cordova.fireWindowEvent('cordovacallbackerror', { 'message': msg }); - throw err; - } - }, - addConstructor: function (func) { - channel.onCordovaReady.subscribe(function () { - try { - func(); - } catch (e) { - console.log('Failed to run constructor: ' + e); - } - }); - } - }; - - module.exports = cordova; - - }); - - // file: /Users/maj/src/cordova-android/cordova-js-src/android/nativeapiprovider.js - define('cordova/android/nativeapiprovider', function (require, exports, module) { - - /** - * Exports the ExposedJsApi.java object if available, otherwise exports the PromptBasedNativeApi. - */ - - var nativeApi = this._cordovaNative || require('cordova/android/promptbasednativeapi'); - var currentApi = nativeApi; - - module.exports = { - get: function () { return currentApi; }, - setPreferPrompt: function (value) { - currentApi = value ? require('cordova/android/promptbasednativeapi') : nativeApi; - }, - // Used only by tests. - set: function (value) { - currentApi = value; - } - }; - - }); - - // file: /Users/maj/src/cordova-android/cordova-js-src/android/promptbasednativeapi.js - define('cordova/android/promptbasednativeapi', function (require, exports, module) { - - /** - * Implements the API of ExposedJsApi.java, but uses prompt() to communicate. - * This is used pre-JellyBean, where addJavascriptInterface() is disabled. - */ - - module.exports = { - exec: function (bridgeSecret, service, action, callbackId, argsJson) { - return prompt(argsJson, 'gap:' + JSON.stringify([bridgeSecret, service, action, callbackId])); - }, - setNativeToJsBridgeMode: function (bridgeSecret, value) { - prompt(value, 'gap_bridge_mode:' + bridgeSecret); - }, - retrieveJsMessages: function (bridgeSecret, fromOnlineEvent) { - return prompt(+fromOnlineEvent, 'gap_poll:' + bridgeSecret); - } - }; - - }); - - // file: src/common/argscheck.js - define('cordova/argscheck', function (require, exports, module) { - - var utils = require('cordova/utils'); - - var moduleExports = module.exports; - - var typeMap = { - 'A': 'Array', - 'D': 'Date', - 'N': 'Number', - 'S': 'String', - 'F': 'Function', - 'O': 'Object' - }; - - function extractParamName (callee, argIndex) { - return (/.*?\((.*?)\)/).exec(callee)[1].split(', ')[argIndex]; - } - - function checkArgs (spec, functionName, args, opt_callee) { - if (!moduleExports.enableChecks) { - return; - } - var errMsg = null; - var typeName; - for (var i = 0; i < spec.length; ++i) { - var c = spec.charAt(i); - var cUpper = c.toUpperCase(); - var arg = args[i]; - // Asterix means allow anything. - if (c === '*') { - continue; - } - typeName = utils.typeName(arg); - if ((arg === null || arg === undefined) && c === cUpper) { - continue; - } - if (typeName !== typeMap[cUpper]) { - errMsg = 'Expected ' + typeMap[cUpper]; - break; - } - } - if (errMsg) { - errMsg += ', but got ' + typeName + '.'; - errMsg = 'Wrong type for parameter "' + extractParamName(opt_callee || args.callee, i) + '" of ' + functionName + ': ' + errMsg; - // Don't log when running unit tests. - if (typeof jasmine === 'undefined') { - console.error(errMsg); - } - throw TypeError(errMsg); - } - } - - function getValue (value, defaultValue) { - return value === undefined ? defaultValue : value; - } - - moduleExports.checkArgs = checkArgs; - moduleExports.getValue = getValue; - moduleExports.enableChecks = true; - - }); - - // file: src/common/base64.js - define('cordova/base64', function (require, exports, module) { - - var base64 = exports; - - base64.fromArrayBuffer = function (arrayBuffer) { - var array = new Uint8Array(arrayBuffer); - return uint8ToBase64(array); - }; - - base64.toArrayBuffer = function (str) { - var decodedStr = typeof atob !== 'undefined' ? atob(str) : Buffer.alloc(str, 'base64').toString('binary'); - var arrayBuffer = new ArrayBuffer(decodedStr.length); - var array = new Uint8Array(arrayBuffer); - for (var i = 0, len = decodedStr.length; i < len; i++) { - array[i] = decodedStr.charCodeAt(i); - } - return arrayBuffer; - }; - - // ------------------------------------------------------------------------------ - - /* This code is based on the performance tests at http://jsperf.com/b64tests - * This 12-bit-at-a-time algorithm was the best performing version on all - * platforms tested. - */ - - var b64_6bit = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; - var b64_12bit; - - var b64_12bitTable = function () { - b64_12bit = []; - for (var i = 0; i < 64; i++) { - for (var j = 0; j < 64; j++) { - b64_12bit[i * 64 + j] = b64_6bit[i] + b64_6bit[j]; - } - } - b64_12bitTable = function () { return b64_12bit; }; - return b64_12bit; - }; - - function uint8ToBase64 (rawData) { - var numBytes = rawData.byteLength; - var output = ''; - var segment; - var table = b64_12bitTable(); - for (var i = 0; i < numBytes - 2; i += 3) { - segment = (rawData[i] << 16) + (rawData[i + 1] << 8) + rawData[i + 2]; - output += table[segment >> 12]; - output += table[segment & 0xfff]; - } - if (numBytes - i === 2) { - segment = (rawData[i] << 16) + (rawData[i + 1] << 8); - output += table[segment >> 12]; - output += b64_6bit[(segment & 0xfff) >> 6]; - output += '='; - } else if (numBytes - i === 1) { - segment = (rawData[i] << 16); - output += table[segment >> 12]; - output += '=='; - } - return output; - } - - }); - - // file: src/common/builder.js - define('cordova/builder', function (require, exports, module) { - - var utils = require('cordova/utils'); - - function each (objects, func, context) { - for (var prop in objects) { - if (objects.hasOwnProperty(prop)) { - func.apply(context, [objects[prop], prop]); - } - } - } - - function clobber (obj, key, value) { - exports.replaceHookForTesting(obj, key); - var needsProperty = false; + if (modules[id].factory) { try { - obj[key] = value; - } catch (e) { - needsProperty = true; - } - // Getters can only be overridden by getters. - if (needsProperty || obj[key] !== value) { - utils.defineGetter(obj, key, function () { - return value; - }); + inProgressModules[id] = requireStack.length; + requireStack.push(id); + return build(modules[id]); + } finally { + delete inProgressModules[id]; + requireStack.pop(); } } + return modules[id].exports; + }; - function assignOrWrapInDeprecateGetter (obj, key, value, message) { - if (message) { - utils.defineGetter(obj, key, function () { - console.log(message); - delete obj[key]; - clobber(obj, key, value); - return value; - }); + define = function (id, factory) { + if (modules[id]) { + throw "module " + id + " already defined"; + } + + modules[id] = { + id: id, + factory: factory + }; + }; + + define.remove = function (id) { + delete modules[id]; + }; + + define.moduleMap = modules; +})(); + +//Export for use in node +if (typeof module === "object" && typeof require === "function") { + module.exports.require = require; + module.exports.define = define; +} + +// file: src/cordova.js +define("cordova", function(require, exports, module) { + +// Workaround for Windows 10 in hosted environment case +// http://www.w3.org/html/wg/drafts/html/master/browsers.html#named-access-on-the-window-object +if (window.cordova && !(window.cordova instanceof HTMLElement)) { + throw new Error("cordova already defined"); +} + + +var channel = require('cordova/channel'); +var platform = require('cordova/platform'); + + +/** + * Intercept calls to addEventListener + removeEventListener and handle deviceready, + * resume, and pause events. + */ +var m_document_addEventListener = document.addEventListener; +var m_document_removeEventListener = document.removeEventListener; +var m_window_addEventListener = window.addEventListener; +var m_window_removeEventListener = window.removeEventListener; + +/** + * Houses custom event handlers to intercept on document + window event listeners. + */ +var documentEventHandlers = {}, + windowEventHandlers = {}; + +document.addEventListener = function(evt, handler, capture) { + var e = evt.toLowerCase(); + if (typeof documentEventHandlers[e] != 'undefined') { + documentEventHandlers[e].subscribe(handler); + } else { + m_document_addEventListener.call(document, evt, handler, capture); + } +}; + +window.addEventListener = function(evt, handler, capture) { + var e = evt.toLowerCase(); + if (typeof windowEventHandlers[e] != 'undefined') { + windowEventHandlers[e].subscribe(handler); + } else { + m_window_addEventListener.call(window, evt, handler, capture); + } +}; + +document.removeEventListener = function(evt, handler, capture) { + var e = evt.toLowerCase(); + // If unsubscribing from an event that is handled by a plugin + if (typeof documentEventHandlers[e] != "undefined") { + documentEventHandlers[e].unsubscribe(handler); + } else { + m_document_removeEventListener.call(document, evt, handler, capture); + } +}; + +window.removeEventListener = function(evt, handler, capture) { + var e = evt.toLowerCase(); + // If unsubscribing from an event that is handled by a plugin + if (typeof windowEventHandlers[e] != "undefined") { + windowEventHandlers[e].unsubscribe(handler); + } else { + m_window_removeEventListener.call(window, evt, handler, capture); + } +}; + +function createEvent(type, data) { + var event = document.createEvent('Events'); + event.initEvent(type, false, false); + if (data) { + for (var i in data) { + if (data.hasOwnProperty(i)) { + event[i] = data[i]; + } + } + } + return event; +} + + +var cordova = { + define:define, + require:require, + version:PLATFORM_VERSION_BUILD_LABEL, + platformVersion:PLATFORM_VERSION_BUILD_LABEL, + platformId:platform.id, + /** + * Methods to add/remove your own addEventListener hijacking on document + window. + */ + addWindowEventHandler:function(event) { + return (windowEventHandlers[event] = channel.create(event)); + }, + addStickyDocumentEventHandler:function(event) { + return (documentEventHandlers[event] = channel.createSticky(event)); + }, + addDocumentEventHandler:function(event) { + return (documentEventHandlers[event] = channel.create(event)); + }, + removeWindowEventHandler:function(event) { + delete windowEventHandlers[event]; + }, + removeDocumentEventHandler:function(event) { + delete documentEventHandlers[event]; + }, + /** + * Retrieve original event handlers that were replaced by Cordova + * + * @return object + */ + getOriginalHandlers: function() { + return {'document': {'addEventListener': m_document_addEventListener, 'removeEventListener': m_document_removeEventListener}, + 'window': {'addEventListener': m_window_addEventListener, 'removeEventListener': m_window_removeEventListener}}; + }, + /** + * Method to fire event from native code + * bNoDetach is required for events which cause an exception which needs to be caught in native code + */ + fireDocumentEvent: function(type, data, bNoDetach) { + var evt = createEvent(type, data); + if (typeof documentEventHandlers[type] != 'undefined') { + if( bNoDetach ) { + documentEventHandlers[type].fire(evt); + } + else { + setTimeout(function() { + // Fire deviceready on listeners that were registered before cordova.js was loaded. + if (type == 'deviceready') { + document.dispatchEvent(evt); + } + documentEventHandlers[type].fire(evt); + }, 0); + } + } else { + document.dispatchEvent(evt); + } + }, + fireWindowEvent: function(type, data) { + var evt = createEvent(type,data); + if (typeof windowEventHandlers[type] != 'undefined') { + setTimeout(function() { + windowEventHandlers[type].fire(evt); + }, 0); + } else { + window.dispatchEvent(evt); + } + }, + + /** + * Plugin callback mechanism. + */ + // Randomize the starting callbackId to avoid collisions after refreshing or navigating. + // This way, it's very unlikely that any new callback would get the same callbackId as an old callback. + callbackId: Math.floor(Math.random() * 2000000000), + callbacks: {}, + callbackStatus: { + NO_RESULT: 0, + OK: 1, + CLASS_NOT_FOUND_EXCEPTION: 2, + ILLEGAL_ACCESS_EXCEPTION: 3, + INSTANTIATION_EXCEPTION: 4, + MALFORMED_URL_EXCEPTION: 5, + IO_EXCEPTION: 6, + INVALID_ACTION: 7, + JSON_EXCEPTION: 8, + ERROR: 9 + }, + + /** + * Called by native code when returning successful result from an action. + */ + callbackSuccess: function(callbackId, args) { + cordova.callbackFromNative(callbackId, true, args.status, [args.message], args.keepCallback); + }, + + /** + * Called by native code when returning error result from an action. + */ + callbackError: function(callbackId, args) { + // TODO: Deprecate callbackSuccess and callbackError in favour of callbackFromNative. + // Derive success from status. + cordova.callbackFromNative(callbackId, false, args.status, [args.message], args.keepCallback); + }, + + /** + * Called by native code when returning the result from an action. + */ + callbackFromNative: function(callbackId, isSuccess, status, args, keepCallback) { + try { + var callback = cordova.callbacks[callbackId]; + if (callback) { + if (isSuccess && status == cordova.callbackStatus.OK) { + callback.success && callback.success.apply(null, args); + } else if (!isSuccess) { + callback.fail && callback.fail.apply(null, args); + } + /* + else + Note, this case is intentionally not caught. + this can happen if isSuccess is true, but callbackStatus is NO_RESULT + which is used to remove a callback from the list without calling the callbacks + typically keepCallback is false in this case + */ + // Clear callback if not expecting any more results + if (!keepCallback) { + delete cordova.callbacks[callbackId]; + } + } + } + catch (err) { + var msg = "Error in " + (isSuccess ? "Success" : "Error") + " callbackId: " + callbackId + " : " + err; + console && console.log && console.log(msg); + cordova.fireWindowEvent("cordovacallbackerror", { 'message': msg }); + throw err; + } + }, + addConstructor: function(func) { + channel.onCordovaReady.subscribe(function() { + try { + func(); + } catch(e) { + console.log("Failed to run constructor: " + e); + } + }); + } +}; + + +module.exports = cordova; + +}); + +// file: /Users/jbowser/cordova/cordova-android/cordova-js-src/android/nativeapiprovider.js +define("cordova/android/nativeapiprovider", function(require, exports, module) { + +/** + * Exports the ExposedJsApi.java object if available, otherwise exports the PromptBasedNativeApi. + */ + +var nativeApi = this._cordovaNative || require('cordova/android/promptbasednativeapi'); +var currentApi = nativeApi; + +module.exports = { + get: function() { return currentApi; }, + setPreferPrompt: function(value) { + currentApi = value ? require('cordova/android/promptbasednativeapi') : nativeApi; + }, + // Used only by tests. + set: function(value) { + currentApi = value; + } +}; + +}); + +// file: /Users/jbowser/cordova/cordova-android/cordova-js-src/android/promptbasednativeapi.js +define("cordova/android/promptbasednativeapi", function(require, exports, module) { + +/** + * Implements the API of ExposedJsApi.java, but uses prompt() to communicate. + * This is used pre-JellyBean, where addJavascriptInterface() is disabled. + */ + +module.exports = { + exec: function(bridgeSecret, service, action, callbackId, argsJson) { + return prompt(argsJson, 'gap:'+JSON.stringify([bridgeSecret, service, action, callbackId])); + }, + setNativeToJsBridgeMode: function(bridgeSecret, value) { + prompt(value, 'gap_bridge_mode:' + bridgeSecret); + }, + retrieveJsMessages: function(bridgeSecret, fromOnlineEvent) { + return prompt(+fromOnlineEvent, 'gap_poll:' + bridgeSecret); + } +}; + +}); + +// file: src/common/argscheck.js +define("cordova/argscheck", function(require, exports, module) { + +var utils = require('cordova/utils'); + +var moduleExports = module.exports; + +var typeMap = { + 'A': 'Array', + 'D': 'Date', + 'N': 'Number', + 'S': 'String', + 'F': 'Function', + 'O': 'Object' +}; + +function extractParamName(callee, argIndex) { + return (/.*?\((.*?)\)/).exec(callee)[1].split(', ')[argIndex]; +} + +function checkArgs(spec, functionName, args, opt_callee) { + if (!moduleExports.enableChecks) { + return; + } + var errMsg = null; + var typeName; + for (var i = 0; i < spec.length; ++i) { + var c = spec.charAt(i), + cUpper = c.toUpperCase(), + arg = args[i]; + // Asterix means allow anything. + if (c == '*') { + continue; + } + typeName = utils.typeName(arg); + if ((arg === null || arg === undefined) && c == cUpper) { + continue; + } + if (typeName != typeMap[cUpper]) { + errMsg = 'Expected ' + typeMap[cUpper]; + break; + } + } + if (errMsg) { + errMsg += ', but got ' + typeName + '.'; + errMsg = 'Wrong type for parameter "' + extractParamName(opt_callee || args.callee, i) + '" of ' + functionName + ': ' + errMsg; + // Don't log when running unit tests. + if (typeof jasmine == 'undefined') { + console.error(errMsg); + } + throw TypeError(errMsg); + } +} + +function getValue(value, defaultValue) { + return value === undefined ? defaultValue : value; +} + +moduleExports.checkArgs = checkArgs; +moduleExports.getValue = getValue; +moduleExports.enableChecks = true; + + +}); + +// file: src/common/base64.js +define("cordova/base64", function(require, exports, module) { + +var base64 = exports; + +base64.fromArrayBuffer = function(arrayBuffer) { + var array = new Uint8Array(arrayBuffer); + return uint8ToBase64(array); +}; + +base64.toArrayBuffer = function(str) { + var decodedStr = typeof atob != 'undefined' ? atob(str) : new Buffer(str,'base64').toString('binary'); + var arrayBuffer = new ArrayBuffer(decodedStr.length); + var array = new Uint8Array(arrayBuffer); + for (var i=0, len=decodedStr.length; i < len; i++) { + array[i] = decodedStr.charCodeAt(i); + } + return arrayBuffer; +}; + +//------------------------------------------------------------------------------ + +/* This code is based on the performance tests at http://jsperf.com/b64tests + * This 12-bit-at-a-time algorithm was the best performing version on all + * platforms tested. + */ + +var b64_6bit = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +var b64_12bit; + +var b64_12bitTable = function() { + b64_12bit = []; + for (var i=0; i<64; i++) { + for (var j=0; j<64; j++) { + b64_12bit[i*64+j] = b64_6bit[i] + b64_6bit[j]; + } + } + b64_12bitTable = function() { return b64_12bit; }; + return b64_12bit; +}; + +function uint8ToBase64(rawData) { + var numBytes = rawData.byteLength; + var output=""; + var segment; + var table = b64_12bitTable(); + for (var i=0;i> 12]; + output += table[segment & 0xfff]; + } + if (numBytes - i == 2) { + segment = (rawData[i] << 16) + (rawData[i+1] << 8); + output += table[segment >> 12]; + output += b64_6bit[(segment & 0xfff) >> 6]; + output += '='; + } else if (numBytes - i == 1) { + segment = (rawData[i] << 16); + output += table[segment >> 12]; + output += '=='; + } + return output; +} + +}); + +// file: src/common/builder.js +define("cordova/builder", function(require, exports, module) { + +var utils = require('cordova/utils'); + +function each(objects, func, context) { + for (var prop in objects) { + if (objects.hasOwnProperty(prop)) { + func.apply(context, [objects[prop], prop]); + } + } +} + +function clobber(obj, key, value) { + exports.replaceHookForTesting(obj, key); + var needsProperty = false; + try { + obj[key] = value; + } catch (e) { + needsProperty = true; + } + // Getters can only be overridden by getters. + if (needsProperty || obj[key] !== value) { + utils.defineGetter(obj, key, function() { + return value; + }); + } +} + +function assignOrWrapInDeprecateGetter(obj, key, value, message) { + if (message) { + utils.defineGetter(obj, key, function() { + console.log(message); + delete obj[key]; + clobber(obj, key, value); + return value; + }); + } else { + clobber(obj, key, value); + } +} + +function include(parent, objects, clobber, merge) { + each(objects, function (obj, key) { + try { + var result = obj.path ? require(obj.path) : {}; + + if (clobber) { + // Clobber if it doesn't exist. + if (typeof parent[key] === 'undefined') { + assignOrWrapInDeprecateGetter(parent, key, result, obj.deprecated); + } else if (typeof obj.path !== 'undefined') { + // If merging, merge properties onto parent, otherwise, clobber. + if (merge) { + recursiveMerge(parent[key], result); + } else { + assignOrWrapInDeprecateGetter(parent, key, result, obj.deprecated); + } + } + result = parent[key]; } else { - clobber(obj, key, value); - } - } - - function include (parent, objects, clobber, merge) { - each(objects, function (obj, key) { - try { - var result = obj.path ? require(obj.path) : {}; - - if (clobber) { - // Clobber if it doesn't exist. - if (typeof parent[key] === 'undefined') { - assignOrWrapInDeprecateGetter(parent, key, result, obj.deprecated); - } else if (typeof obj.path !== 'undefined') { - // If merging, merge properties onto parent, otherwise, clobber. - if (merge) { - recursiveMerge(parent[key], result); - } else { - assignOrWrapInDeprecateGetter(parent, key, result, obj.deprecated); - } - } - result = parent[key]; - } else { - // Overwrite if not currently defined. - if (typeof parent[key] === 'undefined') { - assignOrWrapInDeprecateGetter(parent, key, result, obj.deprecated); - } else { - // Set result to what already exists, so we can build children into it if they exist. - result = parent[key]; - } - } - - if (obj.children) { - include(result, obj.children, clobber, merge); - } - } catch (e) { - utils.alert('Exception building Cordova JS globals: ' + e + ' for key "' + key + '"'); - } - }); - } - - /** - * Merge properties from one object onto another recursively. Properties from - * the src object will overwrite existing target property. - * - * @param target Object to merge properties into. - * @param src Object to merge properties from. - */ - function recursiveMerge (target, src) { - for (var prop in src) { - if (src.hasOwnProperty(prop)) { - if (target.prototype && target.prototype.constructor === target) { - // If the target object is a constructor override off prototype. - clobber(target.prototype, prop, src[prop]); - } else { - if (typeof src[prop] === 'object' && typeof target[prop] === 'object') { - recursiveMerge(target[prop], src[prop]); - } else { - clobber(target, prop, src[prop]); - } - } + // Overwrite if not currently defined. + if (typeof parent[key] == 'undefined') { + assignOrWrapInDeprecateGetter(parent, key, result, obj.deprecated); + } else { + // Set result to what already exists, so we can build children into it if they exist. + result = parent[key]; } } + + if (obj.children) { + include(result, obj.children, clobber, merge); + } + } catch(e) { + utils.alert('Exception building Cordova JS globals: ' + e + ' for key "' + key + '"'); } - - exports.buildIntoButDoNotClobber = function (objects, target) { - include(target, objects, false, false); - }; - exports.buildIntoAndClobber = function (objects, target) { - include(target, objects, true, false); - }; - exports.buildIntoAndMerge = function (objects, target) { - include(target, objects, true, true); - }; - exports.recursiveMerge = recursiveMerge; - exports.assignOrWrapInDeprecateGetter = assignOrWrapInDeprecateGetter; - exports.replaceHookForTesting = function () {}; - }); +} - // file: src/common/channel.js - define('cordova/channel', function (require, exports, module) { +/** + * Merge properties from one object onto another recursively. Properties from + * the src object will overwrite existing target property. + * + * @param target Object to merge properties into. + * @param src Object to merge properties from. + */ +function recursiveMerge(target, src) { + for (var prop in src) { + if (src.hasOwnProperty(prop)) { + if (target.prototype && target.prototype.constructor === target) { + // If the target object is a constructor override off prototype. + clobber(target.prototype, prop, src[prop]); + } else { + if (typeof src[prop] === 'object' && typeof target[prop] === 'object') { + recursiveMerge(target[prop], src[prop]); + } else { + clobber(target, prop, src[prop]); + } + } + } + } +} - var utils = require('cordova/utils'); - var nextGuid = 1; +exports.buildIntoButDoNotClobber = function(objects, target) { + include(target, objects, false, false); +}; +exports.buildIntoAndClobber = function(objects, target) { + include(target, objects, true, false); +}; +exports.buildIntoAndMerge = function(objects, target) { + include(target, objects, true, true); +}; +exports.recursiveMerge = recursiveMerge; +exports.assignOrWrapInDeprecateGetter = assignOrWrapInDeprecateGetter; +exports.replaceHookForTesting = function() {}; +}); + +// file: src/common/channel.js +define("cordova/channel", function(require, exports, module) { + +var utils = require('cordova/utils'), + nextGuid = 1; + +/** + * Custom pub-sub "channel" that can have functions subscribed to it + * This object is used to define and control firing of events for + * cordova initialization, as well as for custom events thereafter. + * + * The order of events during page load and Cordova startup is as follows: + * + * onDOMContentLoaded* Internal event that is received when the web page is loaded and parsed. + * onNativeReady* Internal event that indicates the Cordova native side is ready. + * onCordovaReady* Internal event fired when all Cordova JavaScript objects have been created. + * onDeviceReady* User event fired to indicate that Cordova is ready + * onResume User event fired to indicate a start/resume lifecycle event + * onPause User event fired to indicate a pause lifecycle event + * + * The events marked with an * are sticky. Once they have fired, they will stay in the fired state. + * All listeners that subscribe after the event is fired will be executed right away. + * + * The only Cordova events that user code should register for are: + * deviceready Cordova native code is initialized and Cordova APIs can be called from JavaScript + * pause App has moved to background + * resume App has returned to foreground + * + * Listeners can be registered as: + * document.addEventListener("deviceready", myDeviceReadyListener, false); + * document.addEventListener("resume", myResumeListener, false); + * document.addEventListener("pause", myPauseListener, false); + * + * The DOM lifecycle events should be used for saving and restoring state + * window.onload + * window.onunload + * + */ + +/** + * Channel + * @constructor + * @param type String the channel name + */ +var Channel = function(type, sticky) { + this.type = type; + // Map of guid -> function. + this.handlers = {}; + // 0 = Non-sticky, 1 = Sticky non-fired, 2 = Sticky fired. + this.state = sticky ? 1 : 0; + // Used in sticky mode to remember args passed to fire(). + this.fireArgs = null; + // Used by onHasSubscribersChange to know if there are any listeners. + this.numHandlers = 0; + // Function that is called when the first listener is subscribed, or when + // the last listener is unsubscribed. + this.onHasSubscribersChange = null; +}, + channel = { /** - * Custom pub-sub "channel" that can have functions subscribed to it - * This object is used to define and control firing of events for - * cordova initialization, as well as for custom events thereafter. - * - * The order of events during page load and Cordova startup is as follows: - * - * onDOMContentLoaded* Internal event that is received when the web page is loaded and parsed. - * onNativeReady* Internal event that indicates the Cordova native side is ready. - * onCordovaReady* Internal event fired when all Cordova JavaScript objects have been created. - * onDeviceReady* User event fired to indicate that Cordova is ready - * onResume User event fired to indicate a start/resume lifecycle event - * onPause User event fired to indicate a pause lifecycle event - * - * The events marked with an * are sticky. Once they have fired, they will stay in the fired state. - * All listeners that subscribe after the event is fired will be executed right away. - * - * The only Cordova events that user code should register for are: - * deviceready Cordova native code is initialized and Cordova APIs can be called from JavaScript - * pause App has moved to background - * resume App has returned to foreground - * - * Listeners can be registered as: - * document.addEventListener("deviceready", myDeviceReadyListener, false); - * document.addEventListener("resume", myResumeListener, false); - * document.addEventListener("pause", myPauseListener, false); - * - * The DOM lifecycle events should be used for saving and restoring state - * window.onload - * window.onunload - * + * Calls the provided function only after all of the channels specified + * have been fired. All channels must be sticky channels. */ - - /** - * Channel - * @constructor - * @param type String the channel name - */ - var Channel = function (type, sticky) { - this.type = type; - // Map of guid -> function. - this.handlers = {}; - // 0 = Non-sticky, 1 = Sticky non-fired, 2 = Sticky fired. - this.state = sticky ? 1 : 0; - // Used in sticky mode to remember args passed to fire(). - this.fireArgs = null; - // Used by onHasSubscribersChange to know if there are any listeners. - this.numHandlers = 0; - // Function that is called when the first listener is subscribed, or when - // the last listener is unsubscribed. - this.onHasSubscribersChange = null; - }; - var channel = { - /** - * Calls the provided function only after all of the channels specified - * have been fired. All channels must be sticky channels. - */ - join: function (h, c) { - var len = c.length; - var i = len; - var f = function () { + join: function(h, c) { + var len = c.length, + i = len, + f = function() { if (!(--i)) h(); }; - for (var j = 0; j < len; j++) { - if (c[j].state === 0) { - throw Error('Can only use join with sticky channels.'); - } - c[j].subscribe(f); - } - if (!len) h(); - }, - create: function (type) { - return (channel[type] = new Channel(type, false)); - }, - createSticky: function (type) { - return (channel[type] = new Channel(type, true)); - }, - - /** - * cordova Channels that must fire before "deviceready" is fired. - */ - deviceReadyChannelsArray: [], - deviceReadyChannelsMap: {}, - - /** - * Indicate that a feature needs to be initialized before it is ready to be used. - * This holds up Cordova's "deviceready" event until the feature has been initialized - * and Cordova.initComplete(feature) is called. - * - * @param feature {String} The unique feature name - */ - waitForInitialization: function (feature) { - if (feature) { - var c = channel[feature] || this.createSticky(feature); - this.deviceReadyChannelsMap[feature] = c; - this.deviceReadyChannelsArray.push(c); - } - }, - - /** - * Indicate that initialization code has completed and the feature is ready to be used. - * - * @param feature {String} The unique feature name - */ - initializationComplete: function (feature) { - var c = this.deviceReadyChannelsMap[feature]; - if (c) { - c.fire(); + for (var j=0; jNative bridge. - POLLING: 0, - // For LOAD_URL to be viable, it would need to have a work-around for - // the bug where the soft-keyboard gets dismissed when a message is sent. - LOAD_URL: 1, - // For the ONLINE_EVENT to be viable, it would need to intercept all event - // listeners (both through addEventListener and window.ononline) as well - // as set the navigator property itself. - ONLINE_EVENT: 2, - EVAL_BRIDGE: 3 - }; - var jsToNativeBridgeMode; // Set lazily. - var nativeToJsBridgeMode = nativeToJsModes.EVAL_BRIDGE; - var pollEnabled = false; - var bridgeSecret = -1; - - var messagesFromNative = []; - var isProcessing = false; - var resolvedPromise = typeof Promise === 'undefined' ? null : Promise.resolve(); - var nextTick = resolvedPromise ? function (fn) { resolvedPromise.then(fn); } : function (fn) { setTimeout(fn); }; - - function androidExec (success, fail, service, action, args) { - if (bridgeSecret < 0) { - // If we ever catch this firing, we'll need to queue up exec()s - // and fire them once we get a secret. For now, I don't think - // it's possible for exec() to be called since plugins are parsed but - // not run until until after onNativeReady. - throw new Error('exec() called without bridgeSecret'); + waitForInitialization: function(feature) { + if (feature) { + var c = channel[feature] || this.createSticky(feature); + this.deviceReadyChannelsMap[feature] = c; + this.deviceReadyChannelsArray.push(c); } - // Set default bridge modes if they have not already been set. - // By default, we use the failsafe, since addJavascriptInterface breaks too often - if (jsToNativeBridgeMode === undefined) { - androidExec.setJsToNativeBridgeMode(jsToNativeModes.JS_OBJECT); - } - - // If args is not provided, default to an empty array - args = args || []; - - // Process any ArrayBuffers in the args into a string. - for (var i = 0; i < args.length; i++) { - if (utils.typeName(args[i]) === 'ArrayBuffer') { - args[i] = base64.fromArrayBuffer(args[i]); - } - } - - var callbackId = service + cordova.callbackId++; - var argsJson = JSON.stringify(args); - if (success || fail) { - cordova.callbacks[callbackId] = {success: success, fail: fail}; - } - - var msgs = nativeApiProvider.get().exec(bridgeSecret, service, action, callbackId, argsJson); - // If argsJson was received by Java as null, try again with the PROMPT bridge mode. - // This happens in rare circumstances, such as when certain Unicode characters are passed over the bridge on a Galaxy S2. See CB-2666. - if (jsToNativeBridgeMode === jsToNativeModes.JS_OBJECT && msgs === '@Null arguments.') { - androidExec.setJsToNativeBridgeMode(jsToNativeModes.PROMPT); - androidExec(success, fail, service, action, args); - androidExec.setJsToNativeBridgeMode(jsToNativeModes.JS_OBJECT); - } else if (msgs) { - messagesFromNative.push(msgs); - // Always process async to avoid exceptions messing up stack. - nextTick(processMessages); - } - } - - androidExec.init = function () { - // CB-11828 - // This failsafe checks the version of Android and if it's Jellybean, it switches it to - // using the Online Event bridge for communicating from Native to JS - // - // It's ugly, but it's necessary. - var check = navigator.userAgent.toLowerCase().match(/android\s[0-9].[0-9]/); - var version_code = check && check[0].match(/4.[0-3].*/); - if (version_code !== null && nativeToJsBridgeMode === nativeToJsModes.EVAL_BRIDGE) { - nativeToJsBridgeMode = nativeToJsModes.ONLINE_EVENT; - } - - bridgeSecret = +prompt('', 'gap_init:' + nativeToJsBridgeMode); - channel.onNativeReady.fire(); - }; - - function pollOnceFromOnlineEvent () { - pollOnce(true); - } - - function pollOnce (opt_fromOnlineEvent) { - if (bridgeSecret < 0) { - // This can happen when the NativeToJsMessageQueue resets the online state on page transitions. - // We know there's nothing to retrieve, so no need to poll. - return; - } - var msgs = nativeApiProvider.get().retrieveJsMessages(bridgeSecret, !!opt_fromOnlineEvent); - if (msgs) { - messagesFromNative.push(msgs); - // Process sync since we know we're already top-of-stack. - processMessages(); - } - } - - function pollingTimerFunc () { - if (pollEnabled) { - pollOnce(); - setTimeout(pollingTimerFunc, 50); - } - } - - function hookOnlineApis () { - function proxyEvent (e) { - cordova.fireWindowEvent(e.type); - } - // The network module takes care of firing online and offline events. - // It currently fires them only on document though, so we bridge them - // to window here (while first listening for exec()-releated online/offline - // events). - window.addEventListener('online', pollOnceFromOnlineEvent, false); - window.addEventListener('offline', pollOnceFromOnlineEvent, false); - cordova.addWindowEventHandler('online'); - cordova.addWindowEventHandler('offline'); - document.addEventListener('online', proxyEvent, false); - document.addEventListener('offline', proxyEvent, false); - } - - hookOnlineApis(); - - androidExec.jsToNativeModes = jsToNativeModes; - androidExec.nativeToJsModes = nativeToJsModes; - - androidExec.setJsToNativeBridgeMode = function (mode) { - if (mode === jsToNativeModes.JS_OBJECT && !window._cordovaNative) { - mode = jsToNativeModes.PROMPT; - } - nativeApiProvider.setPreferPrompt(mode === jsToNativeModes.PROMPT); - jsToNativeBridgeMode = mode; - }; - - androidExec.setNativeToJsBridgeMode = function (mode) { - if (mode === nativeToJsBridgeMode) { - return; - } - if (nativeToJsBridgeMode === nativeToJsModes.POLLING) { - pollEnabled = false; - } - - nativeToJsBridgeMode = mode; - // Tell the native side to switch modes. - // Otherwise, it will be set by androidExec.init() - if (bridgeSecret >= 0) { - nativeApiProvider.get().setNativeToJsBridgeMode(bridgeSecret, mode); - } - - if (mode === nativeToJsModes.POLLING) { - pollEnabled = true; - setTimeout(pollingTimerFunc, 1); - } - }; - - function buildPayload (payload, message) { - var payloadKind = message.charAt(0); - if (payloadKind === 's') { - payload.push(message.slice(1)); - } else if (payloadKind === 't') { - payload.push(true); - } else if (payloadKind === 'f') { - payload.push(false); - } else if (payloadKind === 'N') { - payload.push(null); - } else if (payloadKind === 'n') { - payload.push(+message.slice(1)); - } else if (payloadKind === 'A') { - var data = message.slice(1); - payload.push(base64.toArrayBuffer(data)); - } else if (payloadKind === 'S') { - payload.push(window.atob(message.slice(1))); - } else if (payloadKind === 'M') { - var multipartMessages = message.slice(1); - while (multipartMessages !== '') { - var spaceIdx = multipartMessages.indexOf(' '); - var msgLen = +multipartMessages.slice(0, spaceIdx); - var multipartMessage = multipartMessages.substr(spaceIdx + 1, msgLen); - multipartMessages = multipartMessages.slice(spaceIdx + msgLen + 1); - buildPayload(payload, multipartMessage); - } - } else { - payload.push(JSON.parse(message)); - } - } - - // Processes a single message, as encoded by NativeToJsMessageQueue.java. - function processMessage (message) { - var firstChar = message.charAt(0); - if (firstChar === 'J') { - // This is deprecated on the .java side. It doesn't work with CSP enabled. - eval(message.slice(1)); - } else if (firstChar === 'S' || firstChar === 'F') { - var success = firstChar === 'S'; - var keepCallback = message.charAt(1) === '1'; - var spaceIdx = message.indexOf(' ', 2); - var status = +message.slice(2, spaceIdx); - var nextSpaceIdx = message.indexOf(' ', spaceIdx + 1); - var callbackId = message.slice(spaceIdx + 1, nextSpaceIdx); - var payloadMessage = message.slice(nextSpaceIdx + 1); - var payload = []; - buildPayload(payload, payloadMessage); - cordova.callbackFromNative(callbackId, success, status, payload, keepCallback); - } else { - console.log('processMessage failed: invalid message: ' + JSON.stringify(message)); - } - } - - function processMessages () { - // Check for the reentrant case. - if (isProcessing) { - return; - } - if (messagesFromNative.length === 0) { - return; - } - isProcessing = true; - try { - var msg = popMessageFromQueue(); - // The Java side can send a * message to indicate that it - // still has messages waiting to be retrieved. - if (msg === '*' && messagesFromNative.length === 0) { - nextTick(pollOnce); - return; - } - processMessage(msg); - } finally { - isProcessing = false; - if (messagesFromNative.length > 0) { - nextTick(processMessages); - } - } - } - - function popMessageFromQueue () { - var messageBatch = messagesFromNative.shift(); - if (messageBatch === '*') { - return '*'; - } - - var spaceIdx = messageBatch.indexOf(' '); - var msgLen = +messageBatch.slice(0, spaceIdx); - var message = messageBatch.substr(spaceIdx + 1, msgLen); - messageBatch = messageBatch.slice(spaceIdx + msgLen + 1); - if (messageBatch) { - messagesFromNative.unshift(messageBatch); - } - return message; - } - - module.exports = androidExec; - - }); - - // file: src/common/exec/proxy.js - define('cordova/exec/proxy', function (require, exports, module) { - - // internal map of proxy function - var CommandProxyMap = {}; - - module.exports = { - - // example: cordova.commandProxy.add("Accelerometer",{getCurrentAcceleration: function(successCallback, errorCallback, options) {...},...); - add: function (id, proxyObj) { - console.log('adding proxy for ' + id); - CommandProxyMap[id] = proxyObj; - return proxyObj; - }, - - // cordova.commandProxy.remove("Accelerometer"); - remove: function (id) { - var proxy = CommandProxyMap[id]; - delete CommandProxyMap[id]; - CommandProxyMap[id] = null; - return proxy; - }, - - get: function (service, action) { - return (CommandProxyMap[service] ? CommandProxyMap[service][action] : null); - } - }; - }); - - // file: src/common/init.js - define('cordova/init', function (require, exports, module) { - - var channel = require('cordova/channel'); - var cordova = require('cordova'); - var modulemapper = require('cordova/modulemapper'); - var platform = require('cordova/platform'); - var pluginloader = require('cordova/pluginloader'); - var utils = require('cordova/utils'); - - var platformInitChannelsArray = [channel.onNativeReady, channel.onPluginsReady]; - - function logUnfiredChannels (arr) { - for (var i = 0; i < arr.length; ++i) { - if (arr[i].state !== 2) { - console.log('Channel not fired: ' + arr[i].type); - } - } - } - - window.setTimeout(function () { - if (channel.onDeviceReady.state !== 2) { - console.log('deviceready has not fired after 5 seconds.'); - logUnfiredChannels(platformInitChannelsArray); - logUnfiredChannels(channel.deviceReadyChannelsArray); - } - }, 5000); - - // Replace navigator before any modules are required(), to ensure it happens as soon as possible. - // We replace it so that properties that can't be clobbered can instead be overridden. - function replaceNavigator (origNavigator) { - var CordovaNavigator = function () {}; - CordovaNavigator.prototype = origNavigator; - var newNavigator = new CordovaNavigator(); - // This work-around really only applies to new APIs that are newer than Function.bind. - // Without it, APIs such as getGamepads() break. - if (CordovaNavigator.bind) { - for (var key in origNavigator) { - if (typeof origNavigator[key] === 'function') { - newNavigator[key] = origNavigator[key].bind(origNavigator); - } else { - (function (k) { - utils.defineGetterSetter(newNavigator, key, function () { - return origNavigator[k]; - }); - })(key); - } - } - } - return newNavigator; - } - - if (window.navigator) { - window.navigator = replaceNavigator(window.navigator); - } - - if (!window.console) { - window.console = { - log: function () {} - }; - } - if (!window.console.warn) { - window.console.warn = function (msg) { - this.log('warn: ' + msg); - }; - } - - // Register pause, resume and deviceready channels as events on document. - channel.onPause = cordova.addDocumentEventHandler('pause'); - channel.onResume = cordova.addDocumentEventHandler('resume'); - channel.onActivated = cordova.addDocumentEventHandler('activated'); - channel.onDeviceReady = cordova.addStickyDocumentEventHandler('deviceready'); - - // Listen for DOMContentLoaded and notify our channel subscribers. - if (document.readyState === 'complete' || document.readyState === 'interactive') { - channel.onDOMContentLoaded.fire(); - } else { - document.addEventListener('DOMContentLoaded', function () { - channel.onDOMContentLoaded.fire(); - }, false); - } - - // _nativeReady is global variable that the native side can set - // to signify that the native code is ready. It is a global since - // it may be called before any cordova JS is ready. - if (window._nativeReady) { - channel.onNativeReady.fire(); - } - - modulemapper.clobbers('cordova', 'cordova'); - modulemapper.clobbers('cordova/exec', 'cordova.exec'); - modulemapper.clobbers('cordova/exec', 'Cordova.exec'); - - // Call the platform-specific initialization. - platform.bootstrap && platform.bootstrap(); - - // Wrap in a setTimeout to support the use-case of having plugin JS appended to cordova.js. - // The delay allows the attached modules to be defined before the plugin loader looks for them. - setTimeout(function () { - pluginloader.load(function () { - channel.onPluginsReady.fire(); - }); - }, 0); + }, /** - * Create all cordova objects once native side is ready. + * Indicate that initialization code has completed and the feature is ready to be used. + * + * @param feature {String} The unique feature name */ - channel.join(function () { - modulemapper.mapModules(window); + initializationComplete: function(feature) { + var c = this.deviceReadyChannelsMap[feature]; + if (c) { + c.fire(); + } + } + }; - platform.initialize && platform.initialize(); +function checkSubscriptionArgument(argument) { + if (typeof argument !== "function" && typeof argument.handleEvent !== "function") { + throw new Error( + "Must provide a function or an EventListener object " + + "implementing the handleEvent interface." + ); + } +} - // Fire event to notify that all objects are created - channel.onCordovaReady.fire(); +/** + * Subscribes the given function to the channel. Any time that + * Channel.fire is called so too will the function. + * Optionally specify an execution context for the function + * and a guid that can be used to stop subscribing to the channel. + * Returns the guid. + */ +Channel.prototype.subscribe = function(eventListenerOrFunction, eventListener) { + checkSubscriptionArgument(eventListenerOrFunction); + var handleEvent, guid; - // Fire onDeviceReady event once page has fully loaded, all - // constructors have run and cordova info has been received from native - // side. - channel.join(function () { - require('cordova').fireDocumentEvent('deviceready'); - }, channel.deviceReadyChannelsArray); + if (eventListenerOrFunction && typeof eventListenerOrFunction === "object") { + // Received an EventListener object implementing the handleEvent interface + handleEvent = eventListenerOrFunction.handleEvent; + eventListener = eventListenerOrFunction; + } else { + // Received a function to handle event + handleEvent = eventListenerOrFunction; + } - }, platformInitChannelsArray); + if (this.state == 2) { + handleEvent.apply(eventListener || this, this.fireArgs); + return; + } + guid = eventListenerOrFunction.observer_guid; + if (typeof eventListener === "object") { + handleEvent = utils.close(eventListener, handleEvent); + } + + if (!guid) { + // First time any channel has seen this subscriber + guid = '' + nextGuid++; + } + handleEvent.observer_guid = guid; + eventListenerOrFunction.observer_guid = guid; + + // Don't add the same handler more than once. + if (!this.handlers[guid]) { + this.handlers[guid] = handleEvent; + this.numHandlers++; + if (this.numHandlers == 1) { + this.onHasSubscribersChange && this.onHasSubscribersChange(); + } + } +}; + +/** + * Unsubscribes the function with the given guid from the channel. + */ +Channel.prototype.unsubscribe = function(eventListenerOrFunction) { + checkSubscriptionArgument(eventListenerOrFunction); + var handleEvent, guid, handler; + + if (eventListenerOrFunction && typeof eventListenerOrFunction === "object") { + // Received an EventListener object implementing the handleEvent interface + handleEvent = eventListenerOrFunction.handleEvent; + } else { + // Received a function to handle event + handleEvent = eventListenerOrFunction; + } + + guid = handleEvent.observer_guid; + handler = this.handlers[guid]; + if (handler) { + delete this.handlers[guid]; + this.numHandlers--; + if (this.numHandlers === 0) { + this.onHasSubscribersChange && this.onHasSubscribersChange(); + } + } +}; + +/** + * Calls all functions subscribed to this channel. + */ +Channel.prototype.fire = function(e) { + var fail = false, + fireArgs = Array.prototype.slice.call(arguments); + // Apply stickiness. + if (this.state == 1) { + this.state = 2; + this.fireArgs = fireArgs; + } + if (this.numHandlers) { + // Copy the values first so that it is safe to modify it from within + // callbacks. + var toCall = []; + for (var item in this.handlers) { + toCall.push(this.handlers[item]); + } + for (var i = 0; i < toCall.length; ++i) { + toCall[i].apply(this, fireArgs); + } + if (this.state == 2 && this.numHandlers) { + this.numHandlers = 0; + this.handlers = {}; + this.onHasSubscribersChange && this.onHasSubscribersChange(); + } + } +}; + + +// defining them here so they are ready super fast! +// DOM event that is received when the web page is loaded and parsed. +channel.createSticky('onDOMContentLoaded'); + +// Event to indicate the Cordova native side is ready. +channel.createSticky('onNativeReady'); + +// Event to indicate that all Cordova JavaScript objects have been created +// and it's time to run plugin constructors. +channel.createSticky('onCordovaReady'); + +// Event to indicate that all automatically loaded JS plugins are loaded and ready. +// FIXME remove this +channel.createSticky('onPluginsReady'); + +// Event to indicate that Cordova is ready +channel.createSticky('onDeviceReady'); + +// Event to indicate a resume lifecycle event +channel.create('onResume'); + +// Event to indicate a pause lifecycle event +channel.create('onPause'); + +// Channels that must fire before "deviceready" is fired. +channel.waitForInitialization('onCordovaReady'); +channel.waitForInitialization('onDOMContentLoaded'); + +module.exports = channel; + +}); + +// file: /Users/jbowser/cordova/cordova-android/cordova-js-src/exec.js +define("cordova/exec", function(require, exports, module) { + +/** + * Execute a cordova command. It is up to the native side whether this action + * is synchronous or asynchronous. The native side can return: + * Synchronous: PluginResult object as a JSON string + * Asynchronous: Empty string "" + * If async, the native side will cordova.callbackSuccess or cordova.callbackError, + * depending upon the result of the action. + * + * @param {Function} success The success callback + * @param {Function} fail The fail callback + * @param {String} service The name of the service to use + * @param {String} action Action to be run in cordova + * @param {String[]} [args] Zero or more arguments to pass to the method + */ +var cordova = require('cordova'), + nativeApiProvider = require('cordova/android/nativeapiprovider'), + utils = require('cordova/utils'), + base64 = require('cordova/base64'), + channel = require('cordova/channel'), + jsToNativeModes = { + PROMPT: 0, + JS_OBJECT: 1 + }, + nativeToJsModes = { + // Polls for messages using the JS->Native bridge. + POLLING: 0, + // For LOAD_URL to be viable, it would need to have a work-around for + // the bug where the soft-keyboard gets dismissed when a message is sent. + LOAD_URL: 1, + // For the ONLINE_EVENT to be viable, it would need to intercept all event + // listeners (both through addEventListener and window.ononline) as well + // as set the navigator property itself. + ONLINE_EVENT: 2, + EVAL_BRIDGE: 3 + }, + jsToNativeBridgeMode, // Set lazily. + nativeToJsBridgeMode = nativeToJsModes.EVAL_BRIDGE, + pollEnabled = false, + bridgeSecret = -1; + +var messagesFromNative = []; +var isProcessing = false; +var resolvedPromise = typeof Promise == 'undefined' ? null : Promise.resolve(); +var nextTick = resolvedPromise ? function(fn) { resolvedPromise.then(fn); } : function(fn) { setTimeout(fn); }; + +function androidExec(success, fail, service, action, args) { + if (bridgeSecret < 0) { + // If we ever catch this firing, we'll need to queue up exec()s + // and fire them once we get a secret. For now, I don't think + // it's possible for exec() to be called since plugins are parsed but + // not run until until after onNativeReady. + throw new Error('exec() called without bridgeSecret'); + } + // Set default bridge modes if they have not already been set. + // By default, we use the failsafe, since addJavascriptInterface breaks too often + if (jsToNativeBridgeMode === undefined) { + androidExec.setJsToNativeBridgeMode(jsToNativeModes.JS_OBJECT); + } + + // If args is not provided, default to an empty array + args = args || []; + + // Process any ArrayBuffers in the args into a string. + for (var i = 0; i < args.length; i++) { + if (utils.typeName(args[i]) == 'ArrayBuffer') { + args[i] = base64.fromArrayBuffer(args[i]); + } + } + + var callbackId = service + cordova.callbackId++, + argsJson = JSON.stringify(args); + if (success || fail) { + cordova.callbacks[callbackId] = {success:success, fail:fail}; + } + + var msgs = nativeApiProvider.get().exec(bridgeSecret, service, action, callbackId, argsJson); + // If argsJson was received by Java as null, try again with the PROMPT bridge mode. + // This happens in rare circumstances, such as when certain Unicode characters are passed over the bridge on a Galaxy S2. See CB-2666. + if (jsToNativeBridgeMode == jsToNativeModes.JS_OBJECT && msgs === "@Null arguments.") { + androidExec.setJsToNativeBridgeMode(jsToNativeModes.PROMPT); + androidExec(success, fail, service, action, args); + androidExec.setJsToNativeBridgeMode(jsToNativeModes.JS_OBJECT); + } else if (msgs) { + messagesFromNative.push(msgs); + // Always process async to avoid exceptions messing up stack. + nextTick(processMessages); + } +} + +androidExec.init = function() { + //CB-11828 + //This failsafe checks the version of Android and if it's Jellybean, it switches it to + //using the Online Event bridge for communicating from Native to JS + // + //It's ugly, but it's necessary. + var check = navigator.userAgent.toLowerCase().match(/android\s[0-9].[0-9]/); + var version_code = check && check[0].match(/4.[0-3].*/); + if (version_code != null && nativeToJsBridgeMode == nativeToJsModes.EVAL_BRIDGE) { + nativeToJsBridgeMode = nativeToJsModes.ONLINE_EVENT; + } + + bridgeSecret = +prompt('', 'gap_init:' + nativeToJsBridgeMode); + channel.onNativeReady.fire(); +}; + +function pollOnceFromOnlineEvent() { + pollOnce(true); +} + +function pollOnce(opt_fromOnlineEvent) { + if (bridgeSecret < 0) { + // This can happen when the NativeToJsMessageQueue resets the online state on page transitions. + // We know there's nothing to retrieve, so no need to poll. + return; + } + var msgs = nativeApiProvider.get().retrieveJsMessages(bridgeSecret, !!opt_fromOnlineEvent); + if (msgs) { + messagesFromNative.push(msgs); + // Process sync since we know we're already top-of-stack. + processMessages(); + } +} + +function pollingTimerFunc() { + if (pollEnabled) { + pollOnce(); + setTimeout(pollingTimerFunc, 50); + } +} + +function hookOnlineApis() { + function proxyEvent(e) { + cordova.fireWindowEvent(e.type); + } + // The network module takes care of firing online and offline events. + // It currently fires them only on document though, so we bridge them + // to window here (while first listening for exec()-releated online/offline + // events). + window.addEventListener('online', pollOnceFromOnlineEvent, false); + window.addEventListener('offline', pollOnceFromOnlineEvent, false); + cordova.addWindowEventHandler('online'); + cordova.addWindowEventHandler('offline'); + document.addEventListener('online', proxyEvent, false); + document.addEventListener('offline', proxyEvent, false); +} + +hookOnlineApis(); + +androidExec.jsToNativeModes = jsToNativeModes; +androidExec.nativeToJsModes = nativeToJsModes; + +androidExec.setJsToNativeBridgeMode = function(mode) { + if (mode == jsToNativeModes.JS_OBJECT && !window._cordovaNative) { + mode = jsToNativeModes.PROMPT; + } + nativeApiProvider.setPreferPrompt(mode == jsToNativeModes.PROMPT); + jsToNativeBridgeMode = mode; +}; + +androidExec.setNativeToJsBridgeMode = function(mode) { + if (mode == nativeToJsBridgeMode) { + return; + } + if (nativeToJsBridgeMode == nativeToJsModes.POLLING) { + pollEnabled = false; + } + + nativeToJsBridgeMode = mode; + // Tell the native side to switch modes. + // Otherwise, it will be set by androidExec.init() + if (bridgeSecret >= 0) { + nativeApiProvider.get().setNativeToJsBridgeMode(bridgeSecret, mode); + } + + if (mode == nativeToJsModes.POLLING) { + pollEnabled = true; + setTimeout(pollingTimerFunc, 1); + } +}; + +function buildPayload(payload, message) { + var payloadKind = message.charAt(0); + if (payloadKind == 's') { + payload.push(message.slice(1)); + } else if (payloadKind == 't') { + payload.push(true); + } else if (payloadKind == 'f') { + payload.push(false); + } else if (payloadKind == 'N') { + payload.push(null); + } else if (payloadKind == 'n') { + payload.push(+message.slice(1)); + } else if (payloadKind == 'A') { + var data = message.slice(1); + payload.push(base64.toArrayBuffer(data)); + } else if (payloadKind == 'S') { + payload.push(window.atob(message.slice(1))); + } else if (payloadKind == 'M') { + var multipartMessages = message.slice(1); + while (multipartMessages !== "") { + var spaceIdx = multipartMessages.indexOf(' '); + var msgLen = +multipartMessages.slice(0, spaceIdx); + var multipartMessage = multipartMessages.substr(spaceIdx + 1, msgLen); + multipartMessages = multipartMessages.slice(spaceIdx + msgLen + 1); + buildPayload(payload, multipartMessage); + } + } else { + payload.push(JSON.parse(message)); + } +} + +// Processes a single message, as encoded by NativeToJsMessageQueue.java. +function processMessage(message) { + var firstChar = message.charAt(0); + if (firstChar == 'J') { + // This is deprecated on the .java side. It doesn't work with CSP enabled. + eval(message.slice(1)); + } else if (firstChar == 'S' || firstChar == 'F') { + var success = firstChar == 'S'; + var keepCallback = message.charAt(1) == '1'; + var spaceIdx = message.indexOf(' ', 2); + var status = +message.slice(2, spaceIdx); + var nextSpaceIdx = message.indexOf(' ', spaceIdx + 1); + var callbackId = message.slice(spaceIdx + 1, nextSpaceIdx); + var payloadMessage = message.slice(nextSpaceIdx + 1); + var payload = []; + buildPayload(payload, payloadMessage); + cordova.callbackFromNative(callbackId, success, status, payload, keepCallback); + } else { + console.log("processMessage failed: invalid message: " + JSON.stringify(message)); + } +} + +function processMessages() { + // Check for the reentrant case. + if (isProcessing) { + return; + } + if (messagesFromNative.length === 0) { + return; + } + isProcessing = true; + try { + var msg = popMessageFromQueue(); + // The Java side can send a * message to indicate that it + // still has messages waiting to be retrieved. + if (msg == '*' && messagesFromNative.length === 0) { + nextTick(pollOnce); + return; + } + processMessage(msg); + } finally { + isProcessing = false; + if (messagesFromNative.length > 0) { + nextTick(processMessages); + } + } +} + +function popMessageFromQueue() { + var messageBatch = messagesFromNative.shift(); + if (messageBatch == '*') { + return '*'; + } + + var spaceIdx = messageBatch.indexOf(' '); + var msgLen = +messageBatch.slice(0, spaceIdx); + var message = messageBatch.substr(spaceIdx + 1, msgLen); + messageBatch = messageBatch.slice(spaceIdx + msgLen + 1); + if (messageBatch) { + messagesFromNative.unshift(messageBatch); + } + return message; +} + +module.exports = androidExec; + +}); + +// file: src/common/exec/proxy.js +define("cordova/exec/proxy", function(require, exports, module) { + + +// internal map of proxy function +var CommandProxyMap = {}; + +module.exports = { + + // example: cordova.commandProxy.add("Accelerometer",{getCurrentAcceleration: function(successCallback, errorCallback, options) {...},...); + add:function(id,proxyObj) { + console.log("adding proxy for " + id); + CommandProxyMap[id] = proxyObj; + return proxyObj; + }, + + // cordova.commandProxy.remove("Accelerometer"); + remove:function(id) { + var proxy = CommandProxyMap[id]; + delete CommandProxyMap[id]; + CommandProxyMap[id] = null; + return proxy; + }, + + get:function(service,action) { + return ( CommandProxyMap[service] ? CommandProxyMap[service][action] : null ); + } +}; +}); + +// file: src/common/init.js +define("cordova/init", function(require, exports, module) { + +var channel = require('cordova/channel'); +var cordova = require('cordova'); +var modulemapper = require('cordova/modulemapper'); +var platform = require('cordova/platform'); +var pluginloader = require('cordova/pluginloader'); +var utils = require('cordova/utils'); + +var platformInitChannelsArray = [channel.onNativeReady, channel.onPluginsReady]; + +function logUnfiredChannels(arr) { + for (var i = 0; i < arr.length; ++i) { + if (arr[i].state != 2) { + console.log('Channel not fired: ' + arr[i].type); + } + } +} + +window.setTimeout(function() { + if (channel.onDeviceReady.state != 2) { + console.log('deviceready has not fired after 5 seconds.'); + logUnfiredChannels(platformInitChannelsArray); + logUnfiredChannels(channel.deviceReadyChannelsArray); + } +}, 5000); + +// Replace navigator before any modules are required(), to ensure it happens as soon as possible. +// We replace it so that properties that can't be clobbered can instead be overridden. +function replaceNavigator(origNavigator) { + var CordovaNavigator = function() {}; + CordovaNavigator.prototype = origNavigator; + var newNavigator = new CordovaNavigator(); + // This work-around really only applies to new APIs that are newer than Function.bind. + // Without it, APIs such as getGamepads() break. + if (CordovaNavigator.bind) { + for (var key in origNavigator) { + if (typeof origNavigator[key] == 'function') { + newNavigator[key] = origNavigator[key].bind(origNavigator); + } + else { + (function(k) { + utils.defineGetterSetter(newNavigator,key,function() { + return origNavigator[k]; + }); + })(key); + } + } + } + return newNavigator; +} + +if (window.navigator) { + window.navigator = replaceNavigator(window.navigator); +} + +if (!window.console) { + window.console = { + log: function(){} + }; +} +if (!window.console.warn) { + window.console.warn = function(msg) { + this.log("warn: " + msg); + }; +} + +// Register pause, resume and deviceready channels as events on document. +channel.onPause = cordova.addDocumentEventHandler('pause'); +channel.onResume = cordova.addDocumentEventHandler('resume'); +channel.onActivated = cordova.addDocumentEventHandler('activated'); +channel.onDeviceReady = cordova.addStickyDocumentEventHandler('deviceready'); + +// Listen for DOMContentLoaded and notify our channel subscribers. +if (document.readyState == 'complete' || document.readyState == 'interactive') { + channel.onDOMContentLoaded.fire(); +} else { + document.addEventListener('DOMContentLoaded', function() { + channel.onDOMContentLoaded.fire(); + }, false); +} + +// _nativeReady is global variable that the native side can set +// to signify that the native code is ready. It is a global since +// it may be called before any cordova JS is ready. +if (window._nativeReady) { + channel.onNativeReady.fire(); +} + +modulemapper.clobbers('cordova', 'cordova'); +modulemapper.clobbers('cordova/exec', 'cordova.exec'); +modulemapper.clobbers('cordova/exec', 'Cordova.exec'); + +// Call the platform-specific initialization. +platform.bootstrap && platform.bootstrap(); + +// Wrap in a setTimeout to support the use-case of having plugin JS appended to cordova.js. +// The delay allows the attached modules to be defined before the plugin loader looks for them. +setTimeout(function() { + pluginloader.load(function() { + channel.onPluginsReady.fire(); }); +}, 0); - // file: src/common/init_b.js - define('cordova/init_b', function (require, exports, module) { +/** + * Create all cordova objects once native side is ready. + */ +channel.join(function() { + modulemapper.mapModules(window); - var channel = require('cordova/channel'); - var cordova = require('cordova'); - var modulemapper = require('cordova/modulemapper'); - var platform = require('cordova/platform'); - var pluginloader = require('cordova/pluginloader'); - var utils = require('cordova/utils'); + platform.initialize && platform.initialize(); - var platformInitChannelsArray = [channel.onDOMContentLoaded, channel.onNativeReady, channel.onPluginsReady]; + // Fire event to notify that all objects are created + channel.onCordovaReady.fire(); - // setting exec - cordova.exec = require('cordova/exec'); + // Fire onDeviceReady event once page has fully loaded, all + // constructors have run and cordova info has been received from native + // side. + channel.join(function() { + require('cordova').fireDocumentEvent('deviceready'); + }, channel.deviceReadyChannelsArray); - function logUnfiredChannels (arr) { - for (var i = 0; i < arr.length; ++i) { - if (arr[i].state !== 2) { - console.log('Channel not fired: ' + arr[i].type); - } +}, platformInitChannelsArray); + + +}); + +// file: src/common/init_b.js +define("cordova/init_b", function(require, exports, module) { + +var channel = require('cordova/channel'); +var cordova = require('cordova'); +var modulemapper = require('cordova/modulemapper'); +var platform = require('cordova/platform'); +var pluginloader = require('cordova/pluginloader'); +var utils = require('cordova/utils'); + +var platformInitChannelsArray = [channel.onDOMContentLoaded, channel.onNativeReady, channel.onPluginsReady]; + +// setting exec +cordova.exec = require('cordova/exec'); + +function logUnfiredChannels(arr) { + for (var i = 0; i < arr.length; ++i) { + if (arr[i].state != 2) { + console.log('Channel not fired: ' + arr[i].type); + } + } +} + +window.setTimeout(function() { + if (channel.onDeviceReady.state != 2) { + console.log('deviceready has not fired after 5 seconds.'); + logUnfiredChannels(platformInitChannelsArray); + logUnfiredChannels(channel.deviceReadyChannelsArray); + } +}, 5000); + +// Replace navigator before any modules are required(), to ensure it happens as soon as possible. +// We replace it so that properties that can't be clobbered can instead be overridden. +function replaceNavigator(origNavigator) { + var CordovaNavigator = function() {}; + CordovaNavigator.prototype = origNavigator; + var newNavigator = new CordovaNavigator(); + // This work-around really only applies to new APIs that are newer than Function.bind. + // Without it, APIs such as getGamepads() break. + if (CordovaNavigator.bind) { + for (var key in origNavigator) { + if (typeof origNavigator[key] == 'function') { + newNavigator[key] = origNavigator[key].bind(origNavigator); + } + else { + (function(k) { + utils.defineGetterSetter(newNavigator,key,function() { + return origNavigator[k]; + }); + })(key); } } + } + return newNavigator; +} +if (window.navigator) { + window.navigator = replaceNavigator(window.navigator); +} - window.setTimeout(function () { - if (channel.onDeviceReady.state !== 2) { - console.log('deviceready has not fired after 5 seconds.'); - logUnfiredChannels(platformInitChannelsArray); - logUnfiredChannels(channel.deviceReadyChannelsArray); - } - }, 5000); +if (!window.console) { + window.console = { + log: function(){} + }; +} +if (!window.console.warn) { + window.console.warn = function(msg) { + this.log("warn: " + msg); + }; +} - // Replace navigator before any modules are required(), to ensure it happens as soon as possible. - // We replace it so that properties that can't be clobbered can instead be overridden. - function replaceNavigator (origNavigator) { - var CordovaNavigator = function () {}; - CordovaNavigator.prototype = origNavigator; - var newNavigator = new CordovaNavigator(); - // This work-around really only applies to new APIs that are newer than Function.bind. - // Without it, APIs such as getGamepads() break. - if (CordovaNavigator.bind) { - for (var key in origNavigator) { - if (typeof origNavigator[key] === 'function') { - newNavigator[key] = origNavigator[key].bind(origNavigator); - } else { - (function (k) { - utils.defineGetterSetter(newNavigator, key, function () { - return origNavigator[k]; - }); - })(key); - } - } - } - return newNavigator; - } - if (window.navigator) { - window.navigator = replaceNavigator(window.navigator); +// Register pause, resume and deviceready channels as events on document. +channel.onPause = cordova.addDocumentEventHandler('pause'); +channel.onResume = cordova.addDocumentEventHandler('resume'); +channel.onActivated = cordova.addDocumentEventHandler('activated'); +channel.onDeviceReady = cordova.addStickyDocumentEventHandler('deviceready'); + +// Listen for DOMContentLoaded and notify our channel subscribers. +if (document.readyState == 'complete' || document.readyState == 'interactive') { + channel.onDOMContentLoaded.fire(); +} else { + document.addEventListener('DOMContentLoaded', function() { + channel.onDOMContentLoaded.fire(); + }, false); +} + +// _nativeReady is global variable that the native side can set +// to signify that the native code is ready. It is a global since +// it may be called before any cordova JS is ready. +if (window._nativeReady) { + channel.onNativeReady.fire(); +} + +// Call the platform-specific initialization. +platform.bootstrap && platform.bootstrap(); + +// Wrap in a setTimeout to support the use-case of having plugin JS appended to cordova.js. +// The delay allows the attached modules to be defined before the plugin loader looks for them. +setTimeout(function() { + pluginloader.load(function() { + channel.onPluginsReady.fire(); + }); +}, 0); + +/** + * Create all cordova objects once native side is ready. + */ +channel.join(function() { + modulemapper.mapModules(window); + + platform.initialize && platform.initialize(); + + // Fire event to notify that all objects are created + channel.onCordovaReady.fire(); + + // Fire onDeviceReady event once page has fully loaded, all + // constructors have run and cordova info has been received from native + // side. + channel.join(function() { + require('cordova').fireDocumentEvent('deviceready'); + }, channel.deviceReadyChannelsArray); + +}, platformInitChannelsArray); + +}); + +// file: src/common/modulemapper.js +define("cordova/modulemapper", function(require, exports, module) { + +var builder = require('cordova/builder'), + moduleMap = define.moduleMap, + symbolList, + deprecationMap; + +exports.reset = function() { + symbolList = []; + deprecationMap = {}; +}; + +function addEntry(strategy, moduleName, symbolPath, opt_deprecationMessage) { + if (!(moduleName in moduleMap)) { + throw new Error('Module ' + moduleName + ' does not exist.'); + } + symbolList.push(strategy, moduleName, symbolPath); + if (opt_deprecationMessage) { + deprecationMap[symbolPath] = opt_deprecationMessage; + } +} + +// Note: Android 2.3 does have Function.bind(). +exports.clobbers = function(moduleName, symbolPath, opt_deprecationMessage) { + addEntry('c', moduleName, symbolPath, opt_deprecationMessage); +}; + +exports.merges = function(moduleName, symbolPath, opt_deprecationMessage) { + addEntry('m', moduleName, symbolPath, opt_deprecationMessage); +}; + +exports.defaults = function(moduleName, symbolPath, opt_deprecationMessage) { + addEntry('d', moduleName, symbolPath, opt_deprecationMessage); +}; + +exports.runs = function(moduleName) { + addEntry('r', moduleName, null); +}; + +function prepareNamespace(symbolPath, context) { + if (!symbolPath) { + return context; + } + var parts = symbolPath.split('.'); + var cur = context; + for (var i = 0, part; part = parts[i]; ++i) { + cur = cur[part] = cur[part] || {}; + } + return cur; +} + +exports.mapModules = function(context) { + var origSymbols = {}; + context.CDV_origSymbols = origSymbols; + for (var i = 0, len = symbolList.length; i < len; i += 3) { + var strategy = symbolList[i]; + var moduleName = symbolList[i + 1]; + var module = require(moduleName); + // + if (strategy == 'r') { + continue; } + var symbolPath = symbolList[i + 2]; + var lastDot = symbolPath.lastIndexOf('.'); + var namespace = symbolPath.substr(0, lastDot); + var lastName = symbolPath.substr(lastDot + 1); - if (!window.console) { - window.console = { - log: function () {} - }; - } - if (!window.console.warn) { - window.console.warn = function (msg) { - this.log('warn: ' + msg); + var deprecationMsg = symbolPath in deprecationMap ? 'Access made to deprecated symbol: ' + symbolPath + '. ' + deprecationMsg : null; + var parentObj = prepareNamespace(namespace, context); + var target = parentObj[lastName]; + + if (strategy == 'm' && target) { + builder.recursiveMerge(target, module); + } else if ((strategy == 'd' && !target) || (strategy != 'd')) { + if (!(symbolPath in origSymbols)) { + origSymbols[symbolPath] = target; + } + builder.assignOrWrapInDeprecateGetter(parentObj, lastName, module, deprecationMsg); + } + } +}; + +exports.getOriginalSymbol = function(context, symbolPath) { + var origSymbols = context.CDV_origSymbols; + if (origSymbols && (symbolPath in origSymbols)) { + return origSymbols[symbolPath]; + } + var parts = symbolPath.split('.'); + var obj = context; + for (var i = 0; i < parts.length; ++i) { + obj = obj && obj[parts[i]]; + } + return obj; +}; + +exports.reset(); + + +}); + +// file: src/common/modulemapper_b.js +define("cordova/modulemapper_b", function(require, exports, module) { + +var builder = require('cordova/builder'), + symbolList = [], + deprecationMap; + +exports.reset = function() { + symbolList = []; + deprecationMap = {}; +}; + +function addEntry(strategy, moduleName, symbolPath, opt_deprecationMessage) { + symbolList.push(strategy, moduleName, symbolPath); + if (opt_deprecationMessage) { + deprecationMap[symbolPath] = opt_deprecationMessage; + } +} + +// Note: Android 2.3 does have Function.bind(). +exports.clobbers = function(moduleName, symbolPath, opt_deprecationMessage) { + addEntry('c', moduleName, symbolPath, opt_deprecationMessage); +}; + +exports.merges = function(moduleName, symbolPath, opt_deprecationMessage) { + addEntry('m', moduleName, symbolPath, opt_deprecationMessage); +}; + +exports.defaults = function(moduleName, symbolPath, opt_deprecationMessage) { + addEntry('d', moduleName, symbolPath, opt_deprecationMessage); +}; + +exports.runs = function(moduleName) { + addEntry('r', moduleName, null); +}; + +function prepareNamespace(symbolPath, context) { + if (!symbolPath) { + return context; + } + var parts = symbolPath.split('.'); + var cur = context; + for (var i = 0, part; part = parts[i]; ++i) { + cur = cur[part] = cur[part] || {}; + } + return cur; +} + +exports.mapModules = function(context) { + var origSymbols = {}; + context.CDV_origSymbols = origSymbols; + for (var i = 0, len = symbolList.length; i < len; i += 3) { + var strategy = symbolList[i]; + var moduleName = symbolList[i + 1]; + var module = require(moduleName); + // + if (strategy == 'r') { + continue; + } + var symbolPath = symbolList[i + 2]; + var lastDot = symbolPath.lastIndexOf('.'); + var namespace = symbolPath.substr(0, lastDot); + var lastName = symbolPath.substr(lastDot + 1); + + var deprecationMsg = symbolPath in deprecationMap ? 'Access made to deprecated symbol: ' + symbolPath + '. ' + deprecationMsg : null; + var parentObj = prepareNamespace(namespace, context); + var target = parentObj[lastName]; + + if (strategy == 'm' && target) { + builder.recursiveMerge(target, module); + } else if ((strategy == 'd' && !target) || (strategy != 'd')) { + if (!(symbolPath in origSymbols)) { + origSymbols[symbolPath] = target; + } + builder.assignOrWrapInDeprecateGetter(parentObj, lastName, module, deprecationMsg); + } + } +}; + +exports.getOriginalSymbol = function(context, symbolPath) { + var origSymbols = context.CDV_origSymbols; + if (origSymbols && (symbolPath in origSymbols)) { + return origSymbols[symbolPath]; + } + var parts = symbolPath.split('.'); + var obj = context; + for (var i = 0; i < parts.length; ++i) { + obj = obj && obj[parts[i]]; + } + return obj; +}; + +exports.reset(); + + +}); + +// file: /Users/jbowser/cordova/cordova-android/cordova-js-src/platform.js +define("cordova/platform", function(require, exports, module) { + +// The last resume event that was received that had the result of a plugin call. +var lastResumeEvent = null; + +module.exports = { + id: 'android', + bootstrap: function() { + var channel = require('cordova/channel'), + cordova = require('cordova'), + exec = require('cordova/exec'), + modulemapper = require('cordova/modulemapper'); + + // Get the shared secret needed to use the bridge. + exec.init(); + + // TODO: Extract this as a proper plugin. + modulemapper.clobbers('cordova/plugin/android/app', 'navigator.app'); + + var APP_PLUGIN_NAME = Number(cordova.platformVersion.split('.')[0]) >= 4 ? 'CoreAndroid' : 'App'; + + // Inject a listener for the backbutton on the document. + var backButtonChannel = cordova.addDocumentEventHandler('backbutton'); + backButtonChannel.onHasSubscribersChange = function() { + // If we just attached the first handler or detached the last handler, + // let native know we need to override the back button. + exec(null, null, APP_PLUGIN_NAME, "overrideBackbutton", [this.numHandlers == 1]); + }; + + // Add hardware MENU and SEARCH button handlers + cordova.addDocumentEventHandler('menubutton'); + cordova.addDocumentEventHandler('searchbutton'); + + function bindButtonChannel(buttonName) { + // generic button bind used for volumeup/volumedown buttons + var volumeButtonChannel = cordova.addDocumentEventHandler(buttonName + 'button'); + volumeButtonChannel.onHasSubscribersChange = function() { + exec(null, null, APP_PLUGIN_NAME, "overrideButton", [buttonName, this.numHandlers == 1]); }; } + // Inject a listener for the volume buttons on the document. + bindButtonChannel('volumeup'); + bindButtonChannel('volumedown'); - // Register pause, resume and deviceready channels as events on document. - channel.onPause = cordova.addDocumentEventHandler('pause'); - channel.onResume = cordova.addDocumentEventHandler('resume'); - channel.onActivated = cordova.addDocumentEventHandler('activated'); - channel.onDeviceReady = cordova.addStickyDocumentEventHandler('deviceready'); + // The resume event is not "sticky", but it is possible that the event + // will contain the result of a plugin call. We need to ensure that the + // plugin result is delivered even after the event is fired (CB-10498) + var cordovaAddEventListener = document.addEventListener; - // Listen for DOMContentLoaded and notify our channel subscribers. - if (document.readyState === 'complete' || document.readyState === 'interactive') { - channel.onDOMContentLoaded.fire(); - } else { - document.addEventListener('DOMContentLoaded', function () { - channel.onDOMContentLoaded.fire(); - }, false); - } + document.addEventListener = function(evt, handler, capture) { + cordovaAddEventListener(evt, handler, capture); - // _nativeReady is global variable that the native side can set - // to signify that the native code is ready. It is a global since - // it may be called before any cordova JS is ready. - if (window._nativeReady) { - channel.onNativeReady.fire(); - } - - // Call the platform-specific initialization. - platform.bootstrap && platform.bootstrap(); - - // Wrap in a setTimeout to support the use-case of having plugin JS appended to cordova.js. - // The delay allows the attached modules to be defined before the plugin loader looks for them. - setTimeout(function () { - pluginloader.load(function () { - channel.onPluginsReady.fire(); - }); - }, 0); - - /** - * Create all cordova objects once native side is ready. - */ - channel.join(function () { - modulemapper.mapModules(window); - - platform.initialize && platform.initialize(); - - // Fire event to notify that all objects are created - channel.onCordovaReady.fire(); - - // Fire onDeviceReady event once page has fully loaded, all - // constructors have run and cordova info has been received from native - // side. - channel.join(function () { - require('cordova').fireDocumentEvent('deviceready'); - }, channel.deviceReadyChannelsArray); - - }, platformInitChannelsArray); - - }); - - // file: src/common/modulemapper.js - define('cordova/modulemapper', function (require, exports, module) { - - var builder = require('cordova/builder'); - var moduleMap = define.moduleMap; - var symbolList; - var deprecationMap; - - exports.reset = function () { - symbolList = []; - deprecationMap = {}; - }; - - function addEntry (strategy, moduleName, symbolPath, opt_deprecationMessage) { - if (!(moduleName in moduleMap)) { - throw new Error('Module ' + moduleName + ' does not exist.'); + if (evt === 'resume' && lastResumeEvent) { + handler(lastResumeEvent); } - symbolList.push(strategy, moduleName, symbolPath); - if (opt_deprecationMessage) { - deprecationMap[symbolPath] = opt_deprecationMessage; - } - } - - // Note: Android 2.3 does have Function.bind(). - exports.clobbers = function (moduleName, symbolPath, opt_deprecationMessage) { - addEntry('c', moduleName, symbolPath, opt_deprecationMessage); }; - exports.merges = function (moduleName, symbolPath, opt_deprecationMessage) { - addEntry('m', moduleName, symbolPath, opt_deprecationMessage); - }; + // Let native code know we are all done on the JS side. + // Native code will then un-hide the WebView. + channel.onCordovaReady.subscribe(function() { + exec(onMessageFromNative, null, APP_PLUGIN_NAME, 'messageChannel', []); + exec(null, null, APP_PLUGIN_NAME, "show", []); + }); + } +}; - exports.defaults = function (moduleName, symbolPath, opt_deprecationMessage) { - addEntry('d', moduleName, symbolPath, opt_deprecationMessage); - }; +function onMessageFromNative(msg) { + var cordova = require('cordova'); + var action = msg.action; - exports.runs = function (moduleName) { - addEntry('r', moduleName, null); - }; - - function prepareNamespace (symbolPath, context) { - if (!symbolPath) { - return context; - } - var parts = symbolPath.split('.'); - var cur = context; - for (var i = 0, part; part = parts[i]; ++i) { - cur = cur[part] = cur[part] || {}; - } - return cur; - } - - exports.mapModules = function (context) { - var origSymbols = {}; - context.CDV_origSymbols = origSymbols; - for (var i = 0, len = symbolList.length; i < len; i += 3) { - var strategy = symbolList[i]; - var moduleName = symbolList[i + 1]; - var module = require(moduleName); - // - if (strategy === 'r') { - continue; - } - var symbolPath = symbolList[i + 2]; - var lastDot = symbolPath.lastIndexOf('.'); - var namespace = symbolPath.substr(0, lastDot); - var lastName = symbolPath.substr(lastDot + 1); - - var deprecationMsg = symbolPath in deprecationMap ? 'Access made to deprecated symbol: ' + symbolPath + '. ' + deprecationMsg : null; - var parentObj = prepareNamespace(namespace, context); - var target = parentObj[lastName]; - - if (strategy === 'm' && target) { - builder.recursiveMerge(target, module); - } else if ((strategy === 'd' && !target) || (strategy !== 'd')) { - if (!(symbolPath in origSymbols)) { - origSymbols[symbolPath] = target; + switch (action) + { + // Button events + case 'backbutton': + case 'menubutton': + case 'searchbutton': + // App life cycle events + case 'pause': + // Volume events + case 'volumedownbutton': + case 'volumeupbutton': + cordova.fireDocumentEvent(action); + break; + case 'resume': + if(arguments.length > 1 && msg.pendingResult) { + if(arguments.length === 2) { + msg.pendingResult.result = arguments[1]; + } else { + // The plugin returned a multipart message + var res = []; + for(var i = 1; i < arguments.length; i++) { + res.push(arguments[i]); } - builder.assignOrWrapInDeprecateGetter(parentObj, lastName, module, deprecationMsg); + msg.pendingResult.result = res; } + + // Save the plugin result so that it can be delivered to the js + // even if they miss the initial firing of the event + lastResumeEvent = msg; } - }; + cordova.fireDocumentEvent(action, msg); + break; + default: + throw new Error('Unknown event action ' + action); + } +} - exports.getOriginalSymbol = function (context, symbolPath) { - var origSymbols = context.CDV_origSymbols; - if (origSymbols && (symbolPath in origSymbols)) { - return origSymbols[symbolPath]; - } - var parts = symbolPath.split('.'); - var obj = context; - for (var i = 0; i < parts.length; ++i) { - obj = obj && obj[parts[i]]; - } - return obj; - }; +}); - exports.reset(); +// file: /Users/jbowser/cordova/cordova-android/cordova-js-src/plugin/android/app.js +define("cordova/plugin/android/app", function(require, exports, module) { - }); +var exec = require('cordova/exec'); +var APP_PLUGIN_NAME = Number(require('cordova').platformVersion.split('.')[0]) >= 4 ? 'CoreAndroid' : 'App'; - // file: src/common/modulemapper_b.js - define('cordova/modulemapper_b', function (require, exports, module) { +module.exports = { + /** + * Clear the resource cache. + */ + clearCache:function() { + exec(null, null, APP_PLUGIN_NAME, "clearCache", []); + }, - var builder = require('cordova/builder'); - var symbolList = []; - var deprecationMap; + /** + * Load the url into the webview or into new browser instance. + * + * @param url The URL to load + * @param props Properties that can be passed in to the activity: + * wait: int => wait msec before loading URL + * loadingDialog: "Title,Message" => display a native loading dialog + * loadUrlTimeoutValue: int => time in msec to wait before triggering a timeout error + * clearHistory: boolean => clear webview history (default=false) + * openExternal: boolean => open in a new browser (default=false) + * + * Example: + * navigator.app.loadUrl("http://server/myapp/index.html", {wait:2000, loadingDialog:"Wait,Loading App", loadUrlTimeoutValue: 60000}); + */ + loadUrl:function(url, props) { + exec(null, null, APP_PLUGIN_NAME, "loadUrl", [url, props]); + }, - exports.reset = function () { - symbolList = []; - deprecationMap = {}; - }; + /** + * Cancel loadUrl that is waiting to be loaded. + */ + cancelLoadUrl:function() { + exec(null, null, APP_PLUGIN_NAME, "cancelLoadUrl", []); + }, - function addEntry (strategy, moduleName, symbolPath, opt_deprecationMessage) { - symbolList.push(strategy, moduleName, symbolPath); - if (opt_deprecationMessage) { - deprecationMap[symbolPath] = opt_deprecationMessage; - } - } + /** + * Clear web history in this web view. + * Instead of BACK button loading the previous web page, it will exit the app. + */ + clearHistory:function() { + exec(null, null, APP_PLUGIN_NAME, "clearHistory", []); + }, - // Note: Android 2.3 does have Function.bind(). - exports.clobbers = function (moduleName, symbolPath, opt_deprecationMessage) { - addEntry('c', moduleName, symbolPath, opt_deprecationMessage); - }; + /** + * Go to previous page displayed. + * This is the same as pressing the backbutton on Android device. + */ + backHistory:function() { + exec(null, null, APP_PLUGIN_NAME, "backHistory", []); + }, - exports.merges = function (moduleName, symbolPath, opt_deprecationMessage) { - addEntry('m', moduleName, symbolPath, opt_deprecationMessage); - }; + /** + * Override the default behavior of the Android back button. + * If overridden, when the back button is pressed, the "backKeyDown" JavaScript event will be fired. + * + * Note: The user should not have to call this method. Instead, when the user + * registers for the "backbutton" event, this is automatically done. + * + * @param override T=override, F=cancel override + */ + overrideBackbutton:function(override) { + exec(null, null, APP_PLUGIN_NAME, "overrideBackbutton", [override]); + }, - exports.defaults = function (moduleName, symbolPath, opt_deprecationMessage) { - addEntry('d', moduleName, symbolPath, opt_deprecationMessage); - }; + /** + * Override the default behavior of the Android volume button. + * If overridden, when the volume button is pressed, the "volume[up|down]button" + * JavaScript event will be fired. + * + * Note: The user should not have to call this method. Instead, when the user + * registers for the "volume[up|down]button" event, this is automatically done. + * + * @param button volumeup, volumedown + * @param override T=override, F=cancel override + */ + overrideButton:function(button, override) { + exec(null, null, APP_PLUGIN_NAME, "overrideButton", [button, override]); + }, - exports.runs = function (moduleName) { - addEntry('r', moduleName, null); - }; + /** + * Exit and terminate the application. + */ + exitApp:function() { + return exec(null, null, APP_PLUGIN_NAME, "exitApp", []); + } +}; - function prepareNamespace (symbolPath, context) { - if (!symbolPath) { - return context; - } - var parts = symbolPath.split('.'); - var cur = context; - for (var i = 0, part; part = parts[i]; ++i) { - cur = cur[part] = cur[part] || {}; - } - return cur; - } +}); - exports.mapModules = function (context) { - var origSymbols = {}; - context.CDV_origSymbols = origSymbols; - for (var i = 0, len = symbolList.length; i < len; i += 3) { - var strategy = symbolList[i]; - var moduleName = symbolList[i + 1]; - var module = require(moduleName); - // - if (strategy === 'r') { - continue; - } - var symbolPath = symbolList[i + 2]; - var lastDot = symbolPath.lastIndexOf('.'); - var namespace = symbolPath.substr(0, lastDot); - var lastName = symbolPath.substr(lastDot + 1); +// file: src/common/pluginloader.js +define("cordova/pluginloader", function(require, exports, module) { - var deprecationMsg = symbolPath in deprecationMap ? 'Access made to deprecated symbol: ' + symbolPath + '. ' + deprecationMsg : null; - var parentObj = prepareNamespace(namespace, context); - var target = parentObj[lastName]; +var modulemapper = require('cordova/modulemapper'); +var urlutil = require('cordova/urlutil'); - if (strategy === 'm' && target) { - builder.recursiveMerge(target, module); - } else if ((strategy === 'd' && !target) || (strategy !== 'd')) { - if (!(symbolPath in origSymbols)) { - origSymbols[symbolPath] = target; - } - builder.assignOrWrapInDeprecateGetter(parentObj, lastName, module, deprecationMsg); - } - } - }; +// Helper function to inject a