834e8fa88cf4cdda567f3c7ad1ce4aeacbf2f451
[platform/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                 bt_adapter_free_device_info(deviceInfo);
75             
76                 LoggerD("invoke BluetoothHealthApplication.onconnect");
77                 healthChannel = new BluetoothHealthChannel(channel, device, type, application);
78                 object->mConnectedSocketMap.insert(std::pair<unsigned int, BluetoothHealthChannelPtr>(channel, healthChannel));
79                 isChannelInserted = true;
80                 callback->invokeCallback("onconnect", JSBluetoothHealthChannel::createJSObject(callback->getContext(), healthChannel));        
81             }
82             else {
83                 LoggerE("Can't call BluetoothHealthApplication.onconnect because failed to get device info");
84             }
85         }
86         else {
87             LoggerD("BluetoothHealthApplication.onconnect is not set");
88         }
89     }
90
91     // in case of connectToSource()
92     HealthConnReqMapT::iterator i = object->mHealthConnReqMap.find(application);
93     if(i != object->mHealthConnReqMap.end()) {
94         LoggerD("Requested connection");
95         Common::MultiCallbackUserDataPtr callback = i->second->mUserData;
96         if(callback) {
97             if(result == BT_ERROR_NONE) {
98                 if(isChannelInserted == false) {
99                     healthChannel = new BluetoothHealthChannel(channel, i->second->mRemoteDevice, type, application);
100                     object->mConnectedSocketMap.insert(std::pair<unsigned int, BluetoothHealthChannelPtr>(channel, healthChannel));
101                 }
102                 callback->invokeCallback("success", JSBluetoothHealthChannel::createJSObject(callback->getContext(), healthChannel));               
103             }
104             else {
105                 LoggerE("Failed to establish a connection with health profile");
106                 callback->invokeCallback("error", 
107                         JSWebAPIErrorFactory::makeErrorObject(callback->getContext(), UnknownException("Failed to establish a connection with health profile")));
108             }     
109         }       
110
111         // Update mHealthConnReqMap
112         object->mHealthConnReqMap.erase(i);            
113     }
114     else {
115         LoggerD("There is no connection request");
116     }    
117
118     TIME_TRACER_ITEM_END(__FUNCTION__, 1);
119 }
120
121 void BluetoothHealthProfileHandler::onDisconnected(int result, const char *remote_address, unsigned int channel, void *userData)
122 {
123     LoggerD("Enter");
124     TIME_TRACER_ITEM_BEGIN(__FUNCTION__, 1);
125
126     HealthProfileHandlerPtr object = static_cast<HealthProfileHandlerPtr>(userData);
127     if(!object) {
128         LoggerW("userData is NULL");
129         return;
130     }
131
132     LoggerD("Disconnected channel: " << channel);
133     HealthConnectedSocketMapT::iterator iter = object->mConnectedSocketMap.find(channel);
134     if(iter == object->mConnectedSocketMap.end()) {
135         LoggerW("Unexpected health disconnection event");
136         return;
137     }
138
139     if(result == BT_ERROR_NONE) {
140         BluetoothHealthChannelPtr healthChannel = iter->second;
141         object->mConnectedSocketMap.erase(iter);
142
143         healthChannel->setConnectionState(false);
144         MultiCallbackUserDataPtr callback = healthChannel->getListener();
145         if(callback)
146             callback->invokeCallback("onclose");        
147     }
148     else {
149         LoggerW("Failed to disconnect a connection");
150     }
151
152     TIME_TRACER_ITEM_END(__FUNCTION__, 1);
153     LoggerD("End");
154 }
155
156 void BluetoothHealthProfileHandler::onDataReceivedCB(unsigned int channel, const char *data, unsigned int size, void *userData)
157 {
158     LoggerD("Enter");
159
160     TIME_TRACER_ITEM_BEGIN(__FUNCTION__, 1);
161
162     HealthProfileHandlerPtr object = static_cast<HealthProfileHandlerPtr>(userData);
163     if(!object) {
164         LoggerW("userData is NULL");
165         return;
166     }
167
168     LoggerD("data channel: " << channel);
169     LoggerD("sent data size: " << size);
170     HealthConnectedSocketMapT::iterator iter = object->mConnectedSocketMap.find(channel);
171     if(iter == object->mConnectedSocketMap.end()) {
172         LoggerW("Unexpected health data received event");
173         return;
174     }
175
176     BluetoothHealthChannelPtr healthChannel = iter->second;
177     MultiCallbackUserDataPtr callback = healthChannel->getListener();        
178     if(callback) {
179         std::vector<signed char> receivedData;
180         for(unsigned int i = 0; i < size; i++) {
181             receivedData.push_back(static_cast<signed char>(data[i]));
182         }
183         callback->invokeCallback("onmessage", JSUtil::toJSValueRef_(callback->getContext(), receivedData));
184     }
185     
186     TIME_TRACER_ITEM_END(__FUNCTION__, 1);
187 }
188
189 BluetoothHealthProfileHandler* BluetoothHealthProfileHandler::getInstance()
190 {
191     static BluetoothHealthProfileHandler instance;
192     return &instance;
193 }
194
195 BluetoothHealthProfileHandler::BluetoothHealthProfileHandler()
196 {
197     if(bt_hdp_set_connection_state_changed_cb(onConnected, onDisconnected, this) != BT_ERROR_NONE) {
198         LoggerE("bt_hdp_set_connection_state_changed_cb() failed");
199     }
200
201     if(bt_hdp_set_data_received_cb(onDataReceivedCB, this) != BT_ERROR_NONE) {
202         LoggerE("bt_hdp_set_data_received_cb() failed");
203     }    
204 }
205
206 BluetoothHealthProfileHandler::~BluetoothHealthProfileHandler()
207 {
208     // unset platform callback
209     bt_hdp_unset_connection_state_changed_cb();
210     bt_hdp_unset_data_received_cb();
211
212     mHealthConnReqMap.clear();
213     mConnectedSocketMap.clear();
214     mRegisteredHealthAppMap.clear();    
215 }
216
217 void BluetoothHealthProfileHandler::registerSinkApp(unsigned short dataType, std::string name, Common::MultiCallbackUserDataPtr callback)
218 {
219     TIME_TRACER_ITEM_BEGIN(__FUNCTION__, 1);
220     BluetoothHealthProfileHandlerCallback::syncToAsyncRegisterCB(callback, dataType, name);
221     TIME_TRACER_ITEM_END(__FUNCTION__, 1);    
222 }
223
224 void BluetoothHealthProfileHandler::returnRegisteringSinkAppResult(unsigned short dataType, std::string name, Common::MultiCallbackUserDataPtr callback)
225 {
226     LoggerD("Enter");
227     TIME_TRACER_ITEM_BEGIN(__FUNCTION__, 1);
228
229     char *app_id = NULL;
230     int ret = bt_hdp_register_sink_app(dataType, &app_id);
231     switch(ret) {
232         case BT_ERROR_NONE:
233         {
234             LoggerD("Registered app: " << app_id);
235             std::string appID(app_id);
236             //free(app_id);
237             BluetoothHealthApplicationSharedPtr application(new BluetoothHealthApplication(appID, name, dataType));
238             mRegisteredHealthAppMap.insert(std::pair<std::string, BluetoothHealthApplicationSharedPtr>(appID, application));
239             if(callback)
240                 callback->invokeCallback("success", JSBluetoothHealthApplication::createJSObject(callback->getContext(), application));
241             break;
242         }
243         case BT_ERROR_NOT_ENABLED:
244         {
245             if(callback) {
246                 callback->invokeCallback("error", 
247                         JSWebAPIErrorFactory::makeErrorObject(callback->getContext(), ServiceNotAvailableException("Bluetooth device is turned off")));            
248             }
249             break;
250         }
251         default:
252         {
253             if(callback) {
254                 callback->invokeCallback("error", 
255                         JSWebAPIErrorFactory::makeErrorObject(callback->getContext(), UnknownException("Unknown error")));            
256             }
257         }
258     }
259     
260     TIME_TRACER_ITEM_END(__FUNCTION__, 1); 
261 }
262
263 /*
264 void BluetoothHealthProfileHandler::unregisterSinkApplication(JSObjectRef appObj, Common::MultiCallbackUserDataPtr callback)
265 {
266     TIME_TRACER_ITEM_BEGIN(__FUNCTION__, 1);
267     BluetoothHealthProfileHandlerCallback::syncToAsyncUnregisterCB(callback, appObj);
268     TIME_TRACER_ITEM_END(__FUNCTION__, 1);    
269 }
270
271 void BluetoothHealthProfileHandler::returnUnregisteringResult(JSObjectRef appObj, Common::MultiCallbackUserDataPtr callback)
272 {
273     TIME_TRACER_ITEM_BEGIN(__FUNCTION__, 1);
274     
275     BluetoothHealthApplicationSharedPtr app = JSBluetoothHealthApplication::toBluetoothHealthApplication(appObj);
276     int ret = bt_hdp_unregister_sink_app(app->getAppID().c_str());
277     switch(ret) {
278         case BT_ERROR_NONE:
279         {
280             //app->setRegistrationState(false);
281             BluetoothHealthProfileHandlerCallback::syncToAsyncSuccessCB(callback);
282             break;
283         }
284         case BT_ERROR_NOT_ENABLED:
285         {
286             ServiceNotAvailableException *error =  new ServiceNotAvailableException("Bluetooth device is turned off");
287             BluetoothHealthProfileHandlerCallback::syncToAsyncErrorCB(callback, error);
288             break;
289         }
290         default:
291         {
292             UnknownException *error = new UnknownException("Unknown error");
293             BluetoothHealthProfileHandlerCallback::syncToAsyncErrorCB(callback, error);
294         }        
295     }
296     
297     TIME_TRACER_ITEM_END(__FUNCTION__, 1); 
298 }
299 */
300
301 void BluetoothHealthProfileHandler::unregisterApp(std::string appID, Common::MultiCallbackUserDataPtr callback)
302 {
303     TIME_TRACER_ITEM_BEGIN(__FUNCTION__, 1);
304     BluetoothHealthProfileHandlerCallback::syncToAsyncUnregisterCB(callback, appID);
305     TIME_TRACER_ITEM_END(__FUNCTION__, 1);    
306 }
307
308 void BluetoothHealthProfileHandler::returnUnregisteringAppResult(std::string appID, Common::MultiCallbackUserDataPtr callback)
309 {
310     TIME_TRACER_ITEM_BEGIN(__FUNCTION__, 1);  
311
312     RegisteredHealthAppMapT::iterator iter = mRegisteredHealthAppMap.find(appID);
313     BluetoothHealthApplicationSharedPtr application;
314     if(iter != mRegisteredHealthAppMap.end()) {
315         LoggerE("registered Health Application is found");
316         application = iter->second;    
317     }
318     else {
319         LoggerD("Already unregistered");
320         if(callback)
321             callback->invokeCallback("success");
322         return;
323     }    
324
325     int ret = bt_hdp_unregister_sink_app(appID.c_str());
326     switch(ret) {
327         case BT_ERROR_NONE:
328         {
329             mRegisteredHealthAppMap.erase(iter);
330             application->setRegistrationState(false);
331             if(callback)
332                 callback->invokeCallback("success");           
333             break;
334         }
335         case BT_ERROR_NOT_ENABLED:
336         {
337             if(callback) {
338                 callback->invokeCallback("error", 
339                         JSWebAPIErrorFactory::makeErrorObject(callback->getContext(), ServiceNotAvailableException("Bluetooth device is turned off")));            
340             }
341             break;
342         }
343         default:
344         {
345             if(callback) {
346                 callback->invokeCallback("error", 
347                         JSWebAPIErrorFactory::makeErrorObject(callback->getContext(), UnknownException("Unknown error")));            
348             }
349         }        
350     }
351     
352     TIME_TRACER_ITEM_END(__FUNCTION__, 1); 
353 }
354
355 void BluetoothHealthProfileHandler::connectToSource(JSObjectRef remoteDeviceObj, JSObjectRef appObj, Common::MultiCallbackUserDataPtr callback)
356 {
357     LoggerD("Enter");
358     
359     TIME_TRACER_ITEM_BEGIN(__FUNCTION__, 1);
360
361     BluetoothDeviceSharedPtr device = JSBluetoothDevice::toBluetoothDevice(remoteDeviceObj);
362     BluetoothHealthApplicationSharedPtr app = JSBluetoothHealthApplication::toBluetoothHealthApplication(appObj);
363     LoggerD("address: " << device->getAddress().c_str());
364     LoggerD("app ID: " << app->getAppID().c_str());    
365     int ret = bt_hdp_connect_to_source(device->getAddress().c_str(), app->getAppID().c_str());
366     switch(ret) {
367         case BT_ERROR_NONE:
368         {
369             LoggerD("NONE");
370             HealthConnReqPtr connReq = new HealthConnReq(device, callback);
371             mHealthConnReqMap.insert(std::pair<BluetoothHealthApplicationSharedPtr, HealthConnReqPtr>(app, connReq));            
372             break;
373         }
374         case BT_ERROR_NOT_ENABLED:
375         {
376             LoggerD("Not Enabled");
377             ServiceNotAvailableException *error =  new ServiceNotAvailableException("Bluetooth device is turned off");
378             BluetoothHealthProfileHandlerCallback::syncToAsyncErrorCB(callback, error);
379             break;
380         }
381         case BT_ERROR_INVALID_PARAMETER:
382         case BT_ERROR_REMOTE_DEVICE_NOT_BONDED:
383         {
384             LoggerD("invalid value");
385             InvalidValuesException *error = new InvalidValuesException("Invalid value");
386             BluetoothHealthProfileHandlerCallback::syncToAsyncErrorCB(callback, error);
387             break;
388         }
389         default:
390         {
391             LoggerD("Unknown error");
392             UnknownException *error = new UnknownException("Unknown error");
393             BluetoothHealthProfileHandlerCallback::syncToAsyncErrorCB(callback, error);
394         }        
395     }
396
397     TIME_TRACER_ITEM_END(__FUNCTION__, 1); 
398 }
399
400
401 } // Bluetooth
402 } // DeviceAPI