plugins/org.symbian.tools.wrttools/libraries/phonegap.js
changeset 470 d4809db37847
parent 442 980aaebb8022
equal deleted inserted replaced
469:4d198a32ac7d 470:d4809db37847
       
     1 if (typeof(DeviceInfo) != 'object')
       
     2     DeviceInfo = {};
       
     3 
       
     4 /**
       
     5  * This represents the PhoneGap API itself, and provides a global namespace for accessing
       
     6  * information about the state of PhoneGap.
       
     7  * @class
       
     8  */
       
     9 PhoneGap = {
       
    10     queue: {
       
    11         ready: true,
       
    12         commands: [],
       
    13         timer: null
       
    14     },
       
    15     _constructors: []
       
    16 };
       
    17 
       
    18 /**
       
    19  * Boolean flag indicating if the PhoneGap API is available and initialized.
       
    20  */
       
    21 PhoneGap.available = DeviceInfo.uuid != undefined;
       
    22 
       
    23 /**
       
    24  * Execute a PhoneGap command in a queued fashion, to ensure commands do not
       
    25  * execute with any race conditions, and only run when PhoneGap is ready to
       
    26  * recieve them.
       
    27  * @param {String} command Command to be run in PhoneGap, e.g. "ClassName.method"
       
    28  * @param {String[]} [args] Zero or more arguments to pass to the method
       
    29  */
       
    30 PhoneGap.exec = function() {
       
    31     PhoneGap.queue.commands.push(arguments);
       
    32     if (PhoneGap.queue.timer == null)
       
    33         PhoneGap.queue.timer = setInterval(PhoneGap.run_command, 10);
       
    34 };
       
    35 /**
       
    36  * Internal function used to dispatch the request to PhoneGap.  This needs to be implemented per-platform to
       
    37  * ensure that methods are called on the phone in a way appropriate for that device.
       
    38  * @private
       
    39  */
       
    40 PhoneGap.run_command = function() {
       
    41 };
       
    42 
       
    43 /**
       
    44  * This class contains acceleration information
       
    45  * @constructor
       
    46  * @param {Number} x The force applied by the device in the x-axis.
       
    47  * @param {Number} y The force applied by the device in the y-axis.
       
    48  * @param {Number} z The force applied by the device in the z-axis.
       
    49  */
       
    50 function Acceleration(x, y, z) {
       
    51 	/**
       
    52 	 * The force applied by the device in the x-axis.
       
    53 	 */
       
    54 	this.x = x;
       
    55 	/**
       
    56 	 * The force applied by the device in the y-axis.
       
    57 	 */
       
    58 	this.y = y;
       
    59 	/**
       
    60 	 * The force applied by the device in the z-axis.
       
    61 	 */
       
    62 	this.z = z;
       
    63 	/**
       
    64 	 * The time that the acceleration was obtained.
       
    65 	 */
       
    66 	this.timestamp = new Date().getTime();
       
    67 }
       
    68 
       
    69 /**
       
    70  * This class specifies the options for requesting acceleration data.
       
    71  * @constructor
       
    72  */
       
    73 function AccelerationOptions() {
       
    74 	/**
       
    75 	 * The timeout after which if acceleration data cannot be obtained the errorCallback
       
    76 	 * is called.
       
    77 	 */
       
    78 	this.timeout = 10000;
       
    79 }
       
    80 /**
       
    81  * This class provides access to device accelerometer data.
       
    82  * @constructor
       
    83  */
       
    84 function Accelerometer() {
       
    85 	/**
       
    86 	 * The last known acceleration.
       
    87 	 */
       
    88 	this.lastAcceleration = null;
       
    89 }
       
    90 
       
    91 /**
       
    92  * Asynchronously aquires the current acceleration.
       
    93  * @param {Function} successCallback The function to call when the acceleration
       
    94  * data is available
       
    95  * @param {Function} errorCallback The function to call when there is an error 
       
    96  * getting the acceleration data.
       
    97  * @param {AccelerationOptions} options The options for getting the accelerometer data
       
    98  * such as timeout.
       
    99  */
       
   100 
       
   101 Accelerometer.prototype.getCurrentAcceleration = function(successCallback, errorCallback, options) {
       
   102 	// If the acceleration is available then call success
       
   103 	// If the acceleration is not available then call error
       
   104 	
       
   105 	try {
       
   106 		if (!this.serviceObj) 
       
   107 			this.serviceObj = this.getServiceObj();
       
   108 		
       
   109 		if (this.serviceObj == null) 
       
   110 			throw {
       
   111 				name: "DeviceErr",
       
   112 				message: "Could not initialize service object"
       
   113 			};
       
   114 		
       
   115 		//get the sensor channel
       
   116 		var SensorParams = {
       
   117 			SearchCriterion: "AccelerometerAxis"
       
   118 		};
       
   119 		var returnvalue = this.serviceObj.ISensor.FindSensorChannel(SensorParams);
       
   120 		var error = returnvalue["ErrorCode"];
       
   121 		var errmsg = returnvalue["ErrorMessage"];
       
   122 		if (!(error == 0 || error == 1012)) {
       
   123 			var ex = {
       
   124 				name: "Unable to find Sensor Channel: " + error,
       
   125 				message: errmsg
       
   126 			};
       
   127 			throw ex;
       
   128 		}
       
   129 		var channelInfoMap = returnvalue["ReturnValue"][0];
       
   130 		var criteria = {
       
   131 			ChannelInfoMap: channelInfoMap,
       
   132 			ListeningType: "ChannelData"
       
   133 		};
       
   134 		
       
   135 		if (typeof(successCallback) != 'function') 
       
   136 			successCallback = function(){
       
   137 			};
       
   138 		if (typeof(errorCallback) != 'function') 
       
   139 			errorCallback = function(){
       
   140 			};
       
   141 		
       
   142 		this.success_callback = successCallback;
       
   143 		this.error_callback = errorCallback;
       
   144 		//create a closure to persist this instance of Accelerometer into the RegisterForNofication callback
       
   145 		var obj = this;
       
   146 		
       
   147 		// TODO: this call crashes WRT, but there is no other way to read the accel sensor
       
   148 		// http://discussion.forum.nokia.com/forum/showthread.php?t=182151&highlight=memory+leak
       
   149 		this.serviceObj.ISensor.RegisterForNotification(criteria, function(transId, eventCode, result){
       
   150 			try {
       
   151 				var criteria = {
       
   152 					TransactionID: transId
       
   153 				};
       
   154 				obj.serviceObj.ISensor.Cancel(criteria);
       
   155 				
       
   156 				var accel = new Acceleration(result.ReturnValue.XAxisData, result.ReturnValue.YAxisData, result.ReturnValue.ZAxisData);
       
   157 				Accelerometer.lastAcceleration = accel;
       
   158 				
       
   159 				obj.success_callback(accel);
       
   160 				
       
   161 			} 
       
   162 			catch (ex) {
       
   163 				obj.serviceObj.ISensor.Cancel(criteria);
       
   164 				obj.error_callback(ex);
       
   165 			}
       
   166 			
       
   167 		});
       
   168 	} catch (ex) {
       
   169 		errorCallback(ex);
       
   170 	}
       
   171 
       
   172 };
       
   173 
       
   174 
       
   175 /**
       
   176  * Asynchronously aquires the acceleration repeatedly at a given interval.
       
   177  * @param {Function} successCallback The function to call each time the acceleration
       
   178  * data is available
       
   179  * @param {Function} errorCallback The function to call when there is an error 
       
   180  * getting the acceleration data.
       
   181  * @param {AccelerationOptions} options The options for getting the accelerometer data
       
   182  * such as timeout.
       
   183  */
       
   184 
       
   185 Accelerometer.prototype.watchAcceleration = function(successCallback, errorCallback, options) {
       
   186 	this.getCurrentAcceleration(successCallback, errorCallback, options);
       
   187 	// TODO: add the interval id to a list so we can clear all watches
       
   188  	var frequency = (options != undefined)? options.frequency : 10000;
       
   189 	return setInterval(function() {
       
   190 		navigator.accelerometer.getCurrentAcceleration(successCallback, errorCallback, options);
       
   191 	}, frequency);
       
   192 };
       
   193 
       
   194 /**
       
   195  * Clears the specified accelerometer watch.
       
   196  * @param {String} watchId The ID of the watch returned from #watchAcceleration.
       
   197  */
       
   198 Accelerometer.prototype.clearWatch = function(watchId) {
       
   199 	clearInterval(watchId);
       
   200 };
       
   201 
       
   202 //gets the Acceleration Service Object from WRT
       
   203 Accelerometer.prototype.getServiceObj = function() {
       
   204 	var so;
       
   205 	
       
   206     try {
       
   207         so = device.getServiceObject("Service.Sensor", "ISensor");
       
   208     } catch (ex) {
       
   209 		throw {
       
   210 			name: "DeviceError",
       
   211 			message: "Could not initialize accel service object (" + ex.name + ": " + ex.message + ")"
       
   212 		};
       
   213     }		
       
   214 	return so;
       
   215 };
       
   216 
       
   217 if (typeof navigator.accelerometer == "undefined") navigator.accelerometer = new Accelerometer();/**
       
   218  * This class provides access to the device media, interfaces to both sound and video
       
   219  * @constructor
       
   220  */
       
   221 function Audio(src, successCallback, errorCallback) {
       
   222 	this.src = src;
       
   223 	this.successCallback = successCallback;
       
   224 	this.errorCallback = errorCallback;												
       
   225 }
       
   226 
       
   227 Audio.prototype.record = function() {
       
   228 };
       
   229 
       
   230 Audio.prototype.play = function() {
       
   231 try {
       
   232 	if (document.getElementById('gapsound'))
       
   233 		document.body.removeChild(document.getElementById('gapsound'));
       
   234 	var obj;
       
   235 	obj = document.createElement("embed");
       
   236 	obj.setAttribute("id", "gapsound");
       
   237 	obj.setAttribute("type", "audio/x-mpeg");
       
   238 	obj.setAttribute("width", "0");
       
   239 	obj.setAttribute("width", "0");
       
   240 	obj.setAttribute("hidden", "true");
       
   241 	obj.setAttribute("autostart", "true");
       
   242 	obj.setAttribute("src", this.src);
       
   243 	document.body.appendChild(obj);
       
   244 } catch (ex) { debug.log(ex.name + ": " + ex.message); }
       
   245 };
       
   246 
       
   247 Audio.prototype.pause = function() {
       
   248 };
       
   249 
       
   250 Audio.prototype.stop = function() {
       
   251 	document.body.removeChild(document.getElementById('gapsound'));
       
   252 };
       
   253 /**
       
   254  * This class provides access to the device camera.
       
   255  * @constructor
       
   256  */
       
   257 function Camera() {
       
   258 	this.success_callback = null;
       
   259 	this.error_callback = null;
       
   260 }
       
   261 
       
   262 /**
       
   263  * We use the Platform Services 2.0 API here. So we must include a portion of the
       
   264  * PS 2.0 source code (camera API). 
       
   265  * @param {Function} successCallback
       
   266  * @param {Function} errorCallback
       
   267  * @param {Object} options
       
   268  */
       
   269 Camera.prototype.getPicture = function(successCallback, errorCallback, options){
       
   270 	try {
       
   271 		if (!this.serviceObj) {
       
   272 			this.serviceObj = com.nokia.device.load("", "com.nokia.device.camera", "");
       
   273 		}
       
   274 		if (!this.serviceObj) {
       
   275 			throw {
       
   276 				name: "CameraError",
       
   277 				message: "could not load camera service"
       
   278 			};
       
   279 		}
       
   280 		var obj = this;
       
   281 		
       
   282 		obj.success_callback = successCallback;
       
   283 		obj.error_callback = errorCallback;
       
   284 		this.serviceObj.startCamera( function(transactionID, errorCode, outPut) { 
       
   285 			//outPut should be an array of image urls (local), or an error code
       
   286 			if (errorCode == 0) {
       
   287 				obj.success_callback(outPut);
       
   288 			}
       
   289 			else {
       
   290 				obj.error_callback({
       
   291 					name: "CameraError",
       
   292 					message: errorCode
       
   293 				});
       
   294 			}
       
   295 		});
       
   296 		
       
   297 	} catch (ex) {
       
   298 		errorCallback.call(ex);
       
   299 	}
       
   300 	
       
   301 };
       
   302 
       
   303 if (typeof navigator.camera == "undefined") navigator.camera = new Camera();/*
       
   304 Copyright © 2009 Nokia. All rights reserved.
       
   305 Code licensed under the BSD License:
       
   306 Software License Agreement (BSD License) Copyright © 2009 Nokia.
       
   307 All rights reserved.
       
   308 Redistribution and use of this software in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
       
   309 
       
   310 Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 
       
   311 Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 
       
   312 Neither the name of Nokia Corporation. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission of Nokia Corporation. 
       
   313 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
       
   314 
       
   315 version: 1.0
       
   316 */
       
   317 
       
   318 
       
   319 // utility.js
       
   320 //
       
   321 // This file contains some utility functions for S60 providers
       
   322 
       
   323 
       
   324 // Start an application and wait for it to exit
       
   325 
       
   326 //TBD: Get rid of this global, use closures instead
       
   327 
       
   328 DeviceError.prototype = new Error(); //inheritance occurs here
       
   329 DeviceError.prototype.constructor = DeviceError; //If this not present then, it uses default constructor of Error
       
   330 
       
   331 //constructor for DeviceError.
       
   332 function DeviceError(message,code) 
       
   333 {
       
   334 	this.toString = concatenate;
       
   335 	this.code = code;
       
   336 	this.name = "DeviceException";//we can even overwrite default name "Error"
       
   337 	this.message=message; 
       
   338 }
       
   339 
       
   340 function concatenate()
       
   341 {
       
   342 	return (this.name+":"+" "+this.message+" "+this.code);
       
   343 }
       
   344 
       
   345 function splitErrorMessage(errmessage)
       
   346 {
       
   347 	if(errmessage.search(/:/)!=-1)
       
   348 	{
       
   349 		if((errmessage.split(":").length)==2)
       
   350 		{
       
   351 			return errmessage.split(":")[1];
       
   352 		}
       
   353 		if((errmessage.split(":").length)>2)
       
   354 		{
       
   355 			return errmessage.split(":")[2];
       
   356 		}
       
   357 	}
       
   358 	return errmessage;
       
   359 }
       
   360 
       
   361 
       
   362 var __s60_start_and_wait_cb;
       
   363 
       
   364 function __s60_on_app_exit(){
       
   365   widget.onshow = null;
       
   366   if(__s60_start_and_wait_cb != null){
       
   367     __s60_start_and_wait_cb();
       
   368   }
       
   369 }
       
   370 
       
   371 function __s60_on_app_start(){
       
   372   widget.onhide = null;
       
   373   widget.onshow = __s60_on_app_exit;
       
   374 }
       
   375 
       
   376 // This function cannot actually force JS to wait,
       
   377 // but it does supply a callback the apps can use
       
   378 // to continue processing on return from the app.
       
   379 // Apps should take care not to reinvoke this and
       
   380 // should be careful about any other processing
       
   381 // that might happen while the app is running.
       
   382 
       
   383 function __s60_start_and_wait(id, args, app_exit_cb){
       
   384   __s60_start_and_wait_cb = app_exit_cb;
       
   385   widget.onhide = __s60_on_app_start;
       
   386   widget.openApplication(id, args);
       
   387 }
       
   388 
       
   389 function __s60_api_not_supported(){
       
   390   throw(err_ServiceNotSupported);
       
   391 }
       
   392 
       
   393 function __s60_enumerate_object(object, namespace, func, param){
       
   394     var key;
       
   395     for(key in object){
       
   396        
       
   397         var propname;
       
   398        	if(namespace){
       
   399 	    propname = namespace + "." + key;
       
   400 	}
       
   401 	else{
       
   402 	    propname = key;
       
   403 	}
       
   404         var value = object[key];
       
   405         if(typeof value == "object"){
       
   406 	  __s60_enumerate_object(value, propname, func, param);
       
   407 	}
       
   408 	else {
       
   409 	  func(propname,value, param);
       
   410 	}
       
   411     }
       
   412 }
       
   413 /*
       
   414 Copyright © 2009 Nokia. All rights reserved.
       
   415 Code licensed under the BSD License:
       
   416 Software License Agreement (BSD License) Copyright © 2009 Nokia.
       
   417 All rights reserved.
       
   418 Redistribution and use of this software in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
       
   419 
       
   420 Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 
       
   421 Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 
       
   422 Neither the name of Nokia Corporation. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission of Nokia Corporation. 
       
   423 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
       
   424 
       
   425 version: 1.0
       
   426 */
       
   427 
       
   428 
       
   429 var __device_debug_on__ = true;
       
   430 var err_missing_argument = 1003;
       
   431 var event_cancelled = 3;
       
   432 var err_bad_argument = 1002;
       
   433 var err_InvalidService_Argument = 1000;
       
   434 var err_ServiceNotReady = 1006;
       
   435 var err_ServiceNotSupported = 1004;
       
   436 
       
   437 function __device_debug(text){
       
   438   //if(__device_debug_on__) alert(text);
       
   439 }
       
   440 
       
   441 function __device_handle_exception(e, text){
       
   442 	__device_debug(text);
       
   443 	throw(e);
       
   444 }
       
   445 
       
   446 function __device_typeof(value)
       
   447 {
       
   448 	// First check to see if the value is undefined.
       
   449 	if (value == undefined) {
       
   450         return "undefined";
       
   451     }
       
   452 	// Check for objects created with the "new" keyword.
       
   453 	if (value instanceof Object) {
       
   454 		// Check whether it's a string object.
       
   455 		if (value instanceof String) {
       
   456 			return "String";
       
   457 		}
       
   458 		// Check whether it's an array object/array literal.
       
   459 		else 
       
   460 			if (value instanceof Array) {
       
   461 				return "Array";
       
   462 			}
       
   463 	}
       
   464 	// dealing with a literal.
       
   465 		if (typeof value) {
       
   466 			if (typeof value == "object") {
       
   467 				if (typeof value == "object" && !value) {
       
   468 					return "null";
       
   469 				}
       
   470 			}
       
   471            // if not null check for other types
       
   472 			
       
   473 				// Check if it's a string literal.
       
   474 			else if (typeof value == "string") {
       
   475 					return "string";
       
   476 				}
       
   477 		}	 
       
   478 }
       
   479 
       
   480 
       
   481 // The top-level service object. It would be nice to use a namespace here 
       
   482 // (com.nokia.device.service), but emulating namespaces still allows name clashes.
       
   483 /*
       
   484 var sp_device = {
       
   485         //services: null; // TBD: Make the services list a member of this object?
       
   486 	load: __device_service_load,
       
   487         listServices: __device_service_list,
       
   488         listInterfaces: __device_service_interfaces,
       
   489         version: "0.1",
       
   490         info: "device prototype"
       
   491 };
       
   492 */
       
   493 
       
   494 if(undefined == com)
       
   495     var com={};
       
   496 
       
   497 if( typeof com != "object")
       
   498     throw("com defined as non object");
       
   499 
       
   500 if(undefined == com.nokia)
       
   501     com.nokia = {};
       
   502 
       
   503 if( typeof com.nokia != "object")
       
   504     throw("com.nokia defined as non object");
       
   505 
       
   506 if(undefined == com.nokia.device)
       
   507     com.nokia.device = {
       
   508         load: __device_service_load,
       
   509         listServices: __device_service_list,
       
   510         listInterfaces: __device_service_interfaces,
       
   511         version: "0.1",
       
   512         info: "device prototype"
       
   513         };
       
   514 else
       
   515     throw("com.nokia.device already defined");
       
   516 
       
   517 com.nokia.device.SORT_ASCENDING = 0;
       
   518 com.nokia.device.SORT_DESCENDING = 1;
       
   519 
       
   520 com.nokia.device.SORT_BY_DATE = 0;
       
   521 com.nokia.device.SORT_BY_SENDER = 1;
       
   522 
       
   523 com.nokia.device.STATUS_READ = 0;
       
   524 com.nokia.device.STATUS_UNREAD = 1;
       
   525 
       
   526 
       
   527 // Configure the services offered.
       
   528 
       
   529 var __device_services_inited = false;
       
   530 
       
   531 var __device_services = [
       
   532 
       
   533   // For now, the only service is the base "device"" service
       
   534   {
       
   535     "name":"com.nokia.device",
       
   536     "version": 0.1, 
       
   537     "interfaces": []
       
   538   }
       
   539 ];
       
   540 
       
   541 // Initialize the configured services.
       
   542 
       
   543 function __device_services_init(){
       
   544   if(__device_services_inited){
       
   545     return;
       
   546   }
       
   547   __device_services_inited = true;
       
   548 
       
   549   // Get the service-specific service entries. Note that these
       
   550   // need to be individually wrapped by try/catch blocks so that the
       
   551   // interpreter gracefully handles missing services. 
       
   552 
       
   553   try {
       
   554     __device_services[0].interfaces.push(__device_geolocation_service_entry);
       
   555   }catch (e){
       
   556     __device_debug("Missing library implementation: " + e);
       
   557   }
       
   558   try {
       
   559     __device_services[0].interfaces.push(__device_camera_service_entry);
       
   560   }catch (e){
       
   561     __device_debug("Missing library implementation: " + e);
       
   562   }
       
   563   try {
       
   564     __device_services[0].interfaces.push(__device_media_service_entry);
       
   565   }catch (e){
       
   566 //    __device_debug("Missing library implementation: " + e);
       
   567   }
       
   568   try {
       
   569     __device_services[0].interfaces.push(__device_contacts_service_entry);
       
   570   }catch (e){
       
   571 //    __device_debug("Missing library implementation: " + e);
       
   572   }
       
   573  try {
       
   574     __device_services[0].interfaces.push(__device_messaging_service_entry);
       
   575   }catch (e){
       
   576       __device_debug("Missing library implementation: " + e);
       
   577   }
       
   578   try {
       
   579     __device_services[0].interfaces.push(__device_calendar_service_entry);
       
   580   }catch (e){
       
   581       __device_debug("Missing library implementation: " + e);
       
   582   }
       
   583   try {
       
   584     __device_services[0].interfaces.push(__device_landmarks_service_entry);
       
   585   }catch (e){
       
   586       __device_debug("Missing library implementation: " + e);
       
   587   }
       
   588   try {
       
   589     __device_services[0].interfaces.push(__device_event_service_entry);
       
   590   }catch (e){
       
   591       __device_debug("Missing library implementation: " + e);
       
   592   }
       
   593   try {
       
   594     __device_services[0].interfaces.push(__device_sysinfo_service_entry);
       
   595   }catch (e){
       
   596       __device_debug("Missing library implementation: " + e);
       
   597   }
       
   598   try {
       
   599     __device_services[0].interfaces.push(__device_sensors_service_entry);
       
   600   }catch (e){
       
   601       __device_debug("Missing library implementation: " + e);
       
   602   }
       
   603 
       
   604 }
       
   605 
       
   606 function __device_get_implementation(i){
       
   607   //__device_debug("get_implementation: " + i);
       
   608   return  new i.proto(new(i.providers[0].instance));
       
   609 }
       
   610 
       
   611 function __device_get_descriptor(i){
       
   612   //__device_debug("get_descriptor: " + i);
       
   613   return new i.descriptor(new(i.providers[0].descriptor));
       
   614 }
       
   615 
       
   616 function __device_get_interface(s, interfaceName, version){
       
   617   //__device_debug("get_interface: " + s + " " + interfaceName);
       
   618   var i = s.interfaces;
       
   619   if((interfaceName == null) || (interfaceName == '')){
       
   620     // Interface name not specified, get first interface, ignoring version
       
   621     return __device_get_implementation(i[0]);
       
   622   }
       
   623 
       
   624   // Find first match of name and version
       
   625   for (var d in i){
       
   626   
       
   627     if(i[d].name == null){
       
   628       __device_update_descriptor(i[d]);
       
   629     }
       
   630     if(i[d].name == undefined){
       
   631       continue;
       
   632     }
       
   633     if (i[d].name == interfaceName){
       
   634       // Match version if specified
       
   635       if ((version == null) || (version == '') || (i[d].version >= version)){
       
   636 	return __device_get_implementation(i[d]);
       
   637       }
       
   638     }
       
   639   }
       
   640   return null;
       
   641 }
       
   642 
       
   643 // Implemention of the load method
       
   644 
       
   645 function __device_service_load(serviceName, interfaceName, version){
       
   646 
       
   647   __device_services_init();
       
   648   
       
   649   // Service name is specified
       
   650    if ((serviceName != null) && (serviceName != '') &&(serviceName != "*")){
       
   651     for(var s in __device_services){
       
   652       if (serviceName == __device_services[s].name){
       
   653 	return __device_get_interface(__device_services[s], interfaceName, version);
       
   654       }
       
   655     }
       
   656   // Service name not specified, get first implementation 
       
   657   } else {
       
   658     //__device_debug("Trying to get interface implementations: ");
       
   659     for(var s in __device_services){
       
   660       //__device_debug("service_load: " + s + ":" +  __device_services[s].name + ": " + interfaceName);
       
   661       var i = __device_get_interface(__device_services[s], interfaceName, version);
       
   662       if (i != null){
       
   663 	return i;
       
   664       }
       
   665     }
       
   666   }
       
   667   return null;
       
   668 }
       
   669 
       
   670 // Lazily fill in the descriptor table
       
   671 
       
   672 function __device_update_descriptor(i){
       
   673   var d = __device_get_descriptor(i);
       
   674   i.name = d.interfaceName;
       
   675   i.version = d.version;  
       
   676 }
       
   677 // Get an array of interface descriptors for a service
       
   678 
       
   679 function __device_interface_list(s){
       
   680   var retval = new Array();
       
   681   for(var i in s.interfaces){
       
   682     if(s.interfaces[i].name == null){
       
   683       __device_update_descriptor(s.interfaces[i]);
       
   684     }
       
   685     if(s.interfaces[i].name == undefined){
       
   686       continue;
       
   687     }
       
   688     retval[i] = new Object();
       
   689     retval[i].name = s.interfaces[i].name;
       
   690     retval[i].version = s.interfaces[i].version;
       
   691   }  
       
   692   return retval;
       
   693 }
       
   694 
       
   695 // Get a service description
       
   696 
       
   697 function __device_service_descriptor(s){
       
   698   this.name = s.name;
       
   699   this.version = s.version;
       
   700   this.interfaces = __device_interface_list(s);
       
   701   this.toString = __device_service_descriptor_to_string;
       
   702 }
       
   703 
       
   704 function __device_service_descriptor_to_string(){
       
   705   var is = "\nInterfaces(s): ";
       
   706 
       
   707   for (i in this.interfaces){
       
   708     is += "\n" + this.interfaces[i].name + " " + this.interfaces[0].version;
       
   709   }
       
   710   return ("Service: " + this.name + is);
       
   711 }
       
   712 
       
   713 // Implement the listServices method 
       
   714 
       
   715 function __device_service_list(serviceName, interfaceName, version){
       
   716   //__device_debug("__device_service_list: " + serviceName + " " + interfaceName);
       
   717   __device_services_init();
       
   718   var retval = new Array();
       
   719   var n = 0;
       
   720   
       
   721   //Treat empty service and interface names as wildcards
       
   722   if ((serviceName == null)|| (serviceName == '')/* || (serviceName == undefined)*/){
       
   723     serviceName = ".*"; 
       
   724   }
       
   725   if ((interfaceName == null) || (interfaceName == '') /*|| (serviceName == undefined)*/){
       
   726     interfaceName = ".*";
       
   727   }
       
   728  
       
   729   if ((typeof serviceName != "string") || (typeof interfaceName != "string")) {
       
   730   	return retval;
       
   731   }
       
   732   
       
   733   // This method does regular expression matching of service and interface
       
   734 
       
   735   var sregx = new RegExp(serviceName);
       
   736   var iregx = new RegExp(interfaceName);
       
   737  
       
   738   for(var s in __device_services){
       
   739    //__device_debug (serviceName + "==" + __device_services[s].name + "?:" + sregx.test(__device_services[s].name));
       
   740     if (sregx.test(__device_services[s].name)){
       
   741       // Find the first matching interface 
       
   742         
       
   743       for(var i in __device_services[s].interfaces){
       
   744         if(__device_services[s].interfaces[i].name == null){
       
   745           __device_update_descriptor(__device_services[s].interfaces[i]);
       
   746 	}
       
   747         if(__device_services[s].interfaces[i].name == undefined){
       
   748 	  continue;
       
   749 	}
       
   750 	//__device_debug (interfaceName + "==" + __device_services[s].interfaces[i].name + "?:" + iregx.test(__device_services[s].interfaces[i].name));
       
   751 	if (iregx.test(__device_services[s].interfaces[i].name)){
       
   752 	  if ((version == null) || (version == '') || (__device_services[s].interfaces[i].version >= version)){
       
   753             // An interface matched, we're done.
       
   754             retval[n] = new __device_service_descriptor(__device_services[s]);
       
   755             break; 
       
   756 	  }
       
   757 	}
       
   758       }
       
   759     }
       
   760     ++n;
       
   761   }
       
   762   return retval;
       
   763 }
       
   764 
       
   765 // Implement the listInterfaces method
       
   766     
       
   767 function __device_service_interfaces(serviceName){
       
   768   __device_services_init();
       
   769   if(serviceName==null||serviceName==undefined||serviceName==''){
       
   770   	throw new DeviceError("Framework: listInterfaces: serviceName is missing", err_missing_argument);
       
   771   }
       
   772   for (var s in __device_services){
       
   773     if(__device_services[s].name == serviceName){
       
   774       return __device_interface_list(__device_services[s]);
       
   775     }
       
   776   }
       
   777   return null;
       
   778 }
       
   779 
       
   780 function modifyObjectBaseProp(obj){
       
   781   for (pro in obj) {
       
   782     if(typeof obj[pro] == "function" )
       
   783       obj[pro] = 0;
       
   784     }
       
   785 };
       
   786 /*
       
   787 Copyright © 2009 Nokia. All rights reserved.
       
   788 Code licensed under the BSD License:
       
   789 Software License Agreement (BSD License) Copyright © 2009 Nokia.
       
   790 All rights reserved.
       
   791 Redistribution and use of this software in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
       
   792 
       
   793 Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 
       
   794 Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 
       
   795 Neither the name of Nokia Corporation. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission of Nokia Corporation. 
       
   796 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
       
   797 
       
   798 version: 1.0
       
   799 */
       
   800 
       
   801 
       
   802 // S60 sp-based camera provider
       
   803 
       
   804 function __sp_camera_descriptor(){
       
   805   //__device_debug("sp_camera_descriptor");
       
   806   //Read-only properties
       
   807   this.interfaceName = "com.nokia.device.camera";
       
   808   this.version = "0.1";
       
   809   //Class-static properties 
       
   810 }
       
   811 
       
   812 // TBD make local to closure funcs
       
   813 var __sp_camera_start_date;
       
   814 
       
   815 function __sp_camera_instance(){
       
   816   //__device_debug("sp_camera_instance");
       
   817   //Descriptor
       
   818   this.descriptor = new __sp_camera_descriptor();
       
   819   //Core methods
       
   820   this.startCamera = __sp_startCamera;
       
   821   this.stopViewfinder = __s60_api_not_supported;
       
   822   //Extended methods
       
   823   this.takePicture = __s60_api_not_supported;
       
   824   //Private data
       
   825 }
       
   826 
       
   827 var CAMERA_APP_ID = 0x101f857a;
       
   828 
       
   829 //Apps should take care that this is not reinvoked
       
   830 //while the viewfinder is running. 
       
   831 
       
   832 function __sp_startCamera(camera_cb){
       
   833 
       
   834 	//If callback is null , then return missing argument error
       
   835     if( camera_cb == null )
       
   836         throw new DeviceError("Camera:startCamera:callback is missing", err_missing_argument);
       
   837         
       
   838 	//If the callback is not a function, then return bad type error
       
   839 	if( typeof(camera_cb) != "function" )
       
   840 	    throw new DeviceError("Camera:startCamera:callback is a non-function", err_bad_argument);
       
   841 
       
   842   var finished = function (){
       
   843     var invoker = function (arg1, arg2, arg3){
       
   844       //__device_debug("invoker with: " + camera_cb);
       
   845       var it = arg3.ReturnValue;
       
   846       var item;
       
   847       var items = new Array();
       
   848       while (( item = it.getNext()) != undefined){
       
   849           var d = new Date(Date.parse(item.FileDate));
       
   850           //__device_debug(item.FileName + " " + d );
       
   851           // Items returned in reverse date order, so stop iterating before
       
   852           // reaching initial date. (Should be able to do this more efficiently
       
   853           // with sp filter, but that doesn't seem to work right now.)
       
   854           if (d > __sp_camera_start_date) {
       
   855               var pathname = item.FileNameAndPath.replace(/\\/g, "/");
       
   856               var fileScheme = "file:///";
       
   857               //Non-patched builds don't allow file scheme TBD: change this for patched builds
       
   858               items.unshift(fileScheme + pathname);
       
   859           }
       
   860       }
       
   861       var dummyTransID = 0;
       
   862       var dummyStatusCode = 0;
       
   863       camera_cb(dummyTransID, dummyStatusCode, items);
       
   864     };
       
   865 
       
   866     
       
   867     //When camera returns, get the image(s) created
       
   868     try {
       
   869       var mso = device.getServiceObject("Service.MediaManagement", "IDataSource");
       
   870     }
       
   871     catch(e) {
       
   872       __device_handle_exception (e, "media service not available : " + e);
       
   873     }
       
   874     
       
   875     var criteria = new Object();
       
   876 	modifyObjectBaseProp(criteria);
       
   877     criteria.Type = 'FileInfo';
       
   878     criteria.Filter = new Object();
       
   879 	modifyObjectBaseProp(criteria.Filter);
       
   880     criteria.Filter.FileType = 'Image';
       
   881     //criteria.Filter.Key = 'FileDate';
       
   882     //criteria.Filter.StartRange = null;
       
   883     //criteria.Filter.EndRange = null;
       
   884     criteria.Sort = new Object();
       
   885 	modifyObjectBaseProp(criteria.Sort);
       
   886     criteria.Sort.Key = 'FileDate';
       
   887     criteria.Sort.Order = 'Descending';
       
   888     
       
   889     try {
       
   890       var rval = mso.IDataSource.GetList(criteria, invoker);
       
   891     }
       
   892     catch (e) {
       
   893       __device_handle_exception (e, "media service GetList failed: " + e);
       
   894     }
       
   895   };
       
   896 
       
   897   __sp_camera_start_date = new Date();
       
   898   __s60_start_and_wait(CAMERA_APP_ID, "", finished);
       
   899   var dummyTid = 0;
       
   900   return dummyTid;
       
   901 }
       
   902 
       
   903 
       
   904 /*
       
   905 Copyright © 2009 Nokia. All rights reserved.
       
   906 Code licensed under the BSD License:
       
   907 Software License Agreement (BSD License) Copyright © 2009 Nokia.
       
   908 All rights reserved.
       
   909 Redistribution and use of this software in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
       
   910 
       
   911 Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 
       
   912 Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 
       
   913 Neither the name of Nokia Corporation. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission of Nokia Corporation. 
       
   914 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
       
   915 
       
   916 version: 1.0
       
   917 */
       
   918 
       
   919 
       
   920 // Camera service interface
       
   921 
       
   922 var __device_camera_service_entry =  {"name": null, 
       
   923 					 "version": null,
       
   924 					 "proto": __device_camera,
       
   925 					 "descriptor": __device_camera_descriptor,
       
   926 					 "providers": [{"descriptor": __sp_camera_descriptor, "instance": __sp_camera_instance}]
       
   927 					};
       
   928 
       
   929 function __device_camera_descriptor(provider){
       
   930   this.interfaceName = provider.interfaceName;
       
   931   this.version = provider.version;
       
   932 }
       
   933 
       
   934 
       
   935 // Private camera  prototype: called from service factory
       
   936 function __device_camera(provider){
       
   937   //Private properties
       
   938   this.provider = provider;
       
   939   //Read-only properties
       
   940   this.interfaceName = provider.descriptor.interfaceName;
       
   941   this.version = provider.descriptor.version;
       
   942  // this.supportedMediaTypes = provider.supportedMediaTypes;
       
   943  // this.supportedSizes = provider.supportedSizes;
       
   944   //Core methods
       
   945   this.startCamera = __device_camera_startCamera;
       
   946   this.stopViewfinder = __device_camera_stopViewfinder;
       
   947   //Extended methods
       
   948   this.takePicture = __device_camera_takePicture;
       
   949 }
       
   950 
       
   951 
       
   952 //Why bother to define these methods? Because the camera
       
   953 //object defines the contract for providers!
       
   954 
       
   955 function __device_camera_startCamera(camera_cb){
       
   956   return this.provider.startCamera(camera_cb);
       
   957 }
       
   958 
       
   959 function __device_camera_stopViewfinder(){
       
   960   this.provider.stopViewfinder();
       
   961 }
       
   962 
       
   963 function __device_camera_takePicture(format){
       
   964   this.provider.takePicture(format);
       
   965 }
       
   966 /**
       
   967  * This class provides access to the device contacts.
       
   968  * @constructor
       
   969  */
       
   970 
       
   971 function Contacts() {
       
   972 	
       
   973 }
       
   974 
       
   975 function Contact() {
       
   976 	this.id = null;
       
   977 	this.name = { 
       
   978 		formatted: "",
       
   979 		givenName: "",
       
   980 		familyName: ""
       
   981 	};
       
   982     this.phones = [];
       
   983     this.emails = [];
       
   984 }
       
   985 
       
   986 Contact.prototype.displayName = function()
       
   987 {
       
   988     // TODO: can be tuned according to prefs
       
   989 	return this.givenName + " " + this.familyName;
       
   990 };
       
   991 
       
   992 /*
       
   993  * @param {ContactsFilter} filter Object with filter properties. filter.name only for now.
       
   994  * @param {function} successCallback Callback function on success
       
   995  * @param {function} errorCallback Callback function on failure
       
   996  * @param {object} options Object with properties .page and .limit for paging
       
   997  */
       
   998 
       
   999 Contacts.prototype.find = function(filter, successCallback, errorCallback, options) {
       
  1000 	try {
       
  1001 		this.contactsService = device.getServiceObject("Service.Contact", "IDataSource");
       
  1002 		if (typeof options == 'object')
       
  1003 			this.options = options;
       
  1004 		else
       
  1005 			this.options = {};
       
  1006 		
       
  1007 		var criteria = new Object();
       
  1008 		criteria.Type = "Contact";
       
  1009 		if (filter && filter.name) {
       
  1010 			var searchTerm = '';
       
  1011 			if (filter.name.givenName && filter.name.givenName.length > 0) {
       
  1012 				searchTerm += filter.name.givenName;
       
  1013 			}
       
  1014 			if (filter.name.familyName && filter.name.familyName.length > 0) {
       
  1015 				searchTerm += searchTerm.length > 0 ? ' ' + filter.name.familyName : filter.name.familyName;
       
  1016 			}
       
  1017 			if (!filter.name.familyName && !filter.name.givenName && filter.name.formatted) {
       
  1018 				searchTerm = filter.name.formatted;
       
  1019 			}
       
  1020 			criteria.Filter = { SearchVal: searchTerm };
       
  1021 		}
       
  1022 		
       
  1023 		if (typeof(successCallback) != 'function') 
       
  1024 			successCallback = function(){};
       
  1025 		if (typeof(errorCallback) != 'function') 
       
  1026 			errorCallback = function(){};
       
  1027 		if (isNaN(this.options.limit))
       
  1028 			this.options.limit = 200;
       
  1029 		if (isNaN(this.options.page))
       
  1030 			this.options.page = 1;
       
  1031 		
       
  1032 		//need a closure here to bind this method to this instance of the Contacts object
       
  1033 		this.global_success = successCallback;
       
  1034 		var obj = this;
       
  1035 		
       
  1036 		//WRT: result.ReturnValue is an iterator of contacts
       
  1037 		this.contactsService.IDataSource.GetList(criteria, function(transId, eventCode, result){
       
  1038 			obj.success_callback(result.ReturnValue);
       
  1039 		});
       
  1040 	} 
       
  1041 	catch (ex) {
       
  1042 		alert(ex.name + ": " + ex.message);
       
  1043 		errorCallback(ex);
       
  1044 	}
       
  1045 };
       
  1046 
       
  1047 Contacts.prototype.success_callback = function(contacts_iterator) {
       
  1048 	try {
       
  1049 	var gapContacts = new Array();
       
  1050 	if (contacts_iterator) {
       
  1051 		contacts_iterator.reset();
       
  1052 		var contact;
       
  1053 		var i = 0;
       
  1054 		var end = this.options.page * this.options.limit;
       
  1055 		var start = end - this.options.limit;
       
  1056 		while ((contact = contacts_iterator.getNext()) != undefined && i < end) {
       
  1057 			try {
       
  1058 				if (i >= start) {
       
  1059 					var gapContact = new Contact();
       
  1060 					gapContact.name.givenName = Contacts.GetValue(contact, "FirstName");
       
  1061 					gapContact.name.familyName = Contacts.GetValue(contact, "LastName");
       
  1062 					gapContact.name.formatted = gapContact.name.givenName + " " + gapContact.name.familyName;
       
  1063 					gapContact.emails = Contacts.getEmailsList(contact);
       
  1064 					gapContact.phones = Contacts.getPhonesList(contact);
       
  1065 					gapContact.address = Contacts.getAddress(contact);
       
  1066 					gapContact.id = Contacts.GetValue(contact, "id");
       
  1067 					gapContacts.push(gapContact);
       
  1068 				}
       
  1069 				i++;
       
  1070 			} catch (e) {
       
  1071 				alert("ContactsError (" + e.name + ": " + e.message + ")");
       
  1072 			}
       
  1073 		}
       
  1074 	}
       
  1075 	this.contacts = gapContacts;
       
  1076 	this.global_success(gapContacts);
       
  1077 	} catch (ex) { alert(ex.name + ": " + ex.message); }
       
  1078 };
       
  1079 
       
  1080 Contacts.getEmailsList = function(contact) {
       
  1081 	var emails = new Array();
       
  1082 	try {
       
  1083 			emails[0] = { type:"General", address: Contacts.GetValue(contact, "EmailGen") };
       
  1084 			emails[1] = { type:"Work", address: Contacts.GetValue(contact, "EmailWork") };		
       
  1085 			emails[2] = { type:"Home", address: Contacts.GetValue(contact, "EmailHome") };
       
  1086 	} catch (e) {
       
  1087 		emails = [];
       
  1088 	}
       
  1089 	return emails;
       
  1090 };
       
  1091 
       
  1092 Contacts.getPhonesList = function(contact) {
       
  1093 	var phones = new Array();
       
  1094 	try {
       
  1095 			phones[0] = { type:"Mobile", number: Contacts.GetValue(contact, "MobilePhoneGen") };
       
  1096 			phones[1] = { type:"Home", number: Contacts.GetValue(contact, "LandPhoneGen") };
       
  1097 			phones[2] = { type:"Fax", number: Contacts.GetValue(contact, "FaxNumberGen") };
       
  1098 			phones[3] = { type:"Work", number: Contacts.GetValue(contact, "LandPhoneWork") };
       
  1099 			phones[4] = { type:"WorkMobile", number: Contacts.GetValue(contact, "MobilePhoneWork") };
       
  1100 	} catch (e) {
       
  1101 		phones = [];
       
  1102 	}
       
  1103 	return phones;
       
  1104 };
       
  1105 
       
  1106 Contacts.getAddress = function(contact) {
       
  1107 	var address = "";
       
  1108 	try {
       
  1109 		address = Contacts.GetValue(contact, "AddrLabelHome") + ", " + Contacts.GetValue(contact, "AddrStreetHome") + ", " +
       
  1110 				Contacts.GetValue(contact, "AddrLocalHome") + ", " + Contacts.GetValue(contact, "AddrRegionHome") + ", " + 
       
  1111 				Contacts.GetValue(contact, "AddrPostCodeHome") + ", " + Contacts.GetValue(contact, "AddrCountryHome");
       
  1112 	} catch (e) {
       
  1113 		address = "";
       
  1114 	}
       
  1115 	return address;
       
  1116 };
       
  1117 
       
  1118 Contacts.GetValue = function(contactObj, key) {
       
  1119 	try {
       
  1120 		return contactObj[key]["Value"];
       
  1121 	} catch (e) {
       
  1122 		return "";
       
  1123 	}
       
  1124 };
       
  1125 
       
  1126 if (typeof navigator.contacts == "undefined") navigator.contacts = new Contacts();
       
  1127 /**
       
  1128  * This class provides access to the debugging console.
       
  1129  * @constructor
       
  1130  */
       
  1131 function DebugConsole() {
       
  1132 }
       
  1133 
       
  1134 /**
       
  1135  * Print a normal log message to the console
       
  1136  * @param {Object|String} message Message or object to print to the console
       
  1137  */
       
  1138 DebugConsole.prototype.log = function(message) {
       
  1139 	
       
  1140 	//This ends up in C:\jslog_widget.log on the device
       
  1141 	console.log(message);
       
  1142 };
       
  1143 
       
  1144 /**
       
  1145  * Print a warning message to the console
       
  1146  * @param {Object|String} message Message or object to print to the console
       
  1147  */
       
  1148 DebugConsole.prototype.warn = function(message) {
       
  1149 	console.log(message);
       
  1150 };
       
  1151 
       
  1152 /**
       
  1153  * Print an error message to the console
       
  1154  * @param {Object|String} message Message or object to print to the console
       
  1155  */
       
  1156 DebugConsole.prototype.error = function(message) {
       
  1157 	console.log(message);
       
  1158 };
       
  1159 
       
  1160 if (typeof window.debug == "undefined") window.debug = new DebugConsole();
       
  1161 PhoneGap.ExtendWrtDeviceObj = function(){
       
  1162 	
       
  1163 	if (!window.device)
       
  1164 		window.device = {};
       
  1165 	navigator.device = window.device;
       
  1166 
       
  1167 	try {
       
  1168 	
       
  1169 		if (window.menu)
       
  1170 	    	window.menu.hideSoftkeys();
       
  1171 		
       
  1172 		device.available = PhoneGap.available;
       
  1173 		device.platform = null;
       
  1174 		device.version = null;
       
  1175 		device.name = null;
       
  1176 		device.uuid = null;
       
  1177 		
       
  1178 		var so = device.getServiceObject("Service.SysInfo", "ISysInfo");
       
  1179 		var pf = PhoneGap.GetWrtPlatformVersion(so);
       
  1180 		device.platform = pf.platform;
       
  1181 		device.version = pf.version;
       
  1182 		device.uuid = PhoneGap.GetWrtDeviceProperty(so, "IMEI");
       
  1183 		device.name = PhoneGap.GetWrtDeviceProperty(so, "PhoneModel");
       
  1184 	} 
       
  1185 	catch (e) {
       
  1186 		device.available = false;
       
  1187 	}
       
  1188 };
       
  1189 
       
  1190 PhoneGap.GetWrtDeviceProperty = function(serviceObj, key) {
       
  1191 	var criteria = { "Entity": "Device", "Key": key };
       
  1192 	var result = serviceObj.ISysInfo.GetInfo(criteria);
       
  1193 	if (result.ErrorCode == 0) {
       
  1194 		return result.ReturnValue.StringData;
       
  1195 	}
       
  1196 	else {
       
  1197 		return null;
       
  1198 	}
       
  1199 };
       
  1200 
       
  1201 PhoneGap.GetWrtPlatformVersion = function(serviceObj) {
       
  1202 	var criteria = { "Entity": "Device", "Key": "PlatformVersion" };
       
  1203 	var result = serviceObj.ISysInfo.GetInfo(criteria);
       
  1204 	if (result.ErrorCode == 0) {
       
  1205 		var version = {};
       
  1206 		version.platform = result.ReturnValue.MajorVersion;
       
  1207 		version.version = result.ReturnValue.MinorVersion;
       
  1208 		return version;
       
  1209 	}
       
  1210 	else {
       
  1211 		return null;
       
  1212 	}
       
  1213 };
       
  1214 
       
  1215 PhoneGap.ExtendWrtDeviceObj();/**
       
  1216  * This class provides access to device GPS data.
       
  1217  * @constructor
       
  1218  */
       
  1219 function Geolocation() {
       
  1220     /**
       
  1221      * The last known GPS position.
       
  1222      */
       
  1223     this.lastPosition = null;
       
  1224     this.lastError = null;
       
  1225     this.callbacks = {
       
  1226         onLocationChanged: [],
       
  1227         onError:           []
       
  1228     };
       
  1229 };
       
  1230 
       
  1231 /**
       
  1232  * Asynchronously aquires the current position.
       
  1233  * @param {Function} successCallback The function to call when the position
       
  1234  * data is available
       
  1235  * @param {Function} errorCallback The function to call when there is an error 
       
  1236  * getting the position data.
       
  1237  * @param {PositionOptions} options The options for getting the position data
       
  1238  * such as timeout.
       
  1239  */
       
  1240 Geolocation.prototype.getCurrentPosition = function(successCallback, errorCallback, options) {
       
  1241     var referenceTime = 0;
       
  1242     if (this.lastPosition)
       
  1243         referenceTime = this.lastPosition.timestamp;
       
  1244     else
       
  1245         this.start(options);
       
  1246 
       
  1247     var timeout = 20000;
       
  1248     var interval = 500;
       
  1249     if (typeof(options) == 'object' && options.interval)
       
  1250         interval = options.interval;
       
  1251 
       
  1252     if (typeof(successCallback) != 'function')
       
  1253         successCallback = function() {};
       
  1254     if (typeof(errorCallback) != 'function')
       
  1255         errorCallback = function() {};
       
  1256 
       
  1257     var dis = this;
       
  1258     var delay = 0;
       
  1259     var timer = setInterval(function() {
       
  1260         delay += interval;
       
  1261 		//if we have a new position, call success and cancel the timer
       
  1262         if (dis.lastPosition && dis.lastPosition.timestamp > referenceTime) {
       
  1263             successCallback(dis.lastPosition);
       
  1264             clearInterval(timer);
       
  1265         } else if (delay >= timeout) { //else if timeout has occured then call error and cancel the timer
       
  1266             errorCallback();
       
  1267             clearInterval(timer);
       
  1268         }
       
  1269 		//else the interval gets called again
       
  1270     }, interval);
       
  1271 };
       
  1272 
       
  1273 /**
       
  1274  * Asynchronously aquires the position repeatedly at a given interval.
       
  1275  * @param {Function} successCallback The function to call each time the position
       
  1276  * data is available
       
  1277  * @param {Function} errorCallback The function to call when there is an error 
       
  1278  * getting the position data.
       
  1279  * @param {PositionOptions} options The options for getting the position data
       
  1280  * such as timeout and the frequency of the watch.
       
  1281  */
       
  1282 Geolocation.prototype.watchPosition = function(successCallback, errorCallback, options) {
       
  1283 	// Invoke the appropriate callback with a new Position object every time the implementation 
       
  1284 	// determines that the position of the hosting device has changed. 
       
  1285 	this.getCurrentPosition(successCallback, errorCallback, options);
       
  1286 	var frequency = 10000;
       
  1287         if (typeof options == 'object' && options.frequency)
       
  1288             frequency = options.frequency;
       
  1289 	var that = this;
       
  1290 	return setInterval(function() {
       
  1291 		that.getCurrentPosition(successCallback, errorCallback, options);
       
  1292 	}, frequency);
       
  1293 };
       
  1294 
       
  1295 
       
  1296 /**
       
  1297  * Clears the specified position watch.
       
  1298  * @param {String} watchId The ID of the watch returned from #watchPosition.
       
  1299  */
       
  1300 Geolocation.prototype.clearWatch = function(watchId) {
       
  1301 	clearInterval(watchId);
       
  1302 };
       
  1303 
       
  1304 Geolocation.prototype.start = function(options) {
       
  1305 	var so = device.getServiceObject("Service.Location", "ILocation");
       
  1306 	
       
  1307 	//construct the criteria for our location request
       
  1308 	var updateOptions = new Object();
       
  1309 	// Specify that location information need not be guaranteed. This helps in
       
  1310 	// that the widget doesn't need to wait for that information possibly indefinitely.
       
  1311 	updateOptions.PartialUpdates = true;
       
  1312 	
       
  1313 	//default 15 seconds
       
  1314 	if (typeof(options) == 'object' && options.timeout) 
       
  1315 		//options.timeout in in ms, updateOptions.UpdateTimeout in microsecs
       
  1316 		updateOptions.UpdateTimeOut = options.timeout * 1000;
       
  1317 
       
  1318 	//default 1 second
       
  1319 	if (typeof(options) == 'object' && options.interval) 
       
  1320 		//options.timeout in in ms, updateOptions.UpdateTimeout in microsecs
       
  1321 		updateOptions.UpdateInterval = options.interval * 1000;
       
  1322 	
       
  1323 	// Initialize the criteria for the GetLocation call
       
  1324 	var trackCriteria = new Object();
       
  1325 	// could use "BasicLocationInformation" or "GenericLocationInfo"
       
  1326 	trackCriteria.LocationInformationClass = "GenericLocationInfo";
       
  1327 	trackCriteria.Updateoptions = updateOptions;
       
  1328 	
       
  1329 	var dis = this;
       
  1330 	so.ILocation.Trace(trackCriteria, function(transId, eventCode, result) {
       
  1331 		var retVal = result.ReturnValue;
       
  1332 
       
  1333 		if (result.ErrorCode != 0 || isNaN(retVal.Latitude))
       
  1334 			return;
       
  1335 		
       
  1336 		// heading options: retVal.TrueCourse, retVal.MagneticHeading, retVal.Heading, retVal.MagneticCourse
       
  1337 		// but retVal.Heading was the only field being returned with data on the test device (Nokia 5800)
       
  1338 		// WRT does not provide accuracy
       
  1339 		var newCoords = new Coordinates(retVal.Latitude, retVal.Longitude, retVal.Altitude, null, retVal.Heading, retVal.HorizontalSpeed);
       
  1340 		var positionObj = { coords: newCoords, timestamp: (new Date()).getTime() };
       
  1341 
       
  1342 		dis.lastPosition = positionObj;
       
  1343 	});
       
  1344 	
       
  1345 };
       
  1346 
       
  1347 
       
  1348 if (typeof navigator.geolocation == "undefined") navigator.geolocation = new Geolocation();
       
  1349 
       
  1350 /**
       
  1351  * This class provides access to native mapping applications on the device.
       
  1352  */
       
  1353 function Map() {
       
  1354 	
       
  1355 }
       
  1356 
       
  1357 /**
       
  1358  * Shows a native map on the device with pins at the given positions.
       
  1359  * @param {Array} positions
       
  1360  */
       
  1361 Map.prototype.show = function(positions) {
       
  1362 
       
  1363 	var err = "map api is unimplemented on symbian.wrt";
       
  1364 	debug.log(err);
       
  1365 	return { name: "MapError", message: err };
       
  1366 
       
  1367 };
       
  1368 
       
  1369 if (typeof navigator.map == "undefined") navigator.map = new Map();
       
  1370 function Network() {
       
  1371     /**
       
  1372      * The last known Network status.
       
  1373      */
       
  1374 	this.lastReachability = null;
       
  1375 };
       
  1376 
       
  1377 Network.prototype.isReachable = function(hostName, successCallback, options) {
       
  1378 	var req = new XMLHttpRequest();  
       
  1379    	req.open('GET', hostName, true);  
       
  1380    	req.onreadystatechange = function (aEvt) {  
       
  1381      	if (req.readyState == 4) {  
       
  1382         	if(req.status == 200)  
       
  1383         		successCallback(NetworkStatus.REACHABLE_VIA_CARRIER_DATA_NETWORK);
       
  1384          	else  
       
  1385           		successCallback(NetworkStatus.NOT_REACHABLE);
       
  1386  		}  
       
  1387   	};  
       
  1388   	req.send(null);
       
  1389 
       
  1390 };
       
  1391 
       
  1392 /**
       
  1393  * This class contains information about any NetworkStatus.
       
  1394  * @constructor
       
  1395  */
       
  1396 function NetworkStatus() {
       
  1397 	this.code = null;
       
  1398 	this.message = "";
       
  1399 }
       
  1400 
       
  1401 NetworkStatus.NOT_REACHABLE = 0;
       
  1402 NetworkStatus.REACHABLE_VIA_CARRIER_DATA_NETWORK = 1;
       
  1403 NetworkStatus.REACHABLE_VIA_WIFI_NETWORK = 2;
       
  1404 
       
  1405 if (typeof navigator.network == "undefined") navigator.network = new Network();
       
  1406 /**
       
  1407  * This class provides access to notifications on the device.
       
  1408  */
       
  1409 function Notification() {
       
  1410 	
       
  1411 }
       
  1412 
       
  1413 Notification.prototype.vibrate = function(mills)
       
  1414 {
       
  1415 	
       
  1416 	if (!Notification.getSysinfoObject())
       
  1417 		Notification.embedSysinfoObject();
       
  1418 	
       
  1419 	this.sysinfo = Notification.getSysinfoObject();
       
  1420 	this.sysinfo.startvibra(mills, 100);
       
  1421 };
       
  1422 
       
  1423 //TODO: this is not beeping
       
  1424 Notification.prototype.beep = function(count, volume)
       
  1425 {
       
  1426 	if (!Notification.getSysinfoObject())
       
  1427 		Notification.embedSysinfoObject();
       
  1428 	
       
  1429 	this.sysinfo = Notification.getSysinfoObject();	
       
  1430 	this.sysinfo.beep(220,2000);
       
  1431 };
       
  1432 
       
  1433 
       
  1434 /**
       
  1435  * Open a native alert dialog, with a customizable title and button text.
       
  1436  * @param {String} message Message to print in the body of the alert
       
  1437  * @param {String} [title="Alert"] Title of the alert dialog (default: Alert)
       
  1438  * @param {String} [buttonLabel="OK"] Label of the close button (default: OK)
       
  1439  */
       
  1440 Notification.prototype.alert = function(message, title, buttonLabel) {
       
  1441     // Default is to use a browser alert; this will use "index.html" as the title though
       
  1442     alert(message);
       
  1443 };
       
  1444 
       
  1445 /**
       
  1446  * Start spinning the activity indicator on the statusbar
       
  1447  */
       
  1448 Notification.prototype.activityStart = function() {
       
  1449 };
       
  1450 
       
  1451 /**
       
  1452  * Stop spinning the activity indicator on the statusbar, if it's currently spinning
       
  1453  */
       
  1454 Notification.prototype.activityStop = function() {
       
  1455 };
       
  1456 
       
  1457 /**
       
  1458  * Causes the device to blink a status LED.
       
  1459  * @param {Integer} count The number of blinks.
       
  1460  * @param {String} colour The colour of the light.
       
  1461  */
       
  1462 Notification.prototype.blink = function(count, colour) {
       
  1463 	
       
  1464 };
       
  1465 
       
  1466 Notification.embedSysinfoObject = function() {
       
  1467 	var el = document.createElement("embed");
       
  1468 	el.setAttribute("type", "application/x-systeminfo-widget");
       
  1469 	el.setAttribute("hidden", "yes");
       
  1470 	document.getElementsByTagName("body")[0].appendChild(el);
       
  1471 	return;
       
  1472 };
       
  1473 
       
  1474 Notification.getSysinfoObject = function() {
       
  1475 	return document.embeds[0];
       
  1476 };
       
  1477 
       
  1478 if (typeof navigator.notification == "undefined") navigator.notification = new Notification();
       
  1479 /**
       
  1480  * This class provides access to the device orientation.
       
  1481  * @constructor
       
  1482  */
       
  1483 function Orientation() {
       
  1484 	/**
       
  1485 	 * The current orientation, or null if the orientation hasn't changed yet.
       
  1486 	 */
       
  1487 	this.currentOrientation = null;
       
  1488 }
       
  1489 
       
  1490 /**
       
  1491  * Set the current orientation of the phone.  This is called from the device automatically.
       
  1492  * 
       
  1493  * When the orientation is changed, the DOMEvent \c orientationChanged is dispatched against
       
  1494  * the document element.  The event has the property \c orientation which can be used to retrieve
       
  1495  * the device's current orientation, in addition to the \c Orientation.currentOrientation class property.
       
  1496  *
       
  1497  * @param {Number} orientation The orientation to be set
       
  1498  */
       
  1499 Orientation.prototype.setOrientation = function(orientation) {
       
  1500 		if (orientation == this.currentOrientation) 
       
  1501 			return;
       
  1502 		var old = this.currentOrientation;
       
  1503 
       
  1504 		this.currentOrientation = orientation;
       
  1505 		var e = document.createEvent('Events');
       
  1506 		e.initEvent('orientationChanged', 'false', 'false');
       
  1507 		e.orientation = orientation;
       
  1508 		e.oldOrientation = old;
       
  1509 		document.dispatchEvent(e);
       
  1510 };
       
  1511 
       
  1512 /**
       
  1513  * Asynchronously aquires the current orientation.
       
  1514  * @param {Function} successCallback The function to call when the orientation
       
  1515  * is known.
       
  1516  * @param {Function} errorCallback The function to call when there is an error 
       
  1517  * getting the orientation.
       
  1518  */
       
  1519 Orientation.prototype.getCurrentOrientation = function(successCallback, errorCallback) {
       
  1520 	// If the orientation is available then call success
       
  1521 	// If the orientation is not available then call error
       
  1522 	try {
       
  1523 		if (!this.serviceObj) 
       
  1524 			this.serviceObj = this.getServiceObj();
       
  1525 		
       
  1526 		if (this.serviceObj == null) 
       
  1527 			errorCallback({
       
  1528 				name: "DeviceErr",
       
  1529 				message: "Could not initialize service object"
       
  1530 			});
       
  1531 		
       
  1532 		//get the sensor channel
       
  1533 		var SensorParams = {
       
  1534 			SearchCriterion: "Orientation"
       
  1535 		};
       
  1536 		var returnvalue = this.serviceObj.ISensor.FindSensorChannel(SensorParams);
       
  1537 		
       
  1538 		var error = returnvalue["ErrorCode"];
       
  1539 		var errmsg = returnvalue["ErrorMessage"];
       
  1540 		if (!(error == 0 || error == 1012)) {
       
  1541 			var ex = {
       
  1542 				name: "Unable to find Sensor Channel: " + error,
       
  1543 				message: errmsg
       
  1544 			};
       
  1545 			errorCallback(ex);
       
  1546 		}
       
  1547 		var channelInfoMap = returnvalue["ReturnValue"][0];
       
  1548 		var criteria = {
       
  1549 			ChannelInfoMap: channelInfoMap,
       
  1550 			ListeningType: "ChannelData"
       
  1551 		};
       
  1552 		
       
  1553 		if (typeof(successCallback) != 'function') 
       
  1554 			successCallback = function(){
       
  1555 			};
       
  1556 		if (typeof(errorCallback) != 'function') 
       
  1557 			errorCallback = function(){
       
  1558 			};
       
  1559 		
       
  1560 		this.success_callback = successCallback;
       
  1561 		this.error_callback = errorCallback;
       
  1562 		
       
  1563 		//create a closure to persist this instance of orientation object into the RegisterForNofication callback
       
  1564 		var obj = this;
       
  1565 		
       
  1566 		// TODO: this call crashes WRT, but there is no other way to read the orientation sensor
       
  1567 		// http://discussion.forum.nokia.com/forum/showthread.php?t=182151&highlight=memory+leak
       
  1568 		this.serviceObj.ISensor.RegisterForNotification(criteria, function(transId, eventCode, result){
       
  1569 			var criteria = {
       
  1570 				TransactionID: transId
       
  1571 			};
       
  1572 			try {
       
  1573 				//var orientation = result.ReturnValue.DeviceOrientation;
       
  1574 				obj.serviceObj.ISensor.Cancel(criteria);
       
  1575 				
       
  1576 				var orientation = null;
       
  1577 				switch (result.ReturnValue.DeviceOrientation) {
       
  1578 					case "DisplayUpwards": orientation = DisplayOrientation.FACE_UP; break;
       
  1579 					case "DisplayDownwards": orientation = DisplayOrientation.FACE_DOWN; break;
       
  1580 					case "DisplayUp": orientation = DisplayOrientation.PORTRAIT; break;
       
  1581 					case "DisplayDown": orientation = DisplayOrientation.REVERSE_PORTRAIT; break;
       
  1582 					case "DisplayRightUp": orientation = DisplayOrientation.LANDSCAPE_RIGHT_UP; break;
       
  1583 					case "DisplayLeftUp": orientation = DisplayOrientation.LANDSCAPE_LEFT_UP; break;
       
  1584 					
       
  1585 				}
       
  1586 				
       
  1587 				obj.setOrientation(orientation);
       
  1588 				
       
  1589 				obj.success_callback(orientation);
       
  1590 				
       
  1591 			} 
       
  1592 			catch (ex) {
       
  1593 				obj.serviceObj.ISensor.Cancel(criteria);
       
  1594 				obj.error_callback(ex);
       
  1595 			}
       
  1596 			
       
  1597 		});
       
  1598 	} catch (ex) {
       
  1599 		errorCallback({ name: "OrientationError", message: ex.name + ": " + ex.message });
       
  1600 	}
       
  1601 };
       
  1602 
       
  1603 /**
       
  1604  * Asynchronously aquires the orientation repeatedly at a given interval.
       
  1605  * @param {Function} successCallback The function to call each time the orientation
       
  1606  * data is available.
       
  1607  * @param {Function} errorCallback The function to call when there is an error 
       
  1608  * getting the orientation data.
       
  1609  */
       
  1610 Orientation.prototype.watchOrientation = function(successCallback, errorCallback, options) {
       
  1611 	// Invoke the appropriate callback with a new Position object every time the implementation 
       
  1612 	// determines that the position of the hosting device has changed. 
       
  1613 	this.getCurrentOrientation(successCallback, errorCallback);
       
  1614 	var frequency = (options != undefined)? options.frequency : 1000;
       
  1615 	return setInterval(function() {
       
  1616 		navigator.orientation.getCurrentOrientation(successCallback, errorCallback);
       
  1617 	}, frequency);
       
  1618 };
       
  1619 
       
  1620 /**
       
  1621  * Clears the specified orientation watch.
       
  1622  * @param {String} watchId The ID of the watch returned from #watchOrientation.
       
  1623  */
       
  1624 Orientation.prototype.clearWatch = function(watchId) {
       
  1625 	clearInterval(watchId);
       
  1626 };
       
  1627 
       
  1628 //gets the Acceleration Service Object from WRT
       
  1629 Orientation.prototype.getServiceObj = function() {
       
  1630 	var so;
       
  1631 	
       
  1632     try {
       
  1633         so = device.getServiceObject("Service.Sensor", "ISensor");
       
  1634     } catch (ex) {
       
  1635 		throw {
       
  1636 			name: "DeviceError",
       
  1637 			message: ex.name + ": " + ex.message
       
  1638 		};
       
  1639     }		
       
  1640 	return so;
       
  1641 };
       
  1642 
       
  1643 
       
  1644 /**
       
  1645  * This class encapsulates the possible orientation values.
       
  1646  * @constructor
       
  1647  */
       
  1648 function DisplayOrientation() {
       
  1649 	this.code = null;
       
  1650 	this.message = "";
       
  1651 }
       
  1652 
       
  1653 DisplayOrientation.PORTRAIT = 0;
       
  1654 DisplayOrientation.REVERSE_PORTRAIT = 1;
       
  1655 DisplayOrientation.LANDSCAPE_LEFT_UP = 2;
       
  1656 DisplayOrientation.LANDSCAPE_RIGHT_UP = 3;
       
  1657 DisplayOrientation.FACE_UP = 4;
       
  1658 DisplayOrientation.FACE_DOWN = 5;
       
  1659 
       
  1660 if (typeof navigator.orientation == "undefined") navigator.orientation = new Orientation();
       
  1661 /**
       
  1662  * This class contains position information.
       
  1663  * @param {Object} lat
       
  1664  * @param {Object} lng
       
  1665  * @param {Object} acc
       
  1666  * @param {Object} alt
       
  1667  * @param {Object} altacc
       
  1668  * @param {Object} head
       
  1669  * @param {Object} vel
       
  1670  * @constructor
       
  1671  */
       
  1672 function Position(coords, timestamp) {
       
  1673 	this.coords = coords;
       
  1674         this.timestamp = new Date().getTime();
       
  1675 }
       
  1676 
       
  1677 function Coordinates(lat, lng, alt, acc, head, vel) {
       
  1678 	/**
       
  1679 	 * The latitude of the position.
       
  1680 	 */
       
  1681 	this.latitude = lat;
       
  1682 	/**
       
  1683 	 * The longitude of the position,
       
  1684 	 */
       
  1685 	this.longitude = lng;
       
  1686 	/**
       
  1687 	 * The accuracy of the position.
       
  1688 	 */
       
  1689 	this.accuracy = acc;
       
  1690 	/**
       
  1691 	 * The altitude of the position.
       
  1692 	 */
       
  1693 	this.altitude = alt;
       
  1694 	/**
       
  1695 	 * The direction the device is moving at the position.
       
  1696 	 */
       
  1697 	this.heading = head;
       
  1698 	/**
       
  1699 	 * The velocity with which the device is moving at the position.
       
  1700 	 */
       
  1701 	this.speed = vel;
       
  1702 }
       
  1703 
       
  1704 /**
       
  1705  * This class specifies the options for requesting position data.
       
  1706  * @constructor
       
  1707  */
       
  1708 function PositionOptions() {
       
  1709 	/**
       
  1710 	 * Specifies the desired position accuracy.
       
  1711 	 */
       
  1712 	this.enableHighAccuracy = true;
       
  1713 	/**
       
  1714 	 * The timeout after which if position data cannot be obtained the errorCallback
       
  1715 	 * is called.
       
  1716 	 */
       
  1717 	this.timeout = 10000;
       
  1718 }
       
  1719 
       
  1720 /**
       
  1721  * This class contains information about any GSP errors.
       
  1722  * @constructor
       
  1723  */
       
  1724 function PositionError() {
       
  1725 	this.code = null;
       
  1726 	this.message = "";
       
  1727 }
       
  1728 
       
  1729 PositionError.UNKNOWN_ERROR = 0;
       
  1730 PositionError.PERMISSION_DENIED = 1;
       
  1731 PositionError.POSITION_UNAVAILABLE = 2;
       
  1732 PositionError.TIMEOUT = 3;
       
  1733 /**
       
  1734  * This class provides access to the device SMS functionality.
       
  1735  * @constructor
       
  1736  */
       
  1737 function Sms() {
       
  1738 
       
  1739 }
       
  1740 
       
  1741 /**
       
  1742  * Sends an SMS message.
       
  1743  * @param {Integer} number The phone number to send the message to.
       
  1744  * @param {String} message The contents of the SMS message to send.
       
  1745  * @param {Function} successCallback The function to call when the SMS message is sent.
       
  1746  * @param {Function} errorCallback The function to call when there is an error sending the SMS message.
       
  1747  * @param {PositionOptions} options The options for accessing the GPS location such as timeout and accuracy.
       
  1748  */
       
  1749 Sms.prototype.send = function(number, message, successCallback, errorCallback, options) {
       
  1750     try {
       
  1751 		if (!this.serviceObj)
       
  1752 			this.serviceObj = this.getServiceObj();
       
  1753 			
       
  1754 	    // Setup input params using dot syntax
       
  1755 	    var criteria = new Object();
       
  1756 	    criteria.MessageType = 'SMS';
       
  1757 	    criteria.To = number;
       
  1758 	    criteria.BodyText = message;
       
  1759 
       
  1760       	var result = this.serviceObj.IMessaging.Send(criteria);
       
  1761     	if (result.ErrorCode != 0 && result.ErrorCode != "0")
       
  1762 		{
       
  1763 			var exception = { name: "SMSError", message: result.ErrorMessage };
       
  1764 			throw exception;
       
  1765 		} else {
       
  1766 			successCallback.call();
       
  1767 		}
       
  1768     }
       
  1769   	catch(ex)
       
  1770   	{
       
  1771 		errorCallback.call({ name: "SmsError", message: ex.name + ": " + ex.message });
       
  1772   	}
       
  1773 
       
  1774 };
       
  1775 
       
  1776 
       
  1777 //gets the Sms Service Object from WRT
       
  1778 Sms.prototype.getServiceObj = function() {
       
  1779 	var so;
       
  1780 	
       
  1781     try {
       
  1782         so = device.getServiceObject("Service.Messaging", "IMessaging");
       
  1783     } catch (ex) {
       
  1784 		throw {
       
  1785 			name: "SmsError",
       
  1786 			message: "Failed to load sms service (" + ex.name + ": " + ex.message + ")"
       
  1787 		};
       
  1788     }		
       
  1789 	return so;
       
  1790 };
       
  1791 
       
  1792 if (typeof navigator.sms == "undefined") navigator.sms = new Sms();/**
       
  1793  * @author ryan
       
  1794  */
       
  1795 
       
  1796 function Storage() {
       
  1797 	this.available = true;
       
  1798 	this.serialized = null;
       
  1799 	this.items = null;
       
  1800 	
       
  1801 	if (!window.widget) {
       
  1802 		this.available = false;
       
  1803 		return;
       
  1804 	}
       
  1805 	var pref = window.widget.preferenceForKey(Storage.PREFERENCE_KEY);
       
  1806 	
       
  1807 	//storage not yet created
       
  1808 	if (pref == "undefined" || pref == undefined) {
       
  1809 		this.length = 0;
       
  1810 		this.serialized = "({})";
       
  1811 		this.items = {};
       
  1812 		window.widget.setPreferenceForKey(this.serialized, Storage.PREFERENCE_KEY);
       
  1813 	} else {
       
  1814 		this.serialized = pref;'({"store_test": { "key": "store_test", "data": "asdfasdfs" },})';
       
  1815 		this.items = eval(this.serialized);
       
  1816 	}
       
  1817 }
       
  1818 
       
  1819 Storage.PREFERENCE_KEY = "phonegap_storage_pref_key";
       
  1820 
       
  1821 Storage.prototype.index = function (key) {
       
  1822 	
       
  1823 };
       
  1824 
       
  1825 Storage.prototype.getItem = function (key) {
       
  1826 	try {
       
  1827 		return this.items[key].data;
       
  1828 	} catch (ex) {
       
  1829 		return null;
       
  1830 	}
       
  1831 };
       
  1832 
       
  1833 Storage.prototype.setItem = function (key, data) {
       
  1834 
       
  1835 	this.items[key] = {
       
  1836 		"key": key,
       
  1837 		"data": data
       
  1838 	};
       
  1839 	
       
  1840 	this.serialize();
       
  1841 };
       
  1842 
       
  1843 Storage.prototype.removeItem = function (key) {
       
  1844 
       
  1845 	if (this.items[key]) {
       
  1846 		this.items[key] = undefined;
       
  1847 	}
       
  1848 	this.serialize();
       
  1849 };
       
  1850 
       
  1851 Storage.prototype.clear = function () {
       
  1852 	this.serialized = "({})";
       
  1853 	this.items = {};
       
  1854 	this.serialize();
       
  1855 };
       
  1856 
       
  1857 Storage.prototype.serialize = function() {
       
  1858 	var json = "";
       
  1859 	
       
  1860 	for (key in this.items) {
       
  1861 		var item = this.items[key];
       
  1862 		if (typeof item != "undefined") {
       
  1863 			json += "\"" + item.key + "\": { \"key\": \"" + item.key + "\", \"data\": \"" + item.data + "\" }, ";
       
  1864 		}
       
  1865 	}
       
  1866 	this.serialized = "({" + json + "})";
       
  1867 
       
  1868 	window.widget.setPreferenceForKey( this.serialized, Storage.PREFERENCE_KEY);
       
  1869 };
       
  1870 
       
  1871 if (typeof navigator.storage == "undefined" ) navigator.storage = new Storage();
       
  1872 /**
       
  1873  * This class provides access to the telephony features of the device.
       
  1874  * @constructor
       
  1875  */
       
  1876 function Telephony() {
       
  1877 	this.number = "";
       
  1878 }
       
  1879 
       
  1880 /**
       
  1881  * Calls the specifed number.
       
  1882  * @param {Integer} number The number to be called.
       
  1883  */
       
  1884 Telephony.prototype.send = function(number) {
       
  1885 	widget.openURL('tel:+' + number);
       
  1886 };
       
  1887 
       
  1888 if (typeof navigator.telephony == "undefined") navigator.telephony = new Telephony();