mypackage_wrt/preview/script/lib/device.js
changeset 42 20be4dd42b12
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mypackage_wrt/preview/script/lib/device.js	Fri Apr 30 15:01:03 2010 +0100
@@ -0,0 +1,544 @@
+/**
+ * device.js
+ * 
+ * Nokia Web Runtime Service API emulation 
+ * WRT v1.1
+ * 
+ * Copyright 2009 Nokia Corporation. All rights reserved.
+*/
+
+
+/**
+ * device object. entry point to device service API (SAPI)
+ */
+var device = {
+	/**
+	 * device API public method
+	 * 
+	 * @method
+	 * @param {string} provider Name of service provider, eg, "Service.Calendar"
+	 * @param {string} Interface Name of interface, eg, "IDataSource"
+	 * @return {Object} service object  
+	 */
+	getServiceObject: function(provider, Interface){
+
+		if (!device.implementation.context)
+			throw 'device implementation object not instantiated!'
+
+		if (device.implementation.options.enabled) 
+			return device.implementation.getInterface(provider, Interface);
+		else {
+			device.implementation.context.notify('device SAPI is disabled.');
+			throw 'device not defined!';
+		}
+	}
+};
+
+
+
+/**
+ * implementation of device emulation mode
+ * 
+ * @param {String} 		version - version number (default: current version)
+ * @return {Object} 	returns new implementation context object 
+ * @constructor 		
+ */
+device.implementation = function(version){
+
+	this.version = version || '';
+	
+	// set context to current object
+	device.implementation.context = this;	
+
+	var libpath = 'preview/script/lib/',
+		datapath = 'preview/data/';
+	
+	// load implementation files
+	// this is done async by the browser engine, so be aware of sync conditions!!
+	if (version == '1')
+		loadSAPI(libpath + 'sapi1/');
+	else if (!version)
+		loadSAPI();
+	else
+		throw 'unsuppported SAPI version!';
+	
+	function loadSAPI(path){
+		var path = path || (libpath + "sapi/");
+		
+		// load API
+		loadScript(path + "AppManager.js");
+		loadScript(path + "Calendar.js");
+		loadScript(path + "Contact.js");
+		loadScript(path + "Landmarks.js");
+		loadScript(path + "Location.js");
+		loadScript(path + "Logging.js");
+		loadScript(path + "MediaManagement.js");
+		loadScript(path + "Messaging.js");
+		loadScript(path + "Sensor.js");
+		loadScript(path + "SysInfo.js");
+		
+		// load sample data
+		loadScript(datapath + "appManager_data.js");
+		loadScript(datapath + "calendar_data.js");
+		loadScript(datapath + "contact_data.js");
+		loadScript(datapath + "landmarks_data.js");
+		loadScript(datapath + "location_data.js");
+		loadScript(datapath + "logging_data.js");
+		loadScript(datapath + "mediaManagement_data.js");
+		loadScript(datapath + "messaging_data.js");
+		loadScript(datapath + "sensor_data.js");
+		loadScript(datapath + "sysInfo_data.js");
+	}
+	
+	function loadScript(src){
+		var head = document.getElementsByTagName("head")[0] || document.documentElement, 
+			script = document.createElement("script");
+		
+		script.type = "text/javascript";
+		script.src = src;
+		head.appendChild(script);
+	}
+};
+
+(function(){
+device.implementation.prototype = {
+	
+	/**
+	 * Result object
+	 * 
+	 * object returned by API calls
+	 * 
+	 * @param {Object} value
+	 * @param {Integer} code
+	 * @param {String} msg
+	 */
+	Result : function(value, code, msg){
+		return {
+			ReturnValue	: value,
+			ErrorCode	: code || 0,
+			ErrorMessage: msg || undefined
+		};
+	},
+	
+	/**
+	 * AsyncResult object
+	 * 
+	 * object returned by API calls with callbacks
+	 * 
+	 * @param {Integer} transaction id
+	 * @param {Integer} code
+	 * @param {String} msg
+	 */
+	AsyncResult : function(id, code, msg){
+		return {
+			TransactionID	: id,
+			ErrorCode		: code || 0,
+			ErrorMessage	: msg || undefined
+		};
+	},
+	/**
+	 * ErrorResult object
+	 * 
+	 * object returned by API calls when error
+	 * 
+	 * @param {Integer} code
+	 * @param {String} msg
+	 */
+	ErrorResult : function(code, msg){
+		device.implementation.context.debug(code, msg);		
+		return {
+			ErrorCode	: code || 0,
+			ErrorMessage: msg || undefined
+		};
+	},
+	
+	/**
+	 * Iterator object
+	 * 
+	 * object returned as ReturnValue by some API
+	 * 
+	 * @param {Array} data
+	 */
+	Iterator : function(data){
+		var index = 0,
+			data = data || [];
+		return {
+			/**
+			 * reset
+			 */
+			reset : function(){
+				index = 0;
+			},
+			
+			/**
+	 		* getNext
+	 		*/
+			getNext : function(){
+				return index < data.length ? data[index++] : undefined;
+			}
+		}
+	},
+	
+	
+	/**
+	 * internal __methods__
+	 */
+	
+	$break: 	{}, // 'not implemented',
+	
+	debug: function() {
+		if (device.implementation.options.debug && window.console && console.log) 
+			console.log(arguments);
+	},
+	
+	// notify developer of api action
+	notify: function(msg){
+		if (window.console && console.warn)
+			console.warn('API Notice -- ' + msg);
+	},
+	
+	getData : function(provider){
+		if (!device.implementation.data[provider])
+			throw "no data defined for provider '"+provider+"'";
+		
+		if (device.implementation.data[provider]['default'])
+			return device.implementation.data[provider]['default'];
+		else 
+			return device.implementation.data[provider]; 
+	},	
+	
+	getUniqueID : function(){
+		return Number(''+Number(new Date())+ Math.floor(1000*Math.random()));
+	},
+	
+	callAsync : function(object, method, criteria, callback, flag){
+		flag = flag || false;
+		var tid = setTimeout(function(){
+			var result,
+				eventCode = {completed:2, error:4, progress:9},
+				code = eventCode.completed;
+			try{
+				// call method in object's context
+				// flag is passed to trigger the method in case of mandatory callback arg
+				if (flag)
+					result = method.call(object, criteria, null, flag);
+				else
+					result = method.call(object, criteria);
+			} 
+			catch(e){
+				code = eventCode.error;
+			}
+			callback(tid, code, result);
+			
+		}, device.implementation.options.callbackDelay);
+		
+		return this.AsyncResult(tid);
+	},
+		
+	addListener : function(provider, eventType, criteria, callback, handler){
+		if (!device.implementation.listeners[provider])
+			device.implementation.listeners[provider] = {};
+			
+		var tid = this.getUniqueID();
+		device.implementation.listeners[provider][eventType] = {
+			'criteria': criteria,
+			'callback': callback,
+			'handler': handler,
+			'transactionID' : tid
+		};
+		return this.AsyncResult(tid);
+	},
+
+	/*
+	 * specify either eventType or transactionID
+	 * return true if found and removed
+	 */
+	removeListener: function(provider, eventType, transactionID){
+		transactionID = transactionID || null;
+		if (transactionID) {
+			var allEvents = device.implementation.listeners[provider];
+			for (var i in allEvents) {
+				var event = allEvents[i];
+				if (event.transactionID == transactionID) {
+					device.implementation.listeners[provider][i] = null;
+					delete device.implementation.listeners[provider][i];
+					return true;
+				}
+			}
+		}
+		else 
+			if (eventType &&
+			this.hasListener(provider, eventType)) {
+				device.implementation.listeners[provider][eventType] = null;
+				delete device.implementation.listeners[provider][eventType];
+				return true;
+			}
+		return false;
+	},
+
+	hasListener: function(provider, eventType) {	
+		if (!device.implementation.listeners[provider]
+			|| !device.implementation.listeners[provider][eventType])
+			return false;
+				
+		return true;
+	},
+
+	// pluck object properties as array	
+	keys: function(obj) {
+		var keys = [];
+		for (var p in obj)
+			keys.push(p);
+		return keys;
+	},
+	
+	// extend object properties 
+	extend: function(root, ext) {
+		for (var p in ext)
+			root[p] = ext[p];
+		return root;
+	},
+	
+	// extended text string functionality 
+	_t: function(str){
+		
+		str = typeof str != 'undefined' ? String(str) : '';
+		return new StringEx(str);
+	}		
+};
+
+	/**
+	 * extended String object (available only within device.implementation.context through _t() method)
+	 */ 
+	var StringEx = function(str){
+		// define base String non-transferrable methods!
+		this.toString = function(){return str;};
+		this.valueOf = function(){return str.valueOf();};
+	};
+	StringEx.prototype = new String();
+
+	
+	/**
+	 * simple sprintf-type functionality
+	 * 
+	 * "string {title} %s and %s and {here} ".arg({title:'T', here:'H'}, 1, 'there')"
+	 * ==> string T 1 and there and H
+	 * hash (if present) must be first argument
+	 *
+	 * @param {Object} [hash] optional hash to replace {tags}
+	 * @param {String,Number} data for %s tags
+	 * @return {String} original string with tags replaced   
+	 */
+	StringEx.prototype.arg = function(){
+	    var pattern = /\%s|\{\w+\}/g;
+	    var args = arguments, 
+			len = arguments.length, 
+			hash = arguments[0],
+			i = typeof hash == 'object' && !(hash instanceof String) ? 1 : 0;
+			
+	    return this.replace(pattern, function(capture){
+			var key = capture != '%s' && capture.match(/\w+/);
+			if (key)
+				return hash && hash[key] ? hash[key] : capture;
+			else		
+				return i < len ? args[i++] : capture;
+		});
+	}
+	
+	/**
+	 * trim whitespace from beginning and end of string
+	 * @return {String} trimmed string
+	 */
+	StringEx.prototype.trim = function(){
+		return this.replace(/^\s+/, '').replace(/\s+$/, '');
+	}
+	
+	/**
+	 * capitalize string
+	 * @return {String} capitalized string
+	 */
+	StringEx.prototype.capitalize = function(){
+    	return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase();
+	}
+	
+})();
+
+
+/*
+ * device.implementation static (class) properties
+ */
+
+
+/**
+ * pointer to current instantiated device.implementation object.
+ * use to access device.implemenation namespace.
+ * 
+ * @see device.implementation 
+ */
+device.implementation.context = null;	
+
+
+/**
+ * emulation settings options
+ */
+device.implementation.options = {
+	
+	/**
+	 * callback delay (msec)
+	 * @property {Number} 
+	 */
+	callbackDelay	: 1200,
+	
+	/**
+	 * debug flag
+	 * @property {Boolean} 
+	 */
+	debug			: false,
+	
+	/**
+	 * enabled flag
+	 * @property {Boolean} 
+	 */
+	enabled			: true
+};
+
+
+/**
+ * store of interfaces (objects) in the current device implementation.
+ * format: [provider][interface]
+ * 
+ * @property {Object} 
+ */
+device.implementation.interfaces = {};
+
+
+/**
+ * store of data objects defined for current implementation.
+ * data is added useing the loadData method. 
+ * 
+ * @property {Object} format depends on data
+ */
+device.implementation.data = {};
+
+
+/**
+ * store of event listeners
+ * format: [provider][eventType]
+ */
+device.implementation.listeners = {}; 
+
+
+/*
+ * device.implementation static (class) methods
+ */
+
+
+/**
+ * Add a service provider to device implementation
+ * 
+ * @param {string} provider Name of service provider, eg, "Service.Calendar"
+ * @param {string} Interface Name of interface, eg, "IDataService"
+ * @param {Object} serviceProvider Service object
+ * @return  none
+ */
+device.implementation.extend = function(provider, Interface, serviceProvider){
+
+	if (!device.implementation.interfaces[provider])
+		device.implementation.interfaces[provider] = {}; 
+	
+	device.implementation.interfaces[provider][Interface] = serviceProvider;
+};
+
+
+/**
+ * Internal implementation to return a service provider interface object
+ * 
+ * @param {String} provider  Service provider name 
+ * @param {String} Interface	Provider interface name
+ * @exception {String} exception thrown if provider or interface is not implemented 
+ * @return {Object} the service provider interface object or 'undefined'
+ */	
+device.implementation.getInterface = function(provider, Interface){
+		
+	if (device.implementation.interfaces[provider] 
+		&& typeof device.implementation.interfaces[provider][Interface] == 'object') 
+	{
+		var service = new Object();
+		service[Interface] = device.implementation.interfaces[provider][Interface];
+		return service;
+	}
+	else
+		throw 'Error: unknown error'; 
+};
+
+
+/**
+ * Loads data to the data store
+ * 
+ * @param {String} provider  Service provider name 
+ * @param {String} type Data name/label
+ * @param {Function,Object,Array} dataFactory Function to generate the data object, or array/object
+ * @return none
+ */
+device.implementation.loadData = function(provider, type, dataFactory){
+
+	type = type || 'default';
+	if (!device.implementation.data[provider]) 
+		device.implementation.data[provider] = {};
+		
+	device.implementation.data[provider][type] = 
+		typeof dataFactory == 'function' 
+			? dataFactory()
+			: dataFactory;
+};
+
+
+/**
+ * trigger an event listener
+ * 
+ * @param {String} provider Service provider name
+ * @param {String} eventType event type 
+ * @param {Variant} data ReturnValue for callback function 
+ */
+device.implementation.triggerListener = function(provider, eventType, data){
+
+	if (!device.implementation.context.hasListener(provider, eventType)) {
+		device.implementation.context.notify('no listener defined for provider=' + provider + ', eventType=' + eventType);
+		return;
+	}
+	var listener = device.implementation.listeners[provider][eventType];
+
+	// call the provider's handler
+	listener.handler(listener.transactionID, listener.criteria, listener.callback, data);
+}
+
+
+
+/*
+ * ERROR CODES
+ */
+device.implementation.ERR_SUCCESS			 		= 0;
+device.implementation.ERR_INVALID_SERVICE_ARGUMENT	= 1000;
+device.implementation.ERR_UNKNOWN_ARGUMENT_NAME		= 1001;
+device.implementation.ERR_BAD_ARGUMENT_TYPE			= 1002;
+device.implementation.ERR_MISSING_ARGUMENT 			= 1003;
+device.implementation.ERR_SERVICE_NOT_SUPPORTED		= 1004;
+device.implementation.ERR_SERVICE_IN_USE 			= 1005;
+device.implementation.ERR_SERVICE_NOT_READY 		= 1006;
+device.implementation.ERR_NO_MEMORY		 			= 1007;
+device.implementation.ERR_HARDWARE_NOT_AVAILABLE	= 1008;
+device.implementation.ERR_SEVER_BUSY				= 1009;
+device.implementation.ERR_ENTRY_EXISTS				= 1010;
+device.implementation.ERR_ACCESS_DENIED				= 1011;
+device.implementation.ERR_NOT_FOUND					= 1012;
+device.implementation.ERR_UNKNOWN_FORMAT			= 1013;
+device.implementation.ERR_GENERAL_ERROR				= 1014;
+device.implementation.ERR_CANCEL_SUCCESS			= 1015;
+device.implementation.ERR_SERVICE_TIMEDOUT			= 1016;
+device.implementation.ERR_PATH_NOT_FOUND			= 1017;
+
+
+
+// instantiate device imlementation
+new device.implementation();
+