Update change log and spec for wrt-plugins-tizen_0.4.70
[framework/web/wrt-plugins-tizen.git] / src / Bluetooth / BluetoothHealthProfileHandler.cpp
1 //
2 // Tizen Web Device API
3 // Copyright (c) 2012 Samsung Electronics Co., Ltd.
4 //
5 // Licensed under the Apache License, Version 2.0 (the License);
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 // http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 //
17
18
19 #include <Logger.h>
20 #include <JSWebAPIErrorFactory.h>
21 #include <JSUtil.h>
22 #include <TimeTracer.h>
23
24 #include "BluetoothHealthProfileHandler.h"
25 #include "BluetoothHealthProfileHandlerCallback.h"
26 #include "JSBluetoothHealthApplication.h"
27 #include "JSBluetoothDevice.h"
28 #include "JSBluetoothHealthChannel.h"
29 #include "BluetoothHealthChannel.h"
30
31 using namespace DeviceAPI::Common;
32
33 namespace DeviceAPI {
34 namespace Bluetooth {
35
36 void BluetoothHealthProfileHandler::onConnected(int result, const char *remote_address, const char *app_id, 
37         bt_hdp_channel_type_e type, unsigned int channel, void *userData)
38 {
39     LoggerD("Enter");
40     TIME_TRACER_ITEM_BEGIN(__FUNCTION__, 1);
41
42     HealthProfileHandlerPtr object = static_cast<HealthProfileHandlerPtr>(userData);
43     if(!object) {
44         LoggerW("userData is NULL");
45         return;
46     }
47
48     if(result != BT_ERROR_NONE) {
49         LoggerD("Not BT_ERROR_NONE");
50     }
51
52     LoggerD("Connected app: " << app_id);
53     LoggerD("Connected channel: " << channel);
54
55     std::string appID(app_id);
56     RegisteredHealthAppMapT::iterator iter = object->mRegisteredHealthAppMap.find(appID);
57     if(iter == object->mRegisteredHealthAppMap.end()) {
58         LoggerW("This app is not registered");
59         return;        
60     }
61     BluetoothHealthApplicationSharedPtr application = iter->second;
62
63     bool isChannelInserted = false;
64     BluetoothHealthChannelPtr healthChannel = NULL;
65
66     //  call BluetoothHealthApplication.onconnect
67     if(result == BT_ERROR_NONE) {
68         Common::MultiCallbackUserDataPtr callback = application->getOnConnect();
69         if(callback) {
70             bt_device_info_s *deviceInfo = NULL;
71             if(bt_adapter_get_bonded_device_info(remote_address, &deviceInfo) == BT_ERROR_NONE &&
72                     deviceInfo != NULL) {            
73                 BluetoothDeviceSharedPtr device(new BluetoothDevice(deviceInfo));
74                                 // need to check
75                                 device->copyAceCheckAccessFunction(getInstance());
76                 bt_adapter_free_device_info(deviceInfo);
77             
78                 LoggerD("invoke BluetoothHealthApplication.onconnect");
79                 healthChannel = new BluetoothHealthChannel(channel, device, type, application);
80                                 healthChannel->copyAceCheckAccessFunction(getInstance());
81                 object->mConnectedSocketMap.insert(std::pair<unsigned int, BluetoothHealthChannelPtr>(channel, healthChannel));
82                 isChannelInserted = true;
83                 callback->invokeCallback("onconnect", JSBluetoothHealthChannel::createJSObject(callback->getContext(), healthChannel));        
84             }
85             else {
86                 LoggerE("Can't call BluetoothHealthApplication.onconnect because failed to get device info");
87             }
88         }
89         else {
90             LoggerD("BluetoothHealthApplication.onconnect is not set");
91         }
92     }
93
94     // in case of connectToSource()
95     HealthConnReqMapT::iterator i = object->mHealthConnReqMap.find(application);
96     if(i != object->mHealthConnReqMap.end()) {
97         LoggerD("Requested connection");
98         Common::MultiCallbackUserDataPtr callback = i->second->mUserData;
99         if(callback) {
100             if(result == BT_ERROR_NONE) {
101                 if(isChannelInserted == false) {
102                     healthChannel = new BluetoothHealthChannel(channel, i->second->mRemoteDevice, type, application);
103                                         healthChannel->copyAceCheckAccessFunction(getInstance());
104                     object->mConnectedSocketMap.insert(std::pair<unsigned int, BluetoothHealthChannelPtr>(channel, healthChannel));
105                 }
106                 callback->invokeCallback("success", JSBluetoothHealthChannel::createJSObject(callback->getContext(), healthChannel));               
107             }
108             else {
109                 LoggerE("Failed to establish a connection with health profile");
110                 callback->invokeCallback("error", 
111                         JSWebAPIErrorFactory::makeErrorObject(callback->getContext(), UnknownException("Failed to establish a connection with health profile")));
112             }     
113         }       
114
115         // Update mHealthConnReqMap
116         object->mHealthConnReqMap.erase(i);            
117     }
118     else {
119         LoggerD("There is no connection request");
120     }    
121
122     TIME_TRACER_ITEM_END(__FUNCTION__, 1);
123 }
124
125 void BluetoothHealthProfileHandler::onDisconnected(int result, const char *remote_address, unsigned int channel, void *userData)
126 {
127     LoggerD("Enter");
128     TIME_TRACER_ITEM_BEGIN(__FUNCTION__, 1);
129
130     HealthProfileHandlerPtr object = static_cast<HealthProfileHandlerPtr>(userData);
131     if(!object) {
132         LoggerW("userData is NULL");
133         return;
134     }
135
136     LoggerD("Disconnected channel: " << channel);
137     HealthConnectedSocketMapT::iterator iter = object->mConnectedSocketMap.find(channel);
138     if(iter == object->mConnectedSocketMap.end()) {
139         LoggerW("Unexpected health disconnection event");
140         return;
141     }
142
143     if(result == BT_ERROR_NONE) {
144         BluetoothHealthChannelPtr healthChannel = iter->second;
145         object->mConnectedSocketMap.erase(iter);
146
147         healthChannel->setConnectionState(false);
148         MultiCallbackUserDataPtr callback = healthChannel->getListener();
149         if(callback)
150             callback->invokeCallback("onclose");        
151     }
152     else {
153         LoggerW("Failed to disconnect a connection");
154     }
155
156     TIME_TRACER_ITEM_END(__FUNCTION__, 1);
157     LoggerD("End");
158 }
159
160 void BluetoothHealthProfileHandler::onDataReceivedCB(unsigned int channel, const char *data, unsigned int size, void *userData)
161 {
162     LoggerD("Enter");
163
164     TIME_TRACER_ITEM_BEGIN(__FUNCTION__, 1);
165
166     HealthProfileHandlerPtr object = static_cast<HealthProfileHandlerPtr>(userData);
167     if(!object) {
168         LoggerW("userData is NULL");
169         return;
170     }
171
172     LoggerD("data channel: " << channel);
173     LoggerD("sent data size: " << size);
174     HealthConnectedSocketMapT::iterator iter = object->mConnectedSocketMap.find(channel);
175     if(iter == object->mConnectedSocketMap.end()) {
176         LoggerW("Unexpected health data received event");
177         return;
178     }
179
180     BluetoothHealthChannelPtr healthChannel = iter->second;
181     MultiCallbackUserDataPtr callback = healthChannel->getListener();        
182     if(callback) {
183         std::vector<signed char> receivedData;
184         for(unsigned int i = 0; i < size; i++) {
185             receivedData.push_back(static_cast<signed char>(data[i]));
186         }
187         callback->invokeCallback("onmessage", JSUtil::toJSValueRef_(callback->getContext(), receivedData));
188     }
189     
190     TIME_TRACER_ITEM_END(__FUNCTION__, 1);
191 }
192
193 BluetoothHealthProfileHandler* BluetoothHealthProfileHandler::getInstance()
194 {
195     static BluetoothHealthProfileHandler instance;
196     return &instance;
197 }
198
199 BluetoothHealthProfileHandler::BluetoothHealthProfileHandler()
200 {
201         Common::SecurityAccessor();             
202
203     if(bt_hdp_set_connection_state_changed_cb(onConnected, onDisconnected, this) != BT_ERROR_NONE) {
204         LoggerE("bt_hdp_set_connection_state_changed_cb() failed");
205     }
206
207     if(bt_hdp_set_data_received_cb(onDataReceivedCB, this) != BT_ERROR_NONE) {
208         LoggerE("bt_hdp_set_data_received_cb() failed");
209     }    
210 }
211
212
213 BluetoothHealthProfileHandler::~BluetoothHealthProfileHandler()
214 {
215     // unset platform callback
216     bt_hdp_unset_connection_state_changed_cb();
217     bt_hdp_unset_data_received_cb();
218
219     mHealthConnReqMap.clear();
220     mConnectedSocketMap.clear();
221     mRegisteredHealthAppMap.clear();    
222 }
223
224 void BluetoothHealthProfileHandler::registerSinkApp(unsigned short dataType, std::string name, Common::MultiCallbackUserDataPtr callback)
225 {
226     TIME_TRACER_ITEM_BEGIN(__FUNCTION__, 1);
227     BluetoothHealthProfileHandlerCallback::syncToAsyncRegisterCB(callback, dataType, name);
228     TIME_TRACER_ITEM_END(__FUNCTION__, 1);    
229 }
230
231 void BluetoothHealthProfileHandler::returnRegisteringSinkAppResult(unsigned short dataType, std::string name, Common::MultiCallbackUserDataPtr callback)
232 {
233     LoggerD("Enter");
234     TIME_TRACER_ITEM_BEGIN(__FUNCTION__, 1);
235
236     char *app_id = NULL;
237     int ret = bt_hdp_register_sink_app(dataType, &app_id);
238     switch(ret) {
239         case BT_ERROR_NONE:
240         {
241             LoggerD("Registered app: " << app_id);
242             std::string appID(app_id);
243             //free(app_id);
244             BluetoothHealthApplicationSharedPtr application(new BluetoothHealthApplication(appID, name, dataType));
245                         application->copyAceCheckAccessFunction(getInstance());
246
247             mRegisteredHealthAppMap.insert(std::pair<std::string, BluetoothHealthApplicationSharedPtr>(appID, application));
248             if(callback)
249                 callback->invokeCallback("success", JSBluetoothHealthApplication::createJSObject(callback->getContext(), application));
250             break;
251         }
252         case BT_ERROR_NOT_ENABLED:
253         {
254             if(callback) {
255                 callback->invokeCallback("error", 
256                         JSWebAPIErrorFactory::makeErrorObject(callback->getContext(), ServiceNotAvailableException("Bluetooth device is turned off")));            
257             }
258             break;
259         }
260         default:
261         {
262             if(callback) {
263                 callback->invokeCallback("error", 
264                         JSWebAPIErrorFactory::makeErrorObject(callback->getContext(), UnknownException("Unknown error")));            
265             }
266         }
267     }
268     
269     TIME_TRACER_ITEM_END(__FUNCTION__, 1); 
270 }
271
272 /*
273 void BluetoothHealthProfileHandler::unregisterSinkApplication(JSObjectRef appObj, Common::MultiCallbackUserDataPtr callback)
274 {
275     TIME_TRACER_ITEM_BEGIN(__FUNCTION__, 1);
276     BluetoothHealthProfileHandlerCallback::syncToAsyncUnregisterCB(callback, appObj);
277     TIME_TRACER_ITEM_END(__FUNCTION__, 1);    
278 }
279
280 void BluetoothHealthProfileHandler::returnUnregisteringResult(JSObjectRef appObj, Common::MultiCallbackUserDataPtr callback)
281 {
282     TIME_TRACER_ITEM_BEGIN(__FUNCTION__, 1);
283     
284     BluetoothHealthApplicationSharedPtr app = JSBluetoothHealthApplication::toBluetoothHealthApplication(appObj);
285     int ret = bt_hdp_unregister_sink_app(app->getAppID().c_str());
286     switch(ret) {
287         case BT_ERROR_NONE:
288         {
289             //app->setRegistrationState(false);
290             BluetoothHealthProfileHandlerCallback::syncToAsyncSuccessCB(callback);
291             break;
292         }
293         case BT_ERROR_NOT_ENABLED:
294         {
295             ServiceNotAvailableException *error =  new ServiceNotAvailableException("Bluetooth device is turned off");
296             BluetoothHealthProfileHandlerCallback::syncToAsyncErrorCB(callback, error);
297             break;
298         }
299         default:
300         {
301             UnknownException *error = new UnknownException("Unknown error");
302             BluetoothHealthProfileHandlerCallback::syncToAsyncErrorCB(callback, error);
303         }        
304     }
305     
306     TIME_TRACER_ITEM_END(__FUNCTION__, 1); 
307 }
308 */
309
310 void BluetoothHealthProfileHandler::unregisterApp(std::string appID, Common::MultiCallbackUserDataPtr callback)
311 {
312     TIME_TRACER_ITEM_BEGIN(__FUNCTION__, 1);
313     BluetoothHealthProfileHandlerCallback::syncToAsyncUnregisterCB(callback, appID);
314     TIME_TRACER_ITEM_END(__FUNCTION__, 1);    
315 }
316
317 void BluetoothHealthProfileHandler::returnUnregisteringAppResult(std::string appID, Common::MultiCallbackUserDataPtr callback)
318 {
319     TIME_TRACER_ITEM_BEGIN(__FUNCTION__, 1);  
320
321     RegisteredHealthAppMapT::iterator iter = mRegisteredHealthAppMap.find(appID);
322     BluetoothHealthApplicationSharedPtr application;
323     if(iter != mRegisteredHealthAppMap.end()) {
324         LoggerE("registered Health Application is found");
325         application = iter->second;    
326     }
327     else {
328         LoggerD("Already unregistered");
329         if(callback)
330             callback->invokeCallback("success");
331         return;
332     }    
333
334     int ret = bt_hdp_unregister_sink_app(appID.c_str());
335     switch(ret) {
336         case BT_ERROR_NONE:
337         {
338             mRegisteredHealthAppMap.erase(iter);
339             application->setRegistrationState(false);
340             if(callback)
341                 callback->invokeCallback("success");           
342             break;
343         }
344         case BT_ERROR_NOT_ENABLED:
345         {
346             if(callback) {
347                 callback->invokeCallback("error", 
348                         JSWebAPIErrorFactory::makeErrorObject(callback->getContext(), ServiceNotAvailableException("Bluetooth device is turned off")));            
349             }
350             break;
351         }
352         default:
353         {
354             if(callback) {
355                 callback->invokeCallback("error", 
356                         JSWebAPIErrorFactory::makeErrorObject(callback->getContext(), UnknownException("Unknown error")));            
357             }
358         }        
359     }
360     
361     TIME_TRACER_ITEM_END(__FUNCTION__, 1); 
362 }
363
364 void BluetoothHealthProfileHandler::connectToSource(JSObjectRef remoteDeviceObj, JSObjectRef appObj, Common::MultiCallbackUserDataPtr callback)
365 {
366     LoggerD("Enter");
367     
368     TIME_TRACER_ITEM_BEGIN(__FUNCTION__, 1);
369
370     BluetoothDeviceSharedPtr device = JSBluetoothDevice::toBluetoothDevice(remoteDeviceObj);
371     BluetoothHealthApplicationSharedPtr app = JSBluetoothHealthApplication::toBluetoothHealthApplication(appObj);
372     LoggerD("address: " << device->getAddress().c_str());
373     LoggerD("app ID: " << app->getAppID().c_str());    
374     int ret = bt_hdp_connect_to_source(device->getAddress().c_str(), app->getAppID().c_str());
375     switch(ret) {
376         case BT_ERROR_NONE:
377         {
378             LoggerD("NONE");
379             HealthConnReqPtr connReq = new HealthConnReq(device, callback);
380             mHealthConnReqMap.insert(std::pair<BluetoothHealthApplicationSharedPtr, HealthConnReqPtr>(app, connReq));            
381             break;
382         }
383         case BT_ERROR_NOT_ENABLED:
384         {
385             LoggerD("Not Enabled");
386             ServiceNotAvailableException *error =  new ServiceNotAvailableException("Bluetooth device is turned off");
387             BluetoothHealthProfileHandlerCallback::syncToAsyncErrorCB(callback, error);
388             break;
389         }
390         case BT_ERROR_INVALID_PARAMETER:
391         case BT_ERROR_REMOTE_DEVICE_NOT_BONDED:
392         {
393             LoggerD("invalid value");
394             InvalidValuesException *error = new InvalidValuesException("Invalid value");
395             BluetoothHealthProfileHandlerCallback::syncToAsyncErrorCB(callback, error);
396             break;
397         }
398         default:
399         {
400             LoggerD("Unknown error");
401             UnknownException *error = new UnknownException("Unknown error");
402             BluetoothHealthProfileHandlerCallback::syncToAsyncErrorCB(callback, error);
403         }        
404     }
405
406     TIME_TRACER_ITEM_END(__FUNCTION__, 1); 
407 }
408
409
410 } // Bluetooth
411 } // DeviceAPI