2 * PhoneGap v1.1.0 is available under *either* the terms of the modified BSD license *or* the
3 * MIT License (2008). See http://opensource.org/licenses/alphabetical for full text.
5 * Copyright (c) 2005-2010, Nitobi Software Inc.
6 * Copyright (c) 2010-2011, IBM Corporation
7 * Copyright (c) 2011, Codevise Solutions Ltd.
8 * Copyright (c) 2011, Proyectos Equis Ka, S.L.
12 if (typeof PhoneGap === "undefined") {
14 if (typeof(DeviceInfo) !== 'object'){
18 * This represents the PhoneGap API itself, and provides a global namespace for accessing
19 * information about the state of PhoneGap.
23 // This queue holds the currently executing command and all pending
24 // commands executed with PhoneGap.exec().
26 // Indicates if we're currently in the middle of flushing the command
27 // queue on the native side.
28 commandQueueFlushing: false,
30 documentEventHandler: {}, // Collection of custom document event handlers
31 windowEventHandler: {}
35 * List of resource files loaded by PhoneGap.
36 * This is used to ensure JS and other files are loaded only once.
38 PhoneGap.resources = {base: true};
41 * Determine if resource has been loaded by PhoneGap
46 PhoneGap.hasResource = function(name) {
47 return PhoneGap.resources[name];
51 * Add a resource to list of loaded resources by PhoneGap
55 PhoneGap.addResource = function(name) {
56 PhoneGap.resources[name] = true;
60 * Boolean flag indicating if the PhoneGap API is available and initialized.
61 */ // TODO: Remove this, it is unused here ... -jm
62 PhoneGap.available = DeviceInfo.uuid != undefined;
65 * Add an initialization function to a queue that ensures it will run and initialize
66 * application constructors only once PhoneGap has been initialized.
67 * @param {Function} func The function callback you want run once PhoneGap is initialized
69 PhoneGap.addConstructor = function(func) {
70 var state = document.readyState;
71 if ( ( state == 'loaded' || state == 'complete' ) && DeviceInfo.uuid != null )
77 PhoneGap._constructors.push(func);
83 var timer = setInterval(function()
86 var state = document.readyState;
88 if ( ( state == 'loaded' || state == 'complete' ) && DeviceInfo.uuid != null )
90 clearInterval(timer); // stop looking
91 // run our constructors list
92 while (PhoneGap._constructors.length > 0)
94 var constructor = PhoneGap._constructors.shift();
101 if (typeof(console['log']) == 'function')
103 console.log("Failed to run constructor: " + console.processMessage(e));
107 alert("Failed to run constructor: " + e.message);
111 // all constructors run, now fire the deviceready event
112 var e = document.createEvent('Events');
113 e.initEvent('deviceready');
114 document.dispatchEvent(e);
119 // session id for calls
120 PhoneGap.sessionKey = 0;
122 // centralized callbacks
123 PhoneGap.callbackId = 0;
124 PhoneGap.callbacks = {};
125 PhoneGap.callbackStatus = {
128 CLASS_NOT_FOUND_EXCEPTION: 2,
129 ILLEGAL_ACCESS_EXCEPTION: 3,
130 INSTANTIATION_EXCEPTION: 4,
131 MALFORMED_URL_EXCEPTION: 5,
139 * Creates a gap bridge iframe used to notify the native code about queued
144 PhoneGap.createGapBridge = function() {
145 gapBridge = document.createElement("iframe");
146 gapBridge.setAttribute("style", "display:none;");
147 gapBridge.setAttribute("height","0px");
148 gapBridge.setAttribute("width","0px");
149 gapBridge.setAttribute("frameborder","0");
150 document.documentElement.appendChild(gapBridge);
155 * Execute a PhoneGap command by queuing it and letting the native side know
156 * there are queued commands. The native side will then request all of the
157 * queued commands and execute them.
159 * Arguments may be in one of two formats:
161 * FORMAT ONE (preferable)
162 * The native side will call PhoneGap.callbackSuccess or
163 * PhoneGap.callbackError, depending upon the result of the action.
165 * @param {Function} success The success callback
166 * @param {Function} fail The fail callback
167 * @param {String} service The name of the service to use
168 * @param {String} action The name of the action to use
169 * @param {String[]} [args] Zero or more arguments to pass to the method
172 * @param {String} command Command to be run in PhoneGap, e.g.
174 * @param {String[]} [args] Zero or more arguments to pass to the method
175 * object parameters are passed as an array object
176 * [object1, object2] each object will be passed as
179 PhoneGap.exec = function() {
180 if (!PhoneGap.available) {
181 alert("ERROR: Attempting to call PhoneGap.exec()"
182 +" before 'deviceready'. Ignoring.");
186 var successCallback, failCallback, service, action, actionArgs;
187 var callbackId = null;
188 if (typeof arguments[0] !== "string") {
190 successCallback = arguments[0];
191 failCallback = arguments[1];
192 service = arguments[2];
193 action = arguments[3];
194 actionArgs = arguments[4];
196 // Since we need to maintain backwards compatibility, we have to pass
197 // an invalid callbackId even if no callback was provided since plugins
198 // will be expecting it. The PhoneGap.exec() implementation allocates
199 // an invalid callbackId and passes it even if no callbacks were given.
200 callbackId = 'INVALID';
203 splitCommand = arguments[0].split(".");
204 action = splitCommand.pop();
205 service = splitCommand.join(".");
206 actionArgs = Array.prototype.splice.call(arguments, 1);
209 // Start building the command object.
216 // Register the callbacks and add the callbackId to the positional
217 // arguments if given.
218 if (successCallback || failCallback) {
219 callbackId = service + PhoneGap.callbackId++;
220 PhoneGap.callbacks[callbackId] =
221 {success:successCallback, fail:failCallback};
223 if (callbackId != null) {
224 command.arguments.push(callbackId);
227 for (var i = 0; i < actionArgs.length; ++i) {
228 var arg = actionArgs[i];
229 if (arg == undefined || arg == null) {
231 } else if (typeof(arg) == 'object') {
232 command.options = arg;
234 command.arguments.push(arg);
238 // Stringify and queue the command. We stringify to command now to
239 // effectively clone the command arguments in case they are mutated before
240 // the command is executed.
241 PhoneGap.commandQueue.push(JSON.stringify(command));
243 // If the queue length is 1, then that means it was empty before we queued
244 // the given command, so let the native side know that we have some
245 // commands to execute, unless the queue is currently being flushed, in
246 // which case the command will be picked up without notification.
247 if (PhoneGap.commandQueue.length == 1 && !PhoneGap.commandQueueFlushing) {
248 if (!PhoneGap.gapBridge) {
249 PhoneGap.gapBridge = PhoneGap.createGapBridge();
252 PhoneGap.gapBridge.src = "gap://ready";
257 * Called by native code to retrieve all queued commands and clear the queue.
259 PhoneGap.getAndClearQueuedCommands = function() {
260 json = JSON.stringify(PhoneGap.commandQueue);
261 PhoneGap.commandQueue = [];
266 * Called by native code when returning successful result from an action.
270 * args.status - PhoneGap.callbackStatus
271 * args.message - return value
272 * args.keepCallback - 0 to remove callback, 1 to keep callback in PhoneGap.callbacks[]
274 PhoneGap.callbackSuccess = function(callbackId, args) {
275 if (PhoneGap.callbacks[callbackId]) {
277 // If result is to be sent to callback
278 if (args.status == PhoneGap.callbackStatus.OK) {
280 if (PhoneGap.callbacks[callbackId].success) {
281 PhoneGap.callbacks[callbackId].success(args.message);
285 console.log("Error in success callback: "+callbackId+" = "+e);
289 // Clear callback if not expecting any more results
290 if (!args.keepCallback) {
291 delete PhoneGap.callbacks[callbackId];
297 * Called by native code when returning error result from an action.
302 PhoneGap.callbackError = function(callbackId, args) {
303 if (PhoneGap.callbacks[callbackId]) {
305 if (PhoneGap.callbacks[callbackId].fail) {
306 PhoneGap.callbacks[callbackId].fail(args.message);
310 console.log("Error in error callback: "+callbackId+" = "+e);
313 // Clear callback if not expecting any more results
314 if (!args.keepCallback) {
315 delete PhoneGap.callbacks[callbackId];
322 * Does a deep clone of the object.
327 PhoneGap.clone = function(obj) {
332 if(obj instanceof Array){
333 var retVal = new Array();
334 for(var i = 0; i < obj.length; ++i){
335 retVal.push(PhoneGap.clone(obj[i]));
340 if (obj instanceof Function) {
344 if(!(obj instanceof Object)){
348 if (obj instanceof Date) {
352 retVal = new Object();
354 if(!(i in retVal) || retVal[i] != obj[i]) {
355 retVal[i] = PhoneGap.clone(obj[i]);
361 // Intercept calls to document.addEventListener
362 PhoneGap.m_document_addEventListener = document.addEventListener;
364 // Intercept calls to window.addEventListener
365 PhoneGap.m_window_addEventListener = window.addEventListener;
368 * Add a custom window event handler.
370 * @param {String} event The event name that callback handles
371 * @param {Function} callback The event handler
373 PhoneGap.addWindowEventHandler = function(event, callback) {
374 PhoneGap.windowEventHandler[event] = callback;
378 * Add a custom document event handler.
380 * @param {String} event The event name that callback handles
381 * @param {Function} callback The event handler
383 PhoneGap.addDocumentEventHandler = function(event, callback) {
384 PhoneGap.documentEventHandler[event] = callback;
388 * Intercept adding document event listeners and handle our own
390 * @param {Object} evt
391 * @param {Function} handler
394 document.addEventListener = function(evt, handler, capture) {
395 var e = evt.toLowerCase();
397 // If subscribing to an event that is handled by a plugin
398 if (typeof PhoneGap.documentEventHandler[e] !== "undefined") {
399 if (PhoneGap.documentEventHandler[e](e, handler, true)) {
400 return; // Stop default behavior
404 PhoneGap.m_document_addEventListener.call(document, evt, handler, capture);
408 * Intercept adding window event listeners and handle our own
410 * @param {Object} evt
411 * @param {Function} handler
414 window.addEventListener = function(evt, handler, capture) {
415 var e = evt.toLowerCase();
417 // If subscribing to an event that is handled by a plugin
418 if (typeof PhoneGap.windowEventHandler[e] !== "undefined") {
419 if (PhoneGap.windowEventHandler[e](e, handler, true)) {
420 return; // Stop default behavior
424 PhoneGap.m_window_addEventListener.call(window, evt, handler, capture);
427 // Intercept calls to document.removeEventListener and watch for events that
428 // are generated by PhoneGap native code
429 PhoneGap.m_document_removeEventListener = document.removeEventListener;
431 // Intercept calls to window.removeEventListener
432 PhoneGap.m_window_removeEventListener = window.removeEventListener;
435 * Intercept removing document event listeners and handle our own
437 * @param {Object} evt
438 * @param {Function} handler
441 document.removeEventListener = function(evt, handler, capture) {
442 var e = evt.toLowerCase();
444 // If unsubcribing from an event that is handled by a plugin
445 if (typeof PhoneGap.documentEventHandler[e] !== "undefined") {
446 if (PhoneGap.documentEventHandler[e](e, handler, false)) {
447 return; // Stop default behavior
451 PhoneGap.m_document_removeEventListener.call(document, evt, handler, capture);
455 * Intercept removing window event listeners and handle our own
457 * @param {Object} evt
458 * @param {Function} handler
461 window.removeEventListener = function(evt, handler, capture) {
462 var e = evt.toLowerCase();
464 // If unsubcribing from an event that is handled by a plugin
465 if (typeof PhoneGap.windowEventHandler[e] !== "undefined") {
466 if (PhoneGap.windowEventHandler[e](e, handler, false)) {
467 return; // Stop default behavior
471 PhoneGap.m_window_removeEventListener.call(window, evt, handler, capture);
475 * Method to fire document event
477 * @param {String} type The event type to fire
478 * @param {Object} data Data to send with event
480 PhoneGap.fireDocumentEvent = function(type, data) {
481 var e = document.createEvent('Events');
484 for (var i in data) {
488 document.dispatchEvent(e);
492 * Method to fire window event
494 * @param {String} type The event type to fire
495 * @param {Object} data Data to send with event
497 PhoneGap.fireWindowEvent = function(type, data) {
498 var e = document.createEvent('Events');
501 for (var i in data) {
505 window.dispatchEvent(e);
509 * Method to fire event from native code
510 * Leaving this generic version to handle problems with iOS 3.x. Is currently used by orientation and battery events
511 * Remove when iOS 3.x no longer supported and call fireWindowEvent or fireDocumentEvent directly
513 PhoneGap.fireEvent = function(type, target, data) {
514 var e = document.createEvent('Events');
517 for (var i in data) {
521 target = target || document;
522 if (target.dispatchEvent === undefined) { // ie window.dispatchEvent is undefined in iOS 3.x
526 target.dispatchEvent(e);
533 PhoneGap.createUUID = function() {
534 return PhoneGap.UUIDcreatePart(4) + '-' +
535 PhoneGap.UUIDcreatePart(2) + '-' +
536 PhoneGap.UUIDcreatePart(2) + '-' +
537 PhoneGap.UUIDcreatePart(2) + '-' +
538 PhoneGap.UUIDcreatePart(6);
541 PhoneGap.UUIDcreatePart = function(length) {
543 for (var i=0; i<length; i++) {
544 var uuidchar = parseInt((Math.random() * 256)).toString(16);
545 if (uuidchar.length == 1) {
546 uuidchar = "0" + uuidchar;
548 uuidpart += uuidchar;
555 if (!PhoneGap.hasResource("debugconsole")) {
556 PhoneGap.addResource("debugconsole");
559 * This class provides access to the debugging console.
562 var DebugConsole = function() {
563 this.winConsole = window.console;
564 this.logLevel = DebugConsole.INFO_LEVEL;
567 // from most verbose, to least verbose
568 DebugConsole.ALL_LEVEL = 1; // same as first level
569 DebugConsole.INFO_LEVEL = 1;
570 DebugConsole.WARN_LEVEL = 2;
571 DebugConsole.ERROR_LEVEL = 4;
572 DebugConsole.NONE_LEVEL = 8;
574 DebugConsole.prototype.setLevel = function(level) {
575 this.logLevel = level;
579 * Utility function for rendering and indenting strings, or serializing
580 * objects to a string capable of being printed to the console.
581 * @param {Object|String} message The string or object to convert to an indented string
584 DebugConsole.prototype.processMessage = function(message, maxDepth) {
585 if (maxDepth === undefined) maxDepth = 0;
586 if (typeof(message) != 'object') {
587 return (this.isDeprecated ? "WARNING: debug object is deprecated, please use console object \n" + message : message);
593 function indent(str) {
594 return str.replace(/^/mg, " ");
600 function makeStructured(obj, depth) {
604 if (typeof(obj[i]) == 'object' && depth < maxDepth) {
605 str += i + ":\n" + indent(makeStructured(obj[i])) + "\n";
607 str += i + " = " + indent(String(obj[i])).replace(/^ /, "") + "\n";
610 str += i + " = EXCEPTION: " + e.message + "\n";
616 return ("Object:\n" + makeStructured(message, maxDepth));
621 * Print a normal log message to the console
622 * @param {Object|String} message Message or object to print to the console
624 DebugConsole.prototype.log = function(message, maxDepth) {
625 if (PhoneGap.available && this.logLevel <= DebugConsole.INFO_LEVEL)
626 PhoneGap.exec(null, null, 'com.phonegap.debugconsole', 'log',
627 [ this.processMessage(message, maxDepth), { logLevel: 'INFO' } ]
630 this.winConsole.log(message);
634 * Print a warning message to the console
635 * @param {Object|String} message Message or object to print to the console
637 DebugConsole.prototype.warn = function(message, maxDepth) {
638 if (PhoneGap.available && this.logLevel <= DebugConsole.WARN_LEVEL)
639 PhoneGap.exec(null, null, 'com.phonegap.debugconsole', 'log',
640 [ this.processMessage(message, maxDepth), { logLevel: 'WARN' } ]
643 this.winConsole.error(message);
647 * Print an error message to the console
648 * @param {Object|String} message Message or object to print to the console
650 DebugConsole.prototype.error = function(message, maxDepth) {
651 if (PhoneGap.available && this.logLevel <= DebugConsole.ERROR_LEVEL)
652 PhoneGap.exec(null, null, 'com.phonegap.debugconsole', 'log',
653 [ this.processMessage(message, maxDepth), { logLevel: 'ERROR' } ]
656 this.winConsole.error(message);
659 PhoneGap.addConstructor(function() {
660 window.console = new DebugConsole();
663 if (!PhoneGap.hasResource("position")) {
664 PhoneGap.addResource("position");
667 * This class contains position information.
668 * @param {Object} lat
669 * @param {Object} lng
670 * @param {Object} acc
671 * @param {Object} alt
672 * @param {Object} altAcc
673 * @param {Object} head
674 * @param {Object} vel
677 Position = function(coords, timestamp) {
678 this.coords = Coordinates.cloneFrom(coords);
679 this.timestamp = timestamp || new Date().getTime();
682 Position.prototype.equals = function(other) {
683 return (this.coords && other && other.coords &&
684 this.coords.latitude == other.coords.latitude &&
685 this.coords.longitude == other.coords.longitude);
688 Position.prototype.clone = function()
691 this.coords? this.coords.clone() : null,
692 this.timestamp? this.timestamp : new Date().getTime()
696 Coordinates = function(lat, lng, alt, acc, head, vel, altAcc) {
698 * The latitude of the position.
702 * The longitude of the position,
704 this.longitude = lng;
706 * The altitude of the position.
710 * The accuracy of the position.
714 * The direction the device is moving at the position.
718 * The velocity with which the device is moving at the position.
722 * The altitude accuracy of the position.
724 this.altitudeAccuracy = (altAcc != 'undefined') ? altAcc : null;
727 Coordinates.prototype.clone = function()
729 return new Coordinates(
736 this.altitudeAccuracy
740 Coordinates.cloneFrom = function(obj)
742 return new Coordinates(
754 * This class specifies the options for requesting position data.
757 PositionOptions = function(enableHighAccuracy, timeout, maximumAge) {
759 * Specifies the desired position accuracy.
761 this.enableHighAccuracy = enableHighAccuracy || false;
763 * The timeout after which if position data cannot be obtained the errorCallback
766 this.timeout = timeout || 10000;
768 * The age of a cached position whose age is no greater than the specified time
771 this.maximumAge = maximumAge || 0;
773 if (this.maximumAge < 0) {
779 * This class contains information about any GPS errors.
782 PositionError = function(code, message) {
783 this.code = code || 0;
784 this.message = message || "";
787 PositionError.UNKNOWN_ERROR = 0;
788 PositionError.PERMISSION_DENIED = 1;
789 PositionError.POSITION_UNAVAILABLE = 2;
790 PositionError.TIMEOUT = 3;
792 };if (!PhoneGap.hasResource("acceleration")) {
793 PhoneGap.addResource("acceleration");
797 * This class contains acceleration information
799 * @param {Number} x The force applied by the device in the x-axis.
800 * @param {Number} y The force applied by the device in the y-axis.
801 * @param {Number} z The force applied by the device in the z-axis.
803 Acceleration = function(x, y, z) {
805 * The force applied by the device in the x-axis.
809 * The force applied by the device in the y-axis.
813 * The force applied by the device in the z-axis.
817 * The time that the acceleration was obtained.
819 this.timestamp = new Date().getTime();
823 * This class specifies the options for requesting acceleration data.
826 AccelerationOptions = function() {
828 * The timeout after which if acceleration data cannot be obtained the errorCallback
831 this.timeout = 10000;
833 };if (!PhoneGap.hasResource("accelerometer")) {
834 PhoneGap.addResource("accelerometer");
837 * This class provides access to device accelerometer data.
840 Accelerometer = function()
843 * The last known acceleration.
845 this.lastAcceleration = new Acceleration(0,0,0);
849 * Asynchronously aquires the current acceleration.
850 * @param {Function} successCallback The function to call when the acceleration
852 * @param {Function} errorCallback The function to call when there is an error
853 * getting the acceleration data.
854 * @param {AccelerationOptions} options The options for getting the accelerometer data
857 Accelerometer.prototype.getCurrentAcceleration = function(successCallback, errorCallback, options) {
858 // If the acceleration is available then call success
859 // If the acceleration is not available then call error
861 // Created for iPhone, Iphone passes back _accel obj litteral
862 if (typeof successCallback == "function") {
863 successCallback(this.lastAcceleration);
867 // private callback called from Obj-C by name
868 Accelerometer.prototype._onAccelUpdate = function(x,y,z)
870 this.lastAcceleration = new Acceleration(x,y,z);
874 * Asynchronously aquires the acceleration repeatedly at a given interval.
875 * @param {Function} successCallback The function to call each time the acceleration
877 * @param {Function} errorCallback The function to call when there is an error
878 * getting the acceleration data.
879 * @param {AccelerationOptions} options The options for getting the accelerometer data
883 Accelerometer.prototype.watchAcceleration = function(successCallback, errorCallback, options) {
884 //this.getCurrentAcceleration(successCallback, errorCallback, options);
885 // TODO: add the interval id to a list so we can clear all watches
886 var frequency = (options != undefined && options.frequency != undefined) ? options.frequency : 10000;
887 var updatedOptions = {
888 desiredFrequency:frequency
890 PhoneGap.exec(null, null, "com.phonegap.accelerometer", "start", [options]);
892 return setInterval(function() {
893 navigator.accelerometer.getCurrentAcceleration(successCallback, errorCallback, options);
898 * Clears the specified accelerometer watch.
899 * @param {String} watchId The ID of the watch returned from #watchAcceleration.
901 Accelerometer.prototype.clearWatch = function(watchId) {
902 PhoneGap.exec(null, null, "com.phonegap.accelerometer", "stop", []);
903 clearInterval(watchId);
906 Accelerometer.install = function()
908 if (typeof navigator.accelerometer == "undefined") {
909 navigator.accelerometer = new Accelerometer();
913 Accelerometer.installDeviceMotionHandler = function()
915 if (!(window.DeviceMotionEvent == undefined)) {
916 // supported natively, so we don't have to add support
921 var devicemotionEvent = 'devicemotion';
922 self.deviceMotionWatchId = null;
923 self.deviceMotionListenerCount = 0;
924 self.deviceMotionLastEventTimestamp = 0;
926 // backup original `window.addEventListener`, `window.removeEventListener`
927 var _addEventListener = window.addEventListener;
928 var _removeEventListener = window.removeEventListener;
930 var windowDispatchAvailable = !(window.dispatchEvent === undefined); // undefined in iOS 3.x
932 var accelWin = function(acceleration) {
933 var evt = document.createEvent('Events');
934 evt.initEvent(devicemotionEvent);
936 evt.acceleration = null; // not all devices have gyroscope, don't care for now if we actually have it.
937 evt.rotationRate = null; // not all devices have gyroscope, don't care for now if we actually have it:
938 evt.accelerationIncludingGravity = acceleration; // accelerometer, all iOS devices have it
940 var currentTime = new Date().getTime();
941 evt.interval = (self.deviceMotionLastEventTimestamp == 0) ? 0 : (currentTime - self.deviceMotionLastEventTimestamp);
942 self.deviceMotionLastEventTimestamp = currentTime;
944 if (windowDispatchAvailable) {
945 window.dispatchEvent(evt);
947 document.dispatchEvent(evt);
951 var accelFail = function() {
955 // override `window.addEventListener`
956 window.addEventListener = function() {
957 if (arguments[0] === devicemotionEvent) {
958 ++(self.deviceMotionListenerCount);
959 if (self.deviceMotionListenerCount == 1) { // start
960 self.deviceMotionWatchId = navigator.accelerometer.watchAcceleration(accelWin, accelFail, { frequency:500});
964 if (!windowDispatchAvailable) {
965 return document.addEventListener.apply(this, arguments);
967 return _addEventListener.apply(this, arguments);
971 // override `window.removeEventListener'
972 window.removeEventListener = function() {
973 if (arguments[0] === devicemotionEvent) {
974 --(self.deviceMotionListenerCount);
975 if (self.deviceMotionListenerCount == 0) { // stop
976 navigator.accelerometer.clearWatch(self.deviceMotionWatchId);
980 if (!windowDispatchAvailable) {
981 return document.removeEventListener.apply(this, arguments);
983 return _removeEventListener.apply(this, arguments);
989 PhoneGap.addConstructor(Accelerometer.install);
990 PhoneGap.addConstructor(Accelerometer.installDeviceMotionHandler);
993 * PhoneGap is available under *either* the terms of the modified BSD license *or* the
994 * MIT License (2008). See http://opensource.org/licenses/alphabetical for full text.
996 * Copyright (c) 2005-2010, Nitobi Software Inc.
997 * Copyright (c) 2010-2011, IBM Corporation
1000 if (!PhoneGap.hasResource("battery")) {
1001 PhoneGap.addResource("battery");
1004 * This class contains information about the current battery status.
1007 var Battery = function() {
1009 this._isPlugged = null;
1010 this._batteryListener = [];
1011 this._lowListener = [];
1012 this._criticalListener = [];
1016 * Registers as an event producer for battery events.
1018 * @param {Object} eventType
1019 * @param {Object} handler
1020 * @param {Object} add
1022 Battery.prototype.eventHandler = function(eventType, handler, add) {
1023 var me = navigator.battery;
1025 // If there are no current registered event listeners start the battery listener on native side.
1026 if (me._batteryListener.length === 0 && me._lowListener.length === 0 && me._criticalListener.length === 0) {
1027 PhoneGap.exec(me._status, me._error, "com.phonegap.battery", "start", []);
1030 // Register the event listener in the proper array
1031 if (eventType === "batterystatus") {
1032 var pos = me._batteryListener.indexOf(handler);
1034 me._batteryListener.push(handler);
1036 } else if (eventType === "batterylow") {
1037 var pos = me._lowListener.indexOf(handler);
1039 me._lowListener.push(handler);
1041 } else if (eventType === "batterycritical") {
1042 var pos = me._criticalListener.indexOf(handler);
1044 me._criticalListener.push(handler);
1048 // Remove the event listener from the proper array
1049 if (eventType === "batterystatus") {
1050 var pos = me._batteryListener.indexOf(handler);
1052 me._batteryListener.splice(pos, 1);
1054 } else if (eventType === "batterylow") {
1055 var pos = me._lowListener.indexOf(handler);
1057 me._lowListener.splice(pos, 1);
1059 } else if (eventType === "batterycritical") {
1060 var pos = me._criticalListener.indexOf(handler);
1062 me._criticalListener.splice(pos, 1);
1066 // If there are no more registered event listeners stop the battery listener on native side.
1067 if (me._batteryListener.length === 0 && me._lowListener.length === 0 && me._criticalListener.length === 0) {
1068 PhoneGap.exec(null, null, "com.phonegap.battery", "stop", []);
1074 * Callback for battery status
1076 * @param {Object} info keys: level, isPlugged
1078 Battery.prototype._status = function(info) {
1081 if (me._level != info.level || me._isPlugged != info.isPlugged) {
1082 // Fire batterystatus event
1083 //PhoneGap.fireWindowEvent("batterystatus", info);
1084 // use this workaround since iOS 3.x does have window.dispatchEvent
1085 PhoneGap.fireEvent("batterystatus", window, info);
1087 // Fire low battery event
1088 if (info.level == 20 || info.level == 5) {
1089 if (info.level == 20) {
1090 //PhoneGap.fireWindowEvent("batterylow", info);
1091 // use this workaround since iOS 3.x does not have window.dispatchEvent
1092 PhoneGap.fireEvent("batterylow", window, info);
1095 //PhoneGap.fireWindowEvent("batterycritical", info);
1096 // use this workaround since iOS 3.x does not have window.dispatchEvent
1097 PhoneGap.fireEvent("batterycritical", window, info);
1101 me._level = info.level;
1102 me._isPlugged = info.isPlugged;
1107 * Error callback for battery start
1109 Battery.prototype._error = function(e) {
1110 console.log("Error initializing Battery: " + e);
1113 PhoneGap.addConstructor(function() {
1114 if (typeof navigator.battery === "undefined") {
1115 navigator.battery = new Battery();
1116 PhoneGap.addWindowEventHandler("batterystatus", navigator.battery.eventHandler);
1117 PhoneGap.addWindowEventHandler("batterylow", navigator.battery.eventHandler);
1118 PhoneGap.addWindowEventHandler("batterycritical", navigator.battery.eventHandler);
1121 }if (!PhoneGap.hasResource("camera")) {
1122 PhoneGap.addResource("camera");
1126 * This class provides access to the device camera.
1129 Camera = function() {
1133 * Available Camera Options
1134 * {boolean} allowEdit - true to allow editing image, default = false
1135 * {number} quality 0-100 (low to high) default = 100
1136 * {Camera.DestinationType} destinationType default = DATA_URL
1137 * {Camera.PictureSourceType} sourceType default = CAMERA
1138 * {number} targetWidth - width in pixels to scale image default = 0 (no scaling)
1139 * {number} targetHeight - height in pixels to scale image default = 0 (no scaling)
1140 * {Camera.EncodingType} - encodingType default = JPEG
1143 * Format of image that is returned from getPicture.
1145 * Example: navigator.camera.getPicture(success, fail,
1147 * destinationType: Camera.DestinationType.DATA_URL,
1148 * sourceType: Camera.PictureSourceType.PHOTOLIBRARY})
1150 Camera.DestinationType = {
1151 DATA_URL: 0, // Return base64 encoded string
1152 FILE_URI: 1 // Return file uri
1154 Camera.prototype.DestinationType = Camera.DestinationType;
1157 * Source to getPicture from.
1159 * Example: navigator.camera.getPicture(success, fail,
1161 * destinationType: Camera.DestinationType.DATA_URL,
1162 * sourceType: Camera.PictureSourceType.PHOTOLIBRARY})
1164 Camera.PictureSourceType = {
1165 PHOTOLIBRARY : 0, // Choose image from picture library
1166 CAMERA : 1, // Take picture from camera
1167 SAVEDPHOTOALBUM : 2 // Choose image from picture library
1169 Camera.prototype.PictureSourceType = Camera.PictureSourceType;
1172 * Encoding of image returned from getPicture.
1174 * Example: navigator.camera.getPicture(success, fail,
1176 * destinationType: Camera.DestinationType.DATA_URL,
1177 * sourceType: Camera.PictureSourceType.CAMERA,
1178 * encodingType: Camera.EncodingType.PNG})
1180 Camera.EncodingType = {
1181 JPEG: 0, // Return JPEG encoded image
1182 PNG: 1 // Return PNG encoded image
1184 Camera.prototype.EncodingType = Camera.EncodingType;
1187 * Type of pictures to select from. Only applicable when
1188 * PictureSourceType is PHOTOLIBRARY or SAVEDPHOTOALBUM
1190 * Example: navigator.camera.getPicture(success, fail,
1192 * destinationType: Camera.DestinationType.DATA_URL,
1193 * sourceType: Camera.PictureSourceType.PHOTOLIBRARY,
1194 * mediaType: Camera.MediaType.PICTURE})
1196 Camera.MediaType = {
1197 PICTURE: 0, // allow selection of still pictures only. DEFAULT. Will return format specified via DestinationType
1198 VIDEO: 1, // allow selection of video only, ONLY RETURNS URL
1199 ALLMEDIA : 2 // allow selection from all media types
1201 Camera.prototype.MediaType = Camera.MediaType;
1204 * Gets a picture from source defined by "options.sourceType", and returns the
1205 * image as defined by the "options.destinationType" option.
1207 * The defaults are sourceType=CAMERA and destinationType=DATA_URL.
1209 * @param {Function} successCallback
1210 * @param {Function} errorCallback
1211 * @param {Object} options
1213 Camera.prototype.getPicture = function(successCallback, errorCallback, options) {
1214 // successCallback required
1215 if (typeof successCallback != "function") {
1216 console.log("Camera Error: successCallback is not a function");
1220 // errorCallback optional
1221 if (errorCallback && (typeof errorCallback != "function")) {
1222 console.log("Camera Error: errorCallback is not a function");
1226 PhoneGap.exec(successCallback, errorCallback, "com.phonegap.camera","getPicture",[options]);
1231 PhoneGap.addConstructor(function() {
1232 if (typeof navigator.camera == "undefined") navigator.camera = new Camera();
1236 if (!PhoneGap.hasResource("device")) {
1237 PhoneGap.addResource("device");
1240 * this represents the mobile device, and provides properties for inspecting the model, version, UUID of the
1246 this.platform = null;
1247 this.version = null;
1249 this.phonegap = null;
1253 this.platform = DeviceInfo.platform;
1254 this.version = DeviceInfo.version;
1255 this.name = DeviceInfo.name;
1256 this.phonegap = DeviceInfo.gap;
1257 this.uuid = DeviceInfo.uuid;
1264 this.available = PhoneGap.available = this.uuid != null;
1267 PhoneGap.addConstructor(function() {
1268 if (typeof navigator.device === "undefined") {
1269 navigator.device = window.device = new Device();
1274 if (!PhoneGap.hasResource("capture")) {
1275 PhoneGap.addResource("capture");
1277 * The CaptureError interface encapsulates all errors in the Capture API.
1279 function CaptureError() {
1283 // Capture error codes
1284 CaptureError.CAPTURE_INTERNAL_ERR = 0;
1285 CaptureError.CAPTURE_APPLICATION_BUSY = 1;
1286 CaptureError.CAPTURE_INVALID_ARGUMENT = 2;
1287 CaptureError.CAPTURE_NO_MEDIA_FILES = 3;
1288 CaptureError.CAPTURE_NOT_SUPPORTED = 20;
1291 * The Capture interface exposes an interface to the camera and microphone of the hosting device.
1293 function Capture() {
1294 this.supportedAudioModes = [];
1295 this.supportedImageModes = [];
1296 this.supportedVideoModes = [];
1300 * Launch audio recorder application for recording audio clip(s).
1302 * @param {Function} successCB
1303 * @param {Function} errorCB
1304 * @param {CaptureAudioOptions} options
1306 * No audio recorder to launch for iOS - return CAPTURE_NOT_SUPPORTED
1308 Capture.prototype.captureAudio = function(successCallback, errorCallback, options) {
1309 /*if (errorCallback && typeof errorCallback === "function") {
1311 "code": CaptureError.CAPTURE_NOT_SUPPORTED
1314 PhoneGap.exec(successCallback, errorCallback, "com.phonegap.mediacapture", "captureAudio", [options]);
1318 * Launch camera application for taking image(s).
1320 * @param {Function} successCB
1321 * @param {Function} errorCB
1322 * @param {CaptureImageOptions} options
1324 Capture.prototype.captureImage = function(successCallback, errorCallback, options) {
1325 PhoneGap.exec(successCallback, errorCallback, "com.phonegap.mediacapture", "captureImage", [options]);
1329 * Launch camera application for taking image(s).
1331 * @param {Function} successCB
1332 * @param {Function} errorCB
1333 * @param {CaptureImageOptions} options
1335 Capture.prototype._castMediaFile = function(pluginResult) {
1336 var mediaFiles = [];
1338 for (i=0; i<pluginResult.message.length; i++) {
1339 var mediaFile = new MediaFile();
1340 mediaFile.name = pluginResult.message[i].name;
1341 mediaFile.fullPath = pluginResult.message[i].fullPath;
1342 mediaFile.type = pluginResult.message[i].type;
1343 mediaFile.lastModifiedDate = pluginResult.message[i].lastModifiedDate;
1344 mediaFile.size = pluginResult.message[i].size;
1345 mediaFiles.push(mediaFile);
1347 pluginResult.message = mediaFiles;
1348 return pluginResult;
1352 * Launch device camera application for recording video(s).
1354 * @param {Function} successCB
1355 * @param {Function} errorCB
1356 * @param {CaptureVideoOptions} options
1358 Capture.prototype.captureVideo = function(successCallback, errorCallback, options) {
1359 PhoneGap.exec(successCallback, errorCallback, "com.phonegap.mediacapture", "captureVideo", [options]);
1363 * Encapsulates a set of parameters that the capture device supports.
1365 function ConfigurationData() {
1366 // The ASCII-encoded string in lower case representing the media type.
1368 // The height attribute represents height of the image or video in pixels.
1369 // In the case of a sound clip this attribute has value 0.
1371 // The width attribute represents width of the image or video in pixels.
1372 // In the case of a sound clip this attribute has value 0
1377 * Encapsulates all image capture operation configuration options.
1379 var CaptureImageOptions = function() {
1380 // Upper limit of images user can take. Value must be equal or greater than 1.
1382 // The selected image mode. Must match with one of the elements in supportedImageModes array.
1387 * Encapsulates all video capture operation configuration options.
1389 var CaptureVideoOptions = function() {
1390 // Upper limit of videos user can record. Value must be equal or greater than 1.
1392 // Maximum duration of a single video clip in seconds.
1394 // The selected video mode. Must match with one of the elements in supportedVideoModes array.
1399 * Encapsulates all audio capture operation configuration options.
1401 var CaptureAudioOptions = function() {
1402 // Upper limit of sound clips user can record. Value must be equal or greater than 1.
1404 // Maximum duration of a single sound clip in seconds.
1406 // The selected audio mode. Must match with one of the elements in supportedAudioModes array.
1411 * Represents a single file.
1413 * name {DOMString} name of the file, without path information
1414 * fullPath {DOMString} the full path of the file, including the name
1415 * type {DOMString} mime type
1416 * lastModifiedDate {Date} last modified date
1417 * size {Number} size of the file in bytes
1419 function MediaFile(name, fullPath, type, lastModifiedDate, size) {
1420 this.name = name || null;
1421 this.fullPath = fullPath || null;
1422 this.type = type || null;
1423 this.lastModifiedDate = lastModifiedDate || null;
1424 this.size = size || 0;
1428 * Request capture format data for a specific file and type
1430 * @param {Function} successCB
1431 * @param {Function} errorCB
1433 MediaFile.prototype.getFormatData = function(successCallback, errorCallback) {
1434 if (typeof this.fullPath === "undefined" || this.fullPath === null) {
1436 "code": CaptureError.CAPTURE_INVALID_ARGUMENT
1439 PhoneGap.exec(successCallback, errorCallback, "com.phonegap.mediacapture", "getFormatData", [this.fullPath, this.type]);
1444 * MediaFileData encapsulates format information of a media file.
1446 * @param {DOMString} codecs
1447 * @param {long} bitrate
1448 * @param {long} height
1449 * @param {long} width
1450 * @param {float} duration
1452 function MediaFileData(codecs, bitrate, height, width, duration) {
1453 this.codecs = codecs || null;
1454 this.bitrate = bitrate || 0;
1455 this.height = height || 0;
1456 this.width = width || 0;
1457 this.duration = duration || 0;
1460 PhoneGap.addConstructor(function() {
1461 if (typeof navigator.device === "undefined") {
1462 navigator.device = window.device = new Device();
1464 if (typeof navigator.device.capture === "undefined") {
1465 navigator.device.capture = window.device.capture = new Capture();
1469 if (!PhoneGap.hasResource("contact")) {
1470 PhoneGap.addResource("contact");
1474 * Contains information about a single contact.
1475 * @param {DOMString} id unique identifier
1476 * @param {DOMString} displayName
1477 * @param {ContactName} name
1478 * @param {DOMString} nickname
1479 * @param {ContactField[]} phoneNumbers array of phone numbers
1480 * @param {ContactField[]} emails array of email addresses
1481 * @param {ContactAddress[]} addresses array of addresses
1482 * @param {ContactField[]} ims instant messaging user ids
1483 * @param {ContactOrganization[]} organizations
1484 * @param {DOMString} birthday contact's birthday
1485 * @param {DOMString} note user notes about contact
1486 * @param {ContactField[]} photos
1487 * @param {Array.<ContactField>} categories
1488 * @param {ContactField[]} urls contact's web sites
1490 var Contact = function(id, displayName, name, nickname, phoneNumbers, emails, addresses,
1491 ims, organizations, birthday, note, photos, categories, urls) {
1492 this.id = id || null;
1493 this.displayName = displayName || null;
1494 this.name = name || null; // ContactName
1495 this.nickname = nickname || null;
1496 this.phoneNumbers = phoneNumbers || null; // ContactField[]
1497 this.emails = emails || null; // ContactField[]
1498 this.addresses = addresses || null; // ContactAddress[]
1499 this.ims = ims || null; // ContactField[]
1500 this.organizations = organizations || null; // ContactOrganization[]
1501 this.birthday = birthday || null; // JS Date
1502 this.note = note || null;
1503 this.photos = photos || null; // ContactField[]
1504 this.categories = categories || null;
1505 this.urls = urls || null; // ContactField[]
1509 * Converts Dates to milliseconds before sending to iOS
1511 Contact.prototype.convertDatesOut = function()
1513 var dates = new Array("birthday");
1514 for (var i=0; i<dates.length; i++){
1515 var value = this[dates[i]];
1517 if (!value instanceof Date){
1519 value = new Date(value);
1524 if (value instanceof Date){
1525 value = value.valueOf();
1527 this[dates[i]] = value;
1533 * Converts milliseconds to JS Date when returning from iOS
1535 Contact.prototype.convertDatesIn = function()
1537 var dates = new Array("birthday");
1538 for (var i=0; i<dates.length; i++){
1539 var value = this[dates[i]];
1542 this[dates[i]] = new Date(parseFloat(value));
1543 } catch (exception){
1544 console.log("exception creating date");
1550 * Removes contact from device storage.
1551 * @param successCB success callback
1552 * @param errorCB error callback (optional)
1554 Contact.prototype.remove = function(successCB, errorCB) {
1555 if (this.id == null) {
1556 var errorObj = new ContactError();
1557 errorObj.code = ContactError.UNKNOWN_ERROR;
1561 PhoneGap.exec(successCB, errorCB, "com.phonegap.contacts", "remove", [{ "contact": this}]);
1566 * displays contact via iOS UI
1567 * NOT part of W3C spec so no official documentation
1569 * @param errorCB error callback
1570 * @param options object
1571 * allowsEditing: boolean AS STRING
1572 * "true" to allow editing the contact
1573 * "false" (default) display contact
1575 Contact.prototype.display = function(errorCB, options) {
1576 if (this.id == null) {
1577 if (typeof errorCB == "function") {
1578 var errorObj = new ContactError();
1579 errorObj.code = ContactError.UNKNOWN_ERROR;
1584 PhoneGap.exec(null, errorCB, "com.phonegap.contacts","displayContact", [this.id, options]);
1589 * Creates a deep copy of this Contact.
1590 * With the contact ID set to null.
1591 * @return copy of this Contact
1593 Contact.prototype.clone = function() {
1594 var clonedContact = PhoneGap.clone(this);
1595 clonedContact.id = null;
1596 // Loop through and clear out any id's in phones, emails, etc.
1597 if (clonedContact.phoneNumbers) {
1598 for (i=0; i<clonedContact.phoneNumbers.length; i++) {
1599 clonedContact.phoneNumbers[i].id = null;
1602 if (clonedContact.emails) {
1603 for (i=0; i<clonedContact.emails.length; i++) {
1604 clonedContact.emails[i].id = null;
1607 if (clonedContact.addresses) {
1608 for (i=0; i<clonedContact.addresses.length; i++) {
1609 clonedContact.addresses[i].id = null;
1612 if (clonedContact.ims) {
1613 for (i=0; i<clonedContact.ims.length; i++) {
1614 clonedContact.ims[i].id = null;
1617 if (clonedContact.organizations) {
1618 for (i=0; i<clonedContact.organizations.length; i++) {
1619 clonedContact.organizations[i].id = null;
1622 if (clonedContact.photos) {
1623 for (i=0; i<clonedContact.photos.length; i++) {
1624 clonedContact.photos[i].id = null;
1627 if (clonedContact.urls) {
1628 for (i=0; i<clonedContact.urls.length; i++) {
1629 clonedContact.urls[i].id = null;
1632 return clonedContact;
1636 * Persists contact to device storage.
1637 * @param successCB success callback
1638 * @param errorCB error callback - optional
1640 Contact.prototype.save = function(successCB, errorCB) {
1641 // don't modify the original contact
1642 var cloned = PhoneGap.clone(this);
1643 cloned.convertDatesOut();
1644 PhoneGap.exec(successCB, errorCB, "com.phonegap.contacts","save", [{"contact": cloned}]);
1656 var ContactName = function(formatted, familyName, givenName, middle, prefix, suffix) {
1657 this.formatted = formatted != "undefined" ? formatted : null;
1658 this.familyName = familyName != "undefined" ? familyName : null;
1659 this.givenName = givenName != "undefined" ? givenName : null;
1660 this.middleName = middle != "undefined" ? middle : null;
1661 this.honorificPrefix = prefix != "undefined" ? prefix : null;
1662 this.honorificSuffix = suffix != "undefined" ? suffix : null;
1666 * Generic contact field.
1672 var ContactField = function(type, value, pref, id) {
1673 this.type = type != "undefined" ? type : null;
1674 this.value = value != "undefined" ? value : null;
1675 this.pref = pref != "undefined" ? pref : null;
1676 this.id = id != "undefined" ? id : null;
1681 * @param pref - boolean is primary / preferred address
1682 * @param type - string - work, home…..
1684 * @param streetAddress
1690 var ContactAddress = function(pref, type, formatted, streetAddress, locality, region, postalCode, country, id) {
1691 this.pref = pref != "undefined" ? pref : null;
1692 this.type = type != "undefined" ? type : null;
1693 this.formatted = formatted != "undefined" ? formatted : null;
1694 this.streetAddress = streetAddress != "undefined" ? streetAddress : null;
1695 this.locality = locality != "undefined" ? locality : null;
1696 this.region = region != "undefined" ? region : null;
1697 this.postalCode = postalCode != "undefined" ? postalCode : null;
1698 this.country = country != "undefined" ? country : null;
1699 this.id = id != "undefined" ? id : null;
1703 * Contact organization.
1704 * @param pref - boolean is primary / preferred address
1705 * @param type - string - work, home…..
1710 var ContactOrganization = function(pref, type, name, dept, title) {
1711 this.pref = pref != "undefined" ? pref : null;
1712 this.type = type != "undefined" ? type : null;
1713 this.name = name != "undefined" ? name : null;
1714 this.department = dept != "undefined" ? dept : null;
1715 this.title = title != "undefined" ? title : null;
1724 /*var ContactAccount = function(domain, username, userid) {
1725 this.domain = domain != "undefined" ? domain : null;
1726 this.username = username != "undefined" ? username : null;
1727 this.userid = userid != "undefined" ? userid : null;
1731 * Represents a group of Contacts.
1733 var Contacts = function() {
1734 this.inProgress = false;
1735 this.records = new Array();
1738 * Returns an array of Contacts matching the search criteria.
1739 * @param fields that should be searched
1740 * @param successCB success callback
1741 * @param errorCB error callback (optional)
1742 * @param {ContactFindOptions} options that can be applied to contact searching
1743 * @return array of Contacts matching search criteria
1745 Contacts.prototype.find = function(fields, successCB, errorCB, options) {
1746 if (successCB === null) {
1747 throw new TypeError("You must specify a success callback for the find command.");
1749 if (fields === null || fields === "undefined" || fields.length === "undefined" || fields.length <= 0) {
1750 if (typeof errorCB === "function") {
1751 errorCB({"code": ContactError.INVALID_ARGUMENT_ERROR});
1754 PhoneGap.exec(successCB, errorCB, "com.phonegap.contacts","search", [{"fields":fields, "findOptions":options}]);
1758 * need to turn the array of JSON strings representing contact objects into actual objects
1759 * @param array of JSON strings with contact data
1760 * @return call results callback with array of Contact objects
1761 * This function is called from objective C Contacts.search() method.
1763 Contacts.prototype._findCallback = function(pluginResult) {
1764 var contacts = new Array();
1766 for (var i=0; i<pluginResult.message.length; i++) {
1767 var newContact = navigator.contacts.create(pluginResult.message[i]);
1768 newContact.convertDatesIn();
1769 contacts.push(newContact);
1771 pluginResult.message = contacts;
1773 console.log("Error parsing contacts: " +e);
1775 return pluginResult;
1779 * need to turn the JSON string representing contact object into actual object
1780 * @param JSON string with contact data
1781 * Call stored results function with Contact object
1782 * This function is called from objective C Contacts remove and save methods
1784 Contacts.prototype._contactCallback = function(pluginResult)
1786 var newContact = null;
1787 if (pluginResult.message){
1789 newContact = navigator.contacts.create(pluginResult.message);
1790 newContact.convertDatesIn();
1792 console.log("Error parsing contact");
1795 pluginResult.message = newContact;
1796 return pluginResult;
1800 * Need to return an error object rather than just a single error code
1802 * Call optional error callback if found.
1803 * Called from objective c find, remove, and save methods on error.
1805 Contacts.prototype._errCallback = function(pluginResult)
1807 var errorObj = new ContactError();
1808 errorObj.code = pluginResult.message;
1809 pluginResult.message = errorObj;
1810 return pluginResult;
1812 // iPhone only api to create a new contact via the GUI
1813 Contacts.prototype.newContactUI = function(successCallback) {
1814 PhoneGap.exec(successCallback, null, "com.phonegap.contacts","newContact", []);
1816 // iPhone only api to select a contact via the GUI
1817 Contacts.prototype.chooseContact = function(successCallback, options) {
1818 PhoneGap.exec(successCallback, null, "com.phonegap.contacts","chooseContact", options);
1823 * This function creates a new contact, but it does not persist the contact
1824 * to device storage. To persist the contact to device storage, invoke
1826 * @param properties an object who's properties will be examined to create a new Contact
1827 * @returns new Contact object
1829 Contacts.prototype.create = function(properties) {
1831 var contact = new Contact();
1832 for (i in properties) {
1833 if (contact[i] !== 'undefined') {
1834 contact[i] = properties[i];
1841 * ContactFindOptions.
1842 * @param filter used to match contacts against
1843 * @param multiple boolean used to determine if more than one contact should be returned
1845 var ContactFindOptions = function(filter, multiple, updatedSince) {
1846 this.filter = filter || '';
1847 this.multiple = multiple || false;
1852 * An error code assigned by an implementation when an error has occurred
1854 var ContactError = function() {
1861 ContactError.UNKNOWN_ERROR = 0;
1862 ContactError.INVALID_ARGUMENT_ERROR = 1;
1863 ContactError.TIMEOUT_ERROR = 2;
1864 ContactError.PENDING_OPERATION_ERROR = 3;
1865 ContactError.IO_ERROR = 4;
1866 ContactError.NOT_SUPPORTED_ERROR = 5;
1867 ContactError.PERMISSION_DENIED_ERROR = 20;
1870 * Add the contact interface into the browser.
1872 PhoneGap.addConstructor(function() {
1873 if(typeof navigator.contacts == "undefined") {
1874 navigator.contacts = new Contacts();
1878 if (!PhoneGap.hasResource("file")) {
1879 PhoneGap.addResource("file");
1882 * This class provides generic read and write access to the mobile device file system.
1883 * They are not used to read files from a server.
1887 * This class provides some useful information about a file.
1888 * This is the fields returned when navigator.fileMgr.getFileProperties()
1891 FileProperties = function(filePath) {
1892 this.filePath = filePath;
1894 this.lastModifiedDate = null;
1897 * Represents a single file.
1899 * name {DOMString} name of the file, without path information
1900 * fullPath {DOMString} the full path of the file, including the name
1901 * type {DOMString} mime type
1902 * lastModifiedDate {Date} last modified date
1903 * size {Number} size of the file in bytes
1905 File = function(name, fullPath, type, lastModifiedDate, size) {
1906 this.name = name || null;
1907 this.fullPath = fullPath || null;
1908 this.type = type || null;
1909 this.lastModifiedDate = lastModifiedDate || null;
1910 this.size = size || 0;
1913 * Create an event object since we can't set target on DOM event.
1919 File._createEvent = function(type, target) {
1920 // Can't create event object, since we can't set target (its readonly)
1921 //var evt = document.createEvent('Events');
1922 //evt.initEvent("onload", false, false);
1923 var evt = {"type": type};
1924 evt.target = target;
1928 FileError = function() {
1933 // Found in DOMException
1934 FileError.NOT_FOUND_ERR = 1;
1935 FileError.SECURITY_ERR = 2;
1936 FileError.ABORT_ERR = 3;
1938 // Added by this specification
1939 FileError.NOT_READABLE_ERR = 4;
1940 FileError.ENCODING_ERR = 5;
1941 FileError.NO_MODIFICATION_ALLOWED_ERR = 6;
1942 FileError.INVALID_STATE_ERR = 7;
1943 FileError.SYNTAX_ERR = 8;
1944 FileError.INVALID_MODIFICATION_ERR = 9;
1945 FileError.QUOTA_EXCEEDED_ERR = 10;
1946 FileError.TYPE_MISMATCH_ERR = 11;
1947 FileError.PATH_EXISTS_ERR = 12;
1949 //-----------------------------------------------------------------------------
1951 //-----------------------------------------------------------------------------
1953 FileMgr = function() {
1956 FileMgr.prototype.testFileExists = function(fileName, successCallback, errorCallback) {
1957 PhoneGap.exec(successCallback, errorCallback, "com.phonegap.file", "testFileExists", [fileName]);
1960 FileMgr.prototype.testDirectoryExists = function(dirName, successCallback, errorCallback) {
1961 PhoneGap.exec(successCallback, errorCallback, "com.phonegap.file", "testDirectoryExists", [dirName]);
1964 FileMgr.prototype.getFreeDiskSpace = function(successCallback, errorCallback) {
1965 PhoneGap.exec(successCallback, errorCallback, "com.phonegap.file", "getFreeDiskSpace", []);
1968 FileMgr.prototype.write = function(fileName, data, position, successCallback, errorCallback) {
1969 PhoneGap.exec(successCallback, errorCallback, "com.phonegap.file", "write", [fileName, data, position]);
1972 FileMgr.prototype.truncate = function(fileName, size, successCallback, errorCallback) {
1973 PhoneGap.exec(successCallback, errorCallback, "com.phonegap.file", "truncateFile", [fileName, size]);
1976 FileMgr.prototype.readAsText = function(fileName, encoding, successCallback, errorCallback) {
1977 PhoneGap.exec(successCallback, errorCallback, "com.phonegap.file", "readFile", [fileName, encoding]);
1980 FileMgr.prototype.readAsDataURL = function(fileName, successCallback, errorCallback) {
1981 PhoneGap.exec(successCallback, errorCallback, "com.phonegap.file", "readAsDataURL", [fileName]);
1984 PhoneGap.addConstructor(function() {
1985 if (typeof navigator.fileMgr === "undefined") {
1986 navigator.fileMgr = new FileMgr();
1991 //-----------------------------------------------------------------------------
1993 //-----------------------------------------------------------------------------
1996 * This class reads the mobile device file system.
1999 FileReader = function() {
2002 this.readyState = 0;
2011 this.onloadstart = null; // When the read starts.
2012 this.onprogress = null; // While reading (and decoding) file or fileBlob data, and reporting partial file data (progess.loaded/progress.total)
2013 this.onload = null; // When the read has successfully completed.
2014 this.onerror = null; // When the read has failed (see errors).
2015 this.onloadend = null; // When the request has completed (either in success or failure).
2016 this.onabort = null; // When the read has been aborted. For instance, by invoking the abort() method.
2020 FileReader.EMPTY = 0;
2021 FileReader.LOADING = 1;
2022 FileReader.DONE = 2;
2025 * Abort reading file.
2027 FileReader.prototype.abort = function() {
2029 this.readyState = FileReader.DONE;
2033 var error = new FileError();
2034 error.code = error.ABORT_ERR;
2037 // If error callback
2038 if (typeof this.onerror === "function") {
2039 evt = File._createEvent("error", this);
2042 // If abort callback
2043 if (typeof this.onabort === "function") {
2044 evt = File._createEvent("abort", this);
2047 // If load end callback
2048 if (typeof this.onloadend === "function") {
2049 evt = File._createEvent("loadend", this);
2050 this.onloadend(evt);
2057 * @param file The name of the file
2058 * @param encoding [Optional] (see http://www.iana.org/assignments/character-sets)
2060 FileReader.prototype.readAsText = function(file, encoding) {
2062 if (typeof file.fullPath === "undefined") {
2063 this.fileName = file;
2065 this.fileName = file.fullPath;
2069 this.readyState = FileReader.LOADING;
2071 // If loadstart callback
2072 if (typeof this.onloadstart === "function") {
2073 var evt = File._createEvent("loadstart", this);
2074 this.onloadstart(evt);
2077 // Default encoding is UTF-8
2078 var enc = encoding ? encoding : "UTF-8";
2083 navigator.fileMgr.readAsText(this.fileName, enc,
2089 // If DONE (cancelled), then don't do anything
2090 if (me.readyState === FileReader.DONE) {
2095 me.result = decodeURIComponent(r);
2097 // If onload callback
2098 if (typeof me.onload === "function") {
2099 evt = File._createEvent("load", me);
2104 me.readyState = FileReader.DONE;
2106 // If onloadend callback
2107 if (typeof me.onloadend === "function") {
2108 evt = File._createEvent("loadend", me);
2116 // If DONE (cancelled), then don't do anything
2117 if (me.readyState === FileReader.DONE) {
2124 // If onerror callback
2125 if (typeof me.onerror === "function") {
2126 evt = File._createEvent("error", me);
2131 me.readyState = FileReader.DONE;
2133 // If onloadend callback
2134 if (typeof me.onloadend === "function") {
2135 evt = File._createEvent("loadend", me);
2144 * Read file and return data as a base64 encoded data url.
2145 * A data url is of the form:
2146 * data:[<mediatype>][;base64],<data>
2148 * @param file {File} File object containing file properties
2150 FileReader.prototype.readAsDataURL = function(file) {
2153 if (typeof file.fullPath === "undefined") {
2154 this.fileName = file;
2156 this.fileName = file.fullPath;
2160 this.readyState = FileReader.LOADING;
2162 // If loadstart callback
2163 if (typeof this.onloadstart === "function") {
2164 var evt = File._createEvent("loadstart", this);
2165 this.onloadstart(evt);
2171 navigator.fileMgr.readAsDataURL(this.fileName,
2177 // If DONE (cancelled), then don't do anything
2178 if (me.readyState === FileReader.DONE) {
2185 // If onload callback
2186 if (typeof me.onload === "function") {
2187 evt = File._createEvent("load", me);
2192 me.readyState = FileReader.DONE;
2194 // If onloadend callback
2195 if (typeof me.onloadend === "function") {
2196 evt = File._createEvent("loadend", me);
2204 // If DONE (cancelled), then don't do anything
2205 if (me.readyState === FileReader.DONE) {
2212 // If onerror callback
2213 if (typeof me.onerror === "function") {
2214 evt = File._createEvent("error", me);
2219 me.readyState = FileReader.DONE;
2221 // If onloadend callback
2222 if (typeof me.onloadend === "function") {
2223 evt = File._createEvent("loadend", me);
2231 * Read file and return data as a binary data.
2233 * @param file The name of the file
2235 FileReader.prototype.readAsBinaryString = function(file) {
2236 // TODO - Can't return binary data to browser.
2237 this.fileName = file;
2241 * Read file and return data as a binary data.
2243 * @param file The name of the file
2245 FileReader.prototype.readAsArrayBuffer = function(file) {
2246 // TODO - Can't return binary data to browser.
2247 this.fileName = file;
2250 //-----------------------------------------------------------------------------
2252 //-----------------------------------------------------------------------------
2255 * This class writes to the mobile device file system.
2257 @param file {File} a File object representing a file on the file system
2259 FileWriter = function(file) {
2263 this.fileName = file.fullPath || file;
2264 this.length = file.size || 0;
2267 // default is to write at the beginning of the file
2270 this.readyState = 0; // EMPTY
2278 this.onwritestart = null; // When writing starts
2279 this.onprogress = null; // While writing the file, and reporting partial file data
2280 this.onwrite = null; // When the write has successfully completed.
2281 this.onwriteend = null; // When the request has completed (either in success or failure).
2282 this.onabort = null; // When the write has been aborted. For instance, by invoking the abort() method.
2283 this.onerror = null; // When the write has failed (see errors).
2287 FileWriter.INIT = 0;
2288 FileWriter.WRITING = 1;
2289 FileWriter.DONE = 2;
2292 * Abort writing file.
2294 FileWriter.prototype.abort = function() {
2295 // check for invalid state
2296 if (this.readyState === FileWriter.DONE || this.readyState === FileWriter.INIT) {
2297 throw FileError.INVALID_STATE_ERR;
2301 var error = new FileError(), evt;
2302 error.code = error.ABORT_ERR;
2305 // If error callback
2306 if (typeof this.onerror === "function") {
2307 evt = File._createEvent("error", this);
2310 // If abort callback
2311 if (typeof this.onabort === "function") {
2312 evt = File._createEvent("abort", this);
2316 this.readyState = FileWriter.DONE;
2318 // If write end callback
2319 if (typeof this.onwriteend == "function") {
2320 evt = File._createEvent("writeend", this);
2321 this.onwriteend(evt);
2326 * @Deprecated: use write instead
2328 * @param file to write the data to
2329 * @param text to be written
2330 * @param bAppend if true write to end of file, otherwise overwrite the file
2332 FileWriter.prototype.writeAsText = function(file, text, bAppend) {
2333 // Throw an exception if we are already writing a file
2334 if (this.readyState === FileWriter.WRITING) {
2335 throw FileError.INVALID_STATE_ERR;
2338 if (bAppend !== true) {
2339 bAppend = false; // for null values
2342 this.fileName = file;
2345 this.readyState = FileWriter.WRITING;
2349 // If onwritestart callback
2350 if (typeof me.onwritestart === "function") {
2351 var evt = File._createEvent("writestart", me);
2352 me.onwritestart(evt);
2357 navigator.fileMgr.writeAsText(file, text, bAppend,
2362 // If DONE (cancelled), then don't do anything
2363 if (me.readyState === FileWriter.DONE) {
2370 // If onwrite callback
2371 if (typeof me.onwrite === "function") {
2372 evt = File._createEvent("write", me);
2377 me.readyState = FileWriter.DONE;
2379 // If onwriteend callback
2380 if (typeof me.onwriteend === "function") {
2381 evt = File._createEvent("writeend", me);
2390 // If DONE (cancelled), then don't do anything
2391 if (me.readyState === FileWriter.DONE) {
2398 // If onerror callback
2399 if (typeof me.onerror === "function") {
2400 evt = File._createEvent("error", me);
2405 me.readyState = FileWriter.DONE;
2407 // If onwriteend callback
2408 if (typeof me.onwriteend === "function") {
2409 evt = File._createEvent("writeend", me);
2417 * Writes data to the file
2419 * @param text to be written
2421 FileWriter.prototype.write = function(text) {
2422 // Throw an exception if we are already writing a file
2423 if (this.readyState === FileWriter.WRITING) {
2424 throw FileError.INVALID_STATE_ERR;
2428 this.readyState = FileWriter.WRITING;
2432 // If onwritestart callback
2433 if (typeof me.onwritestart === "function") {
2434 var evt = File._createEvent("writestart", me);
2435 me.onwritestart(evt);
2439 navigator.fileMgr.write(this.fileName, text, this.position,
2444 // If DONE (cancelled), then don't do anything
2445 if (me.readyState === FileWriter.DONE) {
2450 // position always increases by bytes written because file would be extended
2452 // The length of the file is now where we are done writing.
2453 me.length = me.position;
2455 // If onwrite callback
2456 if (typeof me.onwrite === "function") {
2457 evt = File._createEvent("write", me);
2462 me.readyState = FileWriter.DONE;
2464 // If onwriteend callback
2465 if (typeof me.onwriteend === "function") {
2466 evt = File._createEvent("writeend", me);
2475 // If DONE (cancelled), then don't do anything
2476 if (me.readyState === FileWriter.DONE) {
2483 // If onerror callback
2484 if (typeof me.onerror === "function") {
2485 evt = File._createEvent("error", me);
2490 me.readyState = FileWriter.DONE;
2492 // If onwriteend callback
2493 if (typeof me.onwriteend === "function") {
2494 evt = File._createEvent("writeend", me);
2503 * Moves the file pointer to the location specified.
2505 * If the offset is a negative number the position of the file
2506 * pointer is rewound. If the offset is greater than the file
2507 * size the position is set to the end of the file.
2509 * @param offset is the location to move the file pointer to.
2511 FileWriter.prototype.seek = function(offset) {
2512 // Throw an exception if we are already writing a file
2513 if (this.readyState === FileWriter.WRITING) {
2514 throw FileError.INVALID_STATE_ERR;
2521 // See back from end of file.
2523 this.position = Math.max(offset + this.length, 0);
2525 // Offset is bigger then file size so set position
2526 // to the end of the file.
2527 else if (offset > this.length) {
2528 this.position = this.length;
2530 // Offset is between 0 and file size so set the position
2531 // to start writing.
2533 this.position = offset;
2538 * Truncates the file to the size specified.
2540 * @param size to chop the file at.
2542 FileWriter.prototype.truncate = function(size) {
2543 // Throw an exception if we are already writing a file
2544 if (this.readyState === FileWriter.WRITING) {
2545 throw FileError.INVALID_STATE_ERR;
2547 // what if no size specified?
2550 this.readyState = FileWriter.WRITING;
2554 // If onwritestart callback
2555 if (typeof me.onwritestart === "function") {
2556 var evt = File._createEvent("writestart", me);
2557 me.onwritestart(evt);
2561 navigator.fileMgr.truncate(this.fileName, size,
2566 // If DONE (cancelled), then don't do anything
2567 if (me.readyState === FileWriter.DONE) {
2571 // Update the length of the file
2573 me.position = Math.min(me.position, r);
2575 // If onwrite callback
2576 if (typeof me.onwrite === "function") {
2577 evt = File._createEvent("write", me);
2582 me.readyState = FileWriter.DONE;
2584 // If onwriteend callback
2585 if (typeof me.onwriteend === "function") {
2586 evt = File._createEvent("writeend", me);
2594 // If DONE (cancelled), then don't do anything
2595 if (me.readyState === FileWriter.DONE) {
2602 // If onerror callback
2603 if (typeof me.onerror === "function") {
2604 evt = File._createEvent("error", me);
2609 me.readyState = FileWriter.DONE;
2611 // If onwriteend callback
2612 if (typeof me.onwriteend === "function") {
2613 evt = File._createEvent("writeend", me);
2620 LocalFileSystem = function() {
2624 LocalFileSystem.TEMPORARY = 0;
2625 LocalFileSystem.PERSISTENT = 1;
2626 LocalFileSystem.RESOURCE = 2;
2627 LocalFileSystem.APPLICATION = 3;
2630 * Requests a filesystem in which to store application data.
2632 * @param {int} type of file system being requested
2633 * @param {Function} successCallback is called with the new FileSystem
2634 * @param {Function} errorCallback is called with a FileError
2636 LocalFileSystem.prototype.requestFileSystem = function(type, size, successCallback, errorCallback) {
2637 if (type < 0 || type > 3) {
2638 if (typeof errorCallback == "function") {
2640 "code": FileError.SYNTAX_ERR
2645 PhoneGap.exec(successCallback, errorCallback, "com.phonegap.file", "requestFileSystem", [type, size]);
2651 * @param {DOMString} uri referring to a local file in a filesystem
2652 * @param {Function} successCallback is called with the new entry
2653 * @param {Function} errorCallback is called with a FileError
2655 LocalFileSystem.prototype.resolveLocalFileSystemURI = function(uri, successCallback, errorCallback) {
2656 PhoneGap.exec(successCallback, errorCallback, "com.phonegap.file", "resolveLocalFileSystemURI", [uri]);
2660 * This function is required as we need to convert raw
2661 * JSON objects into concrete File and Directory objects.
2663 * @param a JSON Objects that need to be converted to DirectoryEntry or FileEntry objects.
2666 LocalFileSystem.prototype._castFS = function(pluginResult) {
2668 entry = new DirectoryEntry();
2669 entry.isDirectory = pluginResult.message.root.isDirectory;
2670 entry.isFile = pluginResult.message.root.isFile;
2671 entry.name = pluginResult.message.root.name;
2672 entry.fullPath = pluginResult.message.root.fullPath;
2673 pluginResult.message.root = entry;
2674 return pluginResult;
2677 LocalFileSystem.prototype._castEntry = function(pluginResult) {
2679 if (pluginResult.message.isDirectory) {
2680 entry = new DirectoryEntry();
2682 else if (pluginResult.message.isFile) {
2683 entry = new FileEntry();
2685 entry.isDirectory = pluginResult.message.isDirectory;
2686 entry.isFile = pluginResult.message.isFile;
2687 entry.name = pluginResult.message.name;
2688 entry.fullPath = pluginResult.message.fullPath;
2689 pluginResult.message = entry;
2690 return pluginResult;
2693 LocalFileSystem.prototype._castEntries = function(pluginResult) {
2694 var entries = pluginResult.message;
2696 for (i=0; i<entries.length; i++) {
2697 retVal.push(window.localFileSystem._createEntry(entries[i]));
2699 pluginResult.message = retVal;
2700 return pluginResult;
2703 LocalFileSystem.prototype._createEntry = function(castMe) {
2705 if (castMe.isDirectory) {
2706 entry = new DirectoryEntry();
2708 else if (castMe.isFile) {
2709 entry = new FileEntry();
2711 entry.isDirectory = castMe.isDirectory;
2712 entry.isFile = castMe.isFile;
2713 entry.name = castMe.name;
2714 entry.fullPath = castMe.fullPath;
2719 LocalFileSystem.prototype._castDate = function(pluginResult) {
2720 if (pluginResult.message.modificationTime) {
2721 var metadataObj = new Metadata();
2723 metadataObj.modificationTime = new Date(pluginResult.message.modificationTime);
2724 pluginResult.message = metadataObj;
2726 else if (pluginResult.message.lastModifiedDate) {
2727 var file = new File();
2728 file.size = pluginResult.message.size;
2729 file.type = pluginResult.message.type;
2730 file.name = pluginResult.message.name;
2731 file.fullPath = pluginResult.message.fullPath;
2732 file.lastModifiedDate = new Date(pluginResult.message.lastModifiedDate);
2733 pluginResult.message = file;
2736 return pluginResult;
2738 LocalFileSystem.prototype._castError = function(pluginResult) {
2739 var fileError = new FileError();
2740 fileError.code = pluginResult.message;
2741 pluginResult.message = fileError;
2742 return pluginResult;
2746 * Information about the state of the file or directory
2748 * {Date} modificationTime (readonly)
2750 Metadata = function() {
2751 this.modificationTime=null;
2755 * Supplies arguments to methods that lookup or create files and directories
2757 * @param {boolean} create file or directory if it doesn't exist
2758 * @param {boolean} exclusive if true the command will fail if the file or directory exists
2760 Flags = function(create, exclusive) {
2761 this.create = create || false;
2762 this.exclusive = exclusive || false;
2766 * An interface representing a file system
2768 * {DOMString} name the unique name of the file system (readonly)
2769 * {DirectoryEntry} root directory of the file system (readonly)
2771 FileSystem = function() {
2777 * An interface representing a directory on the file system.
2779 * {boolean} isFile always false (readonly)
2780 * {boolean} isDirectory always true (readonly)
2781 * {DOMString} name of the directory, excluding the path leading to it (readonly)
2782 * {DOMString} fullPath the absolute full path to the directory (readonly)
2783 * {FileSystem} filesystem on which the directory resides (readonly)
2785 DirectoryEntry = function() {
2786 this.isFile = false;
2787 this.isDirectory = true;
2789 this.fullPath = null;
2790 this.filesystem = null;
2794 * Copies a directory to a new location
2796 * @param {DirectoryEntry} parent the directory to which to copy the entry
2797 * @param {DOMString} newName the new name of the entry, defaults to the current name
2798 * @param {Function} successCallback is called with the new entry
2799 * @param {Function} errorCallback is called with a FileError
2801 DirectoryEntry.prototype.copyTo = function(parent, newName, successCallback, errorCallback) {
2802 PhoneGap.exec(successCallback, errorCallback, "com.phonegap.file", "copyTo", [this.fullPath, parent, newName]);
2806 * Looks up the metadata of the entry
2808 * @param {Function} successCallback is called with a Metadata object
2809 * @param {Function} errorCallback is called with a FileError
2811 DirectoryEntry.prototype.getMetadata = function(successCallback, errorCallback) {
2812 PhoneGap.exec(successCallback, errorCallback, "com.phonegap.file", "getMetadata", [this.fullPath]);
2816 * Gets the parent of the entry
2818 * @param {Function} successCallback is called with a parent entry
2819 * @param {Function} errorCallback is called with a FileError
2821 DirectoryEntry.prototype.getParent = function(successCallback, errorCallback) {
2822 PhoneGap.exec(successCallback, errorCallback, "com.phonegap.file", "getParent", [this.fullPath]);
2826 * Moves a directory to a new location
2828 * @param {DirectoryEntry} parent the directory to which to move the entry
2829 * @param {DOMString} newName the new name of the entry, defaults to the current name
2830 * @param {Function} successCallback is called with the new entry
2831 * @param {Function} errorCallback is called with a FileError
2833 DirectoryEntry.prototype.moveTo = function(parent, newName, successCallback, errorCallback) {
2834 PhoneGap.exec(successCallback, errorCallback, "com.phonegap.file", "moveTo", [this.fullPath, parent, newName]);
2840 * @param {Function} successCallback is called with no parameters
2841 * @param {Function} errorCallback is called with a FileError
2843 DirectoryEntry.prototype.remove = function(successCallback, errorCallback) {
2844 PhoneGap.exec(successCallback, errorCallback, "com.phonegap.file", "remove", [this.fullPath]);
2848 * Returns a URI that can be used to identify this entry.
2850 * @param {DOMString} mimeType for a FileEntry, the mime type to be used to interpret the file, when loaded through this URI.
2851 * @param {Function} successCallback is called with the new entry
2852 * @param {Function} errorCallback is called with a FileError
2854 DirectoryEntry.prototype.toURI = function(mimeType, successCallback, errorCallback) {
2855 return "file://localhost" + this.fullPath;
2856 //PhoneGap.exec(successCallback, errorCallback, "com.phonegap.file", "toURI", [this.fullPath, mimeType]);
2860 * Creates a new DirectoryReader to read entries from this directory
2862 DirectoryEntry.prototype.createReader = function(successCallback, errorCallback) {
2863 return new DirectoryReader(this.fullPath);
2867 * Creates or looks up a directory
2869 * @param {DOMString} path either a relative or absolute path from this directory in which to look up or create a directory
2870 * @param {Flags} options to create or excluively create the directory
2871 * @param {Function} successCallback is called with the new entry
2872 * @param {Function} errorCallback is called with a FileError
2874 DirectoryEntry.prototype.getDirectory = function(path, options, successCallback, errorCallback) {
2875 PhoneGap.exec(successCallback, errorCallback, "com.phonegap.file", "getDirectory", [this.fullPath, path, options]);
2879 * Creates or looks up a file
2881 * @param {DOMString} path either a relative or absolute path from this directory in which to look up or create a file
2882 * @param {Flags} options to create or excluively create the file
2883 * @param {Function} successCallback is called with the new entry
2884 * @param {Function} errorCallback is called with a FileError
2886 DirectoryEntry.prototype.getFile = function(path, options, successCallback, errorCallback) {
2887 PhoneGap.exec(successCallback, errorCallback, "com.phonegap.file", "getFile", [this.fullPath, path, options]);
2891 * Deletes a directory and all of it's contents
2893 * @param {Function} successCallback is called with no parameters
2894 * @param {Function} errorCallback is called with a FileError
2896 DirectoryEntry.prototype.removeRecursively = function(successCallback, errorCallback) {
2897 PhoneGap.exec(successCallback, errorCallback, "com.phonegap.file", "removeRecursively", [this.fullPath]);
2901 * An interface that lists the files and directories in a directory.
2903 DirectoryReader = function(fullPath){
2904 this.fullPath = fullPath || null;
2908 * Returns a list of entries from a directory.
2910 * @param {Function} successCallback is called with a list of entries
2911 * @param {Function} errorCallback is called with a FileError
2913 DirectoryReader.prototype.readEntries = function(successCallback, errorCallback) {
2914 PhoneGap.exec(successCallback, errorCallback, "com.phonegap.file", "readEntries", [this.fullPath]);
2918 * An interface representing a directory on the file system.
2920 * {boolean} isFile always true (readonly)
2921 * {boolean} isDirectory always false (readonly)
2922 * {DOMString} name of the file, excluding the path leading to it (readonly)
2923 * {DOMString} fullPath the absolute full path to the file (readonly)
2924 * {FileSystem} filesystem on which the directory resides (readonly)
2926 FileEntry = function() {
2928 this.isDirectory = false;
2930 this.fullPath = null;
2931 this.filesystem = null;
2935 * Copies a file to a new location
2937 * @param {DirectoryEntry} parent the directory to which to copy the entry
2938 * @param {DOMString} newName the new name of the entry, defaults to the current name
2939 * @param {Function} successCallback is called with the new entry
2940 * @param {Function} errorCallback is called with a FileError
2942 FileEntry.prototype.copyTo = function(parent, newName, successCallback, errorCallback) {
2943 PhoneGap.exec(successCallback, errorCallback, "com.phonegap.file", "copyTo", [this.fullPath, parent, newName]);
2947 * Looks up the metadata of the entry
2949 * @param {Function} successCallback is called with a Metadata object
2950 * @param {Function} errorCallback is called with a FileError
2952 FileEntry.prototype.getMetadata = function(successCallback, errorCallback) {
2953 PhoneGap.exec(successCallback, errorCallback, "com.phonegap.file", "getMetadata", [this.fullPath]);
2957 * Gets the parent of the entry
2959 * @param {Function} successCallback is called with a parent entry
2960 * @param {Function} errorCallback is called with a FileError
2962 FileEntry.prototype.getParent = function(successCallback, errorCallback) {
2963 PhoneGap.exec(successCallback, errorCallback, "com.phonegap.file", "getParent", [this.fullPath]);
2967 * Moves a directory to a new location
2969 * @param {DirectoryEntry} parent the directory to which to move the entry
2970 * @param {DOMString} newName the new name of the entry, defaults to the current name
2971 * @param {Function} successCallback is called with the new entry
2972 * @param {Function} errorCallback is called with a FileError
2974 FileEntry.prototype.moveTo = function(parent, newName, successCallback, errorCallback) {
2975 PhoneGap.exec(successCallback, errorCallback, "com.phonegap.file", "moveTo", [this.fullPath, parent, newName]);
2981 * @param {Function} successCallback is called with no parameters
2982 * @param {Function} errorCallback is called with a FileError
2984 FileEntry.prototype.remove = function(successCallback, errorCallback) {
2985 PhoneGap.exec(successCallback, errorCallback, "com.phonegap.file", "remove", [this.fullPath]);
2989 * Returns a URI that can be used to identify this entry.
2991 * @param {DOMString} mimeType for a FileEntry, the mime type to be used to interpret the file, when loaded through this URI.
2992 * @param {Function} successCallback is called with the new entry
2993 * @param {Function} errorCallback is called with a FileError
2995 FileEntry.prototype.toURI = function(mimeType, successCallback, errorCallback) {
2996 return "file://localhost" + this.fullPath;
2997 //PhoneGap.exec(successCallback, errorCallback, "com.phonegap.file", "toURI", [this.fullPath, mimeType]);
3001 * Creates a new FileWriter associated with the file that this FileEntry represents.
3003 * @param {Function} successCallback is called with the new FileWriter
3004 * @param {Function} errorCallback is called with a FileError
3006 FileEntry.prototype.createWriter = function(successCallback, errorCallback) {
3007 this.file(function(filePointer) {
3008 var writer = new FileWriter(filePointer);
3009 if (writer.fileName == null || writer.fileName == "") {
3010 if (typeof errorCallback == "function") {
3012 "code": FileError.INVALID_STATE_ERR
3016 if (typeof successCallback == "function") {
3017 successCallback(writer);
3023 * Returns a File that represents the current state of the file that this FileEntry represents.
3025 * @param {Function} successCallback is called with the new File object
3026 * @param {Function} errorCallback is called with a FileError
3028 FileEntry.prototype.file = function(successCallback, errorCallback) {
3029 PhoneGap.exec(successCallback, errorCallback, "com.phonegap.file", "getFileMetadata", [this.fullPath]);
3033 * Add the FileSystem interface into the browser.
3035 PhoneGap.addConstructor(function() {
3036 var pgLocalFileSystem = new LocalFileSystem();
3037 // Needed for cast methods
3038 if(typeof window.localFileSystem == "undefined") window.localFileSystem = pgLocalFileSystem;
3039 if(typeof window.requestFileSystem == "undefined") window.requestFileSystem = pgLocalFileSystem.requestFileSystem;
3040 if(typeof window.resolveLocalFileSystemURI == "undefined") window.resolveLocalFileSystemURI = pgLocalFileSystem.resolveLocalFileSystemURI;
3048 * PhoneGap is available under *either* the terms of the modified BSD license *or* the
3049 * MIT License (2008). See http://opensource.org/licenses/alphabetical for full text.
3051 * Copyright (c) 2005-2011, Nitobi Software Inc.
3052 * Copyright (c) 2011, Matt Kane
3055 if (!PhoneGap.hasResource("filetransfer")) {
3056 PhoneGap.addResource("filetransfer");
3059 * FileTransfer uploads a file to a remote server.
3061 FileTransfer = function() {}
3066 FileUploadResult = function() {
3068 this.responseCode = null;
3069 this.response = null;
3075 FileTransferError = function(errorCode) {
3076 this.code = errorCode || null;
3079 FileTransferError.FILE_NOT_FOUND_ERR = 1;
3080 FileTransferError.INVALID_URL_ERR = 2;
3081 FileTransferError.CONNECTION_ERR = 3;
3084 * Given an absolute file path, uploads a file on the device to a remote server
3085 * using a multipart HTTP request.
3086 * @param filePath {String} Full path of the file on the device
3087 * @param server {String} URL of the server to receive the file
3088 * @param successCallback (Function} Callback to be invoked when upload has completed
3089 * @param errorCallback {Function} Callback to be invoked upon error
3090 * @param options {FileUploadOptions} Optional parameters such as file name and mimetype
3092 FileTransfer.prototype.upload = function(filePath, server, successCallback, errorCallback, options) {
3093 if(!options.params) {
3094 options.params = {};
3096 options.filePath = filePath;
3097 options.server = server;
3098 if(!options.fileKey) {
3099 options.fileKey = 'file';
3101 if(!options.fileName) {
3102 options.fileName = 'image.jpg';
3104 if(!options.mimeType) {
3105 options.mimeType = 'image/jpeg';
3108 // successCallback required
3109 if (typeof successCallback != "function") {
3110 console.log("FileTransfer Error: successCallback is not a function");
3115 // errorCallback optional
3116 if (errorCallback && (typeof errorCallback != "function")) {
3117 console.log("FileTransfer Error: errorCallback is not a function");
3121 PhoneGap.exec(successCallback, errorCallback, 'com.phonegap.filetransfer', 'upload', [options]);
3124 FileTransfer.prototype._castTransferError = function(pluginResult) {
3125 var fileError = new FileTransferError(pluginResult.message);
3126 //fileError.code = pluginResult.message;
3127 pluginResult.message = fileError;
3128 return pluginResult;
3131 FileTransfer.prototype._castUploadResult = function(pluginResult) {
3132 var result = new FileUploadResult();
3133 result.bytesSent = pluginResult.message.bytesSent;
3134 result.responseCode = pluginResult.message.responseCode;
3135 result.response = decodeURIComponent(pluginResult.message.response);
3136 pluginResult.message = result;
3137 return pluginResult;
3141 * Options to customize the HTTP request used to upload files.
3142 * @param fileKey {String} Name of file request parameter.
3143 * @param fileName {String} Filename to be used by the server. Defaults to image.jpg.
3144 * @param mimeType {String} Mimetype of the uploaded file. Defaults to image/jpeg.
3145 * @param params {Object} Object with key: value params to send to the server.
3147 FileUploadOptions = function(fileKey, fileName, mimeType, params) {
3148 this.fileKey = fileKey || null;
3149 this.fileName = fileName || null;
3150 this.mimeType = mimeType || null;
3151 this.params = params || null;
3155 PhoneGap.addConstructor(function() {
3156 if (typeof navigator.fileTransfer == "undefined") navigator.fileTransfer = new FileTransfer();
3159 if (!PhoneGap.hasResource("geolocation")) {
3160 PhoneGap.addResource("geolocation");
3163 * This class provides access to device GPS data.
3166 Geolocation = function() {
3167 // The last known GPS position.
3168 this.lastPosition = null;
3169 this.listener = null;
3170 this.timeoutTimerId = 0;
3176 * Asynchronously aquires the current position.
3177 * @param {Function} successCallback The function to call when the position
3179 * @param {Function} errorCallback The function to call when there is an error
3180 * getting the position data.
3181 * @param {PositionOptions} options The options for getting the position data
3183 * PositionOptions.forcePrompt:Bool default false,
3184 * - tells iPhone to prompt the user to turn on location services.
3185 * - may cause your app to exit while the user is sent to the Settings app
3186 * PositionOptions.distanceFilter:double aka Number
3187 * - used to represent a distance in meters.
3190 desiredAccuracy:Number
3191 - a distance in meters
3192 < 10 = best accuracy ( Default value )
3193 < 100 = Nearest Ten Meters
3194 < 1000 = Nearest Hundred Meters
3195 < 3000 = Accuracy Kilometers
3196 3000+ = Accuracy 3 Kilometers
3198 forcePrompt:Boolean default false ( iPhone Only! )
3199 - tells iPhone to prompt the user to turn on location services.
3200 - may cause your app to exit while the user is sent to the Settings app
3202 distanceFilter:Number
3203 - The minimum distance (measured in meters) a device must move laterally before an update event is generated.
3204 - measured relative to the previously delivered location
3205 - default value: null ( all movements will be reported )
3211 Geolocation.prototype.getCurrentPosition = function(successCallback, errorCallback, options)
3213 // create an always valid local success callback
3214 var win = successCallback;
3215 if (!win || typeof(win) != 'function')
3217 win = function(position) {};
3220 // create an always valid local error callback
3221 var fail = errorCallback;
3222 if (!fail || typeof(fail) != 'function')
3224 fail = function(positionError) {};
3231 // set params to our default values
3232 var params = new PositionOptions();
3236 if (options.maximumAge)
3238 // special case here if we have a cached value that is younger than maximumAge
3239 if(this.lastPosition)
3241 var now = new Date().getTime();
3242 if((now - this.lastPosition.timestamp) < options.maximumAge)
3244 win(this.lastPosition); // send cached position immediately
3245 return; // Note, execution stops here -jm
3248 params.maximumAge = options.maximumAge;
3250 if (options.enableHighAccuracy)
3252 params.enableHighAccuracy = (options.enableHighAccuracy == true); // make sure it's truthy
3254 if (options.timeout)
3256 params.timeout = options.timeout;
3260 this.listener = {"success":win,"fail":fail};
3263 var onTimeout = function()
3265 self.setError(new PositionError(PositionError.TIMEOUT,"Geolocation Error: Timeout."));
3268 clearTimeout(this.timeoutTimerId);
3269 this.timeoutTimerId = setTimeout(onTimeout, params.timeout);
3273 * Asynchronously aquires the position repeatedly at a given interval.
3274 * @param {Function} successCallback The function to call each time the position
3276 * @param {Function} errorCallback The function to call when there is an error
3277 * getting the position data.
3278 * @param {PositionOptions} options The options for getting the position data
3279 * such as timeout and the frequency of the watch.
3281 Geolocation.prototype.watchPosition = function(successCallback, errorCallback, options) {
3282 // Invoke the appropriate callback with a new Position object every time the implementation
3283 // determines that the position of the hosting device has changed.
3285 var self = this; // those == this & that
3287 var params = new PositionOptions();
3291 if (options.maximumAge) {
3292 params.maximumAge = options.maximumAge;
3294 if (options.enableHighAccuracy) {
3295 params.enableHighAccuracy = options.enableHighAccuracy;
3297 if (options.timeout) {
3298 params.timeout = options.timeout;
3303 var lastPos = that.lastPosition? that.lastPosition.clone() : null;
3305 var intervalFunction = function() {
3307 var filterFun = function(position) {
3308 if (lastPos == null || !position.equals(lastPos)) {
3309 // only call the success callback when there is a change in position, per W3C
3310 successCallback(position);
3313 // clone the new position, save it as our last position (internal var)
3314 lastPos = position.clone();
3317 that.getCurrentPosition(filterFun, errorCallback, params);
3320 // Retrieve location immediately and schedule next retrieval afterwards
3323 return setInterval(intervalFunction, params.timeout);
3328 * Clears the specified position watch.
3329 * @param {String} watchId The ID of the watch returned from #watchPosition.
3331 Geolocation.prototype.clearWatch = function(watchId) {
3332 clearInterval(watchId);
3336 * Called by the geolocation framework when the current location is found.
3337 * @param {PositionOptions} position The current position.
3339 Geolocation.prototype.setLocation = function(position)
3341 var _position = new Position(position.coords, position.timestamp);
3343 if(this.timeoutTimerId)
3345 clearTimeout(this.timeoutTimerId);
3346 this.timeoutTimerId = 0;
3349 this.lastError = null;
3350 this.lastPosition = _position;
3352 if(this.listener && typeof(this.listener.success) == 'function')
3354 this.listener.success(_position);
3357 this.listener = null;
3361 * Called by the geolocation framework when an error occurs while looking up the current position.
3362 * @param {String} message The text of the error message.
3364 Geolocation.prototype.setError = function(error)
3366 var _error = new PositionError(error.code, error.message);
3368 if(this.timeoutTimerId)
3370 clearTimeout(this.timeoutTimerId);
3371 this.timeoutTimerId = 0;
3374 this.lastError = _error;
3375 // call error handlers directly
3376 if(this.listener && typeof(this.listener.fail) == 'function')
3378 this.listener.fail(_error);
3380 this.listener = null;
3384 Geolocation.prototype.start = function(positionOptions)
3386 PhoneGap.exec(null, null, "com.phonegap.geolocation", "startLocation", [positionOptions]);
3390 Geolocation.prototype.stop = function()
3392 PhoneGap.exec(null, null, "com.phonegap.geolocation", "stopLocation", []);
3396 PhoneGap.addConstructor(function()
3398 if (typeof navigator._geo == "undefined")
3400 // replace origObj's functions ( listed in funkList ) with the same method name on proxyObj
3401 // this is a workaround to prevent UIWebView/MobileSafari default implementation of GeoLocation
3402 // because it includes the full page path as the title of the alert prompt
3403 var __proxyObj = function (origObj,proxyObj,funkList)
3405 var replaceFunk = function(org,proxy,fName)
3407 org[fName] = function()
3409 return proxy[fName].apply(proxy,arguments);
3413 for(var v in funkList) { replaceFunk(origObj,proxyObj,funkList[v]);}
3415 navigator._geo = new Geolocation();
3416 __proxyObj(navigator.geolocation, navigator._geo,
3417 ["setLocation","getCurrentPosition","watchPosition",
3418 "clearWatch","setError","start","stop"]);
3424 if (!PhoneGap.hasResource("compass")) {
3425 PhoneGap.addResource("compass");
3427 CompassError = function(){
3431 // Capture error codes
3432 CompassError.COMPASS_INTERNAL_ERR = 0;
3433 CompassError.COMPASS_NOT_SUPPORTED = 20;
3435 CompassHeading = function() {
3436 this.magneticHeading = null;
3437 this.trueHeading = null;
3438 this.headingAccuracy = null;
3439 this.timestamp = null;
3442 * This class provides access to device Compass data.
3445 Compass = function() {
3447 * List of compass watch timers
3453 * Asynchronously acquires the current heading.
3454 * @param {Function} successCallback The function to call when the heading
3456 * @param {Function} errorCallback The function to call when there is an error
3457 * getting the heading data.
3458 * @param {PositionOptions} options The options for getting the heading data (not used).
3460 Compass.prototype.getCurrentHeading = function(successCallback, errorCallback, options) {
3461 // successCallback required
3462 if (typeof successCallback !== "function") {
3463 console.log("Compass Error: successCallback is not a function");
3467 // errorCallback optional
3468 if (errorCallback && (typeof errorCallback !== "function")) {
3469 console.log("Compass Error: errorCallback is not a function");
3474 PhoneGap.exec(successCallback, errorCallback, "com.phonegap.geolocation", "getCurrentHeading", []);
3478 * Asynchronously acquires the heading repeatedly at a given interval.
3479 * @param {Function} successCallback The function to call each time the heading
3481 * @param {Function} errorCallback The function to call when there is an error
3482 * getting the heading data.
3483 * @param {HeadingOptions} options The options for getting the heading data
3484 * such as timeout and the frequency of the watch.
3486 Compass.prototype.watchHeading= function(successCallback, errorCallback, options)
3488 // Default interval (100 msec)
3489 var frequency = (options !== undefined) ? options.frequency : 100;
3491 // successCallback required
3492 if (typeof successCallback !== "function") {
3493 console.log("Compass Error: successCallback is not a function");
3497 // errorCallback optional
3498 if (errorCallback && (typeof errorCallback !== "function")) {
3499 console.log("Compass Error: errorCallback is not a function");
3503 // Start watch timer to get headings
3504 var id = PhoneGap.createUUID();
3505 navigator.compass.timers[id] = setInterval(
3507 PhoneGap.exec(successCallback, errorCallback, "com.phonegap.geolocation", "getCurrentHeading", [{repeats: 1}]);
3515 * Clears the specified heading watch.
3516 * @param {String} watchId The ID of the watch returned from #watchHeading.
3518 Compass.prototype.clearWatch = function(id)
3520 // Stop javascript timer & remove from timer list
3521 if (id && navigator.compass.timers[id]) {
3522 clearInterval(navigator.compass.timers[id]);
3523 delete navigator.compass.timers[id];
3525 if (navigator.compass.timers.length == 0) {
3527 PhoneGap.exec(null, null, "com.phonegap.geolocation", "stopHeading", []);
3532 * Asynchronously fires when the heading changes from the last reading. The amount of distance
3533 * required to trigger the event is specified in the filter paramter.
3534 * @param {Function} successCallback The function to call each time the heading
3536 * @param {Function} errorCallback The function to call when there is an error
3537 * getting the heading data.
3538 * @param {HeadingOptions} options The options for getting the heading data
3539 * @param {filter} number of degrees change to trigger a callback with heading data (float)
3541 * In iOS this function is more efficient than calling watchHeading with a frequency for updates.
3542 * Only one watchHeadingFilter can be in effect at one time. If a watchHeadingFilter is in effect, calling
3543 * getCurrentHeading or watchHeading will use the existing filter value for specifying heading change.
3545 Compass.prototype.watchHeadingFilter = function(successCallback, errorCallback, options)
3548 if (options === undefined || options.filter === undefined) {
3549 console.log("Compass Error: options.filter not specified");
3553 // successCallback required
3554 if (typeof successCallback !== "function") {
3555 console.log("Compass Error: successCallback is not a function");
3559 // errorCallback optional
3560 if (errorCallback && (typeof errorCallback !== "function")) {
3561 console.log("Compass Error: errorCallback is not a function");
3564 PhoneGap.exec(successCallback, errorCallback, "com.phonegap.geolocation", "watchHeadingFilter", [options]);
3566 Compass.prototype.clearWatchFilter = function()
3568 PhoneGap.exec(null, null, "com.phonegap.geolocation", "stopHeading", []);
3571 PhoneGap.addConstructor(function()
3573 if (typeof navigator.compass == "undefined")
3575 navigator.compass = new Compass();
3580 if (!PhoneGap.hasResource("media")) {
3581 PhoneGap.addResource("media");
3584 * PhoneGap is available under *either* the terms of the modified BSD license *or* the
3585 * MIT License (2008). See http://opensource.org/licenses/alphabetical for full text.
3587 * Copyright (c) 2005-2010, Nitobi Software Inc.
3588 * Copyright (c) 2010,2011 IBM Corporation
3592 * List of media objects.
3595 PhoneGap.mediaObjects = {};
3598 * Object that receives native callbacks.
3601 PhoneGap.Media = function() {};
3605 * Get the media object.
3608 * @param id The media object id (string)
3610 PhoneGap.Media.getMediaObject = function(id) {
3611 return PhoneGap.mediaObjects[id];
3615 * Audio has status update.
3618 * @param id The media object id (string)
3619 * @param msg The status message (int)
3620 * @param value The status code (int)
3622 PhoneGap.Media.onStatus = function(id, msg, value) {
3623 var media = PhoneGap.mediaObjects[id];
3626 if (msg == Media.MEDIA_STATE) {
3627 if (value == Media.MEDIA_STOPPED) {
3628 if (media.successCallback) {
3629 media.successCallback();
3632 if (media.statusCallback) {
3633 media.statusCallback(value);
3636 else if (msg == Media.MEDIA_DURATION) {
3637 media._duration = value;
3639 else if (msg == Media.MEDIA_ERROR) {
3640 if (media.errorCallback) {
3641 media.errorCallback(value);
3644 else if (msg == Media.MEDIA_POSITION) {
3645 media._position = value;
3650 * This class provides access to the device media, interfaces to both sound and video
3652 * @param src The file name or url to play
3653 * @param successCallback The callback to be called when the file is done playing or recording.
3654 * successCallback() - OPTIONAL
3655 * @param errorCallback The callback to be called if there is an error.
3656 * errorCallback(int errorCode) - OPTIONAL
3657 * @param statusCallback The callback to be called when media status has changed.
3658 * statusCallback(int statusCode) - OPTIONAL
3659 * @param positionCallback The callback to be called when media position has changed.
3660 * positionCallback(long position) - OPTIONAL
3662 Media = function(src, successCallback, errorCallback, statusCallback, positionCallback) {
3664 // successCallback optional
3665 if (successCallback && (typeof successCallback != "function")) {
3666 console.log("Media Error: successCallback is not a function");
3670 // errorCallback optional
3671 if (errorCallback && (typeof errorCallback != "function")) {
3672 console.log("Media Error: errorCallback is not a function");
3676 // statusCallback optional
3677 if (statusCallback && (typeof statusCallback != "function")) {
3678 console.log("Media Error: statusCallback is not a function");
3682 // positionCallback optional -- NOT SUPPORTED
3683 if (positionCallback && (typeof positionCallback != "function")) {
3684 console.log("Media Error: positionCallback is not a function");
3688 this.id = PhoneGap.createUUID();
3689 PhoneGap.mediaObjects[this.id] = this;
3691 this.successCallback = successCallback;
3692 this.errorCallback = errorCallback;
3693 this.statusCallback = statusCallback;
3694 this.positionCallback = positionCallback;
3695 this._duration = -1;
3696 this._position = -1;
3700 Media.MEDIA_STATE = 1;
3701 Media.MEDIA_DURATION = 2;
3702 Media.MEDIA_POSITION = 3;
3703 Media.MEDIA_ERROR = 9;
3706 Media.MEDIA_NONE = 0;
3707 Media.MEDIA_STARTING = 1;
3708 Media.MEDIA_RUNNING = 2;
3709 Media.MEDIA_PAUSED = 3;
3710 Media.MEDIA_STOPPED = 4;
3711 Media.MEDIA_MSG = ["None", "Starting", "Running", "Paused", "Stopped"];
3713 // TODO: Will MediaError be used?
3715 * This class contains information about any Media errors.
3719 MediaError = function() {
3725 MediaError.MEDIA_ERR_ABORTED = 1;
3726 MediaError.MEDIA_ERR_NETWORK = 2;
3727 MediaError.MEDIA_ERR_DECODE = 3;
3728 MediaError.MEDIA_ERR_NONE_SUPPORTED = 4;
3731 * Start or resume playing audio file.
3733 Media.prototype.play = function(options) {
3734 PhoneGap.exec(null, null, "com.phonegap.media", "play", [this.id, this.src, options]);
3738 * Stop playing audio file.
3740 Media.prototype.stop = function() {
3741 PhoneGap.exec(null, null, "com.phonegap.media","stop", [this.id, this.src]);
3745 * Pause playing audio file.
3747 Media.prototype.pause = function() {
3748 PhoneGap.exec(null, null, "com.phonegap.media","pause", [this.id, this.src]);
3752 * Seek or jump to a new time in the track..
3754 Media.prototype.seekTo = function(milliseconds) {
3755 PhoneGap.exec(null, null, "com.phonegap.media", "seekTo", [this.id, this.src, milliseconds]);
3759 * Get duration of an audio file.
3760 * The duration is only set for audio that is playing, paused or stopped.
3762 * @return duration or -1 if not known.
3764 Media.prototype.getDuration = function() {
3765 return this._duration;
3769 * Get position of audio.
3773 Media.prototype.getCurrentPosition = function(successCB, errorCB) {
3774 var errCallback = (errorCB == undefined || errorCB == null) ? null : errorCB;
3775 PhoneGap.exec(successCB, errorCB, "com.phonegap.media", "getCurrentPosition", [this.id, this.src]);
3778 // iOS only. prepare/load the audio in preparation for playing
3779 Media.prototype.prepare = function(successCB, errorCB) {
3780 PhoneGap.exec(successCB, errorCB, "com.phonegap.media", "prepare", [this.id, this.src]);
3784 * Start recording audio file.
3786 Media.prototype.startRecord = function() {
3787 PhoneGap.exec(null, null, "com.phonegap.media","startAudioRecord", [this.id, this.src]);
3791 * Stop recording audio file.
3793 Media.prototype.stopRecord = function() {
3794 PhoneGap.exec(null, null, "com.phonegap.media","stopAudioRecord", [this.id, this.src]);
3798 * Release the resources.
3800 Media.prototype.release = function() {
3801 PhoneGap.exec(null, null, "com.phonegap.media","release", [this.id, this.src]);
3805 if (!PhoneGap.hasResource("notification")) {
3806 PhoneGap.addResource("notification");
3809 * This class provides access to notifications on the device.
3811 Notification = function() {
3815 * Open a native alert dialog, with a customizable title and button text.
3817 * @param {String} message Message to print in the body of the alert
3818 * @param {Function} completeCallback The callback that is called when user clicks on a button.
3819 * @param {String} title Title of the alert dialog (default: Alert)
3820 * @param {String} buttonLabel Label of the close button (default: OK)
3822 Notification.prototype.alert = function(message, completeCallback, title, buttonLabel) {
3824 if (title == null || typeof title === 'undefined') {
3827 var _buttonLabel = (buttonLabel || "OK");
3828 PhoneGap.exec(completeCallback, null, "com.phonegap.notification", "alert", [message,{ "title": _title, "buttonLabel": _buttonLabel}]);
3832 * Open a native confirm dialog, with a customizable title and button text.
3833 * The result that the user selects is returned to the result callback.
3835 * @param {String} message Message to print in the body of the alert
3836 * @param {Function} resultCallback The callback that is called when user clicks on a button.
3837 * @param {String} title Title of the alert dialog (default: Confirm)
3838 * @param {String} buttonLabels Comma separated list of the labels of the buttons (default: 'OK,Cancel')
3840 Notification.prototype.confirm = function(message, resultCallback, title, buttonLabels) {
3841 var _title = (title || "Confirm");
3842 var _buttonLabels = (buttonLabels || "OK,Cancel");
3843 this.alert(message, resultCallback, _title, _buttonLabels);
3847 * Causes the device to blink a status LED.
3848 * @param {Integer} count The number of blinks.
3849 * @param {String} colour The colour of the light.
3851 Notification.prototype.blink = function(count, colour) {
3855 Notification.prototype.vibrate = function(mills) {
3856 PhoneGap.exec(null, null, "com.phonegap.notification", "vibrate", []);
3859 Notification.prototype.beep = function(count, volume) {
3860 // No Volume yet for the iphone interface
3861 // We can use a canned beep sound and call that
3862 new Media('beep.wav').play();
3865 PhoneGap.addConstructor(function() {
3866 if (typeof navigator.notification == "undefined") navigator.notification = new Notification();
3869 if (!PhoneGap.hasResource("orientation")) {
3870 PhoneGap.addResource("orientation");
3873 * This class provides access to the device orientation.
3876 Orientation = function() {
3878 * The current orientation, or null if the orientation hasn't changed yet.
3880 this.currentOrientation = null;
3884 * Set the current orientation of the phone. This is called from the device automatically.
3886 * When the orientation is changed, the DOMEvent \c orientationChanged is dispatched against
3887 * the document element. The event has the property \c orientation which can be used to retrieve
3888 * the device's current orientation, in addition to the \c Orientation.currentOrientation class property.
3890 * @param {Number} orientation The orientation to be set
3892 Orientation.prototype.setOrientation = function(orientation) {
3893 Orientation.currentOrientation = orientation;
3894 var e = document.createEvent('Events');
3895 e.initEvent('orientationChanged', 'false', 'false');
3896 e.orientation = orientation;
3897 document.dispatchEvent(e);
3901 * Asynchronously aquires the current orientation.
3902 * @param {Function} successCallback The function to call when the orientation
3904 * @param {Function} errorCallback The function to call when there is an error
3905 * getting the orientation.
3907 Orientation.prototype.getCurrentOrientation = function(successCallback, errorCallback) {
3908 // If the position is available then call success
3909 // If the position is not available then call error
3913 * Asynchronously aquires the orientation repeatedly at a given interval.
3914 * @param {Function} successCallback The function to call each time the orientation
3915 * data is available.
3916 * @param {Function} errorCallback The function to call when there is an error
3917 * getting the orientation data.
3919 Orientation.prototype.watchOrientation = function(successCallback, errorCallback) {
3920 // Invoke the appropriate callback with a new Position object every time the implementation
3921 // determines that the position of the hosting device has changed.
3922 this.getCurrentPosition(successCallback, errorCallback);
3923 return setInterval(function() {
3924 navigator.orientation.getCurrentOrientation(successCallback, errorCallback);
3929 * Clears the specified orientation watch.
3930 * @param {String} watchId The ID of the watch returned from #watchOrientation.
3932 Orientation.prototype.clearWatch = function(watchId) {
3933 clearInterval(watchId);
3936 Orientation.install = function()
3938 if (typeof navigator.orientation == "undefined") {
3939 navigator.orientation = new Orientation();
3942 var windowDispatchAvailable = !(window.dispatchEvent === undefined); // undefined in iOS 3.x
3943 if (windowDispatchAvailable) {
3947 // the code below is to capture window.add/remove eventListener calls on window
3948 // this is for iOS 3.x where listening on 'orientationchange' events don't work on document/window (don't know why)
3949 // however, window.onorientationchange DOES handle the 'orientationchange' event (sent through document), so...
3950 // then we multiplex the window.onorientationchange event (consequently - people shouldn't overwrite this)
3953 var orientationchangeEvent = 'orientationchange';
3954 var newOrientationchangeEvent = 'orientationchange_pg';
3956 // backup original `window.addEventListener`, `window.removeEventListener`
3957 var _addEventListener = window.addEventListener;
3958 var _removeEventListener = window.removeEventListener;
3960 window.onorientationchange = function() {
3961 PhoneGap.fireEvent(newOrientationchangeEvent, window);
3964 // override `window.addEventListener`
3965 window.addEventListener = function() {
3966 if (arguments[0] === orientationchangeEvent) {
3967 arguments[0] = newOrientationchangeEvent;
3970 if (!windowDispatchAvailable) {
3971 return document.addEventListener.apply(this, arguments);
3973 return _addEventListener.apply(this, arguments);
3977 // override `window.removeEventListener'
3978 window.removeEventListener = function() {
3979 if (arguments[0] === orientationchangeEvent) {
3980 arguments[0] = newOrientationchangeEvent;
3983 if (!windowDispatchAvailable) {
3984 return document.removeEventListener.apply(this, arguments);
3986 return _removeEventListener.apply(this, arguments);
3991 PhoneGap.addConstructor(Orientation.install);
3994 if (!PhoneGap.hasResource("sms")) {
3995 PhoneGap.addResource("sms");
3998 * This class provides access to the device SMS functionality.
4006 * Sends an SMS message.
4007 * @param {Integer} number The phone number to send the message to.
4008 * @param {String} message The contents of the SMS message to send.
4009 * @param {Function} successCallback The function to call when the SMS message is sent.
4010 * @param {Function} errorCallback The function to call when there is an error sending the SMS message.
4011 * @param {PositionOptions} options The options for accessing the GPS location such as timeout and accuracy.
4013 Sms.prototype.send = function(number, message, successCallback, errorCallback, options) {
4014 // not sure why this is here when it does nothing????
4017 PhoneGap.addConstructor(function() {
4018 if (typeof navigator.sms == "undefined") navigator.sms = new Sms();
4021 if (!PhoneGap.hasResource("telephony")) {
4022 PhoneGap.addResource("telephony");
4025 * This class provides access to the telephony features of the device.
4028 Telephony = function() {
4033 * Calls the specifed number.
4034 * @param {Integer} number The number to be called.
4036 Telephony.prototype.call = function(number) {
4037 // not sure why this is here when it does nothing????
4040 PhoneGap.addConstructor(function() {
4041 if (typeof navigator.telephony == "undefined") navigator.telephony = new Telephony();
4043 };if (!PhoneGap.hasResource("network")) {
4044 PhoneGap.addResource("network");
4046 // //////////////////////////////////////////////////////////////////
4048 Connection = function() {
4050 * One of the connection constants below.
4052 this.type = Connection.UNKNOWN;
4054 /* initialize from the extended DeviceInfo properties */
4056 this.type = DeviceInfo.connection.type;
4062 Connection.UNKNOWN = "unknown"; // Unknown connection type
4063 Connection.ETHERNET = "ethernet";
4064 Connection.WIFI = "wifi";
4065 Connection.CELL_2G = "2g"; // the default for iOS, for any cellular connection
4066 Connection.CELL_3G = "3g";
4067 Connection.CELL_4G = "4g";
4068 Connection.NONE = "none"; // NO connectivity
4071 PhoneGap.addConstructor(function() {
4072 if (typeof navigator.network == "undefined") navigator.network = {};
4073 if (typeof navigator.network.connection == "undefined") navigator.network.connection = new Connection();
4076 };if (!PhoneGap.hasResource("splashscreen")) {
4077 PhoneGap.addResource("splashscreen");
4080 * This class provides access to the splashscreen
4082 SplashScreen = function() {
4085 SplashScreen.prototype.show = function() {
4086 PhoneGap.exec(null, null, "com.phonegap.splashscreen", "show", []);
4089 SplashScreen.prototype.hide = function() {
4090 PhoneGap.exec(null, null, "com.phonegap.splashscreen", "hide", []);
4093 PhoneGap.addConstructor(function() {
4094 if (typeof navigator.splashscreen == "undefined") navigator.splashscreen = new SplashScreen();