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