1 // Copyright (c) 2014 Intel Corporation. All rights reserved.
2 // Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
6 //Object xwalk.JSON - guaranteed to not being modified by the application programmer
7 var JSON_ = { stringify: JSON.stringify, parse: JSON.parse };
11 var _enableJsLogs = false;
14 if (typeof window !== 'undefined') {
16 } else if (typeof global !== 'undefined') {
18 } else if (typeof self !== 'undefined') {
23 * @brief CommonListenerManager constructor function.
24 * @param nativeMgr NativeManager handle.
25 * @param managerName Name which will be used as native listener name.
26 * @param onIdNotFound Callback without arguments invoked when trying to remove not
27 * existing listener. If unspecified it is replaced by empty
30 var CommonListenerManager = function(nativeMgr, managerName, onIdNotFound) {
33 this.numberOfListeners = 0;
34 this.name = managerName;
35 this.native = nativeMgr;
36 this.hasNativeListener = false;
37 if (onIdNotFound === undefined) {
38 this.idNotFoundBehavior = function() {};
40 this.idNotFoundBehavior = onIdNotFound;
45 * @brief Callback for native listener, which invokes all existing listeners.
46 * @param msg native Arguments object for native listener callback.
48 CommonListenerManager.prototype.onListenerCalled = function(msg) {
49 for (var watchId in this.listeners) {
50 if (this.listeners.hasOwnProperty(watchId)) {
51 this.listeners[watchId](msg, watchId);
57 * @brief Registers new listener.
58 * @param callback Callback function taking single argument.
59 * @retval integer listener id. Use it later to remove listener.
61 CommonListenerManager.prototype.addListener = function(callback) {
62 if (!this.hasNativeListener) {
63 this.native.addListener(this.name, this.onListenerCalled.bind(this));
64 this.hasNativeListener = true;
66 var id = this.nextId++;
67 this.listeners[id] = callback;
68 this.numberOfListeners++;
73 * @brief Remove previously registered listener.
75 * If listener for given id is not found, onIdNotFound callback is invoked.
77 * @param watchId Listener id returned by addListener.
78 * @retval onIdNotFoundCallback return value.
80 CommonListenerManager.prototype.removeListener = function(watchId) {
81 if (this.listeners.hasOwnProperty(watchId)) {
82 delete this.listeners[watchId];
83 this.numberOfListeners--;
84 if (this.numberOfListeners == 0) {
85 this.native.removeListener(this.name);
86 this.hasNativeListener = false;
90 return this.idNotFoundBehavior();
94 var DateConverter = function() {};
96 DateConverter.prototype.toTZDate = function(v, isAllDay) {
97 if (typeof v === 'number') {
104 if (!(v instanceof _global.Object)) {
109 return new tizen.TZDate(
120 return new tizen.TZDate(new Date(v.UTCTimestamp * 1000));
124 DateConverter.prototype.fromTZDate = function(v) {
125 if (!tizen.TZDate || !(v instanceof tizen.TZDate)) {
130 year: v.getFullYear(),
133 timezone: v.getTimezone(),
134 UTCTimestamp: v._utcTimestamp / 1000
138 var _dateConverter = new DateConverter();
141 * Cynara(since tizen 3.0) only support native privilege.
142 * simply web privilege convert native privilege for checking access.
145 ACCOUNT_READ: 'http://tizen.org/privilege/account.read',
146 ACCOUNT_WRITE: 'http://tizen.org/privilege/account.write',
147 ALARM: 'http://tizen.org/privilege/alarm.get',
148 APPLICATION_INFO: 'http://tizen.org/privilege/application.info',
149 APPLICATION_LAUNCH: 'http://tizen.org/privilege/application.launch',
150 APPMANAGER_CERTIFICATE: 'http://tizen.org/privilege/appmanager.certificate',
151 APPMANAGER_KILL: 'http://tizen.org/privilege/appmanager.kill',
152 BLUETOOTH_ADMIN: 'http://tizen.org/privilege/bluetooth.admin',
153 BLUETOOTH_GAP: 'http://tizen.org/privilege/bluetooth.gap',
154 BLUETOOTH_HEALTH: 'http://tizen.org/privilege/bluetooth.health',
155 BLUETOOTH_SPP: 'http://tizen.org/privilege/bluetooth.spp',
156 BLUETOOTHMANAGER: 'http://tizen.org/privilege/bluetoothmanager',
157 BLUETOOTH: 'http://tizen.org/privilege/bluetooth',
158 CALENDAR_READ: 'http://tizen.org/privilege/calendar.read',
159 CALENDAR_WRITE: 'http://tizen.org/privilege/calendar.write',
160 CALLHISTORY_READ: 'http://tizen.org/privilege/callhistory.read',
161 CALLHISTORY_WRITE: 'http://tizen.org/privilege/callhistory.write',
162 CONTACT_READ: 'http://tizen.org/privilege/contact.read',
163 CONTACT_WRITE: 'http://tizen.org/privilege/contact.write',
164 CONTENT_READ: 'http://tizen.org/privilege/content.read',
165 CONTENT_WRITE: 'http://tizen.org/privilege/content.write',
166 DATACONTROL_CONSUMER: 'http://tizen.org/privilege/datacontrol.consumer',
167 DATASYNC: 'http://tizen.org/privilege/datasync',
168 DOWNLOAD: 'http://tizen.org/privilege/download',
169 FILESYSTEM_READ: 'http://tizen.org/privilege/filesystem.read',
170 FILESYSTEM_WRITE: 'http://tizen.org/privilege/filesystem.write',
171 HAPTIC: 'http://tizen.org/privilege/haptic',
172 HEALTHINFO: 'http://tizen.org/privilege/healthinfo',
173 INTERNET: 'http://tizen.org/privilege/internet',
174 LED: 'http://tizen.org/privilege/led',
175 LOCATION: 'http://tizen.org/privilege/location',
176 MEDIACONTROLLER_SERVER: 'http://tizen.org/privilege/mediacontroller.server',
177 MEDIACONTROLLER_CLIENT: 'http://tizen.org/privilege/mediacontroller.client',
178 MESSAGING_READ: 'http://tizen.org/privilege/messaging.read',
179 MESSAGING_WRITE: 'http://tizen.org/privilege/messaging.write',
180 NETWORKBEARERSELECTION: 'http://tizen.org/privilege/networkbearerselection',
181 NFC_ADMIN: 'http://tizen.org/privilege/nfc.admin',
182 NFC_CARDEMULATION: 'http://tizen.org/privilege/nfc.cardemulation',
183 NFC_COMMON: 'http://tizen.org/privilege/nfc.common',
184 NFC_P2P: 'http://tizen.org/privilege/nfc.p2p',
185 NFC_TAG: 'http://tizen.org/privilege/nfc.tag',
186 NOTIFICATION: 'http://tizen.org/privilege/notification',
187 PACKAGE_INFO: 'http://tizen.org/privilege/packagemanager.info',
188 PACKAGEMANAGER_INSTALL: 'http://tizen.org/privilege/packagemanager.install',
189 POWER: 'http://tizen.org/privilege/power',
190 PUSH: 'http://tizen.org/privilege/push',
191 SECUREELEMENT: 'http://tizen.org/privilege/secureelement',
192 SETTING_ADMIN: 'http://tizen.org/privilege/systemsettings.admin',
193 SETTING: 'http://tizen.org/privilege/setting',
194 SYSTEM: 'http://tizen.org/privilege/system',
195 SYSTEMMANAGER: 'http://tizen.org/privilege/systemmanager',
196 TELEPHONY: 'http://tizen.org/privilege/telephony',
197 VOLUME_SET: 'http://tizen.org/privilege/volume.set',
198 WEBSETTING: 'http://tizen.org/privilege/websetting',
199 TV_INPUT_DEVICE: 'http://tizen.org/privilege/tv.inputdevice'
202 Object.freeze(_privilege);
206 Object.defineProperty(this, 'privilege', {
214 Utils.prototype.error = console.error.bind(console);
215 Utils.prototype.warn = console.warn.bind(console);
216 Utils.prototype.log = _enableJsLogs ? console.log.bind(console) : function() {};
217 var appVersion = undefined; // Used to cache required version of an app
220 * @param {string} msg Message to be logged on warn level.
221 * @param {string} deprecationVersion Version from which the deprecation log must appear.
223 Utils.prototype.deprecationWarn = function(msg, deprecationVersion) {
224 // For public code, warning should be always shown
225 this.warn('DEPRECATION WARNING: ' + msg);
228 if (console.assert) {
229 Utils.prototype.assert = console.assert.bind(console);
231 Utils.prototype.assert = function() {
232 if (false === arguments[0]) {
233 console.error('Assertion failed: ', Array.prototype.slice.call(arguments, 1));
238 Utils.prototype.global = _global;
240 Utils.prototype.repackFilter = function(filter) {
241 if (filter instanceof tizen.AttributeFilter) {
243 filterType: 'AttributeFilter',
244 attributeName: filter.attributeName,
245 matchFlag: filter.matchFlag,
246 matchValue: _dateConverter.fromTZDate(filter.matchValue)
249 if (filter instanceof tizen.AttributeRangeFilter) {
251 filterType: 'AttributeRangeFilter',
252 attributeName: filter.attributeName,
253 initialValue: _dateConverter.fromTZDate(filter.initialValue),
254 endValue: _dateConverter.fromTZDate(filter.endValue)
257 if (filter instanceof tizen.CompositeFilter) {
259 var filters = filter.filters;
261 for (var i = 0; i < filters.length; ++i) {
262 _f.push(this.repackFilter(filters[i]));
266 filterType: 'CompositeFilter',
275 var apiVersion = null;
276 Utils.prototype.getPkgApiVersion = function() {
280 var result = native_.callSync('UtilsGetPkgApiVersion');
281 if (native_.isFailure(result)) {
282 throw native_.getErrorObject(result);
284 apiVersion = native_.getResultObject(result);
288 var isPrivilege = function(toCheck) {
289 if (Object.values(_privilege).indexOf(toCheck) < 0) {
295 var cachedPrivileges = {};
296 Utils.prototype.checkPrivilegeAccess = function(privilege) {
297 if (!isPrivilege(privilege)) {
299 'Privilege ' + privilege + ' does not exist. Please fix your code.'
301 throw new WebAPIException(WebAPIException.SECURITY_ERR);
304 if (cachedPrivileges[privilege]) {
307 var result = native_.callSync('UtilsCheckPrivilegeAccess', {
308 privilege: _toString(privilege)
310 var isFailure = native_.isFailure(result);
311 cachedPrivileges[privilege] = !isFailure;
313 throw native_.getErrorObject(result);
317 Utils.prototype.isAppVersionEarlierThan = function(ver) {
318 var app_ver = this.getPkgApiVersion();
320 var arr_ver = ver.split('.'); // reference version
321 var arr_app_ver = app_ver.split('.'); // application version
326 var length = Math.min(arr_ver.length, arr_app_ver.length);
327 for (i = 0; i < length; i++) {
328 num_ver = parseInt(arr_ver[i]);
329 num_app = parseInt(arr_app_ver[i]);
330 if (num_app < num_ver) {
332 } else if (num_app > num_ver) {
337 if (arr_ver.length > arr_app_ver.length) {
343 Utils.prototype.checkPrivilegeAccess4Ver = function(new_ver, new_priv, old_priv) {
344 if (!this.isAppVersionEarlierThan(new_ver)) {
345 this.checkPrivilegeAccess(new_priv);
346 } else if (old_priv != undefined) {
347 this.checkPrivilegeAccess(old_priv);
351 Utils.prototype.checkBackwardCompabilityPrivilegeAccess = function(
355 var result = native_.callSync('UtilsCheckBackwardCompabilityPrivilegeAccess', {
356 current_privilege: _toString(current_privilege),
357 previous_privilege: _toString(previous_privilege)
360 if (native_.isFailure(result)) {
361 throw native_.getErrorObject(result);
365 Utils.prototype.checkProfile = function() {
366 var result = native_.callSync('UtilsCheckProfile', {});
368 return native_.getResultObject(result);
371 Utils.prototype.printDeprecationWarningFor = function(name, replacement) {
372 if (_type.isUndefined(replacement)) {
374 'DEPRECATION WARNING: ' +
376 ' is deprecated and using it is not recommended.'
380 'DEPRECATION WARNING: ' +
382 ' is deprecated and using it is not recommended.' +
391 * Pass array-like object of numbers (Array, Uint8Array, etc.), returns string.
392 * Each char has codepoint equal to value from array cropped with & 0xFF
393 * Useful for passing data through crosswalk.
395 Utils.prototype.ArrayToString = function(data) {
397 var len = data.length;
398 for (var i = 0; i < len; i++) {
399 output += String.fromCharCode(data[i] & 0xff); // conversion to octet
405 * Create new array-like object of numbers: UTF-16 char codes from string.
406 * As type pass Array, Uint8Array, etc.
407 * Useful for passing data through crosswalk.
409 Utils.prototype.StringToArray = function(str, type) {
410 var len = str.length;
411 var output = new type(len);
412 for (var i = 0; i < len; i++) {
413 output[i] = str.charCodeAt(i);
418 /////////////////////////////////////////////////////////////////////////////
420 var Type = function() {};
422 Type.prototype.isBoolean = function(obj) {
423 return typeof obj === 'boolean';
426 Type.prototype.isObject = function(obj) {
427 return null !== obj && typeof obj === 'object' && !this.isArray(obj);
430 Type.prototype.isArray = function(obj) {
431 return Array.isArray(obj);
434 Type.prototype.isOctet = function(value) {
435 return Number.isInteger(value) && 0 <= value && value <= 255;
438 Type.prototype.isByteStream = function(value) {
439 return value instanceof Uint8Array;
442 Type.prototype.isByteStreamArray = function(value) {
443 return Array.isArray(value) && value.every(this.isByteStream);
446 Type.prototype.isLegacyByteStream = function(value) {
447 return Array.isArray(value) && value.every(this.isOctet);
450 Type.prototype.isLegacyByteStreamArray = function(value) {
452 Array.isArray(value) &&
455 return this.isLegacyByteStream(x);
461 Type.prototype.isFunction = function(obj) {
462 return typeof obj === 'function';
465 Type.prototype.isNumber = function(obj) {
466 return typeof obj === 'number';
469 Type.prototype.isString = function(obj) {
470 return typeof obj === 'string';
473 Type.prototype.isStringArray = function(value) {
474 return Array.isArray(value) && value.every(this.isString);
477 Type.prototype.isDate = function(obj) {
478 return obj instanceof Date;
481 Type.prototype.isNull = function(obj) {
485 Type.prototype.isNullOrUndefined = function(obj) {
486 return obj === null || obj === undefined;
489 Type.prototype.isUndefined = function(obj) {
490 return obj === void 0;
493 Type.prototype.isA = function(obj, type) {
494 var clas = Object.prototype.toString.call(obj).slice(8, -1);
495 return obj !== undefined && obj !== null && clas === type;
498 Type.prototype.isEmptyObject = function(obj) {
499 for (var property in obj) {
500 if (obj.hasOwnProperty(property)) {
507 Type.prototype.hasProperty = function(obj, prop) {
511 Type.prototype.arrayContains = function(arr, value) {
512 return arr.indexOf(value) > -1;
515 Type.prototype.getValues = function(obj) {
517 for (var key in obj) {
518 if (obj.hasOwnProperty(key)) {
525 var _type = new Type();
527 /////////////////////////////////////////////////////////////////////////////
529 var Converter = function() {};
531 function _nullableGeneric(func, nullable, val) {
532 if (_type.isNull(val) && nullable === true) {
535 return func.apply(null, [].slice.call(arguments, 2));
539 function _toBoolean(val) {
543 Converter.prototype.toBoolean = function(val, nullable) {
544 return _nullableGeneric(_toBoolean, nullable, val);
547 function _toLong(val) {
548 var ret = parseInt(val);
549 return isNaN(ret) ? (val === true ? 1 : 0) : ret;
552 Converter.prototype.toLong = function(val, nullable) {
553 return _nullableGeneric(_toLong, nullable, val);
556 function _toLongLong(val) {
557 // According to WebIDL specification this will not be a precise representation
558 // of requested val. We're converting the val to signed long and then pass it
559 // to C++ to get the value in required range.
560 return native_.getResultObject(
561 native_.callSync('UtilsToLongLong', {
567 Converter.prototype.toLongLong = function(val, nullable) {
568 return _nullableGeneric(_toLongLong, nullable, val);
571 function _toUnsignedLong(val) {
572 return _toLong(val) >>> 0;
575 Converter.prototype.toUnsignedLong = function(val, nullable) {
576 return _nullableGeneric(_toUnsignedLong, nullable, val);
579 function _toUnsignedLongLong(val) {
580 // According to WebIDL specification this will not be a precise representation
581 // of requested val. We're converting the val to signed long and then pass it
582 // to C++ to get the value in required range.
583 return native_.getResultObject(
584 native_.callSync('UtilsToUnsignedLongLong', {
590 Converter.prototype.toUnsignedLongLong = function(val, nullable) {
591 return _nullableGeneric(_toUnsignedLongLong, nullable, val);
594 function _toShort(val) {
595 return ((_toLong(val) + 32768) & 0xffff) - 32768;
598 Converter.prototype.toShort = function(val, nullable) {
599 return _nullableGeneric(_toShort, nullable, val);
602 function _toUnsignedShort(val) {
603 return Math.abs(_toLong(val)) & 0xffff;
606 Converter.prototype.toUnsignedShort = function(val, nullable) {
607 return _nullableGeneric(_toUnsignedShort, nullable, val);
610 function _toByte(val) {
611 return ((_toLong(val) + 128) & 0xff) - 128;
614 Converter.prototype.toByte = function(val, nullable) {
615 return _nullableGeneric(_toByte, nullable, val);
618 function _toOctet(val) {
619 return _toLong(val) & 0xff;
622 Converter.prototype.toOctet = function(val, nullable) {
623 return _nullableGeneric(_toOctet, nullable, val);
626 function _toDouble(val) {
627 var ret = Number(val);
628 if (isNaN(ret) || !isFinite(ret)) {
629 throw new WebAPIException(
630 WebAPIException.TYPE_MISMATCH_ERR,
631 'Cannot convert ' + String(val) + ' to double.'
637 Converter.prototype.toDouble = function(val, nullable) {
638 return _nullableGeneric(_toDouble, nullable, val);
641 function _toString(val) {
645 Converter.prototype.toString = function(val, nullable) {
646 return _nullableGeneric(_toString, nullable, val);
649 function _toPlatformObject(val, types) {
652 if (_type.isArray(types)) {
658 if (_type.isArray(val)) {
659 throw new WebAPIException(
660 WebAPIException.TYPE_MISMATCH_ERR,
661 'Cannot convert ' + String(val) + ' to ' + String(t[0].name) + '.'
666 for (var i = 0; i < t.length; ++i) {
667 if (val instanceof t[i]) {
672 throw new WebAPIException(
673 WebAPIException.TYPE_MISMATCH_ERR,
674 'Cannot convert ' + String(val) + ' to ' + String(t[0].name) + '.'
678 Converter.prototype.toPlatformObject = function(val, types, nullable) {
679 return _nullableGeneric(_toPlatformObject, nullable, val, types);
682 function _toFunction(val) {
683 if (_type.isFunction(val)) {
687 throw new WebAPIException(
688 WebAPIException.TYPE_MISMATCH_ERR,
689 'Cannot convert ' + String(val) + ' to function.'
693 Converter.prototype.toFunction = function(val, nullable) {
694 return _nullableGeneric(_toFunction, nullable, val);
697 function _toArray(val) {
698 if (_type.isArray(val)) {
702 throw new WebAPIException(
703 WebAPIException.TYPE_MISMATCH_ERR,
704 'Cannot convert ' + String(val) + ' to array.'
708 Converter.prototype.toArray = function(val, nullable) {
709 return _nullableGeneric(_toArray, nullable, val);
712 function _toDictionary(val) {
713 if (_type.isObject(val) || _type.isFunction(val)) {
717 throw new WebAPIException(
718 WebAPIException.TYPE_MISMATCH_ERR,
719 'Cannot convert ' + String(val) + ' to dictionary.'
723 Converter.prototype.toDictionary = function(val, nullable) {
724 return _nullableGeneric(_toDictionary, nullable, val);
727 function _toEnum(val, e) {
728 var v = _toString(val);
729 if (_type.arrayContains(e, v)) {
733 throw new WebAPIException(
734 WebAPIException.TYPE_MISMATCH_ERR,
735 'Cannot convert ' + v + ' to enum.'
739 Converter.prototype.toEnum = function(val, e, nullable) {
740 return _nullableGeneric(_toEnum, nullable, val, e);
743 var _converter = new Converter();
745 /////////////////////////////////////////////////////////////////////////////
747 var Validator = function() {
751 LONG_LONG: 'LONG_LONG',
752 UNSIGNED_LONG: 'UNSIGNED_LONG',
753 UNSIGNED_LONG_LONG: 'UNSIGNED_LONG_LONG',
758 FUNCTION: 'FUNCTION',
759 DICTIONARY: 'DICTIONARY',
760 PLATFORM_OBJECT: 'PLATFORM_OBJECT',
761 LISTENER: 'LISTENER',
764 FILE_REFERENCE: 'FILE_REFERENCE',
765 SIMPLE_TYPE: 'SIMPLE_TYPE' // Boolean, Number or String
770 * Verifies if arguments passed to function are valid.
772 * Description of expected arguments.
773 * This is an array of objects, each object represents one argument.
774 * First object in this array describes first argument, second object describes second
775 * argument, and so on.
776 * Object describing an argument needs to have two properties:
777 * - name - name of the argument,
778 * - type - type of the argument, only values specified in Validator.Types are allowed.
779 * Other properties, which may appear:
780 * - optional - if set to value which evaluates to true, argument is optional
781 * - nullable - if set to to true, argument may be set to null
782 * - values - required in case of some objects, value depends on type
783 * - validator - function which accepts a single parameter and returns true or false;
784 * if this property is present, this function will be executed,
785 * argument converted to expected type is going to be passed to this
788 * @param {Array} a - arguments of a method
789 * @param {Array} d - description of expected arguments
790 * @return {Object} which holds all available arguments.
791 * @throws TypeMismatchError if arguments are not valid
829 * type: Validator.Types.PLATFORM_OBJECT,
830 * values: ApplicationControl // type of platform object
837 * type: Validator.Types.PLATFORM_OBJECT,
838 * values: [Alarm, AlarmRelative, AlarmAbsolute] // accepted types
845 * type: Validator.Types.LISTENER,
846 * values: ['onsuccess', 'onfailure'] // array of callbacks' names
853 * type: Validator.Types.ARRAY,
854 * values: ApplicationControlData // type of each element in array,
855 * // tested with instanceof
862 * type: Validator.Types.ARRAY,
863 * values: Validator.Types.DOUBLE // converts elements, only primitive
864 * // types are supported
871 * type: Validator.Types.ENUM,
872 * values: ['SCREEN_DIM', 'SCREEN_NORMAL', 'CPU_AWAKE'] // array of allowed values
876 Validator.prototype.validateArgs = function(a, d) {
877 var args = { has: {} };
879 for (var i = 0; i < d.length; ++i) {
880 var name = d[i].name;
881 args.has[name] = i < a.length;
883 var optional = d[i].optional;
884 var nullable = d[i].nullable;
887 if (args.has[name] || !optional) {
888 var type = d[i].type;
889 var values = d[i].values;
892 case this.Types.BOOLEAN:
893 val = _converter.toBoolean(val, nullable);
896 case this.Types.LONG:
897 val = _converter.toLong(val, nullable);
900 case this.Types.LONG_LONG:
901 val = _converter.toLongLong(val, nullable);
904 case this.Types.UNSIGNED_LONG:
905 val = _converter.toUnsignedLong(val, nullable);
908 case this.Types.UNSIGNED_LONG_LONG:
909 val = _converter.toUnsignedLongLong(val, nullable);
912 case this.Types.BYTE:
913 val = _converter.toByte(val, nullable);
916 case this.Types.OCTET:
917 val = _converter.toOctet(val, nullable);
920 case this.Types.DOUBLE:
921 val = _converter.toDouble(val, nullable);
924 case this.Types.STRING:
925 val = _converter.toString(val, nullable);
928 case this.Types.FUNCTION:
929 val = _converter.toFunction(val, nullable);
932 case this.Types.DICTIONARY:
933 val = _converter.toDictionary(val, nullable);
936 case this.Types.PLATFORM_OBJECT:
937 val = _converter.toPlatformObject(val, values, nullable);
940 case this.Types.LISTENER:
941 if (_type.isNull(val)) {
943 throw new WebAPIException(
944 WebAPIException.TYPE_MISMATCH_ERR,
945 'Argument "' + name + '" cannot be null.'
949 if (!_type.isObject(val)) {
950 throw new WebAPIException(
951 WebAPIException.TYPE_MISMATCH_ERR,
952 'Argument "' + name + '" should be an object.'
955 for (var ii = 0; ii < values.length; ++ii) {
956 if (_type.hasProperty(val, values[ii])) {
957 val[values[ii]] = _converter.toFunction(
966 case this.Types.ARRAY:
967 val = _converter.toArray(val, nullable);
968 if (!_type.isNull(val) && values) {
972 case this.Types.BOOLEAN:
973 func = _converter.toBoolean;
976 case this.Types.LONG:
977 func = _converter.toLong;
980 case this.Types.LONG_LONG:
981 func = _converter.toLongLong;
984 case this.Types.UNSIGNED_LONG:
985 func = _converter.toUnsignedLong;
988 case this.Types.UNSIGNED_LONG_LONG:
989 func = _converter.toUnsignedLongLong;
992 case this.Types.BYTE:
993 func = _converter.toByte;
996 case this.Types.OCTET:
997 func = _converter.toOctet;
1000 case this.Types.DOUBLE:
1001 func = _converter.toDouble;
1004 case this.Types.STRING:
1005 func = _converter.toString;
1009 func = function(val) {
1010 if (!(val instanceof values)) {
1011 throw new WebAPIException(
1012 WebAPIException.TYPE_MISMATCH_ERR,
1013 'Items of array "' +
1015 '" should be of type: ' +
1024 for (var j = 0; j < val.length; ++j) {
1025 val[j] = func(val[j]);
1030 case this.Types.ENUM:
1031 val = _converter.toEnum(val, values, nullable);
1034 case this.Types.FILE_REFERENCE:
1036 _type.isObject(val) &&
1037 'File' === val.constructor.name &&
1042 val = _converter.toString(val, nullable);
1045 case this.Types.SIMPLE_TYPE:
1046 if (optional && _type.isUndefined(val)) {
1049 if (nullable && _type.isNull(val)) {
1053 !_type.isBoolean(val) &&
1054 !_type.isNumber(val) &&
1055 !_type.isString(val)
1057 throw new WebAPIException(
1058 WebAPIException.TYPE_MISMATCH_ERR,
1059 'Argument "' + name + '" should be boolean, number or string.'
1065 throw new WebAPIException(
1066 WebAPIException.TYPE_MISMATCH_ERR,
1067 'Unknown type: "' + type + '".'
1071 var _validator = d[i].validator;
1073 if (_type.isFunction(_validator) && !_validator(val)) {
1074 throw new WebAPIException(
1075 WebAPIException.TYPE_MISMATCH_ERR,
1076 'Argument "' + name + '" did not pass additional validation.'
1088 * Use this helper to ensure that constructor is invoked by "new" operator.
1090 * @param {Object} obj
1091 * @param {Function} instance
1093 Validator.prototype.isConstructorCall = function(obj, instance) {
1094 if (!(obj instanceof instance) || obj._previouslyConstructed) {
1095 // There is no TypeError exception in Tizen 2.3.0 API spec but it's required
1096 // by current TCTs. For Tizen compliance it's wrapped into WebAPIException.
1097 throw new WebAPIException(
1099 'Constructor cannot be called as function.'
1103 Object.defineProperty(obj, '_previouslyConstructed', {
1111 * @deprecated Use isConstructorCall() instead.
1113 Validator.prototype.validateConstructorCall = function(obj, instance) {
1114 this.isConstructorCall(obj, instance);
1117 var _validator = new Validator();
1119 /////////////////////////////////////////////////////////////////////////////
1121 var NativeManager = function(extension) {
1126 this.CALLBACK_ID_KEY = 'callbackId';
1132 this.LISTENER_ID_KEY = 'listenerId';
1138 var extension_ = extension;
1147 * Map of async reply callbacks.
1149 * @type {Object.<number, function>}
1152 this.callbacks_ = {};
1155 * Map of registered listeners.
1157 * @type {Object.<string, function>}
1160 this.listeners_ = {};
1162 _validator.isConstructorCall(this, NativeManager);
1164 // TODO: Remove mockup if WRT implements sendRuntimeMessage
1165 // This is temporary mockup!
1166 extension.sendRuntimeMessage =
1167 extension.sendRuntimeMessage ||
1169 xwalk.utils.error('Runtime did not implement extension.sendRuntimeMessage!');
1170 throw new WebAPIException(
1171 WebAPIException.UNKNOWN_ERR,
1172 'Runtime did not implement extension.sendRuntimeMessage!'
1176 extension.sendRuntimeAsyncMessage =
1177 extension.sendRuntimeAsyncMessage ||
1180 'Runtime did not implement extension.sendRuntimeAsyncMessage!'
1182 throw new WebAPIException(
1183 WebAPIException.UNKNOWN_ERR,
1184 'Runtime did not implement extension.sendRuntimeAsyncMessage!'
1188 extension.sendRuntimeSyncMessage =
1189 extension.sendRuntimeSyncMessage ||
1192 'Runtime did not implement extension.sendRuntimeSyncMessage!'
1194 throw new WebAPIException(
1195 WebAPIException.UNKNOWN_ERR,
1196 'Runtime did not implement extension.sendRuntimeSyncMessage!'
1200 // check extension prototype
1203 !extension.internal ||
1204 !_type.isFunction(extension.postMessage) ||
1205 !_type.isFunction(extension.internal.sendSyncMessage) ||
1206 !_type.isFunction(extension.internal.sendSyncMessageWithBinaryReply) ||
1207 !_type.isFunction(extension.internal.sendSyncMessageWithStringReply) ||
1208 !_type.isFunction(extension.sendRuntimeMessage) ||
1209 !_type.isFunction(extension.sendRuntimeAsyncMessage) ||
1210 !_type.isFunction(extension.sendRuntimeSyncMessage) ||
1211 !_type.isFunction(extension.setMessageListener)
1213 throw new WebAPIException(
1214 WebAPIException.TYPE_MISMATCH_ERR,
1215 'Wrong extension object passed'
1219 Object.defineProperties(this, {
1234 extension_.setMessageListener(
1237 var msg = JSON_.parse(json);
1239 // Because of special handling of power lock in chromium, the special
1241 // - __DisableChromiumInternalPowerLock
1242 // - __EnableChromiumInternalPowerLock
1243 // could occur. In such cases we are silently ignroing those messages.
1244 // TODO This is workaround for missing patch in chromium-efl package
1245 // which should handle this special message and don't forward it to
1246 // webapi JS. After chromium-efl will be updated, below checking should
1248 if (json.substring(0, 2) === '__') {
1251 xwalk.utils.error('Ignoring message - Invalid JSON received: ' + json);
1256 if (msg.hasOwnProperty(this.CALLBACK_ID_KEY)) {
1257 id = msg[this.CALLBACK_ID_KEY];
1258 delete msg[this.CALLBACK_ID_KEY];
1260 if (!_type.isFunction(this.callbacks_[id])) {
1261 xwalk.utils.error('Wrong callback identifier. Ignoring message.');
1265 var f = this.callbacks_[id];
1266 setTimeout(function() {
1270 xwalk.utils.error('########## exception');
1271 xwalk.utils.error(e);
1274 delete this.callbacks_[id];
1279 if (msg.hasOwnProperty(this.LISTENER_ID_KEY)) {
1280 id = msg[this.LISTENER_ID_KEY];
1281 delete msg[this.LISTENER_ID_KEY];
1283 if (!_type.isFunction(this.listeners_[id])) {
1284 xwalk.utils.error('Wrong listener identifier. Ignoring message.');
1288 var f = this.listeners_[id];
1289 setTimeout(function() {
1293 xwalk.utils.error('########## exception');
1294 xwalk.utils.error(e);
1302 'Missing callback or listener identifier. Ignoring message.'
1308 NativeManager.prototype.call = function(cmd, args, callback) {
1311 var replyId = this.nextReplyId;
1312 args[this.CALLBACK_ID_KEY] = replyId;
1313 this.callbacks_[replyId] = callback;
1315 return this.callSync(cmd, args);
1318 NativeManager.prototype.callSync = function(cmd, args) {
1319 var request = JSON_.stringify({
1324 var response = this.extension.internal.sendSyncMessage(request);
1325 if (response === undefined) {
1326 /* C++ extension didn't set sync response using Instance::SendSyncReply */
1327 throw new WebAPIException(WebAPIException.ABORT_ERR, 'Internal error');
1329 return JSON_.parse(response);
1332 NativeManager.prototype.callSyncWithBinaryAnswer = function (cmd, args) {
1333 var request = JSON_.stringify({
1334 __binaryAnswer: true,
1339 var response = this.extension.internal.sendSyncMessageWithBinaryReply(request);
1340 if (response === undefined) {
1341 /* C++ extension didn't set sync binary response using Instance::SendSyncBinaryReply */
1342 throw new WebAPIException(WebAPIException.ABORT_ERR, 'Internal error');
1347 NativeManager.prototype.callSyncBinaryWithJSONAnswer = function(uint8array_data) {
1348 // method id should be coded as first byte, refer to:
1349 // extension.cc - ParsedInstance:: HandleBinaryMessage
1351 var response = this.extension.internal.sendSyncMessage(uint8array_data);
1352 if (response === undefined) {
1353 /* C++ extension didn't set sync response using Instance::SendSyncReply */
1354 throw new WebAPIException(WebAPIException.ABORT_ERR, 'Internal error');
1356 return JSON_.parse(response);
1359 NativeManager.prototype.sendRuntimeMessage = function(msg, body) {
1360 return this.extension.sendRuntimeMessage(msg, body || '');
1363 NativeManager.prototype.sendRuntimeAsyncMessage = function(msg, body, callback) {
1364 var handler = function(response) {
1365 if (_type.isFunction(callback)) {
1367 if ('success' === response.toLowerCase()) {
1368 result.status = 'success';
1370 result.status = 'error';
1371 result.error = new WebAPIException(
1372 WebAPIException.UNKNOWN_ERR,
1373 'Runtime message failure'
1379 return this.extension.sendRuntimeAsyncMessage(msg, body || '', handler);
1382 NativeManager.prototype.sendRuntimeSyncMessage = function(msg, body) {
1383 return this.extension.sendRuntimeSyncMessage(msg, body || '');
1386 NativeManager.prototype.addListener = function(name, callback) {
1387 if (!_type.isString(name) || !name.length) {
1388 throw new WebAPIException(WebAPIException.TYPE_MISMATCH_ERR);
1391 this.listeners_[name] = callback;
1394 NativeManager.prototype.removeListener = function(name) {
1395 if (this.listeners_.hasOwnProperty(name)) {
1396 delete this.listeners_[name];
1400 NativeManager.prototype.isListenerSet = function(name) {
1401 return this.listeners_.hasOwnProperty(name);
1404 NativeManager.prototype.isSuccess = function(result) {
1405 return result.status !== 'error';
1408 NativeManager.prototype.isFailure = function(result) {
1409 return !this.isSuccess(result);
1412 NativeManager.prototype.getResultObject = function(result) {
1413 return result.result;
1416 NativeManager.prototype.getErrorObject = function(result) {
1417 return new WebAPIException(result.error);
1421 * This function checks if the reported error's name is in valid_error_names.
1422 * If so, it is returned. Otherwise, default_error is returned.
1423 * valid_error_names should contain error names defined in the API reference
1424 * for the called function.
1426 NativeManager.prototype.getErrorObjectAndValidate = function(
1432 Array.isArray(valid_error_names),
1433 'valid_error_names must be an Array. %s was passed instead',
1434 typeof valid_error_names
1436 var error = new WebAPIException(result.error);
1437 if (valid_error_names.includes(error.name)) {
1441 return default_error;
1444 NativeManager.prototype.callIfPossible = function(callback) {
1445 if (!_type.isNullOrUndefined(callback)) {
1446 callback.apply(callback, [].slice.call(arguments, 1));
1450 NativeManager.prototype.callIfPossibleAndReturn = function(callback) {
1451 if (!_type.isNullOrUndefined(callback)) {
1452 return callback.apply(callback, [].slice.call(arguments, 1));
1456 // WebAPIException and WebAPIError definition moved to Utils for compliance
1457 // reasons with blink-wrt environment.
1458 // In blink-wrt the original Tizen module is loaded, which is not providing
1459 // exception constructor.
1460 // As modules needs exceptions internally so they are loaded here for now.
1461 // See http://168.219.209.56/gerrit/#/c/23472/ for more details.
1462 // In future exception definition could be moved back to Tizen module.
1463 function __isObject(object) {
1464 return object instanceof _global.Object;
1467 function __isUndefined(object) {
1468 return object === void 0;
1471 function __isNumber(object) {
1472 return typeof object === 'number';
1475 // WARNING! This list should be in sync with the equivalent enum
1476 // located at tizen.h. Remember to update tizen.h if you change
1483 DOMSTRING_SIZE_ERR: 2,
1484 HIERARCHY_REQUEST_ERR: 3,
1485 WRONG_DOCUMENT_ERR: 4,
1486 INVALID_CHARACTER_ERR: 5,
1487 NO_DATA_ALLOWED_ERR: 6,
1488 NO_MODIFICATION_ALLOWED_ERR: 7,
1490 NOT_SUPPORTED_ERR: 9,
1491 INUSE_ATTRIBUTE_ERR: 10,
1492 INVALID_STATE_ERR: 11,
1494 INVALID_MODIFICATION_ERR: 13,
1496 INVALID_ACCESS_ERR: 15,
1498 TYPE_MISMATCH_ERR: 17,
1502 URL_MISMATCH_ERR: 21,
1503 QUOTA_EXCEEDED_ERR: 22,
1505 INVALID_NODE_TYPE_ERR: 24,
1508 // Error codes for these errors are not really defined anywhere.
1509 INVALID_VALUES_ERR: 100,
1511 SERVICE_NOT_AVAILABLE_ERR: 103,
1512 VERIFICATION_ERR: 105
1515 var code_to_name = {};
1516 code_to_name[errors['NO_ERROR']] = 'NoError';
1517 code_to_name[errors['UNKNOWN_ERR']] = 'UnknownError';
1518 code_to_name[errors['INDEX_SIZE_ERR']] = 'IndexSizeError';
1519 code_to_name[errors['DOMSTRING_SIZE_ERR']] = 'DOMStringSizeError';
1520 code_to_name[errors['HIERARCHY_REQUEST_ERR']] = 'HierarchyRequestError';
1521 code_to_name[errors['WRONG_DOCUMENT_ERR']] = 'WrongDocumentError';
1522 code_to_name[errors['INVALID_CHARACTER_ERR']] = 'InvalidCharacterError';
1523 code_to_name[errors['NO_DATA_ALLOWED_ERR']] = 'NoDataAllowedError';
1524 code_to_name[errors['NO_MODIFICATION_ALLOWED_ERR']] = 'NoModificationAllowedError';
1525 code_to_name[errors['NOT_FOUND_ERR']] = 'NotFoundError';
1526 code_to_name[errors['NOT_SUPPORTED_ERR']] = 'NotSupportedError';
1527 code_to_name[errors['INUSE_ATTRIBUTE_ERR']] = 'InuseAttributeError';
1528 code_to_name[errors['INVALID_STATE_ERR']] = 'InvalidStateError';
1529 code_to_name[errors['SYNTAX_ERR']] = 'SyntaxError';
1530 code_to_name[errors['INVALID_MODIFICATION_ERR']] = 'InvalidModificationError';
1531 code_to_name[errors['NAMESPACE_ERR']] = 'NamespaceError';
1532 code_to_name[errors['INVALID_ACCESS_ERR']] = 'InvalidAccessError';
1533 code_to_name[errors['VALIDATION_ERR']] = 'ValidationError';
1534 code_to_name[errors['TYPE_MISMATCH_ERR']] = 'TypeMismatchError';
1535 code_to_name[errors['SECURITY_ERR']] = 'SecurityError';
1536 code_to_name[errors['NETWORK_ERR']] = 'NetworkError';
1537 code_to_name[errors['ABORT_ERR']] = 'AbortError';
1538 code_to_name[errors['URL_MISMATCH_ERR']] = 'URLMismatchError';
1539 code_to_name[errors['QUOTA_EXCEEDED_ERR']] = 'QuotaExceededError';
1540 code_to_name[errors['TIMEOUT_ERR']] = 'TimeoutError';
1541 code_to_name[errors['INVALID_NODE_TYPE_ERR']] = 'InvalidNodeTypeError';
1542 code_to_name[errors['DATA_CLONE_ERR']] = 'DataCloneError';
1544 code_to_name[errors['INVALID_VALUES_ERR']] = 'InvalidValuesError';
1545 code_to_name[errors['IO_ERR']] = 'IOError';
1546 code_to_name[errors['SERVICE_NOT_AVAILABLE_ERR']] = 'ServiceNotAvailableError';
1547 code_to_name[errors['VERIFICATION_ERR']] = 'VerificationError';
1549 var name_to_code = {};
1550 Object.keys(errors).forEach(function(key) {
1551 name_to_code[code_to_name[errors[key]]] = errors[key];
1555 * Generic exception interface.
1557 * @param {number} code 16-bit error code.
1558 * @param {string} message An error message that describes the details of
1559 * an encountered error.
1560 * @param {string} name An error type.
1562 var WebAPIException = function(code, message, name) {
1564 var name_ = code_to_name[code];
1565 var message_ = 'Unknown error';
1567 switch (arguments.length) {
1569 var error = arguments[0];
1570 if (__isObject(error)) {
1573 message_ = error.message;
1574 if (__isUndefined(code_) && !__isUndefined(name_))
1575 code_ = name_to_code[name_];
1576 if (__isUndefined(name_) && !__isUndefined(code_))
1577 name_ = code_to_name[code_];
1578 } else if (__isNumber(error)) {
1579 // backward compatibility with crosswalk implementation
1581 name_ = code_to_name[code];
1586 if (__isNumber(arguments[0])) {
1587 code_ = arguments[0];
1588 if (!__isUndefined(code_to_name[code_])) {
1589 name_ = code_to_name[code_];
1592 name_ = String(arguments[0]);
1593 if (!__isUndefined(name_to_code[name_])) {
1594 code_ = name_to_code[name_];
1597 message_ = String(arguments[1]);
1600 // backward compatibility with crosswalk implementation
1601 code_ = Number(arguments[0]);
1602 message_ = String(arguments[1]);
1603 name_ = String(arguments[2]);
1609 if (code_ > errors.DATA_CLONE_ERR) {
1614 Object.defineProperties(this, {
1615 code: { value: code_, writable: false, enumerable: true },
1616 name: { value: name_, writable: false, enumerable: true },
1617 message: { value: message_, writable: false, enumerable: true }
1620 this.constructor.prototype.__proto__ = Error.prototype;
1622 Error.captureStackTrace && Error.captureStackTrace(this, this.constructor);
1625 WebAPIException.prototype.toString = function() {
1626 return this.name + ': ' + this.message;
1629 var error_constants = {};
1630 for (var prop in errors) {
1631 error_constants[prop] = { value: errors[prop], writable: false, enumerable: true };
1633 Object.defineProperties(WebAPIException, error_constants);
1634 Object.defineProperties(WebAPIException.prototype, error_constants);
1636 // Modules should be 'undefined' if related feature is not supported.
1637 // Below function could be used for conditional definition of JS API exports as in below:
1638 // var relatedFeature = 'http://tizen.org/feature/network.bluetooth.audio.media';
1639 // xwalk.utils.exportModuleIfFeatureSupported(relatedFeature, exports,
1640 // new MediaKeyManager(), undefined);
1641 function exportModuleIfFeatureSupported(relatedFeature, successExport, failureExport) {
1643 if (true === tizen.systeminfo.getCapability(relatedFeature)) {
1644 return successExport;
1649 return failureExport;
1652 // Export WebAPIException and WebAPIError into global scope.
1653 // For compliance reasons their constructors should not be exported in tizen namespace,
1654 // but should be available internally to allow throwing exceptions from modules.
1656 if (typeof window !== 'undefined') {
1658 } else if (typeof global !== 'undefined') {
1660 } else if (typeof self !== 'undefined') {
1663 scope = scope || {};
1664 scope.WebAPIException = WebAPIException;
1665 scope.WebAPIError = WebAPIException;
1667 // ArrayBufferParser is used for parsing the binary data returned from C++ as ArrayBuffer.
1668 // It expects contents like:
1669 // - JSON coded as utf-8 format (1 byte per element)
1670 // - binary data of any ArrayBuffer (M bytes per element)
1671 // WARNING: for convienence of parsing data in JS layer, we always provide
1672 // JSON part (size + coded JSON) which length is a multiplication of 8 to
1673 // handle 1, 2, 4 and 8 bytes data smoothly.
1674 // Refer to common::tools::ReportSuccessToBinary, ReportErrorToBinary and
1675 // ReportDataToBinary methods
1676 function ArrayBufferParser(array) {
1678 this.typedArray_ = new Uint8Array(array);
1681 ArrayBufferParser.prototype.getJSON = function () {
1682 if (this.idx_ >= this.typedArray_.length) {
1683 console.log('No more data');
1686 // expecting 4 bytes size (N) starting from startIdx
1690 (this.typedArray_[this.idx_] << 24) +
1691 (this.typedArray_[this.idx_ + 1] << 16) +
1692 (this.typedArray_[this.idx_ + 2] << 8) +
1693 this.typedArray_[this.idx_ + 3];
1695 var subArray = this.typedArray_.slice(this.idx_ + 4, this.idx_ + 4 + N);
1696 var resultJson = JSON.parse(Utils.prototype.ArrayToString(subArray));
1701 ArrayBufferParser.prototype.getData = function (ArrayType) {
1702 if (this.idx_ >= this.typedArray_.length) {
1703 console.log('No more data');
1706 // Expecting 8 bytes size (N) starting from startIdx
1707 // N bytes of data. Refer to common::tools::PushJSONToBinary comment.
1709 (this.typedArray_[this.idx_] << 56) +
1710 (this.typedArray_[this.idx_ + 1] << 48) +
1711 (this.typedArray_[this.idx_ + 2] << 40) +
1712 (this.typedArray_[this.idx_ + 3] << 32) +
1713 (this.typedArray_[this.idx_ + 4] << 24) +
1714 (this.typedArray_[this.idx_ + 5] << 16) +
1715 (this.typedArray_[this.idx_ + 6] << 8) +
1716 this.typedArray_[this.idx_ + 7];
1718 // As ArrayType constructor expects the size in elements (not bytes),
1719 // N need to be adjusted
1720 N /= ArrayType.BYTES_PER_ELEMENT;
1721 // getting N elements starting from idx_ + 8
1722 var subArray = new ArrayType(this.typedArray_.buffer, this.idx_ + 8, N);
1727 Utils.prototype.dateConverter = _dateConverter;
1728 Utils.prototype.type = _type;
1729 Utils.prototype.converter = _converter;
1730 Utils.prototype.validator = _validator;
1731 Utils.prototype.NativeManager = NativeManager;
1732 Utils.prototype.CommonListenerManager = CommonListenerManager;
1733 Utils.prototype.exportModuleIfFeatureSupported = exportModuleIfFeatureSupported;
1734 Utils.prototype.ArrayBufferParser = ArrayBufferParser;
1736 var native_ = new NativeManager(extension);
1738 exports.utils = new Utils();
1740 Object.freeze(exports);
1741 Object.freeze(exports.utils);
1742 Object.freeze(Utils.prototype);
1743 Object.freeze(NativeManager.prototype);
1744 Object.freeze(CommonListenerManager.prototype);