From 66f15fdd3758331f7fffd7f3dd83a8d528a9b925 Mon Sep 17 00:00:00 2001 From: Joe Bowser Date: Fri, 18 Jan 2013 15:00:02 -0800 Subject: [PATCH 1/3] Adding purity to the test suite. Purity is a test class that may be renamed later --- .../org/apache/cordova/test/JQMTabTest.java | 24 +++++ .../org/apache/cordova/test/util/Purity.java | 101 ++++++++++++++++++ 2 files changed, 125 insertions(+) create mode 100644 test/src/org/apache/cordova/test/util/Purity.java diff --git a/test/src/org/apache/cordova/test/JQMTabTest.java b/test/src/org/apache/cordova/test/JQMTabTest.java index 8d01ff29..1e58dee4 100644 --- a/test/src/org/apache/cordova/test/JQMTabTest.java +++ b/test/src/org/apache/cordova/test/JQMTabTest.java @@ -21,15 +21,39 @@ package org.apache.cordova.test; */ +import org.apache.cordova.CordovaWebView; +import org.apache.cordova.test.util.Purity; import org.apache.cordova.test.actions.jqmtabbackbutton; +import android.app.Instrumentation; import android.test.ActivityInstrumentationTestCase2; +import android.widget.FrameLayout; +import android.widget.LinearLayout; public class JQMTabTest extends ActivityInstrumentationTestCase2 { + private Instrumentation mInstr; + private jqmtabbackbutton testActivity; + private FrameLayout containerView; + private LinearLayout innerContainer; + private CordovaWebView testView; + private Purity touchTool; + public JQMTabTest(Class activityClass) { super(activityClass); // TODO Auto-generated constructor stub } + + protected void setUp() throws Exception { + super.setUp(); + mInstr = this.getInstrumentation(); + testActivity = this.getActivity(); + containerView = (FrameLayout) testActivity.findViewById(android.R.id.content); + innerContainer = (LinearLayout) containerView.getChildAt(0); + testView = (CordovaWebView) innerContainer.getChildAt(0); + touchTool = new Purity(testActivity, getInstrumentation()); + } + + } diff --git a/test/src/org/apache/cordova/test/util/Purity.java b/test/src/org/apache/cordova/test/util/Purity.java new file mode 100644 index 00000000..0cee4944 --- /dev/null +++ b/test/src/org/apache/cordova/test/util/Purity.java @@ -0,0 +1,101 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. +*/ + +/* + * Purity is a small set of Android utility methods that allows us to simulate touch events on + * Android applications. This is important for simulating some of the most annoying tests. + */ + +package org.apache.cordova.test.util; + +import android.app.Instrumentation; +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.Picture; +import android.os.SystemClock; +import android.util.DisplayMetrics; +import android.view.MotionEvent; +import android.webkit.WebView; + + +public class Purity { + + Instrumentation inst; + int width, height; + float density; + Bitmap state; + + public Purity(Context ctx, Instrumentation i) + { + inst = i; + DisplayMetrics display = ctx.getResources().getDisplayMetrics(); + density = display.density; + width = display.widthPixels; + height = display.heightPixels; + + } + + /* + * WebKit doesn't give you real pixels anymore, this is done for subpixel fonts to appear on + * iOS and Android. However, Android automation requires real pixels + */ + private int getRealCoord(int coord) + { + return (int) (coord * density); + } + + public void touch(int x, int y) + { + int realX = getRealCoord(x); + int realY = getRealCoord(y); + long downTime = SystemClock.uptimeMillis(); + // event time MUST be retrieved only by this way! + long eventTime = SystemClock.uptimeMillis(); + MotionEvent event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_DOWN, realX, realY, 0); + inst.sendPointerSync(event); + } + + public void setBitmap(WebView view) + { + Picture p = view.capturePicture(); + state = Bitmap.createBitmap(p.getWidth(), p.getHeight(), Bitmap.Config.ARGB_8888); + } + + public boolean checkRenderView(WebView view) + { + if(state == null) + { + setBitmap(view); + return false; + } + else + { + Picture p = view.capturePicture(); + Bitmap newState = Bitmap.createBitmap(p.getWidth(), p.getHeight(), Bitmap.Config.ARGB_8888); + boolean result = newState.equals(state); + newState.recycle(); + return result; + } + } + + public void clearBitmap() + { + state.recycle(); + } +} From 1adf268e7166d0a3355504adfd76498929096bb6 Mon Sep 17 00:00:00 2001 From: Joe Bowser Date: Tue, 22 Jan 2013 15:18:21 -0800 Subject: [PATCH 2/3] Updates to tests, including the use of Purity --- test/assets/www/cordova.android.js | 946 ++++++++++-------- .../org/apache/cordova/test/IFrameTest.java | 66 +- .../org/apache/cordova/test/JQMTabTest.java | 24 +- .../org/apache/cordova/test/util/Purity.java | 10 + 4 files changed, 602 insertions(+), 444 deletions(-) diff --git a/test/assets/www/cordova.android.js b/test/assets/www/cordova.android.js index 7655804b..a2c90cea 100644 --- a/test/assets/www/cordova.android.js +++ b/test/assets/www/cordova.android.js @@ -1,6 +1,6 @@ -// commit 832eb92dbc908e9544bed202878906fba49667c7 +// commit 71223711fb1591b1255d871140d959fd9095f0c3 -// File generated at :: Fri Nov 30 2012 05:23:45 GMT-0800 (PST) +// File generated at :: Mon Jan 21 2013 13:45:08 GMT-0800 (PST) /* Licensed to the Apache Software Foundation (ASF) under one @@ -78,6 +78,7 @@ var require, delete modules[id]; }; + define.moduleMap = modules; })(); //Export for use in node @@ -320,6 +321,8 @@ module.exports = cordova; define("cordova/argscheck", function(require, exports, module) { var exec = require('cordova/exec'); +var utils = require('cordova/utils'); + var moduleExports = module.exports; var typeMap = { @@ -340,7 +343,7 @@ function checkArgs(spec, functionName, args, opt_callee) { return; } var errMsg = null; - var type; + var typeName; for (var i = 0; i < spec.length; ++i) { var c = spec.charAt(i), cUpper = c.toUpperCase(), @@ -349,17 +352,17 @@ function checkArgs(spec, functionName, args, opt_callee) { if (c == '*') { continue; } - type = Object.prototype.toString.call(arg).slice(8, -1); + typeName = utils.typeName(arg); if ((arg === null || arg === undefined) && c == cUpper) { continue; } - if (type != typeMap[cUpper]) { + if (typeName != typeMap[cUpper]) { errMsg = 'Expected ' + typeMap[cUpper]; break; } } if (errMsg) { - errMsg += ', but got ' + type + '.'; + errMsg += ', but got ' + typeName + '.'; errMsg = 'Wrong type for parameter "' + extractParamName(opt_callee || args.callee, i) + '" of ' + functionName + ': ' + errMsg; // Don't log when running jake test. if (typeof jasmine == 'undefined') { @@ -369,7 +372,12 @@ function checkArgs(spec, functionName, args, opt_callee) { } } +function getValue(value, defaultValue) { + return value === undefined ? defaultValue : value; +} + moduleExports.checkArgs = checkArgs; +moduleExports.getValue = getValue; moduleExports.enableChecks = true; @@ -402,6 +410,8 @@ 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 { @@ -431,10 +441,6 @@ function include(parent, objects, clobber, merge) { // Overwrite if not currently defined. if (typeof parent[key] == 'undefined') { assignOrWrapInDeprecateGetter(parent, key, result, obj.deprecated); - } else if (merge && typeof obj.path !== 'undefined') { - // If merging, merge parent onto result - recursiveMerge(result, parent[key]); - parent[key] = result; } else { // Set result to what already exists, so we can build children into it if they exist. result = parent[key]; @@ -460,19 +466,18 @@ function include(parent, objects, clobber, merge) { function recursiveMerge(target, src) { for (var prop in src) { if (src.hasOwnProperty(prop)) { - if (typeof target.prototype !== 'undefined' && target.prototype.constructor === target) { + if (target.prototype && target.prototype.constructor === target) { // If the target object is a constructor override off prototype. - target.prototype[prop] = src[prop]; + clobber(target.prototype, prop, src[prop]); } else { - if (typeof src[prop] === 'object') { - target[prop] = recursiveMerge(target[prop], src[prop]); + if (typeof src[prop] === 'object' && typeof target[prop] === 'object') { + recursiveMerge(target[prop], src[prop]); } else { clobber(target, prop, src[prop]); } } } } - return target; } module.exports = { @@ -484,7 +489,9 @@ module.exports = { }, buildIntoAndMerge: function(objects, target) { include(target, objects, true, true); - } + }, + recursiveMerge: recursiveMerge, + assignOrWrapInDeprecateGetter: assignOrWrapInDeprecateGetter }; }); @@ -897,54 +904,9 @@ module.exports = { device: { path: 'cordova/plugin/device' }, - DirectoryEntry: { - path: 'cordova/plugin/DirectoryEntry' - }, - DirectoryReader: { - path: 'cordova/plugin/DirectoryReader' - }, - Entry: { - path: 'cordova/plugin/Entry' - }, - File: { - path: 'cordova/plugin/File' - }, - FileEntry: { - path: 'cordova/plugin/FileEntry' - }, - FileError: { - path: 'cordova/plugin/FileError' - }, - FileReader: { - path: 'cordova/plugin/FileReader' - }, - FileSystem: { - path: 'cordova/plugin/FileSystem' - }, - FileTransfer: { - path: 'cordova/plugin/FileTransfer' - }, - FileTransferError: { - path: 'cordova/plugin/FileTransferError' - }, - FileUploadOptions: { - path: 'cordova/plugin/FileUploadOptions' - }, - FileUploadResult: { - path: 'cordova/plugin/FileUploadResult' - }, - FileWriter: { - path: 'cordova/plugin/FileWriter' - }, - Flags: { - path: 'cordova/plugin/Flags' - }, GlobalizationError: { path: 'cordova/plugin/GlobalizationError' }, - LocalFileSystem: { - path: 'cordova/plugin/LocalFileSystem' - }, Media: { path: 'cordova/plugin/Media' }, @@ -957,9 +919,6 @@ module.exports = { MediaFileData:{ path: 'cordova/plugin/MediaFileData' }, - Metadata:{ - path: 'cordova/plugin/Metadata' - }, Position: { path: 'cordova/plugin/Position' }, @@ -968,12 +927,6 @@ module.exports = { }, ProgressEvent: { path: 'cordova/plugin/ProgressEvent' - }, - requestFileSystem:{ - path: 'cordova/plugin/requestFileSystem' - }, - resolveLocalFileSystemURI:{ - path: 'cordova/plugin/resolveLocalFileSystemURI' } }, clobbers: { @@ -1008,6 +961,7 @@ define("cordova/exec", function(require, exports, module) { */ var cordova = require('cordova'), nativeApiProvider = require('cordova/plugin/android/nativeapiprovider'), + utils = require('cordova/utils'), jsToNativeModes = { PROMPT: 0, JS_OBJECT: 1, @@ -1043,6 +997,13 @@ function androidExec(success, fail, service, action, args) { androidExec.setJsToNativeBridgeMode(jsToNativeModes.JS_OBJECT); } + // 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] = window.btoa(String.fromCharCode.apply(null, new Uint8Array(args[i]))); + } + } + var callbackId = service + cordova.callbackId++, argsJson = JSON.stringify(args), returnValue; @@ -1157,6 +1118,14 @@ function processMessage(message) { payload = null; } else if (payloadKind == 'n') { payload = +message.slice(nextSpaceIdx + 2); + } else if (payloadKind == 'A') { + var data = message.slice(nextSpaceIdx + 2); + var bytes = window.atob(data); + var arraybuffer = new Uint8Array(bytes.length); + for (var i = 0; i < bytes.length; i++) { + arraybuffer[i] = bytes.charCodeAt(i); + } + payload = arraybuffer.buffer; } else { payload = JSON.parse(message.slice(nextSpaceIdx + 1)); } @@ -1206,6 +1175,107 @@ androidExec.processMessages = function(messages) { module.exports = androidExec; +}); + +// file: lib/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); +}; + +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[part] = cur[part] || {}; + } + return cur[parts[i-1]]; +} + +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 symbolPath = symbolList[i + 2]; + var lastDot = symbolPath.lastIndexOf('.'); + var namespace = symbolPath.substr(0, lastDot); + var lastName = symbolPath.substr(lastDot + 1); + + var module = require(moduleName); + 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 (target) { + 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.loadMatchingModules = function(matchingRegExp) { + for (var k in moduleMap) { + if (matchingRegExp.exec(k)) { + require(k); + } + } +}; + +exports.reset(); + + }); // file: lib/android/platform.js @@ -1216,7 +1286,11 @@ module.exports = { initialize:function() { var channel = require("cordova/channel"), cordova = require('cordova'), - exec = require('cordova/exec'); + exec = require('cordova/exec'), + modulemapper = require('cordova/modulemapper'); + + modulemapper.loadMatchingModules(/cordova.*\/symbols$/); + modulemapper.mapModules(window); // Inject a listener for the backbutton on the document. var backButtonChannel = cordova.addDocumentEventHandler('backbutton'); @@ -1334,7 +1408,8 @@ module.exports = Acceleration; // file: lib/common/plugin/Camera.js define("cordova/plugin/Camera", function(require, exports, module) { -var exec = require('cordova/exec'), +var argscheck = require('cordova/argscheck'), + exec = require('cordova/exec'), Camera = require('cordova/plugin/CameraConstants'); var cameraExport = {}; @@ -1355,90 +1430,21 @@ for (var key in Camera) { * @param {Object} options */ cameraExport.getPicture = function(successCallback, errorCallback, options) { + argscheck.checkArgs('fFO', 'Camera.getPicture', arguments); options = options || {}; - // successCallback required - if (typeof successCallback != "function") { - console.log("Camera Error: successCallback is not a function"); - return; - } + var getValue = argscheck.getValue; - // errorCallback optional - if (errorCallback && (typeof errorCallback != "function")) { - console.log("Camera Error: errorCallback is not a function"); - return; - } - - var quality = 50; - if (typeof options.quality == "number") { - quality = options.quality; - } else if (typeof options.quality == "string") { - var qlity = parseInt(options.quality, 10); - if (isNaN(qlity) === false) { - quality = qlity.valueOf(); - } - } - - var destinationType = Camera.DestinationType.FILE_URI; - if (typeof options.destinationType == "number") { - destinationType = options.destinationType; - } - - var sourceType = Camera.PictureSourceType.CAMERA; - if (typeof options.sourceType == "number") { - sourceType = options.sourceType; - } - - var targetWidth = -1; - if (typeof options.targetWidth == "number") { - targetWidth = options.targetWidth; - } else if (typeof options.targetWidth == "string") { - var width = parseInt(options.targetWidth, 10); - if (isNaN(width) === false) { - targetWidth = width.valueOf(); - } - } - - var targetHeight = -1; - if (typeof options.targetHeight == "number") { - targetHeight = options.targetHeight; - } else if (typeof options.targetHeight == "string") { - var height = parseInt(options.targetHeight, 10); - if (isNaN(height) === false) { - targetHeight = height.valueOf(); - } - } - - var encodingType = Camera.EncodingType.JPEG; - if (typeof options.encodingType == "number") { - encodingType = options.encodingType; - } - - var mediaType = Camera.MediaType.PICTURE; - if (typeof options.mediaType == "number") { - mediaType = options.mediaType; - } - var allowEdit = false; - if (typeof options.allowEdit == "boolean") { - allowEdit = options.allowEdit; - } else if (typeof options.allowEdit == "number") { - allowEdit = options.allowEdit <= 0 ? false : true; - } - var correctOrientation = false; - if (typeof options.correctOrientation == "boolean") { - correctOrientation = options.correctOrientation; - } else if (typeof options.correctOrientation == "number") { - correctOrientation = options.correctOrientation <=0 ? false : true; - } - var saveToPhotoAlbum = false; - if (typeof options.saveToPhotoAlbum == "boolean") { - saveToPhotoAlbum = options.saveToPhotoAlbum; - } else if (typeof options.saveToPhotoAlbum == "number") { - saveToPhotoAlbum = options.saveToPhotoAlbum <=0 ? false : true; - } - var popoverOptions = null; - if (typeof options.popoverOptions == "object") { - popoverOptions = options.popoverOptions; - } + var quality = getValue(options.quality, 50); + var destinationType = getValue(options.destinationType, Camera.DestinationType.FILE_URI); + var sourceType = getValue(options.sourceType, Camera.PictureSourceType.CAMERA); + var targetWidth = getValue(options.targetWidth, -1); + var targetHeight = getValue(options.targetHeight, -1); + var encodingType = getValue(options.encodingType, Camera.EncodingType.JPEG); + var mediaType = getValue(options.mediaType, Camera.MediaType.PICTURE); + var allowEdit = !!options.allowEdit; + var correctOrientation = !!options.correctOrientation; + var saveToPhotoAlbum = !!options.saveToPhotoAlbum; + var popoverOptions = getValue(options.popoverOptions, null); var args = [quality, destinationType, sourceType, targetWidth, targetHeight, encodingType, mediaType, allowEdit, correctOrientation, saveToPhotoAlbum, popoverOptions]; @@ -1460,7 +1466,8 @@ define("cordova/plugin/CameraConstants", function(require, exports, module) { module.exports = { DestinationType:{ DATA_URL: 0, // Return base64 encoded string - FILE_URI: 1 // Return file uri (content://media/external/images/media/2 for Android) + FILE_URI: 1, // Return file uri (content://media/external/images/media/2 for Android) + NATIVE_URI: 2 // Return native uri (eg. asset-library://... for iOS) }, EncodingType:{ JPEG: 0, // Return JPEG encoded image @@ -1612,10 +1619,10 @@ module.exports = CompassError; define("cordova/plugin/CompassHeading", function(require, exports, module) { var CompassHeading = function(magneticHeading, trueHeading, headingAccuracy, timestamp) { - this.magneticHeading = (magneticHeading !== undefined ? magneticHeading : null); - this.trueHeading = (trueHeading !== undefined ? trueHeading : null); - this.headingAccuracy = (headingAccuracy !== undefined ? headingAccuracy : null); - this.timestamp = (timestamp !== undefined ? timestamp : new Date().getTime()); + this.magneticHeading = magneticHeading || null; + this.trueHeading = trueHeading || null; + this.headingAccuracy = headingAccuracy || null; + this.timestamp = timestamp || new Date().getTime(); }; module.exports = CompassHeading; @@ -1664,7 +1671,8 @@ module.exports = { // file: lib/common/plugin/Contact.js define("cordova/plugin/Contact", function(require, exports, module) { -var exec = require('cordova/exec'), +var argscheck = require('cordova/argscheck'), + exec = require('cordova/exec'), ContactError = require('cordova/plugin/ContactError'), utils = require('cordova/utils'); @@ -1749,7 +1757,8 @@ var Contact = function (id, displayName, name, nickname, phoneNumbers, emails, a * @param errorCB error callback */ Contact.prototype.remove = function(successCB, errorCB) { - var fail = function(code) { + argscheck.checkArgs('FF', 'Contact.remove', arguments); + var fail = errorCB && function(code) { errorCB(new ContactError(code)); }; if (this.id === null) { @@ -1767,50 +1776,26 @@ Contact.prototype.remove = function(successCB, errorCB) { */ Contact.prototype.clone = function() { var clonedContact = utils.clone(this); - var i; clonedContact.id = null; clonedContact.rawId = null; + + function nullIds(arr) { + if (arr) { + for (var i = 0; i < arr.length; ++i) { + arr[i].id = null; + } + } + } + // Loop through and clear out any id's in phones, emails, etc. - if (clonedContact.phoneNumbers) { - for (i = 0; i < clonedContact.phoneNumbers.length; i++) { - clonedContact.phoneNumbers[i].id = null; - } - } - if (clonedContact.emails) { - for (i = 0; i < clonedContact.emails.length; i++) { - clonedContact.emails[i].id = null; - } - } - if (clonedContact.addresses) { - for (i = 0; i < clonedContact.addresses.length; i++) { - clonedContact.addresses[i].id = null; - } - } - if (clonedContact.ims) { - for (i = 0; i < clonedContact.ims.length; i++) { - clonedContact.ims[i].id = null; - } - } - if (clonedContact.organizations) { - for (i = 0; i < clonedContact.organizations.length; i++) { - clonedContact.organizations[i].id = null; - } - } - if (clonedContact.categories) { - for (i = 0; i < clonedContact.categories.length; i++) { - clonedContact.categories[i].id = null; - } - } - if (clonedContact.photos) { - for (i = 0; i < clonedContact.photos.length; i++) { - clonedContact.photos[i].id = null; - } - } - if (clonedContact.urls) { - for (i = 0; i < clonedContact.urls.length; i++) { - clonedContact.urls[i].id = null; - } - } + nullIds(clonedContact.phoneNumbers); + nullIds(clonedContact.emails); + nullIds(clonedContact.addresses); + nullIds(clonedContact.ims); + nullIds(clonedContact.organizations); + nullIds(clonedContact.categories); + nullIds(clonedContact.photos); + nullIds(clonedContact.urls); return clonedContact; }; @@ -1820,21 +1805,22 @@ Contact.prototype.clone = function() { * @param errorCB error callback */ Contact.prototype.save = function(successCB, errorCB) { - var fail = function(code) { - errorCB(new ContactError(code)); - }; + argscheck.checkArgs('FFO', 'Contact.save', arguments); + var fail = errorCB && function(code) { + errorCB(new ContactError(code)); + }; var success = function(result) { - if (result) { - if (typeof successCB === 'function') { - var fullContact = require('cordova/plugin/contacts').create(result); - successCB(convertIn(fullContact)); - } - } - else { - // no Entry object returned - fail(ContactError.UNKNOWN_ERROR); - } - }; + if (result) { + if (successCB) { + var fullContact = require('cordova/plugin/contacts').create(result); + successCB(convertIn(fullContact)); + } + } + else { + // no Entry object returned + fail(ContactError.UNKNOWN_ERROR); + } + }; var dupContact = convertOut(utils.clone(this)); exec(success, fail, "Contacts", "save", [dupContact]); }; @@ -2055,7 +2041,8 @@ module.exports = Coordinates; // file: lib/common/plugin/DirectoryEntry.js define("cordova/plugin/DirectoryEntry", function(require, exports, module) { -var utils = require('cordova/utils'), +var argscheck = require('cordova/argscheck'), + utils = require('cordova/utils'), exec = require('cordova/exec'), Entry = require('cordova/plugin/Entry'), FileError = require('cordova/plugin/FileError'), @@ -2071,7 +2058,7 @@ var utils = require('cordova/utils'), * TODO: implement this!!! {FileSystem} filesystem on which the directory resides (readonly) */ var DirectoryEntry = function(name, fullPath) { - DirectoryEntry.__super__.constructor.apply(this, [false, true, name, fullPath]); + DirectoryEntry.__super__.constructor.call(this, false, true, name, fullPath); }; utils.extend(DirectoryEntry, Entry); @@ -2092,11 +2079,12 @@ DirectoryEntry.prototype.createReader = function() { * @param {Function} errorCallback is called with a FileError */ DirectoryEntry.prototype.getDirectory = function(path, options, successCallback, errorCallback) { - var win = typeof successCallback !== 'function' ? null : function(result) { + argscheck.checkArgs('sOFF', 'DirectoryEntry.getDirectory', arguments); + var win = successCallback && function(result) { var entry = new DirectoryEntry(result.name, result.fullPath); successCallback(entry); }; - var fail = typeof errorCallback !== 'function' ? null : function(code) { + var fail = errorCallback && function(code) { errorCallback(new FileError(code)); }; exec(win, fail, "File", "getDirectory", [this.fullPath, path, options]); @@ -2109,7 +2097,8 @@ DirectoryEntry.prototype.getDirectory = function(path, options, successCallback, * @param {Function} errorCallback is called with a FileError */ DirectoryEntry.prototype.removeRecursively = function(successCallback, errorCallback) { - var fail = typeof errorCallback !== 'function' ? null : function(code) { + argscheck.checkArgs('FF', 'DirectoryEntry.removeRecursively', arguments); + var fail = errorCallback && function(code) { errorCallback(new FileError(code)); }; exec(successCallback, fail, "File", "removeRecursively", [this.fullPath]); @@ -2124,12 +2113,13 @@ DirectoryEntry.prototype.removeRecursively = function(successCallback, errorCall * @param {Function} errorCallback is called with a FileError */ DirectoryEntry.prototype.getFile = function(path, options, successCallback, errorCallback) { - var win = typeof successCallback !== 'function' ? null : function(result) { + argscheck.checkArgs('sOFF', 'DirectoryEntry.getFile', arguments); + var win = successCallback && function(result) { var FileEntry = require('cordova/plugin/FileEntry'); var entry = new FileEntry(result.name, result.fullPath); successCallback(entry); }; - var fail = typeof errorCallback !== 'function' ? null : function(code) { + var fail = errorCallback && function(code) { errorCallback(new FileError(code)); }; exec(win, fail, "File", "getFile", [this.fullPath, path, options]); @@ -2190,7 +2180,8 @@ module.exports = DirectoryReader; // file: lib/common/plugin/Entry.js define("cordova/plugin/Entry", function(require, exports, module) { -var exec = require('cordova/exec'), +var argscheck = require('cordova/argscheck'), + exec = require('cordova/exec'), FileError = require('cordova/plugin/FileError'), Metadata = require('cordova/plugin/Metadata'); @@ -2209,8 +2200,8 @@ var exec = require('cordova/exec'), * (readonly) */ function Entry(isFile, isDirectory, name, fullPath, fileSystem) { - this.isFile = (typeof isFile != 'undefined'?isFile:false); - this.isDirectory = (typeof isDirectory != 'undefined'?isDirectory:false); + this.isFile = !!isFile; + this.isDirectory = !!isDirectory; this.name = name || ''; this.fullPath = fullPath || ''; this.filesystem = fileSystem || null; @@ -2225,15 +2216,16 @@ function Entry(isFile, isDirectory, name, fullPath, fileSystem) { * {Function} is called with a FileError */ Entry.prototype.getMetadata = function(successCallback, errorCallback) { - var success = typeof successCallback !== 'function' ? null : function(lastModified) { - var metadata = new Metadata(lastModified); - successCallback(metadata); - }; - var fail = typeof errorCallback !== 'function' ? null : function(code) { - errorCallback(new FileError(code)); - }; + argscheck.checkArgs('FF', 'Entry.getMetadata', arguments); + var success = successCallback && function(lastModified) { + var metadata = new Metadata(lastModified); + successCallback(metadata); + }; + var fail = errorCallback && function(code) { + errorCallback(new FileError(code)); + }; - exec(success, fail, "File", "getMetadata", [this.fullPath]); + exec(success, fail, "File", "getMetadata", [this.fullPath]); }; /** @@ -2247,8 +2239,8 @@ Entry.prototype.getMetadata = function(successCallback, errorCallback) { * {Object} keys and values to set */ Entry.prototype.setMetadata = function(successCallback, errorCallback, metadataObject) { - - exec(successCallback, errorCallback, "File", "setMetadata", [this.fullPath, metadataObject]); + argscheck.checkArgs('FFO', 'Entry.setMetadata', arguments); + exec(successCallback, errorCallback, "File", "setMetadata", [this.fullPath, metadataObject]); }; /** @@ -2264,36 +2256,25 @@ Entry.prototype.setMetadata = function(successCallback, errorCallback, metadataO * {Function} called with a FileError */ Entry.prototype.moveTo = function(parent, newName, successCallback, errorCallback) { - var fail = function(code) { - if (typeof errorCallback === 'function') { - errorCallback(new FileError(code)); - } + argscheck.checkArgs('oSFF', 'Entry.moveTo', arguments); + var fail = errorCallback && function(code) { + errorCallback(new FileError(code)); }; - // user must specify parent Entry - if (!parent) { - fail(FileError.NOT_FOUND_ERR); - return; - } // source path var srcPath = this.fullPath, // entry name name = newName || this.name, success = function(entry) { if (entry) { - if (typeof successCallback === 'function') { + if (successCallback) { // create appropriate Entry object var result = (entry.isDirectory) ? new (require('cordova/plugin/DirectoryEntry'))(entry.name, entry.fullPath) : new (require('cordova/plugin/FileEntry'))(entry.name, entry.fullPath); - try { - successCallback(result); - } - catch (e) { - console.log('Error invoking callback: ' + e); - } + successCallback(result); } } else { // no Entry object returned - fail(FileError.NOT_FOUND_ERR); + fail && fail(FileError.NOT_FOUND_ERR); } }; @@ -2314,18 +2295,11 @@ Entry.prototype.moveTo = function(parent, newName, successCallback, errorCallbac * {Function} called with a FileError */ Entry.prototype.copyTo = function(parent, newName, successCallback, errorCallback) { - var fail = function(code) { - if (typeof errorCallback === 'function') { - errorCallback(new FileError(code)); - } + argscheck.checkArgs('oSFF', 'Entry.copyTo', arguments); + var fail = errorCallback && function(code) { + errorCallback(new FileError(code)); }; - // user must specify parent Entry - if (!parent) { - fail(FileError.NOT_FOUND_ERR); - return; - } - // source path var srcPath = this.fullPath, // entry name @@ -2333,20 +2307,15 @@ Entry.prototype.copyTo = function(parent, newName, successCallback, errorCallbac // success callback success = function(entry) { if (entry) { - if (typeof successCallback === 'function') { + if (successCallback) { // create appropriate Entry object var result = (entry.isDirectory) ? new (require('cordova/plugin/DirectoryEntry'))(entry.name, entry.fullPath) : new (require('cordova/plugin/FileEntry'))(entry.name, entry.fullPath); - try { - successCallback(result); - } - catch (e) { - console.log('Error invoking callback: ' + e); - } + successCallback(result); } } else { // no Entry object returned - fail(FileError.NOT_FOUND_ERR); + fail && fail(FileError.NOT_FOUND_ERR); } }; @@ -2383,7 +2352,8 @@ Entry.prototype.toURI = function(mimeType) { * @param errorCallback {Function} called with a FileError */ Entry.prototype.remove = function(successCallback, errorCallback) { - var fail = typeof errorCallback !== 'function' ? null : function(code) { + argscheck.checkArgs('FF', 'Entry.remove', arguments); + var fail = errorCallback && function(code) { errorCallback(new FileError(code)); }; exec(successCallback, fail, "File", "remove", [this.fullPath]); @@ -2396,12 +2366,13 @@ Entry.prototype.remove = function(successCallback, errorCallback) { * @param errorCallback {Function} called with a FileError */ Entry.prototype.getParent = function(successCallback, errorCallback) { - var win = typeof successCallback !== 'function' ? null : function(result) { + argscheck.checkArgs('FF', 'Entry.getParent', arguments); + var win = successCallback && function(result) { var DirectoryEntry = require('cordova/plugin/DirectoryEntry'); var entry = new DirectoryEntry(result.name, result.fullPath); successCallback(entry); }; - var fail = typeof errorCallback !== 'function' ? null : function(code) { + var fail = errorCallback && function(code) { errorCallback(new FileError(code)); }; exec(win, fail, "File", "getParent", [this.fullPath]); @@ -2429,8 +2400,46 @@ var File = function(name, fullPath, type, lastModifiedDate, size){ this.type = type || null; this.lastModifiedDate = lastModifiedDate || null; this.size = size || 0; + + // These store the absolute start and end for slicing the file. + this.start = 0; + this.end = this.size; }; +/** + * Returns a "slice" of the file. Since Cordova Files don't contain the actual + * content, this really returns a File with adjusted start and end. + * Slices of slices are supported. + * start {Number} The index at which to start the slice (inclusive). + * end {Number} The index at which to end the slice (exclusive). + */ +File.prototype.slice = function(start, end) { + var size = this.end - this.start; + var newStart = 0; + var newEnd = size; + if (arguments.length) { + if (start < 0) { + newStart = Math.max(size + start, 0); + } else { + newStart = Math.min(size, start); + } + } + + if (arguments.length >= 2) { + if (end < 0) { + newEnd = Math.max(size + end, 0); + } else { + newEnd = Math.min(end, size); + } + } + + var newFile = new File(this.name, this.fullPath, this.type, this.lastModifiedData, this.size); + newFile.start = this.start + newStart; + newFile.end = this.start + newEnd; + return newFile; +}; + + module.exports = File; }); @@ -2471,13 +2480,9 @@ FileEntry.prototype.createWriter = function(successCallback, errorCallback) { var writer = new FileWriter(filePointer); if (writer.fileName === null || writer.fileName === "") { - if (typeof errorCallback === "function") { - errorCallback(new FileError(FileError.INVALID_STATE_ERR)); - } + errorCallback && errorCallback(new FileError(FileError.INVALID_STATE_ERR)); } else { - if (typeof successCallback === "function") { - successCallback(writer); - } + successCallback && successCallback(writer); } }, errorCallback); }; @@ -2489,11 +2494,11 @@ FileEntry.prototype.createWriter = function(successCallback, errorCallback) { * @param {Function} errorCallback is called with a FileError */ FileEntry.prototype.file = function(successCallback, errorCallback) { - var win = typeof successCallback !== 'function' ? null : function(f) { + var win = successCallback && function(f) { var file = new File(f.name, f.fullPath, f.type, f.lastModifiedDate, f.size); successCallback(file); }; - var fail = typeof errorCallback !== 'function' ? null : function(code) { + var fail = errorCallback && function(code) { errorCallback(new FileError(code)); }; exec(win, fail, "File", "getFileMetadata", [this.fullPath]); @@ -2539,8 +2544,12 @@ module.exports = FileError; define("cordova/plugin/FileReader", function(require, exports, module) { var exec = require('cordova/exec'), + modulemapper = require('cordova/modulemapper'), + utils = require('cordova/utils'), + File = require('cordova/plugin/File'), FileError = require('cordova/plugin/FileError'), - ProgressEvent = require('cordova/plugin/ProgressEvent'); + ProgressEvent = require('cordova/plugin/ProgressEvent'), + origFileReader = modulemapper.getOriginalSymbol(this, 'FileReader'); /** * This class reads the mobile device file system. @@ -2551,23 +2560,11 @@ var exec = require('cordova/exec'), * @constructor */ var FileReader = function() { - this.fileName = ""; - - this.readyState = 0; // FileReader.EMPTY - - // File data - this.result = null; - - // Error - this.error = null; - - // Event handlers - this.onloadstart = null; // When the read starts. - this.onprogress = null; // While reading (and decoding) file or fileBlob data, and reporting partial file data (progress.loaded/progress.total) - this.onload = null; // When the read has successfully completed. - this.onerror = null; // When the read has failed (see errors). - this.onloadend = null; // When the request has completed (either in success or failure). - this.onabort = null; // When the read has been aborted. For instance, by invoking the abort() method. + this._readyState = 0; + this._error = null; + this._result = null; + this._fileName = ''; + this._realReader = origFileReader ? new origFileReader() : {}; }; // States @@ -2575,17 +2572,70 @@ FileReader.EMPTY = 0; FileReader.LOADING = 1; FileReader.DONE = 2; +utils.defineGetter(FileReader.prototype, 'readyState', function() { + return this._fileName ? this._readyState : this._realReader.readyState; +}); + +utils.defineGetter(FileReader.prototype, 'error', function() { + return this._fileName ? this._error: this._realReader.error; +}); + +utils.defineGetter(FileReader.prototype, 'result', function() { + return this._fileName ? this._result: this._realReader.result; +}); + +function defineEvent(eventName) { + utils.defineGetterSetter(FileReader.prototype, eventName, function() { + return this._realReader[eventName] || null; + }, function(value) { + this._realReader[eventName] = value; + }); +} +defineEvent('onloadstart'); // When the read starts. +defineEvent('onprogress'); // While reading (and decoding) file or fileBlob data, and reporting partial file data (progress.loaded/progress.total) +defineEvent('onload'); // When the read has successfully completed. +defineEvent('onerror'); // When the read has failed (see errors). +defineEvent('onloadend'); // When the request has completed (either in success or failure). +defineEvent('onabort'); // When the read has been aborted. For instance, by invoking the abort() method. + +function initRead(reader, file) { + // Already loading something + if (reader.readyState == FileReader.LOADING) { + throw new FileError(FileError.INVALID_STATE_ERR); + } + + reader._result = null; + reader._error = null; + reader._readyState = FileReader.LOADING; + + if (typeof file == 'string') { + // Deprecated in Cordova 2.4. + console.warning('Using a string argument with FileReader.readAs functions is deprecated.'); + reader._fileName = file; + } else if (typeof file.fullPath == 'string') { + reader._fileName = file.fullPath; + } else { + reader._fileName = ''; + return true; + } + + reader.onloadstart && reader.onloadstart(new ProgressEvent("loadstart", {target:reader})); +} + /** * Abort reading file. */ FileReader.prototype.abort = function() { - this.result = null; + if (origFileReader && !this._fileName) { + return this._realReader.abort(); + } + this._result = null; - if (this.readyState == FileReader.DONE || this.readyState == FileReader.EMPTY) { + if (this._readyState == FileReader.DONE || this._readyState == FileReader.EMPTY) { return; } - this.readyState = FileReader.DONE; + this._readyState = FileReader.DONE; // If abort callback if (typeof this.onabort === 'function') { @@ -2604,43 +2654,33 @@ FileReader.prototype.abort = function() { * @param encoding [Optional] (see http://www.iana.org/assignments/character-sets) */ FileReader.prototype.readAsText = function(file, encoding) { - // Figure out pathing - this.fileName = ''; - if (typeof file.fullPath === 'undefined') { - this.fileName = file; - } else { - this.fileName = file.fullPath; - } - - // Already loading something - if (this.readyState == FileReader.LOADING) { - throw new FileError(FileError.INVALID_STATE_ERR); - } - - // LOADING state - this.readyState = FileReader.LOADING; - - // If loadstart callback - if (typeof this.onloadstart === "function") { - this.onloadstart(new ProgressEvent("loadstart", {target:this})); + if (initRead(this, file)) { + return this._realReader.readAsText(file, encoding); } // Default encoding is UTF-8 var enc = encoding ? encoding : "UTF-8"; - var me = this; + var execArgs = [this._fileName, enc]; + + // Maybe add slice parameters. + if (file.end < file.size) { + execArgs.push(file.start, file.end); + } else if (file.start > 0) { + execArgs.push(file.start); + } // Read file exec( // Success callback function(r) { // If DONE (cancelled), then don't do anything - if (me.readyState === FileReader.DONE) { + if (me._readyState === FileReader.DONE) { return; } // Save result - me.result = r; + me._result = r; // If onload callback if (typeof me.onload === "function") { @@ -2648,7 +2688,7 @@ FileReader.prototype.readAsText = function(file, encoding) { } // DONE state - me.readyState = FileReader.DONE; + me._readyState = FileReader.DONE; // If onloadend callback if (typeof me.onloadend === "function") { @@ -2658,18 +2698,18 @@ FileReader.prototype.readAsText = function(file, encoding) { // Error callback function(e) { // If DONE (cancelled), then don't do anything - if (me.readyState === FileReader.DONE) { + if (me._readyState === FileReader.DONE) { return; } // DONE state - me.readyState = FileReader.DONE; + me._readyState = FileReader.DONE; // null result - me.result = null; + me._result = null; // Save error - me.error = new FileError(e); + me._error = new FileError(e); // If onerror callback if (typeof me.onerror === "function") { @@ -2680,7 +2720,7 @@ FileReader.prototype.readAsText = function(file, encoding) { if (typeof me.onloadend === "function") { me.onloadend(new ProgressEvent("loadend", {target:me})); } - }, "File", "readAsText", [this.fileName, enc]); + }, "File", "readAsText", execArgs); }; @@ -2692,42 +2732,34 @@ FileReader.prototype.readAsText = function(file, encoding) { * @param file {File} File object containing file properties */ FileReader.prototype.readAsDataURL = function(file) { - this.fileName = ""; - if (typeof file.fullPath === "undefined") { - this.fileName = file; - } else { - this.fileName = file.fullPath; - } - - // Already loading something - if (this.readyState == FileReader.LOADING) { - throw new FileError(FileError.INVALID_STATE_ERR); - } - - // LOADING state - this.readyState = FileReader.LOADING; - - // If loadstart callback - if (typeof this.onloadstart === "function") { - this.onloadstart(new ProgressEvent("loadstart", {target:this})); + if (initRead(this, file)) { + return this._realReader.readAsDataURL(file); } var me = this; + var execArgs = [this._fileName]; + + // Maybe add slice parameters. + if (file.end < file.size) { + execArgs.push(file.start, file.end); + } else if (file.start > 0) { + execArgs.push(file.start); + } // Read file exec( // Success callback function(r) { // If DONE (cancelled), then don't do anything - if (me.readyState === FileReader.DONE) { + if (me._readyState === FileReader.DONE) { return; } // DONE state - me.readyState = FileReader.DONE; + me._readyState = FileReader.DONE; // Save result - me.result = r; + me._result = r; // If onload callback if (typeof me.onload === "function") { @@ -2742,17 +2774,17 @@ FileReader.prototype.readAsDataURL = function(file) { // Error callback function(e) { // If DONE (cancelled), then don't do anything - if (me.readyState === FileReader.DONE) { + if (me._readyState === FileReader.DONE) { return; } // DONE state - me.readyState = FileReader.DONE; + me._readyState = FileReader.DONE; - me.result = null; + me._result = null; // Save error - me.error = new FileError(e); + me._error = new FileError(e); // If onerror callback if (typeof me.onerror === "function") { @@ -2763,7 +2795,7 @@ FileReader.prototype.readAsDataURL = function(file) { if (typeof me.onloadend === "function") { me.onloadend(new ProgressEvent("loadend", {target:me})); } - }, "File", "readAsDataURL", [this.fileName]); + }, "File", "readAsDataURL", execArgs); }; /** @@ -2772,8 +2804,12 @@ FileReader.prototype.readAsDataURL = function(file) { * @param file {File} File object containing file properties */ FileReader.prototype.readAsBinaryString = function(file) { + if (initRead(this, file)) { + return this._realReader.readAsBinaryString(file); + } // TODO - Can't return binary data to browser. console.log('method "readAsBinaryString" is not supported at this time.'); + this.abort(); }; /** @@ -2782,8 +2818,12 @@ FileReader.prototype.readAsBinaryString = function(file) { * @param file {File} File object containing file properties */ FileReader.prototype.readAsArrayBuffer = function(file) { + if (initRead(this, file)) { + return this._realReader.readAsArrayBuffer(file); + } // TODO - Can't return binary data to browser. console.log('This method is not supported at this time.'); + this.abort(); }; module.exports = FileReader; @@ -2816,7 +2856,8 @@ module.exports = FileSystem; // file: lib/common/plugin/FileTransfer.js define("cordova/plugin/FileTransfer", function(require, exports, module) { -var exec = require('cordova/exec'), +var argscheck = require('cordova/argscheck'), + exec = require('cordova/exec'), FileTransferError = require('cordova/plugin/FileTransferError'), ProgressEvent = require('cordova/plugin/ProgressEvent'); @@ -2850,8 +2891,7 @@ var FileTransfer = function() { * @param trustAllHosts {Boolean} Optional trust all hosts (e.g. for self-signed certs), defaults to false */ FileTransfer.prototype.upload = function(filePath, server, successCallback, errorCallback, options, trustAllHosts) { - // sanity parameter checking - if (!filePath || !server) throw new Error("FileTransfer.upload requires filePath and server URL parameters at the minimum."); + argscheck.checkArgs('ssFFO*', 'FileTransfer.upload', arguments); // check for options var fileKey = null; var fileName = null; @@ -2875,7 +2915,7 @@ FileTransfer.prototype.upload = function(filePath, server, successCallback, erro } } - var fail = function(e) { + var fail = errorCallback && function(e) { var error = new FileTransferError(e.code, e.source, e.target, e.http_status); errorCallback(error); }; @@ -2884,10 +2924,10 @@ FileTransfer.prototype.upload = function(filePath, server, successCallback, erro var win = function(result) { if (typeof result.lengthComputable != "undefined") { if (self.onprogress) { - return self.onprogress(newProgressEvent(result)); + self.onprogress(newProgressEvent(result)); } } else { - return successCallback(result); + successCallback && successCallback(result); } }; exec(win, fail, 'FileTransfer', 'upload', [filePath, server, fileKey, fileName, mimeType, params, trustAllHosts, chunkedMode, headers, this._id]); @@ -2902,15 +2942,14 @@ FileTransfer.prototype.upload = function(filePath, server, successCallback, erro * @param trustAllHosts {Boolean} Optional trust all hosts (e.g. for self-signed certs), defaults to false */ FileTransfer.prototype.download = function(source, target, successCallback, errorCallback, trustAllHosts) { - // sanity parameter checking - if (!source || !target) throw new Error("FileTransfer.download requires source URI and target URI parameters at the minimum."); + argscheck.checkArgs('ssFF*', 'FileTransfer.download', arguments); var self = this; var win = function(result) { if (typeof result.lengthComputable != "undefined") { if (self.onprogress) { return self.onprogress(newProgressEvent(result)); } - } else { + } else if (successCallback) { var entry = null; if (result.isDirectory) { entry = new (require('cordova/plugin/DirectoryEntry'))(); @@ -2926,7 +2965,7 @@ FileTransfer.prototype.download = function(source, target, successCallback, erro } }; - var fail = function(e) { + var fail = errorCallback && function(e) { var error = new FileTransferError(e.code, e.source, e.target, e.http_status); errorCallback(error); }; @@ -3322,55 +3361,48 @@ module.exports = GlobalizationError; define("cordova/plugin/InAppBrowser", function(require, exports, module) { var exec = require('cordova/exec'); - -function InAppBrowser() -{ - var _channel = require('cordova/channel'); +var channel = require('cordova/channel'); + +function InAppBrowser() { this.channels = { - 'loadstart': _channel.create('loadstart'), - 'loadstop' : _channel.create('loadstop'), - 'exit' : _channel.create('exit') + 'loadstart': channel.create('loadstart'), + 'loadstop' : channel.create('loadstop'), + 'exit' : channel.create('exit') }; } -InAppBrowser.prototype._eventHandler = function(event) -{ - if (event.type in this.channels) { - this.channels[event.type].fire(event); +InAppBrowser.prototype = { + _eventHandler: function (event) { + if (event.type in this.channels) { + this.channels[event.type].fire(event); + } + }, + close: function (eventname) { + exec(null, null, "InAppBrowser", "close", []); + }, + addEventListener: function (eventname,f) { + if (eventname in this.channels) { + this.channels[eventname].subscribe(f); + } + }, + removeEventListener: function(eventname, f) { + if (eventname in this.channels) { + this.channels[eventname].unsubscribe(f); + } } -} - -InAppBrowser.open = function(strUrl, strWindowName, strWindowFeatures) -{ +}; + +module.exports = function(strUrl, strWindowName, strWindowFeatures) { var iab = new InAppBrowser(); var cb = function(eventname) { iab._eventHandler(eventname); - } + }; exec(cb, null, "InAppBrowser", "open", [strUrl, strWindowName, strWindowFeatures]); return iab; -} - -InAppBrowser.prototype.close = function(eventname, f) -{ - exec(null, null, "InAppBrowser", "close", []); -} - -InAppBrowser.prototype.addEventListener = function(eventname, f) -{ - if (eventname in this.channels) { - this.channels[eventname].subscribe(f); - } -} - -InAppBrowser.prototype.removeEventListener = function(eventname, f) -{ - if (eventname in this.channels) { - this.channels[eventname].unsubscribe(f); - } -} - -module.exports = InAppBrowser.open; +}; +//Export the original open so it can be used if needed +module.exports._orig = window.open; }); @@ -3396,7 +3428,8 @@ module.exports = LocalFileSystem; // file: lib/common/plugin/Media.js define("cordova/plugin/Media", function(require, exports, module) { -var utils = require('cordova/utils'), +var argscheck = require('cordova/argscheck'), + utils = require('cordova/utils'), exec = require('cordova/exec'); var mediaObjects = {}; @@ -3414,25 +3447,7 @@ var mediaObjects = {}; * statusCallback(int statusCode) - OPTIONAL */ var Media = function(src, successCallback, errorCallback, statusCallback) { - - // successCallback optional - if (successCallback && (typeof successCallback !== "function")) { - console.log("Media Error: successCallback is not a function"); - return; - } - - // errorCallback optional - if (errorCallback && (typeof errorCallback !== "function")) { - console.log("Media Error: errorCallback is not a function"); - return; - } - - // statusCallback optional - if (statusCallback && (typeof statusCallback !== "function")) { - console.log("Media Error: statusCallback is not a function"); - return; - } - + argscheck.checkArgs('SFFF', 'Media', arguments); this.id = utils.createUUID(); mediaObjects[this.id] = this; this.src = src; @@ -3576,12 +3591,12 @@ Media.onStatus = function(id, msgType, value) { media._position = Number(value); break; default : - console && console.error && console.error("Unhandled Media.onStatus :: " + msgType); + console.error && console.error("Unhandled Media.onStatus :: " + msgType); break; } } else { - console && console.error && console.error("Received Media.onStatus callback for unknown media :: " + id); + console.error && console.error("Received Media.onStatus callback for unknown media :: " + id); } }; @@ -5113,10 +5128,50 @@ var exec = require('cordova/exec'); */ module.exports = function(successCallback, errorCallback, message, forceAsync) { var action = forceAsync ? 'echoAsync' : 'echo'; + if (!forceAsync && message.constructor == ArrayBuffer) { + action = 'echoArrayBuffer'; + } exec(successCallback, errorCallback, "Echo", action, [message]); }; +}); + +// file: lib/android/plugin/file/symbols.js +define("cordova/plugin/file/symbols", function(require, exports, module) { + + +var modulemapper = require('cordova/modulemapper'), + symbolshelper = require('cordova/plugin/file/symbolshelper'); + +symbolshelper(modulemapper.clobbers); + +}); + +// file: lib/common/plugin/file/symbolshelper.js +define("cordova/plugin/file/symbolshelper", function(require, exports, module) { + +module.exports = function(exportFunc) { + exportFunc('cordova/plugin/DirectoryEntry', 'DirectoryEntry'); + exportFunc('cordova/plugin/DirectoryReader', 'DirectoryReader'); + exportFunc('cordova/plugin/Entry', 'Entry'); + exportFunc('cordova/plugin/File', 'File'); + exportFunc('cordova/plugin/FileEntry', 'FileEntry'); + exportFunc('cordova/plugin/FileError', 'FileError'); + exportFunc('cordova/plugin/FileReader', 'FileReader'); + exportFunc('cordova/plugin/FileSystem', 'FileSystem'); + exportFunc('cordova/plugin/FileTransfer', 'FileTransfer'); + exportFunc('cordova/plugin/FileTransferError', 'FileTransferError'); + exportFunc('cordova/plugin/FileUploadOptions', 'FileUploadOptions'); + exportFunc('cordova/plugin/FileUploadResult', 'FileUploadResult'); + exportFunc('cordova/plugin/FileWriter', 'FileWriter'); + exportFunc('cordova/plugin/Flags', 'Flags'); + exportFunc('cordova/plugin/LocalFileSystem', 'LocalFileSystem'); + exportFunc('cordova/plugin/Metadata', 'Metadata'); + exportFunc('cordova/plugin/requestFileSystem', 'requestFileSystem'); + exportFunc('cordova/plugin/resolveLocalFileSystemURI', 'resolveLocalFileSystemURI'); +}; + }); // file: lib/common/plugin/geolocation.js @@ -6172,16 +6227,31 @@ define("cordova/utils", function(require, exports, module) { var utils = exports; /** - * Defines a property getter for obj[key]. + * Defines a property getter / setter for obj[key]. */ -utils.defineGetter = function(obj, key, func) { +utils.defineGetterSetter = function(obj, key, getFunc, opt_setFunc) { if (Object.defineProperty) { - Object.defineProperty(obj, key, { get: func }); + var desc = { + get: getFunc, + configurable: true + }; + if (opt_setFunc) { + desc.set = opt_setFunc; + } + Object.defineProperty(obj, key, desc); } else { - obj.__defineGetter__(key, func); + obj.__defineGetter__(key, getFunc); + if (opt_setFunc) { + obj.__defineSetter__(key, opt_setFunc); + } } }; +/** + * Defines a property getter for obj[key]. + */ +utils.defineGetter = utils.defineGetterSetter; + utils.arrayIndexOf = function(a, item) { if (a.indexOf) { return a.indexOf(item); @@ -6206,18 +6276,22 @@ utils.arrayRemove = function(a, item) { return index != -1; }; +utils.typeName = function(val) { + return Object.prototype.toString.call(val).slice(8, -1); +}; + /** * Returns an indication of whether the argument is an array or not */ utils.isArray = function(a) { - return Object.prototype.toString.call(a) == '[object Array]'; + return utils.typeName(a) == 'Array'; }; /** * Returns an indication of whether the argument is a Date or not */ utils.isDate = function(d) { - return Object.prototype.toString.call(d) == '[object Date]'; + return utils.typeName(d) == 'Date'; }; /** @@ -6402,7 +6476,7 @@ window.cordova = require('cordova'); // 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. if (context.navigator) { - function CordovaNavigator() {} + var CordovaNavigator = function() {}; CordovaNavigator.prototype = context.navigator; context.navigator = new CordovaNavigator(); } @@ -6420,12 +6494,12 @@ window.cordova = require('cordova'); // Drop the common globals into the window object, but be nice and don't overwrite anything. builder.buildIntoButDoNotClobber(base.defaults, context); - builder.buildIntoAndMerge(base.merges, context); builder.buildIntoAndClobber(base.clobbers, context); + builder.buildIntoAndMerge(base.merges, context); builder.buildIntoButDoNotClobber(platform.defaults, context); - builder.buildIntoAndMerge(platform.merges, context); builder.buildIntoAndClobber(platform.clobbers, context); + builder.buildIntoAndMerge(platform.merges, context); // Call the platform-specific initialization platform.initialize(); diff --git a/test/src/org/apache/cordova/test/IFrameTest.java b/test/src/org/apache/cordova/test/IFrameTest.java index 02bb1305..7cb87987 100644 --- a/test/src/org/apache/cordova/test/IFrameTest.java +++ b/test/src/org/apache/cordova/test/IFrameTest.java @@ -21,14 +21,72 @@ package org.apache.cordova.test; */ +import org.apache.cordova.CordovaWebView; +import org.apache.cordova.test.util.Purity; import org.apache.cordova.test.actions.iframe; +import android.app.Activity; +import android.app.Instrumentation; import android.test.ActivityInstrumentationTestCase2; +import android.test.TouchUtils; +import android.widget.FrameLayout; +import android.widget.LinearLayout; -public class IFrameTest extends ActivityInstrumentationTestCase2