framework/www/phonegap.js
changeset 0 54063d8b0412
equal deleted inserted replaced
-1:000000000000 0:54063d8b0412
       
     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 	contacts_iterator.reset();
       
  1051     var contact;
       
  1052 	var i = 0;
       
  1053 	var end = this.options.page * this.options.limit;
       
  1054 	var start = end - this.options.limit;
       
  1055 	while ((contact = contacts_iterator.getNext()) != undefined && i < end) {
       
  1056 		try {
       
  1057 			if (i >= start) {
       
  1058 				var gapContact = new Contact();
       
  1059 				gapContact.name.givenName = Contacts.GetValue(contact, "FirstName");
       
  1060 				gapContact.name.familyName = Contacts.GetValue(contact, "LastName");
       
  1061 				gapContact.name.formatted = gapContact.name.givenName + " " + gapContact.name.familyName;
       
  1062 				gapContact.emails = Contacts.getEmailsList(contact);
       
  1063 				gapContact.phones = Contacts.getPhonesList(contact);
       
  1064 				gapContact.address = Contacts.getAddress(contact);
       
  1065 				gapContact.id = Contacts.GetValue(contact, "id");
       
  1066 				gapContacts.push(gapContact);
       
  1067 			}
       
  1068 			i++;
       
  1069 		} catch (e) {
       
  1070 			alert("ContactsError (" + e.name + ": " + e.message + ")");
       
  1071 		}
       
  1072 	}
       
  1073 	this.contacts = gapContacts;
       
  1074 	this.global_success(gapContacts);
       
  1075 	} catch (ex) { alert(ex.name + ": " + ex.message); }
       
  1076 };
       
  1077 
       
  1078 Contacts.getEmailsList = function(contact) {
       
  1079 	var emails = new Array();
       
  1080 	try {
       
  1081 			emails[0] = { type:"General", address: Contacts.GetValue(contact, "EmailGen") };
       
  1082 			emails[1] = { type:"Work", address: Contacts.GetValue(contact, "EmailWork") };		
       
  1083 			emails[2] = { type:"Home", address: Contacts.GetValue(contact, "EmailHome") };
       
  1084 	} catch (e) {
       
  1085 		emails = [];
       
  1086 	}
       
  1087 	return emails;
       
  1088 };
       
  1089 
       
  1090 Contacts.getPhonesList = function(contact) {
       
  1091 	var phones = new Array();
       
  1092 	try {
       
  1093 			phones[0] = { type:"Mobile", number: Contacts.GetValue(contact, "MobilePhoneGen") };
       
  1094 			phones[1] = { type:"Home", number: Contacts.GetValue(contact, "LandPhoneGen") };
       
  1095 			phones[2] = { type:"Fax", number: Contacts.GetValue(contact, "FaxNumberGen") };
       
  1096 			phones[3] = { type:"Work", number: Contacts.GetValue(contact, "LandPhoneWork") };
       
  1097 			phones[4] = { type:"WorkMobile", number: Contacts.GetValue(contact, "MobilePhoneWork") };
       
  1098 	} catch (e) {
       
  1099 		phones = [];
       
  1100 	}
       
  1101 	return phones;
       
  1102 };
       
  1103 
       
  1104 Contacts.getAddress = function(contact) {
       
  1105 	var address = "";
       
  1106 	try {
       
  1107 		address = Contacts.GetValue(contact, "AddrLabelHome") + ", " + Contacts.GetValue(contact, "AddrStreetHome") + ", " +
       
  1108 				Contacts.GetValue(contact, "AddrLocalHome") + ", " + Contacts.GetValue(contact, "AddrRegionHome") + ", " + 
       
  1109 				Contacts.GetValue(contact, "AddrPostCodeHome") + ", " + Contacts.GetValue(contact, "AddrCountryHome");
       
  1110 	} catch (e) {
       
  1111 		address = "";
       
  1112 	}
       
  1113 	return address;
       
  1114 };
       
  1115 
       
  1116 Contacts.GetValue = function(contactObj, key) {
       
  1117 	try {
       
  1118 		return contactObj[key]["Value"];
       
  1119 	} catch (e) {
       
  1120 		return "";
       
  1121 	}
       
  1122 };
       
  1123 
       
  1124 if (typeof navigator.contacts == "undefined") navigator.contacts = new Contacts();
       
  1125 /**
       
  1126  * This class provides access to the debugging console.
       
  1127  * @constructor
       
  1128  */
       
  1129 function DebugConsole() {
       
  1130 }
       
  1131 
       
  1132 /**
       
  1133  * Print a normal log message to the console
       
  1134  * @param {Object|String} message Message or object to print to the console
       
  1135  */
       
  1136 DebugConsole.prototype.log = function(message) {
       
  1137 	
       
  1138 	//This ends up in C:\jslog_widget.log on the device
       
  1139 	console.log(message);
       
  1140 };
       
  1141 
       
  1142 /**
       
  1143  * Print a warning message to the console
       
  1144  * @param {Object|String} message Message or object to print to the console
       
  1145  */
       
  1146 DebugConsole.prototype.warn = function(message) {
       
  1147 };
       
  1148 
       
  1149 /**
       
  1150  * Print an error message to the console
       
  1151  * @param {Object|String} message Message or object to print to the console
       
  1152  */
       
  1153 DebugConsole.prototype.error = function(message) {
       
  1154 };
       
  1155 
       
  1156 if (typeof window.debug == "undefined") window.debug = new DebugConsole();
       
  1157 PhoneGap.ExtendWrtDeviceObj = function(){
       
  1158 	
       
  1159 	if (!window.device)
       
  1160 		window.device = {};
       
  1161 	navigator.device = window.device;
       
  1162 
       
  1163 	try {
       
  1164 	
       
  1165 		if (window.menu)
       
  1166 	    	window.menu.hideSoftkeys();
       
  1167 		
       
  1168 		device.available = PhoneGap.available;
       
  1169 		device.platform = null;
       
  1170 		device.version = null;
       
  1171 		device.name = null;
       
  1172 		device.uuid = null;
       
  1173 		
       
  1174 		var so = device.getServiceObject("Service.SysInfo", "ISysInfo");
       
  1175 		var pf = PhoneGap.GetWrtPlatformVersion(so);
       
  1176 		device.platform = pf.platform;
       
  1177 		device.version = pf.version;
       
  1178 		device.uuid = PhoneGap.GetWrtDeviceProperty(so, "IMEI");
       
  1179 		device.name = PhoneGap.GetWrtDeviceProperty(so, "PhoneModel");
       
  1180 	} 
       
  1181 	catch (e) {
       
  1182 		device.available = false;
       
  1183 	}
       
  1184 };
       
  1185 
       
  1186 PhoneGap.GetWrtDeviceProperty = function(serviceObj, key) {
       
  1187 	var criteria = { "Entity": "Device", "Key": key };
       
  1188 	var result = serviceObj.ISysInfo.GetInfo(criteria);
       
  1189 	if (result.ErrorCode == 0) {
       
  1190 		return result.ReturnValue.StringData;
       
  1191 	}
       
  1192 	else {
       
  1193 		return null;
       
  1194 	}
       
  1195 };
       
  1196 
       
  1197 PhoneGap.GetWrtPlatformVersion = function(serviceObj) {
       
  1198 	var criteria = { "Entity": "Device", "Key": "PlatformVersion" };
       
  1199 	var result = serviceObj.ISysInfo.GetInfo(criteria);
       
  1200 	if (result.ErrorCode == 0) {
       
  1201 		var version = {};
       
  1202 		version.platform = result.ReturnValue.MajorVersion;
       
  1203 		version.version = result.ReturnValue.MinorVersion;
       
  1204 		return version;
       
  1205 	}
       
  1206 	else {
       
  1207 		return null;
       
  1208 	}
       
  1209 };
       
  1210 
       
  1211 PhoneGap.ExtendWrtDeviceObj();/**
       
  1212  * This class provides access to device GPS data.
       
  1213  * @constructor
       
  1214  */
       
  1215 function Geolocation() {
       
  1216     /**
       
  1217      * The last known GPS position.
       
  1218      */
       
  1219     this.lastPosition = null;
       
  1220     this.lastError = null;
       
  1221     this.callbacks = {
       
  1222         onLocationChanged: [],
       
  1223         onError:           []
       
  1224     };
       
  1225 };
       
  1226 
       
  1227 /**
       
  1228  * Asynchronously aquires the current position.
       
  1229  * @param {Function} successCallback The function to call when the position
       
  1230  * data is available
       
  1231  * @param {Function} errorCallback The function to call when there is an error 
       
  1232  * getting the position data.
       
  1233  * @param {PositionOptions} options The options for getting the position data
       
  1234  * such as timeout.
       
  1235  */
       
  1236 Geolocation.prototype.getCurrentPosition = function(successCallback, errorCallback, options) {
       
  1237     var referenceTime = 0;
       
  1238     if (this.lastPosition)
       
  1239         referenceTime = this.lastPosition.timestamp;
       
  1240     else
       
  1241         this.start(options);
       
  1242 
       
  1243     var timeout = 20000;
       
  1244     var interval = 500;
       
  1245     if (typeof(options) == 'object' && options.interval)
       
  1246         interval = options.interval;
       
  1247 
       
  1248     if (typeof(successCallback) != 'function')
       
  1249         successCallback = function() {};
       
  1250     if (typeof(errorCallback) != 'function')
       
  1251         errorCallback = function() {};
       
  1252 
       
  1253     var dis = this;
       
  1254     var delay = 0;
       
  1255     var timer = setInterval(function() {
       
  1256         delay += interval;
       
  1257 		//if we have a new position, call success and cancel the timer
       
  1258         if (dis.lastPosition && dis.lastPosition.timestamp > referenceTime) {
       
  1259             successCallback(dis.lastPosition);
       
  1260             clearInterval(timer);
       
  1261         } else if (delay >= timeout) { //else if timeout has occured then call error and cancel the timer
       
  1262             errorCallback();
       
  1263             clearInterval(timer);
       
  1264         }
       
  1265 		//else the interval gets called again
       
  1266     }, interval);
       
  1267 };
       
  1268 
       
  1269 /**
       
  1270  * Asynchronously aquires the position repeatedly at a given interval.
       
  1271  * @param {Function} successCallback The function to call each time the position
       
  1272  * data is available
       
  1273  * @param {Function} errorCallback The function to call when there is an error 
       
  1274  * getting the position data.
       
  1275  * @param {PositionOptions} options The options for getting the position data
       
  1276  * such as timeout and the frequency of the watch.
       
  1277  */
       
  1278 Geolocation.prototype.watchPosition = function(successCallback, errorCallback, options) {
       
  1279 	// Invoke the appropriate callback with a new Position object every time the implementation 
       
  1280 	// determines that the position of the hosting device has changed. 
       
  1281 	this.getCurrentPosition(successCallback, errorCallback, options);
       
  1282 	var frequency = 10000;
       
  1283         if (typeof options == 'object' && options.frequency)
       
  1284             frequency = options.frequency;
       
  1285 	var that = this;
       
  1286 	return setInterval(function() {
       
  1287 		that.getCurrentPosition(successCallback, errorCallback, options);
       
  1288 	}, frequency);
       
  1289 };
       
  1290 
       
  1291 
       
  1292 /**
       
  1293  * Clears the specified position watch.
       
  1294  * @param {String} watchId The ID of the watch returned from #watchPosition.
       
  1295  */
       
  1296 Geolocation.prototype.clearWatch = function(watchId) {
       
  1297 	clearInterval(watchId);
       
  1298 };
       
  1299 
       
  1300 Geolocation.prototype.start = function(options) {
       
  1301 	var so = device.getServiceObject("Service.Location", "ILocation");
       
  1302 	
       
  1303 	//construct the criteria for our location request
       
  1304 	var updateOptions = new Object();
       
  1305 	// Specify that location information need not be guaranteed. This helps in
       
  1306 	// that the widget doesn't need to wait for that information possibly indefinitely.
       
  1307 	updateOptions.PartialUpdates = true;
       
  1308 	
       
  1309 	//default 15 seconds
       
  1310 	if (typeof(options) == 'object' && options.timeout) 
       
  1311 		//options.timeout in in ms, updateOptions.UpdateTimeout in microsecs
       
  1312 		updateOptions.UpdateTimeOut = options.timeout * 1000;
       
  1313 
       
  1314 	//default 1 second
       
  1315 	if (typeof(options) == 'object' && options.interval) 
       
  1316 		//options.timeout in in ms, updateOptions.UpdateTimeout in microsecs
       
  1317 		updateOptions.UpdateInterval = options.interval * 1000;
       
  1318 	
       
  1319 	// Initialize the criteria for the GetLocation call
       
  1320 	var trackCriteria = new Object();
       
  1321 	// could use "BasicLocationInformation" or "GenericLocationInfo"
       
  1322 	trackCriteria.LocationInformationClass = "GenericLocationInfo";
       
  1323 	trackCriteria.Updateoptions = updateOptions;
       
  1324 	
       
  1325 	var dis = this;
       
  1326 	so.ILocation.Trace(trackCriteria, function(transId, eventCode, result) {
       
  1327 		var retVal = result.ReturnValue;
       
  1328 
       
  1329 		if (result.ErrorCode != 0 || isNaN(retVal.Latitude))
       
  1330 			return;
       
  1331 		
       
  1332 		// heading options: retVal.TrueCourse, retVal.MagneticHeading, retVal.Heading, retVal.MagneticCourse
       
  1333 		// but retVal.Heading was the only field being returned with data on the test device (Nokia 5800)
       
  1334 		// WRT does not provide accuracy
       
  1335 		var newCoords = new Coordinates(retVal.Latitude, retVal.Longitude, retVal.Altitude, null, retVal.Heading, retVal.HorizontalSpeed);
       
  1336 		var positionObj = { coords: newCoords, timestamp: (new Date()).getTime() };
       
  1337 
       
  1338 		dis.lastPosition = positionObj;
       
  1339 	});
       
  1340 	
       
  1341 };
       
  1342 
       
  1343 
       
  1344 if (typeof navigator.geolocation == "undefined") navigator.geolocation = new Geolocation();
       
  1345 
       
  1346 /**
       
  1347  * This class provides access to native mapping applications on the device.
       
  1348  */
       
  1349 function Map() {
       
  1350 	
       
  1351 }
       
  1352 
       
  1353 /**
       
  1354  * Shows a native map on the device with pins at the given positions.
       
  1355  * @param {Array} positions
       
  1356  */
       
  1357 Map.prototype.show = function(positions) {
       
  1358 
       
  1359 	var err = "map api is unimplemented on symbian.wrt";
       
  1360 	debug.log(err);
       
  1361 	return { name: "MapError", message: err };
       
  1362 
       
  1363 };
       
  1364 
       
  1365 if (typeof navigator.map == "undefined") navigator.map = new Map();
       
  1366 function Network() {
       
  1367     /**
       
  1368      * The last known Network status.
       
  1369      */
       
  1370 	this.lastReachability = null;
       
  1371 };
       
  1372 
       
  1373 Network.prototype.isReachable = function(hostName, successCallback, options) {
       
  1374 	var req = new XMLHttpRequest();  
       
  1375    	req.open('GET', hostName, true);  
       
  1376    	req.onreadystatechange = function (aEvt) {  
       
  1377      	if (req.readyState == 4) {  
       
  1378         	if(req.status == 200)  
       
  1379         		successCallback(NetworkStatus.REACHABLE_VIA_CARRIER_DATA_NETWORK);
       
  1380          	else  
       
  1381           		successCallback(NetworkStatus.NOT_REACHABLE);
       
  1382  		}  
       
  1383   	};  
       
  1384   	req.send(null);
       
  1385 
       
  1386 };
       
  1387 
       
  1388 /**
       
  1389  * This class contains information about any NetworkStatus.
       
  1390  * @constructor
       
  1391  */
       
  1392 function NetworkStatus() {
       
  1393 	this.code = null;
       
  1394 	this.message = "";
       
  1395 }
       
  1396 
       
  1397 NetworkStatus.NOT_REACHABLE = 0;
       
  1398 NetworkStatus.REACHABLE_VIA_CARRIER_DATA_NETWORK = 1;
       
  1399 NetworkStatus.REACHABLE_VIA_WIFI_NETWORK = 2;
       
  1400 
       
  1401 if (typeof navigator.network == "undefined") navigator.network = new Network();
       
  1402 /**
       
  1403  * This class provides access to notifications on the device.
       
  1404  */
       
  1405 function Notification() {
       
  1406 	
       
  1407 }
       
  1408 
       
  1409 Notification.prototype.vibrate = function(mills)
       
  1410 {
       
  1411 	
       
  1412 	if (!Notification.getSysinfoObject())
       
  1413 		Notification.embedSysinfoObject();
       
  1414 	
       
  1415 	this.sysinfo = Notification.getSysinfoObject();
       
  1416 	this.sysinfo.startvibra(mills, 100);
       
  1417 };
       
  1418 
       
  1419 //TODO: this is not beeping
       
  1420 Notification.prototype.beep = function(count, volume)
       
  1421 {
       
  1422 	if (!Notification.getSysinfoObject())
       
  1423 		Notification.embedSysinfoObject();
       
  1424 	
       
  1425 	this.sysinfo = Notification.getSysinfoObject();	
       
  1426 	this.sysinfo.beep(220,2000);
       
  1427 };
       
  1428 
       
  1429 
       
  1430 /**
       
  1431  * Open a native alert dialog, with a customizable title and button text.
       
  1432  * @param {String} message Message to print in the body of the alert
       
  1433  * @param {String} [title="Alert"] Title of the alert dialog (default: Alert)
       
  1434  * @param {String} [buttonLabel="OK"] Label of the close button (default: OK)
       
  1435  */
       
  1436 Notification.prototype.alert = function(message, title, buttonLabel) {
       
  1437     // Default is to use a browser alert; this will use "index.html" as the title though
       
  1438     alert(message);
       
  1439 };
       
  1440 
       
  1441 /**
       
  1442  * Start spinning the activity indicator on the statusbar
       
  1443  */
       
  1444 Notification.prototype.activityStart = function() {
       
  1445 };
       
  1446 
       
  1447 /**
       
  1448  * Stop spinning the activity indicator on the statusbar, if it's currently spinning
       
  1449  */
       
  1450 Notification.prototype.activityStop = function() {
       
  1451 };
       
  1452 
       
  1453 /**
       
  1454  * Causes the device to blink a status LED.
       
  1455  * @param {Integer} count The number of blinks.
       
  1456  * @param {String} colour The colour of the light.
       
  1457  */
       
  1458 Notification.prototype.blink = function(count, colour) {
       
  1459 	
       
  1460 };
       
  1461 
       
  1462 Notification.embedSysinfoObject = function() {
       
  1463 	var el = document.createElement("embed");
       
  1464 	el.setAttribute("type", "application/x-systeminfo-widget");
       
  1465 	el.setAttribute("hidden", "yes");
       
  1466 	document.getElementsByTagName("body")[0].appendChild(el);
       
  1467 	return;
       
  1468 };
       
  1469 
       
  1470 Notification.getSysinfoObject = function() {
       
  1471 	return document.embeds[0];
       
  1472 };
       
  1473 
       
  1474 if (typeof navigator.notification == "undefined") navigator.notification = new Notification();
       
  1475 /**
       
  1476  * This class provides access to the device orientation.
       
  1477  * @constructor
       
  1478  */
       
  1479 function Orientation() {
       
  1480 	/**
       
  1481 	 * The current orientation, or null if the orientation hasn't changed yet.
       
  1482 	 */
       
  1483 	this.currentOrientation = null;
       
  1484 }
       
  1485 
       
  1486 /**
       
  1487  * Set the current orientation of the phone.  This is called from the device automatically.
       
  1488  * 
       
  1489  * When the orientation is changed, the DOMEvent \c orientationChanged is dispatched against
       
  1490  * the document element.  The event has the property \c orientation which can be used to retrieve
       
  1491  * the device's current orientation, in addition to the \c Orientation.currentOrientation class property.
       
  1492  *
       
  1493  * @param {Number} orientation The orientation to be set
       
  1494  */
       
  1495 Orientation.prototype.setOrientation = function(orientation) {
       
  1496 		if (orientation == this.currentOrientation) 
       
  1497 			return;
       
  1498 		var old = this.currentOrientation;
       
  1499 
       
  1500 		this.currentOrientation = orientation;
       
  1501 		var e = document.createEvent('Events');
       
  1502 		e.initEvent('orientationChanged', 'false', 'false');
       
  1503 		e.orientation = orientation;
       
  1504 		e.oldOrientation = old;
       
  1505 		document.dispatchEvent(e);
       
  1506 };
       
  1507 
       
  1508 /**
       
  1509  * Asynchronously aquires the current orientation.
       
  1510  * @param {Function} successCallback The function to call when the orientation
       
  1511  * is known.
       
  1512  * @param {Function} errorCallback The function to call when there is an error 
       
  1513  * getting the orientation.
       
  1514  */
       
  1515 Orientation.prototype.getCurrentOrientation = function(successCallback, errorCallback) {
       
  1516 	// If the orientation is available then call success
       
  1517 	// If the orientation is not available then call error
       
  1518 	try {
       
  1519 		if (!this.serviceObj) 
       
  1520 			this.serviceObj = this.getServiceObj();
       
  1521 		
       
  1522 		if (this.serviceObj == null) 
       
  1523 			errorCallback({
       
  1524 				name: "DeviceErr",
       
  1525 				message: "Could not initialize service object"
       
  1526 			});
       
  1527 		
       
  1528 		//get the sensor channel
       
  1529 		var SensorParams = {
       
  1530 			SearchCriterion: "Orientation"
       
  1531 		};
       
  1532 		var returnvalue = this.serviceObj.ISensor.FindSensorChannel(SensorParams);
       
  1533 		
       
  1534 		var error = returnvalue["ErrorCode"];
       
  1535 		var errmsg = returnvalue["ErrorMessage"];
       
  1536 		if (!(error == 0 || error == 1012)) {
       
  1537 			var ex = {
       
  1538 				name: "Unable to find Sensor Channel: " + error,
       
  1539 				message: errmsg
       
  1540 			};
       
  1541 			errorCallback(ex);
       
  1542 		}
       
  1543 		var channelInfoMap = returnvalue["ReturnValue"][0];
       
  1544 		var criteria = {
       
  1545 			ChannelInfoMap: channelInfoMap,
       
  1546 			ListeningType: "ChannelData"
       
  1547 		};
       
  1548 		
       
  1549 		if (typeof(successCallback) != 'function') 
       
  1550 			successCallback = function(){
       
  1551 			};
       
  1552 		if (typeof(errorCallback) != 'function') 
       
  1553 			errorCallback = function(){
       
  1554 			};
       
  1555 		
       
  1556 		this.success_callback = successCallback;
       
  1557 		this.error_callback = errorCallback;
       
  1558 		
       
  1559 		//create a closure to persist this instance of orientation object into the RegisterForNofication callback
       
  1560 		var obj = this;
       
  1561 		
       
  1562 		// TODO: this call crashes WRT, but there is no other way to read the orientation sensor
       
  1563 		// http://discussion.forum.nokia.com/forum/showthread.php?t=182151&highlight=memory+leak
       
  1564 		this.serviceObj.ISensor.RegisterForNotification(criteria, function(transId, eventCode, result){
       
  1565 			var criteria = {
       
  1566 				TransactionID: transId
       
  1567 			};
       
  1568 			try {
       
  1569 				//var orientation = result.ReturnValue.DeviceOrientation;
       
  1570 				obj.serviceObj.ISensor.Cancel(criteria);
       
  1571 				
       
  1572 				var orientation = null;
       
  1573 				switch (result.ReturnValue.DeviceOrientation) {
       
  1574 					case "DisplayUpwards": orientation = DisplayOrientation.FACE_UP; break;
       
  1575 					case "DisplayDownwards": orientation = DisplayOrientation.FACE_DOWN; break;
       
  1576 					case "DisplayUp": orientation = DisplayOrientation.PORTRAIT; break;
       
  1577 					case "DisplayDown": orientation = DisplayOrientation.REVERSE_PORTRAIT; break;
       
  1578 					case "DisplayRightUp": orientation = DisplayOrientation.LANDSCAPE_RIGHT_UP; break;
       
  1579 					case "DisplayLeftUp": orientation = DisplayOrientation.LANDSCAPE_LEFT_UP; break;
       
  1580 					
       
  1581 				}
       
  1582 				
       
  1583 				obj.setOrientation(orientation);
       
  1584 				
       
  1585 				obj.success_callback(orientation);
       
  1586 				
       
  1587 			} 
       
  1588 			catch (ex) {
       
  1589 				obj.serviceObj.ISensor.Cancel(criteria);
       
  1590 				obj.error_callback(ex);
       
  1591 			}
       
  1592 			
       
  1593 		});
       
  1594 	} catch (ex) {
       
  1595 		errorCallback({ name: "OrientationError", message: ex.name + ": " + ex.message });
       
  1596 	}
       
  1597 };
       
  1598 
       
  1599 /**
       
  1600  * Asynchronously aquires the orientation repeatedly at a given interval.
       
  1601  * @param {Function} successCallback The function to call each time the orientation
       
  1602  * data is available.
       
  1603  * @param {Function} errorCallback The function to call when there is an error 
       
  1604  * getting the orientation data.
       
  1605  */
       
  1606 Orientation.prototype.watchOrientation = function(successCallback, errorCallback, options) {
       
  1607 	// Invoke the appropriate callback with a new Position object every time the implementation 
       
  1608 	// determines that the position of the hosting device has changed. 
       
  1609 	this.getCurrentOrientation(successCallback, errorCallback);
       
  1610 	var frequency = (options != undefined)? options.frequency : 1000;
       
  1611 	return setInterval(function() {
       
  1612 		navigator.orientation.getCurrentOrientation(successCallback, errorCallback);
       
  1613 	}, frequency);
       
  1614 };
       
  1615 
       
  1616 /**
       
  1617  * Clears the specified orientation watch.
       
  1618  * @param {String} watchId The ID of the watch returned from #watchOrientation.
       
  1619  */
       
  1620 Orientation.prototype.clearWatch = function(watchId) {
       
  1621 	clearInterval(watchId);
       
  1622 };
       
  1623 
       
  1624 //gets the Acceleration Service Object from WRT
       
  1625 Orientation.prototype.getServiceObj = function() {
       
  1626 	var so;
       
  1627 	
       
  1628     try {
       
  1629         so = device.getServiceObject("Service.Sensor", "ISensor");
       
  1630     } catch (ex) {
       
  1631 		throw {
       
  1632 			name: "DeviceError",
       
  1633 			message: ex.name + ": " + ex.message
       
  1634 		};
       
  1635     }		
       
  1636 	return so;
       
  1637 };
       
  1638 
       
  1639 
       
  1640 /**
       
  1641  * This class encapsulates the possible orientation values.
       
  1642  * @constructor
       
  1643  */
       
  1644 function DisplayOrientation() {
       
  1645 	this.code = null;
       
  1646 	this.message = "";
       
  1647 }
       
  1648 
       
  1649 DisplayOrientation.PORTRAIT = 0;
       
  1650 DisplayOrientation.REVERSE_PORTRAIT = 1;
       
  1651 DisplayOrientation.LANDSCAPE_LEFT_UP = 2;
       
  1652 DisplayOrientation.LANDSCAPE_RIGHT_UP = 3;
       
  1653 DisplayOrientation.FACE_UP = 4;
       
  1654 DisplayOrientation.FACE_DOWN = 5;
       
  1655 
       
  1656 if (typeof navigator.orientation == "undefined") navigator.orientation = new Orientation();
       
  1657 /**
       
  1658  * This class contains position information.
       
  1659  * @param {Object} lat
       
  1660  * @param {Object} lng
       
  1661  * @param {Object} acc
       
  1662  * @param {Object} alt
       
  1663  * @param {Object} altacc
       
  1664  * @param {Object} head
       
  1665  * @param {Object} vel
       
  1666  * @constructor
       
  1667  */
       
  1668 function Position(coords, timestamp) {
       
  1669 	this.coords = coords;
       
  1670         this.timestamp = new Date().getTime();
       
  1671 }
       
  1672 
       
  1673 function Coordinates(lat, lng, alt, acc, head, vel) {
       
  1674 	/**
       
  1675 	 * The latitude of the position.
       
  1676 	 */
       
  1677 	this.latitude = lat;
       
  1678 	/**
       
  1679 	 * The longitude of the position,
       
  1680 	 */
       
  1681 	this.longitude = lng;
       
  1682 	/**
       
  1683 	 * The accuracy of the position.
       
  1684 	 */
       
  1685 	this.accuracy = acc;
       
  1686 	/**
       
  1687 	 * The altitude of the position.
       
  1688 	 */
       
  1689 	this.altitude = alt;
       
  1690 	/**
       
  1691 	 * The direction the device is moving at the position.
       
  1692 	 */
       
  1693 	this.heading = head;
       
  1694 	/**
       
  1695 	 * The velocity with which the device is moving at the position.
       
  1696 	 */
       
  1697 	this.speed = vel;
       
  1698 }
       
  1699 
       
  1700 /**
       
  1701  * This class specifies the options for requesting position data.
       
  1702  * @constructor
       
  1703  */
       
  1704 function PositionOptions() {
       
  1705 	/**
       
  1706 	 * Specifies the desired position accuracy.
       
  1707 	 */
       
  1708 	this.enableHighAccuracy = true;
       
  1709 	/**
       
  1710 	 * The timeout after which if position data cannot be obtained the errorCallback
       
  1711 	 * is called.
       
  1712 	 */
       
  1713 	this.timeout = 10000;
       
  1714 }
       
  1715 
       
  1716 /**
       
  1717  * This class contains information about any GSP errors.
       
  1718  * @constructor
       
  1719  */
       
  1720 function PositionError() {
       
  1721 	this.code = null;
       
  1722 	this.message = "";
       
  1723 }
       
  1724 
       
  1725 PositionError.UNKNOWN_ERROR = 0;
       
  1726 PositionError.PERMISSION_DENIED = 1;
       
  1727 PositionError.POSITION_UNAVAILABLE = 2;
       
  1728 PositionError.TIMEOUT = 3;
       
  1729 /**
       
  1730  * This class provides access to the device SMS functionality.
       
  1731  * @constructor
       
  1732  */
       
  1733 function Sms() {
       
  1734 
       
  1735 }
       
  1736 
       
  1737 /**
       
  1738  * Sends an SMS message.
       
  1739  * @param {Integer} number The phone number to send the message to.
       
  1740  * @param {String} message The contents of the SMS message to send.
       
  1741  * @param {Function} successCallback The function to call when the SMS message is sent.
       
  1742  * @param {Function} errorCallback The function to call when there is an error sending the SMS message.
       
  1743  * @param {PositionOptions} options The options for accessing the GPS location such as timeout and accuracy.
       
  1744  */
       
  1745 Sms.prototype.send = function(number, message, successCallback, errorCallback, options) {
       
  1746     try {
       
  1747 		if (!this.serviceObj)
       
  1748 			this.serviceObj = this.getServiceObj();
       
  1749 			
       
  1750 	    // Setup input params using dot syntax
       
  1751 	    var criteria = new Object();
       
  1752 	    criteria.MessageType = 'SMS';
       
  1753 	    criteria.To = number;
       
  1754 	    criteria.BodyText = message;
       
  1755 
       
  1756       	var result = this.serviceObj.IMessaging.Send(criteria);
       
  1757     	if (result.ErrorCode != 0 && result.ErrorCode != "0")
       
  1758 		{
       
  1759 			var exception = { name: "SMSError", message: result.ErrorMessage };
       
  1760 			throw exception;
       
  1761 		} else {
       
  1762 			successCallback.call();
       
  1763 		}
       
  1764     }
       
  1765   	catch(ex)
       
  1766   	{
       
  1767 		errorCallback.call({ name: "SmsError", message: ex.name + ": " + ex.message });
       
  1768   	}
       
  1769 
       
  1770 };
       
  1771 
       
  1772 
       
  1773 //gets the Sms Service Object from WRT
       
  1774 Sms.prototype.getServiceObj = function() {
       
  1775 	var so;
       
  1776 	
       
  1777     try {
       
  1778         so = device.getServiceObject("Service.Messaging", "IMessaging");
       
  1779     } catch (ex) {
       
  1780 		throw {
       
  1781 			name: "SmsError",
       
  1782 			message: "Failed to load sms service (" + ex.name + ": " + ex.message + ")"
       
  1783 		};
       
  1784     }		
       
  1785 	return so;
       
  1786 };
       
  1787 
       
  1788 if (typeof navigator.sms == "undefined") navigator.sms = new Sms();/**
       
  1789  * @author ryan
       
  1790  */
       
  1791 
       
  1792 function Storage() {
       
  1793 	this.available = true;
       
  1794 	this.serialized = null;
       
  1795 	this.items = null;
       
  1796 	
       
  1797 	if (!window.widget) {
       
  1798 		this.available = false;
       
  1799 		return;
       
  1800 	}
       
  1801 	var pref = window.widget.preferenceForKey(Storage.PREFERENCE_KEY);
       
  1802 	
       
  1803 	//storage not yet created
       
  1804 	if (pref == "undefined" || pref == undefined) {
       
  1805 		this.length = 0;
       
  1806 		this.serialized = "({})";
       
  1807 		this.items = {};
       
  1808 		window.widget.setPreferenceForKey(this.serialized, Storage.PREFERENCE_KEY);
       
  1809 	} else {
       
  1810 		this.serialized = pref;'({"store_test": { "key": "store_test", "data": "asdfasdfs" },})';
       
  1811 		this.items = eval(this.serialized);
       
  1812 	}
       
  1813 }
       
  1814 
       
  1815 Storage.PREFERENCE_KEY = "phonegap_storage_pref_key";
       
  1816 
       
  1817 Storage.prototype.index = function (key) {
       
  1818 	
       
  1819 };
       
  1820 
       
  1821 Storage.prototype.getItem = function (key) {
       
  1822 	try {
       
  1823 		return this.items[key].data;
       
  1824 	} catch (ex) {
       
  1825 		return null;
       
  1826 	}
       
  1827 };
       
  1828 
       
  1829 Storage.prototype.setItem = function (key, data) {
       
  1830 
       
  1831 	this.items[key] = {
       
  1832 		"key": key,
       
  1833 		"data": data
       
  1834 	};
       
  1835 	
       
  1836 	this.serialize();
       
  1837 };
       
  1838 
       
  1839 Storage.prototype.removeItem = function (key) {
       
  1840 
       
  1841 	if (this.items[key]) {
       
  1842 		this.items[key] = undefined;
       
  1843 	}
       
  1844 	this.serialize();
       
  1845 };
       
  1846 
       
  1847 Storage.prototype.clear = function () {
       
  1848 	this.serialized = "({})";
       
  1849 	this.items = {};
       
  1850 	this.serialize();
       
  1851 };
       
  1852 
       
  1853 Storage.prototype.serialize = function() {
       
  1854 	var json = "";
       
  1855 	
       
  1856 	for (key in this.items) {
       
  1857 		var item = this.items[key];
       
  1858 		if (typeof item != "undefined") {
       
  1859 			json += "\"" + item.key + "\": { \"key\": \"" + item.key + "\", \"data\": \"" + item.data + "\" }, ";
       
  1860 		}
       
  1861 	}
       
  1862 	this.serialized = "({" + json + "})";
       
  1863 
       
  1864 	window.widget.setPreferenceForKey( this.serialized, Storage.PREFERENCE_KEY);
       
  1865 };
       
  1866 
       
  1867 if (typeof navigator.storage == "undefined" ) navigator.storage = new Storage();
       
  1868 /**
       
  1869  * This class provides access to the telephony features of the device.
       
  1870  * @constructor
       
  1871  */
       
  1872 function Telephony() {
       
  1873 	this.number = "";
       
  1874 }
       
  1875 
       
  1876 /**
       
  1877  * Calls the specifed number.
       
  1878  * @param {Integer} number The number to be called.
       
  1879  */
       
  1880 Telephony.prototype.send = function(number) {
       
  1881 	widget.openURL('tel:+' + number);
       
  1882 };
       
  1883 
       
  1884 if (typeof navigator.telephony == "undefined") navigator.telephony = new Telephony();