/* * bt-connection-popup * * Copyright 2012 Samsung Electronics Co., Ltd * * Contact: Hocheol Seo * Injun Yang * Seungyoun Ju * * Licensed under the Flora License, Version 1.1 (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.tizenopensource.org/license * * 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 #include #include #include "bt-connection-main.h" #include "bt-connection-view.h" #include "bt-connection-handler.h" #define VCONFKEY_SAP_STATUS "memory/private/sap/conn_status" #define BT_ADDRESS_LENGTH 18 static bool is_le_disconnecting; static int __bt_app_destory_cb(void *data) { bt_app_data_t *ad = NULL; DBG(""); ad = (bt_app_data_t *)data; if (ad == NULL) { ERR("Invalid param"); return 0; } if (ad->timer) { ecore_timer_del(ad->timer); ad->timer = NULL; } _bt_destroy_app(ad); return 0; } static void __bt_wms_status_handler(keynode_t *key, void *data) { int status; int type; bt_app_data_t *ad; ad = (bt_app_data_t *)data; if (ad == NULL) { ERR("Invalid param"); return; } type = vconf_keynode_get_type(key); if (type == VCONF_TYPE_BOOL) status = vconf_keynode_get_bool(key); else { ERR("Invalid vconf type : %d", type); return; } DBG("WMS is %s", status == WMS_CONNECTED ? "connected" : "disconnected" ); if (status == WMS_CONNECTED) { /* To show connected view, create new popup */ /* or update edc part */ /* See _bt_update_connect_status_popup() */ if (ad->timer) { ecore_timer_del(ad->timer); ad->timer = NULL; } _bt_create_connected_popup(ad); _bt_send_result(ad, KEY_VAL_CONNECTED); ad->timer = ecore_timer_add(APP_DESTORY_TIMEOUT, (Ecore_Task_Cb) __bt_app_destory_cb, ad); } return; } static void __bt_hf_connection_state_changed(int result, bool connected, const char *remote_address, bt_audio_profile_type_e type, void *user_data) { if (connected == true) { DBG("Bluetooth HF is connected"); } else { DBG("Bluetooth HF is disconnected"); } } static bool __bt_adapter_bonded_device_cb(bt_device_info_s *device_info, void *user_data) { int ret; bool is_connected = false; char* remote_address = (char*)user_data; if (!(device_info->bt_class.major_device_class & BT_MAJOR_DEVICE_CLASS_COMPUTER) && !(device_info->bt_class.major_device_class & BT_MAJOR_DEVICE_CLASS_PHONE)) return true; memcpy(remote_address, device_info->remote_address, BT_ADDRESS_LENGTH); ret = bt_device_is_profile_connected(device_info->remote_address, BT_PROFILE_AG, &is_connected); if (ret == BT_ERROR_NONE && is_connected) { remote_address[0] = '\0'; return false; } return true; } static gboolean __bt_hf_is_connected(const char* remote_address) { int ret; gboolean is_connected = FALSE; ret = bt_adapter_foreach_bonded_device(__bt_adapter_bonded_device_cb, (void*)remote_address); if (ret != BT_ERROR_NONE) { ERR("bt_adapter_foreach_bonded_device is failed 0x%X", ret); return FALSE; } if (remote_address[0] == '\0') is_connected = TRUE; DBG("Aleady HF is %s", is_connected ? "connected" : "disconnected"); return is_connected; } static void __bt_adapter_state_changed(int result, bt_adapter_state_e adapter_state, void *user_data) { int ret; char remote_address[BT_ADDRESS_LENGTH] = { 0, }; if (user_data == NULL) { ERR("Invalid param"); return; } if (result != BT_ERROR_NONE) { ERR("BT Adapter operation is failed : %d", result); return; } DBG("BT Adapter is %s", adapter_state == BT_ADAPTER_ENABLED ? "enabled" : "disabled"); if (adapter_state == BT_ADAPTER_ENABLED) { if (__bt_hf_is_connected(&remote_address[0]) == FALSE) { DBG("Make a HF connection"); ret = bt_audio_connect(&remote_address[0], BT_AUDIO_PROFILE_TYPE_AG); if (ret != BT_ERROR_NONE) { ERR("HF Connection is failed"); return; } } } return; } int _bt_get_wms_status(void) { int ret; int status = WMS_DISCONNECTED; ret = vconf_get_bool(VCONFKEY_WMS_WMANAGER_CONNECTED, &status); if (ret != 0) { ERR("Vconf get failed"); return WMS_DISCONNECTED; } DBG("WMS status : %d", status); return status; } void _bt_get_sap_status(void) { int ret; int status = 0; ret = vconf_get_int(VCONFKEY_SAP_STATUS, &status); if (ret != 0) { ERR("Vconf get failed"); } DBG("SAP status : %d", status); return; } gboolean _bt_send_result(bt_app_data_t *ad, const char *val) { if (ad == NULL) return FALSE; bundle *kb; bundle *res_b; int ret; static gboolean is_sent = FALSE; DBG(""); if (ad->service_clone == NULL) { ERR("Invalid param"); return FALSE; } if (is_sent == TRUE) { ERR("Aleady send response !!!"); return FALSE; } ret = service_to_bundle(ad->service_clone, &kb); if (ret != SERVICE_ERROR_NONE) { ERR("service is failed : %d", ret); return FALSE; } aul_create_result_bundle(kb, &res_b); if (res_b == NULL) return FALSE; bundle_add(res_b, "__BT_CONNECTION__", val); aul_send_service_result(res_b); bundle_free(res_b); bundle_free(kb); is_sent = TRUE; DBG("Send result : %s", val); return TRUE; } bool __device_check_gatt_cb(bt_profile_e profile, void *user_data) { bool *is_connected = (bool *)user_data; if (profile == BT_PROFILE_GATT) { *is_connected = true; return false; } return true; } bool __bt_le_is_connected(const char *remote_address) { int ret; bool is_connected = false; if (remote_address == NULL) { return false; } ret = bt_device_foreach_connected_profiles(remote_address, __device_check_gatt_cb, &is_connected); if (ret != BT_ERROR_NONE) { ERR("bt_device_foreach_connected_profiles fail (0x%08x)", ret); return false; } return is_connected; } void __bt_gatt_disconnected_cb(int result, void *user_data) { DBG("called"); if (result != BT_ERROR_NONE) { ERR("GATT disconnect fail (0x%08x)", result); is_le_disconnecting = false; } return; #if 0 char remote_address[BT_ADDRESS_LENGTH] = { 0, }; bool is_advertising = false; int ret; if (result != BT_ERROR_NONE) { ERR("GATT disconnect fail (0x%08x)", result); return; } if (__bt_hf_is_connected(&remote_address[0]) == TRUE) { DBG("Handsfree is already connected"); return; } ret = bt_adapter_is_advertising(&is_advertising); if (ret == BT_ERROR_NONE && is_advertising) { ret = bt_adapter_stop_advertising(); if (ret != BT_ERROR_NONE) { ERR("bt_adapter_stop_advertising failed (0x%08x)", ret); } } DBG("Make a HF connection"); ret = bt_audio_connect(&remote_address[0], BT_AUDIO_PROFILE_TYPE_AG); if (ret != BT_ERROR_NONE) { ERR("HF Connection is failed"); return; } return; #endif } static void __bt_device_connection_state_changed_cb(bool connected, const char *remote_address, void *user_data) { bool is_advertising = false; int ret; char remote_add[BT_ADDRESS_LENGTH] = { 0, }; DBG("address: %s, connected: %d", remote_address, connected); if (is_le_disconnecting == false || connected == true) { DBG("is_le_disconnecting IS FALSE"); return; } is_le_disconnecting = false; if (__bt_hf_is_connected(&remote_add[0]) == true) { DBG("Handsfree is already connected"); return; } if (strncmp(remote_address, remote_add, BT_ADDRESS_LENGTH-1) != 0) { DBG("remote address is different"); return; } ret = bt_adapter_is_advertising(&is_advertising); if (ret == BT_ERROR_NONE && is_advertising) { ret = bt_adapter_stop_advertising(); if (ret != BT_ERROR_NONE) { ERR("bt_adapter_stop_advertising failed (0x%08x)", ret); } } DBG("Make a HF connection"); ret = bt_audio_connect(&remote_add[0], BT_AUDIO_PROFILE_TYPE_AG); if (ret != BT_ERROR_NONE) { ERR("HF Connection is failed"); return; } return; } gboolean _bt_init(void *data) { int ret; bt_adapter_state_e adapter_state = BT_ADAPTER_DISABLED; char remote_address[BT_ADDRESS_LENGTH] = { 0, }; bool is_advertising = false; bt_app_data_t *ad; ad = (bt_app_data_t *)data; is_le_disconnecting = false; if (ad == NULL) { return FALSE; } if (ad->initialize == TRUE) { DBG("bt_initialize already done"); return TRUE; } ret = bt_initialize(); if (ret != BT_ERROR_NONE) { ERR("bt_initialize is failed : %d", ret); return FALSE; } ret = bt_adapter_set_state_changed_cb(__bt_adapter_state_changed, data); if (ret != BT_ERROR_NONE) { ERR("bt_adapter_set_state_changed_cb is failed : %d", ret); bt_deinitialize(); return FALSE; } ret = bt_device_set_connection_state_changed_cb(__bt_device_connection_state_changed_cb, NULL); if (ret != BT_ERROR_NONE) { ERR("bt_device_set_connection_state_changed_cb is failed : %d", ret); return FALSE; } ret = bt_adapter_get_state(&adapter_state); if (ret != BT_ERROR_NONE) { ERR("bt_adapter_get_state is failed : %d", ret); return FALSE; } ret = bt_audio_initialize(); if (ret != BT_ERROR_NONE) { ERR("bt_audio_initialize is failed : %d", ret); return FALSE; } ret = bt_audio_set_connection_state_changed_cb(__bt_hf_connection_state_changed, NULL); if (ret != BT_ERROR_NONE) { ERR("bt_audio_set_connection_state_changed_cb is failed : %d", ret); bt_hf_deinitialize(); return FALSE; } if (adapter_state == BT_ADAPTER_ENABLED) { DBG("Aleady BT enabled"); #ifdef FEATURE_TIZENW if (__bt_hf_is_connected(&remote_address[0]) == FALSE) { DBG("Make a HF connection"); ret = bt_audio_connect(&remote_address[0], BT_AUDIO_PROFILE_TYPE_AG); if (ret != BT_ERROR_NONE) { ERR("HF Connection is failed"); return FALSE; } } #else if (__bt_hf_is_connected(&remote_address[0]) == FALSE) { if (__bt_le_is_connected(&remote_address[0])) { ret = bt_adapter_is_advertising(&is_advertising); if (ret == BT_ERROR_NONE && is_advertising) { ret = bt_adapter_stop_advertising(); if (ret != BT_ERROR_NONE) { ERR("bt_adapter_stop_advertising failed (0x%08x)", ret); } } ret = bt_device_disconnect_le(__bt_gatt_disconnected_cb, &remote_address[0]); if (ret == BT_ERROR_NONE) is_le_disconnecting = true; return TRUE; } DBG("Make a HF connection"); ret = bt_audio_connect(&remote_address[0], BT_AUDIO_PROFILE_TYPE_AG); if (ret != BT_ERROR_NONE) { ERR("HF Connection is failed"); return FALSE; } } #endif /* FEATURE_TIZENW */ return TRUE; } else { DBG("Enable BT adapter"); ret = bt_adapter_enable(); if (ret != BT_ERROR_NONE) { ERR("bt_adapter_enable is failed : %d", ret); return FALSE; } } return TRUE; } void _bt_deinit(void *data) { int ret; char remote_address[BT_ADDRESS_LENGTH] = { 0, }; bool is_advertising = FALSE; bt_app_data_t *ad; ad = (bt_app_data_t *)data; if (ad == NULL) return; if (ad->initialize == FALSE) { DBG("bt_deinitialize already done"); return; } if (__bt_hf_is_connected(&remote_address[0]) == FALSE) { ret = bt_adapter_is_advertising(&is_advertising); if (ret == BT_ERROR_NONE && !is_advertising) { ret = bt_adapter_start_advertising(NULL); if (ret != BT_ERROR_NONE) { ERR("bt_adapter_stop_advertising failed (0x%08x)", ret); } } } ret = bt_audio_unset_connection_state_changed_cb(); if (ret != BT_ERROR_NONE) ERR("bt_audio_unset_connection_state_changed_cb is failed : %d", ret); ret = bt_audio_deinitialize(); if (ret != BT_ERROR_NONE) ERR("bt_audio_deinitialize is failed : %d", ret); ret = bt_hf_deinitialize(); if (ret != BT_ERROR_NONE) ERR("bt_hf_deinitialize is failed : %d", ret); ret = bt_device_unset_connection_state_changed_cb(); if (ret != BT_ERROR_NONE) ERR("bt_device_unset_connection_state_changed_cb is failed : %d", ret); ret = bt_adapter_unset_state_changed_cb(); if (ret != BT_ERROR_NONE) ERR("bt_adapter_unset_state_changed_cb is failed : %d", ret); ret = bt_deinitialize(); if (ret != BT_ERROR_NONE) ERR("bt_deinitialize is failed : %d", ret); return; } gboolean _bt_register_vconf_handler(void *data) { int ret; ret = vconf_notify_key_changed(VCONFKEY_WMS_WMANAGER_CONNECTED, (vconf_callback_fn) __bt_wms_status_handler, data); if (ret < 0) { ERR("Unable to register key handler"); return FALSE; } return TRUE; } void _bt_unregister_vconf_handler(void) { vconf_ignore_key_changed(VCONFKEY_WMS_WMANAGER_CONNECTED, (vconf_callback_fn) __bt_wms_status_handler); return; }