4 * Copyright 2012 Samsung Electronics Co., Ltd
6 * Contact: Hocheol Seo <hocheol.seo@samsung.com>
7 * GirishAshok Joshi <girish.joshi@samsung.com>
8 * DoHyun Pyun <dh79.pyun@samsung.com>
10 * Licensed under the Flora License, Version 1.1 (the "License");
11 * you may not use this file except in compliance with the License.
12 * You may obtain a copy of the License at
14 * http://www.tizenopensource.org/license
16 * Unless required by applicable law or agreed to in writing,
17 * software distributed under the License is distributed on an "AS IS" BASIS,
18 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19 * See the License for the specific language governing permissions and
20 * limitations under the License.
24 #include <bluetooth.h>
25 #include <bluetooth_internal.h>
28 #include <notification.h>
29 #include <dpm/restriction.h>
31 // #ifndef TIZEN_PROFILE_TV
38 #include <system_info.h>
40 #include "bt-main-ug.h"
43 #include "bt-string-define.h"
44 #include "bt-net-connection.h"
45 #include "bt-widget.h"
47 /**********************************************************************
49 ***********************************************************************/
51 gboolean _bt_util_update_class_of_device_by_service_list(bt_service_class_t service_list,
52 bt_major_class_t *major_class,
53 bt_minor_class_t *minor_class)
57 retvm_if(service_list == BT_SC_NONE, FALSE,
58 "Invalid argument: service_list is NULL");
61 if (service_list & BT_SC_HFP_SERVICE_MASK ||
62 service_list & BT_SC_HSP_SERVICE_MASK ||
63 #ifdef TIZEN_BT_A2DP_SINK_ENABLE
64 service_list & BT_SC_A2DP_SOURCE_SERVICE_MASK ||
66 service_list & BT_SC_A2DP_SERVICE_MASK) /* Handsfree device */
67 *major_class = BT_MAJOR_DEV_CLS_AUDIO;
68 else if (service_list & BT_SC_NAP_SERVICE_MASK ||
69 service_list & BT_SC_PANU_SERVICE_MASK)
70 *major_class = BT_MAJOR_DEV_CLS_PHONE;
73 if (service_list & BT_SC_HFP_SERVICE_MASK ||
74 service_list & BT_SC_HSP_SERVICE_MASK)
75 *minor_class = BTAPP_MIN_DEV_CLS_HEADSET_PROFILE;
76 else if (service_list & BT_SC_A2DP_SERVICE_MASK)
77 *minor_class = BTAPP_MIN_DEV_CLS_HEADPHONES;
78 else if (service_list & BT_SC_NAP_SERVICE_MASK ||
79 service_list & BT_SC_PANU_SERVICE_MASK)
80 *minor_class = BTAPP_MIN_DEV_CLS_SMART_PHONE;
82 BT_DBG("Updated major_class = %x, minor_class = %x", *major_class,
89 void _bt_util_set_value(const char *req, unsigned int *search_type,
90 unsigned int *op_mode)
94 ret_if(search_type == NULL);
95 ret_if(op_mode == NULL);
97 if (!strcasecmp(req, "send") || !strcasecmp(req, "browse")) {
98 *search_type = BT_COD_SC_OBJECT_TRANSFER;
99 *op_mode = BT_LAUNCH_SEND_FILE;
100 } else if (!strcasecmp(req, "print")) {
101 *search_type = BT_DEVICE_MAJOR_MASK_IMAGING;
102 *op_mode = BT_LAUNCH_PRINT_IMAGE;
103 } else if (!strcasecmp(req, "call") || !strcasecmp(req, "sound")) {
104 *search_type = BT_DEVICE_MAJOR_MASK_AUDIO;
105 *op_mode = BT_LAUNCH_CONNECT_HEADSET;
106 } else if (!strcasecmp(req, "connect_source")) {
107 *search_type = BT_DEVICE_MAJOR_MASK_AUDIO;
108 *op_mode = BT_LAUNCH_CONNECT_AUDIO_SOURCE;
109 } else if (!strcasecmp(req, "nfc")) {
110 *search_type = BT_DEVICE_MAJOR_MASK_MISC;
111 *op_mode = BT_LAUNCH_USE_NFC;
112 } else if (!strcasecmp(req, "pick")) {
113 *search_type = BT_DEVICE_MAJOR_MASK_MISC;
114 *op_mode = BT_LAUNCH_PICK;
115 } else if (!strcasecmp(req, "visibility")) {
116 *search_type = BT_DEVICE_MAJOR_MASK_MISC;
117 *op_mode = BT_LAUNCH_VISIBILITY;
118 } else if (!strcasecmp(req, "onoff")) {
119 *search_type = BT_DEVICE_MAJOR_MASK_MISC;
120 *op_mode = BT_LAUNCH_ONOFF;
121 } else if (!strcasecmp(req, "contact")) {
122 *search_type = BT_COD_SC_OBJECT_TRANSFER;
123 *op_mode = BT_LAUNCH_SHARE_CONTACT;
124 } else if (!strcasecmp(req, "help")) {
125 *search_type = BT_DEVICE_MAJOR_MASK_MISC;
126 *op_mode = BT_LAUNCH_HELP;
128 *search_type = BT_DEVICE_MAJOR_MASK_MISC;
129 *op_mode = BT_LAUNCH_NORMAL;
137 gboolean _bt_util_store_get_value(const char *key, bt_store_type_t store_type,
138 unsigned int size, void *value)
141 retv_if(value == NULL, FALSE);
146 gboolean *boolean = FALSE;
149 switch (store_type) {
150 case BT_STORE_BOOLEAN:
151 boolean = (gboolean *)value;
152 ret = vconf_get_bool(key, &int_value);
154 BT_ERR("Get bool is failed");
158 *boolean = (int_value != FALSE);
161 intval = (int *)value;
162 ret = vconf_get_int(key, intval);
164 BT_ERR("Get int is failed");
169 case BT_STORE_STRING:
170 str = vconf_get_str(key);
172 BT_ERR("Get string is failed");
176 strncpy((char *)value, str, size - 1);
181 BT_ERR("Unknown Store Type");
189 void _bt_util_set_phone_name(void)
191 char *phone_name = NULL;
194 phone_name = vconf_get_str(VCONFKEY_SETAPPL_DEVICE_NAME_STR);
198 if (strlen(phone_name) != 0) {
199 if (!g_utf8_validate(phone_name, -1, (const char **)&ptr))
202 bt_adapter_set_name(phone_name);
208 int _bt_util_get_phone_name(char *phone_name, int size)
211 retv_if(phone_name == NULL, BT_UG_FAIL);
213 if (_bt_util_store_get_value(VCONFKEY_SETAPPL_DEVICE_NAME_STR,
214 BT_STORE_STRING, size,
215 (void *)phone_name) < 0) {
216 g_strlcpy(phone_name, BT_DEFAULT_PHONE_NAME, size);
220 return BT_UG_ERROR_NONE;
223 char * _bt_util_get_timeout_string(int timeout)
229 string = g_strdup(BT_STR_OFF);
232 string = g_strdup(BT_STR_TWO_MINUTES);
234 case BT_FIVE_MINUTES:
235 string = g_strdup(BT_STR_FIVE_MINUTES);
238 string = g_strdup(BT_STR_ONE_HOUR);
241 string = g_strdup(BT_STR_ALWAYS_ON);
244 string = g_strdup(BT_STR_OFF);
252 int _bt_util_get_timeout_value(int index)
263 timeout = BT_TWO_MINUTES;
266 timeout = BT_FIVE_MINUTES;
269 timeout = BT_ONE_HOUR;
272 timeout = BT_ALWAYS_ON;
283 int _bt_util_get_timeout_index(int timeout)
296 case BT_FIVE_MINUTES:
310 BT_DBG("index: %d", index);
316 gboolean _bt_util_is_battery_low(void)
326 if (vconf_get_int(VCONFKEY_SYSMAN_BATTERY_CHARGE_NOW, (void *)&charging))
327 BT_ERR("Get the battery charging status fail");
332 BT_DBG("charging: %d", charging);
334 if (vconf_get_int(VCONFKEY_SYSMAN_BATTERY_STATUS_LOW, (void *)&value)) {
335 BT_ERR("Get the battery low status fail");
339 if (value <= VCONFKEY_SYSMAN_BAT_POWER_OFF)
346 void _bt_util_addr_type_to_addr_string(char *address,
351 ret_if(address == NULL);
352 ret_if(addr == NULL);
354 snprintf(address, BT_ADDRESS_STR_LEN, "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X", addr[0],
355 addr[1], addr[2], addr[3], addr[4], addr[5]);
360 void _bt_util_addr_type_to_addr_result_string(char *address,
365 ret_if(address == NULL);
366 ret_if(addr == NULL);
368 snprintf(address, BT_ADDRESS_STR_LEN, "%2.2X-%2.2X-%2.2X-%2.2X-%2.2X-%2.2X", addr[0],
369 addr[1], addr[2], addr[3], addr[4], addr[5]);
374 void _bt_util_addr_type_to_addr_net_string(char *address,
379 ret_if(address == NULL);
380 ret_if(addr == NULL);
382 snprintf(address, BT_ADDRESS_STR_LEN, "%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X", addr[0],
383 addr[1], addr[2], addr[3], addr[4], addr[5]);
388 void _bt_util_addr_string_to_addr_type(unsigned char *addr,
396 if (!address || !addr)
399 for (i = 0; i < BT_ADDRESS_LENGTH_MAX; i++) {
400 addr[i] = strtol(address, &ptr, 16);
401 if (ptr[0] != '\0') {
403 BT_ERR("Unexpected string");
413 void _bt_util_convert_time_to_string(unsigned int remain_time,
414 char *text_display, char *text_read,
415 int size_display, int size_read)
421 ret_if(remain_time > BT_TIMEOUT_MAX);
424 second = remain_time % 60;
427 minute = remain_time / 60;
429 if (size_display == BT_EXTRA_STR_LEN && text_display != NULL)
430 snprintf(text_display, size_display, "%d:%02d", minute, second);
432 if (size_read == BT_BUFFER_LEN && text_read != NULL) {
433 char min_part[BT_BUFFER_LEN] = { 0, };
434 char sec_part[BT_BUFFER_LEN] = { 0, };
438 snprintf(min_part, BT_BUFFER_LEN, "%s",
441 snprintf(min_part, BT_BUFFER_LEN, "%d %s",
442 minute, BT_STR_MINUTES);
446 snprintf(sec_part, BT_BUFFER_LEN, "%s",
449 snprintf(sec_part, BT_BUFFER_LEN, "%d %s",
450 second, BT_STR_SECONDS);
452 snprintf(text_read, size_read, "%s %s", min_part, sec_part);
457 void _bt_util_launch_no_event(void *data, void *obj, void *event)
461 ("End key is pressed. But there is no action to process in popup");
465 void _bt_util_set_list_disabled(Evas_Object *genlist, Eina_Bool disable)
468 Elm_Object_Item *item = NULL;
469 Elm_Object_Item *next = NULL;
471 item = elm_genlist_first_item_get(genlist);
473 while (item != NULL) {
474 next = elm_genlist_item_next_get(item);
476 elm_object_item_disabled_set(item, disable);
478 _bt_update_genlist_item(item);
484 gboolean _bt_util_is_profile_connected(int connected_type, unsigned char *addr)
487 char addr_str[BT_ADDRESS_STR_LEN + 1] = { 0 };
488 gboolean connected = FALSE;
490 int connected_profiles = 0x00;
491 bt_profile_e profile;
493 retv_if(addr == NULL, FALSE);
495 _bt_util_addr_type_to_addr_string(addr_str, addr);
497 BT_DBG("connected profiles: %d connected type : %d", connected_profiles,
500 switch (connected_type) {
501 case BT_HEADSET_CONNECTED:
502 profile = BT_PROFILE_HSP;
504 case BT_STEREO_HEADSET_CONNECTED:
505 profile = BT_PROFILE_A2DP;
507 case BT_MUSIC_PLAYER_CONNECTED:
508 profile = BT_PROFILE_A2DP_SINK;
510 case BT_HID_CONNECTED:
511 profile = BT_PROFILE_HID;
513 case BT_LE_HID_CONNECTED:
514 if (TIZEN_FEATURE_BT_HOG) {
515 profile = BT_PROFILE_GATT;
520 case BT_NETWORK_CONNECTED:
521 profile = BT_PROFILE_NAP;
523 case BT_NETWORK_SERVER_CONNECTED:
524 profile = BT_PROFILE_NAP_SERVER;
528 BT_ERR("Unknown type!");
532 ret = bt_device_is_profile_connected(addr_str, profile,
535 if (ret < BT_ERROR_NONE) {
536 BT_ERR("failed with [0x%04x]", ret);
544 void _bt_util_free_device_uuids(bt_dev_t *item)
548 ret_if(item == NULL);
551 for (i = 0; item->uuids[i] != NULL; i++)
552 g_free(item->uuids[i]);
559 void _bt_util_free_device_item(bt_dev_t *item)
561 ret_if(item == NULL);
563 _bt_util_free_device_uuids(item);
565 if (item->net_profile) {
566 _bt_unset_profile_state_changed_cb(item->net_profile);
567 item->net_profile = NULL;
574 gboolean _bt_util_is_space_str(const char *name_str)
576 retv_if(name_str == NULL, FALSE);
577 retv_if(*name_str == '\0', FALSE);
580 if (*name_str != '\0' && *name_str != ' ')
589 void _bt_util_max_len_reached_cb(void *data, Evas_Object *obj,
594 char str[BT_STR_ACCES_INFO_MAX_LEN] = {0, };
595 char *stms_str = NULL;
597 stms_str = BT_STR_MAX_CHARACTER_REACHED;
599 snprintf(str, sizeof(str), stms_str, DEVICE_NAME_MAX_CHARACTER);
601 ret = notification_status_message_post(str);
602 if (ret != NOTIFICATION_ERROR_NONE)
603 BT_ERR("notification_status_message_post() ERROR [%d]", ret);
608 void _bt_util_change_discoverable_mode(bt_ug_data *ugd, gboolean discoverable)
612 int ret = BT_ERROR_NONE;
617 ecore_timer_del(ugd->timer);
621 ret_if(ugd->op_status == BT_DEACTIVATED);
624 ret = bt_adapter_set_visibility(
625 BT_ADAPTER_VISIBILITY_MODE_GENERAL_DISCOVERABLE, 0);
627 ret = bt_adapter_set_visibility(
628 BT_ADAPTER_VISIBILITY_MODE_NON_DISCOVERABLE, 0);
630 if (ret != BT_ERROR_NONE)
631 BT_ERR("bt_adapter_set_visibility fail! ret = %d", ret);
637 Eina_Bool _bt_timer_change_discoverable_mode(void *data)
641 bt_ug_data *ugd = data;
642 _bt_util_change_discoverable_mode(ugd, TRUE);
649 int _bt_util_check_any_profile_connected(bt_dev_t *dev)
654 if (dev->service_list & BT_SC_HFP_SERVICE_MASK ||
655 dev->service_list & BT_SC_HSP_SERVICE_MASK ||
656 dev->service_list & BT_SC_A2DP_SERVICE_MASK) {
657 connected = _bt_util_is_profile_connected(BT_HEADSET_CONNECTED,
660 connected = _bt_util_is_profile_connected(BT_STEREO_HEADSET_CONNECTED,
667 if (dev->service_list & BT_SC_A2DP_SOURCE_SERVICE_MASK) {
668 connected = _bt_util_is_profile_connected(BT_MUSIC_PLAYER_CONNECTED,
674 if (dev->service_list & BT_SC_PANU_SERVICE_MASK ||
675 dev->service_list & BT_SC_NAP_SERVICE_MASK ||
676 dev->service_list & BT_SC_GN_SERVICE_MASK) {
677 connected = _bt_util_is_profile_connected(BT_NETWORK_CONNECTED,
680 connected = _bt_util_is_profile_connected(BT_NETWORK_SERVER_CONNECTED,
687 if (dev->service_list & BT_SC_HID_SERVICE_MASK) {
688 connected = _bt_util_is_profile_connected(BT_HID_CONNECTED,
695 /* TODO : other GATT device scenario should be considered.
696 In this case, only HOG device scenario is considered. */
697 if (TIZEN_FEATURE_BT_HOG && dev->is_le_device) {
698 connected = _bt_util_is_profile_connected(BT_LE_HID_CONNECTED,
709 static void __bt_util_dpm_policy_changed_cb(const char *name, const char *value, void *user_data)
713 bt_ug_data *ugd = NULL;
715 ret_if(user_data == NULL);
716 ret_if(name == NULL);
717 ret_if(value == NULL);
719 ugd = (bt_ug_data *)user_data;
721 BT_DBG("policy name: %s", name);
722 BT_DBG("policy value: %s", value);
724 if (strcmp(name, "bluetooth") != 0) {
725 BT_ERR("Not bluetooth policy");
729 if (!strcmp(value, "disallowed")) {
730 BT_DBG("BT policy is restricted");
733 elm_object_item_disabled_set(ugd->onoff_item, EINA_TRUE);
736 elm_object_disabled_set(ugd->onoff_btn, EINA_TRUE);
737 } else if (!strcmp(value, "allowed")) {
738 BT_DBG("BT policy is allowed");
741 elm_object_item_disabled_set(ugd->onoff_item, EINA_FALSE);
744 elm_object_disabled_set(ugd->onoff_btn, EINA_FALSE);
746 BT_ERR("Unknown string value");
752 int _bt_util_create_dpm_context(void *ug_data)
757 device_policy_manager_h handle = NULL;
758 bt_ug_data *ugd = NULL;
760 retv_if(ug_data == NULL, BT_UG_FAIL);
762 ugd = (bt_ug_data *)ug_data;
764 handle = dpm_manager_create();
766 if (handle == NULL) {
767 BT_ERR("Fail to create dpm context");
771 ret = dpm_add_policy_changed_cb(handle, "bluetooth",
772 __bt_util_dpm_policy_changed_cb,
773 (void *)ugd, &ugd->dpm_callback_id);
774 if (ret != DPM_ERROR_NONE)
775 BT_ERR("Fail to destroy dpm context [%d]", ret);
777 ugd->dpm_handle = (void *)handle;
780 return BT_UG_ERROR_NONE;
783 void _bt_util_destroy_dpm_context(void *ug_data)
788 bt_ug_data *ugd = NULL;
790 ret_if(ug_data == NULL);
792 ugd = (bt_ug_data *)ug_data;
794 ret = dpm_remove_policy_changed_cb(ugd->dpm_handle, ugd->dpm_callback_id);
795 if (ret != DPM_ERROR_NONE)
796 BT_ERR("Fail to remove callback [%d]", ret);
798 ret = dpm_manager_destroy(ugd->dpm_handle);
799 if (ret != DPM_ERROR_NONE)
800 BT_ERR("Fail to destroy dpm context [%d]", ret);
802 ugd->dpm_handle = NULL;
803 ugd->dpm_callback_id = 0;
808 gboolean _bt_util_is_dpm_restricted(void *handle)
815 retv_if(handle == NULL, FALSE);
817 ret = dpm_restriction_get_bluetooth_mode_change_state((device_policy_manager_h)handle,
819 if (ret != DPM_ERROR_NONE) {
820 BT_ERR("Fail to destroy dpm context [%d]", ret);
824 BT_DBG("BT dpm state: %d", dpm_state);
827 return (dpm_state == 0) ? TRUE : FALSE;
830 static bool __bt_util_file_exists(const char *file)
835 res = stat(file, &st) == 0 || strcmp(file, "/") == 0;
841 static bool __bt_util_file_remove(const char *file)
846 res = remove(file) == 0;
851 static char *__bt_util_make_vcard_file_path(const char *working_dir, const char *display_name)
853 char file_path[PATH_MAX] = { 0 };
860 display_name = "Unknown";
863 snprintf(file_path, sizeof(file_path), "%s%s-%u.vcf", working_dir, display_name, id);
865 } while (__bt_util_file_exists(file_path));
867 BT_DBG("file_path = %s", file_path);
869 return strdup(file_path);
872 static bool __bt_util_write_vcard_to_file(int fd, contacts_record_h record, bool my_profile)
874 char *vcard_buff = NULL;
881 contacts_vcard_make_from_my_profile(record, &vcard_buff);
883 contacts_vcard_make_from_person(record, &vcard_buff);
886 BT_ERR("vcard_buff is NULL");
890 size_left = strlen(vcard_buff);
892 int written = write(fd, vcard_buff, size_left);
894 BT_ERR("write() failed: %d", errno);
897 size_left -= written;
900 ok = (size_left == 0);
908 static bool __bt_util_write_vcard_to_file_from_id(int fd, int person_id)
910 contacts_record_h record = NULL;
914 int ret = contacts_db_get_record(_contacts_person._uri, person_id, &record);
915 if (ret != CONTACTS_ERROR_NONE) {
916 BT_ERR("contacts_db_get_record() failed: %d", ret);
921 if (!__bt_util_write_vcard_to_file(fd, record, false)) {
922 BT_ERR("_write_vcard_to_file() failed");
930 contacts_record_destroy(record, true);
935 char *_bt_util_vcard_create_from_id(int id, bool my_profile, const char *working_dir)
939 contacts_record_h record = NULL;
940 char *vcard_path = NULL;
945 if (TIZEN_PROFILE_TV)
948 BT_DBG("id = %i my_profile = %d", id, my_profile);
950 ret = contacts_connect();
951 if (ret != CONTACTS_ERROR_NONE)
952 BT_ERR("contacts_connect failed : ct_err = [%d]", ret);
955 char *display_name = NULL;
957 int ret = contacts_db_get_record((my_profile ?
958 _contacts_my_profile._uri :
959 _contacts_person._uri), id, &record);
960 if (ret != CONTACTS_ERROR_NONE) {
961 BT_ERR("contacts_db_get_record() failed: %d", ret);
967 contacts_record_get_str_p(record, _contacts_my_profile.display_name, &display_name);
969 contacts_record_get_str_p(record, _contacts_person.display_name, &display_name);
971 (void) display_name; /* Ignore unused variable for dummy contacts.h */
973 vcard_path = __bt_util_make_vcard_file_path(working_dir, "Contact");
975 BT_ERR("_make_vcard_file_path() failed");
979 fd = open(vcard_path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
981 BT_ERR("open(%s) Failed(%d)", vcard_path, errno);
985 if (!__bt_util_write_vcard_to_file(fd, record, my_profile)) {
986 BT_ERR("_write_vcard_to_file() failed");
993 ret = contacts_disconnect();
994 if (ret != CONTACTS_ERROR_NONE)
995 BT_ERR("contacts_disconnect failed : ct_err = [%d]", ret);
998 contacts_record_destroy(record, true);
1003 __bt_util_file_remove(vcard_path);
1016 char *_bt_util_vcard_create_from_id_list(const int *id_list, int count, const char *working_dir, volatile bool *cancel)
1020 char *vcard_path = NULL;
1025 if (TIZEN_PROFILE_TV)
1028 if (!id_list || count <= 0)
1031 ret = contacts_connect();
1032 if (ret != CONTACTS_ERROR_NONE)
1033 BT_ERR("contacts_connect failed : ct_err = [%d]", ret);
1038 vcard_path = __bt_util_make_vcard_file_path(working_dir, "Contacts");
1040 BT_ERR("_make_vcard_file_path() failed");
1044 fd = open(vcard_path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
1046 BT_ERR("open(%s) Failed(%d)", vcard_path, errno);
1050 for (i = 0; !(*cancel) && (i < count); ++i) {
1051 if (!__bt_util_write_vcard_to_file_from_id(fd, id_list[i])) {
1052 BT_ERR("_composer_write_vcard_to_file() failed");
1060 ret = contacts_disconnect();
1061 if (ret != CONTACTS_ERROR_NONE)
1062 BT_ERR("contacts_disconnect failed : ct_err = [%d]", ret);
1067 __bt_util_file_remove(vcard_path);
1080 tizen_profile_t _get_tizen_profile()
1082 static tizen_profile_t profile = _PROFILE_UNKNOWN;
1085 if (__builtin_expect(profile != _PROFILE_UNKNOWN, 1))
1088 system_info_get_platform_string("http://tizen.org/feature/profile", &profileName);
1089 switch (*profileName) {
1092 profile = _PROFILE_MOBILE;
1096 profile = _PROFILE_WEARABLE;
1100 profile = _PROFILE_TV;
1104 profile = _PROFILE_IVI;
1106 default: // common or unknown ==> ALL ARE COMMON.
1107 profile = _PROFILE_COMMON;