Merge "[Application] Fixed path of getAppSharedURI" into tizen_5.0
[platform/core/api/webapi-plugins.git] / src / bluetooth / bluetooth_api.js
1 /*
2  * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *    Licensed under the Apache License, Version 2.0 (the "License");
5  *    you may not use this file except in compliance with the License.
6  *    You may obtain a copy of the License at
7  *
8  *        http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *    Unless required by applicable law or agreed to in writing, software
11  *    distributed under the License is distributed on an "AS IS" BASIS,
12  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *    See the License for the specific language governing permissions and
14  *    limitations under the License.
15  */
16  
17 var T = xwalk.utils.type;
18 var Converter = xwalk.utils.converter;
19 var AV = xwalk.utils.validator;
20 var Privilege = xwalk.utils.privilege;
21 var privUtils_ = xwalk.utils;
22 var native = new xwalk.utils.NativeManager(extension);
23
24 // class BluetoothClassDeviceMajor /////////////////////////////////////////
25 var BluetoothClassDeviceMajor = function() {
26     Object.defineProperties(this, {
27         MISC:          {value: 0x00, writable: false, enumerable: true},
28         COMPUTER:      {value: 0x01, writable: false, enumerable: true},
29         PHONE:         {value: 0x02, writable: false, enumerable: true},
30         NETWORK:       {value: 0x03, writable: false, enumerable: true},
31         AUDIO_VIDEO:   {value: 0x04, writable: false, enumerable: true},
32         PERIPHERAL:    {value: 0x05, writable: false, enumerable: true},
33         IMAGING:       {value: 0x06, writable: false, enumerable: true},
34         WEARABLE:      {value: 0x07, writable: false, enumerable: true},
35         TOY:           {value: 0x08, writable: false, enumerable: true},
36         HEALTH:        {value: 0x09, writable: false, enumerable: true},
37         UNCATEGORIZED: {value: 0x1F, writable: false, enumerable: true}
38     });
39 };
40
41 // class BluetoothClassDeviceMinor /////////////////////////////////////////
42 var BluetoothClassDeviceMinor = function() {
43     Object.defineProperties(this, {
44         COMPUTER_UNCATEGORIZED:           {value: 0x00, writable: false, enumerable: true},
45         COMPUTER_DESKTOP:                 {value: 0x01, writable: false, enumerable: true},
46         COMPUTER_SERVER:                  {value: 0x02, writable: false, enumerable: true},
47         COMPUTER_LAPTOP:                  {value: 0x03, writable: false, enumerable: true},
48         COMPUTER_HANDHELD_PC_OR_PDA:      {value: 0x04, writable: false, enumerable: true},
49         COMPUTER_PALM_PC_OR_PDA:          {value: 0x05, writable: false, enumerable: true},
50         COMPUTER_WEARABLE:                {value: 0x06, writable: false, enumerable: true},
51
52         PHONE_UNCATEGORIZED:              {value: 0x00, writable: false, enumerable: true},
53         PHONE_CELLULAR:                   {value: 0x01, writable: false, enumerable: true},
54         PHONE_CORDLESS:                   {value: 0x02, writable: false, enumerable: true},
55         PHONE_SMARTPHONE:                 {value: 0x03, writable: false, enumerable: true},
56         PHONE_MODEM_OR_GATEWAY:           {value: 0x04, writable: false, enumerable: true},
57         PHONE_ISDN:                       {value: 0x05, writable: false, enumerable: true},
58
59         AV_UNRECOGNIZED:                  {value: 0x00, writable: false, enumerable: true},
60         AV_WEARABLE_HEADSET:              {value: 0x01, writable: false, enumerable: true},
61         AV_HANDSFREE:                     {value: 0x02, writable: false, enumerable: true},
62         AV_MICROPHONE:                    {value: 0x04, writable: false, enumerable: true},
63         AV_LOUDSPEAKER:                   {value: 0x05, writable: false, enumerable: true},
64         AV_HEADPHONES:                    {value: 0x06, writable: false, enumerable: true},
65         AV_PORTABLE_AUDIO:                {value: 0x07, writable: false, enumerable: true},
66         AV_CAR_AUDIO:                     {value: 0x08, writable: false, enumerable: true},
67         AV_SETTOP_BOX:                    {value: 0x09, writable: false, enumerable: true},
68         AV_HIFI:                          {value: 0x0A, writable: false, enumerable: true},
69         AV_VCR:                           {value: 0x0B, writable: false, enumerable: true},
70         AV_VIDEO_CAMERA:                  {value: 0x0C, writable: false, enumerable: true},
71         AV_CAMCORDER:                     {value: 0x0D, writable: false, enumerable: true},
72         AV_MONITOR:                       {value: 0x0E, writable: false, enumerable: true},
73         AV_DISPLAY_AND_LOUDSPEAKER:       {value: 0x0F, writable: false, enumerable: true},
74         AV_VIDEO_CONFERENCING:            {value: 0x10, writable: false, enumerable: true},
75         AV_GAMING_TOY:                    {value: 0x12, writable: false, enumerable: true},
76
77         PERIPHERAL_UNCATEGORIZED:         {value: 0x00, writable: false, enumerable: true},
78         PERIPHERAL_KEYBOARD:              {value: 0x10, writable: false, enumerable: true},
79         PERIPHERAL_POINTING_DEVICE:       {value: 0x20, writable: false, enumerable: true},
80         PERIPHERAL_KEYBOARD_AND_POINTING_DEVICE: {
81             value: 0x30,
82             writable: false,
83             enumerable: true
84         },
85         PERIPHERAL_JOYSTICK:              {value: 0x01, writable: false, enumerable: true},
86         PERIPHERAL_GAMEPAD:               {value: 0x02, writable: false, enumerable: true},
87         PERIPHERAL_REMOTE_CONTROL:        {value: 0x03, writable: false, enumerable: true},
88         PERIPHERAL_SENSING_DEVICE:        {value: 0x04, writable: false, enumerable: true},
89         PERIPHERAL_DEGITIZER_TABLET:      {value: 0x05, writable: false, enumerable: true},
90         PERIPHERAL_CARD_READER:           {value: 0x06, writable: false, enumerable: true},
91         PERIPHERAL_DIGITAL_PEN:           {value: 0x07, writable: false, enumerable: true},
92         PERIPHERAL_HANDHELD_SCANNER:      {value: 0x08, writable: false, enumerable: true},
93         PERIPHERAL_HANDHELD_INPUT_DEVICE: {value: 0x09, writable: false, enumerable: true},
94
95         IMAGING_UNCATEGORIZED:            {value: 0x00, writable: false, enumerable: true},
96         IMAGING_DISPLAY:                  {value: 0x04, writable: false, enumerable: true},
97         IMAGING_CAMERA:                   {value: 0x08, writable: false, enumerable: true},
98         IMAGING_SCANNER:                  {value: 0x10, writable: false, enumerable: true},
99         IMAGING_PRINTER:                  {value: 0x20, writable: false, enumerable: true},
100
101         WEARABLE_WRITST_WATCH:            {value: 0x01, writable: false, enumerable: true},
102         WEARABLE_PAGER:                   {value: 0x02, writable: false, enumerable: true},
103         WEARABLE_JACKET:                  {value: 0x03, writable: false, enumerable: true},
104         WEARABLE_HELMET:                  {value: 0x04, writable: false, enumerable: true},
105         WEARABLE_GLASSES:                 {value: 0x05, writable: false, enumerable: true},
106
107         TOY_ROBOT:                        {value: 0x01, writable: false, enumerable: true},
108         TOY_VEHICLE:                      {value: 0x02, writable: false, enumerable: true},
109         TOY_DOLL:                         {value: 0x03, writable: false, enumerable: true},
110         TOY_CONTROLLER:                   {value: 0x04, writable: false, enumerable: true},
111         TOY_GAME:                         {value: 0x05, writable: false, enumerable: true},
112
113         HEALTH_UNDEFINED:                 {value: 0x00, writable: false, enumerable: true},
114         HEALTH_BLOOD_PRESSURE_MONITOR:    {value: 0x01, writable: false, enumerable: true},
115         HEALTH_THERMOMETER:               {value: 0x02, writable: false, enumerable: true},
116         HEALTH_WEIGHING_SCALE:            {value: 0x03, writable: false, enumerable: true},
117         HEALTH_GLUCOSE_METER:             {value: 0x04, writable: false, enumerable: true},
118         HEALTH_PULSE_OXIMETER:            {value: 0x05, writable: false, enumerable: true},
119         HEALTH_PULSE_RATE_MONITOR:        {value: 0x06, writable: false, enumerable: true},
120         HEALTH_DATA_DISPLAY:              {value: 0x07, writable: false, enumerable: true},
121         HEALTH_STEP_COUNTER:              {value: 0x08, writable: false, enumerable: true},
122         HEALTH_BODY_COMPOSITION_ANALYZER: {value: 0x09, writable: false, enumerable: true},
123         HEALTH_PEAK_FLOW_MONITOR:         {value: 0x0A, writable: false, enumerable: true},
124         HEALTH_MEDICATION_MONITOR:        {value: 0x0B, writable: false, enumerable: true},
125         HEALTH_KNEE_PROSTHESIS:           {value: 0x0C, writable: false, enumerable: true},
126         HEALTH_ANKLE_PROSTHESIS:          {value: 0x0D, writable: false, enumerable: true}
127     });
128 };
129
130 // class BluetoothClassDeviceService ///////////////////////////////////////
131 var BluetoothClassDeviceService = function() {
132     Object.defineProperties(this, {
133         LIMITED_DISCOVERABILITY: {value: 0x0001, writable: false, enumerable: true},
134         POSITIONING:             {value: 0x0008, writable: false, enumerable: true},
135         NETWORKING:              {value: 0x0010, writable: false, enumerable: true},
136         RENDERING:               {value: 0x0020, writable: false, enumerable: true},
137         CAPTURING:               {value: 0x0040, writable: false, enumerable: true},
138         OBJECT_TRANSFER:         {value: 0x0080, writable: false, enumerable: true},
139         AUDIO:                   {value: 0x0100, writable: false, enumerable: true},
140         TELEPHONY:               {value: 0x0200, writable: false, enumerable: true},
141         INFORMATION:             {value: 0x0400, writable: false, enumerable: true}
142     });
143 };
144
145 //class tizen.BluetoothLEServiceData ////////////////////////////////////////////////////
146 tizen.BluetoothLEServiceData = function(d) {
147   AV.isConstructorCall(this, tizen.BluetoothLEServiceData);
148   var uuid_ = '';
149   var data_ = '';
150
151   Object.defineProperties(this, {
152     uuid: {
153       enumerable: true,
154       get: function() {
155         return uuid_;
156       },
157       set: function(v) {
158         uuid_ = Converter.toString(v);
159       }
160     },
161     data: {
162       enumerable: true,
163       get: function() {
164         return data_;
165       },
166       set: function(v) {
167         data_ = Converter.toString(v);
168       }
169     }
170   });
171
172   if (arguments.length >= 2) {  // public constructor
173     this.uuid = arguments[0];
174     this.data = arguments[1];
175   } else if (d && T.isObject(d)) {  // internal constructor
176     this.uuid = d.uuid;
177     this.data = d.data;
178   } else {
179     uuid_ = undefined;
180     data_ = undefined;
181   }
182 };
183
184 //class BluetoothLEAdvertiseData ////////////////////////////////////////////////////
185 tizen.BluetoothLEAdvertiseData = function(dict) {
186   AV.isConstructorCall(this, tizen.BluetoothLEAdvertiseData);
187   var includeName_ = false;
188   var uuids_ = null;
189   var solicitationuuids_ = null;
190   var appearance_ = null;
191   var includeTxPowerLevel_ = false;
192   var serviceData_ = null;
193   var manufacturerData_ = null;
194
195   Object.defineProperties(this, {
196     includeName: {
197       enumerable: true,
198       get: function() {
199         return includeName_;
200       },
201       set: function(v) {
202         includeName_ = Converter.toBoolean(v, true);
203       }
204     },
205     uuids: {
206       enumerable: true,
207       get: function() {
208         return uuids_;
209       },
210       set: function(v) {
211         if (T.isNull(v)) {
212           uuids_ = v;
213         } else if (T.isArray(v)) {
214           for (var i = 0; i < v.length; ++i) {
215             if (!T.isString(v[i])) {
216               v[i] = Converter.toString(v[i]);
217             }
218           }
219           uuids_ = v;
220         }
221       }
222     },
223     solicitationuuids: {
224       enumerable: true,
225       get: function() {
226         return solicitationuuids_;
227       },
228       set: function(v) {
229         if (T.isNull(v)) {
230           solicitationuuids_ = v;
231         } else if (T.isArray(v)) {
232           for (var i = 0; i < v.length; ++i) {
233             if (!T.isString(v[i])) {
234               v[i] = Converter.toString(v[i]);
235             }
236           }
237           solicitationuuids_ = v;
238         }
239       }
240     },
241     appearance: {
242       enumerable: true,
243       get: function() {
244         return appearance_;
245       },
246       set: function(v) {
247         appearance_ = Converter.toUnsignedLong(v, true);
248       }
249     },
250     includeTxPowerLevel: {
251       enumerable: true,
252       get: function() {
253         return includeTxPowerLevel_;
254       },
255       set: function(v) {
256         includeTxPowerLevel_ = Converter.toBoolean(v, true);
257       }
258     },
259     serviceData: {
260       enumerable: true,
261       get: function() {
262         return serviceData_;
263       },
264       set: function(v) {
265         if (T.isNull(v) || (v instanceof tizen.BluetoothLEServiceData)) {
266           serviceData_ = v;
267         }
268       }
269     },
270     manufacturerData: {
271       enumerable: true,
272       get: function() {
273         return manufacturerData_;
274       },
275       set: function(v) {
276         if (T.isNull(v) || (v instanceof tizen.BluetoothLEManufacturerData)) {
277           manufacturerData_ = v;
278         }
279       }
280     }
281   });
282
283   if (T.isObject(dict)) {
284     var o = {};
285
286     // includeName
287     if (T.isNull(dict.includeName) || T.isBoolean(dict.includeName)) {
288       o.includeName = dict.includeName;
289     } else if (!T.isUndefined(dict.includeName)) {
290       return;
291     }
292
293     // uuids
294     if (T.isNull(dict.uuids)) {
295       o.uuids = dict.uuids;
296     } else if (T.isArray(dict.uuids)) {
297       for (var i = 0; i < dict.uuids.length; ++i) {
298         if (!T.isString(dict.uuids[i])) {
299           return;
300         }
301       }
302       o.uuids = dict.uuids;
303     } else if (!T.isUndefined(dict.uuids)) {
304       return;
305     }
306
307     // solicitationuuids
308     if (T.isNull(dict.solicitationuuids)) {
309       o.solicitationuuids = dict.solicitationuuids;
310     } else if (T.isArray(dict.solicitationuuids)) {
311       for (var i = 0; i < dict.solicitationuuids.length; ++i) {
312         if (!T.isString(dict.solicitationuuids[i])) {
313           return;
314         }
315       }
316       o.solicitationuuids = dict.solicitationuuids;
317     } else if (!T.isUndefined(dict.solicitationuuids)) {
318       return;
319     }
320
321     // appearance
322     if (T.isNull(dict.appearance) || T.isNumber(dict.appearance)) {
323       o.appearance = dict.appearance;
324     } else if (!T.isUndefined(dict.appearance)) {
325       return;
326     }
327
328     // includeTxPowerLevel
329     if (T.isNull(dict.includeTxPowerLevel) || T.isBoolean(dict.includeTxPowerLevel)) {
330       o.includeTxPowerLevel = dict.includeTxPowerLevel;
331     } else if (!T.isUndefined(dict.includeTxPowerLevel)) {
332       return;
333     }
334
335     // serviceData
336     if (T.isNull(dict.serviceData) || dict.serviceData instanceof tizen.BluetoothLEServiceData) {
337       o.serviceData = dict.serviceData;
338     } else if (!T.isUndefined(dict.serviceData)) {
339       return;
340     }
341
342     // manufacturerData
343     if (T.isNull(dict.manufacturerData) ||
344         (dict.manufacturerData instanceof tizen.BluetoothLEManufacturerData)) {
345       o.manufacturerData = dict.manufacturerData;
346     } else if (!T.isUndefined(dict.manufacturerData)) {
347       return;
348     }
349
350     for (var prop in o) {
351       if (o.hasOwnProperty(prop) && this.hasOwnProperty(prop)) {
352         this[prop] = o[prop];
353       }
354     }
355   }
356 };
357
358 //class tizen.BluetoothLEManufacturerData ////////////////////////////////////////////////////
359 tizen.BluetoothLEManufacturerData = function(d) {
360   AV.isConstructorCall(this, tizen.BluetoothLEManufacturerData);
361   var id_ = '';
362   var data_ = '';
363
364   Object.defineProperties(this, {
365     id: {
366       enumerable: true,
367       get: function() {
368         return id_;
369       },
370       set: function(v) {
371         id_ = Converter.toString(v);
372       }
373     },
374     data: {
375       enumerable: true,
376       get: function() {
377         return data_;
378       },
379       set: function(v) {
380         data_ = Converter.toString(v);
381       }
382     }
383   });
384
385   if (arguments.length >= 2) {  // public constructor
386     this.id = arguments[0];
387     this.data = arguments[1];
388   } else if (d && T.isObject(d)) {  // internal constructor
389     this.id = d.id;
390     this.data = d.data;
391   } else {
392     id_ = undefined;
393     data_ = undefined;
394   }
395 };
396
397 // class BluetoothClass ////////////////////////////////////////////////////
398 var BluetoothClass = function(data) {
399     var services = [];
400     if (data) {
401         services = data.services;
402     }
403
404     Object.defineProperties(this, {
405         major : {value: data.major, writable: false, enumerable: true},
406         minor : {value: data.minor, writable: false, enumerable: true},
407         services : {
408             enumerable: true,
409             set : function(){},
410             get : function(){ return services.slice(); }
411         }
412     });
413 };
414
415 var BluetoothClass_hasService = function() {
416   privUtils_.log('Entered BluetoothClass.hasService()');
417   privUtils_.checkPrivilegeAccess4Ver("2.4", Privilege.BLUETOOTH, Privilege.BLUETOOTH_GAP);
418
419   var args = AV.validateMethod(arguments, [
420       {
421           name : 'service',
422           type : AV.Types.UNSIGNED_LONG
423       }
424   ]);
425
426   var size = this.services.length;
427   for (var i = 0; i < size; i++) {
428       if (this.services[i] === args.service) {
429           return true;
430       }
431   }
432   return false;
433 };
434
435 BluetoothClass.prototype.hasService = function() {
436     return BluetoothClass_hasService.apply(this, arguments);
437 };
438
439 // class BluetoothSocket ////////////////////////////////////////////////////
440 var _BLUETOOTH_SOCKET_STATE_CLOSED = 'CLOSED';
441
442 function BluetoothSocketListeners() {
443     var that = this;
444     this.socketCallback = function (data) {
445         var event = data;
446         var socket = that.sockets[event.id];
447
448         if (socket) {
449             if ('onclose' === event.event) {
450                 // no more events
451                 that.removeListener(event.id);
452                 // change state
453                 Object.defineProperty(socket, 'state', {value : _BLUETOOTH_SOCKET_STATE_CLOSED});
454             }
455
456             var callback = socket[event.event];
457             if (T.isFunction(callback)) {
458                 callback();
459             }
460         } else {
461             privUtils_.log('Received event for an unknown socket: ' + event.id);
462         }
463     };
464 }
465
466 BluetoothSocketListeners.prototype.sockets = {};
467
468 BluetoothSocketListeners.prototype.addListener = function(socket) {
469     if (T.isEmptyObject(this.sockets)) {
470         native.addListener('BLUETOOTH_SOCKET_STATE_CHANGED', this.socketCallback);
471     }
472
473     this.sockets[socket._id] = socket;
474 };
475
476 BluetoothSocketListeners.prototype.removeListener = function(id) {
477     delete this.sockets[id];
478
479     if (T.isEmptyObject(this.sockets)) {
480         native.removeListener('BLUETOOTH_SOCKET_STATE_CHANGED', this.socketCallback);
481     }
482 };
483
484 var _bluetoothSocketListeners = new BluetoothSocketListeners();
485
486 var BluetoothSocket = function(data) {
487     Object.defineProperties(this, {
488         uuid : {value: data.uuid, writable: false, enumerable: true},
489         state : {value: data.state, writable: false, enumerable: true, configurable: true},
490         peer : {value: new BluetoothDevice(data.peer), writable: false, enumerable: true},
491         onmessage : {value: null, writable: true, enumerable: true},
492         onclose : {value: null, writable: true, enumerable: true},
493         _id : {value: data.id, writable: false, enumerable: false}
494     });
495
496     _bluetoothSocketListeners.addListener(this);
497 };
498
499 BluetoothSocket.prototype.writeData = function() {
500     privUtils_.log('Entered BluetoothSocket.writeData()');
501
502     var args = AV.validateMethod(arguments, [
503         {
504             name : 'data',
505             type : AV.Types.ARRAY,
506             values : AV.Types.BYTE
507         }
508     ]);
509
510     var callArgs = {
511         id : this._id,
512         data : args.data
513     };
514
515     var result = native.callSync('BluetoothSocket_writeData', callArgs);
516
517     if (native.isFailure(result)) {
518         throw native.getErrorObject(result);
519     } else {
520         return native.getResultObject(result);
521     }
522 };
523
524 BluetoothSocket.prototype.readData = function() {
525     privUtils_.log('Entered BluetoothSocket.readData()');
526
527     var callArgs = {
528         id : this._id
529     };
530
531     var result = native.callSync('BluetoothSocket_readData', callArgs);
532
533     if (native.isFailure(result)) {
534         throw native.getErrorObject(result);
535     } else {
536         return native.getResultObject(result);
537     }
538 };
539
540 BluetoothSocket.prototype.close = function() {
541     privUtils_.log('Entered BluetoothSocket.close()');
542
543     if (_BLUETOOTH_SOCKET_STATE_CLOSED !== this.state) {
544         var callArgs = {
545             id : this._id
546         };
547
548         var result = native.callSync('BluetoothSocket_close', callArgs);
549
550         if (native.isFailure(result)) {
551             throw native.getErrorObject(result);
552         }
553
554         // change state
555         Object.defineProperty(this, 'state', { value : _BLUETOOTH_SOCKET_STATE_CLOSED });
556     }
557 };
558
559 //class BluetoothLEDevice ////////////////////////////////////////////////////
560 var BluetoothLEDevice = function(data) {
561     var address = "", name = null, txpowerlevel = null, appearance = null, uuids = null,
562         solicitationuuids = null, serviceData = null, manufacturerData = null, rssi = null;
563
564     if (data) {
565       address = data.address;
566       name = data.name || null;
567       txpowerlevel = data.txpowerlevel || null;
568       appearance = data.appearance || null;
569       uuids = data.uuids || null;
570       solicitationuuids = data.solicitationuuids || null;
571       if (data.serviceData) {
572         data.serviceData.forEach(function(d) {
573             serviceData.push(new tizen.BluetoothLEServiceData(d));
574         });
575       }
576       if (data.manufacturerData) {
577         manufacturerData = new tizen.BluetoothLEManufacturerData(data.manufacturerData);
578       }
579       if (data.rssi) {
580         rssi = data.rssi;
581       }
582     }
583
584     Object.defineProperties(this, {
585         address : {value: address, writable: false, enumerable: true},
586         name : {value: name, writable: false, enumerable: true},
587         txpowerlevel : {value: txpowerlevel, writable: false, enumerable: true},
588         appearance : {value: appearance, writable: false, enumerable: true},
589         uuids : {
590             enumerable: true,
591             set : function(){},
592             get : function(){
593               var service_uuids = uuids ? uuids.slice() : null;
594               return service_uuids;
595             }
596         },
597         solicitationuuids : {
598             enumerable: true,
599             set : function(){},
600             get : function(){ return solicitationuuids ? solicitationuuids.slice() : null; }
601         },
602         serviceData : {
603             enumerable: true,
604             set : function(){},
605             get : function(){ return serviceData ? serviceData.slice() : null; }
606         },
607         manufacturerData : {
608             value: manufacturerData,
609             writable: false,
610             enumerable: true},
611         rssi : {value: rssi, writable: false, enumerable: true}
612     });
613 };
614
615 BluetoothLEDevice.prototype.connect = function() {
616     privUtils_.log('Entered BluetoothLEDevice.connect()');
617     var args = AV.validateMethod(arguments, [
618     {
619         name : 'successCallback',
620         type : AV.Types.FUNCTION,
621         optional : true,
622         nullable : true
623     },
624     {
625         name : 'errorCallback',
626             type : AV.Types.FUNCTION,
627             optional : true,
628             nullable : true
629         }
630     ]);
631
632     var callback = function(result) {
633         if (native.isFailure(result)) {
634             native.callIfPossible(args.errorCallback, native.getErrorObject(result));
635         } else {
636             native.callIfPossible(args.successCallback);
637         }
638     };
639     // Errors are handled by error callback
640     var result = native.call('BluetoothLEDevice_connect', {address : this.address}, callback);
641     if (native.isFailure(result)) {
642       throw native.getErrorObject(result);
643     }
644 };
645
646 BluetoothLEDevice.prototype.disconnect = function() {
647     privUtils_.log('Entered BluetoothLEDevice.disconnect()');
648     var args = AV.validateMethod(arguments, [
649     {
650         name : 'successCallback',
651         type : AV.Types.FUNCTION,
652         optional : true,
653         nullable : true
654     },
655     {
656         name : 'errorCallback',
657             type : AV.Types.FUNCTION,
658             optional : true,
659             nullable : true
660         }
661     ]);
662     var callback = function(result) {
663         if (native.isFailure(result)) {
664             native.callIfPossible(args.errorCallback, native.getErrorObject(result));
665         } else {
666             native.callIfPossible(args.successCallback);
667         }
668     };
669
670     var result = native.call('BluetoothLEDevice_disconnect', {address : this.address}, callback);
671     if (native.isFailure(result)) {
672         throw native.getErrorObject(result);
673     }
674 };
675
676 BluetoothLEDevice.prototype.getService = function() {
677     privUtils_.log('Entered BluetoothLEDevice.getService()');
678     var args = AV.validateMethod(arguments, [
679         {
680             name: 'uuid',
681             type: AV.Types.STRING
682         }
683     ]);
684
685     var callArgs = {
686         uuid : args.uuid,
687         address : this.address
688     };
689
690     var result = native.callSync('BluetoothLEDevice_getService', callArgs);
691     if (native.isFailure(result)) {
692         throw native.getErrorObject(result);
693     } else {
694         return new BluetoothGATTService(native.getResultObject(result));
695     }
696 };
697
698 BluetoothLEDevice.prototype.getServiceAllUuids = function() {
699   privUtils_.log('Entered BluetoothLEDevice.getServiceAllUuids()');
700
701   var callArgs = {
702     address : this.address
703   };
704
705   var result = native.callSync('BluetoothLEDevice_getServiceAllUuids', callArgs);
706   if (native.isFailure(result)) {
707     throw native.getErrorObject(result);
708   } else {
709     var uuids = native.getResultObject(result);
710     return uuids;
711   }
712 };
713
714 BluetoothLEDevice.prototype.addConnectStateChangeListener = function() {
715     privUtils_.log('Entered BluetoothLEDevice.addConnectStateChangeListener()');
716     var args = AV.validateMethod(arguments, [
717         {
718             name: 'listener',
719             type: AV.Types.LISTENER,
720             values: ['onconnected', 'ondisconnected']
721         }
722     ]);
723
724     var that = this;
725
726     var func = function(event) {
727         if (event.address === that.address && args.listener[event.action]) {
728             args.listener[event.action](that);
729         }
730     }
731
732     var watchId = _bleConnectChangeListener.addListener(func);
733
734     return watchId;
735 };
736
737 BluetoothLEDevice.prototype.removeConnectStateChangeListener = function() {
738     privUtils_.log('Entered BluetoothLEDevice.removeConnectStateChangeListener()');
739
740     var args = AV.validateMethod(arguments, [
741         {
742             name: 'watchID',
743             type: AV.Types.LONG
744         }
745     ]);
746
747     _bleConnectChangeListener.removeListener(args.watchID);
748 };
749
750 // class BluetoothDevice ////////////////////////////////////////////////////
751 var BluetoothDevice = function(data) {
752     var self = this;
753     function _getter(field) {
754         var callArgs = {};
755
756         callArgs.address = self.address;
757         callArgs.field = field;
758
759         var result = native.callSync('BluetoothDevice_getBoolValue', callArgs);
760
761         if (native.isFailure(result)) {
762             return false;
763         } else {
764             return native.getResultObject(result);
765         }
766     }
767
768     function isBondedGetter() {
769         return _getter('isBonded');
770     }
771
772     function isTrustedGetter() {
773         return _getter('isTrusted');
774     }
775
776     function isConnectedGetter() {
777         return _getter('isConnected');
778     }
779
780     var uuids = [];
781     if (data) {
782         uuids = data.uuids;
783     }
784
785     Object.defineProperties(this, {
786         name : {value: data.name, writable: false, enumerable: true},
787         address : {value: data.address, writable: false, enumerable: true},
788         deviceClass : {value: new BluetoothClass(data.deviceClass),
789             writable: false,
790             enumerable: true},
791         isBonded : {
792             enumerable: true,
793             set : function(){},
794             get : isBondedGetter
795         },
796         isTrusted : {
797             enumerable: true,
798             set : function(){},
799             get : isTrustedGetter
800         },
801         isConnected : {
802             enumerable: true,
803             set : function(){},
804             get : isConnectedGetter
805         },
806         uuids : {
807             enumerable: true,
808             set : function(){},
809             get : function(){ return uuids.slice(); }
810         }
811     });
812 };
813
814 BluetoothDevice.prototype.connectToServiceByUUID = function() {
815     privUtils_.log('Entered BluetoothDevice.connectToServiceByUUID()');
816
817     var args = AV.validateMethod(arguments, [
818         {
819             name : 'uuid',
820             type : AV.Types.STRING
821         },
822         {
823             name : 'successCallback',
824             type : AV.Types.FUNCTION
825         },
826         {
827             name : 'errorCallback',
828             type : AV.Types.FUNCTION,
829             optional : true,
830             nullable : true
831         }
832     ]);
833
834     var callArgs = {
835         address : this.address,
836         uuid : args.uuid
837     };
838     var callback = function(result) {
839         if (native.isFailure(result)) {
840             native.callIfPossible(args.errorCallback, native.getErrorObject(result));
841         } else {
842             args.successCallback(new BluetoothSocket(native.getResultObject(result)));
843         }
844     };
845
846     var result = native.call('BluetoothDevice_connectToServiceByUUID', callArgs, callback);
847     if (native.isFailure(result)) {
848       throw native.getErrorObject(result);
849     }
850 };
851
852 // class BluetoothServiceHandler ////////////////////////////////////////////////////
853 function BluetoothServiceListeners() {
854     var that = this;
855     this.serviceCallback = function (data) {
856         var e = data;
857         var service = that.services[e.uuid];
858         var result = new BluetoothSocket(e);
859
860         if (service) {
861             privUtils_.log(service);
862             service.onconnect(result);
863         }
864     };
865 }
866
867 BluetoothServiceListeners.prototype.services = {};
868
869 BluetoothServiceListeners.prototype.addListener = function(service) {
870     if (T.isEmptyObject(this.services)) {
871         native.addListener('BLUETOOTH_SERVICE_ONCONNECT', this.serviceCallback);
872     }
873
874     this.services[service.uuid] = service;
875 };
876
877 BluetoothServiceListeners.prototype.removeListener = function(uuid) {
878     delete this.services[uuid];
879
880     if (T.isEmptyObject(this.services)) {
881         native.removeListener('BLUETOOTH_SERVICE_ONCONNECT', this.serviceCallback);
882     }
883 };
884
885 var _bluetoothServiceListeners = new BluetoothServiceListeners();
886
887 var BluetoothServiceHandler = function(data) {
888     function isConnectedGetter() {
889         var callArgs = {
890             uuid : this.uuid
891         };
892
893         var result = native.callSync('BluetoothAdapter_isServiceConnected', { uuid : this.uuid });
894
895         if (native.isFailure(result)) {
896             return false;
897         } else {
898             return native.getResultObject(result);
899         }
900     }
901
902     Object.defineProperties(this, {
903         uuid : {value: data.uuid, writable: false, enumerable: true},
904         name : {value: data.name, writable: false, enumerable: true},
905         isConnected : {
906             enumerable: true,
907             set : function(){},
908             get : isConnectedGetter
909         },
910         onconnect : {value: null, writable: true, enumerable: true}
911     });
912
913     _bluetoothServiceListeners.addListener(this);
914 };
915
916 BluetoothServiceHandler.prototype.unregister = function() {
917     privUtils_.log('Entered BluetoothServiceHandler.unregister()');
918     var args = AV.validateMethod(arguments, [
919         {
920             name : 'successCallback',
921             type : AV.Types.FUNCTION,
922             optional : true,
923             nullable : true
924         },
925         {
926             name : 'errorCallback',
927             type : AV.Types.FUNCTION,
928             optional : true,
929             nullable : true
930         }
931     ]);
932
933     var callArgs = {
934         uuid : this.uuid
935     };
936
937     var callback = function(result) {
938         if (native.isFailure(result)) {
939             native.callIfPossible(args.errorCallback, native.getErrorObject(result));
940         } else {
941             native.callIfPossible(args.successCallback);
942         }
943     };
944
945     var result = native.call('BluetoothServiceHandler_unregister', callArgs, callback);
946     if (native.isFailure(result)) {
947       throw native.getErrorObject(result);
948     }
949
950     _bluetoothServiceListeners.removeListener(this.uuid);
951 };
952
953 // class BluetoothHealthApplication ////////////////////////////////////////////////////
954 function BluetoothHealthApplicationListeners() {
955     var that = this;
956     this.appCallback = function (data) {
957         var event = data;
958         var app = that.apps[event.id];
959
960         if (app) {
961             var callback = app[event.event];
962             if (T.isFunction(callback)) {
963                 var param;
964                 switch (event.event) {
965                 case 'onconnect':
966                     param = new BluetoothHealthChannel(native.getResultObject(event));
967                     break;
968
969                 default:
970                     privUtils_.log('Unknown event: ' + event.event);
971                     break;
972                 }
973                 callback(param);
974             }
975         } else {
976             privUtils_.log('Received event for an unknown application: ' + event.id);
977         }
978     };
979 }
980
981 BluetoothHealthApplicationListeners.prototype.apps = {};
982
983 BluetoothHealthApplicationListeners.prototype.addListener = function(app) {
984     if (T.isEmptyObject(this.apps)) {
985         native.addListener('BLUETOOTH_HEALTH_APPLICATION_CHANGED', this.appCallback);
986     }
987
988     this.apps[app._id] = app;
989 };
990
991 BluetoothHealthApplicationListeners.prototype.removeListener = function(id) {
992     delete this.apps[id];
993
994     if (T.isEmptyObject(this.apps)) {
995         native.removeListener('BLUETOOTH_HEALTH_APPLICATION_CHANGED', this.appCallback);
996     }
997 };
998
999 var _bluetoothHealthApplicationListeners = new BluetoothHealthApplicationListeners();
1000
1001 var BluetoothHealthApplication = function(data) {
1002     Object.defineProperties(this, {
1003         dataType : {value: data.dataType, writable: false, enumerable: true},
1004         name : {value: data.name, writable: false, enumerable: true},
1005         onconnect : {value: null, writable: true, enumerable: true},
1006         _id : {value: data._id, writable: false, enumerable: false}
1007     });
1008
1009     _bluetoothHealthApplicationListeners.addListener(this);
1010 };
1011
1012 BluetoothHealthApplication.prototype.unregister = function() {
1013     privUtils_.log('Entered BluetoothHealthApplication.unregister()');
1014     var args = AV.validateMethod(arguments, [
1015         {
1016             name : 'successCallback',
1017             type : AV.Types.FUNCTION,
1018             optional : true,
1019             nullable : true
1020         },
1021         {
1022             name : 'errorCallback',
1023             type : AV.Types.FUNCTION,
1024             optional : true,
1025             nullable : true
1026         }
1027     ]);
1028
1029     var callArgs = {id : this._id};
1030
1031     var callback = function(result) {
1032         if (native.isFailure(result)) {
1033             native.callIfPossible(args.errorCallback, native.getErrorObject(result));
1034         } else {
1035             native.callIfPossible(args.successCallback);
1036         }
1037     };
1038
1039     var result = native.call('BluetoothHealthApplication_unregister', callArgs, callback);
1040     if (native.isFailure(result)) {
1041       throw native.getErrorObject(result);
1042     }
1043
1044     _bluetoothHealthApplicationListeners.removeListener(this._id);
1045 };
1046
1047 // class BluetoothProfileHandler ////////////////////////////////////////////////////
1048 var _BluetoothProfileType = {
1049     HEALTH : 'HEALTH'
1050 };
1051
1052 var BluetoothProfileHandler = function(data) {
1053     if (data) {
1054         Object.defineProperties(this, {
1055             profileType : {value: data.profileType, writable: false, enumerable: true}
1056         });
1057     }
1058 };
1059
1060 // class BluetoothHealthProfileHandler ////////////////////////////////////////////////////
1061 var BluetoothHealthProfileHandler = function(data) {
1062     BluetoothProfileHandler.call(this, data);
1063 };
1064
1065 BluetoothHealthProfileHandler.prototype = new BluetoothProfileHandler();
1066
1067 BluetoothHealthProfileHandler.prototype.constructor = BluetoothProfileHandler;
1068
1069 BluetoothHealthProfileHandler.prototype.registerSinkApplication = function() {
1070     privUtils_.log('Entered BluetoothHealthProfileHandler.registerSinkApplication()');
1071
1072     var args = AV.validateMethod(arguments, [
1073         {
1074             name : 'dataType',
1075             type : AV.Types.LONG // there's no short type
1076         },
1077         {
1078             name : 'name',
1079             type : AV.Types.STRING
1080         },
1081         {
1082             name : 'successCallback',
1083             type : AV.Types.FUNCTION
1084         },
1085         {
1086             name : 'errorCallback',
1087             type : AV.Types.FUNCTION,
1088             optional : true,
1089             nullable : true
1090         }
1091     ]);
1092
1093     var callArgs = {
1094         dataType : args.dataType,
1095         name : args.name
1096     };
1097
1098     var callback = function(result) {
1099         if (native.isFailure(result)) {
1100             native.callIfPossible(args.errorCallback, native.getErrorObject(result));
1101         } else {
1102             args.successCallback(new BluetoothHealthApplication(native.getResultObject(result)));
1103         }
1104     };
1105
1106     var result = native.call('BluetoothHealthProfileHandler_registerSinkApp', callArgs, callback);
1107     if (native.isFailure(result)) {
1108       throw native.getErrorObject(result);
1109     }
1110 };
1111
1112 BluetoothHealthProfileHandler.prototype.connectToSource = function() {
1113     privUtils_.log('Entered BluetoothHealthProfileHandler.connectToSource()');
1114
1115     var args = AV.validateMethod(arguments, [
1116         {
1117             name : 'peer',
1118             type : AV.Types.PLATFORM_OBJECT,
1119             values : BluetoothDevice
1120         },
1121         {
1122             name : 'application',
1123             type : AV.Types.PLATFORM_OBJECT,
1124             values : BluetoothHealthApplication
1125         },
1126         {
1127             name : 'successCallback',
1128             type : AV.Types.FUNCTION
1129         },
1130         {
1131             name : 'errorCallback',
1132             type : AV.Types.FUNCTION,
1133             optional : true,
1134             nullable : true
1135         }
1136     ]);
1137
1138     var callArgs = {
1139         address : args.peer.address,
1140         appId : args.application._id
1141     };
1142
1143     var callback = function(result) {
1144         if (native.isFailure(result)) {
1145             native.callIfPossible(args.errorCallback, native.getErrorObject(result));
1146         } else {
1147             var channel = native.getResultObject(result);
1148             channel.peer = args.peer;
1149             channel.appId = args.application._id;
1150             args.successCallback(new BluetoothHealthChannel(channel));
1151         }
1152     };
1153
1154     var result = native.call('BluetoothHealthProfileHandler_connectToSource', callArgs, callback);
1155     if (native.isFailure(result)) {
1156       throw native.getErrorObject(result);
1157     }
1158 };
1159
1160 // class BluetoothHealthChannel ////////////////////////////////////////////////////
1161 var BluetoothHealthChannel = function(data) {
1162     Object.defineProperties(this, {
1163         peer : {value: data.peer, writable: false, enumerable: true},
1164         channelType : {value: data.channelType, writable: false, enumerable: true},
1165         application : {
1166             value: _bluetoothHealthApplicationListeners.apps[data.appId],
1167             writable: false,
1168             enumerable: true
1169         },
1170         isConnected : {
1171             value: data.isConnected,
1172             writable: false,
1173             enumerable: true,
1174             configurable: true},
1175         _id : {value: data._id, writable: false, enumerable: false}
1176     });
1177 };
1178
1179 BluetoothHealthChannel.prototype.close = function() {
1180     privUtils_.log('Entered BluetoothHealthChannel.close()');
1181
1182     if (this.isConnected) {
1183         var callArgs = {
1184             channel : this._id,
1185             address : this.peer.address
1186         };
1187
1188         var result = native.callSync('BluetoothHealthChannel_close', callArgs);
1189
1190         if (native.isFailure(result)) {
1191             throw native.getErrorObject(result);
1192         }
1193
1194         Object.defineProperty(this, 'isConnected', { value : false });
1195     }
1196 };
1197
1198 BluetoothHealthChannel.prototype.sendData = function() {
1199     privUtils_.log('Entered BluetoothHealthChannel.sendData()');
1200     var args = AV.validateMethod(arguments, [
1201         {
1202             name : 'data',
1203             type : AV.Types.ARRAY,
1204             values : AV.Types.BYTE
1205         }
1206     ]);
1207
1208     var callArgs = {
1209         channel : this._id,
1210         data : args.data
1211     };
1212
1213     var result = native.callSync('BluetoothHealthChannel_sendData', callArgs);
1214
1215     if (native.isFailure(result)) {
1216         throw native.getErrorObject(result);
1217     } else {
1218         return native.getResultObject(result);
1219     }
1220 };
1221
1222 var _healthListeners = {};
1223
1224 function _BluetoothHealthChannelChangeCallback(event) {
1225     var e = event;
1226     var callback = _healthListeners[e.id];
1227     var d;
1228
1229     switch (e.event) {
1230     case 'onmessage':
1231         d = e.data;
1232         break;
1233
1234     case 'onclose':
1235         break;
1236
1237     default:
1238         privUtils_.log('Unknown mode: ' + e.event);
1239         return;
1240     }
1241
1242     if (callback[e.event]) {
1243         callback[e.event](d);
1244     }
1245 }
1246
1247 var BluetoothHealthChannel_setListener = function() {
1248   privUtils_.log('Entered BluetoothHealthChannel.setListener()');
1249   privUtils_.checkPrivilegeAccess4Ver("2.4", Privilege.BLUETOOTH, Privilege.BLUETOOTH_HEALTH);
1250   var args = AV.validateMethod(arguments, [
1251       {
1252           name : 'changeCallback',
1253           type : AV.Types.LISTENER,
1254           values : ['onmessage', 'onclose']
1255       }
1256   ]);
1257
1258   if (T.isEmptyObject(_healthListeners)) {
1259       native.addListener('BluetoothHealthChannelChangeCallback',
1260               _BluetoothHealthChannelChangeCallback);
1261   }
1262   _healthListeners[this._id] = args.changeCallback;
1263 };
1264
1265
1266 BluetoothHealthChannel.prototype.setListener = function() {
1267     BluetoothHealthChannel_setListener.apply(this, arguments);
1268 };
1269
1270 var BluetoothHealthChannel_unsetListener  = function() {
1271   privUtils_.log('Entered BluetoothHealthChannel.unsetListener ()');
1272   if (T.isEmptyObject(_healthListeners)) {
1273     privUtils_.checkPrivilegeAccess4Ver("2.4", Privilege.BLUETOOTH, Privilege.BLUETOOTH_HEALTH);
1274   }
1275
1276   delete _healthListeners[this._id];
1277
1278   if (T.isEmptyObject(_healthListeners)) {
1279       native.removeListener('BluetoothHealthChannelChangeCallback',
1280               _BluetoothHealthChannelChangeCallback);
1281   }
1282 };
1283
1284 BluetoothHealthChannel.prototype.unsetListener  = function() {
1285   BluetoothHealthChannel_unsetListener.apply(this, arguments);
1286 };
1287
1288
1289 /**
1290  * Creates a manager for specified listener event.
1291  *
1292  * @param {string} name - name of the listener this manager handles
1293  * @param {function} callback - function to be invoked when event specified by the name fires.
1294  *                              This function should return false if the callback doesn't want
1295  *                              to handle the event anymore, true otherwise.
1296  *                              This function should have following signature:
1297  *                              bool callback(event, successCallback, errorCallback);
1298  *
1299  * @return {object} object which allows to add or remove callbacks for specified listener
1300  */
1301 function _singleListenerBuilder(name, callback) {
1302   var listenerName = name;
1303   var successCallback;
1304   var errorCallback;
1305   var callbackFunction = callback;
1306   var listenerRegistered = false;
1307
1308   function innerCallback(event) {
1309     if (!callbackFunction(event, successCallback, errorCallback)) {
1310       removeListener();
1311     }
1312   }
1313
1314   function addListener(s, e) {
1315     successCallback = s;
1316     errorCallback = e;
1317
1318     if (!listenerRegistered) {
1319       native.addListener(listenerName, innerCallback);
1320       listenerRegistered = true;
1321     }
1322   }
1323
1324   function removeListener() {
1325     if (listenerRegistered) {
1326       native.removeListener(listenerName, innerCallback);
1327       listenerRegistered = false;
1328     }
1329
1330     successCallback = undefined;
1331     errorCallback = undefined;
1332   }
1333
1334   return {
1335     addListener: addListener,
1336     removeListener: removeListener
1337   };
1338 }
1339
1340 var _bleScanListener = _singleListenerBuilder('BluetoothLEScanCallback',
1341     function(event, successCallback, errorCallback) {
1342
1343   var d;
1344   var ret = true;
1345
1346   switch (event.action) {
1347     case 'onsuccess':
1348       d = new BluetoothLEDevice(event.data);
1349       break;
1350
1351     case 'onerror':
1352       if (errorCallback) {
1353         errorCallback(native.getErrorObject(event));
1354       }
1355       return ret;
1356
1357     default:
1358       privUtils_.log('Unknown mode: ' + event.action);
1359       return ret;
1360   }
1361   if (successCallback) {
1362     successCallback(d);
1363   }
1364
1365   return ret;
1366 });
1367
1368 var _bleAdvertiseListener = _singleListenerBuilder('BluetoothLEAdvertiseCallback',
1369     function(event, successCallback, errorCallback) {
1370   var d;
1371   var ret = true;
1372
1373   switch (event.action) {
1374     case 'onstate':
1375       if (successCallback) {
1376         successCallback(native.getResultObject(event));
1377         if (native.getResultObject(event) == 'STOPPED') {
1378           _bleAdvertiseListener.removeListener();
1379         }
1380       }
1381       return ret;
1382
1383     case 'onerror':
1384       if (errorCallback) {
1385         errorCallback(native.getErrorObject(event));
1386       }
1387       return ret;
1388
1389     default:
1390       privUtils_.log('Unknown mode: ' + event.action);
1391       return ret;
1392   }
1393 });
1394
1395 //class BluetoothLEAdapter ////////////////////////////////////////////////////
1396 var BluetoothLEAdapter = function() {
1397 };
1398
1399 BluetoothLEAdapter.prototype.startScan = function() {
1400   privUtils_.log('Entered BluetoothLEAdapter.startScan()');
1401   var args = AV.validateMethod(arguments, [{
1402     name: 'successCallback',
1403     type: AV.Types.FUNCTION
1404   }, {
1405     name: 'errorCallback',
1406     type: AV.Types.FUNCTION,
1407     optional: true,
1408     nullable: true
1409   }]);
1410
1411   var result = native.callSync('BluetoothLEAdapter_startScan', {});
1412   if (native.isFailure(result)) {
1413     throw native.getErrorObject(result);
1414   }
1415
1416   _bleScanListener.addListener(args.successCallback, args.errorCallback);
1417 };
1418
1419 BluetoothLEAdapter.prototype.stopScan = function() {
1420   privUtils_.log('Entered BluetoothLEAdapter.stopScan()');
1421
1422   _bleScanListener.removeListener();
1423
1424   var result = native.callSync('BluetoothLEAdapter_stopScan', {});
1425   if (native.isFailure(result)) {
1426     throw native.getErrorObject(result);
1427   }
1428 };
1429
1430 var _BluetoothAdvertisePacketType = {
1431   ADVERTISE: 'ADVERTISE',
1432   SCAN_RESPONSE: 'SCAN_RESPONSE'
1433 };
1434
1435 var _BluetoothAdvertisingMode = {
1436   BALANCED: 'BALANCED',
1437   LOW_LATENCY: 'LOW_LATENCY',
1438   LOW_ENERGY: 'LOW_ENERGY'
1439 };
1440
1441 BluetoothLEAdapter.prototype.startAdvertise = function() {
1442   privUtils_.log('Entered BluetoothLEAdapter.startAdvertise()');
1443   var args = AV.validateMethod(arguments, [{
1444     name: 'advertiseData',
1445     type: AV.Types.PLATFORM_OBJECT,
1446     values: tizen.BluetoothLEAdvertiseData
1447   }, {
1448     name: 'packetType',
1449     type: AV.Types.ENUM,
1450     values: T.getValues(_BluetoothAdvertisePacketType)
1451   }, {
1452     name: 'successCallback',
1453     type: AV.Types.FUNCTION
1454   }, {
1455     name: 'errorCallback',
1456     type: AV.Types.FUNCTION,
1457     optional: true,
1458     nullable: true
1459   }, {
1460     name: 'mode',
1461     type: AV.Types.ENUM,
1462     values: T.getValues(_BluetoothAdvertisingMode),
1463     optional: true,
1464     nullable: true
1465   }, {
1466     name: 'connectable',
1467     type: AV.Types.BOOLEAN,
1468     optional: true,
1469     nullable: true
1470   }]);
1471
1472   var callArgs = {
1473     advertiseData: args.advertiseData,
1474     packetType: args.packetType,
1475     mode: T.isNullOrUndefined(args.mode) ? _BluetoothAdvertisingMode.BALANCED : args.mode,
1476     connectable: T.isNullOrUndefined(args.connectable) ? true : args.connectable
1477   };
1478
1479   var result = native.callSync('BluetoothLEAdapter_startAdvertise', callArgs);
1480
1481   if (native.isFailure(result)) {
1482     throw native.getErrorObject(result);
1483   }
1484
1485   _bleAdvertiseListener.addListener(args.successCallback, args.errorCallback);
1486 };
1487
1488 BluetoothLEAdapter.prototype.stopAdvertise = function() {
1489   privUtils_.log('Entered BluetoothLEAdapter.stopAdvertise()');
1490
1491   var result = native.callSync('BluetoothLEAdapter_stopAdvertise', {});
1492
1493   if (native.isFailure(result)) {
1494     throw native.getErrorObject(result);
1495   }
1496 };
1497
1498 //class BluetoothGATTService ////////////////////////////////////////////////////
1499 var BluetoothGATTService = function(data, address) {
1500     var handle_ = data.handle;
1501     var uuid_ = data.uuid;
1502     //address_ is needed to control if device is still connected
1503     var address_ = address || data.address;
1504     function servicesGetter() {
1505         var services = [];
1506         var result = native.callSync('BluetoothGATTService_getServices',
1507                 {handle: handle_, address : address_});
1508         if (native.isSuccess(result)) {
1509             var resultObject = native.getResultObject(result);
1510             resultObject.forEach(function(s) {
1511                 services.push(new BluetoothGATTService(s, address_));
1512             });
1513         }
1514         return services;
1515     }
1516     function characteristicsGetter() {
1517         var characteristics = [];
1518         var result = native.callSync('BluetoothGATTService_getCharacteristics',
1519                 {handle: handle_, uuid: uuid_, address : address_});
1520         if (native.isSuccess(result)) {
1521             var resultObject = native.getResultObject(result);
1522             resultObject.forEach(function(c) {
1523                 characteristics.push(new BluetoothGATTCharacteristic(c, address_));
1524             });
1525         }
1526         return characteristics;
1527     }
1528     Object.defineProperties(this, {
1529         uuid : {value: uuid_, writable: false, enumerable: true},
1530         services : {enumerable: true, set : function() {}, get : servicesGetter},
1531         characteristics : {enumerable: true, set : function() {}, get : characteristicsGetter}
1532     });
1533 };
1534
1535 var toByteArray = function(array) {
1536     var d = [];
1537
1538     array.forEach(function(b) {
1539         d.push(Converter.toOctet(b));
1540     });
1541     return d;
1542 };
1543
1544 //class BluetoothGATTCharacteristic ////////////////////////////////////////////////////
1545 var BluetoothGATTCharacteristic = function(data, address) {
1546   var handle_ = data.handle;
1547   var descriptors_ = [];
1548   var isBroadcast_ = false;
1549   var hasExtendedProperties_ = false;
1550   var isNotify_ = false;
1551   var isIndication_ = false;
1552   var isReadable_ = false;
1553   var isSignedWrite_ = false;
1554   var isWritable_ = false;
1555   var isWriteNoResponse_ = false;
1556   //address_ is needed to control if device is still connected
1557   var address_ = address;
1558
1559   if (T.isObject(data)) {
1560     data.descriptors.forEach(function(dd) {
1561       descriptors_.push(new BluetoothGATTDescriptor(dd, address_));
1562     });
1563     isBroadcast_ = data.isBroadcast;
1564     hasExtendedProperties_ = data.hasExtendedProperties;
1565     isNotify_ = data.isNotify;
1566     isIndication_ = data.isIndication;
1567     isReadable_ = data.isReadable;
1568     isSignedWrite_ = data.isSignedWrite;
1569     isWritable_ = data.isWritable;
1570     isWriteNoResponse_ = data.isWriteNoResponse;
1571   }
1572
1573   Object.defineProperties(this, {
1574     descriptors: {
1575       enumerable: true,
1576       get: function() {
1577         return descriptors_.slice();
1578       },
1579       set: function() {
1580       }
1581     },
1582     isBroadcast: {
1583       enumerable: true,
1584       get: function() {
1585         return isBroadcast_;
1586       },
1587       set: function() {
1588       }
1589     },
1590     hasExtendedProperties: {
1591       enumerable: true,
1592       get: function() {
1593         return hasExtendedProperties_;
1594       },
1595       set: function() {
1596       }
1597     },
1598     isNotify: {
1599       enumerable: true,
1600       get: function() {
1601         return isNotify_;
1602       },
1603       set: function() {
1604       }
1605     },
1606     isIndication: {
1607       enumerable: true,
1608       get: function() {
1609         return isIndication_;
1610       },
1611       set: function() {
1612       }
1613     },
1614     isReadable: {
1615       enumerable: true,
1616       get: function() {
1617         return isReadable_;
1618       },
1619       set: function() {
1620       }
1621     },
1622     isSignedWrite: {
1623       enumerable: true,
1624       get: function() {
1625         return isSignedWrite_;
1626       },
1627       set: function() {
1628       }
1629     },
1630     isWritable: {
1631       enumerable: true,
1632       get: function() {
1633         return isWritable_;
1634       },
1635       set: function() {
1636       }
1637     },
1638     isWriteNoResponse: {
1639       enumerable: true,
1640       get: function() {
1641         return isWriteNoResponse_;
1642       },
1643       set: function() {
1644       }
1645     }
1646   });
1647
1648   this.readValue = function() {
1649       privUtils_.log('Entered BluetoothGATTCharacteristic.readValue()');
1650       var args = AV.validateMethod(arguments, [{
1651         name: 'successCallback',
1652         type: AV.Types.FUNCTION
1653       }, {
1654         name: 'errorCallback',
1655         type: AV.Types.FUNCTION,
1656         optional: true,
1657         nullable: true
1658       }]);
1659
1660       var callback = function(result) {
1661         if (native.isFailure(result)) {
1662           native.callIfPossible(args.errorCallback, native.getErrorObject(result));
1663         } else {
1664           var d = toByteArray(native.getResultObject(result));
1665           args.successCallback(d);
1666         }
1667       };
1668
1669       var callArgs = {handle : handle_, address : address_};
1670
1671       var result = native.call('BluetoothGATT_readValue', callArgs, callback);
1672
1673       if (native.isFailure(result)) {
1674         throw native.getErrorObject(result);
1675       }
1676     };
1677
1678     this.writeValue = function() {
1679       privUtils_.log('Entered BluetoothGATTCharacteristic.writeValue()');
1680       var args = AV.validateMethod(arguments, [{
1681         name: 'value',
1682         type: AV.Types.ARRAY,
1683         values: AV.Types.BYTE
1684       }, {
1685         name: 'successCallback',
1686         type: AV.Types.FUNCTION,
1687         optional: true,
1688         nullable: true
1689       }, {
1690         name: 'errorCallback',
1691         type: AV.Types.FUNCTION,
1692         optional: true,
1693         nullable: true
1694       }]);
1695
1696       var callback = function(result) {
1697         if (native.isFailure(result)) {
1698           native.callIfPossible(args.errorCallback, native.getErrorObject(result));
1699         } else {
1700           native.callIfPossible(args.successCallback);
1701         }
1702       };
1703
1704       var callArgs = { handle : handle_, value: toByteArray(args.value), address : address_ };
1705
1706       var result = native.call('BluetoothGATT_writeValue', callArgs, callback);
1707
1708       if (native.isFailure(result)) {
1709         throw native.getErrorObject(result);
1710       }
1711     };
1712
1713     var addValueChangeListener = function() {
1714       privUtils_.log('Entered BluetoothGATTCharacteristic.addValueChangeListener()');
1715       privUtils_.checkPrivilegeAccess4Ver("2.4", Privilege.BLUETOOTH, Privilege.BLUETOOTH_ADMIN);
1716       var args = AV.validateMethod(arguments, [{
1717         name: 'callback',
1718         type: AV.Types.FUNCTION
1719       }]);
1720
1721       var callArgs = { handle: handle_, address : address_ };
1722
1723       var callback = function(event) {
1724         if (event.handle === handle_) {
1725           args.callback(toByteArray(native.getResultObject(event)));
1726         }
1727       };
1728
1729       return _bluetoothGATTCharacteristicListener.addListener(callback, callArgs);
1730     };
1731
1732     this.addValueChangeListener = function() {
1733       return addValueChangeListener.apply(this, arguments);
1734     };
1735
1736     this.removeValueChangeListener = function() {
1737       privUtils_.log('Entered BluetoothGATTCharacteristic.removeValueChangeListener()');
1738
1739       var args = AV.validateMethod(arguments, [{
1740         name: 'watchID',
1741         type: AV.Types.LONG
1742       }]);
1743
1744       var callArgs = { handle: handle_, address : address_ };
1745
1746       return _bluetoothGATTCharacteristicListener.removeListener(args.watchID, callArgs);
1747     };
1748 };
1749
1750
1751 /**
1752  * Creates a manager for specified listener event. Manager handles multiple
1753  * registered listeners
1754  *
1755  * @param {string} name - name of the listener this manager handles
1756  * @param {function} callback - function to be invoked when event specified by the name fires.
1757  *                              This function should have following signature:
1758  *                              void callback(listener, event);
1759  * @param {string} addListenerId - optional parameter. If specified, this native
1760  *                                 method will be called synchronously when
1761  *                                 listener is added.
1762  * @param {string} removeListenerId - optional parameter. If specified, this native
1763  *                                 method will be called synchronously when
1764  *                                 listener is removed.
1765  * @param {bool} repeatNativeCall - optional parameter. If specified, the addListenerId
1766  *                                 and removeListenerId methods will be called synchronously
1767  *                                 each time listener is added/removed. Otherwise they are
1768  *                                 going to be called just once: when first listener is added
1769  *                                 and last listener is removed.
1770  *
1771  * @return {object} object which allows to add or remove callbacks for specified listener
1772  */
1773 function _multipleListenerBuilder(name, callback, addListenerId, removeListenerId, repeatNativeCall) {
1774   var listenerName = name;
1775   var addId = addListenerId;
1776   var removeId = removeListenerId;
1777   var callbackFunction = callback;
1778   var listeners = {};
1779   var nextId = 1;
1780   var jsListenerRegistered = false;
1781   var nativeListenerRegistered = false;
1782   var repeatNativeListenerCall = repeatNativeCall;
1783
1784   function innerCallback(event) {
1785     for (var watchId in listeners) {
1786       if (listeners.hasOwnProperty(watchId)) {
1787         callbackFunction(listeners[watchId], event);
1788       }
1789     }
1790   }
1791
1792   function addListener(callback, args) {
1793     var id = ++nextId;
1794
1795     if (addId && (!nativeListenerRegistered || repeatNativeListenerCall)) {
1796       var result = native.callSync(addId, args || {});
1797       if (native.isFailure(result)) {
1798         throw native.getErrorObject(result);
1799       }
1800       nativeListenerRegistered = true;
1801     }
1802
1803     if (!jsListenerRegistered) {
1804       native.addListener(listenerName, innerCallback);
1805       jsListenerRegistered = true;
1806     }
1807
1808     listeners[id] = callback;
1809     return id;
1810   }
1811
1812   function removeListener(watchId, args) {
1813     if (listeners.hasOwnProperty(watchId)) {
1814       delete listeners[watchId];
1815     }
1816
1817     if (removeId && ((nativeListenerRegistered && T.isEmptyObject(listeners)) || repeatNativeListenerCall)) {
1818       var result = native.callSync(removeId, args || {});
1819       if (native.isFailure(result)) {
1820         throw native.getErrorObject(result);
1821       }
1822       nativeListenerRegistered = false;
1823     }
1824
1825     if (jsListenerRegistered && T.isEmptyObject(listeners)) {
1826       native.removeListener(listenerName, innerCallback);
1827       jsListenerRegistered = false;
1828     }
1829   }
1830
1831   return {
1832     addListener: addListener,
1833     removeListener: removeListener
1834   };
1835 }
1836
1837 var _bluetoothGATTCharacteristicListener = _multipleListenerBuilder(
1838     'BluetoothGATTCharacteristicValueChangeListener',
1839     function(listener, event) {
1840       listener(event);
1841     },
1842     'BluetoothGATTCharacteristic_addValueChangeListener',
1843     'BluetoothGATTCharacteristic_removeValueChangeListener',
1844     true
1845 );
1846
1847 var _bleConnectChangeListener = _multipleListenerBuilder(
1848     'BluetoothLEConnectChangeCallback',
1849     function(listener, event) {
1850         listener(event);
1851     },
1852     'BluetoothLEDevice_addConnectStateChangeListener',
1853     'BluetoothLEDevice_removeConnectStateChangeListener'
1854 );
1855
1856 //class BluetoothGATTDescriptor ////////////////////////////////////////////////////
1857 var BluetoothGATTDescriptor = function(data, address) {
1858   var handle_ = data.handle;
1859   //address_ is needed to control if device is still connected
1860   var address_ = address;
1861
1862   this.readValue = function() {
1863     privUtils_.log('Entered BluetoothGATTDescriptor.readValue()');
1864     var args = AV.validateMethod(arguments, [{
1865       name: 'successCallback',
1866       type: AV.Types.FUNCTION
1867     }, {
1868       name: 'errorCallback',
1869       type: AV.Types.FUNCTION,
1870       optional: true,
1871       nullable: true
1872     }]);
1873
1874     var callback = function(result) {
1875       if (native.isFailure(result)) {
1876         native.callIfPossible(args.errorCallback, native.getErrorObject(result));
1877       } else {
1878         var d = toByteArray(native.getResultObject(result));
1879         args.successCallback(d);
1880       }
1881     };
1882
1883     var callArgs = {handle : handle_, address : address_};
1884
1885     var result = native.call('BluetoothGATT_readValue', callArgs, callback);
1886
1887     if (native.isFailure(result)) {
1888       throw native.getErrorObject(result);
1889     }
1890   };
1891
1892   this.writeValue = function() {
1893     privUtils_.log('Entered BluetoothGATTDescriptor.writeValue()');
1894     var args = AV.validateMethod(arguments, [{
1895       name: 'value',
1896       type: AV.Types.ARRAY,
1897       values: AV.Types.BYTE
1898     }, {
1899       name: 'successCallback',
1900       type: AV.Types.FUNCTION,
1901       optional: true,
1902       nullable: true
1903     }, {
1904       name: 'errorCallback',
1905       type: AV.Types.FUNCTION,
1906       optional: true,
1907       nullable: true
1908     }]);
1909
1910     var callback = function(result) {
1911       if (native.isFailure(result)) {
1912         native.callIfPossible(args.errorCallback, native.getErrorObject(result));
1913       } else {
1914         native.callIfPossible(args.successCallback);
1915       }
1916     };
1917
1918     var callArgs = { handle : handle_, value: toByteArray(args.value), address : address_ };
1919
1920     var result = native.call('BluetoothGATT_writeValue', callArgs, callback);
1921
1922     if (native.isFailure(result)) {
1923       throw native.getErrorObject(result);
1924     }
1925   };
1926 };
1927
1928
1929
1930 // class BluetoothAdapter ////////////////////////////////////////////////////
1931 var BluetoothAdapter = function() {
1932     function nameGetter() {
1933         var result = native.callSync('BluetoothAdapter_getName', {});
1934
1935         if (native.isFailure(result)) {
1936             return '';
1937         } else {
1938             return native.getResultObject(result);
1939         }
1940     }
1941
1942     function addressGetter() {
1943         var result = native.callSync('BluetoothAdapter_getAddress', {});
1944
1945         if (native.isFailure(result)) {
1946             return '';
1947         } else {
1948             return native.getResultObject(result);
1949         }
1950     }
1951
1952     function poweredGetter() {
1953         var result = native.callSync('BluetoothAdapter_getPowered', {});
1954
1955         if (native.isFailure(result)) {
1956             return false;
1957         } else {
1958             return native.getResultObject(result);
1959         }
1960     }
1961
1962     function visibleGetter() {
1963         var result = native.callSync('BluetoothAdapter_getVisible', {});
1964
1965         if (native.isFailure(result)) {
1966             return false;
1967         } else {
1968             return native.getResultObject(result);
1969         }
1970     }
1971
1972     Object.defineProperties(this, {
1973         name : {
1974             enumerable: true,
1975             set : function(){},
1976             get : nameGetter
1977         },
1978         address : {
1979             enumerable: true,
1980             set : function(){},
1981             get : addressGetter
1982         },
1983         powered : {
1984             enumerable: true,
1985             set : function(){},
1986             get : poweredGetter
1987         },
1988         visible : {
1989             enumerable: true,
1990             set : function(){},
1991             get : visibleGetter
1992         }
1993     });
1994 };
1995
1996 BluetoothAdapter.prototype.setName = function() {
1997     privUtils_.log('Entered BluetoothAdapter.setName()');
1998     var args = AV.validateMethod(arguments, [
1999         {
2000             name : 'name',
2001             type : AV.Types.STRING
2002         },
2003         {
2004             name : 'successCallback',
2005             type : AV.Types.FUNCTION,
2006             optional : true,
2007             nullable : true
2008         },
2009         {
2010             name : 'errorCallback',
2011             type : AV.Types.FUNCTION,
2012             optional : true,
2013             nullable : true
2014         }
2015     ]);
2016
2017     var callArgs = {
2018         name : args.name
2019     };
2020
2021     var callback = function(result) {
2022         if (native.isFailure(result)) {
2023             native.callIfPossible(args.errorCallback, native.getErrorObject(result));
2024         } else {
2025             native.callIfPossible(args.successCallback);
2026         }
2027     };
2028
2029     var result = native.call('BluetoothAdapter_setName', callArgs, callback);
2030     if (native.isFailure(result)) {
2031       throw native.getErrorObject(result);
2032     }
2033 };
2034
2035 BluetoothAdapter.prototype.setPowered = function() {
2036     privUtils_.log('Entered BluetoothAdapter.setPowered()');
2037     privUtils_.warn('DEPRECATION WARNING: setPowered() is deprecated and will be removed from next release. '
2038         + 'Let the user turn on/off Bluetooth through the Settings application instead.');
2039
2040     var args = AV.validateMethod(arguments, [
2041         {
2042             name : 'powered',
2043             type : AV.Types.BOOLEAN
2044         },
2045         {
2046             name : 'successCallback',
2047             type : AV.Types.FUNCTION,
2048             optional : true,
2049             nullable : true
2050         },
2051         {
2052             name : 'errorCallback',
2053             type : AV.Types.FUNCTION,
2054             optional : true,
2055             nullable : true
2056         }
2057     ]);
2058
2059     var callArgs = {
2060         powered : args.powered
2061     };
2062
2063     var callback = function(result) {
2064         if (native.isFailure(result)) {
2065             native.callIfPossible(args.errorCallback, native.getErrorObject(result));
2066         } else {
2067             native.callIfPossible(args.successCallback);
2068         }
2069     };
2070
2071     var result = native.call('BluetoothAdapter_setPowered', callArgs, callback);
2072     if (native.isFailure(result)) {
2073       throw native.getErrorObject(result);
2074     }
2075 };
2076
2077
2078 // This method is deprecated since Tizen 2.3 and will be removed in Tizen 3.0.
2079 BluetoothAdapter.prototype.setVisible = function() {
2080     privUtils_.log('Entered BluetoothAdapter.setVisible()');
2081     privUtils_.warn('DEPRECATION WARNING: setVisible() is deprecated and will be removed from next release. '
2082         + 'Let the user change the Bluetooth visibility through the Settings application instead.');
2083
2084     var args = AV.validateMethod(arguments, [
2085         {
2086             name : 'visible',
2087             type : AV.Types.BOOLEAN
2088         },
2089         {
2090             name : 'successCallback',
2091             type : AV.Types.FUNCTION,
2092             optional : true,
2093             nullable : true
2094         },
2095         {
2096             name : 'errorCallback',
2097             type : AV.Types.FUNCTION,
2098             optional : true,
2099             nullable : true
2100         },
2101         {
2102             name : 'timeout',
2103             type : AV.Types.UNSIGNED_LONG,
2104             optional : true,
2105             nullable : true
2106         }
2107     ]);
2108
2109     var callArgs = {
2110         visible : args.visible,
2111     };
2112
2113     if (args.visible === true) {
2114         if (T.isNullOrUndefined(args.timeout)) {
2115             callArgs.timeout = 0;
2116         } else {
2117             callArgs.timeout = args.timeout > 65535 ? 180 : args.timeout;
2118         }
2119     }
2120
2121     var callback = function(result) {
2122         if (native.isFailure(result)) {
2123             native.callIfPossible(args.errorCallback, native.getErrorObject(result));
2124         } else {
2125             native.callIfPossible(args.successCallback);
2126         }
2127     };
2128
2129     var result = native.call('BluetoothAdapter_setVisible', callArgs, callback);
2130     if (native.isFailure(result)) {
2131       throw native.getErrorObject(result);
2132     }
2133 };
2134
2135 var _listener;
2136
2137 function _BluetoothAdapterChangeCallback(event) {
2138     privUtils_.log('_BluetoothAdapterChangeCallback');
2139
2140     var e = event;
2141     var d;
2142
2143     switch (e.action) {
2144     case 'onstatechanged':
2145         d = e.powered;
2146         break;
2147
2148     case 'onnamechanged':
2149         d = e.name;
2150         break;
2151
2152     case 'onvisibilitychanged':
2153         d = e.visible;
2154         break;
2155
2156     default:
2157         privUtils_.log('Unknown mode: ' + e.action);
2158         return;
2159     }
2160
2161     if (_listener[e.action]) {
2162         _listener[e.action](d);
2163     }
2164 }
2165
2166 BluetoothAdapter.prototype.setChangeListener = function() {
2167     privUtils_.log('Entered BluetoothAdapter.setChangeListener()');
2168     var args = AV.validateMethod(arguments, [
2169         {
2170             name : 'changeCallback',
2171             type : AV.Types.LISTENER,
2172             values : ['onstatechanged', 'onnamechanged', 'onvisibilitychanged']
2173         }
2174     ]);
2175
2176     if (T.isNullOrUndefined(_listener)) {
2177         native.addListener('BluetoothAdapterChangeCallback', _BluetoothAdapterChangeCallback);
2178     }
2179     _listener = args.changeCallback;
2180 };
2181
2182 BluetoothAdapter.prototype.unsetChangeListener = function() {
2183     privUtils_.log('Entered BluetoothAdapter.unsetChangeListener()');
2184     if (!T.isNullOrUndefined(_listener)) {
2185         native.removeListener('BluetoothAdapterChangeCallback', _BluetoothAdapterChangeCallback);
2186         _listener = undefined;
2187     }
2188 };
2189
2190 var _discoverDevicesSuccessCallback;
2191 var _discoverDevicesErrorCallback;
2192
2193 function _BluetoothDiscoverDevicesSuccessCallback(event) {
2194     var e = event;
2195     var d = null;
2196
2197     switch (e.action) {
2198     case 'onstarted':
2199         break;
2200
2201     case 'ondevicefound':
2202         d = new BluetoothDevice(e.data);
2203         break;
2204
2205     case 'ondevicedisappeared':
2206         d = e.data;
2207         break;
2208
2209     case 'onfinished':
2210         var result = e.data;
2211         d = [];
2212         result.forEach(function (data) {
2213             d.push(new BluetoothDevice(data));
2214         });
2215
2216         //remove listeners after discovering
2217         native.removeListener('BluetoothDiscoverDevicesSuccessCallback',
2218                 _BluetoothDiscoverDevicesSuccessCallback);
2219         native.removeListener('BluetoothDiscoverDevicesErrorCallback',
2220                 _BluetoothDiscoverDevicesErrorCallback);
2221         break;
2222
2223     default:
2224         privUtils_.log('Unknown mode: ' + e.action);
2225         return;
2226     }
2227
2228     if (_discoverDevicesSuccessCallback[e.action]) {
2229         _discoverDevicesSuccessCallback[e.action](d);
2230     }
2231 }
2232
2233 function _BluetoothDiscoverDevicesErrorCallback(event) {
2234     var e = event;
2235     setTimeout(function() {
2236         native.callIfPossible(_discoverDevicesErrorCallback, native.getErrorObject(e));
2237     }, 0);
2238 }
2239
2240 BluetoothAdapter.prototype.discoverDevices = function() {
2241     privUtils_.log('Entered BluetoothAdapter.discoverDevices()');
2242     var args = AV.validateMethod(arguments, [
2243         {
2244             name : 'successCallback',
2245             type : AV.Types.LISTENER,
2246             values : ['onstarted', 'ondevicefound', 'ondevicedisappeared', 'onfinished']
2247         },
2248         {
2249             name : 'errorCallback',
2250             type : AV.Types.FUNCTION,
2251             optional : true,
2252             nullable : true
2253         }
2254     ]);
2255
2256     _discoverDevicesSuccessCallback = args.successCallback;
2257     _discoverDevicesErrorCallback = args.errorCallback;
2258     native.addListener('BluetoothDiscoverDevicesSuccessCallback',
2259             _BluetoothDiscoverDevicesSuccessCallback);
2260     native.addListener('BluetoothDiscoverDevicesErrorCallback',
2261             _BluetoothDiscoverDevicesErrorCallback);
2262
2263     var result = native.callSync('BluetoothAdapter_discoverDevices', {});
2264
2265     if (native.isFailure(result)) {
2266         native.removeListener('BluetoothDiscoverDevicesSuccessCallback',
2267                 _BluetoothDiscoverDevicesSuccessCallback);
2268         native.removeListener('BluetoothDiscoverDevicesErrorCallback',
2269                 _BluetoothDiscoverDevicesErrorCallback);
2270         throw native.getErrorObject(result);
2271     }
2272 };
2273
2274 BluetoothAdapter.prototype.stopDiscovery = function() {
2275     privUtils_.log('Entered BluetoothAdapter.stopDiscovery()');
2276     var args = AV.validateMethod(arguments, [
2277         {
2278             name : 'successCallback',
2279             type : AV.Types.FUNCTION,
2280             optional : true,
2281             nullable : true
2282         },
2283         {
2284             name : 'errorCallback',
2285             type : AV.Types.FUNCTION,
2286             optional : true,
2287             nullable : true
2288         }
2289     ]);
2290
2291     var callback = function(result) {
2292         if (native.isFailure(result)) {
2293             native.callIfPossible(args.errorCallback, native.getErrorObject(result));
2294         } else {
2295             native.callIfPossible(args.successCallback);
2296         }
2297     };
2298
2299     var result = native.call('BluetoothAdapter_stopDiscovery', {}, callback);
2300     if (native.isFailure(result)) {
2301       throw native.getErrorObject(result);
2302     }
2303 };
2304
2305 BluetoothAdapter.prototype.getKnownDevices = function() {
2306     privUtils_.log('Entered BluetoothAdapter.getKnownDevices()');
2307     var args = AV.validateMethod(arguments, [
2308         {
2309             name : 'successCallback',
2310             type : AV.Types.FUNCTION
2311         },
2312         {
2313             name : 'errorCallback',
2314             type : AV.Types.FUNCTION,
2315             optional : true,
2316             nullable : true
2317         }
2318     ]);
2319
2320     var callback = function(result) {
2321         if (native.isFailure(result)) {
2322             native.callIfPossible(args.errorCallback, native.getErrorObject(result));
2323         } else {
2324             var r = native.getResultObject(result).devices;
2325             var devices = [];
2326             r.forEach(function (data) {
2327                 devices.push(new BluetoothDevice(data));
2328             });
2329             args.successCallback(devices);
2330         }
2331     };
2332
2333     var result = native.call('BluetoothAdapter_getKnownDevices', {}, callback);
2334     if (native.isFailure(result)) {
2335       throw native.getErrorObject(result);
2336     }
2337 };
2338
2339 BluetoothAdapter.prototype.getDevice = function() {
2340     privUtils_.log('Entered BluetoothAdapter.getDevice()');
2341     var args = AV.validateMethod(arguments, [
2342         {
2343             name : 'address',
2344             type : AV.Types.STRING
2345         },
2346         {
2347             name : 'successCallback',
2348             type : AV.Types.FUNCTION
2349         },
2350         {
2351             name : 'errorCallback',
2352             type : AV.Types.FUNCTION,
2353             optional : true,
2354             nullable : true
2355         }
2356     ]);
2357
2358     var callback = function(result) {
2359         if (native.isFailure(result)) {
2360             native.callIfPossible(args.errorCallback, native.getErrorObject(result));
2361         } else {
2362             args.successCallback(new BluetoothDevice(native.getResultObject(result)));
2363         }
2364     };
2365
2366     var result = native.call('BluetoothAdapter_getDevice', {address : args.address}, callback);
2367     if (native.isFailure(result)) {
2368       throw native.getErrorObject(result);
2369     }
2370 };
2371
2372 BluetoothAdapter.prototype.createBonding = function() {
2373     privUtils_.log('Entered BluetoothAdapter.createBonding()');
2374     var args = AV.validateMethod(arguments, [
2375         {
2376             name : 'address',
2377             type : AV.Types.STRING
2378         },
2379         {
2380             name : 'successCallback',
2381             type : AV.Types.FUNCTION,
2382             optional : false,
2383             nullable : false
2384         },
2385         {
2386             name : 'errorCallback',
2387             type : AV.Types.FUNCTION,
2388             optional : true,
2389             nullable : true
2390         }
2391     ]);
2392
2393     var callArgs = {
2394         address : args.address
2395     };
2396
2397     var callback = function(result) {
2398         if (native.isFailure(result)) {
2399             native.callIfPossible(args.errorCallback, native.getErrorObject(result));
2400         } else {
2401             args.successCallback(new BluetoothDevice(native.getResultObject(result)));
2402         }
2403     };
2404
2405     var result = native.call('BluetoothAdapter_createBonding', callArgs, callback);
2406     if (native.isFailure(result)) {
2407       throw native.getErrorObject(result);
2408     }
2409 };
2410
2411 BluetoothAdapter.prototype.destroyBonding = function() {
2412     privUtils_.log('Entered BluetoothAdapter.destroyBonding()');
2413     var args = AV.validateMethod(arguments, [
2414         {
2415             name : 'address',
2416             type : AV.Types.STRING
2417         },
2418         {
2419             name : 'successCallback',
2420             type : AV.Types.FUNCTION,
2421             optional : true,
2422             nullable : true
2423         },
2424         {
2425             name : 'errorCallback',
2426             type : AV.Types.FUNCTION,
2427             optional : true,
2428             nullable : true
2429         }
2430     ]);
2431
2432     var callArgs = {
2433         address : args.address
2434     };
2435
2436     var callback = function(result) {
2437         if (native.isFailure(result)) {
2438             native.callIfPossible(args.errorCallback, native.getErrorObject(result));
2439         } else {
2440             native.callIfPossible(args.successCallback);
2441         }
2442     };
2443
2444     var result = native.call('BluetoothAdapter_destroyBonding', callArgs, callback);
2445     if (native.isFailure(result)) {
2446       throw native.getErrorObject(result);
2447     }
2448 };
2449
2450 BluetoothAdapter.prototype.registerRFCOMMServiceByUUID = function() {
2451     privUtils_.log('Entered BluetoothAdapter.registerRFCOMMServiceByUUID()');
2452     var args = AV.validateMethod(arguments, [
2453         {
2454             name : 'uuid',
2455             type : AV.Types.STRING
2456         },
2457         {
2458             name : 'name',
2459             type : AV.Types.STRING
2460         },
2461         {
2462             name : 'successCallback',
2463             type : AV.Types.FUNCTION,
2464         },
2465         {
2466             name : 'errorCallback',
2467             type : AV.Types.FUNCTION,
2468             optional : true,
2469             nullable : true
2470         }
2471     ]);
2472
2473     var callArgs = {
2474         uuid : args.uuid,
2475         name : args.name
2476     };
2477
2478     var callback = function(result) {
2479         if (native.isFailure(result)) {
2480             native.callIfPossible(args.errorCallback, native.getErrorObject(result));
2481         } else {
2482             // if registration was finished with success create BluetoothServiceHandler
2483             // with parameters passed to this function (uuid and name).
2484             args.successCallback(new BluetoothServiceHandler(callArgs));
2485         }
2486     };
2487
2488     var result = native.call('BluetoothAdapter_registerRFCOMMServiceByUUID', callArgs, callback);
2489     if (native.isFailure(result)) {
2490       throw native.getErrorObject(result);
2491     }
2492 };
2493
2494 BluetoothAdapter.prototype.getBluetoothProfileHandler = function() {
2495     privUtils_.log('Entered BluetoothAdapter.getBluetoothProfileHandler()');
2496
2497     var args = AV.validateMethod(arguments, [
2498         {
2499             name : 'profileType',
2500             type : AV.Types.ENUM,
2501             values : T.getValues(_BluetoothProfileType)
2502         }
2503     ]);
2504
2505     var callArgs = {profileType : args.profileType};
2506
2507     var result = native.callSync('BluetoothAdapter_getBluetoothProfileHandler', callArgs);
2508
2509     if (native.isFailure(result)) {
2510         throw native.getErrorObject(result);
2511     } else {
2512         switch (args.profileType) {
2513         case _BluetoothProfileType.HEALTH:
2514             return new BluetoothHealthProfileHandler(callArgs);
2515
2516         default:
2517             throw new WebAPIException('NotSupportedError', 'Profile ' + args.profileType + ' is not supported.');
2518         }
2519     }
2520 };
2521
2522 // class BluetoothManager ////////////////////////////////////////////////////
2523 var BluetoothManager = function() {
2524     Object.defineProperties(this, {
2525         deviceMajor : {
2526             value: new BluetoothClassDeviceMajor(),
2527             writable: false,
2528             enumerable: true
2529         },
2530         deviceMinor : {
2531             value: new BluetoothClassDeviceMinor(),
2532             writable: false,
2533             enumerable: true
2534         },
2535         deviceService : {
2536             value: new BluetoothClassDeviceService(),
2537             writable: false,
2538             enumerable: true
2539         }
2540     });
2541 };
2542
2543 var BluetoothManager_getDefaultAdapter = function() {
2544   privUtils_.checkPrivilegeAccess4Ver("2.4", Privilege.BLUETOOTH, Privilege.BLUETOOTH_GAP);
2545
2546   return new BluetoothAdapter();
2547 };
2548
2549
2550 BluetoothManager.prototype.getDefaultAdapter = function() {
2551     privUtils_.log('Entered BluetoothManager.getDefaultAdapter()');
2552     return BluetoothManager_getDefaultAdapter();
2553 };
2554
2555 var BluetoothManager_getLEAdapter = function() {
2556   privUtils_.checkPrivilegeAccess4Ver("2.4", Privilege.BLUETOOTH, Privilege.BLUETOOTH_ADMIN);
2557
2558   return new BluetoothLEAdapter();
2559 };
2560
2561 BluetoothManager.prototype.getLEAdapter = function() {
2562     privUtils_.log('Entered BluetoothManager.getLEAdapter()');
2563     return BluetoothManager_getLEAdapter();
2564 };
2565 // exports ///////////////////////////////////////////////////////////////////
2566 exports = new BluetoothManager();