diff options
Diffstat (limited to 'mobile_src/Bluetooth/BluetoothHealthProfileHandler.cpp')
-rw-r--r-- | mobile_src/Bluetooth/BluetoothHealthProfileHandler.cpp | 411 |
1 files changed, 411 insertions, 0 deletions
diff --git a/mobile_src/Bluetooth/BluetoothHealthProfileHandler.cpp b/mobile_src/Bluetooth/BluetoothHealthProfileHandler.cpp new file mode 100644 index 0000000..8299baa --- /dev/null +++ b/mobile_src/Bluetooth/BluetoothHealthProfileHandler.cpp @@ -0,0 +1,411 @@ +// +// Tizen Web Device API +// Copyright (c) 2012 Samsung Electronics Co., Ltd. +// +// Licensed under the Apache License, Version 2.0 (the License); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + + +#include <Logger.h> +#include <JSWebAPIErrorFactory.h> +#include <JSUtil.h> +#include <TimeTracer.h> + +#include "BluetoothHealthProfileHandler.h" +#include "BluetoothHealthProfileHandlerCallback.h" +#include "JSBluetoothHealthApplication.h" +#include "JSBluetoothDevice.h" +#include "JSBluetoothHealthChannel.h" +#include "BluetoothHealthChannel.h" + +using namespace DeviceAPI::Common; + +namespace DeviceAPI { +namespace Bluetooth { + +void BluetoothHealthProfileHandler::onConnected(int result, const char *remote_address, const char *app_id, + bt_hdp_channel_type_e type, unsigned int channel, void *userData) +{ + LoggerD("Enter"); + TIME_TRACER_ITEM_BEGIN(__FUNCTION__, 1); + + HealthProfileHandlerPtr object = static_cast<HealthProfileHandlerPtr>(userData); + if(!object) { + LoggerW("userData is NULL"); + return; + } + + if(result != BT_ERROR_NONE) { + LoggerD("Not BT_ERROR_NONE"); + } + + LoggerD("Connected app: " << app_id); + LoggerD("Connected channel: " << channel); + + std::string appID(app_id); + RegisteredHealthAppMapT::iterator iter = object->mRegisteredHealthAppMap.find(appID); + if(iter == object->mRegisteredHealthAppMap.end()) { + LoggerW("This app is not registered"); + return; + } + BluetoothHealthApplicationSharedPtr application = iter->second; + + bool isChannelInserted = false; + BluetoothHealthChannelPtr healthChannel = NULL; + + // call BluetoothHealthApplication.onconnect + if(result == BT_ERROR_NONE) { + Common::MultiCallbackUserDataPtr callback = application->getOnConnect(); + if(callback) { + bt_device_info_s *deviceInfo = NULL; + if(bt_adapter_get_bonded_device_info(remote_address, &deviceInfo) == BT_ERROR_NONE && + deviceInfo != NULL) { + BluetoothDeviceSharedPtr device(new BluetoothDevice(deviceInfo)); + // need to check + device->copyAceCheckAccessFunction(getInstance()); + bt_adapter_free_device_info(deviceInfo); + + LoggerD("invoke BluetoothHealthApplication.onconnect"); + healthChannel = new BluetoothHealthChannel(channel, device, type, application); + healthChannel->copyAceCheckAccessFunction(getInstance()); + object->mConnectedSocketMap.insert(std::pair<unsigned int, BluetoothHealthChannelPtr>(channel, healthChannel)); + isChannelInserted = true; + callback->invokeCallback("onconnect", JSBluetoothHealthChannel::createJSObject(callback->getContext(), healthChannel)); + } + else { + LoggerE("Can't call BluetoothHealthApplication.onconnect because failed to get device info"); + } + } + else { + LoggerD("BluetoothHealthApplication.onconnect is not set"); + } + } + + // in case of connectToSource() + HealthConnReqMapT::iterator i = object->mHealthConnReqMap.find(application); + if(i != object->mHealthConnReqMap.end()) { + LoggerD("Requested connection"); + Common::MultiCallbackUserDataPtr callback = i->second->mUserData; + if(callback) { + if(result == BT_ERROR_NONE) { + if(isChannelInserted == false) { + healthChannel = new BluetoothHealthChannel(channel, i->second->mRemoteDevice, type, application); + healthChannel->copyAceCheckAccessFunction(getInstance()); + object->mConnectedSocketMap.insert(std::pair<unsigned int, BluetoothHealthChannelPtr>(channel, healthChannel)); + } + callback->invokeCallback("success", JSBluetoothHealthChannel::createJSObject(callback->getContext(), healthChannel)); + } + else { + LoggerE("Failed to establish a connection with health profile"); + callback->invokeCallback("error", + JSWebAPIErrorFactory::makeErrorObject(callback->getContext(), UnknownException("Failed to establish a connection with health profile"))); + } + } + + // Update mHealthConnReqMap + object->mHealthConnReqMap.erase(i); + } + else { + LoggerD("There is no connection request"); + } + + TIME_TRACER_ITEM_END(__FUNCTION__, 1); +} + +void BluetoothHealthProfileHandler::onDisconnected(int result, const char *remote_address, unsigned int channel, void *userData) +{ + LoggerD("Enter"); + TIME_TRACER_ITEM_BEGIN(__FUNCTION__, 1); + + HealthProfileHandlerPtr object = static_cast<HealthProfileHandlerPtr>(userData); + if(!object) { + LoggerW("userData is NULL"); + return; + } + + LoggerD("Disconnected channel: " << channel); + HealthConnectedSocketMapT::iterator iter = object->mConnectedSocketMap.find(channel); + if(iter == object->mConnectedSocketMap.end()) { + LoggerW("Unexpected health disconnection event"); + return; + } + + if(result == BT_ERROR_NONE) { + BluetoothHealthChannelPtr healthChannel = iter->second; + object->mConnectedSocketMap.erase(iter); + + healthChannel->setConnectionState(false); + MultiCallbackUserDataPtr callback = healthChannel->getListener(); + if(callback) + callback->invokeCallback("onclose"); + } + else { + LoggerW("Failed to disconnect a connection"); + } + + TIME_TRACER_ITEM_END(__FUNCTION__, 1); + LoggerD("End"); +} + +void BluetoothHealthProfileHandler::onDataReceivedCB(unsigned int channel, const char *data, unsigned int size, void *userData) +{ + LoggerD("Enter"); + + TIME_TRACER_ITEM_BEGIN(__FUNCTION__, 1); + + HealthProfileHandlerPtr object = static_cast<HealthProfileHandlerPtr>(userData); + if(!object) { + LoggerW("userData is NULL"); + return; + } + + LoggerD("data channel: " << channel); + LoggerD("sent data size: " << size); + HealthConnectedSocketMapT::iterator iter = object->mConnectedSocketMap.find(channel); + if(iter == object->mConnectedSocketMap.end()) { + LoggerW("Unexpected health data received event"); + return; + } + + BluetoothHealthChannelPtr healthChannel = iter->second; + MultiCallbackUserDataPtr callback = healthChannel->getListener(); + if(callback) { + std::vector<signed char> receivedData; + for(unsigned int i = 0; i < size; i++) { + receivedData.push_back(static_cast<signed char>(data[i])); + } + callback->invokeCallback("onmessage", JSUtil::toJSValueRef_(callback->getContext(), receivedData)); + } + + TIME_TRACER_ITEM_END(__FUNCTION__, 1); +} + +BluetoothHealthProfileHandler* BluetoothHealthProfileHandler::getInstance() +{ + static BluetoothHealthProfileHandler instance; + return &instance; +} + +BluetoothHealthProfileHandler::BluetoothHealthProfileHandler() +{ + Common::SecurityAccessor(); + + if(bt_hdp_set_connection_state_changed_cb(onConnected, onDisconnected, this) != BT_ERROR_NONE) { + LoggerE("bt_hdp_set_connection_state_changed_cb() failed"); + } + + if(bt_hdp_set_data_received_cb(onDataReceivedCB, this) != BT_ERROR_NONE) { + LoggerE("bt_hdp_set_data_received_cb() failed"); + } +} + + +BluetoothHealthProfileHandler::~BluetoothHealthProfileHandler() +{ + // unset platform callback + bt_hdp_unset_connection_state_changed_cb(); + bt_hdp_unset_data_received_cb(); + + mHealthConnReqMap.clear(); + mConnectedSocketMap.clear(); + mRegisteredHealthAppMap.clear(); +} + +void BluetoothHealthProfileHandler::registerSinkApp(unsigned short dataType, std::string name, Common::MultiCallbackUserDataPtr callback) +{ + TIME_TRACER_ITEM_BEGIN(__FUNCTION__, 1); + BluetoothHealthProfileHandlerCallback::syncToAsyncRegisterCB(callback, dataType, name); + TIME_TRACER_ITEM_END(__FUNCTION__, 1); +} + +void BluetoothHealthProfileHandler::returnRegisteringSinkAppResult(unsigned short dataType, std::string name, Common::MultiCallbackUserDataPtr callback) +{ + LoggerD("Enter"); + TIME_TRACER_ITEM_BEGIN(__FUNCTION__, 1); + + char *app_id = NULL; + int ret = bt_hdp_register_sink_app(dataType, &app_id); + switch(ret) { + case BT_ERROR_NONE: + { + LoggerD("Registered app: " << app_id); + std::string appID(app_id); + //free(app_id); + BluetoothHealthApplicationSharedPtr application(new BluetoothHealthApplication(appID, name, dataType)); + application->copyAceCheckAccessFunction(getInstance()); + + mRegisteredHealthAppMap.insert(std::pair<std::string, BluetoothHealthApplicationSharedPtr>(appID, application)); + if(callback) + callback->invokeCallback("success", JSBluetoothHealthApplication::createJSObject(callback->getContext(), application)); + break; + } + case BT_ERROR_NOT_ENABLED: + { + if(callback) { + callback->invokeCallback("error", + JSWebAPIErrorFactory::makeErrorObject(callback->getContext(), ServiceNotAvailableException("Bluetooth device is turned off"))); + } + break; + } + default: + { + if(callback) { + callback->invokeCallback("error", + JSWebAPIErrorFactory::makeErrorObject(callback->getContext(), UnknownException("Unknown error"))); + } + } + } + + TIME_TRACER_ITEM_END(__FUNCTION__, 1); +} + +/* +void BluetoothHealthProfileHandler::unregisterSinkApplication(JSObjectRef appObj, Common::MultiCallbackUserDataPtr callback) +{ + TIME_TRACER_ITEM_BEGIN(__FUNCTION__, 1); + BluetoothHealthProfileHandlerCallback::syncToAsyncUnregisterCB(callback, appObj); + TIME_TRACER_ITEM_END(__FUNCTION__, 1); +} + +void BluetoothHealthProfileHandler::returnUnregisteringResult(JSObjectRef appObj, Common::MultiCallbackUserDataPtr callback) +{ + TIME_TRACER_ITEM_BEGIN(__FUNCTION__, 1); + + BluetoothHealthApplicationSharedPtr app = JSBluetoothHealthApplication::toBluetoothHealthApplication(appObj); + int ret = bt_hdp_unregister_sink_app(app->getAppID().c_str()); + switch(ret) { + case BT_ERROR_NONE: + { + //app->setRegistrationState(false); + BluetoothHealthProfileHandlerCallback::syncToAsyncSuccessCB(callback); + break; + } + case BT_ERROR_NOT_ENABLED: + { + ServiceNotAvailableException *error = new ServiceNotAvailableException("Bluetooth device is turned off"); + BluetoothHealthProfileHandlerCallback::syncToAsyncErrorCB(callback, error); + break; + } + default: + { + UnknownException *error = new UnknownException("Unknown error"); + BluetoothHealthProfileHandlerCallback::syncToAsyncErrorCB(callback, error); + } + } + + TIME_TRACER_ITEM_END(__FUNCTION__, 1); +} +*/ + +void BluetoothHealthProfileHandler::unregisterApp(std::string appID, Common::MultiCallbackUserDataPtr callback) +{ + TIME_TRACER_ITEM_BEGIN(__FUNCTION__, 1); + BluetoothHealthProfileHandlerCallback::syncToAsyncUnregisterCB(callback, appID); + TIME_TRACER_ITEM_END(__FUNCTION__, 1); +} + +void BluetoothHealthProfileHandler::returnUnregisteringAppResult(std::string appID, Common::MultiCallbackUserDataPtr callback) +{ + TIME_TRACER_ITEM_BEGIN(__FUNCTION__, 1); + + RegisteredHealthAppMapT::iterator iter = mRegisteredHealthAppMap.find(appID); + BluetoothHealthApplicationSharedPtr application; + if(iter != mRegisteredHealthAppMap.end()) { + LoggerE("registered Health Application is found"); + application = iter->second; + } + else { + LoggerD("Already unregistered"); + if(callback) + callback->invokeCallback("success"); + return; + } + + int ret = bt_hdp_unregister_sink_app(appID.c_str()); + switch(ret) { + case BT_ERROR_NONE: + { + mRegisteredHealthAppMap.erase(iter); + application->setRegistrationState(false); + if(callback) + callback->invokeCallback("success"); + break; + } + case BT_ERROR_NOT_ENABLED: + { + if(callback) { + callback->invokeCallback("error", + JSWebAPIErrorFactory::makeErrorObject(callback->getContext(), ServiceNotAvailableException("Bluetooth device is turned off"))); + } + break; + } + default: + { + if(callback) { + callback->invokeCallback("error", + JSWebAPIErrorFactory::makeErrorObject(callback->getContext(), UnknownException("Unknown error"))); + } + } + } + + TIME_TRACER_ITEM_END(__FUNCTION__, 1); +} + +void BluetoothHealthProfileHandler::connectToSource(JSObjectRef remoteDeviceObj, JSObjectRef appObj, Common::MultiCallbackUserDataPtr callback) +{ + LoggerD("Enter"); + + TIME_TRACER_ITEM_BEGIN(__FUNCTION__, 1); + + BluetoothDeviceSharedPtr device = JSBluetoothDevice::toBluetoothDevice(remoteDeviceObj); + BluetoothHealthApplicationSharedPtr app = JSBluetoothHealthApplication::toBluetoothHealthApplication(appObj); + LoggerD("address: " << device->getAddress().c_str()); + LoggerD("app ID: " << app->getAppID().c_str()); + int ret = bt_hdp_connect_to_source(device->getAddress().c_str(), app->getAppID().c_str()); + switch(ret) { + case BT_ERROR_NONE: + { + LoggerD("NONE"); + HealthConnReqPtr connReq = new HealthConnReq(device, callback); + mHealthConnReqMap.insert(std::pair<BluetoothHealthApplicationSharedPtr, HealthConnReqPtr>(app, connReq)); + break; + } + case BT_ERROR_NOT_ENABLED: + { + LoggerD("Not Enabled"); + ServiceNotAvailableException *error = new ServiceNotAvailableException("Bluetooth device is turned off"); + BluetoothHealthProfileHandlerCallback::syncToAsyncErrorCB(callback, error); + break; + } + case BT_ERROR_INVALID_PARAMETER: + case BT_ERROR_REMOTE_DEVICE_NOT_BONDED: + { + LoggerD("invalid value"); + InvalidValuesException *error = new InvalidValuesException("Invalid value"); + BluetoothHealthProfileHandlerCallback::syncToAsyncErrorCB(callback, error); + break; + } + default: + { + LoggerD("Unknown error"); + UnknownException *error = new UnknownException("Unknown error"); + BluetoothHealthProfileHandlerCallback::syncToAsyncErrorCB(callback, error); + } + } + + TIME_TRACER_ITEM_END(__FUNCTION__, 1); +} + + +} // Bluetooth +} // DeviceAPI |