org.symbian.tools.wrttools.previewer/preview/script/lib/device.js
changeset 37 641b65b14318
child 210 0f7abfd6ae62
equal deleted inserted replaced
35:ec3f1313ae92 37:641b65b14318
       
     1 /**
       
     2  * device.js
       
     3  * 
       
     4  * Nokia Web Runtime Service API emulation 
       
     5  * WRT v1.1
       
     6  * 
       
     7  * Copyright 2009 Nokia Corporation. All rights reserved.
       
     8 */
       
     9 
       
    10 
       
    11 /**
       
    12  * device object. entry point to device service API (SAPI)
       
    13  */
       
    14 var device = {
       
    15 	/**
       
    16 	 * device API public method
       
    17 	 * 
       
    18 	 * @method
       
    19 	 * @param {string} provider Name of service provider, eg, "Service.Calendar"
       
    20 	 * @param {string} Interface Name of interface, eg, "IDataSource"
       
    21 	 * @return {Object} service object  
       
    22 	 */
       
    23 	getServiceObject: function(provider, Interface){
       
    24 
       
    25 		if (!device.implementation.context)
       
    26 			throw 'device implementation object not instantiated!'
       
    27 
       
    28 		if (device.implementation.options.enabled) 
       
    29 			return device.implementation.getInterface(provider, Interface);
       
    30 		else {
       
    31 			device.implementation.context.notify('device SAPI is disabled.');
       
    32 			throw 'device not defined!';
       
    33 		}
       
    34 	}
       
    35 };
       
    36 
       
    37 
       
    38 
       
    39 /**
       
    40  * implementation of device emulation mode
       
    41  * 
       
    42  * @param {String} 		version - version number (default: current version)
       
    43  * @return {Object} 	returns new implementation context object 
       
    44  * @constructor 		
       
    45  */
       
    46 device.implementation = function(version){
       
    47 
       
    48 	this.version = version || '';
       
    49 	
       
    50 	// set context to current object
       
    51 	device.implementation.context = this;	
       
    52 
       
    53 	var libpath = 'preview/script/lib/',
       
    54 		datapath = 'preview/data/';
       
    55 	
       
    56 	// load implementation files
       
    57 	// this is done async by the browser engine, so be aware of sync conditions!!
       
    58 	if (version == '1')
       
    59 		loadSAPI(libpath + 'sapi1/');
       
    60 	else if (!version)
       
    61 		loadSAPI();
       
    62 	else
       
    63 		throw 'unsuppported SAPI version!';
       
    64 	
       
    65 	function loadSAPI(path){
       
    66 		var path = path || (libpath + "sapi/");
       
    67 		
       
    68 		// load API
       
    69 		loadScript(path + "AppManager.js");
       
    70 		loadScript(path + "Calendar.js");
       
    71 		loadScript(path + "Contact.js");
       
    72 		loadScript(path + "Landmarks.js");
       
    73 		loadScript(path + "Location.js");
       
    74 		loadScript(path + "Logging.js");
       
    75 		loadScript(path + "MediaManagement.js");
       
    76 		loadScript(path + "Messaging.js");
       
    77 		loadScript(path + "Sensor.js");
       
    78 		loadScript(path + "SysInfo.js");
       
    79 		
       
    80 		// load sample data
       
    81 		loadScript(datapath + "appManager_data.js");
       
    82 		loadScript(datapath + "calendar_data.js");
       
    83 		loadScript(datapath + "contact_data.js");
       
    84 		loadScript(datapath + "landmarks_data.js");
       
    85 		loadScript(datapath + "location_data.js");
       
    86 		loadScript(datapath + "logging_data.js");
       
    87 		loadScript(datapath + "mediaManagement_data.js");
       
    88 		loadScript(datapath + "messaging_data.js");
       
    89 		loadScript(datapath + "sensor_data.js");
       
    90 		loadScript(datapath + "sysInfo_data.js");
       
    91 	}
       
    92 	
       
    93 	function loadScript(src){
       
    94 		var head = document.getElementsByTagName("head")[0] || document.documentElement, 
       
    95 			script = document.createElement("script");
       
    96 		
       
    97 		script.type = "text/javascript";
       
    98 		script.src = src;
       
    99 		head.appendChild(script);
       
   100 	}
       
   101 };
       
   102 
       
   103 (function(){
       
   104 device.implementation.prototype = {
       
   105 	
       
   106 	/**
       
   107 	 * Result object
       
   108 	 * 
       
   109 	 * object returned by API calls
       
   110 	 * 
       
   111 	 * @param {Object} value
       
   112 	 * @param {Integer} code
       
   113 	 * @param {String} msg
       
   114 	 */
       
   115 	Result : function(value, code, msg){
       
   116 		return {
       
   117 			ReturnValue	: value,
       
   118 			ErrorCode	: code || 0,
       
   119 			ErrorMessage: msg || undefined
       
   120 		};
       
   121 	},
       
   122 	
       
   123 	/**
       
   124 	 * AsyncResult object
       
   125 	 * 
       
   126 	 * object returned by API calls with callbacks
       
   127 	 * 
       
   128 	 * @param {Integer} transaction id
       
   129 	 * @param {Integer} code
       
   130 	 * @param {String} msg
       
   131 	 */
       
   132 	AsyncResult : function(id, code, msg){
       
   133 		return {
       
   134 			TransactionID	: id,
       
   135 			ErrorCode		: code || 0,
       
   136 			ErrorMessage	: msg || undefined
       
   137 		};
       
   138 	},
       
   139 	/**
       
   140 	 * ErrorResult object
       
   141 	 * 
       
   142 	 * object returned by API calls when error
       
   143 	 * 
       
   144 	 * @param {Integer} code
       
   145 	 * @param {String} msg
       
   146 	 */
       
   147 	ErrorResult : function(code, msg){
       
   148 		device.implementation.context.debug(code, msg);		
       
   149 		return {
       
   150 			ErrorCode	: code || 0,
       
   151 			ErrorMessage: msg || undefined
       
   152 		};
       
   153 	},
       
   154 	
       
   155 	/**
       
   156 	 * Iterator object
       
   157 	 * 
       
   158 	 * object returned as ReturnValue by some API
       
   159 	 * 
       
   160 	 * @param {Array} data
       
   161 	 */
       
   162 	Iterator : function(data){
       
   163 		var index = 0,
       
   164 			data = data || [];
       
   165 		return {
       
   166 			/**
       
   167 			 * reset
       
   168 			 */
       
   169 			reset : function(){
       
   170 				index = 0;
       
   171 			},
       
   172 			
       
   173 			/**
       
   174 	 		* getNext
       
   175 	 		*/
       
   176 			getNext : function(){
       
   177 				return index < data.length ? data[index++] : undefined;
       
   178 			}
       
   179 		}
       
   180 	},
       
   181 	
       
   182 	
       
   183 	/**
       
   184 	 * internal __methods__
       
   185 	 */
       
   186 	
       
   187 	$break: 	{}, // 'not implemented',
       
   188 	
       
   189 	debug: function() {
       
   190 		if (device.implementation.options.debug && window.console && console.log) 
       
   191 			console.log(arguments);
       
   192 	},
       
   193 	
       
   194 	// notify developer of api action
       
   195 	notify: function(msg){
       
   196 		if (window.console && console.warn)
       
   197 			console.warn('API Notice -- ' + msg);
       
   198 	},
       
   199 	
       
   200 	getData : function(provider){
       
   201 		if (!device.implementation.data[provider])
       
   202 			throw "no data defined for provider '"+provider+"'";
       
   203 		
       
   204 		if (device.implementation.data[provider]['default'])
       
   205 			return device.implementation.data[provider]['default'];
       
   206 		else 
       
   207 			return device.implementation.data[provider]; 
       
   208 	},	
       
   209 	
       
   210 	getUniqueID : function(){
       
   211 		return Number(''+Number(new Date())+ Math.floor(1000*Math.random()));
       
   212 	},
       
   213 	
       
   214 	callAsync : function(object, method, criteria, callback, flag){
       
   215 		flag = flag || false;
       
   216 		var tid = setTimeout(function(){
       
   217 			var result,
       
   218 				eventCode = {completed:2, error:4, progress:9},
       
   219 				code = eventCode.completed;
       
   220 			try{
       
   221 				// call method in object's context
       
   222 				// flag is passed to trigger the method in case of mandatory callback arg
       
   223 				if (flag)
       
   224 					result = method.call(object, criteria, null, flag);
       
   225 				else
       
   226 					result = method.call(object, criteria);
       
   227 			} 
       
   228 			catch(e){
       
   229 				code = eventCode.error;
       
   230 			}
       
   231 			callback(tid, code, result);
       
   232 			
       
   233 		}, device.implementation.options.callbackDelay);
       
   234 		
       
   235 		return this.AsyncResult(tid);
       
   236 	},
       
   237 		
       
   238 	addListener : function(provider, eventType, criteria, callback, handler){
       
   239 		if (!device.implementation.listeners[provider])
       
   240 			device.implementation.listeners[provider] = {};
       
   241 			
       
   242 		var tid = this.getUniqueID();
       
   243 		device.implementation.listeners[provider][eventType] = {
       
   244 			'criteria': criteria,
       
   245 			'callback': callback,
       
   246 			'handler': handler,
       
   247 			'transactionID' : tid
       
   248 		};
       
   249 		return this.AsyncResult(tid);
       
   250 	},
       
   251 
       
   252 	/*
       
   253 	 * specify either eventType or transactionID
       
   254 	 * return true if found and removed
       
   255 	 */
       
   256 	removeListener: function(provider, eventType, transactionID){
       
   257 		transactionID = transactionID || null;
       
   258 		if (transactionID) {
       
   259 			var allEvents = device.implementation.listeners[provider];
       
   260 			for (var i in allEvents) {
       
   261 				var event = allEvents[i];
       
   262 				if (event.transactionID == transactionID) {
       
   263 					device.implementation.listeners[provider][i] = null;
       
   264 					delete device.implementation.listeners[provider][i];
       
   265 					return true;
       
   266 				}
       
   267 			}
       
   268 		}
       
   269 		else 
       
   270 			if (eventType &&
       
   271 			this.hasListener(provider, eventType)) {
       
   272 				device.implementation.listeners[provider][eventType] = null;
       
   273 				delete device.implementation.listeners[provider][eventType];
       
   274 				return true;
       
   275 			}
       
   276 		return false;
       
   277 	},
       
   278 
       
   279 	hasListener: function(provider, eventType) {	
       
   280 		if (!device.implementation.listeners[provider]
       
   281 			|| !device.implementation.listeners[provider][eventType])
       
   282 			return false;
       
   283 				
       
   284 		return true;
       
   285 	},
       
   286 
       
   287 	// pluck object properties as array	
       
   288 	keys: function(obj) {
       
   289 		var keys = [];
       
   290 		for (var p in obj)
       
   291 			keys.push(p);
       
   292 		return keys;
       
   293 	},
       
   294 	
       
   295 	// extend object properties 
       
   296 	extend: function(root, ext) {
       
   297 		for (var p in ext)
       
   298 			root[p] = ext[p];
       
   299 		return root;
       
   300 	},
       
   301 	
       
   302 	// extended text string functionality 
       
   303 	_t: function(str){
       
   304 		
       
   305 		str = typeof str != 'undefined' ? String(str) : '';
       
   306 		return new StringEx(str);
       
   307 	}		
       
   308 };
       
   309 
       
   310 	/**
       
   311 	 * extended String object (available only within device.implementation.context through _t() method)
       
   312 	 */ 
       
   313 	var StringEx = function(str){
       
   314 		// define base String non-transferrable methods!
       
   315 		this.toString = function(){return str;};
       
   316 		this.valueOf = function(){return str.valueOf();};
       
   317 	};
       
   318 	StringEx.prototype = new String();
       
   319 
       
   320 	
       
   321 	/**
       
   322 	 * simple sprintf-type functionality
       
   323 	 * 
       
   324 	 * "string {title} %s and %s and {here} ".arg({title:'T', here:'H'}, 1, 'there')"
       
   325 	 * ==> string T 1 and there and H
       
   326 	 * hash (if present) must be first argument
       
   327 	 *
       
   328 	 * @param {Object} [hash] optional hash to replace {tags}
       
   329 	 * @param {String,Number} data for %s tags
       
   330 	 * @return {String} original string with tags replaced   
       
   331 	 */
       
   332 	StringEx.prototype.arg = function(){
       
   333 	    var pattern = /\%s|\{\w+\}/g;
       
   334 	    var args = arguments, 
       
   335 			len = arguments.length, 
       
   336 			hash = arguments[0],
       
   337 			i = typeof hash == 'object' && !(hash instanceof String) ? 1 : 0;
       
   338 			
       
   339 	    return this.replace(pattern, function(capture){
       
   340 			var key = capture != '%s' && capture.match(/\w+/);
       
   341 			if (key)
       
   342 				return hash && hash[key] ? hash[key] : capture;
       
   343 			else		
       
   344 				return i < len ? args[i++] : capture;
       
   345 		});
       
   346 	}
       
   347 	
       
   348 	/**
       
   349 	 * trim whitespace from beginning and end of string
       
   350 	 * @return {String} trimmed string
       
   351 	 */
       
   352 	StringEx.prototype.trim = function(){
       
   353 		return this.replace(/^\s+/, '').replace(/\s+$/, '');
       
   354 	}
       
   355 	
       
   356 	/**
       
   357 	 * capitalize string
       
   358 	 * @return {String} capitalized string
       
   359 	 */
       
   360 	StringEx.prototype.capitalize = function(){
       
   361     	return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase();
       
   362 	}
       
   363 	
       
   364 })();
       
   365 
       
   366 
       
   367 /*
       
   368  * device.implementation static (class) properties
       
   369  */
       
   370 
       
   371 
       
   372 /**
       
   373  * pointer to current instantiated device.implementation object.
       
   374  * use to access device.implemenation namespace.
       
   375  * 
       
   376  * @see device.implementation 
       
   377  */
       
   378 device.implementation.context = null;	
       
   379 
       
   380 
       
   381 /**
       
   382  * emulation settings options
       
   383  */
       
   384 device.implementation.options = {
       
   385 	
       
   386 	/**
       
   387 	 * callback delay (msec)
       
   388 	 * @property {Number} 
       
   389 	 */
       
   390 	callbackDelay	: 1200,
       
   391 	
       
   392 	/**
       
   393 	 * debug flag
       
   394 	 * @property {Boolean} 
       
   395 	 */
       
   396 	debug			: false,
       
   397 	
       
   398 	/**
       
   399 	 * enabled flag
       
   400 	 * @property {Boolean} 
       
   401 	 */
       
   402 	enabled			: true
       
   403 };
       
   404 
       
   405 
       
   406 /**
       
   407  * store of interfaces (objects) in the current device implementation.
       
   408  * format: [provider][interface]
       
   409  * 
       
   410  * @property {Object} 
       
   411  */
       
   412 device.implementation.interfaces = {};
       
   413 
       
   414 
       
   415 /**
       
   416  * store of data objects defined for current implementation.
       
   417  * data is added useing the loadData method. 
       
   418  * 
       
   419  * @property {Object} format depends on data
       
   420  */
       
   421 device.implementation.data = {};
       
   422 
       
   423 
       
   424 /**
       
   425  * store of event listeners
       
   426  * format: [provider][eventType]
       
   427  */
       
   428 device.implementation.listeners = {}; 
       
   429 
       
   430 
       
   431 /*
       
   432  * device.implementation static (class) methods
       
   433  */
       
   434 
       
   435 
       
   436 /**
       
   437  * Add a service provider to device implementation
       
   438  * 
       
   439  * @param {string} provider Name of service provider, eg, "Service.Calendar"
       
   440  * @param {string} Interface Name of interface, eg, "IDataService"
       
   441  * @param {Object} serviceProvider Service object
       
   442  * @return  none
       
   443  */
       
   444 device.implementation.extend = function(provider, Interface, serviceProvider){
       
   445 
       
   446 	if (!device.implementation.interfaces[provider])
       
   447 		device.implementation.interfaces[provider] = {}; 
       
   448 	
       
   449 	device.implementation.interfaces[provider][Interface] = serviceProvider;
       
   450 };
       
   451 
       
   452 
       
   453 /**
       
   454  * Internal implementation to return a service provider interface object
       
   455  * 
       
   456  * @param {String} provider  Service provider name 
       
   457  * @param {String} Interface	Provider interface name
       
   458  * @exception {String} exception thrown if provider or interface is not implemented 
       
   459  * @return {Object} the service provider interface object or 'undefined'
       
   460  */	
       
   461 device.implementation.getInterface = function(provider, Interface){
       
   462 		
       
   463 	if (device.implementation.interfaces[provider] 
       
   464 		&& typeof device.implementation.interfaces[provider][Interface] == 'object') 
       
   465 	{
       
   466 		var service = new Object();
       
   467 		service[Interface] = device.implementation.interfaces[provider][Interface];
       
   468 		return service;
       
   469 	}
       
   470 	else
       
   471 		throw 'Error: unknown error'; 
       
   472 };
       
   473 
       
   474 
       
   475 /**
       
   476  * Loads data to the data store
       
   477  * 
       
   478  * @param {String} provider  Service provider name 
       
   479  * @param {String} type Data name/label
       
   480  * @param {Function,Object,Array} dataFactory Function to generate the data object, or array/object
       
   481  * @return none
       
   482  */
       
   483 device.implementation.loadData = function(provider, type, dataFactory){
       
   484 
       
   485 	type = type || 'default';
       
   486 	if (!device.implementation.data[provider]) 
       
   487 		device.implementation.data[provider] = {};
       
   488 		
       
   489 	device.implementation.data[provider][type] = 
       
   490 		typeof dataFactory == 'function' 
       
   491 			? dataFactory()
       
   492 			: dataFactory;
       
   493 };
       
   494 
       
   495 
       
   496 /**
       
   497  * trigger an event listener
       
   498  * 
       
   499  * @param {String} provider Service provider name
       
   500  * @param {String} eventType event type 
       
   501  * @param {Variant} data ReturnValue for callback function 
       
   502  */
       
   503 device.implementation.triggerListener = function(provider, eventType, data){
       
   504 
       
   505 	if (!device.implementation.context.hasListener(provider, eventType)) {
       
   506 		device.implementation.context.notify('no listener defined for provider=' + provider + ', eventType=' + eventType);
       
   507 		return;
       
   508 	}
       
   509 	var listener = device.implementation.listeners[provider][eventType];
       
   510 
       
   511 	// call the provider's handler
       
   512 	listener.handler(listener.transactionID, listener.criteria, listener.callback, data);
       
   513 }
       
   514 
       
   515 
       
   516 
       
   517 /*
       
   518  * ERROR CODES
       
   519  */
       
   520 device.implementation.ERR_SUCCESS			 		= 0;
       
   521 device.implementation.ERR_INVALID_SERVICE_ARGUMENT	= 1000;
       
   522 device.implementation.ERR_UNKNOWN_ARGUMENT_NAME		= 1001;
       
   523 device.implementation.ERR_BAD_ARGUMENT_TYPE			= 1002;
       
   524 device.implementation.ERR_MISSING_ARGUMENT 			= 1003;
       
   525 device.implementation.ERR_SERVICE_NOT_SUPPORTED		= 1004;
       
   526 device.implementation.ERR_SERVICE_IN_USE 			= 1005;
       
   527 device.implementation.ERR_SERVICE_NOT_READY 		= 1006;
       
   528 device.implementation.ERR_NO_MEMORY		 			= 1007;
       
   529 device.implementation.ERR_HARDWARE_NOT_AVAILABLE	= 1008;
       
   530 device.implementation.ERR_SEVER_BUSY				= 1009;
       
   531 device.implementation.ERR_ENTRY_EXISTS				= 1010;
       
   532 device.implementation.ERR_ACCESS_DENIED				= 1011;
       
   533 device.implementation.ERR_NOT_FOUND					= 1012;
       
   534 device.implementation.ERR_UNKNOWN_FORMAT			= 1013;
       
   535 device.implementation.ERR_GENERAL_ERROR				= 1014;
       
   536 device.implementation.ERR_CANCEL_SUCCESS			= 1015;
       
   537 device.implementation.ERR_SERVICE_TIMEDOUT			= 1016;
       
   538 device.implementation.ERR_PATH_NOT_FOUND			= 1017;
       
   539 
       
   540 
       
   541 
       
   542 // instantiate device imlementation
       
   543 new device.implementation();
       
   544