Initialize Tizen 2.3 tizen_2.3 2.3a_release submit/tizen_2.3/20140531.114329
authorSehong Na <sehong.na@samsung.com>
Sat, 31 May 2014 04:19:46 +0000 (13:19 +0900)
committerSehong Na <sehong.na@samsung.com>
Sat, 31 May 2014 04:19:46 +0000 (13:19 +0900)
47 files changed:
.gitignore [new file with mode: 0644]
AUTHORS [new file with mode: 0644]
CMakeLists.txt [new file with mode: 0644]
LICENSE [new file with mode: 0644]
client/CMakeLists.txt [new file with mode: 0755]
client/include/weconn.h [new file with mode: 0644]
client/include/weconn_type.h [new file with mode: 0644]
client/src/weconnection.c [new file with mode: 0644]
client/weconn.pc.in [new file with mode: 0644]
include/conn.h [new file with mode: 0644]
include/control.h [new file with mode: 0644]
include/dbus.h [new file with mode: 0644]
include/driver.h [new file with mode: 0644]
include/error.h [new file with mode: 0644]
include/events.h [new file with mode: 0644]
include/log.h [new file with mode: 0644]
include/object.h [new file with mode: 0644]
include/service.h [new file with mode: 0644]
include/technology.h [new file with mode: 0644]
include/util.h [new file with mode: 0644]
introspection/service.xml [new file with mode: 0644]
introspection/technology.xml [new file with mode: 0644]
packaging/weconn.spec [new file with mode: 0644]
plugins/CMakeLists.txt [new file with mode: 0755]
plugins/bluetooth.c [new file with mode: 0644]
plugins/esap.c [new file with mode: 0644]
plugins/esap.h [new file with mode: 0644]
plugins/pan.c [new file with mode: 0644]
plugins/plugin.h [new file with mode: 0644]
resources/etc/dbus-1/system.d/weconn.conf [new file with mode: 0644]
resources/etc/opt/upgrade/500.net.weconn.patch.sh [new file with mode: 0755]
resources/mdbus2 [new file with mode: 0755]
resources/usr/lib/systemd/system/weconn.service [new file with mode: 0644]
resources/usr/share/appcessory/wearable-connection.xml [new file with mode: 0644]
resources/usr/share/dbus-1/services/net.weconn.service [new file with mode: 0644]
src/control/control.c [new file with mode: 0644]
src/dbus.c [new file with mode: 0644]
src/driver.c [new file with mode: 0644]
src/error.c [new file with mode: 0644]
src/main.c [new file with mode: 0644]
src/object.c [new file with mode: 0644]
src/service.c [new file with mode: 0644]
src/technology.c [new file with mode: 0644]
src/util.c [new file with mode: 0644]
test/CMakeLists.txt [new file with mode: 0644]
test/w_connection_manager_test.c [new file with mode: 0644]
weconn.manifest [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..17eecd4
--- /dev/null
@@ -0,0 +1,14 @@
+# git ls-files --others --exclude-from=.git/info/exclude
+# Lines that start with '#' are comments.
+# For a project mostly in C, the following would be a good set of
+# exclude patterns (uncomment them if you want to use them):
+# *.[oa]
+# *~
+*.[oa]
+*~
+build-stamp
+cmake_build_tmp
+configure-stamp
+.project
+.cproject
+.settings
diff --git a/AUTHORS b/AUTHORS
new file mode 100644 (file)
index 0000000..8834b34
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,4 @@
+Danny Jeongseok Seo <s.seo@samsung.com>
+Misun Kim <ms0123.kim@samsung.com>
+Sanghoon Cho <sanghoon80.cho@samsung.com>
+Kyoungyoup Park <gynaru.park@samsung.com>
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644 (file)
index 0000000..368db4f
--- /dev/null
@@ -0,0 +1,87 @@
+CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
+PROJECT(weconn)
+
+SET(PREFIX ${CMAKE_INSTALL_PREFIX})
+SET(LIBDIR "${PREFIX}/lib")
+SET(INCLUDEDIR "${PREFIX}/include")
+SET(PKGCONFIGDIR "${PREFIX}/lib/pkgconfig" CACHE PATH PKGCONFIGDIR)
+SET(INTROSPECTION "${CMAKE_SOURCE_DIR}/introspection")
+SET(WECONNLIB "${LIBDIR}/${PROJECT_NAME}")
+SET(BINDIR "${PREFIX}/sbin")
+SET(main_PROGRAM "weconnd")
+
+
+INCLUDE(FindPkgConfig)
+pkg_check_modules(pkgs REQUIRED
+       dlog
+       vconf
+       gio-2.0
+       glib-2.0
+       gio-unix-2.0
+       alarm-service
+       sap-client-stub-api
+       capi-appfw-application
+       capi-network-bluetooth
+       capi-system-info
+)
+
+FOREACH(flag ${pkgs_CFLAGS})
+       SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}")
+ENDFOREACH(flag)
+
+INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR} ${CMAKE_SOURCE_DIR}/include/)
+
+SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS}")
+SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC -Wall -Werror -Wextra -fvisibility=hidden -fdata-sections -ffunction-sections -Wl,--gc-sections")
+SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-unused-parameter -Wno-missing-field-initializers -Wdeclaration-after-statement -Wmissing-declarations")
+SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-unused-local-typedefs -Wcast-align -Wconversion")
+SET(CMAKE_C_FLAGS_DEBUG "-O0 -g")
+SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--as-needed -Wl,-z,nodelete")
+
+ADD_DEFINITIONS("-DVERSION=\"${VERSION}\"")
+ADD_DEFINITIONS("-DEXPORT_API=__attribute__((visibility(\"default\")))")
+ADD_DEFINITIONS("-DWECONN_PLUGIN_PATH=\"${WECONNLIB}\"")
+
+MESSAGE(${CMAKE_C_FLAGS})
+MESSAGE(${pkgs_LDFLAGS})
+
+REMOVE_DEFINITIONS("-DLOG_TAG=\"CAPI_NETWORK_WECONN\"")
+ADD_DEFINITIONS("-DLOG_TAG=\"WECONN\"")
+
+
+SET(SRCS
+       src/dbus.c
+       src/main.c
+       src/util.c
+       src/error.c
+       src/driver.c
+       src/object.c
+       src/service.c
+       src/technology.c
+       src/control/control.c
+)
+
+CONFIGURE_FILE(client/include/weconn_type.h include/weconn_type.h COPYONLY)
+
+ADD_CUSTOM_COMMAND(
+       WORKING_DIRECTORY
+       OUTPUT ${CMAKE_BINARY_DIR}/generated-code.c
+       COMMAND gdbus-codegen --interface-prefix net.weconn. --generate-c-code generated-code --c-namespace weconn --c-generate-object-manager --generate-docbook generated-docs
+       ${INTROSPECTION}/service.xml
+       ${INTROSPECTION}/technology.xml
+       COMMENT "Generating GDBus .c/.h")
+
+ADD_EXECUTABLE(${main_PROGRAM} ${SRCS} ${CMAKE_BINARY_DIR}/generated-code.c)
+TARGET_LINK_LIBRARIES(${main_PROGRAM} ${pkgs_LDFLAGS} "-ldl -L${CMAKE_BINARY_DIR}")
+
+INSTALL(TARGETS ${main_PROGRAM} DESTINATION ${BINDIR})
+
+
+# Wearable device connection controller plugins
+ADD_SUBDIRECTORY(plugins)
+
+# Wearable device connection controller API library in TIZEN C API (Development)
+ADD_SUBDIRECTORY(client)
+
+# Wearable connection manager API sample
+ADD_SUBDIRECTORY(test)
diff --git a/LICENSE b/LICENSE
new file mode 100644 (file)
index 0000000..d8522e9
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,203 @@
+Copyright (c) 2013 - 2014 Samsung Electronics Co., Ltd. All rights reserved.
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   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.
diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..eb7ad84
--- /dev/null
@@ -0,0 +1,26 @@
+SET(CLIENT "weconn")
+
+REMOVE_DEFINITIONS("-DLOG_TAG=\"WECONN\"")
+ADD_DEFINITIONS("-DLOG_TAG=\"CAPI_NETWORK_WECONN\"")
+
+
+CONFIGURE_FILE(../src/util.c src/util.c COPYONLY)
+
+SET(CLIENT_SRCS
+       src/util.c
+       src/weconnection.c
+)
+
+INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/include/)
+
+ADD_LIBRARY(${CLIENT} SHARED ${CLIENT_SRCS})
+TARGET_LINK_LIBRARIES(${CLIENT} ${pkgs_LDFLAGS})
+SET_TARGET_PROPERTIES(${CLIENT} PROPERTIES VERSION ${VERSION} SOVERSION 0 OUTPUT_NAME ${CLIENT})
+
+# pkgconfig file
+CONFIGURE_FILE(${CLIENT}.pc.in ${CLIENT}.pc @ONLY)
+
+# install
+INSTALL(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include/ DESTINATION include/${CLIENT})
+INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/${CLIENT}.pc DESTINATION ${LIBDIR}/pkgconfig)
+INSTALL(TARGETS ${CLIENT} DESTINATION ${LIBDIR})
diff --git a/client/include/weconn.h b/client/include/weconn.h
new file mode 100644 (file)
index 0000000..056b53c
--- /dev/null
@@ -0,0 +1,163 @@
+/*
+ * Wearable device Connection Controller Framework
+ *
+ * Copyright (c) 2013 - 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __WECONN_CLIENT_H__
+#define __WECONN_CLIENT_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <tizen.h>
+
+#include "weconn_type.h"
+
+/**
+ * @addtogroup CAPI_WEARABLE_DEVICE_CONNECTION_MANAGER_MODULE
+ * @{
+ */
+
+/**
+ * @brief  The wearable connection handle for all connection functions.
+ */
+typedef void *weconn_h;
+
+/**
+* @brief Called after weconn_connect_service() is completed.
+* @param[in] result  The result
+* @param[in] user_data The user data passed from weconn_connect_service()
+* @pre weconn_connect_service() will invoke this callback function.
+* @see weconn_connect_service()
+*/
+typedef void (*weconn_connected_cb) (int result, void *user_data);
+
+/**
+ * @brief  Creates a handle for managing wearable connections.
+ * @remarks @a handle must be released with weconn_destroy().
+ * @param[out] conn  The handle of the wearable connection
+ * @return On success, 0 is returned. On error, -1 or -errno is returned.
+ *          All the errno numbers specified by POSIX, the ISO C standard.
+ * @see weconn_destroy()
+ */
+int weconn_create(weconn_h *conn);
+
+/**
+ * @brief  Destroys the wearable connection handle.
+ * @param[in] conn  The handle of the wearable connection
+ * @return On success, 0 is returned. On error, -1 or -errno is returned.
+ *          All the errno numbers specified by POSIX, the ISO C standard.
+ * @see weconn_create()
+ */
+int weconn_destroy(weconn_h conn);
+
+/**
+ * @brief  Gets the wearable connection service state.
+ * @details The returned state is for the wearable connection service type.
+ * @param[in] conn  The handle of the wearable connection
+ * @param[in] type  The wearable connection service type
+ * @param[out] state  The state of wearable connection service type
+ * @return On success, 0 is returned. On error, -1 or -errno is returned.
+ *          All the errno numbers specified by POSIX, the ISO C standard.
+ */
+int weconn_get_service_state(weconn_h conn,
+                               weconn_service_type_e type, weconn_service_state_e *state);
+
+/**
+ * @brief  Gets the wearable device state.
+ * @details The returned state is for the connection device type.
+ * @param[in] conn  The handle of the wearable connection
+ * @param[in] type  The wearable connection device type
+ * @param[out] state  The state of wearable connection device type
+ * @return On success, 0 is returned. On error, -1 or -errno is returned.
+ *          All the errno numbers specified by POSIX, the ISO C standard.
+ */
+int weconn_get_device_state(weconn_h conn,
+                               weconn_device_type_e type, weconn_device_state_e *state);
+
+/**
+ * @brief  Connect a service..
+ * @param[in] conn  The handle of the wearable connection
+ * @param[in] type  The wearable connection service type
+ * @param[in] callback  The callback function to be called.
+ *                     This can be NULL if you don't want to get the notification.
+ * @param[in] user_data The user data passed to the callback function
+ * @return On success, 0 is returned. On error, -1 or -errno is returned.
+ *          All the errno numbers specified by POSIX, the ISO C standard.
+ */
+int weconn_connect_service(weconn_h conn, weconn_service_type_e type,
+                               weconn_connected_cb callback, void *user_data);
+
+/**
+ * @brief  Disconnect a service..
+ * @param[in] conn  The handle of the wearable connection
+ * @param[in] type  The wearable connection service type
+ * @param[in] callback  The callback function to be called.
+ *                     This can be NULL if you don't want to get the notification.
+ * @param[in] user_data The user data passed to the callback function
+ * @return On success, 0 is returned. On error, -1 or -errno is returned.
+ *          All the errno numbers specified by POSIX, the ISO C standard.
+ */
+int weconn_disconnect_service(weconn_h conn, weconn_service_type_e type,
+                               weconn_connected_cb callback, void *user_data);
+
+/**
+ * @brief  Called when the state of service is changed
+ * @param[out] state  The state of service
+ * @param[out] user_data  The user data passed from the callback
+ *                             registration function
+ * @see weconn_set_service_state_change_cb()
+ * @see weconn_unset_service_state_change_cb()
+ */
+typedef void(*weconn_service_state_changed_cb)
+                               (weconn_service_state_e state, void *user_data);
+
+/**
+ * @brief  Registers the callback called when the state of service is
+ *                             changed.
+ * @param[in] conn  The handle of the wearable connection
+ * @param[in] callback  The callback function to be called
+ * @param[in] type  The wearable connection service type
+ * @param[in] user_data  The user data passed from the callback
+ *                             registration function
+ * @return On success, 0 is returned. On error, -1 or -errno is returned.
+ *          All the errno numbers specified by POSIX, the ISO C standard.
+ */
+int weconn_set_service_state_change_cb(weconn_h conn,
+               weconn_service_state_changed_cb callback,
+               weconn_service_type_e type, void *user_data);
+
+/**
+ * @brief  Unregisters the callback called when the state of service is
+ *                             changed.
+ * @param[in] conn  The handle of the wearable connection
+ * @param[in] type  The wearable connection service type
+ * @return On success, 0 is returned. On error, -1 or -errno is returned.
+ *          All the errno numbers specified by POSIX, the ISO C standard.
+ */
+int weconn_unset_service_state_change_cb(weconn_h conn,
+               weconn_service_type_e type);
+/**
+* @}
+*/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __WECONN_CLIENT_H__ */
diff --git a/client/include/weconn_type.h b/client/include/weconn_type.h
new file mode 100644 (file)
index 0000000..7ad8a9b
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * Wearable device Connection Controller Framework
+ *
+ * Copyright (c) 2013 - 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __WECONN_TYPE_H__
+#define __WECONN_TYPE_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @addtogroup CAPI_WEARABLE_DEVICE_CONNECTION_ENUMERATION_TYPE
+ * @{
+ */
+
+/**
+ * @brief  Enumerations of wearable connection service type.
+ */
+typedef enum
+{
+       /* Generic connectivity */
+       W_SERVICE_TYPE_HOST_TO_WEARABLE_CONNECTIVITY    = 0x01,
+                               /* Generic connectivity between host and wearable devices */
+       W_SERVICE_TYPE_INTERNET_CONNECTIVITY                    = 0x02,
+                               /* Generic connectivity into the Internet accessibility */
+
+       /* Specific technology based connectivity */
+       W_SERVICE_TYPE_BT_HFP           = 0x11, /* Bluetooth Hands-Free Profile */
+       W_SERVICE_TYPE_BT_SPP           = 0x12, /* Bluetooth Serial Port Profile */
+       W_SERVICE_TYPE_BT_PAN           = 0x13, /* Bluetooth Personal Area Network */
+       W_SERVICE_TYPE_BT_GATT          = 0x14,
+                                                                       /* Bluetooth Generic Attribute Profile */
+       W_SERVICE_TYPE_CELLULAR         = 0x15, /* Cellular Network */
+       W_SERVICE_TYPE_WIFI                     = 0x16, /* Wi-Fi Network */
+       W_SERVICE_TYPE_WIFI_P2P         = 0x17, /* Wi-Fi P2P Network */
+       W_SERVICE_TYPE_WIFI_ADHOC       = 0x18, /* Wi-Fi Ad-hoc Network */
+       W_SERVICE_TYPE_ETHERNET         = 0x19, /* Cable Network */
+} weconn_service_type_e;
+
+/**
+ * @brief  Enumerations of wearable connection service state.
+ */
+typedef enum
+{
+       W_SERVICE_STATE_DISCONNECTED    = 0x01,
+       W_SERVICE_STATE_CONNECTING              = 0x02,
+       W_SERVICE_STATE_CONNECTED               = 0x03,
+       W_SERVICE_STATE_DISCONNECTING   = 0x04,
+} weconn_service_state_e;
+
+/**
+ * @brief  Enumerations of wearable connection device type.
+ */
+typedef enum
+{
+       W_DEVICE_TYPE_BT                        = 0x01, /* Bluetooth */
+       W_DEVICE_TYPE_CELLULAR          = 0x02, /* Cellular */
+       W_DEVICE_TYPE_WIFI                      = 0x03, /* Wi-Fi */
+       W_DEVICE_TYPE_WIFI_P2P          = 0x04, /* Wi-Fi P2P */
+       W_DEVICE_TYPE_WIFI_ADHOC        = 0x05, /* Wi-Fi Ad-hoc */
+       W_DEVICE_TYPE_ETHERNET          = 0x06, /* Cable */
+} weconn_device_type_e;
+
+/**
+ * @brief  Enumerations of wearable connection device state.
+ */
+typedef enum
+{
+       W_DEVICE_STATE_DISABLED         = 0x01,
+       W_DEVICE_STATE_ENABLED          = 0x02,
+} weconn_device_state_e;
+
+/**
+* @}
+*/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __WECONN_TYPE_H__ */
diff --git a/client/src/weconnection.c b/client/src/weconnection.c
new file mode 100644 (file)
index 0000000..93a1d95
--- /dev/null
@@ -0,0 +1,858 @@
+/*
+ * Wearable device Connection Controller Framework
+ *
+ * Copyright (c) 2013 - 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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 <glib.h>
+#include <dlfcn.h>
+#include <errno.h>
+#include <gio/gio.h>
+
+#include "log.h"
+#include "dbus.h"
+#include "util.h"
+#include "weconn.h"
+
+struct weconn_connection {
+       GDBusConnection *connection;
+       GCancellable *cancellable;
+
+       weconn_service_type_e connect_service_type;
+       weconn_connected_cb connected_callback;
+       void *connect_user_data;
+
+       weconn_service_type_e disconnect_service_type;
+       weconn_connected_cb disconnected_callback;
+       void *disconnect_user_data;
+
+       int ref_count;
+       bool lazy_destroy;
+};
+
+struct weconn_service_handle {
+       weconn_h conn;
+       weconn_service_state_changed_cb callback;
+       void *user_data;
+};
+
+static __thread void *handle_libweconn = NULL;
+static __thread GHashTable *weconn_handle_hash = NULL;
+
+static __thread GHashTable *wc_internet_service_con_changed_cb_hash = NULL;
+static __thread GHashTable *wc_wearable_service_con_changed_cb_hash = NULL;
+
+static __thread guint weconn_conn_subscribe_id_weconn_state = 0;
+
+static bool __weconn_check_handle_validity(weconn_h conn)
+{
+       struct weconn_connection *h;
+
+       if (!conn || !weconn_handle_hash)
+               return false;
+
+       h = g_hash_table_lookup(weconn_handle_hash, conn);
+       if (!h)
+               return false;
+
+       if (h->lazy_destroy)
+               return false;
+
+       return true;
+}
+
+static GDBusConnection *__weconn_call_ref(struct weconn_connection *h)
+{
+       if (h->lazy_destroy)
+               return NULL;
+
+       g_object_ref(h->connection);
+
+       __sync_fetch_and_add(&h->ref_count, 1);
+
+       return h->connection;
+}
+
+static void __weconn_call_unref(struct weconn_connection *h)
+{
+       __sync_synchronize();
+       if (h->ref_count < 1)
+               return;
+
+       g_object_unref(h->connection);
+
+       if (__sync_sub_and_fetch(&h->ref_count, 1) < 1 && h->lazy_destroy)
+               g_hash_table_remove(weconn_handle_hash, h);
+}
+
+static const char *__weconn_get_technology_path4service(
+               weconn_service_type_e service_type)
+{
+       switch (service_type) {
+       case W_SERVICE_TYPE_BT_HFP:
+       case W_SERVICE_TYPE_BT_SPP:
+       case W_SERVICE_TYPE_BT_PAN:
+       case W_SERVICE_TYPE_BT_GATT:
+               return WECONN_TECHNOLOGY_BLUETOOTH_PATH;
+       case W_SERVICE_TYPE_CELLULAR:
+               return WECONN_TECHNOLOGY_CELLULAR_PATH;
+       case W_SERVICE_TYPE_WIFI:
+               return WECONN_TECHNOLOGY_WIFI_PATH;
+       case W_SERVICE_TYPE_WIFI_P2P:
+               return WECONN_TECHNOLOGY_WIFI_P2P_PATH;
+       case W_SERVICE_TYPE_WIFI_ADHOC:
+               return WECONN_TECHNOLOGY_WIFI_ADHOC_PATH;
+       case W_SERVICE_TYPE_ETHERNET:
+               return WECONN_TECHNOLOGY_ETHERNET_PATH;
+       default:
+               break;
+       }
+
+       return NULL;
+}
+
+static const char *__weconn_get_technology_path4device(
+               weconn_device_type_e device_type)
+{
+       switch (device_type) {
+       case W_DEVICE_TYPE_BT:
+               return WECONN_TECHNOLOGY_BLUETOOTH_PATH;
+       case W_DEVICE_TYPE_CELLULAR:
+               return WECONN_TECHNOLOGY_CELLULAR_PATH;
+       case W_DEVICE_TYPE_WIFI:
+               return WECONN_TECHNOLOGY_WIFI_PATH;
+       case W_DEVICE_TYPE_WIFI_P2P:
+               return WECONN_TECHNOLOGY_WIFI_P2P_PATH;
+       case W_DEVICE_TYPE_WIFI_ADHOC:
+               return WECONN_TECHNOLOGY_WIFI_ADHOC_PATH;
+       case W_DEVICE_TYPE_ETHERNET:
+               return WECONN_TECHNOLOGY_ETHERNET_PATH;
+       }
+
+       return NULL;
+}
+
+static GDBusConnection *__weconn_setup_dbus(void)
+{
+       GError *error = NULL;
+       GDBusConnection *connection = NULL;
+
+       connection = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error);
+       if (!connection) {
+               ERR("Failed to get system bus %s", error->message);
+               g_error_free(error);
+               return NULL;
+       }
+
+       return connection;
+}
+
+static void __weconn_destroy_handle(gpointer data)
+{
+       g_free(data);
+
+       if (handle_libweconn && g_hash_table_size(weconn_handle_hash) < 1) {
+               dlclose(handle_libweconn);
+               handle_libweconn = NULL;
+       }
+}
+
+static void __weconn_bt_connection_response(struct weconn_connection *conn,
+               int result, gpointer user_data)
+{
+       struct weconn_connection *h = conn;
+       if (!h)
+               return;
+
+       h->connected_callback(result, h->connect_user_data);
+       h->connected_callback = NULL;
+       h->connect_service_type = 0;
+}
+
+static void __weconn_bt_disconnection_response(struct weconn_connection *conn,
+               int result, gpointer user_data)
+{
+       struct weconn_connection *h = conn;
+       if (!h)
+               return;
+
+       h->disconnected_callback(result, h->disconnect_user_data);
+       h->disconnected_callback = NULL;
+       h->disconnect_service_type = 0;
+}
+
+static void __weconn_connection_response(gpointer key, gpointer value,
+               gpointer user_data)
+{
+       struct weconn_connection *h = NULL;
+       int *result;
+
+
+       h = (struct weconn_connection *)key;
+       if (!h)
+               return;
+
+       result = (int *)user_data;
+
+       if (h->connected_callback) {
+               switch (h->connect_service_type) {
+               case W_SERVICE_TYPE_BT_HFP:
+               case W_SERVICE_TYPE_BT_SPP:
+               case W_SERVICE_TYPE_BT_PAN:
+               case W_SERVICE_TYPE_BT_GATT:
+                       __weconn_bt_connection_response(h, *result, user_data);
+                       break;
+               case W_SERVICE_TYPE_CELLULAR:
+                       break;
+               case W_SERVICE_TYPE_WIFI:
+                       break;
+               case W_SERVICE_TYPE_WIFI_P2P:
+                       break;
+               case W_SERVICE_TYPE_WIFI_ADHOC:
+                       break;
+               case W_SERVICE_TYPE_ETHERNET:
+                       break;
+               default:
+                       break;
+               }
+       }
+}
+
+static void __weconn_disconnection_response(gpointer key, gpointer value,
+               gpointer user_data)
+{
+       struct weconn_connection *h = NULL;
+       int *result;
+
+
+       h = (struct weconn_connection *)key;
+       if (!h)
+               return;
+
+       result = (int *)user_data;
+
+       if (h->disconnected_callback) {
+               switch (h->disconnect_service_type) {
+               case W_SERVICE_TYPE_BT_HFP:
+               case W_SERVICE_TYPE_BT_SPP:
+               case W_SERVICE_TYPE_BT_PAN:
+               case W_SERVICE_TYPE_BT_GATT:
+                       __weconn_bt_disconnection_response(h, *result, user_data);
+                       break;
+               case W_SERVICE_TYPE_CELLULAR:
+                       break;
+               case W_SERVICE_TYPE_WIFI:
+                       break;
+               case W_SERVICE_TYPE_WIFI_P2P:
+                       break;
+               case W_SERVICE_TYPE_WIFI_ADHOC:
+                       break;
+               case W_SERVICE_TYPE_ETHERNET:
+                       break;
+               default:
+                       break;
+               }
+       }
+}
+
+static void __weconn_pan_service_state_changed(gpointer key, gpointer value,
+               gpointer user_data)
+{
+       weconn_h conn;
+       struct weconn_service_handle *h_service = NULL;
+       int *state = NULL;
+
+       conn = (weconn_h)key;
+       if (!conn)
+               return;
+
+       h_service = (struct weconn_service_handle *)value;
+       if (!h_service)
+               return;
+
+       state = (int *)user_data;
+       if (!state)
+               return;
+
+       if (h_service->callback) {
+               h_service->callback(*state, h_service->user_data);
+       }
+}
+
+static void __weconn_technology_signal_filter(GDBusConnection *conn,
+               const gchar *name, const gchar *path, const gchar *interface,
+               const gchar *sig, GVariant *param, gpointer user_data)
+{
+       const char *service;
+       int result;
+
+       if (g_strcmp0(sig, WECONN_TECHNOLOGY_SIGNAL_CONNECTION_RESULT) == 0) {
+               g_variant_get(param, "(si)", &service, &result);
+
+               if (g_strcmp0(XSTR(W_SERVICE_TYPE_BT_HFP), service) == 0) {
+               } else if (g_strcmp0(XSTR(W_SERVICE_TYPE_BT_SPP), service) == 0) {
+               } else if (g_strcmp0(XSTR(W_SERVICE_TYPE_BT_PAN), service) == 0) {
+                       g_hash_table_foreach(weconn_handle_hash,
+                                       __weconn_connection_response, &result);
+               } else if (g_strcmp0(XSTR(W_SERVICE_TYPE_BT_GATT), service) == 0) {
+               } else if (g_strcmp0(XSTR(W_SERVICE_TYPE_CELLULAR), service) == 0) {
+               } else if (g_strcmp0(XSTR(W_SERVICE_TYPE_WIFI), service) == 0) {
+               } else if (g_strcmp0(XSTR(W_SERVICE_TYPE_WIFI_P2P), service) == 0) {
+               } else if (g_strcmp0(XSTR(W_SERVICE_TYPE_WIFI_ADHOC), service) == 0) {
+               } else if (g_strcmp0(XSTR(W_SERVICE_TYPE_ETHERNET), service) == 0) {
+               }
+       } else if (g_strcmp0(sig, WECONN_TECHNOLOGY_SIGNAL_DISCONNECTION_RESULT) == 0) {
+               g_variant_get(param, "(si)", &service, &result);
+
+               if (g_strcmp0(XSTR(W_SERVICE_TYPE_BT_HFP), service) == 0) {
+               } else if (g_strcmp0(XSTR(W_SERVICE_TYPE_BT_SPP), service) == 0) {
+               } else if (g_strcmp0(XSTR(W_SERVICE_TYPE_BT_PAN), service) == 0) {
+                       g_hash_table_foreach(weconn_handle_hash,
+                                       __weconn_disconnection_response, &result);
+               } else if (g_strcmp0(XSTR(W_SERVICE_TYPE_BT_GATT), service) == 0) {
+               } else if (g_strcmp0(XSTR(W_SERVICE_TYPE_CELLULAR), service) == 0) {
+               } else if (g_strcmp0(XSTR(W_SERVICE_TYPE_WIFI), service) == 0) {
+               } else if (g_strcmp0(XSTR(W_SERVICE_TYPE_WIFI_P2P), service) == 0) {
+               } else if (g_strcmp0(XSTR(W_SERVICE_TYPE_WIFI_ADHOC), service) == 0) {
+               } else if (g_strcmp0(XSTR(W_SERVICE_TYPE_ETHERNET), service) == 0) {
+               }
+       } else if (g_strcmp0(sig, WECONN_TECHNOLOGY_SIGNAL_SERVICE_STATE_CHANGED) == 0) {
+               g_variant_get(param, "(si)", &service, &result);
+
+               if (g_strcmp0(XSTR(W_SERVICE_TYPE_BT_HFP), service) == 0) {
+               } else if (g_strcmp0(XSTR(W_SERVICE_TYPE_BT_SPP), service) == 0) {
+               } else if (g_strcmp0(XSTR(W_SERVICE_TYPE_BT_PAN), service) == 0) {
+                       g_hash_table_foreach(wc_internet_service_con_changed_cb_hash,
+                                       __weconn_pan_service_state_changed, &result);
+               } else if (g_strcmp0(XSTR(W_SERVICE_TYPE_BT_GATT), service) == 0) {
+               } else if (g_strcmp0(XSTR(W_SERVICE_TYPE_CELLULAR), service) == 0) {
+               } else if (g_strcmp0(XSTR(W_SERVICE_TYPE_WIFI), service) == 0) {
+               } else if (g_strcmp0(XSTR(W_SERVICE_TYPE_WIFI_P2P), service) == 0) {
+               } else if (g_strcmp0(XSTR(W_SERVICE_TYPE_WIFI_ADHOC), service) == 0) {
+               } else if (g_strcmp0(XSTR(W_SERVICE_TYPE_ETHERNET), service) == 0) {
+               }
+       } else {
+               ERR("No handle signal(%s)", sig);
+       }
+}
+
+static bool __weconn_register_signal(void)
+{
+       GDBusConnection *connection = NULL;
+       guint id;
+
+       connection = __weconn_setup_dbus();
+       if (connection == NULL)
+               return false;
+
+       id = g_dbus_connection_signal_subscribe(
+                       connection,
+                       WECONN_SERVICE_DBUS,
+                       WECONN_TECHNOLOGY_INTERFACE,
+                       NULL,
+                       NULL,
+                       NULL,
+                       G_DBUS_SIGNAL_FLAGS_NONE,
+                       __weconn_technology_signal_filter,
+                       NULL,
+                       NULL);
+       if (id == 0) {
+               ERR("Failed register signals (%d)", id);
+               return false;
+       }
+
+       weconn_conn_subscribe_id_weconn_state = id;
+
+       return true;
+}
+
+static void __weconn_deregister_signal(void)
+{
+       GDBusConnection *connection = NULL;
+
+       connection = __weconn_setup_dbus();
+       if (connection == NULL)
+               return;
+
+       g_dbus_connection_signal_unsubscribe(connection,
+                       weconn_conn_subscribe_id_weconn_state);
+}
+
+EXPORT_API int weconn_create(weconn_h *conn)
+{
+       struct weconn_connection *h;
+
+       if (!conn || __weconn_check_handle_validity(*conn))
+               return -EINVAL;
+
+       if (!weconn_handle_hash) {
+               g_type_init();
+
+               weconn_handle_hash = g_hash_table_new_full(g_direct_hash,
+                               g_direct_equal, NULL, __weconn_destroy_handle);
+       }
+
+       if (!handle_libweconn)
+               handle_libweconn = dlopen("/usr/lib/libweconn.so", RTLD_LAZY);
+
+       if (!wc_internet_service_con_changed_cb_hash)
+               wc_internet_service_con_changed_cb_hash = g_hash_table_new_full(
+                               g_str_hash, g_str_equal, NULL, g_free);
+
+       if (!wc_wearable_service_con_changed_cb_hash)
+               wc_wearable_service_con_changed_cb_hash = g_hash_table_new_full(
+                               g_str_hash, g_str_equal, NULL, g_free);
+
+       h = g_try_new0(struct weconn_connection, 1);
+       if (!h)
+               return -ENOMEM;
+
+       h->connection = __weconn_setup_dbus();
+       if (!h->connection) {
+               g_free(h);
+               return -EIO;
+       }
+
+       h->cancellable = g_cancellable_new();
+       *conn = (weconn_h)h;
+
+       g_hash_table_replace(weconn_handle_hash, *conn, *conn);
+
+       __weconn_register_signal();
+
+       return 0;
+}
+
+EXPORT_API int weconn_destroy(weconn_h conn)
+{
+       struct weconn_connection *h;
+
+       if (!__weconn_check_handle_validity(conn))
+               return -EINVAL;
+
+       h = (struct weconn_connection *)conn;
+       g_object_unref(h->connection);
+       g_cancellable_cancel(h->cancellable);
+
+       if (wc_internet_service_con_changed_cb_hash) {
+               g_hash_table_destroy(wc_internet_service_con_changed_cb_hash);
+               wc_internet_service_con_changed_cb_hash = NULL;
+       }
+
+       if (wc_wearable_service_con_changed_cb_hash) {
+               g_hash_table_destroy(wc_wearable_service_con_changed_cb_hash);
+               wc_wearable_service_con_changed_cb_hash = NULL;
+       }
+
+       __sync_synchronize();
+       if (h->ref_count > 0)
+               h->lazy_destroy = true;
+       else
+               g_hash_table_remove(weconn_handle_hash, conn);
+
+       __weconn_deregister_signal();
+
+       return 0;
+}
+
+EXPORT_API int weconn_get_service_state(weconn_h conn,
+                               weconn_service_type_e type, weconn_service_state_e *state)
+{
+       GVariant *reply, *inner;
+       GError *error = NULL;
+       struct weconn_connection *h = (struct weconn_connection *)conn;
+       const char *service_type = NULL;
+       const char *value = NULL;
+       weconn_service_state_e value_e;
+       const char *technology_path = NULL;
+
+       if (!state || !__weconn_check_handle_validity(conn))
+               return -EINVAL;
+
+       service_type = wc_service_type_enum2string(type);
+       if (!service_type) {
+
+               /* TODO: please make more general to care all of technologies */
+
+               if (type == W_SERVICE_TYPE_HOST_TO_WEARABLE_CONNECTIVITY)
+                       type = W_SERVICE_TYPE_BT_SPP;
+               else if (type == W_SERVICE_TYPE_INTERNET_CONNECTIVITY)
+                       type = W_SERVICE_TYPE_BT_PAN;
+               else
+                       return -EINVAL;
+
+               service_type = wc_service_type_enum2string(type);
+       }
+
+       technology_path = __weconn_get_technology_path4service(type);
+       if (!technology_path)
+               return -EINVAL;
+
+       reply = g_dbus_connection_call_sync(__weconn_call_ref(h),
+                       WECONN_SERVICE_DBUS,
+                       technology_path,
+                       WECONN_TECHNOLOGY_INTERFACE,
+                       "GetProperty",
+                       g_variant_new("(s)", service_type),
+                       NULL,
+                       G_DBUS_CALL_FLAGS_NONE,
+                       DBUS_REPLY_TIMEOUT,
+                       h->cancellable,
+                       &error);
+
+       __weconn_call_unref(h);
+
+       if (error) {
+               ERR("Failed to request (%s)", error->message);
+               g_error_free(error);
+
+               if (reply)
+                       g_variant_unref(reply);
+
+               return -EIO;
+       }
+
+       if (!reply) {
+               ERR("Failed to request");
+               return -EIO;
+       }
+
+       g_variant_get(reply, "(v)", &inner);
+       value = g_variant_get_string(inner, NULL);
+       g_variant_unref(inner);
+
+       value_e = wc_service_state_string2enum(value);
+       g_variant_unref(reply);
+
+       if (value_e)
+               *state = value_e;
+       else
+               return -EIO;
+
+       return 0;
+}
+
+EXPORT_API int weconn_get_device_state(weconn_h conn,
+                               weconn_device_type_e type, weconn_device_state_e *state)
+{
+       GVariant *reply, *inner;
+       GError *error = NULL;
+       struct weconn_connection *h = (struct weconn_connection *)conn;
+       const char *device_type = NULL;
+       const char *value = NULL;
+       weconn_device_state_e value_e;
+       const char *technology_path = NULL;
+
+       if (!state || !__weconn_check_handle_validity(conn))
+               return -EINVAL;
+
+       device_type = wc_device_type_enum2string(type);
+       if (!device_type)
+               return -EINVAL;
+
+       technology_path = __weconn_get_technology_path4device(type);
+       if (!technology_path)
+               return -EINVAL;
+
+       reply = g_dbus_connection_call_sync(__weconn_call_ref(h),
+                       WECONN_SERVICE_DBUS,
+                       technology_path,
+                       WECONN_TECHNOLOGY_INTERFACE,
+                       "GetProperty",
+                       g_variant_new("(s)", device_type),
+                       NULL,
+                       G_DBUS_CALL_FLAGS_NONE,
+                       DBUS_REPLY_TIMEOUT,
+                       h->cancellable,
+                       &error);
+
+       __weconn_call_unref(h);
+
+       if (error) {
+               ERR("Failed to request (%s)", error->message);
+               g_error_free(error);
+
+               if (reply)
+                       g_variant_unref(reply);
+
+               return -EIO;
+       }
+
+       if (!reply) {
+               ERR("Failed to request");
+               return -EIO;
+       }
+
+       g_variant_get(reply, "(v)", &inner);
+       value = g_variant_get_string(inner, NULL);
+       g_variant_unref(inner);
+
+       value_e = wc_device_state_string2enum(value);
+       g_variant_unref(reply);
+
+       if (value_e)
+               *state = value_e;
+       else
+               return -EIO;
+
+       return 0;
+}
+
+EXPORT_API int weconn_connect_service(weconn_h conn,
+                               weconn_service_type_e type, weconn_connected_cb callback,
+                               void *user_data)
+{
+       int err = -EIO;
+       GVariant *reply;
+       GError *error = NULL;
+       struct weconn_connection *h = (struct weconn_connection *)conn;
+       const char *service_type = NULL;
+       const char *technology_path = NULL;
+
+       if (!__weconn_check_handle_validity(conn))
+               return -EINVAL;
+
+       if (h->connected_callback) {
+               DBG("connection is inprogress");
+               return -EINPROGRESS;
+       }
+
+       service_type = wc_service_type_enum2string(type);
+       if (!service_type) {
+               /* TODO: please make more general to care all of technologies */
+
+               if (type == W_SERVICE_TYPE_HOST_TO_WEARABLE_CONNECTIVITY)
+                       type = W_SERVICE_TYPE_BT_SPP;
+               else if (type == W_SERVICE_TYPE_INTERNET_CONNECTIVITY)
+                       type = W_SERVICE_TYPE_BT_PAN;
+               else
+                       return -EINVAL;
+
+               service_type = wc_service_type_enum2string(type);
+       }
+
+       technology_path = __weconn_get_technology_path4service(type);
+       if (!technology_path)
+               return -EINVAL;
+
+       reply = g_dbus_connection_call_sync(__weconn_call_ref(h),
+                       WECONN_SERVICE_DBUS,
+                       technology_path,
+                       WECONN_TECHNOLOGY_INTERFACE,
+                       "Connect",
+                       g_variant_new("(s)", service_type),
+                       NULL,
+                       G_DBUS_CALL_FLAGS_NONE,
+                       DBUS_REPLY_TIMEOUT,
+                       h->cancellable,
+                       &error);
+
+       __weconn_call_unref(h);
+
+       if (error) {
+               ERR("Failed to request (%s)", error->message);
+               if (g_strrstr(error->message, "AlreadyConnected"))
+                       err = -EISCONN;
+               else if (g_strrstr(error->message, "NotConnected"))
+                       err = -ENOTCONN;
+               else if (g_strrstr(error->message, "InProgress"))
+                       err = -EINPROGRESS;
+               else if (g_strrstr(error->message, "LostConnection"))
+                       err = -EIO;
+
+               g_error_free(error);
+
+               if (reply)
+                       g_variant_unref(reply);
+
+               return err;
+       }
+
+       if (!reply) {
+               ERR("Failed to request");
+               return err;
+       }
+
+       g_variant_unref(reply);
+
+       if (callback) {
+               h->connect_service_type = type;
+               h->connected_callback = callback;
+               if (user_data)
+                       h->connect_user_data = user_data;
+       }
+
+       return 0;
+}
+
+EXPORT_API int weconn_disconnect_service(weconn_h conn,
+               weconn_service_type_e type, weconn_connected_cb callback,
+               void *user_data)
+{
+       int err = -EIO;
+       GVariant *reply;
+       GError *error = NULL;
+       struct weconn_connection *h = (struct weconn_connection *)conn;
+       const char *service_type = NULL;
+       const char *technology_path = NULL;
+
+       if (!__weconn_check_handle_validity(conn))
+               return -EINVAL;
+
+       if (h->disconnected_callback) {
+               DBG("disconnection is inprogress");
+               return -EINPROGRESS;
+       }
+
+       service_type = wc_service_type_enum2string(type);
+       if (!service_type) {
+
+               /* TODO: please make more general to care all of technologies */
+
+               if (type == W_SERVICE_TYPE_HOST_TO_WEARABLE_CONNECTIVITY)
+                       type = W_SERVICE_TYPE_BT_SPP;
+               else if (type == W_SERVICE_TYPE_INTERNET_CONNECTIVITY)
+                       type = W_SERVICE_TYPE_BT_PAN;
+               else
+                       return -EINVAL;
+
+               service_type = wc_service_type_enum2string(type);
+       }
+
+       technology_path = __weconn_get_technology_path4service(type);
+       if (!technology_path)
+               return -EINVAL;
+
+       reply = g_dbus_connection_call_sync(__weconn_call_ref(h),
+                       WECONN_SERVICE_DBUS,
+                       technology_path,
+                       WECONN_TECHNOLOGY_INTERFACE,
+                       "Disconnect",
+                       g_variant_new("(s)", service_type),
+                       NULL,
+                       G_DBUS_CALL_FLAGS_NONE,
+                       DBUS_REPLY_TIMEOUT,
+                       h->cancellable,
+                       &error);
+
+       __weconn_call_unref(h);
+
+       if (error) {
+               ERR("Failed to request (%s)", error->message);
+               if (g_strrstr(error->message, "AlreadyConnected"))
+                       err = -EISCONN;
+               else if (g_strrstr(error->message, "NotConnected"))
+                       err = -ENOTCONN;
+
+               g_error_free(error);
+
+               if (reply)
+                       g_variant_unref(reply);
+
+               return err;
+       }
+
+       if (!reply) {
+               ERR("Failed to request");
+               return err;
+       }
+
+       g_variant_unref(reply);
+
+       if (callback) {
+               h->disconnect_service_type = type;
+               h->disconnected_callback = callback;
+               if (user_data)
+                       h->disconnect_user_data = user_data;
+       }
+
+       return 0;
+}
+
+EXPORT_API int weconn_set_service_state_change_cb(weconn_h conn,
+               weconn_service_state_changed_cb callback,
+               weconn_service_type_e type, void *user_data)
+{
+       struct weconn_service_handle *h_service = NULL;
+
+       if (!__weconn_check_handle_validity(conn) || callback == NULL)
+               return -EINVAL;
+
+       h_service = g_try_malloc0(sizeof(struct weconn_service_handle));
+       if (h_service == NULL)
+               return -EINVAL;
+
+       h_service->conn = conn;
+       h_service->callback = callback;
+       h_service->user_data = user_data;
+
+       switch (type) {
+       case W_SERVICE_TYPE_HOST_TO_WEARABLE_CONNECTIVITY:
+               g_hash_table_replace(wc_wearable_service_con_changed_cb_hash,
+                               conn, h_service);
+               break;
+       case W_SERVICE_TYPE_INTERNET_CONNECTIVITY:
+               g_hash_table_replace(wc_internet_service_con_changed_cb_hash,
+                               conn, h_service);
+               break;
+       case W_SERVICE_TYPE_BT_PAN:
+       case W_SERVICE_TYPE_BT_HFP:
+       case W_SERVICE_TYPE_BT_SPP:
+       case W_SERVICE_TYPE_BT_GATT:
+       case W_SERVICE_TYPE_CELLULAR:
+       case W_SERVICE_TYPE_WIFI:
+       case W_SERVICE_TYPE_WIFI_P2P:
+       case W_SERVICE_TYPE_WIFI_ADHOC:
+       case W_SERVICE_TYPE_ETHERNET:
+       default:
+               ERR("Not support service type (%d)", type);
+               g_free(h_service);
+               break;
+       }
+
+       return 0;
+}
+
+EXPORT_API int weconn_unset_service_state_change_cb(weconn_h conn,
+               weconn_service_type_e type)
+{
+       if (!__weconn_check_handle_validity(conn))
+               return -EINVAL;
+
+       switch (type) {
+       case W_SERVICE_TYPE_HOST_TO_WEARABLE_CONNECTIVITY:
+               g_hash_table_remove(wc_wearable_service_con_changed_cb_hash,
+                               conn);
+               break;
+       case W_SERVICE_TYPE_INTERNET_CONNECTIVITY:
+               g_hash_table_remove(wc_internet_service_con_changed_cb_hash,
+                               conn);
+               break;
+       case W_SERVICE_TYPE_BT_PAN:
+       case W_SERVICE_TYPE_BT_HFP:
+       case W_SERVICE_TYPE_BT_SPP:
+       case W_SERVICE_TYPE_BT_GATT:
+       case W_SERVICE_TYPE_CELLULAR:
+       case W_SERVICE_TYPE_WIFI:
+       case W_SERVICE_TYPE_WIFI_P2P:
+       case W_SERVICE_TYPE_WIFI_ADHOC:
+       case W_SERVICE_TYPE_ETHERNET:
+       default:
+               break;
+       }
+
+       return 0;
+}
diff --git a/client/weconn.pc.in b/client/weconn.pc.in
new file mode 100644 (file)
index 0000000..b51db8a
--- /dev/null
@@ -0,0 +1,11 @@
+prefix=@PREFIX@
+exec_prefix=@PREFIX@
+libdir=@LIBDIR@
+includedir=@INCLUDEDIR@/weconn
+
+Name: weconn
+Description: Wearable device connection controller API library in TIZEN C API (Development)
+Requires: dlog glib-2.0 gobject-2.0
+Version: @VERSION@
+Libs: -L${libdir} -lweconn
+Cflags: -I${includedir}
diff --git a/include/conn.h b/include/conn.h
new file mode 100644 (file)
index 0000000..3765fa9
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Wearable device Connection Controller Framework
+ *
+ * Copyright (c) 2013 - 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __WECONN_H__
+#define __WECONN_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __WECONN_H__ */
diff --git a/include/control.h b/include/control.h
new file mode 100644 (file)
index 0000000..11e4d5c
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Wearable device Connection Controller Framework
+ *
+ * Copyright (c) 2013 - 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __WECONN_CONTROL_H__
+#define __WECONN_CONTROL_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "log.h"
+#include "events.h"
+#include "object.h"
+
+#define PROP_CONTROL_TYPE_HOST            0x00
+#define PROP_CONTROL_TYPE_WEARABLE 0x01
+
+int wc_control_add_bearer(WcObject * wo_bearer);
+WcObject *wc_control_get_object(void);
+int wc_control_get_device_type(void);
+
+int control_init(void);
+void control_cleanup(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __WECONN_CONTROL_H__ */
diff --git a/include/dbus.h b/include/dbus.h
new file mode 100644 (file)
index 0000000..ba7df57
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Wearable device Connection Controller Framework
+ *
+ * Copyright (c) 2013 - 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __WECONN_DBUS_H__
+#define __WECONN_DBUS_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <gio/gio.h>
+
+#include "conn.h"
+
+#define DBUS_REPLY_TIMEOUT (120 * 1000)
+
+#define WECONN_SERVICE_DBUS                    "net.weconn"
+#define WECONN_PATH_DBUS                       "/net/weconn"
+
+#define WECONN_SERVICE_INTERFACE       WECONN_SERVICE_DBUS ".Service"
+#define WECONN_TECHNOLOGY_INTERFACE    WECONN_SERVICE_DBUS ".Technology"
+
+#define WECONN_SERVICE_PATH                    WECONN_PATH_DBUS "/service"
+#define WECONN_TECHNOLOGY_PATH         WECONN_PATH_DBUS "/technology"
+#define WECONN_TECHNOLOGY_BLUETOOTH_PATH       WECONN_TECHNOLOGY_PATH "/bluetooth"
+#define WECONN_TECHNOLOGY_CELLULAR_PATH                WECONN_TECHNOLOGY_PATH "/cellular"
+#define WECONN_TECHNOLOGY_WIFI_PATH                    WECONN_TECHNOLOGY_PATH "/wifi"
+#define WECONN_TECHNOLOGY_WIFI_P2P_PATH                WECONN_TECHNOLOGY_PATH "/p2p"
+#define WECONN_TECHNOLOGY_WIFI_ADHOC_PATH      WECONN_TECHNOLOGY_PATH "/adhoc"
+#define WECONN_TECHNOLOGY_ETHERNET_PATH                WECONN_TECHNOLOGY_PATH "/ethernet"
+
+#define WECONN_TECHNOLOGY_SIGNAL_CONNECTION_RESULT     "SignalConnectionResult"
+#define WECONN_TECHNOLOGY_SIGNAL_DISCONNECTION_RESULT  "SignalDisconnectionResult"
+#define WECONN_TECHNOLOGY_SIGNAL_SERVICE_STATE_CHANGED "SignalServiceStateChanged"
+
+int dbus_init(GBusType bus_type, const char *bus_name, const char *obj_path,
+               void (*__init_cb)(void));
+void dbus_cleanup(void);
+
+GDBusConnection *dbus_get_connection(void);
+
+const char *dbus_name2path(const char *name);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __WECONN_DBUS_H__ */
diff --git a/include/driver.h b/include/driver.h
new file mode 100644 (file)
index 0000000..c0e5da9
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Wearable device Connection Controller Framework
+ *
+ * Copyright (c) 2013 - 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __WECONN_DRIVER_H__
+#define __WECONN_DRIVER_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "object.h"
+
+int wc_bearer_driver_init(WcObject *wo, const char *desc_name);
+int wc_bearer_driver_activate(WcObject *wo, const char *desc_name);
+int wc_bearer_driver_deactivate(WcObject *wo, const char *desc_name);
+int wc_bearer_driver_connect(WcObject *wo, const char *address,
+               const char *desc_name);
+int wc_bearer_driver_disconnect(WcObject *wo, const char *desc_name);
+void wc_bearer_driver_exit(WcObject *wo, const char *desc_name);
+
+int driver_init(const char *driver_path);
+void driver_cleanup(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __WECONN_DRIVER_H__ */
diff --git a/include/error.h b/include/error.h
new file mode 100644 (file)
index 0000000..09756b3
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Wearable device Connection Controller Framework
+ *
+ * Copyright (c) 2013 - 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __WECONN_ERROR_H__
+#define __WECONN_ERROR_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <gio/gio.h>
+
+void wc_error_add(const gchar *msg, ...);
+void wc_error_return(GDBusMethodInvocation *invocation);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __WECONN_ERROR_H__ */
diff --git a/include/events.h b/include/events.h
new file mode 100644 (file)
index 0000000..786c3fc
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * Wearable device Connection Controller Framework
+ *
+ * Copyright (c) 2013 - 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __WECONN_EVENTSH__
+#define __WECONN_EVENTSH__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Generic property changed */
+#define WC_OBJECT_EVENT_PROPERTY_CHANGED "PropertiesChanged"
+
+/* Bearer events */
+#define WC_BEARER_EVENT_BT_CONNECTED_SPP  "BtConnectedSpp"
+#define WC_BEARER_EVENT_BT_CONNECTED_GATT "BtConnectedGatt"
+#define WC_BEARER_EVENT_BT_CONNECTED_HFP  "BtConnectedHfp"
+#define WC_BEARER_EVENT_BT_CONNECTED_PAN  "BtConnectedPan"
+
+/* Technology events */
+
+/* Service events */
+
+/* Bearer (plug-in) events */
+#define WC_OBJECT_EVENT_BEARER_ENABLED         "BearerEnabled"
+#define WC_OBJECT_EVENT_BEARER_DISABLED                "BearerDisabled"
+
+/* eSAP events */
+/* For example, to send data uses WC_OBJECT_EVENT_SAP_SEND_DATA
+ *     wc_object_emit_callback(wo, WC_OBJECT_EVENT_SAP_SEND_DATA, data);
+ * to receive data uses
+ *     WC_OBJECT_EVENT_SAP_RECEIVE_DATA[main_cmd][sub_cmd][response_type]
+ *     wc_object_add_callback(wo,
+ *         WC_OBJECT_EVENT_SAP_RECEIVE_DATA[main_cmd][sub_cmd][response_type],
+ *         user_data);
+ */
+#define WC_OBJECT_EVENT_SAP_SEND_DATA          "eSAP-send"
+#define WC_OBJECT_EVENT_SAP_RECEIVE_DATA       "eSAP-receive"
+
+
+/* TODO: to plug-in developer,
+ *             develop each plug-in APIs and define each event for those APIs.
+ */
+#define WC_OBJECT_EVENT_SAP_BCMSERVICE_STATUS  "bcmservice_status"
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __WECONN_EVENTSH__ */
diff --git a/include/log.h b/include/log.h
new file mode 100644 (file)
index 0000000..04c2f7a
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Wearable device Connection Controller Framework
+ *
+ * Copyright (c) 2013 - 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __WECONN_LOG_H__
+#define __WECONN_LOG_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <dlog.h>
+
+#define ERR(fmt, args...) do { LOGE(fmt, ## args); } while(0)
+#define WARN(fmt, args...) do { LOGW(fmt, ## args); } while(0)
+#define DBG(fmt, args...) do { LOGI(fmt, ## args); } while(0)
+
+#define SECURE_ERR(fmt, args...) do { SECURE_LOGE(fmt, ## args); } while(0)
+#define SECURE_WARN(fmt, args...) do { SECURE_LOGW(fmt, ## args); } while(0)
+#define SECURE_DBG(fmt, args...) do { SECURE_LOGI(fmt, ## args); } while(0)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __WECONN_LOG_H__ */
diff --git a/include/object.h b/include/object.h
new file mode 100644 (file)
index 0000000..b90658d
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * Wearable device Connection Controller Framework
+ *
+ * Copyright (c) 2013 - 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __WECONN_OBJECT_H__
+#define __WECONN_OBJECT_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <gio/gio.h>
+
+#include "log.h"
+
+#define WC_OBJECT_TYPE_DEFAULT                 0xFF000000
+#define WC_OBJECT_TYPE_BEARER_DRIVER   (WC_OBJECT_TYPE_DEFAULT | 0x00010000)
+#define WC_OBJECT_TYPE_SERVICE                 (WC_OBJECT_TYPE_DEFAULT | 0x00020000)
+#define WC_OBJECT_TYPE_TECHNOLOGY              (WC_OBJECT_TYPE_DEFAULT | 0x00030000)
+#define WC_OBJECT_TYPE_CONTROL                 (WC_OBJECT_TYPE_DEFAULT | 0x00040000)
+
+#define WC_OBJECT_CHECK(o,t) \
+       if (!o) { WARN("WcObject is NULL"); return; } \
+       if (wc_object_get_type(o) != t) \
+               { WARN("type(0x%x != 0x%x) mismatch", wc_object_get_type(o), t); return; }
+#define WC_OBJECT_CHECK_RETURN(o,t,r) \
+       if (!o) { WARN("WcObject is NULL"); return r; } \
+       if (wc_object_get_type(o) != t) \
+               { WARN("type(0x%x != 0x%x) mismatch", wc_object_get_type(o), t); return r; }
+
+#define WC_OBJECT_KEY_FIND(keys, k) \
+       g_slist_find_custom((keys), (k), (GCompareFunc)g_strcmp0)
+
+typedef struct wc_object WcObject;
+typedef gboolean (*WcObjectCallback)(WcObject *wo, const void *event_info,
+                                               void *user_data);
+
+WcObject *wc_object_new(const char *name, unsigned int type);
+void wc_object_free(WcObject *wo);
+WcObject *wc_object_find(const char *name);
+
+const char *wc_object_get_name(WcObject *wo);
+const char *wc_object_peek_name(WcObject *wo);
+unsigned int wc_object_get_type(WcObject *wo);
+
+int wc_object_append_element(WcObject *wo,
+               const char *element_name, void *element);
+void *wc_object_get_element(WcObject *wo, const char *element_name);
+
+typedef void (*wc_object_foreach_get_elements_cb)(WcObject *wo,
+               const char *element_name, void *element, void *user_data);
+int wc_object_foreach_get_elements(WcObject *wo,
+               wc_object_foreach_get_elements_cb callback, void *user_data);
+
+int wc_object_set_dbus_interface(WcObject *wo, GDBusInterfaceSkeleton *di);
+GDBusInterfaceSkeleton *wc_object_get_dbus_interface(WcObject *wo);
+
+int wc_object_export(WcObject *wo, const char *path);
+int wc_object_unexport(WcObject *wo);
+
+int wc_object_add_callback(WcObject *wo, const char *event,
+                               WcObjectCallback callback, void *user_data);
+int wc_object_del_callback(WcObject *wo, const char *event,
+                               WcObjectCallback callback);
+int wc_object_emit_callback(WcObject *wo, const char *event,
+                               const void *event_info);
+
+#define wc_object_set_property(co, ...) \
+       wc_object_set_property_full(co, __VA_ARGS__, NULL, NULL)
+
+int wc_object_set_property_full(WcObject *wo, const char *first_property, ...);
+char *wc_object_get_property(WcObject *wo, const char *key);
+
+const char *wc_object_peek_property(WcObject *wo, const char *key);
+GHashTable *wc_object_peek_property_hash(WcObject *wo);
+
+void wc_object_set_timeout_connecting(WcObject *wo,
+               guint timeout, const char *service);
+guint wc_object_get_timeout_connecting(WcObject *wo);
+char *wc_object_get_connecting_service(WcObject *wo);
+void wc_object_set_timeout_disconnecting(WcObject *wo,
+               guint timeout, const char *service);
+guint wc_object_get_timeout_disconnecting(WcObject *wo);
+char *wc_object_get_disconnecting_service(WcObject *wo);
+#endif /* __WECONN_OBJECT_H__ */
diff --git a/include/service.h b/include/service.h
new file mode 100644 (file)
index 0000000..fc8865e
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Wearable device Connection Controller Framework
+ *
+ * Copyright (c) 2013 - 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __WECONN_SERVICE_H__
+#define __WECONN_SERVICE_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int service_init(void);
+void service_cleanup(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __WECONN_SERVICE_H__ */
diff --git a/include/technology.h b/include/technology.h
new file mode 100644 (file)
index 0000000..f07cad2
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Wearable device Connection Controller Framework
+ *
+ * Copyright (c) 2013 - 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __WECONN_TECHNOLOGY_H__
+#define __WECONN_TECHNOLOGY_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define WC_TECHNOLOGY_BLUETOOTH                "bluetooth"
+#define WC_TECHNOLOGY_CELLULAR         "cellular"
+#define WC_TECHNOLOGY_WIFI                     "Wi-Fi"
+#define WC_TECHNOLOGY_ETHERNET         "ethernet"
+
+
+#define CONNMAN_SERVICE        "net.connman"
+#define CONNMAN_SERVICE_INTERFACE      CONNMAN_SERVICE ".Service"
+#define CONNMAN_SIGNAL_PROPERTY_CHANGED        "PropertyChanged"
+
+/**
+ * @brief  Enumerations of wearable connection service state.
+ */
+typedef enum
+{
+       WC_SERVICE_STATE_IDLE                   = 0x00,
+       WC_SERVICE_STATE_FAILURE                = 0x01,
+       WC_SERVICE_STATE_DISCONNECTED   = 0x02,
+       WC_SERVICE_STATE_ASSOCIATION    = 0x03,
+       WC_SERVICE_STATE_CONFIGURATION  = 0x04,
+       WC_SERVICE_STATE_READY                  = 0x05,
+       WC_SERVICE_STATE_ONLINE                 = 0x06,
+} wc_technology_service_state_e;
+
+
+int wc_technology_add_bearer(WcObject *wo);
+WcObject *wc_technology_get_bearer(const char *technology);
+
+int technology_init(void);
+void technology_cleanup(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __WECONN_TECHNOLOGY_H__ */
diff --git a/include/util.h b/include/util.h
new file mode 100644 (file)
index 0000000..f3ff540
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Wearable device Connection Controller Framework
+ *
+ * Copyright (c) 2013 - 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __WECONN_UTIL_H__
+#define __WECONN_UTIL_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <app_service.h>
+#include "weconn_type.h"
+
+#define XSTR(X)                #X
+
+/**
+ * @brief  Enumerations of wearable connection popup type.
+ */
+typedef enum
+{
+       WC_POPUP_TYPE_PAN_CONNECT               = 0x01,
+       WC_POPUP_TYPE_PAN_DISCONNECT    = 0x02,
+} weconn_popup_type_e;
+
+weconn_service_type_e wc_service_type_string2enum(const char *service_type);
+const char *wc_service_type_enum2string(weconn_service_type_e service_type);
+weconn_service_state_e wc_service_state_string2enum(const char *service_state);
+const char *wc_service_state_enum2string(weconn_service_state_e service_state);
+weconn_device_type_e wc_device_type_string2enum(const char *device_type);
+const char *wc_device_type_enum2string(weconn_device_type_e device_type);
+weconn_device_state_e wc_device_state_string2enum(const char *device_state);
+const char *wc_device_state_enum2string(weconn_device_state_e device_state);
+weconn_device_type_e wc_device_get_type_from_path(const char *path);
+int wc_launch_popup(weconn_popup_type_e type, service_reply_cb callback,
+               void *user_data);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __WECONN_UTIL_H__ */
diff --git a/introspection/service.xml b/introspection/service.xml
new file mode 100644 (file)
index 0000000..d6774b8
--- /dev/null
@@ -0,0 +1,8 @@
+<node>
+       <interface name="net.weconn.Service">
+               <signal name="PropertyChanged">
+                       <arg name="name" type="s"/>
+                       <arg name="value" type="v"/>
+               </signal>
+       </interface>
+</node>
diff --git a/introspection/technology.xml b/introspection/technology.xml
new file mode 100644 (file)
index 0000000..7b18481
--- /dev/null
@@ -0,0 +1,27 @@
+<node>
+       <interface name="net.weconn.Technology">
+               <method name="GetProperties">
+                       <arg name="properties" type="a{sv}" direction="out"/>
+               </method>
+               <method name="GetProperty">
+                       <arg name="name" type="s" direction="in"/>
+                       <arg name="value" type="v" direction="out"/>
+               </method>
+               <method name="SetProperty">
+                       <arg name="name" type="s" direction="in"/>
+                       <arg name="value" type="v" direction="in"/>
+               </method>
+               <method name="Scan">
+               </method>
+                <method name="Connect">
+                       <arg name="service" type="s" direction="in"/>
+                </method>
+                <method name="Disconnect">
+                       <arg name="service" type="s" direction="in"/>
+                </method>
+               <signal name="PropertyChanged">
+                       <arg name="name" type="s"/>
+                       <arg name="value" type="v"/>
+               </signal>
+       </interface>
+</node>
diff --git a/packaging/weconn.spec b/packaging/weconn.spec
new file mode 100644 (file)
index 0000000..676989a
--- /dev/null
@@ -0,0 +1,110 @@
+Name:          weconn
+Summary:       WEarable device CONNection controller framework (We connect all)
+Version:       0.1.56
+Release:       1
+Group:         System/Network
+License:       Apache-2.0
+Source0:       %{name}-%{version}.tar.gz
+BuildRequires: cmake
+BuildRequires: python-xml
+BuildRequires: pkgconfig(dlog)
+BuildRequires: pkgconfig(vconf)
+BuildRequires: pkgconfig(gio-2.0)
+BuildRequires: pkgconfig(glib-2.0)
+BuildRequires: pkgconfig(capi-base-common)
+BuildRequires: pkgconfig(sap-client-stub-api)
+BuildRequires: pkgconfig(capi-appfw-application)
+BuildRequires: pkgconfig(capi-network-bluetooth)
+BuildRequires: pkgconfig(capi-system-info)
+BuildRequires: pkgconfig(alarm-service)
+Requires(post):                /sbin/ldconfig
+Requires(post):                /usr/bin/vconftool
+Requires(postun):      /sbin/ldconfig
+Requires:              /usr/bin/vconftool
+
+%description
+Wearable device requires an automatic controller to manage various connection bearers
+without UI based control panel. Wearable connection controller provides client and
+daemon for managing various connection bearers within wearable devices running the
+Linux operating system.
+
+%package devel
+Summary:       WEarable device CONNection controller API library (devel)
+Group:         System/Network
+License:       Apache
+Requires:      %{name} = %{version}-%{release}
+
+%description devel
+Wearable device connection controller API library in TIZEN C API (Development)
+
+%prep
+%setup -q
+
+
+%build
+cmake . -DCMAKE_INSTALL_PREFIX=%{_prefix} -DVERSION=%{version}
+make %{?_smp_mflags}
+
+
+%install
+%make_install
+
+#Systemd service file
+mkdir -p %{buildroot}%{_libdir}/systemd/system/
+cp resources/usr/lib/systemd/system/weconn.service %{buildroot}%{_libdir}/systemd/system/weconn.service
+mkdir -p %{buildroot}%{_libdir}/systemd/system/multi-user.target.wants/
+ln -s ../weconn.service %{buildroot}%{_libdir}/systemd/system/multi-user.target.wants/weconn.service
+
+mkdir -p %{buildroot}%{_datadir}/dbus-1/services/
+cp resources/usr/share/dbus-1/services/net.weconn.service %{buildroot}%{_datadir}/dbus-1/services/net.weconn.service
+
+#DBus DAC (manifest enables DBus SMACK)
+mkdir -p %{buildroot}%{_sysconfdir}/dbus-1/system.d/
+cp resources/etc/dbus-1/system.d/weconn.conf %{buildroot}%{_sysconfdir}/dbus-1/system.d/
+
+#appcessory
+mkdir -p %{buildroot}%{_datadir}/appcessory/
+cp resources/usr/share/appcessory/wearable-connection.xml %{buildroot}%{_datadir}/appcessory/
+
+#FOTA patch
+mkdir -p %{buildroot}%{_sysconfdir}/opt/upgrade/
+cp resources/etc/opt/upgrade/500.net.weconn.patch.sh %{buildroot}%{_sysconfdir}/opt/upgrade/
+
+#License
+mkdir -p %{buildroot}%{_datadir}/license
+cp LICENSE %{buildroot}%{_datadir}/license/weconn
+
+%post
+
+#Systemd enhanced BT power on
+mkdir -p %{_sysconfdir}/systemd/default-extra-dependencies/ignore-units.d/
+ln -s %{_libdir}/systemd/system/weconn.service %{_sysconfdir}/systemd/default-extra-dependencies/ignore-units.d/
+
+vconftool set -t int file/private/weconn/connected_bt_version 0 -s system::vconf_network
+vconftool set -t int file/private/weconn/disconnected_manually 0 -s system::vconf_network
+vconftool set -t string file/private/weconn/connected_manufacturer "" -s system::vconf_network
+vconftool set -t string file/private/weconn/autoconnectable_unique_bt_target_address "" -s system::vconf_network
+vconftool set -t int file/private/weconn/last_bt_status 0 -s system::vconf_network
+vconftool set -tf int memory/private/weconn/all_connected 0 -s system::vconf_network -i
+
+%postun -p /sbin/ldconfig
+
+
+%files
+%manifest weconn.manifest
+%attr(644,-,-) %{_libdir}/*.so.*
+%attr(500,root,root) %{_sbindir}/*
+%attr(400,root,root) %{_libdir}/weconn/*.so
+%attr(644,root,root) %{_datadir}/dbus-1/services/*
+#DBus DAC
+%attr(644,root,root) %{_sysconfdir}/dbus-1/system.d/*
+%attr(644,root,root) %{_libdir}/systemd/system/weconn.service
+%attr(644,root,root) %{_libdir}/systemd/system/multi-user.target.wants/weconn.service
+%attr(700,root,root) %{_sysconfdir}/opt/upgrade/500.net.weconn.patch.sh
+%{_datadir}/license/weconn
+%{_datadir}/appcessory/wearable-connection.xml
+
+%files devel
+%{_libdir}/libweconn.so
+%{_includedir}/weconn
+%{_libdir}/pkgconfig/weconn.pc
diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..0061e36
--- /dev/null
@@ -0,0 +1,16 @@
+REMOVE_DEFINITIONS("-DLOG_TAG=\"CAPI_NETWORK_WECONN\"")
+ADD_DEFINITIONS("-DLOG_TAG=\"WECONN\"")
+
+
+SET(PLUGINS
+       pan
+       esap
+       bluetooth
+)
+
+FOREACH(plugin ${PLUGINS})
+       ADD_LIBRARY(${plugin} SHARED ${plugin}.c ../src/util.c)
+       TARGET_LINK_LIBRARIES(${plugin} ${pkgs_LDFLAGS} "-L${CMAKE_BINARY_DIR}")
+       SET_TARGET_PROPERTIES(${plugin} PROPERTIES PREFIX "" OUTPUT_NAME ${plugin})
+       INSTALL(TARGETS ${plugin} LIBRARY DESTINATION ${WECONNLIB})
+ENDFOREACH(plugin)
diff --git a/plugins/bluetooth.c b/plugins/bluetooth.c
new file mode 100644 (file)
index 0000000..6d7f5fa
--- /dev/null
@@ -0,0 +1,1468 @@
+/*
+ * Wearable device Connection Controller Framework
+ *
+ * Copyright (c) 2013 - 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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 <alarm.h>
+#include <vconf.h>
+#include <bluetooth.h>
+#include <vconf-keys.h>
+
+#include "esap.h"
+#include "plugin.h"
+
+#define BT_ADVERTISING_INTERVAL_FAST           150.0f //msec
+#define BT_ADVERTISING_INTERVAL_NORMAL         500.0f //msec
+#define FAST_ADVERTISING_TIMEOUT                       30 //sec
+
+#define BT_ADV_MANUFACTURER_COMPANY                    0x75
+#define BT_ADV_MANUFACTURER_SERVICE_ID         0x02
+#define BT_ADV_MANUFACTURER_VERSION                    0x01
+#define BT_ADV_MANUFACTURER_PKG_NAME           "watchmanager"
+
+#define VCONFKEY_WECONN_LAST_BT_STATUS \
+                               "file/private/weconn/last_bt_status"
+
+static int sap_rfcomm_ready = 0;
+static int sap_connected = 0;
+static bool hf_connected = false;
+
+static gboolean mBTRecoveryState = FALSE;
+
+static alarm_id_t fast_advertising_timer_id = 0;
+
+static void __bt_start_advertising(bool fast);
+static void __bt_page_scan(bool on);
+
+static bool __bt_check_bonded_device_cb(bt_device_info_s *device_info,
+               void *user_data)
+{
+       if (device_info && device_info->bt_class.major_device_class
+                                                       == BT_MAJOR_DEVICE_CLASS_AUDIO_VIDEO) {
+               int ret;
+               bool is_a2dp_connected = false;
+
+               DBG("Major class[0x%x]", device_info->bt_class.major_device_class);
+
+               ret = bt_device_is_profile_connected(device_info->remote_address,
+                                               BT_PROFILE_A2DP, &is_a2dp_connected);
+
+               DBG("ret[%d], is_a2dp_connected [%d]", ret, is_a2dp_connected);
+
+               if (ret == BT_ERROR_NONE && is_a2dp_connected == false)
+                       __bt_page_scan(true);
+       }
+
+       return true;
+}
+
+static void __bt_notify_all_connected(int connected)
+{
+       int all_connected = 0;
+
+       if (vconf_get_int(VCONFKEY_WECONN_ALL_CONNECTED, &all_connected) < 0) {
+               ERR("Failed to get all connected status");
+       } else {
+               if (all_connected == connected) {
+                       ERR("Not changed all connected state");
+                       return;
+               }
+       }
+
+       if (connected == 0)
+               vconf_set_int(VCONFKEY_WECONN_ALL_CONNECTED, 0);
+       else
+               vconf_set_int(VCONFKEY_WECONN_ALL_CONNECTED, 1);
+
+       DBG("All connected");
+}
+
+static void __bt_page_scan(bool on)
+{
+       int err;
+       bool prev_status = false;
+
+       err = bt_adapter_get_connectable(&prev_status);
+       if (err != BT_ERROR_NONE) {
+               ERR("Failed to get bt_adapter_get_connectable(%d)", err);
+               return;
+       }
+
+       if (prev_status == false && on == true) {
+               err = bt_adapter_set_connectable(true);
+               if (err != BT_ERROR_NONE)
+                       ERR("Failed to start page scan(%d)", err);
+               else
+                       DBG("Page scan started");
+       } else if (prev_status == true && on == false) {
+               err = bt_adapter_set_connectable(false);
+               if (err != BT_ERROR_NONE)
+                       ERR("Failed to stop page scan(%d)", err);
+               else
+                       DBG("Page scan stopped");
+
+               /* check bonded device and enable page scan if AV headset is paired*/
+               if (bt_adapter_foreach_bonded_device(__bt_check_bonded_device_cb,
+                                                                                               NULL) != BT_ERROR_NONE)
+                       ERR("Failed to check bonded devices");
+       } else {
+               DBG("Skip setting: old(%d), new(%d)", prev_status, on);
+       }
+}
+
+static int __get_setup_wizard_state(void)
+{
+       int ret = 0, state = 0;
+
+       ret = vconf_get_bool(VCONFKEY_SETUP_WIZARD_FIRST_BOOT, &state);
+       if (ret < 0) {
+               ERR("Failed to get state(%d)", ret);
+               return -EIO;
+       }
+
+       DBG("Setup wizard running state(%d)", state);
+
+       return state;
+}
+
+static void __bt_set_advertising_manufacturer_data(int setup_wizard_state)
+{
+       int err = 0;
+       static char prev_data[24] = {0, };
+       char data[24] = {0, };
+       int len = 0;
+
+       /* Complete manufacturer data */
+       // Company
+       data[0] = 0x00;
+       data[1] = BT_ADV_MANUFACTURER_COMPANY;
+
+       // TODO: Read value from somewhere
+       // Version
+       data[2] = BT_ADV_MANUFACTURER_VERSION;
+
+       // Service ID
+       data[3] = 0x00;
+       data[4] = BT_ADV_MANUFACTURER_SERVICE_ID;
+
+       // TODO : Read value from somewhere
+       // Device ID (b2 : 0x01, wingtip : 0x02)
+       data[5] = 0x00;
+       data[6] = 0x01;
+
+       if (setup_wizard_state == 1) {
+               // Purpose (setup : 0x01, auto connection : 0x02)
+               data[7] = 0x01;
+
+               /* Data for Quick Connect */
+               // Length of package name
+               data[8] = 0x0c;
+
+               // Package name for auto installation
+               memcpy(&data[9], BT_ADV_MANUFACTURER_PKG_NAME,
+                                       sizeof(BT_ADV_MANUFACTURER_PKG_NAME));
+               len = 9 + strlen(BT_ADV_MANUFACTURER_PKG_NAME);
+
+               // BT rssi calibrating constant
+               data[len] = 0x00;
+               len++;
+       } else {/* setup wizard is not running */
+               data[7] = 0x02;
+               len = 8;
+       }
+
+       DBG("len(%d)", len);
+       memcpy(prev_data, data, sizeof(data));
+
+       err = bt_adapter_set_advertising_manufacturer_data(data, len);
+       if (err != BT_ERROR_NONE)
+               ERR("Failed to set manufacturer data(%d)", err);
+}
+
+static 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;
+               DBG("LE is connected");
+               return false;
+       }
+
+       return true;
+}
+
+static bool __device_check_hfp_cb(bt_profile_e profile, void *user_data)
+{
+       bool *is_connected = (bool *)user_data;
+
+       if (profile == BT_PROFILE_AG) {
+               *is_connected = true;
+               DBG("HFP is connected");
+               return false;
+       }
+
+       return true;
+}
+
+static bool __bt_check_connection_status(const char *addr,
+               bt_device_connected_profile func)
+{
+       int ret;
+       bool is_connected = false;
+
+       if (!addr || !func || addr[0] == '\0')
+               return false;
+
+       SECURE_DBG("Addr[%s]", addr);
+       ret = bt_device_foreach_connected_profiles(addr, func, &is_connected);
+       if (ret != BT_ERROR_NONE) {
+               ERR("Failed to bt_device_foreach_connected_profiles(0x%08x)", ret);
+               return false;
+       }
+
+       return is_connected;
+}
+
+static int __fast_advertising_timeout_cb(alarm_id_t alarm_id, void * data)
+{
+       DBG("fast advertising timer expired!!");
+
+       if (fast_advertising_timer_id > 0) {
+               alarmmgr_remove_alarm(fast_advertising_timer_id);
+               fast_advertising_timer_id = 0;
+       }
+
+       if (sap_connected != SAP_CONNECTED && hf_connected != true)
+               __bt_start_advertising(false);
+
+       return 0;
+}
+
+static void __fast_advertising_timer_stop(void)
+{
+       if (fast_advertising_timer_id <= 0)
+               return;
+
+       DBG("Alarm unregistered(%d)", fast_advertising_timer_id);
+       alarmmgr_remove_alarm(fast_advertising_timer_id);
+       fast_advertising_timer_id = 0;
+}
+
+static void __fast_advertising_timer_start(void)
+{
+       int result = 0;
+
+       __fast_advertising_timer_stop();
+
+       result = alarmmgr_set_cb(__fast_advertising_timeout_cb, NULL);
+       if (result != ALARMMGR_RESULT_SUCCESS) {
+               ERR("Failed to set timer(%d)", result);
+               return;
+       }
+
+       result = alarmmgr_add_alarm(ALARM_TYPE_VOLATILE, FAST_ADVERTISING_TIMEOUT,
+                       0, NULL, &fast_advertising_timer_id);
+       if (result != ALARMMGR_RESULT_SUCCESS) {
+               ERR("Failed to add alarm(%d)", result);
+               return;
+       }
+
+       DBG("Alarm registered(%d)", fast_advertising_timer_id);
+}
+
+static void __bt_update_white_list(const char *bt_target_address,
+               int setup_wizard_state)
+{
+       int ret = 0;
+       bool is_advertising = false;
+
+       ret = bt_adapter_is_advertising(&is_advertising);
+       if (ret == BT_ERROR_NONE && is_advertising == true)
+               bt_adapter_stop_advertising();
+
+       /* should remove the previous connected addresses */
+       DBG("Clear white list");
+       ret = bt_adapter_clear_white_list();
+       if (ret != BT_ERROR_NONE)
+               ERR("Failed to clear white list(%d)", ret);
+
+       if (!bt_target_address) {
+               DBG("target address is NULL");
+               return;
+       }
+
+       if (strlen(bt_target_address) < 17) {
+               /* BT address formatted [xx:xx:xx:xx:xx:xx] */
+               DBG("Invalid mac address");
+               return;
+       }
+
+       if (setup_wizard_state == 1) {
+               DBG("Setup Wizard is running");
+               return;
+       }
+
+       WARN("Adding white list[%c%c:%c%c:%c%c]",
+                       bt_target_address[0], bt_target_address[1],
+                       bt_target_address[3], bt_target_address[4],
+                       bt_target_address[15], bt_target_address[16]);
+       SECURE_DBG("white list[%s]", bt_target_address);
+       ret = bt_adapter_add_white_list(bt_target_address);
+       if (ret != BT_ERROR_NONE)
+               ERR("Failed to add white list(%d)", ret);
+}
+
+static void __bt_start_advertising(bool fast)
+{
+       int ret = 0;
+       bool is_advertising = false;
+       bt_adapter_advertising_params_s adv_params = { 0, };
+       bt_adapter_state_e device_status;
+       int setup_wizard_state = 0;
+       int disconnected_manually = 0;
+       const char *autoconnectable_bt_address = NULL;
+
+       bt_adapter_get_state(&device_status);
+       if (device_status != BT_ADAPTER_ENABLED) {
+               ERR("BT disabled");
+               return;
+       }
+
+       if (sap_connected == SAP_CONNECTED || hf_connected == true) {
+               ERR("SPP(%d) HFP(%d)", sap_connected, hf_connected);
+               return;
+       }
+
+       /* page scan should be on, even if LE does not advertised */
+       __bt_page_scan(true);
+
+       vconf_get_int(VCONFKEY_WECONN_DISCONNECTED_MANUALLY, &disconnected_manually);
+       if (disconnected_manually) {
+               DBG("Disconnected manually(%d)", disconnected_manually);
+               return;
+       }
+
+       /* Important: BT auto-connectable address should be set by WMS,
+        *                      when EULA acceptance has been made by an user.
+        */
+       autoconnectable_bt_address =
+                       vconf_get_str(VCONFKEY_WECONN_AUTOCONNECTABLE_BT_ADDRESS);
+       if (autoconnectable_bt_address && strlen(autoconnectable_bt_address) > 0 &&
+                       __bt_check_connection_status(autoconnectable_bt_address,
+                                                                                       __device_check_gatt_cb) == true) {
+               return;
+       }
+
+       DBG("fast(%d)", fast);
+       if (fast) {
+               __fast_advertising_timer_start();
+
+               adv_params.interval_max = BT_ADVERTISING_INTERVAL_FAST;
+               adv_params.interval_min = BT_ADVERTISING_INTERVAL_FAST;
+       } else {
+               adv_params.interval_max = BT_ADVERTISING_INTERVAL_NORMAL;
+               adv_params.interval_min = BT_ADVERTISING_INTERVAL_NORMAL;
+       }
+
+       setup_wizard_state = __get_setup_wizard_state();
+
+       __bt_update_white_list(autoconnectable_bt_address, setup_wizard_state);
+
+       if (setup_wizard_state == 1) {
+               adv_params.filter_policy = BT_ADAPTER_ADVERTISING_FILTER_ALLOW_CONN_WL;
+               adv_params.interval_max = BT_ADVERTISING_INTERVAL_FAST;
+               adv_params.interval_min = BT_ADVERTISING_INTERVAL_FAST;
+       } else {
+               if (autoconnectable_bt_address &&
+                                               strlen(autoconnectable_bt_address) > 0) {
+                       adv_params.filter_policy =
+                                                       BT_ADAPTER_ADVERTISING_FILTER_ALLOW_SCAN_CONN_WL;
+               } else {
+                       WARN("Start advertising without white list");
+                       adv_params.filter_policy = BT_ADAPTER_ADVERTISING_FILTER_DEFAULT;
+               }
+       }
+
+       g_free((gpointer)autoconnectable_bt_address);
+
+       ret = bt_adapter_is_advertising(&is_advertising);
+       if (ret == BT_ERROR_NONE && is_advertising == true)
+               bt_adapter_stop_advertising();
+
+       __bt_set_advertising_manufacturer_data(setup_wizard_state);
+
+       ret = bt_adapter_start_advertising(&adv_params);
+       if (ret == BT_ERROR_NONE) {
+               DBG("LE Advertising is started(%.2fms)", adv_params.interval_max);
+               return;
+       }
+
+       ERR("Failed to start advertising(%d)", ret);
+}
+
+static void __bt_stop_advertising(void)
+{
+       int ret = 0;
+       bool is_advertising = FALSE;
+
+       /* Either HFP or SPP connected, stop advertising and disable page scan */
+       if (fast_advertising_timer_id > 0) {
+               alarmmgr_remove_alarm(fast_advertising_timer_id);
+               fast_advertising_timer_id = 0;
+       }
+
+       ret = bt_adapter_is_advertising(&is_advertising);
+       if (ret == BT_ERROR_NONE && is_advertising == false)
+               goto page_scan_off;
+
+       ret = bt_adapter_stop_advertising();
+       if (ret == BT_ERROR_NONE)
+               DBG("LE Advertising is stopped");
+       else
+               ERR("Fail to stop advertising(%d)", ret);
+
+page_scan_off:
+       if(__get_setup_wizard_state() != 1)
+               __bt_page_scan(false);
+}
+
+static void __bt_set_visibility(bt_adapter_visibility_mode_e mode)
+{
+       int ret = 0;
+       bt_adapter_visibility_mode_e visibility = 0;
+       int setup_wizard_state = __get_setup_wizard_state();
+
+       if (setup_wizard_state == 1) {
+               ERR("Setup wizard is running and no need to set visibility");
+               return;
+       }
+
+       ret = bt_adapter_get_visibility(&visibility, NULL);
+       if (ret != BT_ERROR_NONE) {
+               ERR("Failed to get bt_adapter_get_visibility(%d)", ret);
+               return;
+       }
+
+       DBG("Visibility(%d), mode(%d)", visibility, mode);
+       if (visibility != mode) {
+               bt_adapter_set_visibility(mode, 0);
+               if (ret != BT_ERROR_NONE)
+                       ERR("Failed to set bt_adapter_set_visibility(%d)", ret);
+       }
+}
+
+static void __setup_wizard_state_cb(keynode_t *node, void *user_data)
+{
+       int err = 0, state = 0;
+       WcObject * wo = (WcObject*)user_data;
+
+       if (!wo)
+               return;
+
+       if (node)
+               state = vconf_keynode_get_bool(node);
+       else
+               err = vconf_get_bool(VCONFKEY_SETUP_WIZARD_FIRST_BOOT, &state);
+       if (err < 0) {
+               ERR("Failed to get setup wizard state");
+               return;
+       }
+
+       DBG("setup wizard state: %d", state);
+       if (state == 0)
+               __bt_page_scan(false);
+}
+
+static void __power_saving_mode_cb(keynode_t *node, void *user_data)
+{
+       int ret = 0;
+       int ps_mode = 0;
+       bt_adapter_state_e last_bt_status = BT_ADAPTER_DISABLED;
+       WcObject * wo = (WcObject*)user_data;
+
+       if (!wo)
+               return;
+
+       if (node)
+               ps_mode = vconf_keynode_get_int(node);
+       else {
+               ret = vconf_get_int(VCONFKEY_SETAPPL_PSMODE, &ps_mode);
+               if (ret < 0) {
+                       ERR("Failed to get power saving mode");
+                       return;
+               }
+       }
+
+       if (ps_mode == SETTING_PSMODE_WEARABLE) {
+               ret = bt_adapter_get_state(&last_bt_status);
+               if (ret != BT_ERROR_NONE) {
+                       ERR("Failed to get bluetooth status (%d)", ret);
+                       return;
+               }
+
+               DBG("bluetooth status : %d", last_bt_status);
+               if (last_bt_status != BT_ADAPTER_ENABLED)
+                       return;
+
+               vconf_set_int(VCONFKEY_WECONN_LAST_BT_STATUS, last_bt_status);
+
+               ret = bt_adapter_disable();
+               if (ret != BT_ERROR_NONE)
+                       ERR("Failed to disable bluetooth (%d)", ret);
+       } else if (ps_mode == SETTING_PSMODE_NORMAL) {
+               vconf_get_int(VCONFKEY_WECONN_LAST_BT_STATUS, (int*)&last_bt_status);
+               if (last_bt_status == BT_ADAPTER_ENABLED) {
+                       ret = bt_adapter_enable();
+                       if (ret != BT_ERROR_NONE)
+                               ERR("Failed to enable bluetooth (%d)", ret);
+               } else
+                       DBG("bluetooth was not enabled");
+       } else
+               DBG("Invalid value : %d", ps_mode);
+}
+
+static void __rfcomm_ready_status_changed_cb(keynode_t *node, void *user_data)
+{
+       int err = 0, rfcomm_ready = 0;
+       WcObject * wo = (WcObject*)user_data;
+
+       if (!wo)
+               return;
+
+       if (node)
+               rfcomm_ready = vconf_keynode_get_int(node);
+       else
+               err = vconf_get_int(VCONFKEY_RFCOMM_READY_STATUS, &rfcomm_ready);
+
+       if (err < 0) {
+               ERR("Failed to get rfcomm ready status");
+               return;
+       }
+
+       sap_rfcomm_ready = rfcomm_ready;
+       DBG("rfcomm_ready(%d), SPP(%d), HFP(%d)",
+                       rfcomm_ready, sap_connected, hf_connected);
+
+       if (rfcomm_ready == 1) {
+               if (sap_connected != SAP_CONNECTED && hf_connected != true)
+                       __bt_start_advertising(true);
+       } else
+                       __bt_stop_advertising();
+}
+
+static void __pm_key_ignore_cb(keynode_t *node, void *user_data)
+{
+       int ret = 0;    
+       int mode = 0;
+       bt_adapter_state_e bt_status = BT_ADAPTER_DISABLED;
+       static bt_adapter_state_e prev_bt_status = BT_ADAPTER_DISABLED;
+
+       if (node)
+               mode = vconf_keynode_get_int(node);
+       else
+               ret = vconf_get_int(VCONFKEY_PM_KEY_IGNORE, &mode);
+
+       DBG("current pm mode : %s mode", mode ? "clock" : "normal");
+
+       ret = bt_adapter_get_state(&bt_status);
+       if (ret != BT_ERROR_NONE) {
+               ERR("Failed to get bluetooth status (%d)", ret);
+               return;
+       }
+       DBG("bluetooth status : %d", bt_status);
+
+       if (mode == 1) {
+               if (bt_status != BT_ADAPTER_ENABLED)
+                       return;
+
+               ret = bt_adapter_disable();
+               if (ret != BT_ERROR_NONE)
+                       ERR("Failed to disable bluetooth (%d)", ret);
+       } else {
+               if (bt_status != BT_ADAPTER_DISABLED)
+                       return;
+               else if (prev_bt_status == BT_ADAPTER_ENABLED) {
+                       ret = bt_adapter_enable();
+                       if (ret != BT_ERROR_NONE)
+                               ERR("Failed to enable bluetooth (%d)", ret);
+               }
+       }
+
+       prev_bt_status = bt_status;
+}
+
+static void __bt_fatal_recovery(void)
+{
+       int ret;
+       bt_adapter_state_e state = BT_ADAPTER_DISABLED;
+
+       ret = bt_adapter_get_state(&state);
+       if (ret != BT_ERROR_NONE)
+               ERR("Fatally failed to get BT state(%d)", ret);
+
+       WARN("BT state(%d)", state);
+       bt_adapter_disable();
+
+       mBTRecoveryState = TRUE;
+}
+
+static void __bt_check_fatal_recovery(void)
+{
+       const char *autoconnectable_bt_address = NULL;
+
+       /* Important: BT auto-connectable address should be set by WMS,
+        *                      when EULA acceptance has been made by an user.
+        */
+       autoconnectable_bt_address =
+                                       vconf_get_str(VCONFKEY_WECONN_AUTOCONNECTABLE_BT_ADDRESS);
+       if (autoconnectable_bt_address && strlen(autoconnectable_bt_address) > 0 &&
+                       __bt_check_connection_status(autoconnectable_bt_address,
+                                                                                       __device_check_gatt_cb) == true) {
+               g_free((gpointer)autoconnectable_bt_address);
+
+               ERR("Fatal error: both EDR and LE was connected");
+
+               __bt_fatal_recovery();
+               return;
+       }
+
+       g_free((gpointer)autoconnectable_bt_address);
+}
+
+static void __sap_connection_status_changed_cb(keynode_t *node, void *user_data)
+{
+       int err = 0, sap_conn = 0;
+       int disconnected_manually = 0;
+       WcObject * wo = (WcObject*)user_data;
+
+       if (!wo)
+               return;
+
+       if (node)
+               sap_conn = vconf_keynode_get_int(node);
+       else
+               err = vconf_get_int(VCONFKEY_SAP_CONNECTION_STATUS, &sap_conn);
+
+       if (err < 0) {
+               ERR("Failed to get sap connection status");
+               return;
+       }
+
+       if (sap_connected == sap_conn) {
+               ERR("sap connection is not changed(%d)", sap_conn);
+               return;
+       }
+
+       sap_connected = sap_conn;
+       DBG("rfcomm_ready(%d), SPP(%d), HFP(%d)", sap_rfcomm_ready, sap_conn, hf_connected);
+       if (sap_conn == SAP_CONNECTED) {
+               __bt_stop_advertising();
+               __bt_set_visibility(BT_ADAPTER_VISIBILITY_MODE_NON_DISCOVERABLE);
+
+               if (hf_connected) {
+                       __bt_notify_all_connected(1);
+
+                       vconf_get_int(VCONFKEY_WECONN_DISCONNECTED_MANUALLY,
+                                                       &disconnected_manually);
+                       if (disconnected_manually)
+                               vconf_set_int(VCONFKEY_WECONN_DISCONNECTED_MANUALLY, 0);
+               }
+
+               wc_object_set_property(wo, XSTR(W_SERVICE_TYPE_BT_SPP),
+                               XSTR(W_SERVICE_STATE_CONNECTED));
+       } else {
+               __bt_notify_all_connected(0);
+
+               if (hf_connected != true)
+                       __bt_check_fatal_recovery();
+
+               if (sap_rfcomm_ready == 1 && hf_connected != true) {
+                       /* start LE advertising */
+                       DBG("HFP is disconnected");
+                       __bt_start_advertising(false);
+               }
+
+               wc_object_set_property(wo, XSTR(W_SERVICE_TYPE_BT_SPP),
+                                                               XSTR(W_SERVICE_STATE_DISCONNECTED));
+       }
+}
+
+static void __on_bt_adapter_state_changed(int result, bt_adapter_state_e state,
+                                                                                       void *user_data)
+{
+       int sap_conn = SAP_DISCONNECTED;
+       const char *autoconnectable_bt_address = NULL;
+       WcObject *wo = (WcObject *)user_data;
+
+       if (mBTRecoveryState == TRUE && state == BT_ADAPTER_DISABLED) {
+               ERR("BT fatal recovery tries to turn BT power on");
+
+               bt_adapter_enable();
+               mBTRecoveryState = FALSE;
+
+               return;
+       }
+
+       if (!wo)
+               return;
+
+       DBG("result = %d, state = %d", result, state);
+       switch (state) {
+       case BT_ADAPTER_ENABLED:
+               /* BT ON */
+               wc_object_emit_callback(wo, WC_OBJECT_EVENT_BEARER_ENABLED, NULL);
+
+               /* Update SPP state */
+               if (vconf_get_int(VCONFKEY_SAP_CONNECTION_STATUS, &sap_conn) < 0) {
+                       ERR("Failed to get sap connection status, but go ahead.");
+                       sap_connected = SAP_DISCONNECTED;
+               } else
+                       sap_connected = sap_conn;
+
+               autoconnectable_bt_address =
+                               vconf_get_str(VCONFKEY_WECONN_AUTOCONNECTABLE_BT_ADDRESS);
+               SECURE_DBG("last connected BT address(%s)", autoconnectable_bt_address);
+               if (autoconnectable_bt_address &&
+                                               strlen(autoconnectable_bt_address) > 0) {
+                       /* Update HFP status */
+                       hf_connected = __bt_check_connection_status(
+                                       autoconnectable_bt_address, __device_check_hfp_cb);
+               } else {
+                       /* If not, clear white list, for example, factory reset */
+                       __bt_update_white_list(NULL, 0);
+               }
+
+               g_free((gpointer)autoconnectable_bt_address);
+
+               vconf_set_int(VCONFKEY_WECONN_LAST_BT_STATUS, 0);
+
+               DBG("BT power(%d), rfcomm_ready(%d), SPP(%d) HFP(%d)",
+                               state, sap_rfcomm_ready, sap_connected, hf_connected);
+               if (sap_rfcomm_ready == 1 &&
+                               sap_connected != SAP_CONNECTED && hf_connected != true)
+                       __bt_start_advertising(true);
+
+               wc_object_set_property(wo, XSTR(W_DEVICE_TYPE_BT),
+                                                               XSTR(W_DEVICE_STATE_ENABLED));
+
+               break;
+       case BT_ADAPTER_DISABLED:
+               /* BT OFF */
+               wc_object_emit_callback(wo, WC_OBJECT_EVENT_BEARER_DISABLED, NULL);
+
+               hf_connected = false;
+               sap_connected = false;
+
+               __fast_advertising_timer_stop();
+
+               wc_object_set_property(wo, XSTR(W_DEVICE_TYPE_BT),
+                                                               XSTR(W_DEVICE_STATE_DISABLED));
+
+               break;
+       }
+}
+
+static void __on_bt_audio_connection_state_changed_cb(int result,
+               bool connected, const char *remote_address,
+               bt_audio_profile_type_e type, void *user_data)
+{
+       int disconnected_manually = 0;
+       WcObject *wo = (WcObject *)user_data;
+
+       DBG("result %d, type %d, rfcomm_ready(%d), SPP(%d), HFP(%d)",
+                                       result, type, sap_rfcomm_ready, sap_connected, connected);
+       SECURE_DBG("remote(%s)", remote_address);
+
+       if (type != BT_AUDIO_PROFILE_TYPE_AG) {
+               if (type == BT_AUDIO_PROFILE_TYPE_A2DP) {
+                       if (connected == false)
+                               __bt_page_scan(true);
+                       else
+                               if (hf_connected == true || sap_connected == SAP_CONNECTED)
+                                       bt_adapter_set_connectable(false);
+               }
+               return;
+       }
+
+       if (!wo)
+               return;
+
+       hf_connected = connected;
+       if (connected) {
+               __bt_stop_advertising();
+               __bt_set_visibility(BT_ADAPTER_VISIBILITY_MODE_NON_DISCOVERABLE);
+
+               if (sap_connected == SAP_CONNECTED) {
+                       __bt_notify_all_connected(1);
+
+                       vconf_get_int(VCONFKEY_WECONN_DISCONNECTED_MANUALLY,
+                                                       &disconnected_manually);
+                       if (disconnected_manually)
+                               vconf_set_int(VCONFKEY_WECONN_DISCONNECTED_MANUALLY, 0);
+               }
+
+               wc_object_set_property(wo, XSTR(W_SERVICE_TYPE_BT_HFP),
+                               XSTR(W_SERVICE_STATE_CONNECTED));
+       } else {
+               __bt_notify_all_connected(0);
+
+               if (sap_connected != SAP_CONNECTED)
+                       __bt_check_fatal_recovery();
+
+               if (sap_rfcomm_ready == 1 && sap_connected != SAP_CONNECTED) {
+                       /* start LE advertising */
+                       DBG("SAP is disconnected");
+                       __bt_start_advertising(false);
+               }
+
+               wc_object_set_property(wo, XSTR(W_SERVICE_TYPE_BT_HFP),
+                                                               XSTR(W_SERVICE_STATE_DISCONNECTED));
+       }
+}
+
+static void __on_bt_socket_connection_state_changed_cb(int result,
+               bt_socket_connection_state_e state,
+               bt_socket_connection_s *connection, void *user_data)
+{
+       WcObject *wo = (WcObject *)user_data;
+
+       DBG("result %d, state %d", result, state);
+
+       if (!wo)
+               return;
+
+/*
+       if (state == BT_SOCKET_CONNECTED)
+               wc_object_set_property(wo, XSTR(W_SERVICE_TYPE_BT_SPP),
+                               XSTR(W_SERVICE_STATE_CONNECTED));
+       else
+               wc_object_set_property(wo, XSTR(W_SERVICE_TYPE_BT_SPP),
+                               XSTR(W_SERVICE_STATE_DISCONNECTED));
+*/
+}
+
+static void __on_bt_device_connection_state_changed_cb(bool connected,
+               const char *remote_address, void *user_data)
+{
+       WcObject *wo = (WcObject *)user_data;
+
+       DBG("result %d ", connected);
+       if(remote_address != NULL)
+               SECURE_DBG("remote address [%s]", remote_address);
+
+       if (!wo)
+               return;
+
+/* This callback is triggered by ACL connected / disconnected event
+       if (connected)
+               wc_object_set_property(wo, XSTR(W_SERVICE_TYPE_BT_HFP),
+                               XSTR(W_SERVICE_STATE_CONNECTED));
+       else
+               wc_object_set_property(wo, XSTR(W_SERVICE_TYPE_BT_HFP),
+                               XSTR(W_SERVICE_STATE_DISCONNECTED));
+*/
+}
+
+static void __on_bt_device_bond_destroy_cb(int result,
+               char *remote_address, void *user_data)
+{
+       WcObject *wo = (WcObject *)user_data;
+
+       if (!wo || !remote_address)
+               return;
+
+       DBG("result(%d) address(%s)", result, remote_address);
+       if (result == BT_ERROR_NONE) {
+               // Disable page scan if HFP or SAP is connected
+               if (hf_connected == true || sap_connected == SAP_CONNECTED)
+                       __bt_page_scan(false);
+       }
+
+       return;
+}
+
+static void __on_bt_device_bond_created_cb(int result,
+               bt_device_info_s *device_info, void *user_data)
+{
+       WcObject *wo = (WcObject *)user_data;
+
+       if (!wo || !device_info)
+               return;
+
+       DBG("result(%d), device class(%d)", result,
+                       device_info->bt_class.major_device_class);
+       if (device_info->bt_class.major_device_class != BT_MAJOR_DEVICE_CLASS_PHONE)
+               return;
+}
+
+static gboolean __on_bt_sap_cmd_cb(WcObject *wo,
+               const void *event_info, void *user_data)
+{
+       struct SAP_event_data *evt_data = NULL;
+       struct SAP_event_data *new_data = NULL;
+       char buf[SAP_DATA_LEN_MAX] = { '\0', };
+       char *bt_address = NULL;
+       // TODO: All of them should be from BT framework.
+       char *profiles = "HFP SPP GATT PAN";
+       char cod[3] = {0x28, 0x07, 0x04};
+       char services = 0x07;
+       unsigned int pos = 0;
+       int res, mainCmd, subCmd, cmdType, btVersion;
+
+       evt_data = (struct SAP_event_data *)event_info;
+       if (evt_data == NULL)
+               return TRUE;
+
+       mainCmd = (int)evt_data->data[1];
+       if (mainCmd != SAP_PDU_CMD_BLUETOOTH) {
+               ERR("Invalid bluetooth command %d", mainCmd);
+               return TRUE;
+       }
+
+       subCmd = (int)evt_data->data[2];
+       switch(subCmd) {
+       case SAP_PDU_BT_CMD_GET_VERSION:
+               DBG("SAP_PDU_BT_CMD_GET_VERSION");
+
+               cmdType = (int)evt_data->data[3];
+               switch (cmdType) {
+               case SAP_PDU_CMD_TYPE_REQ:
+                       new_data = g_try_malloc0(sizeof(struct SAP_event_data));
+                       if (new_data == NULL)
+                               return TRUE;
+
+                       new_data->count = evt_data->count;
+                       new_data->index = evt_data->index;
+                       new_data->data_len = SAP_DATA_LEN_MIN + 1;
+
+                       buf[pos++] = (char)new_data->data_len;
+                       buf[pos++] = (char)SAP_PDU_CMD_BLUETOOTH;
+                       buf[pos++] = (char)SAP_PDU_BT_CMD_GET_VERSION;
+                       buf[pos++] = (char)SAP_PDU_CMD_TYPE_REQ_OK;
+                       buf[pos++] = (char)SAP_PDU_BT_VER_40_P;
+                       memcpy(new_data->data, buf, new_data->data_len);
+
+                       wc_object_emit_callback(wo, WC_OBJECT_EVENT_SAP_SEND_DATA, new_data);
+                       g_free(new_data);
+                       break;
+               case SAP_PDU_CMD_TYPE_REQ_OK:
+                       btVersion = (int)evt_data->data[SAP_DATA_LEN_MIN];
+                       switch (btVersion) {
+                       case SAP_PDU_BT_VER_30:
+                               vconf_set_int(VCONFKEY_WECONN_CONNECTED_BT_VERSION,
+                                                               SAP_PDU_BT_VER_30);
+                               break;
+                       case SAP_PDU_BT_VER_40_LE:
+                               vconf_set_int(VCONFKEY_WECONN_CONNECTED_BT_VERSION,
+                                                               SAP_PDU_BT_VER_40_LE);
+                               break;
+                       case SAP_PDU_BT_VER_40_DUAL:
+                               vconf_set_int(VCONFKEY_WECONN_CONNECTED_BT_VERSION,
+                                                               SAP_PDU_BT_VER_40_DUAL);
+                               break;
+                       case SAP_PDU_BT_VER_40_P:
+                               vconf_set_int(VCONFKEY_WECONN_CONNECTED_BT_VERSION,
+                                                               SAP_PDU_BT_VER_40_P);
+                               break;
+                       case SAP_PDU_BT_VER_41:
+                               vconf_set_int(VCONFKEY_WECONN_CONNECTED_BT_VERSION,
+                                                               SAP_PDU_BT_VER_41);
+                               break;
+                       default:
+                               DBG("Unknown BT version");
+                               break;
+                       }
+                       break;
+               }
+
+               break;
+       case SAP_PDU_BT_CMD_GET_ADDRESS:
+               DBG("SAP_PDU_BT_CMD_GET_ADDRESS");
+
+               cmdType = (int)evt_data->data[3];
+               switch (cmdType) {
+               case SAP_PDU_CMD_TYPE_REQ:
+                       new_data = g_try_malloc0(sizeof(struct SAP_event_data));
+                       if (new_data == NULL)
+                               return TRUE;
+
+                       new_data->count = evt_data->count;
+                       new_data->index = evt_data->index;
+
+                       res = bt_adapter_get_address(&bt_address);
+                       if (res == BT_ERROR_NONE && bt_address) {
+                               new_data->data_len = SAP_DATA_LEN_MIN + strlen(bt_address);
+
+                               buf[pos++] = (char)new_data->data_len;
+                               buf[pos++] = (char)SAP_PDU_CMD_BLUETOOTH;
+                               buf[pos++] = (char)SAP_PDU_BT_CMD_GET_ADDRESS;
+                               buf[pos++] = (char)SAP_PDU_CMD_TYPE_REQ_OK;
+                               memcpy(&buf[pos], bt_address, strlen(bt_address));
+                               memcpy(new_data->data, buf, new_data->data_len);
+
+                               free(bt_address);
+                       } else {
+                               new_data->data_len = SAP_DATA_LEN_MIN;
+                               buf[pos++] = (char)new_data->data_len;
+                               buf[pos++] = (char)SAP_PDU_CMD_BLUETOOTH;
+                               buf[pos++] = (char)SAP_PDU_BT_CMD_GET_ADDRESS;
+                               buf[pos++] = (char)SAP_PDU_CMD_TYPE_RESP_ERR;
+                               memcpy(new_data->data, buf, new_data->data_len);
+                       }
+
+                       wc_object_emit_callback(wo, WC_OBJECT_EVENT_SAP_SEND_DATA, new_data);
+                       g_free(new_data);
+                       break;
+               case SAP_PDU_CMD_TYPE_REQ_OK:
+                       pos = evt_data->data_len - (unsigned int)SAP_DATA_LEN_MIN;
+
+                       bt_address = g_strndup(&evt_data->data[SAP_DATA_LEN_MIN], pos);
+                       vconf_set_str(VCONFKEY_WECONN_AUTOCONNECTABLE_BT_ADDRESS,
+                                                       bt_address);
+                       g_free(bt_address);
+
+                       break;
+               }
+
+               break;
+       case SAP_PDU_BT_CMD_GET_PROFILES:
+               DBG("SAP_PDU_BT_CMD_GET_PROFILES");
+
+               cmdType = (int)evt_data->data[3];
+               switch (cmdType) {
+               case SAP_PDU_CMD_TYPE_REQ:
+                       new_data = g_try_malloc0(sizeof(struct SAP_event_data));
+                       if (new_data == NULL)
+                               return TRUE;
+
+                       new_data->count = evt_data->count;
+                       new_data->index = evt_data->index;
+                       new_data->data_len = SAP_DATA_LEN_MIN + strlen(profiles);
+
+                       buf[pos++] = (char)new_data->data_len;
+                       buf[pos++] = (char)SAP_PDU_CMD_BLUETOOTH;
+                       buf[pos++] = (char)SAP_PDU_BT_CMD_GET_PROFILES;
+                       buf[pos++] = (char)SAP_PDU_CMD_TYPE_REQ_OK;
+                       memcpy(&buf[pos], profiles, strlen(profiles));
+                       memcpy(new_data->data, buf, new_data->data_len);
+
+                       wc_object_emit_callback(wo, WC_OBJECT_EVENT_SAP_SEND_DATA, new_data);
+                       g_free(new_data);
+                       break;
+               }
+
+               break;
+       case SAP_PDU_BT_CMD_GET_COD:
+               DBG("SAP_PDU_BT_CMD_GET_COD");
+
+               cmdType = (int)evt_data->data[3];
+               switch (cmdType) {
+               case SAP_PDU_CMD_TYPE_REQ:
+                       new_data = g_try_malloc0(sizeof(struct SAP_event_data));
+                       if (new_data == NULL)
+                               return TRUE;
+
+                       new_data->count = evt_data->count;
+                       new_data->index = evt_data->index;
+                       new_data->data_len = SAP_DATA_LEN_MIN + sizeof(cod);
+
+                       buf[pos++] = (char)new_data->data_len;
+                       buf[pos++] = (char)SAP_PDU_CMD_BLUETOOTH;
+                       buf[pos++] = (char)SAP_PDU_BT_CMD_GET_COD;
+                       buf[pos++] = (char)SAP_PDU_CMD_TYPE_REQ_OK;
+                       memcpy(&buf[pos], cod, sizeof(cod));
+                       memcpy(new_data->data, buf, new_data->data_len);
+
+                       wc_object_emit_callback(wo, WC_OBJECT_EVENT_SAP_SEND_DATA, new_data);
+                       g_free(new_data);
+                       break;
+               case SAP_PDU_CMD_TYPE_REQ_OK:
+                       break;
+               }
+
+               break;
+       case SAP_PDU_BT_CMD_GET_SERVICES:
+               DBG("SAP_PDU_BT_CMD_GET_SERVICES");
+
+               cmdType = (int)evt_data->data[3];
+               switch (cmdType) {
+               case SAP_PDU_CMD_TYPE_REQ:
+                       new_data = g_try_malloc0(sizeof(struct SAP_event_data));
+                       if (new_data == NULL)
+                               return TRUE;
+
+                       new_data->count = evt_data->count;
+                       new_data->index = evt_data->index;
+                       new_data->data_len = SAP_DATA_LEN_MIN + 1;
+
+                       buf[pos++] = (char)new_data->data_len;
+                       buf[pos++] = (char)SAP_PDU_CMD_BLUETOOTH;
+                       buf[pos++] = (char)SAP_PDU_BT_CMD_GET_SERVICES;
+                       buf[pos++] = (char)SAP_PDU_CMD_TYPE_REQ_OK;
+                       buf[pos++] = services;
+                       memcpy(new_data->data, buf, new_data->data_len);
+
+                       wc_object_emit_callback(wo, WC_OBJECT_EVENT_SAP_SEND_DATA, new_data);
+                       g_free(new_data);
+                       break;
+               case SAP_PDU_CMD_TYPE_REQ_OK:
+                       break;
+               }
+
+               break;
+       case SAP_PDU_BT_CMD_DISCONNECTED_MANUALLY:
+               DBG("SAP_PDU_BT_CMD_DISCONNECTED_MANUALLY");
+
+               cmdType = (int)evt_data->data[3];
+               switch (cmdType) {
+               case SAP_PDU_CMD_TYPE_NOTI:
+                       new_data = g_try_malloc0(sizeof(struct SAP_event_data));
+                       if (new_data == NULL)
+                               return TRUE;
+
+                       vconf_set_int(VCONFKEY_WECONN_DISCONNECTED_MANUALLY, 1);
+
+                       new_data->count = evt_data->count;
+                       new_data->index = evt_data->index;
+                       new_data->data_len = SAP_DATA_LEN_MIN;
+
+                       buf[pos++] = (char)new_data->data_len;
+                       buf[pos++] = (char)SAP_PDU_CMD_BLUETOOTH;
+                       buf[pos++] = evt_data->data[2];
+                       buf[pos++] = (char)SAP_PDU_CMD_TYPE_REQ_OK;
+                       memcpy(new_data->data, buf, new_data->data_len);
+
+                       wc_object_emit_callback(wo, WC_OBJECT_EVENT_SAP_SEND_DATA, new_data);
+                       g_free(new_data);
+                       break;
+               default:
+                       ERR("Invalid bt sub command %d", evt_data->data[3]);
+                       break;
+               }
+
+               break;
+       default:
+               ERR("Invalid bt sub command %d", evt_data->data[2]);
+               break;
+       }
+
+       return TRUE;
+}
+
+static void _bt_bearer_register_events(WcObject *wo)
+{
+       enum SAP_PDU_commands_type cmd_type = SAP_PDU_CMD_TYPE_REQ;
+       enum SAP_PDU_BT_commands bt_cmds = SAP_PDU_BT_CMD_GET_VERSION;
+       char *cmd = NULL;
+       char *event = NULL;
+
+       cmd = g_strdup_printf("%s[%d]",
+                       WC_OBJECT_EVENT_SAP_RECEIVE_DATA, SAP_PDU_CMD_BLUETOOTH);
+
+       while (cmd_type < SAP_PDU_CMD_TYPE_MAX ) {
+               while (bt_cmds < SAP_PDU_BT_CMD_MAX) {
+                       event = g_strdup_printf("%s[%d][%d]", cmd, bt_cmds, cmd_type);
+                       wc_object_add_callback(wo, event, __on_bt_sap_cmd_cb, NULL);
+                       g_free(event);
+
+                       bt_cmds++;
+
+                       if (bt_cmds == SAP_PDU_BT_CMD_FX_MAX)
+                               bt_cmds = SAP_PDU_BT_CMD_DISCONNECTED_MANUALLY;
+               }
+
+               bt_cmds = SAP_PDU_BT_CMD_GET_VERSION;
+               cmd_type++;
+       }
+
+       g_free(cmd);
+}
+
+static void _bt_bearer_deregister_events(WcObject *wo)
+{
+       enum SAP_PDU_commands_type cmd_type = SAP_PDU_CMD_TYPE_REQ;
+       enum SAP_PDU_BT_commands bt_cmds = SAP_PDU_BT_CMD_GET_VERSION;
+       char *cmd = NULL;
+       char *event = NULL;
+
+       cmd = g_strdup_printf("%s[%d]",
+                       WC_OBJECT_EVENT_SAP_RECEIVE_DATA, SAP_PDU_CMD_BLUETOOTH);
+
+       while (cmd_type < SAP_PDU_CMD_TYPE_MAX ) {
+               while (bt_cmds < SAP_PDU_BT_CMD_MAX) {
+                       event = g_strdup_printf("%s[%d][%d]", cmd, bt_cmds, cmd_type);
+                       wc_object_del_callback(wo, event, __on_bt_sap_cmd_cb);
+                       g_free(event);
+
+                       bt_cmds++;
+
+                       if (bt_cmds == SAP_PDU_BT_CMD_FX_MAX)
+                               bt_cmds = SAP_PDU_BT_CMD_SET_PAN_CONFIGURATION_ON;
+               }
+
+               bt_cmds = SAP_PDU_BT_CMD_GET_VERSION;
+               cmd_type++;
+       }
+
+       g_free(cmd);
+}
+
+static void _register_vconf_callback(WcObject *wo)
+{
+       int ret = VCONF_OK;
+
+       if (!wo)
+               return;
+
+       DBG("");
+
+       // TODO: use sap event callback
+       ret = vconf_notify_key_changed(VCONFKEY_SAP_CONNECTION_STATUS,
+                       __sap_connection_status_changed_cb, wo);
+       if (ret != VCONF_OK)
+               ERR("Failed to register sap connection status callback(%d)", ret);
+
+       ret = vconf_notify_key_changed(VCONFKEY_RFCOMM_READY_STATUS,
+                       __rfcomm_ready_status_changed_cb, wo);
+       if (ret != VCONF_OK)
+               ERR("Failed to register sap connection status callback(%d)", ret);
+
+       ret = vconf_notify_key_changed(VCONFKEY_SETUP_WIZARD_FIRST_BOOT,
+                       __setup_wizard_state_cb, wo);
+       if (ret != VCONF_OK)
+               ERR("Failed to register setup wizard state callback(%d)", ret);
+
+       ret = vconf_notify_key_changed(VCONFKEY_SETAPPL_PSMODE, __power_saving_mode_cb, wo);
+       if (ret != VCONF_OK)
+               ERR("Failed to register power saving mode callback (%d)", ret);
+
+       ret = vconf_notify_key_changed(VCONFKEY_PM_KEY_IGNORE, __pm_key_ignore_cb, wo);
+       if (ret != VCONF_OK)
+               ERR("Failed to register pm key ignore callback (%d)", ret);
+}
+
+static void _deregister_vconf_callback(void)
+{
+       int ret = VCONF_OK;
+
+       DBG("");
+
+       ret = vconf_ignore_key_changed(VCONFKEY_SAP_CONNECTION_STATUS,
+                       __sap_connection_status_changed_cb);
+       if (ret != VCONF_OK)
+               ERR("Failed to de-register sap connection status callback(%d)", ret);
+
+       ret = vconf_ignore_key_changed(VCONFKEY_RFCOMM_READY_STATUS,
+                       __rfcomm_ready_status_changed_cb);
+       if (ret != VCONF_OK)
+               ERR("Failed to register sap connection status callback(%d)", ret);
+
+       ret = vconf_ignore_key_changed(VCONFKEY_SETUP_WIZARD_FIRST_BOOT,
+                       __setup_wizard_state_cb);
+       if (ret != VCONF_OK)
+               ERR("Failed to de-register setup wizard state callback(%d)", ret);
+
+       ret = vconf_ignore_key_changed(VCONFKEY_SETAPPL_PSMODE,
+                       __power_saving_mode_cb);
+       if (ret != VCONF_OK)
+               ERR("Failed to de-register power saving mode callback (%d)", ret);
+
+       ret = vconf_ignore_key_changed(VCONFKEY_PM_KEY_IGNORE,
+                       __pm_key_ignore_cb);
+       if (ret != VCONF_OK)
+               ERR("Failed to de-register  pm key ignore callback (%d)", ret);
+}
+
+static void _register_bt_event_listener(WcObject *wo)
+{
+       if (!wo)
+               return;
+
+       DBG("");
+
+       /* BT power event listener */
+       bt_adapter_set_state_changed_cb(
+                       __on_bt_adapter_state_changed, wo);
+
+       /* BT HFP event listener */
+       bt_audio_set_connection_state_changed_cb(
+                       __on_bt_audio_connection_state_changed_cb, wo);
+
+       /* BT SPP event listener */
+       /* TODO: should register eSAP event listener */
+       bt_socket_set_connection_state_changed_cb(
+                       __on_bt_socket_connection_state_changed_cb, wo);
+
+       /* TODO: use HFP rather than device state */
+       bt_device_set_connection_state_changed_cb(
+                       __on_bt_device_connection_state_changed_cb, wo);
+
+       bt_device_set_bond_created_cb(
+                       __on_bt_device_bond_created_cb, wo);
+
+       bt_device_set_bond_destroyed_cb(
+                       __on_bt_device_bond_destroy_cb, wo);
+}
+
+static void _deregister_bt_event_listener(void)
+{
+       DBG("");
+
+       bt_adapter_unset_state_changed_cb();
+
+       bt_device_unset_bond_created_cb();
+
+       bt_device_unset_connection_state_changed_cb();
+
+       bt_audio_unset_connection_state_changed_cb();
+
+       bt_socket_unset_connection_state_changed_cb();
+}
+
+static int bt_bearer_init(WcObject *wo)
+{
+       int ret;
+       int sap_conn = SAP_DISCONNECTED;
+       const char *autoconnectable_bt_address = NULL;
+       bt_adapter_state_e state = BT_ADAPTER_DISABLED;
+
+       ret = bt_initialize();
+       if (ret != BT_ERROR_NONE)
+               return ret;
+
+       ret = bt_audio_initialize();
+       if (ret != BT_ERROR_NONE)
+               return ret;
+
+       ret = alarmmgr_init("weconn");
+       if (ret != ALARMMGR_RESULT_SUCCESS)
+               ERR("alarmmgr_init FAILED (%d)", ret);
+
+       ret = bt_adapter_get_state(&state);
+       if (ret != BT_ERROR_NONE)
+               return ret;
+
+       if (state == BT_ADAPTER_ENABLED) {
+               wc_object_emit_callback(wo, WC_OBJECT_EVENT_BEARER_ENABLED, NULL);
+
+               /* Update SPP state */
+               if (vconf_get_int(VCONFKEY_SAP_CONNECTION_STATUS, &sap_conn) < 0) {
+                       ERR("Failed to get sap connection status, but go ahead.");
+                       sap_connected = SAP_DISCONNECTED;
+               } else
+                       sap_connected = sap_conn;
+
+               autoconnectable_bt_address =
+                               vconf_get_str(VCONFKEY_WECONN_AUTOCONNECTABLE_BT_ADDRESS);
+               DBG("last connected BT address(%s)", autoconnectable_bt_address);
+               if (autoconnectable_bt_address &&
+                                               strlen(autoconnectable_bt_address) > 0) {
+                       /* Update HFP status */
+                       hf_connected = __bt_check_connection_status(
+                                       autoconnectable_bt_address, __device_check_hfp_cb);
+               } else {
+                       /* If not, clear white list, for example, factory reset */
+                       __bt_update_white_list(NULL, 0);
+               }
+
+               g_free((gpointer)autoconnectable_bt_address);
+
+               DBG("BT power(%d), rfcomm_ready(%d), SPP(%d) HFP(%d)",
+                               state, sap_rfcomm_ready, sap_connected, hf_connected);
+               if (sap_rfcomm_ready == 1 &&
+                               sap_connected != SAP_CONNECTED && hf_connected != true)
+                       __bt_start_advertising(true);
+
+               wc_object_set_property(wo, XSTR(W_DEVICE_TYPE_BT),
+                                                               XSTR(W_DEVICE_STATE_ENABLED));
+       }
+
+       _register_vconf_callback(wo);
+
+       _register_bt_event_listener(wo);
+
+       _bt_bearer_register_events(wo);
+
+       return ret;
+}
+
+static int bt_bearer_activate(WcObject *wo)
+{
+       int ret;
+       bt_adapter_state_e state = BT_ADAPTER_DISABLED;
+
+       ret = bt_adapter_get_state(&state);
+       if (ret != BT_ERROR_NONE)
+               return ret;
+
+       DBG("BT state = %d", state);
+       if (state == BT_ADAPTER_DISABLED) {
+               ret = bt_adapter_enable();
+               if (ret != BT_ERROR_NONE) {
+                       ERR("Failed to enable bluetooth device");
+                       return ret;
+               }
+       }
+
+       DBG("Activated");
+
+       return 0;
+}
+
+static int bt_bearer_deactivate(WcObject *wo)
+{
+       int ret;
+       bt_adapter_state_e state = BT_ADAPTER_DISABLED;
+
+       DBG("Deactivated");
+
+       ret = bt_adapter_get_state(&state);
+       if (ret != BT_ERROR_NONE)
+               return ret;
+
+       DBG("BT state = %d", state);
+       if (state == BT_ADAPTER_ENABLED)
+               bt_adapter_disable();
+
+       return 0;
+}
+
+static void bt_bearer_exit(WcObject *wo)
+{
+       DBG("Unloaded");
+
+       _bt_bearer_deregister_events(wo);
+
+       _deregister_vconf_callback();
+
+       _deregister_bt_event_listener();
+
+       bt_deinitialize();
+
+       alarmmgr_fini();
+}
+
+EXPORT_API struct bearer_driver_desc bearer_driver_desc = {
+       .name = "bluetooth",
+       .technology = WC_TECHNOLOGY_BLUETOOTH,
+
+       .init = bt_bearer_init,
+       .activate = bt_bearer_activate,
+       .deactivate = bt_bearer_deactivate,
+       .exit = bt_bearer_exit,
+};
diff --git a/plugins/esap.c b/plugins/esap.c
new file mode 100644 (file)
index 0000000..c030061
--- /dev/null
@@ -0,0 +1,866 @@
+/*
+ * Wearable device Connection Controller Framework
+ *
+ * Copyright (c) 2013 - 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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 <vconf.h>
+#include <vconf-keys.h>
+#include <system_info.h>
+#include <SAPInterface.h>
+
+#include "esap.h"
+#include "control.h"
+#include "plugin.h"
+
+
+#define BUF_SIZE               1024
+#define SAP_CHANNEL_ID         222
+
+#define SAP_CONNECTION_VCONF_NOTIFICATION "memory/private/sap/conn_status"
+
+struct esap_private_data {
+       WcObject *wo_esap;
+       unsigned char role;
+};
+
+static unsigned int sap_service_handle;
+static unsigned int sap_local_agentId;
+static struct esap_private_data *gpd;
+static GSList *send_pdu_list = NULL;
+
+static int __util_send_sap_pdu_data(GSList *pdu_list);
+static int __util_process_sap_pdu_data(WcObject *wo, GSList **pdu_list);
+static unsigned int __util_encode_sap_pdu_data(GSList *pdu_list, char **dst);
+static int __util_decode_sap_pdu_data(char *src, unsigned int src_len, GSList **pdu_list);
+
+static int __util_process_sap_pdu_data(WcObject *wo, GSList **pdu_list)
+{
+       unsigned int index = 0;
+       int count = 0;
+       char *event;
+       GSList *list;
+       struct SAP_PDU_data *pdu_data = NULL;
+       struct SAP_event_data *evt_data = NULL;
+
+       index = g_slist_length(send_pdu_list);
+       for (list = *pdu_list; list; list = list->next) {
+               pdu_data = (struct SAP_PDU_data *)list->data;
+               if (pdu_data != NULL) {
+                       evt_data = g_try_malloc0(sizeof(struct SAP_event_data));
+                       if (evt_data == NULL)
+                               return -1;
+
+                       evt_data->index = index;
+                       evt_data->count = g_slist_length(*pdu_list);
+                       evt_data->data_len = (unsigned int)pdu_data->length;
+                       memcpy(evt_data->data, pdu_data->data, evt_data->data_len);
+
+                       event = g_strdup_printf("%s[%d][%d][%d]", WC_OBJECT_EVENT_SAP_RECEIVE_DATA,
+                                       evt_data->data[1], evt_data->data[2], evt_data->data[3]);
+
+                       wc_object_emit_callback(wo, event, evt_data);
+                       g_free(evt_data);
+                       g_free(event);
+                       count++;
+               }
+       }
+
+       return count;
+}
+
+static int __util_send_sap_pdu_data(GSList *pdu_list)
+{
+       char *buf;
+       unsigned int len = 0;
+       int res = -1;
+
+       if (g_slist_length(pdu_list) <= 0) {
+               ERR("No PDU data to send");
+               return -1;
+       }
+
+       len = __util_encode_sap_pdu_data(pdu_list, &buf);
+       if (len > 0) {
+               res = sendData(sap_service_handle, SAP_CHANNEL_ID, (unsigned short int)len, (void*)buf);
+               if (res == 0)
+                       DBG("Completed to send data %d byte", len);
+               else
+                       ERR("Failed to send data, error %d", res);
+
+               g_free(buf);
+       }
+
+       return res;
+}
+
+static unsigned int __util_encode_sap_pdu_data(GSList *pdu_list, char **dst)
+{
+       GSList *list;
+       struct SAP_PDU_data *pdu_data = NULL;
+       char buf[SAP_DATA_LEN_MAX] = {0};
+       unsigned int length = 0;
+       unsigned int index = 0;
+
+       for (list = pdu_list; list != NULL; list = list->next) {
+               pdu_data = (struct SAP_PDU_data *)list->data;
+               if (pdu_data != NULL) {
+                       if (pdu_data->main_cmd == 0 || pdu_data->sub_cmd == 0 ||
+                                       pdu_data->type_cmd == 0) {
+                               ERR("Invalid PDU data: main_cmd[%d], sub_cmd[%d], type_cmd[%d]",
+                                               pdu_data->main_cmd, pdu_data->sub_cmd, pdu_data->type_cmd);
+                               continue;
+                       }
+
+                       length = (unsigned int)pdu_data->length + (unsigned int)SAP_DATA_LEN_MIN;
+                       buf[index++] = (char)length;
+                       buf[index++] = pdu_data->main_cmd;
+                       buf[index++] = pdu_data->sub_cmd;
+                       buf[index++] = pdu_data->type_cmd;
+                       memcpy(&buf[index], pdu_data->data, (unsigned int)pdu_data->length);
+
+                       index += (unsigned int)pdu_data->length;
+               }
+       }
+
+       *dst = g_try_malloc0(index + 1);
+       g_strlcat(*dst, buf, index + 1);
+
+       DBG("Completed to encode data %d byte", index);
+       return index;
+}
+
+static int __util_decode_sap_pdu_data(char *src, unsigned int src_len, GSList **pdu_list)
+{
+       int res = -1;
+       unsigned int pos = 0;
+       unsigned int data_len = 0;
+       struct SAP_PDU_data *pdu_data = NULL;
+
+       if (src_len < SAP_DATA_LEN_MIN) {
+               ERR("invalid data length, %d", src_len);
+               return res;
+       }
+
+       while (pos < src_len) {
+               pdu_data = g_try_malloc0(sizeof(struct SAP_PDU_data));
+               if (!pdu_data || !src) {
+                       ERR("invalid input parameter !!!");
+                       return res;
+               }
+
+               data_len = (unsigned int)src[pos];
+               if (data_len < SAP_DATA_LEN_MIN) {
+                       ERR("invalid pdu data length, %d", data_len);
+                       goto error;
+               }
+
+               memcpy(pdu_data->data, &src[pos], data_len);
+               pdu_data->length = (char)data_len;
+
+               *pdu_list = g_slist_append(*pdu_list, pdu_data);
+               pos += data_len;
+       }
+
+       if (*pdu_list) {
+               res = (int)g_slist_length(*pdu_list);
+               DBG("Done decode data counts = %d", res);
+       }
+
+       return res;
+
+error:
+       if (g_slist_length(*pdu_list) > 0)
+               g_slist_free_full(*pdu_list, g_free);
+       else {
+               if (pdu_data != NULL)
+                       g_free(pdu_data);
+       }
+
+       return res;
+}
+
+static int _request_feature_exchange(GSList *feat_list)
+{
+       GSList *list;
+       GSList *pdu_list = NULL;
+       struct SAP_PDU_data *sap_data = NULL;
+
+       if (feat_list == NULL)
+               return 0;
+
+       for (list = feat_list; list != NULL; list = list->next) {
+               if (g_strcmp0(list->data, XSTR(SAP_PDU_BT_CMD_GET_VERSION)) == 0) {
+                       sap_data = g_try_malloc0(sizeof(struct SAP_PDU_data));
+                       if (!sap_data) {
+                               ERR("invalid input parameter !!!");
+                               return -1;
+                       }
+
+                       sap_data->main_cmd = SAP_PDU_CMD_BLUETOOTH;
+                       sap_data->sub_cmd = SAP_PDU_BT_CMD_GET_VERSION;
+                       sap_data->type_cmd = SAP_PDU_CMD_TYPE_REQ;
+                       pdu_list = g_slist_append(pdu_list, sap_data);
+               } else if (g_strcmp0(list->data, XSTR(SAP_PDU_BT_CMD_GET_ADDRESS)) == 0) {
+                       sap_data = g_try_malloc0(sizeof(struct SAP_PDU_data));
+                       if (!sap_data) {
+                               ERR("invalid input parameter !!!");
+                               return -1;
+                       }
+
+                       sap_data->main_cmd = SAP_PDU_CMD_BLUETOOTH;
+                       sap_data->sub_cmd = SAP_PDU_BT_CMD_GET_ADDRESS;
+                       sap_data->type_cmd = SAP_PDU_CMD_TYPE_REQ;
+                       pdu_list = g_slist_append(pdu_list, sap_data);
+               } else if (g_strcmp0(list->data, XSTR(SAP_PDU_BT_CMD_GET_PROFILES)) == 0) {
+                       sap_data = g_try_malloc0(sizeof(struct SAP_PDU_data));
+                       if (!sap_data) {
+                               ERR("invalid input parameter !!!");
+                               return -1;
+                       }
+
+                       sap_data->main_cmd = SAP_PDU_CMD_BLUETOOTH;
+                       sap_data->sub_cmd = SAP_PDU_BT_CMD_GET_PROFILES;
+                       sap_data->type_cmd = SAP_PDU_CMD_TYPE_REQ;
+                       pdu_list = g_slist_append(pdu_list, sap_data);
+               } else if (g_strcmp0(list->data, XSTR(SAP_PDU_GENERIC_CMD_GET_MANUFACTURER)) == 0) {
+                       sap_data = g_try_malloc0(sizeof(struct SAP_PDU_data));
+                       if (!sap_data) {
+                               ERR("invalid input parameter !!!");
+                               return -1;
+                       }
+
+                       sap_data->main_cmd = SAP_PDU_CMD_GENERIC;
+                       sap_data->sub_cmd = SAP_PDU_GENERIC_CMD_GET_MANUFACTURER;
+                       sap_data->type_cmd = SAP_PDU_CMD_TYPE_REQ;
+                       pdu_list = g_slist_append(pdu_list, sap_data);
+               } else {
+                       ERR("Not support feature : %s", (char *)list->data);
+               }
+       }
+
+       __util_send_sap_pdu_data(pdu_list);
+
+       g_slist_free_full(pdu_list, g_free);
+
+       return 0;
+}
+
+static void on_register_service_agent_confirm(int wStatusCode, unsigned int uwLocalAgentId)
+{
+       DBG("wStatusCode: %d, uwLocalAgentId: %d", wStatusCode, uwLocalAgentId);
+
+       if (wStatusCode != RESULT_SUCCESS) {
+               DBG("Register service agent failed.\n");
+               return;
+       }
+
+       sap_local_agentId = uwLocalAgentId;
+
+       if (gpd->role == SAP_ROLE_PROVIDER) {
+               DBG("No need to call findPeerAgent!!");
+               return;
+       }
+
+       if (findPeerAgent(uwLocalAgentId) != RESULT_SUCCESS) {
+               DBG("fail to call findPeerAgent.\n");
+               // TBD: error handling
+               return;
+       }
+       DBG("success to call findPeerAgent\n");
+}
+
+static void on_deregister_service_agent_confirm(int wStatusCode, unsigned int uwLocalAgentId)
+{
+       DBG("wStatusCode: %d, uwLocalAgentId: %d", wStatusCode, uwLocalAgentId);
+}
+
+static void on_peer_agent(unsigned int uwLocalAgentId, PeerAgent* pPeerAgent, int wStatusCode)
+{
+       DBG("wStatusCode: %d, uwLocalAgentId: %d", wStatusCode, uwLocalAgentId);
+
+       if (wStatusCode != RESULT_SUCCESS) {
+               DBG("find peer agent failed.");
+               //TBD: error handling
+               return;
+       } else if (wStatusCode == RESULT_SUCCESS)  {
+               DBG("find peer agent success: ALE Name %s, Id %s", pPeerAgent->pchALEName, pPeerAgent->pchASPID);
+
+               if(createServiceConnection(uwLocalAgentId, pPeerAgent) != RESULT_SUCCESS) {
+                       ERR("fail to create service connection");
+                       // TBD: error handling
+                       return;
+               }
+       }
+}
+
+static void on_service_connection_confirm(unsigned int uwLocalAgentId, unsigned int uwServiceHandle, PeerAgent* pPeerAgent, int wStatusCode)
+{
+       DBG("uwLocalAgentId: %d, uwServiceHandle: %d, wStatusCode: %d", uwLocalAgentId, uwServiceHandle, wStatusCode);
+
+       if (wStatusCode != RESULT_SUCCESS) {
+               DBG("service connection fail.\n");
+               // TBD: retry logic
+       } else {
+               DBG("service connection success.\n");
+               sap_service_handle = uwServiceHandle;
+       }
+}
+
+static void on_service_connection_indication(unsigned int uwLocalAgentId, unsigned int uwServiceHandle, PeerAgent* pPeerAgent)
+{
+       WcObject *wo = NULL;
+
+       DBG("uwLocalAgentId: %d, uwServiceHandle: %d",
+                       uwLocalAgentId, uwServiceHandle);
+
+       if (acceptServiceConnection(uwLocalAgentId, uwServiceHandle,
+                       pPeerAgent) != RESULT_SUCCESS) {
+               ERR("fail to accept service connection");
+               // TBD: error handling
+               return;
+       } else {
+               GSList *list = NULL;
+
+               DBG("success to accept service connection");
+               // wait for service connection confirm? - Need to check.
+               sap_service_handle = uwServiceHandle;
+
+               wo = wc_object_find(WC_TECHNOLOGY_BLUETOOTH);
+               if (wo) {
+                       wc_object_set_property(wo, WC_OBJECT_EVENT_SAP_BCMSERVICE_STATUS,
+                                       XSTR(W_SERVICE_STATE_CONNECTED));
+               }
+
+               list = g_slist_append(list, XSTR(SAP_PDU_BT_CMD_GET_VERSION));
+               list = g_slist_append(list, XSTR(SAP_PDU_GENERIC_CMD_GET_MANUFACTURER));
+
+               _request_feature_exchange(list);
+       }
+}
+
+static void on_service_termination_indication(unsigned int uwServiceHandle, int wStatusCode)
+{
+       WcObject *wo = NULL;
+
+       DBG("uwServiceHandle: %d, wStatusCode: %d", uwServiceHandle, wStatusCode);
+
+       wo = wc_object_find(WC_TECHNOLOGY_BLUETOOTH);
+       if (!wo) {
+               ERR("No technology");
+               return;
+       }
+
+       wc_object_set_property(wo, WC_OBJECT_EVENT_SAP_BCMSERVICE_STATUS,
+                       XSTR(W_SERVICE_STATE_DISCONNECTED));
+}
+
+static void on_receive(unsigned int uwServiceHandle,
+               unsigned short int uwChannelId,
+               unsigned int uwPayloadLength, void *pvBuffer)
+{
+       int res = 0;
+       WcObject *wo = NULL;
+       GSList *pdu_list = NULL;
+       char payload[BUF_SIZE] = { '\0', };
+
+       if (pvBuffer == NULL)
+               return;
+
+       DBG("uwServiceHandle:%d, uwChannelId:%d, uwPayloadLength:%d\n",
+                       uwServiceHandle, uwChannelId, uwPayloadLength);
+
+       wo = wc_object_find(WC_TECHNOLOGY_BLUETOOTH);
+       if (!wo) {
+               ERR("No technology");
+               return;
+       }
+
+       memset(payload, 0, BUF_SIZE);
+       memcpy(payload, pvBuffer, uwPayloadLength);
+
+       res = __util_decode_sap_pdu_data(payload, uwPayloadLength, &pdu_list);
+       if (res > 0) {
+               res = __util_process_sap_pdu_data(wo, &pdu_list);
+               DBG("processed %d data", res);
+       } else {
+               ERR("Mal-formed data");
+       }
+}
+
+static void on_space_available(unsigned int uwServiceHandle,
+               unsigned short int uwChannelId, unsigned int ulSpaceAvailable)
+{
+       DBG("uwChannelId: %d, ulSpaceAvailable: %d", uwChannelId, ulSpaceAvailable);
+}
+
+static void on_error(unsigned int uwServiceHandle, unsigned int dwErrorCode)
+{
+       DBG("uwServiceHandle: %d, dwErrorCode: %d\n", uwServiceHandle, dwErrorCode);
+}
+
+static SAPNotification sap_noti_funcs = {
+       on_register_service_agent_confirm,
+       on_receive,
+       on_service_connection_indication,
+       on_service_termination_indication,
+       on_service_connection_confirm,
+       on_peer_agent,
+       on_space_available,
+       on_error,
+       on_deregister_service_agent_confirm,
+};
+
+static gboolean _esap_service_init(WcObject *wo)
+{
+       ServiceDesc *service;
+       ChannelDesc *channel;
+       int ret;
+
+       if (!gpd || !wo)
+               return FALSE;
+
+       // register callbacks
+       ret = registerNotifications(sap_noti_funcs);
+       if (ret != RESULT_SUCCESS) {
+               ERR("Fail to register notification");
+               return FALSE;
+       }
+
+       DBG("registerNotifications success: sap_service_handle %d", sap_service_handle);
+       // Define service description
+       service = (ServiceDesc *)g_try_malloc0(sizeof(ServiceDesc));
+       if (service == NULL) {
+               ERR("Memory allocation fail for ServiceDesc");
+               return FALSE;
+       }
+
+       channel = (ChannelDesc *)g_try_malloc0(sizeof(ChannelDesc));
+       if (channel == NULL) {
+               ERR("Memory allocation fail for ChannelDesc");
+               g_free(service);
+               return FALSE;
+       }
+
+       channel->wChannelID = SAP_CHANNEL_ID;
+       channel->ubNoOfPayloadType = 1; // which value is to be set???
+       channel->payloadTypeList = SAP_ALL_PAYLOAD; // Json or binary
+
+       service->pchASPID = "/system/bcmservice";
+       service->pchSPFName = "/system/bcmservice";
+       service->wConnectionTypeMask = SAP_ALL; // all connectivity
+       service->ubRole = gpd->role;
+       service->pChDescArray = channel;
+       service->numChannels = 1;
+
+       // register service
+       // ret = getRegisteredServiceAgent(service->pchASPID, SERVICE_AGENT_ROLE_PROVIDER);
+       ret = registerServiceAgent(service);
+       if (ret != RESULT_SUCCESS) {
+               ERR("registerServiceAgent Fail with reason: %d", ret);
+               g_free(service);
+               g_free(channel);
+               return FALSE;
+       }
+
+       wc_object_set_property(wo, WC_OBJECT_EVENT_SAP_BCMSERVICE_STATUS,
+                       XSTR(W_SERVICE_STATE_DISCONNECTED));
+
+       DBG("SAP service registered(%s)", (gpd->role == SAP_ROLE_PROVIDER) ? "PROVIDER" : "CONSUMER");
+       return TRUE;
+}
+
+static gboolean __on_esap_event_send_data_cb(WcObject *wo,
+               const void *event_info, void *user_data)
+{
+       struct SAP_event_data *evt_data = NULL;
+       struct SAP_send_data *send_data = NULL;
+       int res;
+
+       evt_data = (struct SAP_event_data *)event_info;
+       if (evt_data == NULL)
+               return TRUE;
+
+       if (evt_data->count > 1) {
+               send_data = g_slist_nth_data(send_pdu_list, evt_data->index);
+               if (send_data == NULL) {
+                       send_data = g_try_malloc0(sizeof(struct SAP_send_data));
+                       if (send_data == NULL)
+                               return TRUE;
+
+                       send_data->count = 1;
+                       send_data->data_len = evt_data->data_len;
+                       memcpy(send_data->data, evt_data->data, evt_data->data_len);
+                       send_pdu_list = g_slist_append(send_pdu_list, send_data);
+               } else {
+                       send_data->count++;
+
+                       if (send_data->count == evt_data->count) {
+                               memcpy(&send_data->data[send_data->data_len],
+                                               evt_data->data, evt_data->data_len);
+                               send_data->data_len += evt_data->data_len;
+
+                               res = sendData(sap_service_handle, SAP_CHANNEL_ID,
+                                               (unsigned short int)send_data->data_len,
+                                               (void*)send_data->data);
+                               if (res == 0)
+                                       DBG("Completed to send data %d byte", send_data->data_len);
+                               else
+                                       ERR("Failed to send data, error %d", res);
+
+                               g_free(send_data);
+                               send_pdu_list = g_slist_remove(send_pdu_list, send_data);
+                       } else {
+                               memcpy(&send_data->data[send_data->data_len],
+                                               evt_data->data, evt_data->data_len);
+                               send_data->data_len += evt_data->data_len;
+                       }
+               }
+       } else {
+               res = sendData(sap_service_handle, SAP_CHANNEL_ID,
+                               (unsigned short int)evt_data->data_len,
+                               (void*)evt_data->data);
+               if (res == 0)
+                       DBG("Completed to send data %d byte", evt_data->data_len);
+               else
+                       ERR("Failed to send data, error %d", res);
+       }
+
+       return TRUE;
+}
+
+static gboolean _on_generic_sap_cmd_cb(WcObject *wo,
+               const void *event_info, void *user_data)
+{
+       struct SAP_event_data *evt_data = NULL;
+       struct SAP_event_data *new_data = NULL;
+       char buf[SAP_DATA_LEN_MAX] = { '\0', };
+       char *value = NULL;
+       unsigned int len;
+       unsigned int pos = 0;
+       int mainCmd, subCmd, cmdType;
+       int ret;
+
+       evt_data = (struct SAP_event_data *)event_info;
+       if (evt_data == NULL)
+               return TRUE;
+
+       mainCmd = (int)evt_data->data[1];
+       if (mainCmd != SAP_PDU_CMD_GENERIC) {
+               ERR("Invalid generic command %d", mainCmd);
+               return TRUE;
+       }
+
+       subCmd = (int)evt_data->data[2];
+       switch (subCmd) {
+       case SAP_PDU_GENERIC_CMD_GET_PLATFORM_NAME:
+               DBG("SAP_PDU_GENERIC_CMD_GET_PLATFORM_NAME");
+
+               cmdType = (int)evt_data->data[3];
+               switch (cmdType) {
+               case SAP_PDU_CMD_TYPE_REQ:
+                       ret = system_info_get_value_string(SYSTEM_INFO_KEY_PLATFORM_NAME,
+                                       &value);
+                       if (ret == 0 && value != NULL) {
+                               new_data = g_try_malloc0(sizeof(struct SAP_event_data));
+                               if (new_data == NULL)
+                                       return TRUE;
+
+                               new_data->count = evt_data->count;
+                               new_data->index = evt_data->index;
+                               new_data->data_len = SAP_DATA_LEN_MIN + strlen(value);
+
+                               buf[pos++] = (char)new_data->data_len;
+                               buf[pos++] = (char)SAP_PDU_CMD_GENERIC;
+                               buf[pos++] = (char)SAP_PDU_GENERIC_CMD_GET_PLATFORM_VERSION;
+                               buf[pos++] = (char)SAP_PDU_CMD_TYPE_REQ_OK;
+                               memcpy(&buf[pos], value, strlen(value));
+                               memcpy(new_data->data, buf, new_data->data_len);
+
+                               g_free(value);
+
+                               wc_object_emit_callback(wo, WC_OBJECT_EVENT_SAP_SEND_DATA, new_data);
+                               g_free(new_data);
+                       }
+                       break;
+               case SAP_PDU_CMD_TYPE_REQ_OK:
+                       break;
+               default:
+                       break;
+               }
+               break;
+       case SAP_PDU_GENERIC_CMD_GET_PLATFORM_VERSION:
+               DBG("SAP_PDU_GENERIC_CMD_GET_PLATFORM_VERSION");
+
+               cmdType = (int)evt_data->data[3];
+               switch (cmdType) {
+               case SAP_PDU_CMD_TYPE_REQ:
+                       ret = system_info_get_value_string(SYSTEM_INFO_KEY_TIZEN_VERSION,
+                                       &value);
+                       if (ret == 0 && value != NULL) {
+                               new_data = g_try_malloc0(sizeof(struct SAP_event_data));
+                               if (new_data == NULL)
+                                       return TRUE;
+
+                               new_data->count = evt_data->count;
+                               new_data->index = evt_data->index;
+                               new_data->data_len = SAP_DATA_LEN_MIN + strlen(value);
+
+                               buf[pos++] = (char)new_data->data_len;
+                               buf[pos++] = (char)SAP_PDU_CMD_GENERIC;
+                               buf[pos++] = (char)SAP_PDU_GENERIC_CMD_GET_PLATFORM_VERSION;
+                               buf[pos++] = (char)SAP_PDU_CMD_TYPE_REQ_OK;
+                               memcpy(&buf[pos], value, strlen(value));
+                               memcpy(new_data->data, buf, new_data->data_len);
+
+                               g_free(value);
+
+                               wc_object_emit_callback(wo, WC_OBJECT_EVENT_SAP_SEND_DATA, new_data);
+                               g_free(new_data);
+                       }
+                       break;
+               case SAP_PDU_CMD_TYPE_REQ_OK:
+                       break;
+               default:
+                       ERR("Invalid generic type command(%d)", cmdType);
+                       break;
+               }
+               break;
+       case SAP_PDU_GENERIC_CMD_GET_MANUFACTURER:
+               DBG("SAP_PDU_GENERIC_CMD_GET_MANUFACTURER");
+
+               cmdType = (int)evt_data->data[3];
+               switch (cmdType) {
+               case SAP_PDU_CMD_TYPE_REQ:
+                       ret = system_info_get_value_string(SYSTEM_INFO_KEY_MANUFACTURER,
+                                       &value);
+                       if (ret == 0 && value != NULL) {
+                               new_data = g_try_malloc0(sizeof(struct SAP_event_data));
+                               if (new_data == NULL)
+                                       return TRUE;
+
+                               new_data->count = evt_data->count;
+                               new_data->index = evt_data->index;
+                               new_data->data_len = SAP_DATA_LEN_MIN + strlen(value);
+
+                               buf[pos++] = (char)new_data->data_len;
+                               buf[pos++] = (char)SAP_PDU_CMD_GENERIC;
+                               buf[pos++] = (char)SAP_PDU_GENERIC_CMD_GET_MANUFACTURER;
+                               buf[pos++] = (char)SAP_PDU_CMD_TYPE_REQ_OK;
+                               memcpy(&buf[pos], value, strlen(value));
+                               memcpy(new_data->data, buf, new_data->data_len);
+
+                               g_free(value);
+
+                               wc_object_emit_callback(wo, WC_OBJECT_EVENT_SAP_SEND_DATA, new_data);
+                               g_free(new_data);
+                       }
+                       break;
+               case SAP_PDU_CMD_TYPE_REQ_OK:
+                       len = evt_data->data_len - (unsigned int)SAP_DATA_LEN_MIN;
+
+                       value = g_strndup(&evt_data->data[SAP_DATA_LEN_MIN], len);
+                       vconf_set_str(VCONFKEY_WECONN_CONNECTED_MANUFACTURER, value);
+
+                       g_free(value);
+                       break;
+               case SAP_PDU_CMD_TYPE_RESP_ERR:
+                       break;
+               case SAP_PDU_CMD_TYPE_NOTI:
+                       break;
+               default:
+                       ERR("Invalid generic type command(%d)", cmdType);
+                       break;
+               }
+               break;
+       default:
+               ERR("Invalid generic sub command(%d)", subCmd);
+               break;
+       }
+
+       return TRUE;
+}
+
+static void _esap_bearer_register_events(WcObject *wo)
+{
+       enum SAP_PDU_commands_type cmd_type = SAP_PDU_CMD_TYPE_REQ;
+       enum SAP_PDU_GENERIC_commands generic_cmds = SAP_PDU_GENERIC_CMD_GET_PLATFORM_NAME;
+       char *cmd = NULL;
+       char *event = NULL;
+
+       cmd = g_strdup_printf("%s[%d]",
+                       WC_OBJECT_EVENT_SAP_RECEIVE_DATA, SAP_PDU_CMD_GENERIC);
+
+       while (cmd_type < SAP_PDU_CMD_TYPE_MAX ) {
+               while (generic_cmds < SAP_PDU_GENERIC_CMD_MAX) {
+                       event = g_strdup_printf("%s[%d][%d]", cmd, generic_cmds, cmd_type);
+                       wc_object_add_callback(wo, event, _on_generic_sap_cmd_cb, NULL);
+                       g_free(event);
+
+                       generic_cmds++;
+               }
+
+               generic_cmds = SAP_PDU_GENERIC_CMD_GET_PLATFORM_NAME;
+               cmd_type++;
+       }
+
+       wc_object_add_callback(wo, WC_OBJECT_EVENT_SAP_SEND_DATA,
+                       __on_esap_event_send_data_cb, NULL);
+
+       g_free(cmd);
+}
+
+static void _esap_bearer_deregister_events(WcObject *wo)
+{
+       enum SAP_PDU_commands_type cmd_type = SAP_PDU_CMD_TYPE_REQ;
+       enum SAP_PDU_GENERIC_commands generic_cmds = SAP_PDU_GENERIC_CMD_GET_PLATFORM_NAME;
+       char *cmd = NULL;
+       char *event = NULL;
+
+       cmd = g_strdup_printf("%s[%d]",
+                       WC_OBJECT_EVENT_SAP_RECEIVE_DATA, SAP_PDU_CMD_GENERIC);
+
+       while (cmd_type < SAP_PDU_CMD_TYPE_MAX ) {
+               while (generic_cmds < SAP_PDU_GENERIC_CMD_MAX) {
+                       event = g_strdup_printf("%s[%d][%d]", cmd, generic_cmds, cmd_type);
+                       wc_object_del_callback(wo, event, _on_generic_sap_cmd_cb);
+                       g_free(event);
+
+                       generic_cmds++;
+               }
+
+               generic_cmds = SAP_PDU_GENERIC_CMD_GET_PLATFORM_NAME;
+               cmd_type++;
+       }
+
+       wc_object_del_callback(wo, WC_OBJECT_EVENT_SAP_SEND_DATA,
+                       __on_esap_event_send_data_cb);
+
+       g_free(cmd);
+}
+
+static void __esap_connection_changed_cb(keynode_t *key, void *data)
+{
+       int status = 0;
+       WcObject *wo = (WcObject *)data;
+
+       vconf_get_int(SAP_CONNECTION_VCONF_NOTIFICATION, &status);
+       DBG("status : %d", status);
+
+       if (status == 1) {
+               _esap_service_init(wo);
+
+               _esap_bearer_register_events(wo);
+       } else {
+               DBG("%s is disconnected", SAP_CONNECTION_VCONF_NOTIFICATION);
+
+               _esap_bearer_deregister_events(wo);
+
+               wc_object_set_property(wo, WC_OBJECT_EVENT_SAP_BCMSERVICE_STATUS,
+                               XSTR(W_SERVICE_STATE_DISCONNECTED));
+       }
+}
+
+static int esap_bearer_init(WcObject *wo)
+{
+       int type;
+       unsigned char role;
+
+       type = wc_control_get_device_type();
+       if (type == PROP_CONTROL_TYPE_WEARABLE) {
+               role = SAP_ROLE_PROVIDER;
+       } else if (type == PROP_CONTROL_TYPE_HOST) {
+               role = SAP_ROLE_CONSUMER;
+       } else {
+               ERR("Unknown type");
+               return -EINVAL;
+       }
+
+       gpd = g_try_new0(struct esap_private_data, 1);
+       if (!gpd)
+               return -ENOMEM;
+
+       /* FIXME: why WcObject -> wo.element -> WcObject (circular dependency) */
+       gpd->wo_esap = wo;
+       gpd->role = role;
+
+       /* FIXEME: test code */
+       do {
+               int status = 0;
+               vconf_get_int(SAP_CONNECTION_VCONF_NOTIFICATION, &status);
+
+               if (status == 1)
+                       _esap_service_init(wo);
+               else
+                       vconf_notify_key_changed(SAP_CONNECTION_VCONF_NOTIFICATION,
+                                       __esap_connection_changed_cb, wo);
+       } while(0);
+
+       return 0;
+}
+
+static int esap_bearer_activate(WcObject *wo)
+{
+       gboolean ret;
+
+       ret = _esap_service_init(wo);
+       DBG("Activated: %d", ret);
+       return 0;
+}
+
+static int esap_bearer_deactivate(WcObject *wo)
+{
+       DBG("Deactivated");
+
+       return 0;
+}
+
+static int esap_bearer_connect(WcObject *wo, const char* address)
+{
+       DBG("Connected");
+       // TBD: request connect() through SAP interface
+       return 0;
+}
+
+static int esap_bearer_disconnect(WcObject *wo)
+{
+       DBG("Disconnected");
+       // TBD: request disconnect() through SAP interface
+       return 0;
+}
+
+static void esap_bearer_exit(WcObject *wo)
+{
+       vconf_ignore_key_changed(SAP_CONNECTION_VCONF_NOTIFICATION,
+                       __esap_connection_changed_cb);
+
+       if (gpd) {
+               g_free(gpd);
+               gpd = NULL;
+       }
+}
+
+EXPORT_API struct bearer_driver_desc bearer_driver_desc = {
+       .name = "esap",
+       .technology = WC_TECHNOLOGY_BLUETOOTH,
+
+       .init = esap_bearer_init,
+       .activate = esap_bearer_activate,
+       .deactivate = esap_bearer_deactivate,
+       .connect = esap_bearer_connect,
+       .disconnect = esap_bearer_disconnect,
+       .exit = esap_bearer_exit,
+};
diff --git a/plugins/esap.h b/plugins/esap.h
new file mode 100644 (file)
index 0000000..efa49ae
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ * Wearable device Connection Controller Framework
+ *
+ * Copyright (c) 2013 - 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __WECONN_ESAP_H__
+#define __WECONN_ESAP_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "log.h"
+#include "events.h"
+#include "object.h"
+
+#define SAP_ROLE_PROVIDER 0x00
+#define SAP_ROLE_CONSUMER 0x01
+
+#define SAP_DATA_LEN_MIN 4
+#define SAP_DATA_LEN_MAX 255
+#define SAP_DATA_MAC_ADDR_LEN 17
+
+#define VCONFKEY_WECONN_CONNECTED_BT_VERSION \
+                               "file/private/weconn/connected_bt_version"
+#define VCONFKEY_WECONN_DISCONNECTED_MANUALLY \
+                               "file/private/weconn/disconnected_manually"
+#define VCONFKEY_WECONN_CONNECTED_MANUFACTURER \
+                               "file/private/weconn/connected_manufacturer"
+#define VCONFKEY_WECONN_AUTOCONNECTABLE_BT_ADDRESS \
+                               "file/private/weconn/autoconnectable_unique_bt_target_address"
+
+#define VCONFKEY_WECONN_ALL_CONNECTED  "memory/private/weconn/all_connected"
+#define VCONFKEY_RFCOMM_READY_STATUS   "memory/private/sap/rfcomm_ready"
+#define VCONFKEY_SAP_CONNECTION_STATUS "memory/private/sap/conn_status"
+#define SAP_DISCONNECTED       0
+#define SAP_CONNECTED          1
+
+enum SAP_PDU_commands_type {
+       SAP_PDU_CMD_TYPE_REQ = 0x01,
+       SAP_PDU_CMD_TYPE_REQ_OK = 0x02,
+       SAP_PDU_CMD_TYPE_RESP_ERR = 0x03,
+       SAP_PDU_CMD_TYPE_NOTI = 0x04,
+       SAP_PDU_CMD_TYPE_MAX = 0x05,
+};
+
+enum SAP_PDU_commands {
+       SAP_PDU_CMD_GENERIC = 0x01,
+       SAP_PDU_CMD_BLUETOOTH = 0x02,
+       SAP_PDU_CMD_WIFI = 0x03,
+       SAP_PDU_CMD_CELLULAR = 0x04,
+       SAP_PDU_CMD_ETHERNET = 0x05,
+};
+
+enum SAP_PDU_BT_commands {
+       SAP_PDU_BT_CMD_UNKNOWN = 0x00,
+       SAP_PDU_BT_CMD_GET_VERSION = 0x01,
+       SAP_PDU_BT_CMD_GET_ADDRESS = 0x02,
+       SAP_PDU_BT_CMD_GET_PROFILES = 0x03,
+       SAP_PDU_BT_CMD_GET_COD = 0x04,
+       SAP_PDU_BT_CMD_GET_SERVICES = 0x05,
+       SAP_PDU_BT_CMD_FX_MAX = 0x06,
+
+       SAP_PDU_BT_CMD_SET_PAN_CONFIGURATION_ON = 0x11,
+       SAP_PDU_BT_CMD_SET_PAN_CONFIGURATION_OFF = 0x12,
+       SAP_PDU_BT_CMD_SET_PAN_CONNECTION = 0x13,
+       SAP_PDU_BT_CMD_DISCONNECTED_MANUALLY = 0x14,
+       SAP_PDU_BT_CMD_MAX = 0x15,
+};
+
+enum SAP_PDU_BT_version {
+       SAP_PDU_BT_VER_UNKOWN = 0x00, // unknown
+       SAP_PDU_BT_VER_30 = 0x01, // 3.0
+       SAP_PDU_BT_VER_40_LE = 0x02, // 4.0 LE ONLY
+       SAP_PDU_BT_VER_40_DUAL = 0x03, // 4.0 DUAL
+       SAP_PDU_BT_VER_40_P = 0x04, // 4.0'
+       SAP_PDU_BT_VER_41 = 0x05, // 4.1
+};
+
+enum SAP_PDU_BT_profile {
+       SAP_PDU_BT_PROFILE_UNKOWN = 0x00,
+       SAP_PDU_BT_PROFILE_HFP = 0x01,
+       SAP_PDU_BT_PROFILE_SPP = 0x02,
+       SAP_PDU_BT_PROFILE_GATT = 0x03,
+       SAP_PDU_BT_PROFILE_PAN = 0x04,
+       SAP_PDU_BT_PROFILE_MAX = 0x05,
+};
+
+enum SAP_PDU_WIFI_commands {
+       SAP_PDU_WIFI_CMD_UNKNOWN = 0x00,
+       SAP_PDU_WIFI_CMD_GET_VERSION = 0x01,
+       SAP_PDU_WIFI_CMD_GET_MAC_ADDR = 0x02,
+       SAP_PDU_WIFI_CMD_GET_IP_ADDR = 0x03,
+       SAP_PDU_WIFI_CMD_MAX = 0x04,
+};
+
+enum SAP_PDU_CELLULAR_commands {
+       SAP_PDU_CELLULAR_CMD_UNKNOWN = 0x00,
+       SAP_PDU_CELLULAR_CMD_GET_IP_ADDR = 0x01,
+       SAP_PDU_CELLULAR_CMD_MAX = 0x02,
+};
+
+enum SAP_PDU_ETHERNET_commands {
+       SAP_PDU_ETHERNET_CMD_UNKNOWN = 0x00,
+       SAP_PDU_ETHERNET_CMD_GET_MAC_ADDR = 0x01,
+       SAP_PDU_ETHERNET_CMD_GET_IP_ADDR = 0x02,
+       SAP_PDU_ETHERNET_CMD_MAX = 0x03,
+};
+
+enum SAP_PDU_GENERIC_commands {
+       SAP_PDU_GENERIC_CMD_UNKNOWN = 0x00,
+       SAP_PDU_GENERIC_CMD_GET_PLATFORM_NAME = 0x01,
+       SAP_PDU_GENERIC_CMD_GET_PLATFORM_VERSION = 0x02,
+       SAP_PDU_GENERIC_CMD_GET_MANUFACTURER = 0x03,
+       SAP_PDU_GENERIC_CMD_MAX = 0x04,
+};
+
+struct SAP_PDU_data {
+       char length;
+       char main_cmd;
+       char sub_cmd;
+       char type_cmd;
+       char data[SAP_DATA_LEN_MAX];
+};
+
+struct SAP_event_data {
+       unsigned int index;
+       unsigned int count;
+       unsigned int data_len;
+       char data[SAP_DATA_LEN_MAX];
+};
+
+struct SAP_send_data {
+       unsigned int index;
+       unsigned int count;
+       unsigned int data_len;
+       char data[SAP_DATA_LEN_MAX];
+};
+
+typedef struct _SAP_PDU_CMD_Callbacks SAP_PDU_CMD_Callbacks;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __WECONN_PLUGIN_H__ */
diff --git a/plugins/pan.c b/plugins/pan.c
new file mode 100644 (file)
index 0000000..d31323b
--- /dev/null
@@ -0,0 +1,923 @@
+/*
+ * Wearable device Connection Controller Framework
+ *
+ * Copyright (c) 2013 - 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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 "util.h"
+#include "plugin.h"
+#include "esap.h"
+#include "technology.h"
+
+static __thread guint weconn_conn_subscribe_id_connman_state = 0;
+
+static int pan_bearer_connect(WcObject *wo, const char *address);
+static int pan_bearer_disconnect(WcObject *wo);
+
+static const char **__get_pan_profile(GDBusConnection *connection)
+{
+       GVariant *reply;
+       unsigned int n = 0;
+       GError *error = NULL;
+       const char *obj_path = NULL;
+       const char **obj_array =  NULL;
+       GVariantIter *iter = NULL, *next = NULL;
+       GSList *string_list = NULL, *slist;
+
+       reply = g_dbus_connection_call_sync(connection,
+                       "net.connman",
+                       "/",
+                       "net.connman.Manager",
+                       "GetServices",
+                       NULL,
+                       NULL,
+                       G_DBUS_CALL_FLAGS_NONE,
+                       DBUS_REPLY_TIMEOUT,
+                       NULL,
+                       &error);
+
+       if (error) {
+               ERR("Failed to request (%s)", error->message);
+               g_error_free(error);
+
+               if (reply)
+                       g_variant_unref(reply);
+
+               return NULL;
+       }
+
+       if (!reply) {
+               ERR("Failed to request");
+               return NULL;
+       }
+
+       g_variant_get(reply, "(a(oa{sv}))", &iter);
+       while (g_variant_iter_loop(iter, "(oa{sv})", &obj_path, &next)) {
+               if (g_str_has_prefix(obj_path, "/net/connman/service/bluetooth_")
+                                                               != TRUE)
+                       continue;
+
+               n++;
+               string_list = g_slist_prepend(string_list, g_strdup(obj_path));
+       }
+
+       if (iter)
+               g_variant_iter_free(iter);
+
+       if (next)
+               g_variant_iter_free(next);
+
+       g_variant_unref(reply);
+
+       obj_array = g_try_new(const char *, n + 1);
+       if (!obj_array) {
+               ERR("No memory");
+               return NULL;
+       }
+
+       obj_array[n--] = NULL;
+       for (slist = string_list; slist; slist = slist->next)
+               obj_array[n--] = slist->data;
+
+       g_slist_free(string_list);
+
+       return obj_array;
+}
+
+#ifdef USE_STATIC_IP
+static int __request_pan_set_dns(GDBusConnection *connection,
+               const char *obj_path)
+{
+       GVariantBuilder *builder;
+       GVariant *params = NULL;
+       GVariant *reply = NULL;
+       GError *error = NULL;
+       int err = -EIO;
+
+       const char *prop_nameserver_config = "Nameservers.Configuration";
+       const char *dns = "192.168.44.1";
+
+       builder = g_variant_builder_new(G_VARIANT_TYPE ("as"));
+       g_variant_builder_add(builder, "s", dns);
+       params = g_variant_new("(sv)",
+                       prop_nameserver_config, g_variant_builder_end(builder));
+       g_variant_builder_unref(builder);
+
+       reply = g_dbus_connection_call_sync(connection,
+                       "net.connman",
+                       obj_path,
+                       "net.connman.Service",
+                       "SetProperty",
+                       params,
+                       NULL,
+                       G_DBUS_CALL_FLAGS_NONE,
+                       DBUS_REPLY_TIMEOUT,
+                       NULL,
+                       &error);
+
+       if (error) {
+               ERR("Failed to request (%s)", error->message);
+               if (g_strrstr(error->message, "net.connman.Error.AlreadyConnected"))
+                       err = -EISCONN;
+               else if (g_strrstr(error->message, "net.connman.Error.NotConnected"))
+                       err = -ENOTCONN;
+
+               g_error_free(error);
+
+               if (reply)
+                       g_variant_unref(reply);
+
+               return err;
+       }
+
+       if (!reply) {
+               ERR("Failed to request");
+               return -EIO;
+       }
+
+       g_variant_unref(reply);
+
+       return 0;
+}
+
+static int __request_pan_set_static_ip(GDBusConnection *connection,
+               const char *obj_path)
+{
+       GVariantBuilder *builder;
+       GVariant *params = NULL;
+       GVariant *reply = NULL;
+       GError *error = NULL;
+       int err = -EIO;
+
+       const char *prop_ipv4_config = "IPv4.Configuration";
+       const char *prop_method = "Method";
+       const char *prop_address = "Address";
+       const char *prop_gateway = "Gateway";
+       const char *prop_netmask = "Netmask";
+       const char *manual_method = "manual";
+       const char *ipaddress = "192.168.44.179";
+       const char *netmask = "255.255.255.0";
+       const char *gateway = "192.168.44.1";
+
+       builder = g_variant_builder_new(G_VARIANT_TYPE ("a{sv}"));
+
+       g_variant_builder_add(builder, "{sv}", prop_method, g_variant_new_string(manual_method));
+       g_variant_builder_add(builder, "{sv}", prop_address, g_variant_new_string(ipaddress));
+       g_variant_builder_add(builder, "{sv}", prop_netmask, g_variant_new_string(netmask));
+       g_variant_builder_add(builder, "{sv}", prop_gateway, g_variant_new_string(gateway));
+
+       params = g_variant_new("(sv)",
+                       prop_ipv4_config, g_variant_builder_end(builder));
+       g_variant_builder_unref(builder);
+
+       reply = g_dbus_connection_call_sync(connection,
+                       "net.connman",
+                       obj_path,
+                       "net.connman.Service",
+                       "SetProperty",
+                       params,
+                       NULL,
+                       G_DBUS_CALL_FLAGS_NONE,
+                       DBUS_REPLY_TIMEOUT,
+                       NULL,
+                       &error);
+
+       if (error) {
+               ERR("Failed to request (%s)", error->message);
+               if (g_strrstr(error->message, "net.connman.Error.AlreadyConnected"))
+                       err = -EISCONN;
+               else if (g_strrstr(error->message, "net.connman.Error.NotConnected"))
+                       err = -ENOTCONN;
+
+               g_error_free(error);
+
+               if (reply)
+                       g_variant_unref(reply);
+
+               return err;
+       }
+
+       if (!reply) {
+               ERR("Failed to request");
+               return -EIO;
+       }
+
+       g_variant_unref(reply);
+
+       return 0;
+}
+#endif
+
+static int __request_pan_command(GDBusConnection *connection,
+               const char *obj_path, const char *method)
+{
+       int err = -EIO;
+       GVariant *reply;
+       GError *error = NULL;
+
+#ifdef USE_STATIC_IP
+       err = __request_pan_set_static_ip(connection, obj_path);
+       if (err < 0)
+               SECURE_ERR("Failed to set static IP(%d)", err);
+
+       err = __request_pan_set_dns(connection, obj_path);
+       if (err < 0)
+               SECURE_ERR("Failed to set DNS(%d)", err);
+#endif
+
+       reply = g_dbus_connection_call_sync(connection,
+                       "net.connman",
+                       obj_path,
+                       "net.connman.Service",
+                       method,
+                       NULL,
+                       NULL,
+                       G_DBUS_CALL_FLAGS_NONE,
+                       DBUS_REPLY_TIMEOUT,
+                       NULL,
+                       &error);
+
+       if (error) {
+               ERR("Failed to request (%s)", error->message);
+               if (g_strrstr(error->message, "net.connman.Error.AlreadyConnected"))
+                       err = -EISCONN;
+               else if (g_strrstr(error->message, "net.connman.Error.NotConnected"))
+                       err = -ENOTCONN;
+
+               g_error_free(error);
+
+               if (reply)
+                       g_variant_unref(reply);
+
+               return err;
+       }
+
+       if (!reply) {
+               ERR("Failed to request");
+               return -EIO;
+       }
+
+       g_variant_unref(reply);
+
+       return 0;
+}
+
+static int _pan_bearer_request_pan_configuration(WcObject *wo, gboolean enable)
+{
+       struct SAP_event_data *new_data = NULL;
+       char buf[SAP_DATA_LEN_MAX] = { '\0', };
+       int pos = 0;
+
+       new_data = g_try_malloc0(sizeof(struct SAP_event_data));
+       if (new_data == NULL)
+               return -ENOMEM;
+
+       new_data->count = 1;
+       new_data->index = 1;
+       new_data->data_len = (char)SAP_DATA_LEN_MIN;
+
+       buf[pos++] = (char)new_data->data_len;
+       buf[pos++] = (char)SAP_PDU_CMD_BLUETOOTH;
+
+       if (enable == TRUE)
+               buf[pos++] = (char)SAP_PDU_BT_CMD_SET_PAN_CONFIGURATION_ON;
+       else
+               buf[pos++] = (char)SAP_PDU_BT_CMD_SET_PAN_CONFIGURATION_OFF;
+
+       buf[pos++] = (char)SAP_PDU_CMD_TYPE_REQ;
+
+       memcpy(new_data->data, buf, new_data->data_len);
+
+       wc_object_emit_callback(wo, WC_OBJECT_EVENT_SAP_SEND_DATA, new_data);
+       g_free(new_data);
+
+       return 0;
+}
+
+static GVariant *_get_properties(GDBusConnection *connection,
+               const char *obj_path)
+{
+       GVariant *reply;
+       GError *error = NULL;
+
+       if (!connection || !obj_path)
+               return NULL;
+
+       reply = g_dbus_connection_call_sync(connection,
+                       "net.connman",
+                       obj_path,
+                       "net.connman.Service",
+                       "GetProperties",
+                       NULL,
+                       NULL,
+                       G_DBUS_CALL_FLAGS_NONE,
+                       DBUS_REPLY_TIMEOUT,
+                       NULL,
+                       &error);
+
+       if (error) {
+               ERR("Failed to request (%s)", error->message);
+               g_error_free(error);
+
+               if (reply)
+                       g_variant_unref(reply);
+
+               return NULL;
+       }
+
+       if (!reply) {
+               ERR("Failed to request");
+               return NULL;
+       }
+
+       return reply;
+}
+
+static int _get_pan_state(WcObject *wo)
+{
+       int ret = W_SERVICE_STATE_DISCONNECTED;
+       unsigned int i, num = 0;
+       GError *error = NULL;
+       const char **obj_array =  NULL;
+       GDBusConnection *connection = NULL;
+       GVariantIter *iter = NULL;
+       GVariant *reply;
+       GVariant *value = NULL;
+       gchar *key = NULL;
+
+       if (!wo)
+               return -EINVAL;
+
+       DBG("");
+
+       connection = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error);
+       if (!connection) {
+               ERR("Failed to get system bus[%s]", error->message);
+               g_error_free(error);
+               return -EIO;
+       }
+
+       obj_array = __get_pan_profile(connection);
+       num = g_strv_length((char **)obj_array);
+       if (!num) {
+               ERR("Failed to get profiles");
+               return -ENXIO;
+       }
+
+       for (i=0; i<num; i++) {
+               reply = _get_properties(connection, obj_array[i]);
+               if (reply != NULL) {
+                       g_variant_get(reply, "(a{sv})", &iter);
+                       while (g_variant_iter_loop(iter, "{sv}", &key, &value)) {
+                               const gchar *state = NULL;
+
+                               if (g_strcmp0(key, "State") == 0) {
+                                       state = g_variant_get_string(value, NULL);
+                                       if (g_strcmp0(state, "association") == 0)
+                                               ret = W_SERVICE_STATE_CONNECTING;
+                                       else if (g_strcmp0(state, "configuration") == 0)
+                                               ret = W_SERVICE_STATE_CONNECTING;
+                                       else if (g_strcmp0(state, "ready") == 0)
+                                               ret = W_SERVICE_STATE_CONNECTED;
+                                       else if (g_strcmp0(state, "online") == 0)
+                                               ret = W_SERVICE_STATE_CONNECTED;
+                                       else
+                                               ret = W_SERVICE_STATE_DISCONNECTED;
+                               }
+
+                               if (ret != W_SERVICE_STATE_DISCONNECTED)
+                                       break;
+                       }
+
+                       g_variant_unref(reply);
+               }
+       }
+
+       return ret;
+}
+
+static void __pan_set_property(WcObject *wo, char *key, char *property)
+{
+       char *property_old = NULL;
+
+       if (!key || !property)
+               return;
+
+       property_old = wc_object_get_property(wo, key);
+       if (property_old != NULL) {
+               if (g_strcmp0(property_old, property) == 0) {
+                       DBG("not changed property : %s", property);
+                       g_free(property_old);
+                       return;
+               }
+               g_free(property_old);
+       }
+
+       wc_object_set_property(wo, key, property);
+}
+
+static int _pan_connect(WcObject *wo)
+{
+       int err = -EIO;
+       unsigned int i, num = 0;
+       GError *error = NULL;
+       const char **obj_array =  NULL;
+       GDBusConnection *connection = NULL;
+
+       if (!wo)
+               return -EINVAL;
+
+       DBG("");
+
+       connection = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error);
+       if (!connection) {
+               ERR("Failed to get system bus[%s]", error->message);
+               g_error_free(error);
+               return -EIO;
+       }
+
+       obj_array = __get_pan_profile(connection);
+       num = g_strv_length((char **)obj_array);
+       if (!num) {
+               ERR("Failed to get profiles");
+               return -ENXIO;
+       }
+
+       for (i=0; i<num; i++) {
+               err = __request_pan_command(connection, obj_array[i], "Connect");
+               if (err == 0 || err == -EISCONN)
+                       break;
+       }
+
+       g_strfreev((char **)obj_array);
+
+       if (err == 0)
+               DBG("PAN successfully connected");
+
+       g_object_unref(connection);
+
+       return err;
+}
+
+static int _pan_disconnect(WcObject *wo)
+{
+       int err = -EIO;
+       unsigned int i, num = 0;
+       GError *error = NULL;
+       const char **obj_array =  NULL;
+       GDBusConnection *connection = NULL;
+
+       if (!wo)
+               return -EINVAL;
+
+       connection = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error);
+       if (!connection) {
+               ERR("Failed to get system bus %s", error->message);
+               g_error_free(error);
+               return -EIO;
+       }
+
+       obj_array = __get_pan_profile(connection);
+       num = g_strv_length((char **)obj_array);
+       if (!num) {
+               ERR("Failed to get profiles");
+               return -ENXIO;
+       }
+
+       for (i=0; i<num; i++) {
+               err = __request_pan_command(connection, obj_array[i], "Disconnect");
+               if (err == 0)
+                       break;
+       }
+
+       g_strfreev((char **)obj_array);
+
+       if (err == 0) {
+               DBG("PAN successfully disconnected");
+               _pan_bearer_request_pan_configuration(wo, FALSE);
+       } else
+               ERR("failed to disconnect [%d]", err);
+
+       g_object_unref(connection);
+
+       return err;
+}
+
+static gboolean _on_pan_sap_cmd_cb(WcObject *wo,
+               const void *event_info, void *user_data)
+{
+       struct SAP_event_data *evt_data = NULL;
+       int res, mainCmd, subCmd, cmdType;
+       char *pan_state = NULL;
+
+       evt_data = (struct SAP_event_data *)event_info;
+       if (evt_data == NULL)
+               return TRUE;
+
+       mainCmd = (int)evt_data->data[1];
+       if (mainCmd != SAP_PDU_CMD_BLUETOOTH) {
+               ERR("Invalid bluetooth command(%02x)", mainCmd);
+               return TRUE;
+       }
+
+       subCmd = (int)evt_data->data[2];
+       switch (subCmd) {
+       case SAP_PDU_BT_CMD_SET_PAN_CONFIGURATION_ON:
+               DBG("SAP_PDU_BT_CMD_SET_PAN_CONFIGURATION_ON");
+               break;
+       case SAP_PDU_BT_CMD_SET_PAN_CONFIGURATION_OFF:
+               DBG("SAP_PDU_BT_CMD_SET_PAN_CONFIGURATION_OFF");
+               break;
+       case SAP_PDU_BT_CMD_SET_PAN_CONNECTION:
+               DBG("SAP_PDU_BT_CMD_SET_PAN_CONNECTION");
+
+               cmdType = (int)evt_data->data[3];
+               switch (cmdType) {
+               case SAP_PDU_CMD_TYPE_REQ:
+                       res = _pan_connect(wo);
+                       if (res < 0) {
+                               ERR("Failed pan connect");
+
+                               __pan_set_property(wo, XSTR(W_SERVICE_TYPE_BT_PAN),
+                                               XSTR(W_SERVICE_STATE_DISCONNECTED));
+                       }
+
+                       break;
+               default:
+                       break;
+               }
+
+               break;
+       case SAP_PDU_BT_CMD_DISCONNECTED_MANUALLY:
+               DBG("SAP_PDU_BT_CMD_DISCONNECTED_MANUALLY");
+
+               cmdType = (int)evt_data->data[3];
+               switch (cmdType) {
+               case SAP_PDU_CMD_TYPE_NOTI:
+                       pan_state = wc_object_get_property(wo, XSTR(W_SERVICE_TYPE_BT_PAN));
+                       if (g_strcmp0(pan_state, XSTR(W_SERVICE_STATE_CONNECTED)) == 0) {
+                               res = _pan_disconnect(wo);
+                               if (res < 0)
+                                       ERR("Failed pan connect");
+                       }
+
+                       g_free(pan_state);
+                       break;
+               default:
+                       break;
+               }
+               break;
+       default:
+               break;
+       }
+
+       return TRUE;
+}
+
+static void _pan_bearer_register_events(WcObject *wo)
+{
+       enum SAP_PDU_commands_type cmd_type = SAP_PDU_CMD_TYPE_REQ;
+       enum SAP_PDU_BT_commands pan_cmds = SAP_PDU_BT_CMD_SET_PAN_CONFIGURATION_ON;
+       char *cmd = NULL;
+       char *event = NULL;
+
+       cmd = g_strdup_printf("%s[%d]",
+                       WC_OBJECT_EVENT_SAP_RECEIVE_DATA, SAP_PDU_CMD_BLUETOOTH);
+
+       while (cmd_type < SAP_PDU_CMD_TYPE_MAX ) {
+               while (pan_cmds < SAP_PDU_BT_CMD_MAX) {
+                       event = g_strdup_printf("%s[%d][%d]", cmd, pan_cmds, cmd_type);
+                       wc_object_add_callback(wo, event, _on_pan_sap_cmd_cb, NULL);
+                       g_free(event);
+
+                       pan_cmds++;
+               }
+
+               pan_cmds = SAP_PDU_BT_CMD_SET_PAN_CONFIGURATION_ON;
+               cmd_type++;
+       }
+
+       g_free(cmd);
+}
+
+static void _pan_connect_cb(service_h request,
+               service_h reply, service_result_e result, void *user_data)
+{
+       int ret;
+       char *resp = NULL;
+       const char *connected = NULL;
+       WcObject *wo = (WcObject *)user_data;
+
+       if (!wo) {
+               ERR("WcObject is NULL");
+               return;
+       }
+
+       if (result != SERVICE_RESULT_SUCCEEDED) {
+               ERR("service reply failed = [%d]", result);
+               return;
+       }
+
+       ret = service_get_extra_data(reply, "_WCPOPUP_RESP_", &resp);
+       if (ret != SERVICE_ERROR_NONE) {
+               ERR("failed to retrieve response = [%d]", ret);
+               return;
+       }
+
+       if (g_strcmp0(resp, "OK") == 0) {
+               connected = (const char *)g_hash_table_lookup(
+                               wc_object_peek_property_hash(wo), XSTR(W_SERVICE_TYPE_BT_SPP));
+               if (g_strcmp0(connected, XSTR(W_SERVICE_STATE_CONNECTED)) != 0) {
+                       ERR("CM does not connected correctly");
+                       __pan_set_property(wo, XSTR(W_SERVICE_TYPE_BT_PAN),
+                                       XSTR(W_SERVICE_STATE_DISCONNECTED));
+                       return;
+               }
+
+               ret = _pan_bearer_request_pan_configuration(wo, TRUE);
+               if (ret < 0)
+                       ERR("Failed pan configuration on");
+               else
+                       DBG("Requested pan configuration on");
+       } else if (g_strcmp0(resp, "CANCEL") == 0) {
+               __pan_set_property(wo, XSTR(W_SERVICE_TYPE_BT_PAN),
+                               XSTR(W_SERVICE_STATE_DISCONNECTED));
+       }
+}
+
+static void _pan_disconnect_cb(service_h request,
+               service_h reply, service_result_e result, void *user_data)
+{
+       int ret;
+       char *resp = NULL;
+       const char *connected = NULL;
+       WcObject *wo = (WcObject *)user_data;
+
+       if (!wo) {
+               ERR("WcObject is NULL");
+               return;
+       }
+
+       if (result != SERVICE_RESULT_SUCCEEDED) {
+               ERR("service reply failed = [%d]", result);
+               return;
+       }
+
+       ret = service_get_extra_data(reply, "_WCPOPUP_RESP_", &resp);
+       if (ret != SERVICE_ERROR_NONE) {
+               ERR("failed to retrieve response = [%d]", ret);
+               return;
+       }
+
+       if (g_strcmp0(resp, "OK") == 0) {
+               ret = _pan_disconnect(wo);
+               if (ret < 0)
+                       ERR("Failed pan connect");
+       } else if (g_strcmp0(resp, "CANCEL") == 0) {
+               connected = (const char *)g_hash_table_lookup(
+                               wc_object_peek_property_hash(wo), XSTR(W_SERVICE_TYPE_BT_SPP));
+               if (g_strcmp0(connected, XSTR(W_SERVICE_STATE_CONNECTED)) == 0) {
+                       __pan_set_property(wo, XSTR(W_SERVICE_TYPE_BT_PAN),
+                                       XSTR(W_SERVICE_STATE_CONNECTED));
+               }
+       }
+}
+
+static void __notify_bt_service_state_changed(const char *state, void *user_data)
+{
+       static wc_technology_service_state_e pan_service_state_old = 0;
+
+       WcObject *wo = (WcObject *)user_data;
+       if (!wo)
+               return;
+
+       if (!state) {
+               ERR("state is NULL");
+               return;
+       }
+
+       DBG("bt_service_state_changed : %s", state);
+
+       if (g_strcmp0(state, "idle") == 0) {
+               pan_service_state_old = WC_SERVICE_STATE_IDLE;
+       } else if (g_strcmp0(state, "disconnect") == 0) {
+               if (pan_service_state_old > WC_SERVICE_STATE_DISCONNECTED) {
+                       __pan_set_property(wo, XSTR(W_SERVICE_TYPE_BT_PAN),
+                                       XSTR(W_SERVICE_STATE_DISCONNECTED));
+               }
+               pan_service_state_old = WC_SERVICE_STATE_DISCONNECTED;
+       } else if (g_strcmp0(state, "failure") == 0) {
+               if (pan_service_state_old > WC_SERVICE_STATE_DISCONNECTED) {
+                       __pan_set_property(wo, XSTR(W_SERVICE_TYPE_BT_PAN),
+                                       XSTR(W_SERVICE_STATE_DISCONNECTED));
+               }
+               pan_service_state_old = WC_SERVICE_STATE_FAILURE;
+       } else if (g_strcmp0(state, "association") == 0) {
+               pan_service_state_old = WC_SERVICE_STATE_ASSOCIATION;
+       } else if (g_strcmp0(state, "configuration") == 0) {
+               pan_service_state_old = WC_SERVICE_STATE_CONFIGURATION;
+       } else if (g_strcmp0(state, "ready") == 0) {
+               if (pan_service_state_old < WC_SERVICE_STATE_READY) {
+                       __pan_set_property(wo, XSTR(W_SERVICE_TYPE_BT_PAN),
+                                       XSTR(W_SERVICE_STATE_CONNECTED));
+               }
+               pan_service_state_old = WC_SERVICE_STATE_READY;
+       } else if (g_strcmp0(state, "online") == 0) {
+               if (pan_service_state_old < WC_SERVICE_STATE_READY) {
+                       __pan_set_property(wo, XSTR(W_SERVICE_TYPE_BT_PAN),
+                                       XSTR(W_SERVICE_STATE_CONNECTED));
+               }
+               pan_service_state_old = WC_SERVICE_STATE_ONLINE;
+       }
+}
+
+static void __handle_service_state_changed(const gchar *path,
+               const char *key, const char *state, void *user_data)
+{
+       weconn_device_type_e device_type;
+
+       if (path == NULL || key == NULL || state == NULL)
+               return;
+
+       device_type = wc_device_get_type_from_path(path);
+       switch (device_type) {
+       case W_DEVICE_TYPE_BT:
+               __notify_bt_service_state_changed(state, user_data);
+               break;
+       case W_DEVICE_TYPE_CELLULAR:
+               break;
+       case W_DEVICE_TYPE_WIFI:
+               break;
+       case W_DEVICE_TYPE_WIFI_P2P:
+               break;
+       case W_DEVICE_TYPE_WIFI_ADHOC:
+               break;
+       case W_DEVICE_TYPE_ETHERNET:
+               break;
+       default:
+               break;
+       }
+}
+
+static void __pan_connman_service_signal_filter(GDBusConnection *conn,
+               const gchar *name, const gchar *path, const gchar *interface,
+               const gchar *sig, GVariant *param, gpointer user_data)
+{
+       const char *key = NULL;
+       const char *value = NULL;
+       GVariant *var;
+
+       if (g_strcmp0(sig, CONNMAN_SIGNAL_PROPERTY_CHANGED) == 0) {
+               g_variant_get(param, "(sv)", &key, &var);
+
+               if (g_strcmp0(key, "State") == 0) {
+                       g_variant_get(var, "s", &value);
+                       __handle_service_state_changed(path, key, value, user_data);
+               } else if (g_strcmp0(key, "Error") == 0) {
+                       g_variant_get(var, "s", &value);
+                       ERR("Error (%s)", value);
+               }
+
+               g_free((gchar *)value);
+               g_free((gchar *)key);
+               if (var != NULL)
+                       g_variant_unref(var);
+       } else {
+               ERR("No handle signal(%s)", sig);
+       }
+}
+
+static int pan_bearer_init(WcObject *wo)
+{
+       GError *error = NULL;
+       GDBusConnection *connection = NULL;
+       guint id;
+
+       _pan_bearer_register_events(wo);
+
+       connection = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error);
+       if (!connection) {
+               ERR("Failed to get system bus %s", error->message);
+               g_error_free(error);
+               return -1;
+       }
+
+       id = g_dbus_connection_signal_subscribe(
+                       connection,
+                       CONNMAN_SERVICE,
+                       CONNMAN_SERVICE_INTERFACE,
+                       CONNMAN_SIGNAL_PROPERTY_CHANGED,
+                       NULL,
+                       "State",
+                       G_DBUS_SIGNAL_FLAGS_NONE,
+                       __pan_connman_service_signal_filter,
+                       wo,
+                       NULL);
+
+       if (id == 0) {
+               ERR("Failed register signals (%d)", id);
+               return -1;
+       }
+
+       weconn_conn_subscribe_id_connman_state = id;
+
+       return 0;
+}
+
+static int pan_bearer_connect(WcObject *wo, const char *address)
+{
+       int err = -EIO;
+       char *connected = NULL;
+       weconn_service_state_e state;
+
+       if (!wo)
+               return -EINVAL;
+
+       connected = wc_object_get_property(wo, WC_OBJECT_EVENT_SAP_BCMSERVICE_STATUS);
+       if (connected != NULL) {
+               if (g_strcmp0(connected, XSTR(W_SERVICE_STATE_CONNECTED)) != 0) {
+                       ERR("CM does not connected correctly");
+                       g_free(connected);
+                       return -EIO;
+               }
+               g_free(connected);
+       }
+
+
+       state = _get_pan_state(wo);
+       if (state == W_SERVICE_STATE_CONNECTING) {
+               DBG("InProgress...");
+               return -EINPROGRESS;
+       } else if (state == W_SERVICE_STATE_CONNECTED) {
+               DBG("already connected");
+               return -EISCONN;
+       }
+
+       err = wc_launch_popup(WC_POPUP_TYPE_PAN_CONNECT, _pan_connect_cb, wo);
+       if (err < 0)
+               ERR("failed launch pan popup");
+
+       return err;
+}
+
+static int pan_bearer_disconnect(WcObject *wo)
+{
+       int err = -EIO;
+       weconn_service_state_e state;
+
+       state = _get_pan_state(wo);
+       if (state == W_SERVICE_STATE_CONNECTING) {
+               DBG("InProgress...");
+               return -EINPROGRESS;
+       } else if (state == W_SERVICE_STATE_DISCONNECTED) {
+               DBG("Not connected");
+               return -ENOTCONN;
+       }
+
+       err = wc_launch_popup(WC_POPUP_TYPE_PAN_DISCONNECT, _pan_disconnect_cb, wo);
+       if (err < 0)
+               ERR("failed launch pan popup");
+
+       return err;
+}
+
+static void pan_bearer_exit(WcObject *wo)
+{
+       GError *error = NULL;
+       GDBusConnection *connection = NULL;
+
+       DBG("Unloaded");
+
+       connection = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error);
+       if (!connection) {
+               ERR("Failed to get system bus %s", error->message);
+               g_error_free(error);
+               return;
+       }
+
+       g_dbus_connection_signal_unsubscribe(connection,
+                       weconn_conn_subscribe_id_connman_state);
+}
+
+EXPORT_API struct bearer_driver_desc bearer_driver_desc = {
+               .name = "pan",
+               .technology = WC_TECHNOLOGY_BLUETOOTH,
+
+               .init = pan_bearer_init,
+               .connect = pan_bearer_connect,
+               .disconnect = pan_bearer_disconnect,
+               .exit = pan_bearer_exit,
+};
diff --git a/plugins/plugin.h b/plugins/plugin.h
new file mode 100644 (file)
index 0000000..35cb80a
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Wearable device Connection Controller Framework
+ *
+ * Copyright (c) 2013 - 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __WECONN_PLUGIN_H__
+#define __WECONN_PLUGIN_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <errno.h>
+
+#include "log.h"
+#include "dbus.h"
+#include "util.h"
+#include "events.h"
+#include "object.h"
+#include "technology.h"
+
+struct bearer_driver_desc {
+       const char *name;
+       const char *technology;
+
+       int (*init)(WcObject *wcdrv);
+       int (*activate)(WcObject *wcdrv);
+       int (*deactivate)(WcObject *wcdrv);
+       int (*connect)(WcObject *wcdrv, const char *address);
+       int (*disconnect)(WcObject *wcdrv);
+       void (*exit)(WcObject *wcdrv);
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __WECONN_PLUGIN_H__ */
diff --git a/resources/etc/dbus-1/system.d/weconn.conf b/resources/etc/dbus-1/system.d/weconn.conf
new file mode 100644 (file)
index 0000000..b7a275f
--- /dev/null
@@ -0,0 +1,21 @@
+<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
+       "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
+       <policy user="0">
+               <allow own="net.weconn"/>
+               <allow send_destination="net.weconn"/>
+               <allow send_interface="net.weconn.Service"/>
+               <allow send_interface="net.netcon.Technology"/>
+       </policy>
+       <policy user="5000">
+               <allow own="net.weconn"/>
+               <allow send_destination="net.weconn"/>
+               <allow send_interface="net.netconfig.Service"/>
+               <allow send_interface="net.netconfig.Technology"/>
+       </policy>
+       <policy at_console="true">
+               <allow send_destination="net.weconn"/>
+       </policy>
+       <policy context="default">
+               <deny send_destination="net.weconn"/>
+       </policy>
+</busconfig>
diff --git a/resources/etc/opt/upgrade/500.net.weconn.patch.sh b/resources/etc/opt/upgrade/500.net.weconn.patch.sh
new file mode 100755 (executable)
index 0000000..6e1fc6d
--- /dev/null
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+#vconf
+if [ ! -e /opt/var/kdb/memory/private/weconn/all_connected ]; then
+/usr/bin/vconftool set -tf int memory/private/weconn/all_connected 0 -s system::vconf_network -i
+fi
diff --git a/resources/mdbus2 b/resources/mdbus2
new file mode 100755 (executable)
index 0000000..e36f4c7
Binary files /dev/null and b/resources/mdbus2 differ
diff --git a/resources/usr/lib/systemd/system/weconn.service b/resources/usr/lib/systemd/system/weconn.service
new file mode 100644 (file)
index 0000000..2ff8446
--- /dev/null
@@ -0,0 +1,11 @@
+[Unit]
+Description=Wearable device connection controller
+
+[Service]
+Type=forking
+BusName=net.weconn
+ExecStart=/usr/sbin/weconnd
+Restart=always
+
+[Install]
+WantedBy=multi-user.target
diff --git a/resources/usr/share/appcessory/wearable-connection.xml b/resources/usr/share/appcessory/wearable-connection.xml
new file mode 100644 (file)
index 0000000..4f3dffd
--- /dev/null
@@ -0,0 +1,47 @@
+<!DOCTYPE resources [
+<!ELEMENT resources (application)>
+<!ELEMENT application (serviceProfile)+>
+<!ELEMENT supportedTransports (transport)+>
+<!ELEMENT serviceProfile (supportedTransports, serviceChannel+)>
+<!ELEMENT transport EMPTY>
+<!ELEMENT serviceChannel EMPTY>
+<!ATTLIST application name CDATA #REQUIRED>
+<!ATTLIST application xmlns:android CDATA #IMPLIED>
+<!ATTLIST serviceProfile xmlns:android CDATA #IMPLIED>
+<!ATTLIST serviceProfile serviceImpl CDATA #REQUIRED>
+<!ATTLIST serviceProfile role (provider | consumer) #REQUIRED>
+<!ATTLIST serviceProfile name CDATA #REQUIRED>
+<!ATTLIST serviceProfile id CDATA #REQUIRED>
+<!ATTLIST serviceProfile version CDATA #REQUIRED>
+<!ATTLIST serviceProfile serviceLimit (ANY | ONE_ACCESSORY | ONE_PEERAGENT | any | one_accessory | one_peeragent) "ANY">
+<!ATTLIST serviceProfile serviceTimeout CDATA #IMPLIED>
+<!ATTLIST supportedTransports xmlns:android CDATA #IMPLIED>
+<!ATTLIST transport xmlns:android CDATA #IMPLIED>
+<!ATTLIST transport type (TRANSPORT_WIFI | TRANSPORT_BT | TRANSPORT_BLE | TRANSPORT_USB | transport_wifi | transport_bt | transport_ble | transport_usb) #REQUIRED>
+<!ATTLIST serviceChannel xmlns:android CDATA #IMPLIED>
+<!ATTLIST serviceChannel id CDATA #REQUIRED>
+<!ATTLIST serviceChannel dataRate (Low | High | low | high) #REQUIRED>
+<!ATTLIST serviceChannel priority (Low | Medium | High | low | medium | high) #REQUIRED>
+<!ATTLIST serviceChannel reliability (enable | disable | ENABLE | DISABLE) #REQUIRED>
+]>
+
+
+<resources>
+       <application name="/usr/sbin/weconnd">
+               <serviceProfile
+               id="/system/bcmservice"
+               name="BCMService"
+               role="Provider"
+               serviceImpl="/usr/sbin/weconnd"
+               version="1.0">
+                       <supportedTransports>
+                               <transport type="TRANSPORT_BT"/>
+                       </supportedTransports>
+                       <serviceChannel
+                       id="222"
+                       dataRate="Low"
+                       priority="Low"
+                       reliability="disable"/>
+               </serviceProfile>
+       </application>
+</resources>
diff --git a/resources/usr/share/dbus-1/services/net.weconn.service b/resources/usr/share/dbus-1/services/net.weconn.service
new file mode 100644 (file)
index 0000000..3b00181
--- /dev/null
@@ -0,0 +1,5 @@
+[D-BUS Service]
+Name=net.weconn
+Exec=/bin/false
+User=root
+SystemdService=weconn.service
diff --git a/src/control/control.c b/src/control/control.c
new file mode 100644 (file)
index 0000000..2b2164a
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+ * Wearable device Connection Controller Framework
+ *
+ * Copyright (c) 2013 - 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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 <errno.h>
+
+#include "control.h"
+#include "driver.h"
+
+struct wc_control {
+       int device_type;
+       const GSList *driver_list;
+};
+
+static WcObject *wo_control;
+
+static gboolean on_spp_connected(WcObject *wo_control, const void *event_info,
+               void *user_data)
+{
+       int ret;
+       WcObject *wo_bearer = (WcObject*)user_data;
+
+       /* FIXME: when spp is connected, what do you want to activate here? */
+       ret = wc_bearer_driver_activate(wo_bearer, "correct name");
+       DBG("activate request: %d", ret);
+
+       return TRUE;
+}
+
+static gboolean on_bearer_created(WcObject *wo_bearer, const void *event_info,
+               void *user_data)
+{
+       const char *name = NULL;
+
+       if (!wo_bearer) {
+               DBG("no bearer object!!");
+               return FALSE;
+       }
+
+       name = wc_object_get_name(wo_bearer);
+
+       if (!name)
+               return FALSE;
+
+       /* FIXME: it doesn't work correctly */
+       if (g_strcmp0(name, "eSAP") == 0) {
+               int ret;
+               ret = wc_object_add_callback(wo_control,
+                               WC_BEARER_EVENT_BT_CONNECTED_SPP, on_spp_connected, wo_bearer);
+               DBG("add callback for SPP connection: %d", ret);
+       } else {
+               DBG("%s bearer added", name);
+       }
+
+       return TRUE;
+}
+
+int wc_control_add_bearer(WcObject *wo_bearer)
+{
+       /* FIXME: controller is a one of bearer?? what does that mean? */
+       wc_object_add_callback(wo_bearer, WC_OBJECT_EVENT_BEARER_ENABLED,
+                       on_bearer_created, NULL);
+
+       return 0;
+}
+
+WcObject *wc_control_get_object(void)
+{
+       if (!wo_control) {
+               ERR("control object is NULL !!");
+               return NULL;
+       }
+
+       return wo_control;
+}
+
+EXPORT_API int wc_control_get_device_type(void)
+{
+       struct wc_control *cd = NULL;
+
+       if (!wo_control)
+               return -EINVAL;
+
+       cd = wc_object_get_element(wo_control, "control_driver");
+       if (cd)
+               return cd->device_type;
+
+       return -EINVAL;
+}
+
+int control_init(void)
+{
+       struct wc_control *cd = NULL;
+       
+       wo_control = wc_object_new("control", WC_OBJECT_TYPE_CONTROL);
+       if (!wo_control)
+               return -ENOMEM;
+
+       cd = g_try_new0 (struct wc_control, 1);
+       if (!cd)
+               return -ENOMEM;
+
+       /* FIXME */
+       /* TBD: determine current mode Host or Wearable */
+       cd->device_type = PROP_CONTROL_TYPE_WEARABLE;
+       wc_object_append_element(wo_control, "control_driver", cd);
+
+       /*
+        * TODO: According to the various wearable device scenarios,
+        *       each control should be implemented.
+        *
+        *       All of controls are based on wearable device scenarios.
+        */
+       DBG("control init success.");
+
+       return 0;
+}
+
+static void __clean_control_elements(WcObject *wo,
+               const char *element_name, void *element, void *user_data)
+{
+       g_free((gpointer)element_name);
+       g_free(element);
+}
+
+void control_cleanup(void)
+{
+       if (!wo_control)
+               return;
+
+       WC_OBJECT_CHECK(wo_control, WC_OBJECT_TYPE_CONTROL);
+
+       wc_object_foreach_get_elements(wo_control, __clean_control_elements, NULL);
+
+       wc_object_free(wo_control);
+}
diff --git a/src/dbus.c b/src/dbus.c
new file mode 100644 (file)
index 0000000..ebaf356
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * Wearable device Connection Controller Framework
+ *
+ * Copyright (c) 2013 - 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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 <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "log.h"
+#include "dbus.h"
+
+static GDBusConnection *__connection = NULL;
+static GDBusObjectManagerServer *__object_manager_server = NULL;
+
+
+static void __request_name_cb(GDBusConnection *conn, const gchar *name,
+               gpointer user_data)
+{
+       void (*__init_cb)(void) = user_data;
+
+       /* Successfully register DBus name */
+       __connection = conn;
+
+       g_dbus_object_manager_server_set_connection(__object_manager_server, conn);
+
+       if (__init_cb)
+               __init_cb();
+}
+
+static void __lost_name_cb(GDBusConnection *conn, const gchar *name,
+               gpointer user_data)
+{
+       /* May service name is already in use */
+       ERR("Service name is already in use");
+
+       /* The result of DBus name request is only permitted,
+        *  such as DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER.
+        */
+       exit(1);
+}
+
+GDBusConnection *dbus_get_connection(void)
+{
+       return __connection;
+}
+
+const char *dbus_name2path(const char *name)
+{
+       size_t len, i, j;
+       char *buf;
+       char hex[3];
+
+       if (!name)
+               return NULL;
+
+       len = strlen(name);
+       if (len == 0)
+               return NULL;
+
+       buf = g_malloc0(len * 4);
+       if (!buf)
+               return NULL;
+
+       for (i = 0, j = 0; i < len; i++) {
+               if (g_ascii_isalnum(name[i]) || name[i] == '_' || name[i] == '/') {
+                       buf[j] = name[i];
+                       j++;
+               } else {
+                       snprintf(hex, 3, "%02X", name[i]);
+                       buf[j++] = '_';
+                       buf[j++] = hex[0];
+                       buf[j++] = hex[1];
+                       buf[j++] = '_';
+               }
+       }
+
+       return buf;
+}
+
+int dbus_init(GBusType bus_type, const char *bus_name, const char *obj_path,
+               void (*__init_cb)(void))
+{
+       guint id;
+
+       __object_manager_server = g_dbus_object_manager_server_new(obj_path);
+       if (!__object_manager_server)
+               return -ENOMEM;
+
+       id = g_bus_own_name(bus_type, bus_name, G_BUS_NAME_OWNER_FLAGS_NONE, NULL,
+                       __request_name_cb, __lost_name_cb, __init_cb, NULL);
+       if (id == 0) {
+               ERR("Failed to get system bus");
+               return -EIO;
+       }
+
+       return 0;
+}
+
+void dbus_cleanup(void)
+{
+       g_object_unref(__object_manager_server);
+       __object_manager_server = NULL;
+
+       g_object_unref(__connection);
+       __connection = NULL;
+}
diff --git a/src/driver.c b/src/driver.c
new file mode 100644 (file)
index 0000000..a734d6d
--- /dev/null
@@ -0,0 +1,290 @@
+/*
+ * Wearable device Connection Controller Framework
+ *
+ * Copyright (c) 2013 - 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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 <dlfcn.h>
+#include <errno.h>
+#include <gio/gio.h>
+
+#include "dbus.h"
+#include "driver.h"
+#include "technology.h"
+#include "plugins/plugin.h"
+
+#include "generated-code.h"
+
+struct bearer_driver {
+       const struct bearer_driver_desc *desc;
+
+       const char *path;
+       void *user_data;
+       void *handle;
+};
+
+static GSList *driver_list;
+
+/* TIP: driver is an element of WcObject
+ *      For example, there might be a bluetooth WcObject,
+ *      which has bluetooth, esap and pan elements.
+ */
+
+static WcObject *wc_bearer_driver_new(const char *filename,
+               const struct bearer_driver_desc *desc, void *dl_handle)
+{
+       int err;
+       WcObject *wo;
+       struct bearer_driver *bd;
+
+       wo = wc_object_find(desc->technology);
+       if (!wo) {
+               wo = wc_object_new(desc->technology, WC_OBJECT_TYPE_BEARER_DRIVER);
+               if (!wo)
+                       return NULL;
+       }
+
+       bd = g_try_new0(struct bearer_driver, 1);
+       if (!bd)
+               return NULL;
+
+       bd->desc = desc;
+       bd->handle = dl_handle;
+       bd->path = g_strdup(filename);
+
+       err = wc_object_append_element(wo, desc->name, bd);
+       if (err < 0)
+               g_free(bd);
+
+       return wo;
+}
+
+static void wc_bearer_driver_free(struct bearer_driver *bd)
+{
+       if (!bd)
+               return;
+
+       g_free((gpointer)bd->path);
+       dlclose(bd->handle);
+       g_free(bd);
+}
+
+static int __add_bearer(const char *filename, gpointer handle)
+{
+       GSList *list;
+       WcObject *wo;
+       struct bearer_driver_desc *desc;
+
+       desc = dlsym(handle, "bearer_driver_desc");
+       if (!desc)
+               return -EIO;
+
+       wo = wc_bearer_driver_new(filename, desc, handle);
+       if (!wo)
+               return -ENOMEM;
+
+       wc_technology_add_bearer(wo);
+
+       wc_bearer_driver_init(wo, desc->name);
+
+       /* Check already registered */
+       for (list = driver_list; list; list = list->next) {
+               if (wo == list->data) {
+                       DBG("driver %s, %p, %p, %s(%s) registered",
+                                       filename, desc, handle, desc->technology, desc->name);
+
+                       return -EALREADY;
+               }
+       }
+
+       driver_list = g_slist_append(driver_list, wo);
+
+       DBG("driver %s, %p, %p, %s(%s) created",
+                       filename, desc, handle, desc->technology, desc->name);
+
+       return 0;
+}
+
+int wc_bearer_driver_init(WcObject *wo, const char *desc_name)
+{
+       struct bearer_driver *bd;
+
+       WC_OBJECT_CHECK_RETURN(wo, WC_OBJECT_TYPE_BEARER_DRIVER, -EINVAL);
+
+       bd = wc_object_get_element(wo, desc_name);
+       if (!bd)
+               return -EINVAL;
+
+       if (bd->desc->init)
+               return bd->desc->init(wo);
+
+       return -ENXIO;
+}
+
+int wc_bearer_driver_activate(WcObject *wo, const char *desc_name)
+{
+       struct bearer_driver *bd;
+
+       WC_OBJECT_CHECK_RETURN(wo, WC_OBJECT_TYPE_BEARER_DRIVER, -EINVAL);
+
+       bd = wc_object_get_element(wo, desc_name);
+       if (!bd)
+               return -EINVAL;
+
+       if (bd->desc->activate)
+               return bd->desc->activate(wo);
+
+       return -ENXIO;
+}
+
+int wc_bearer_driver_deactivate(WcObject *wo, const char *desc_name)
+{
+       struct bearer_driver *bd;
+
+       WC_OBJECT_CHECK_RETURN(wo, WC_OBJECT_TYPE_BEARER_DRIVER, -EINVAL);
+
+       bd = wc_object_get_element(wo, desc_name);
+       if (!bd)
+               return -EINVAL;
+
+       if (bd->desc->deactivate)
+               return bd->desc->deactivate(wo);
+
+       return -ENXIO;
+}
+
+int wc_bearer_driver_connect(WcObject *wo, const char *address,
+               const char *desc_name)
+{
+       struct bearer_driver *bd;
+
+       WC_OBJECT_CHECK_RETURN(wo, WC_OBJECT_TYPE_BEARER_DRIVER, -EINVAL);
+
+       bd = wc_object_get_element(wo, desc_name);
+       if (!bd)
+               return -EINVAL;
+
+       if (bd->desc->connect)
+               return bd->desc->connect(wo, address);
+
+       return -ENXIO;
+}
+
+int wc_bearer_driver_disconnect(WcObject *wo, const char *desc_name)
+{
+       struct bearer_driver *bd;
+
+       WC_OBJECT_CHECK_RETURN(wo, WC_OBJECT_TYPE_BEARER_DRIVER, -EINVAL);
+
+       bd = wc_object_get_element(wo, desc_name);
+       if (!bd)
+               return -EINVAL;
+
+       if (bd->desc->disconnect)
+               return bd->desc->disconnect(wo);
+
+       return -ENXIO;
+}
+
+void wc_bearer_driver_exit(WcObject *wo, const char *desc_name)
+{
+       struct bearer_driver *bd;
+
+       WC_OBJECT_CHECK(wo, WC_OBJECT_TYPE_BEARER_DRIVER);
+
+       bd = wc_object_get_element(wo, desc_name);
+       if (!bd)
+               return;
+
+       if (bd->desc->exit)
+               bd->desc->exit(wo);
+}
+
+int driver_init(const char *driver_path)
+{
+       int err;
+       void *h;
+       GDir *dir;
+       char *filename;
+       const gchar *file;
+
+       if (!driver_path)
+               return -EINVAL;
+
+       dir = g_dir_open(driver_path, 0, NULL);
+       if (!dir) {
+               ERR("Failed to open driver(%s)", driver_path);
+               return -EIO;
+       }
+
+       while ((file = g_dir_read_name(dir)) != NULL) {
+               if (g_str_has_prefix(file, "lib") == TRUE ||
+                               g_str_has_suffix(file, ".so") == FALSE)
+                       continue;
+
+               filename = g_build_filename(driver_path, file, NULL);
+
+               h = dlopen(filename, RTLD_NOW);
+               if (!h) {
+                       ERR("Failed to open (%s) %s", filename, dlerror());
+                       g_free(filename);
+                       continue;
+               }
+
+               err = __add_bearer(filename, h);
+               if (err < 0 && err != -EALREADY)
+                       dlclose(h);
+
+               g_free(filename);
+       }
+
+       g_dir_close(dir);
+
+       return 0;
+}
+
+static void __clean_bearer_driver_elements(WcObject *wo,
+               const char *element_name, void *element, void *user_data)
+{
+       struct bearer_driver *bd = (struct bearer_driver *)element;
+
+       wc_bearer_driver_exit(wo, element_name);
+
+       wc_bearer_driver_free(bd);
+
+       g_free((gpointer)element_name);
+       g_free(element);
+}
+
+static void __clean_bearer_drivers(gpointer data)
+{
+       WcObject *wo = data;
+
+       if (!wo)
+               return;
+
+       WC_OBJECT_CHECK(wo, WC_OBJECT_TYPE_BEARER_DRIVER);
+
+       wc_object_foreach_get_elements(wo, __clean_bearer_driver_elements, NULL);
+
+       wc_object_unexport(wo);
+       wc_object_free(wo);
+}
+
+void driver_cleanup(void)
+{
+       g_slist_free_full(driver_list, __clean_bearer_drivers);
+}
diff --git a/src/error.c b/src/error.c
new file mode 100644 (file)
index 0000000..783153d
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Wearable device Connection Controller Framework
+ *
+ * Copyright (c) 2013 - 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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 <stdio.h>
+#include <stdarg.h>
+
+#include "log.h"
+#include "error.h"
+
+static char *__error_message;
+
+void wc_error_add(const char *msg, ...)
+{
+       va_list ap;
+       gchar buf[1024] = { 0, };
+       char *new_message;
+
+       va_start(ap, msg);
+       vsnprintf(buf, 1023, msg, ap);
+       va_end(ap);
+
+       if (__error_message) {
+               new_message = g_strdup_printf("%s; %s", __error_message, buf);
+
+               g_free(__error_message);
+               __error_message = new_message;
+       } else
+               __error_message = g_strdup(buf);
+
+       ERR("%s", __error_message);
+}
+
+void wc_error_return(GDBusMethodInvocation *invocation)
+{
+       if (!invocation)
+               return;
+
+       if (!__error_message)
+               g_dbus_method_invocation_return_error(invocation, G_DBUS_ERROR,
+                               G_DBUS_ERROR_FAILED, "No error message");
+       else
+               g_dbus_method_invocation_return_error(invocation, G_DBUS_ERROR,
+                               G_DBUS_ERROR_FAILED, __error_message);
+
+       g_free(__error_message);
+       __error_message = NULL;
+}
diff --git a/src/main.c b/src/main.c
new file mode 100644 (file)
index 0000000..3ed7d0a
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * Wearable device Connection Controller Framework
+ *
+ * Copyright (c) 2013 - 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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 <errno.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+#include "log.h"
+#include "dbus.h"
+#include "driver.h"
+#include "control.h"
+#include "service.h"
+#include "technology.h"
+
+
+static void __on_log_glib(const gchar *log_domain, GLogLevelFlags log_level,
+               const gchar *msg, gpointer user_data)
+{
+       ERR("glib %s", msg);
+}
+
+static void __init(void)
+{
+       technology_init();
+
+       service_init();
+
+       control_init();
+
+       driver_init(WECONN_PLUGIN_PATH);
+}
+
+static void __cleanup(void)
+{
+       control_cleanup();
+
+       driver_cleanup();
+
+       service_cleanup();
+
+       technology_cleanup();
+}
+
+int main (int argc, char *argv[])
+{
+       int err;
+       GMainLoop *main_loop;
+
+       umask(0077);
+
+       DBG("Wearable Connection Controller %s", VERSION);
+
+       if (daemon(0, 0) != 0)
+               DBG("Cannot start daemon");
+
+       g_type_init();
+
+#if 0
+       g_log_set_always_fatal(
+                       G_LOG_FATAL_MASK | G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING);
+#endif
+
+       g_log_set_default_handler(__on_log_glib, NULL);
+
+       main_loop = g_main_loop_new(NULL, FALSE);
+
+       err = dbus_init(G_BUS_TYPE_SYSTEM, WECONN_SERVICE_DBUS, WECONN_PATH_DBUS,
+                       __init);
+       if (err < 0)
+               return -1;
+
+       g_main_loop_run(main_loop);
+
+       __cleanup();
+
+       dbus_cleanup();
+
+       return 0;
+}
diff --git a/src/object.c b/src/object.c
new file mode 100644 (file)
index 0000000..d828f42
--- /dev/null
@@ -0,0 +1,582 @@
+/*
+ * Wearable device Connection Controller Framework
+ *
+ * Copyright (c) 2013 - 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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 <errno.h>
+#include <stdarg.h>
+
+#include "log.h"
+#include "dbus.h"
+#include "error.h"
+#include "events.h"
+#include "object.h"
+
+#include "weconn_type.h"
+
+struct wc_callback_type {
+       const char *event;
+       WcObjectCallback callback;
+       void *user_data;
+};
+
+struct wc_element_type {
+       const char *element_name;
+       void *element;
+};
+
+struct wc_object {
+       const char *name;
+       unsigned int type;
+
+       GSList *element_list;
+
+       GSList *callbacks;
+       GHashTable *property;
+       void *user_data;
+
+       char *service_connecting;
+       guint timeout_connecting;
+       char *service_disconnecting;
+       guint timeout_disconnecting;
+
+       GDBusInterfaceSkeleton *di;
+};
+
+static GSList *object_list;
+
+EXPORT_API WcObject *wc_object_new(const char *name, unsigned int type)
+{
+       struct wc_object *wo;
+
+       if (!name)
+               return NULL;
+
+       wo = g_try_new0(struct wc_object, 1);
+       if (!wo)
+               return NULL;
+
+       wo->name = g_strdup(name);
+       wo->type = type;
+       wo->property = g_hash_table_new_full(g_str_hash, g_str_equal,
+                                                               g_free, g_free);
+
+       object_list = g_slist_append(object_list, wo);
+
+       return wo;
+}
+
+EXPORT_API void wc_object_free(WcObject *wo)
+{
+       GSList *list = NULL;
+       struct wc_callback_type *wcb = NULL;
+       struct wc_element_type *we;
+
+       if (!wo)
+               return;
+
+       g_free((gpointer)wo->name);
+       g_object_unref(wo->di);
+       g_hash_table_destroy(wo->property);
+
+       if (wo->callbacks) {
+               for (list = wo->callbacks; list; list = list->next) {
+                       wcb = (struct wc_callback_type *)list->data;
+                       if (!wcb)
+                               continue;
+
+                       if (wcb->event)
+                               g_free((gpointer)wcb->event);
+
+                       g_free(wcb);
+               }
+
+               g_slist_free(wo->callbacks);
+               wo->callbacks = NULL;
+       }
+
+       for (list = wo->element_list; list; list = list->next) {
+               we = (struct wc_element_type *)list->data;
+
+               g_free((gpointer)we->element_name);
+               g_free(we->element);
+       }
+
+       g_slist_free(wo->element_list);
+
+       object_list = g_slist_remove(object_list, wo);
+
+       g_free(wo);
+}
+
+EXPORT_API WcObject *wc_object_find(const char *name)
+{
+       GSList *list = object_list;
+       WcObject *wo;
+
+       if (!name)
+               return NULL;
+
+       while (list) {
+               wo = (WcObject *)list->data;
+               if (g_strcmp0(wo->name, name) == 0)
+                       return wo;
+
+               list = list->next;
+       }
+
+       return NULL;
+}
+
+EXPORT_API const char *wc_object_get_name(WcObject *wo)
+{
+       if (!wo)
+               return NULL;
+
+       return g_strdup(wo->name);
+}
+
+EXPORT_API const char *wc_object_peek_name(WcObject *wo)
+{
+       if (!wo)
+               return NULL;
+
+       return wo->name;
+}
+
+EXPORT_API unsigned int wc_object_get_type(WcObject *wo)
+{
+       if (!wo)
+               return 0;
+
+       return wo->type;
+}
+
+EXPORT_API int wc_object_append_element(WcObject *wo,
+               const char *element_name, void *element)
+{
+       GSList *list;
+       struct wc_element_type *we;
+
+       if (!wo || !element_name)
+               return -EINVAL;
+
+       if (strlen(element_name) < 1)
+               return -EINVAL;
+
+       /* Check already registered */
+       for (list = wo->element_list; list; list = list->next) {
+               we = (struct wc_element_type *)list->data;
+
+               if (we && g_strcmp0(element_name, we->element_name) == 0)
+                       return -EALREADY;
+       }
+
+       we = g_try_new0(struct wc_element_type, 1);
+       if (!we)
+               return -ENOMEM;
+
+       we->element_name = g_strdup(element_name);
+       we->element = element;
+
+       wo->element_list = g_slist_append(wo->element_list, we);
+
+       return 0;
+}
+
+EXPORT_API void *wc_object_get_element(WcObject *wo, const char *element_name)
+{
+       GSList *list;
+       struct wc_element_type *we;
+
+       if (!wo || !element_name)
+               return NULL;
+
+       if (strlen(element_name) < 1)
+               return NULL;
+
+       for (list = wo->element_list; list; list = list->next) {
+               we = (struct wc_element_type *)list->data;
+
+               if (we && g_strcmp0(element_name, we->element_name) == 0)
+                       return we->element;
+       }
+
+       return NULL;
+}
+
+EXPORT_API int wc_object_foreach_get_elements(WcObject *wo,
+               wc_object_foreach_get_elements_cb callback, void *user_data)
+{
+       GSList *list;
+       struct wc_element_type *we;
+
+       if (!wo || !callback)
+               return -EINVAL;
+
+       for (list = wo->element_list; list; list = list->next) {
+               we = (struct wc_element_type *)list->data;
+
+               callback(wo, we->element_name, we->element, user_data);
+       }
+
+       return 0;
+}
+
+EXPORT_API int wc_object_set_dbus_interface(WcObject *wo,
+               GDBusInterfaceSkeleton *di)
+{
+       if (!wo || !di)
+               return -EINVAL;
+
+       wo->di = di;
+       return 0;
+}
+
+EXPORT_API GDBusInterfaceSkeleton *wc_object_get_dbus_interface(WcObject *wo)
+{
+       if (!wo)
+               return NULL;
+
+       return wo->di;
+}
+
+EXPORT_API int wc_object_export(WcObject *wo, const char *path)
+{
+       GError *error = NULL;
+       gboolean ret;
+       const char *real_path = NULL;
+
+       if (!wo || !path)
+               return -EINVAL;
+
+       if (!wo->di)
+               return -EINVAL;
+
+       real_path = dbus_name2path(path);
+
+       if (g_variant_is_object_path(real_path) == FALSE) {
+               wc_error_add("InvalidName %s", real_path);
+               g_free((gpointer)real_path);
+               return -EINVAL;
+       }
+
+       ret = g_dbus_interface_skeleton_export(wo->di, dbus_get_connection(),
+                       real_path, &error);
+       if (ret == FALSE) {
+               if (error) {
+                       wc_error_add("%s", error->message);
+                       g_error_free(error);
+               } else
+                       wc_error_add("DBusObjectPathFailed");
+
+               g_free((gpointer)real_path);
+               return -EIO;
+       }
+
+       wc_object_set_property(wo, "object-path", real_path);
+
+       g_free((gpointer)real_path);
+
+       return 0;
+}
+
+EXPORT_API int wc_object_unexport(WcObject *wo)
+{
+       if (!wo)
+               return -EINVAL;
+
+       if (!wo->di)
+               return -EINVAL;
+
+       g_dbus_interface_skeleton_unexport(wo->di);
+
+       return 0;
+}
+
+EXPORT_API int wc_object_add_callback(WcObject *wo, const char *event,
+               WcObjectCallback callback, void *user_data)
+{
+       GSList *list;
+       struct wc_callback_type *wcb = NULL;
+
+       if (!wo || !event || !callback)
+               return -EINVAL;
+
+       if (strlen(event) < 1)
+               return -EINVAL;
+
+       /* Check already registered */
+       list = wo->callbacks;
+       while (list) {
+               wcb = (struct wc_callback_type *)list->data;
+               if (wcb && wcb->callback == callback && g_strcmp0(wcb->event, event) == 0)
+                       return -EALREADY;
+
+               list = list->next;
+       }
+
+       wcb = g_try_new0(struct wc_callback_type, 1);
+       if (!wcb)
+               return -ENOMEM;
+
+       wcb->event = g_strdup(event);
+       wcb->callback = callback;
+       wcb->user_data = user_data;
+
+       wo->callbacks = g_slist_append(wo->callbacks, wcb);
+
+       return 0;
+}
+
+EXPORT_API int wc_object_del_callback(WcObject *wo, const char *event,
+               WcObjectCallback callback)
+{
+       struct wc_callback_type *wcb = NULL;
+       GSList *l = NULL;
+
+       if (!wo || !event || !callback || !wo->callbacks)
+               return -EINVAL;
+
+       if (strlen(event) < 1)
+               return -EINVAL;
+
+       l = wo->callbacks;
+       while (l) {
+               wcb = l->data;
+               if (!wcb) {
+                       l = l->next;
+                       continue;
+               }
+
+               if (wcb->callback != callback) {
+                       l = l->next;
+                       continue;
+               }
+
+               if (g_strcmp0(wcb->event, event) != 0) {
+                       l = l->next;
+                       continue;
+               }
+
+               l = l->next;
+               wo->callbacks = g_slist_remove(wo->callbacks, wcb);
+               g_free((gpointer)wcb->event);
+               g_free(wcb);
+       }
+
+       return 0;
+}
+
+EXPORT_API int wc_object_emit_callback(WcObject *wo, const char *event,
+               const void *event_info)
+{
+       struct wc_callback_type *wcb = NULL;
+       GSList *l = NULL;
+       size_t event_len;
+
+       if (!wo || !event)
+               return -EINVAL;
+
+       event_len = strlen(event);
+       if (event_len < 1)
+               return -EINVAL;
+
+       l = wo->callbacks;
+       while (l) {
+               wcb = l->data;
+               if (!wcb) {
+                       l = l->next;
+                       continue;
+               }
+
+               if (g_strcmp0(wcb->event, event) != 0) {
+                       l = l->next;
+                       continue;
+               }
+
+               if (wcb->callback) {
+                       int ret = wcb->callback(wo, event_info, wcb->user_data);
+                       if (ret == FALSE) {
+                               l = l->next;
+                               wo->callbacks = g_slist_remove(wo->callbacks, wcb);
+                               continue;
+                       }
+               }
+
+               l = l->next;
+       }
+
+       if (wo->di && event_len > 5 && g_str_has_prefix(event, "dbus-") == TRUE) {
+               /*
+                * if event is 'dbus-xxx', emit dbus signal 'xxx'
+                * but, only support one parameter.
+                *
+                * if you want use multiple parameters,
+                * use g_signal_emit_by_name() directly.
+                */
+               g_signal_emit_by_name(wo->di, event + 5, event_info);
+       }
+
+       return 0;
+}
+
+static GSList *_set_property_real(WcObject *wo, const char *key,
+               const char *value, GSList *list)
+{
+       if (!wo || !key)
+               return list;
+
+       if (!value) {
+               g_hash_table_remove(wo->property, key);
+
+               return g_slist_append(list, (gpointer)key);
+       }
+
+       g_hash_table_replace(wo->property, g_strdup(key), g_strdup(value));
+
+       return g_slist_append(list, (gpointer)key);
+}
+
+EXPORT_API int wc_object_set_property_full(WcObject *wo,
+               const char *first_property, ...)
+{
+       va_list argptr;
+       GSList *list = NULL;
+       const char *k;
+       const char *v;
+
+       if (!wo || !first_property)
+               return -EINVAL;
+
+       va_start(argptr, first_property);
+
+       k = first_property;
+       v = va_arg(argptr, char *);
+       list = _set_property_real(wo, k, v, list);
+
+       while (1) {
+               k = va_arg(argptr, char *);
+               if (!k)
+                       break;
+
+               v = va_arg(argptr, char *);
+               list = _set_property_real(wo, k, v, list);
+       }
+
+       va_end(argptr);
+
+       if (!list)
+               return -ENODATA;
+
+       if (g_slist_length(list) > 0)
+               wc_object_emit_callback(wo, WC_OBJECT_EVENT_PROPERTY_CHANGED, list);
+
+       g_slist_free(list);
+
+       return 0;
+}
+
+EXPORT_API char *wc_object_get_property(WcObject *wo, const char *key)
+{
+       if (!wo || !key)
+               return NULL;
+
+       return g_strdup(g_hash_table_lookup(wo->property, key));
+}
+
+EXPORT_API const char *wc_object_peek_property(WcObject *wo, const char *key)
+{
+       if (!wo || !key)
+               return NULL;
+
+       return g_hash_table_lookup(wo->property, key);
+}
+
+EXPORT_API GHashTable *wc_object_peek_property_hash(WcObject *wo)
+{
+       if (!wo)
+               return NULL;
+
+       return wo->property;
+}
+
+EXPORT_API void wc_object_set_timeout_connecting(WcObject *wo,
+               guint timeout, const char *service)
+{
+       if (!wo)
+               return;
+
+       wo->timeout_connecting = timeout;
+
+       if (wo->service_connecting != NULL) {
+               g_free(wo->service_connecting);
+               wo->service_connecting = NULL;
+       }
+
+       if (service != NULL)
+               wo->service_connecting = g_strdup(service);
+}
+
+EXPORT_API guint wc_object_get_timeout_connecting(WcObject *wo)
+{
+       if (!wo)
+               return 0;
+
+       return wo->timeout_connecting;
+}
+
+EXPORT_API char *wc_object_get_connecting_service(WcObject *wo)
+{
+       if (!wo)
+               return 0;
+
+       return wo->service_connecting;
+}
+
+EXPORT_API void wc_object_set_timeout_disconnecting(WcObject *wo,
+               guint timeout, const char *service)
+{
+       if (!wo)
+               return;
+
+       wo->timeout_disconnecting = timeout;
+
+       if (wo->service_disconnecting != NULL) {
+               g_free(wo->service_disconnecting);
+               wo->service_disconnecting = NULL;
+       }
+
+       if (service != NULL)
+               wo->service_disconnecting = g_strdup(service);
+}
+
+EXPORT_API guint wc_object_get_timeout_disconnecting(WcObject *wo)
+{
+       if (!wo)
+               return 0;
+
+       return wo->timeout_disconnecting;
+}
+
+EXPORT_API char *wc_object_get_disconnecting_service(WcObject *wo)
+{
+       if (!wo)
+               return 0;
+
+       return wo->service_disconnecting;
+}
diff --git a/src/service.c b/src/service.c
new file mode 100644 (file)
index 0000000..88ea4b6
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Wearable device Connection Controller Framework
+ *
+ * Copyright (c) 2013 - 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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 <errno.h>
+#include <gio/gio.h>
+
+#include "log.h"
+#include "dbus.h"
+#include "object.h"
+#include "service.h"
+
+#include "generated-code.h"
+
+static WcObject *wo_service;
+
+int service_init(void)
+{
+       GDBusInterfaceSkeleton *di;
+
+       wo_service = wc_object_new("service", WC_OBJECT_TYPE_SERVICE);
+       if (!wo_service)
+               return -ENOMEM;
+
+       di = G_DBUS_INTERFACE_SKELETON(weconn_service_skeleton_new());
+
+       /* TODO: extend technology to get bearers' properties */
+       wc_object_append_element(wo_service, "service", NULL);
+       wc_object_set_dbus_interface(wo_service, di);
+       wc_object_export(wo_service, WECONN_SERVICE_PATH);
+
+       return 0;
+}
+
+void service_cleanup(void)
+{
+       /* TODO: clean all of services */
+
+       wc_object_unexport(wo_service);
+       wc_object_free(wo_service);
+}
diff --git a/src/technology.c b/src/technology.c
new file mode 100644 (file)
index 0000000..0d3fed4
--- /dev/null
@@ -0,0 +1,640 @@
+/*
+ * Wearable device Connection Controller Framework
+ *
+ * Copyright (c) 2013 - 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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 <errno.h>
+#include <gio/gio.h>
+
+#include "log.h"
+#include "dbus.h"
+#include "util.h"
+#include "error.h"
+#include "driver.h"
+#include "events.h"
+#include "object.h"
+#include "technology.h"
+
+#include "generated-code.h"
+
+#define CONNECT_TIMEOUT                120
+
+static GSList *technology_list = NULL;
+
+static void __dbus_builder_add_sv(gpointer key, gpointer value,
+               gpointer user_data)
+{
+       GVariantBuilder *b = user_data;
+       if (!b)
+               return;
+
+       g_variant_builder_add(b, "{sv}", key, g_variant_new_string(value));
+}
+
+static gboolean __get_properties(GDBusInterfaceSkeleton *di,
+               GDBusMethodInvocation *invocation, gpointer user_data)
+{
+       WcObject *wo = (WcObject *)user_data;
+       GVariant *result = NULL;
+       GVariantBuilder *b;
+
+       DBG("");
+
+       if (!wo) {
+               wc_error_add("InvalidArguments");
+               wc_error_return(invocation);
+               return TRUE;
+       }
+
+       b = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
+
+       g_hash_table_foreach(wc_object_peek_property_hash(wo),
+                                                       __dbus_builder_add_sv, b);
+
+       result = g_variant_builder_end(b);
+
+       g_variant_builder_unref(b);
+
+       g_dbus_method_invocation_return_value(invocation,
+                       g_variant_new("(@a{sv})", result));
+
+       return TRUE;
+}
+
+static gboolean __get_property(GDBusInterfaceSkeleton *di,
+               GDBusMethodInvocation *invocation,
+               const gchar *name, gpointer user_data)
+{
+       gpointer value;
+       WcObject *wo = (WcObject *)user_data;
+       weconn_service_type_e service_type;
+       weconn_device_type_e device_type;
+       const char *default_property = NULL;
+
+       DBG("%s", name);
+
+       if (!wo || !name) {
+               wc_error_add("InvalidArguments");
+               wc_error_return(invocation);
+               return TRUE;
+       }
+
+       service_type = wc_service_type_string2enum(name);
+       if (service_type)
+               default_property = XSTR(W_SERVICE_STATE_DISCONNECTED);
+       else {
+               device_type = wc_device_type_string2enum(name);
+
+               if (device_type)
+                       default_property = XSTR(W_DEVICE_STATE_DISABLED);
+               else {
+                       wc_error_add("InvalidArguments");
+                       wc_error_return(invocation);
+                       return TRUE;
+               }
+       }
+
+       value = g_hash_table_lookup(wc_object_peek_property_hash(wo), name);
+       if (value) {
+               g_dbus_method_invocation_return_value(invocation,
+                               g_variant_new("(v)", g_variant_new_string(value)));
+       } else {
+               g_dbus_method_invocation_return_value(invocation,
+                               g_variant_new("(v)", g_variant_new_string(default_property)));
+       }
+
+       return TRUE;
+}
+
+static gboolean __set_property(GDBusInterfaceSkeleton *di,
+               GDBusMethodInvocation *invocation,
+               const gchar *name, gpointer user_data)
+{
+       WcObject *wo = (WcObject *)user_data;
+
+       DBG("%s", name);
+
+       if (!wo || !name) {
+               wc_error_add("InvalidArguments");
+               wc_error_return(invocation);
+               return TRUE;
+       }
+
+       /* TODO: set property */
+
+       g_dbus_method_invocation_return_value(invocation, g_variant_new("()"));
+
+       return TRUE;
+}
+
+static gboolean __scan(GDBusInterfaceSkeleton *di,
+               GDBusMethodInvocation *invocation, gpointer user_data)
+{
+       WcObject *wo = (WcObject *)user_data;
+
+       DBG("");
+
+       if (!wo) {
+               wc_error_add("InvalidArguments");
+               wc_error_return(invocation);
+               return TRUE;
+       }
+
+       g_dbus_method_invocation_return_value(invocation, g_variant_new("()"));
+
+       return TRUE;
+}
+
+static const char *__service_type_string2_driver_name(const char *service_type)
+{
+       if (g_strcmp0(XSTR(W_SERVICE_TYPE_BT_HFP), service_type) == 0)
+               return "bluetooth";
+       else if (g_strcmp0(XSTR(W_SERVICE_TYPE_BT_SPP), service_type) == 0)
+               return "esap";
+       else if (g_strcmp0(XSTR(W_SERVICE_TYPE_BT_PAN), service_type) == 0)
+               return "pan";
+       else if (g_strcmp0(XSTR(W_SERVICE_TYPE_BT_GATT), service_type) == 0)
+               return "bluetooth";
+       else if (g_strcmp0(XSTR(W_SERVICE_TYPE_CELLULAR), service_type) == 0)
+               return "cellular";
+       else if (g_strcmp0(XSTR(W_SERVICE_TYPE_WIFI), service_type) == 0)
+               return "wifi";
+       else if (g_strcmp0(XSTR(W_SERVICE_TYPE_WIFI_P2P), service_type) == 0)
+               return "p2p";
+       else if (g_strcmp0(XSTR(W_SERVICE_TYPE_WIFI_ADHOC), service_type) == 0)
+               return "adhoc";
+       else if (g_strcmp0(XSTR(W_SERVICE_TYPE_ETHERNET), service_type) == 0)
+               return "ethernet";
+
+       return NULL;
+}
+
+static void __connect_result_emit_signal(WcObject *wo,
+               const gchar *service, const char *signal_name, int result)
+{
+       GDBusConnection *connection = NULL;
+       GError *error = NULL;
+       GVariant *variant = NULL;
+
+       if (!wo)
+               return;
+
+       if (!service) {
+               ERR("service is NULL");
+               return;
+       }
+
+       connection = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error);
+       if (!connection) {
+               ERR("Failed to get system bus[%s]", error->message);
+               g_error_free(error);
+               return;
+       }
+
+       variant = g_variant_new("(si)", service, result);
+
+       g_dbus_connection_emit_signal(connection, NULL,
+                       WECONN_PATH_DBUS, WECONN_TECHNOLOGY_INTERFACE,
+                       signal_name, variant, NULL);
+
+       g_object_unref(connection);
+}
+
+static gboolean __connect_timeout_cb(gpointer user_data)
+{
+       char *service = NULL;
+       char *state = NULL;
+       WcObject *wo = (WcObject *)user_data;
+       if (!wo)
+               return FALSE;
+
+       service = wc_object_get_connecting_service(wo);
+       if (!service)
+               return FALSE;
+
+       state = wc_object_get_property(wo, service);
+       if (state != NULL) {
+               if (g_strcmp0(state, XSTR(W_SERVICE_STATE_DISCONNECTED)) != 0)
+                       wc_object_set_property(wo, service,
+                                       XSTR(W_SERVICE_STATE_DISCONNECTED));
+
+               g_free(state);
+       }
+
+       __connect_result_emit_signal(wo, service,
+                       WECONN_TECHNOLOGY_SIGNAL_CONNECTION_RESULT, -ETIMEDOUT);
+
+       wc_object_set_timeout_connecting(wo, 0, NULL);
+
+       DBG("connect_timeout callback");
+       return FALSE;
+}
+
+static gboolean __disconnect_timeout_cb(gpointer user_data)
+{
+       char *service = NULL;
+       char *state = NULL;
+       WcObject *wo = (WcObject *)user_data;
+       if (!wo)
+               return FALSE;
+
+       service = wc_object_get_disconnecting_service(wo);
+       if (!service)
+               return FALSE;
+
+       state = wc_object_get_property(wo, service);
+       if (state != NULL) {
+               if (g_strcmp0(state, XSTR(W_SERVICE_STATE_CONNECTED)) != 0)
+                       wc_object_set_property(wo, service,
+                                       XSTR(W_SERVICE_STATE_CONNECTED));
+
+               g_free(state);
+       }
+
+       __connect_result_emit_signal(wo, service,
+                       WECONN_TECHNOLOGY_SIGNAL_DISCONNECTION_RESULT, -ETIMEDOUT);
+
+       wc_object_set_timeout_disconnecting(wo, 0, NULL);
+
+       DBG("disconnect_timeout callback");
+       return FALSE;
+}
+
+static void __connect_timer_clear(WcObject *wo)
+{
+       guint timer = 0;
+
+       if (!wo)
+               return;
+
+       timer = wc_object_get_timeout_connecting(wo);
+       if (timer > 0) {
+               g_source_remove(timer);
+               wc_object_set_timeout_connecting(wo, 0, NULL);
+       }
+
+       DBG("connect_timer cleared");
+}
+
+static void __disconnect_timer_clear(WcObject *wo)
+{
+       guint timer = 0;
+
+       if (!wo)
+               return;
+
+       timer = wc_object_get_timeout_disconnecting(wo);
+       if (timer > 0) {
+               g_source_remove(timer);
+               wc_object_set_timeout_disconnecting(wo, 0, NULL);
+       }
+
+       DBG("disconnect_timer cleared");
+}
+
+static gboolean __connect(GDBusInterfaceSkeleton *di,
+               GDBusMethodInvocation *invocation,
+               const gchar *service, gpointer user_data)
+{
+       int err;
+       guint timer;
+       char *service_state;
+       WcObject *wo = (WcObject *)user_data;
+
+       DBG("");
+
+       /* TODO:
+        *    1. If host CM, at first configure PAN, BT tethering on,
+        *                 and send PAN_CONNECTION command to wearable CM.
+        *    2. If wearable CM, send PAN_CONFIGURATION command to host CM.
+        */
+
+       // __request_pan_configuration();
+
+       /* TODO:
+        *    After PAN_CONNECTION request from host CM, do following procedure.
+        */
+
+       if (!wo || wc_object_get_type(wo) != WC_OBJECT_TYPE_BEARER_DRIVER) {
+               wc_error_add("InvalidArguments");
+               wc_error_return(invocation);
+               return TRUE;
+       }
+
+       service_state = wc_object_get_property(wo, service);
+       if (service_state != NULL) {
+               if (g_strcmp0(service_state, XSTR(W_SERVICE_STATE_CONNECTING)) == 0) {
+                       wc_error_add("InProgress");
+                       wc_error_return(invocation);
+                       g_free(service_state);
+                       return TRUE;
+               }
+               g_free(service_state);
+       }
+
+       err = wc_bearer_driver_connect(wo, NULL,
+                       __service_type_string2_driver_name(service));
+       if (err == -EISCONN) {
+               wc_error_add("AlreadyConnected");
+               wc_error_return(invocation);
+               return TRUE;
+       } else if (err == -EIO) {
+               wc_error_add("LostConnection");
+               wc_error_return(invocation);
+               return TRUE;
+       } else if (err < 0) {
+               /* TODO: specific error code should be defined */
+               wc_error_add("ConnectionFailed");
+               wc_error_return(invocation);
+               return TRUE;
+       }
+
+       if (wc_object_get_timeout_connecting(wo) == 0) {
+               wc_object_set_property(wo, service, XSTR(W_SERVICE_STATE_CONNECTING));
+               timer = g_timeout_add_seconds(CONNECT_TIMEOUT,
+                               __connect_timeout_cb, wo);
+               wc_object_set_timeout_connecting(wo, timer, service);
+       }
+
+       g_dbus_method_invocation_return_value(invocation, g_variant_new("()"));
+       return TRUE;
+}
+
+static gboolean __disconnect(GDBusInterfaceSkeleton *di,
+               GDBusMethodInvocation *invocation,
+               const gchar *service, gpointer user_data)
+{
+       int err;
+       guint timer;
+       char *service_state;
+       WcObject *wo = (WcObject *)user_data;
+
+       DBG("");
+
+       if (!wo || wc_object_get_type(wo) != WC_OBJECT_TYPE_BEARER_DRIVER) {
+               wc_error_add("InvalidArguments");
+               wc_error_return(invocation);
+               return TRUE;
+       }
+
+       service_state = wc_object_get_property(wo, service);
+       if (service_state != NULL) {
+               if (g_strcmp0(service_state, XSTR(W_SERVICE_STATE_DISCONNECTING)) == 0) {
+                       wc_error_add("InProgress");
+                       wc_error_return(invocation);
+                       g_free(service_state);
+                       return TRUE;
+               }
+               g_free(service_state);
+       }
+
+       err = wc_bearer_driver_disconnect(wo,
+                       __service_type_string2_driver_name(service));
+       if (err == -ENOTCONN) {
+               wc_error_add("NotConnected");
+               wc_error_return(invocation);
+
+               return TRUE;
+       } else if (err < 0) {
+               /* TODO: specific error code should be defined */
+               wc_error_add("DisconnectionFailed");
+               wc_error_return(invocation);
+               return TRUE;
+       }
+
+       if (wc_object_get_timeout_disconnecting(wo) == 0) {
+               wc_object_set_property(wo, service, XSTR(W_SERVICE_STATE_DISCONNECTING));
+               timer = g_timeout_add_seconds(CONNECT_TIMEOUT,
+                               __disconnect_timeout_cb, wo);
+               wc_object_set_timeout_disconnecting(wo, timer, service);
+       }
+
+       g_dbus_method_invocation_return_value(invocation, g_variant_new("()"));
+       return TRUE;
+}
+
+static gboolean __wc_technology_bt_property_changed_cb(WcObject *wo,
+               const void *event_info, void *user_data)
+{
+       const char *key = NULL;
+       char *state = NULL;
+       char *service = NULL;
+       char *bcmservice_state = NULL;
+       GSList *list_properies = NULL;
+       GSList *list = NULL;
+
+       list_properies = (GSList *)event_info;
+       if (!list_properies)
+               return TRUE;
+
+       if (g_slist_length(list_properies) < 1) {
+               ERR("No property");
+               return TRUE;
+       }
+
+       for (list = list_properies; list; list = list->next) {
+               key = (const char *)list->data;
+               DBG("property : %s", key);
+               if (g_strcmp0(key, XSTR(W_SERVICE_TYPE_BT_PAN)) == 0) {
+                       state = wc_object_get_property(wo, key);
+                       if (!state)
+                               continue;
+
+                       DBG("state : %s", state);
+
+                       if (g_strcmp0(state, XSTR(W_SERVICE_STATE_CONNECTED)) == 0) {
+
+                               service = wc_object_get_connecting_service(wo);
+                               if (g_strcmp0(service, key) == 0) {
+                                       __connect_result_emit_signal(wo, key,
+                                                       WECONN_TECHNOLOGY_SIGNAL_CONNECTION_RESULT, 0);
+                                       __connect_timer_clear(wo);
+                               }
+
+                               service = wc_object_get_disconnecting_service(wo);
+                               if (g_strcmp0(service, key) == 0) {
+                                       __connect_result_emit_signal(wo, key,
+                                                       WECONN_TECHNOLOGY_SIGNAL_DISCONNECTION_RESULT, -ECANCELED);
+                                       __disconnect_timer_clear(wo);
+                                       return TRUE;
+                               }
+
+                               __connect_result_emit_signal(wo, key,
+                                                       WECONN_TECHNOLOGY_SIGNAL_SERVICE_STATE_CHANGED,
+                                                       W_SERVICE_STATE_CONNECTED);
+
+                       } else if (g_strcmp0(state, XSTR(W_SERVICE_STATE_DISCONNECTED)) == 0) {
+
+                               service = wc_object_get_connecting_service(wo);
+                               if (g_strcmp0(service, key) == 0) {
+                                       bcmservice_state = wc_object_get_property(wo,
+                                                                               WC_OBJECT_EVENT_SAP_BCMSERVICE_STATUS);
+                                       if (g_strcmp0(bcmservice_state, XSTR(W_SERVICE_STATE_CONNECTED)) == 0)
+                                               __connect_result_emit_signal(wo, key,
+                                                               WECONN_TECHNOLOGY_SIGNAL_CONNECTION_RESULT, -ECANCELED);
+                                       else
+                                               __connect_result_emit_signal(wo, key,
+                                                               WECONN_TECHNOLOGY_SIGNAL_DISCONNECTION_RESULT, -EIO);
+
+                                       __connect_result_emit_signal(wo, key,
+                                                       WECONN_TECHNOLOGY_SIGNAL_CONNECTION_RESULT, -ECANCELED);
+                                       __connect_timer_clear(wo);
+                                       return TRUE;
+                               }
+
+                               service = wc_object_get_disconnecting_service(wo);
+                               if (g_strcmp0(service, key) == 0) {
+                                       bcmservice_state = wc_object_get_property(wo,
+                                                                               WC_OBJECT_EVENT_SAP_BCMSERVICE_STATUS);
+                                       if (g_strcmp0(bcmservice_state, XSTR(W_SERVICE_STATE_CONNECTED)) == 0)
+                                               __connect_result_emit_signal(wo, key,
+                                                               WECONN_TECHNOLOGY_SIGNAL_DISCONNECTION_RESULT, 0);
+                                       else
+                                               __connect_result_emit_signal(wo, key,
+                                                               WECONN_TECHNOLOGY_SIGNAL_DISCONNECTION_RESULT, -ENOTCONN);
+                                       __disconnect_timer_clear(wo);
+                               }
+
+                               __connect_result_emit_signal(wo, key,
+                                               WECONN_TECHNOLOGY_SIGNAL_SERVICE_STATE_CHANGED,
+                                               W_SERVICE_STATE_DISCONNECTED);
+                       }
+
+                       g_free(state);
+               }
+       }
+
+       return TRUE;
+}
+
+static void __wc_technology_register_service_state_changed(WcObject *wo)
+{
+       const char *technology;
+
+       if (!wo)
+               return;
+
+       technology = wc_object_peek_name(wo);
+       if (g_strcmp0(technology, WC_TECHNOLOGY_BLUETOOTH) == 0) {
+               wc_object_add_callback(wo, WC_OBJECT_EVENT_PROPERTY_CHANGED,
+                               __wc_technology_bt_property_changed_cb, NULL);
+       } else if (g_strcmp0(technology, WC_TECHNOLOGY_CELLULAR) == 0) {
+
+       }
+}
+
+static gboolean __wc_technology_bearer_enabled_cb(WcObject *wo,
+               const void *event_info, void *user_data)
+{
+       const char *path;
+       GDBusInterfaceSkeleton *di;
+
+       DBG("technology %s added", wc_object_peek_name(wo));
+
+       if (!wo)
+               return TRUE;
+
+       di = G_DBUS_INTERFACE_SKELETON(weconn_technology_skeleton_new());
+
+       g_signal_connect(di, "handle-get-properties",
+                       G_CALLBACK(__get_properties), wo);
+       g_signal_connect(di, "handle-get-property",
+                       G_CALLBACK(__get_property), wo);
+       g_signal_connect(di, "handle-set-property",
+                       G_CALLBACK(__set_property), wo);
+       g_signal_connect(di, "handle-get-properties",
+                       G_CALLBACK(__scan), wo);
+       g_signal_connect(di, "handle-connect",
+                       G_CALLBACK(__connect), wo);
+       g_signal_connect(di, "handle-disconnect",
+                       G_CALLBACK(__disconnect), wo);
+
+       wc_object_set_dbus_interface(wo, di);
+
+       technology_list = g_slist_prepend(technology_list, wo);
+
+       path = g_strdup_printf("%s/%s",
+                       WECONN_TECHNOLOGY_PATH, wc_object_peek_name(wo));
+
+       wc_object_export(wo, path);
+       g_free((gpointer)path);
+
+       __wc_technology_register_service_state_changed(wo);
+
+       return TRUE;
+}
+
+static gboolean __wc_technology_bearer_disabled_cb(WcObject *wo,
+               const void *event_info, void *user_data)
+{
+       if (!wo)
+               return TRUE;
+
+       wc_object_unexport(wo);
+
+       /* TODO: g_signal_connect_closure for each c_handler */
+
+       technology_list = g_slist_remove(technology_list, wo);
+
+       return TRUE;
+}
+
+int wc_technology_add_bearer(WcObject *wo)
+{
+       int err;
+
+       err = wc_object_add_callback(wo, WC_OBJECT_EVENT_BEARER_ENABLED,
+                       __wc_technology_bearer_enabled_cb, NULL);
+       if (err < 0 && err != -EALREADY)
+               return err;
+
+       err = wc_object_add_callback(wo, WC_OBJECT_EVENT_BEARER_DISABLED,
+                       __wc_technology_bearer_disabled_cb, NULL);
+
+       return err;
+}
+
+WcObject *wc_technology_get_bearer(const char *technology)
+{
+       GSList *list = technology_list;
+       WcObject *wo;
+
+       if (!technology)
+               return NULL;
+
+       while (list) {
+               wo = (WcObject *)list->data;
+               if (wo && g_strcmp0(technology, wc_object_peek_name(wo)) == 0)
+                       return wo;
+
+               list = list->next;
+       }
+
+       return NULL;
+}
+
+int technology_init(void)
+{
+       /* TODO: initialize default technologies */
+
+       return 0;
+}
+
+void technology_cleanup(void)
+{
+       /* TODO: clean all of technologies */
+}
diff --git a/src/util.c b/src/util.c
new file mode 100644 (file)
index 0000000..559816a
--- /dev/null
@@ -0,0 +1,236 @@
+/*
+ * Wearable device Connection Controller Framework
+ *
+ * Copyright (c) 2013 - 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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 <glib.h>
+
+#include "log.h"
+#include "util.h"
+
+#define CONNMAN_PATH           "/net/connman"
+#define CONNMAN_CELLULAR_SERVICE_PROFILE_PREFIX \
+                                                                       CONNMAN_PATH "/service/cellular_"
+#define CONNMAN_WIFI_SERVICE_PROFILE_PREFIX \
+                                                                       CONNMAN_PATH "/service/wifi_"
+#define CONNMAN_ETHERNET_SERVICE_PROFILE_PREFIX \
+                                                                       CONNMAN_PATH "/service/ethernet_"
+#define CONNMAN_BLUETOOTH_SERVICE_PROFILE_PREFIX \
+                                                                       CONNMAN_PATH "/service/bluetooth_"
+
+weconn_service_type_e wc_service_type_string2enum(const char *service_type)
+{
+       if (g_strcmp0(XSTR(W_SERVICE_TYPE_BT_HFP), service_type) == 0)
+               return W_SERVICE_TYPE_BT_HFP;
+       else if (g_strcmp0(XSTR(W_SERVICE_TYPE_BT_SPP), service_type) == 0)
+               return W_SERVICE_TYPE_BT_SPP;
+       else if (g_strcmp0(XSTR(W_SERVICE_TYPE_BT_PAN), service_type) == 0)
+               return W_SERVICE_TYPE_BT_PAN;
+       else if (g_strcmp0(XSTR(W_SERVICE_TYPE_BT_GATT), service_type) == 0)
+               return W_SERVICE_TYPE_BT_GATT;
+       else if (g_strcmp0(XSTR(W_SERVICE_TYPE_CELLULAR), service_type) == 0)
+               return W_SERVICE_TYPE_CELLULAR;
+       else if (g_strcmp0(XSTR(W_SERVICE_TYPE_WIFI), service_type) == 0)
+               return W_SERVICE_TYPE_WIFI;
+       else if (g_strcmp0(XSTR(W_SERVICE_TYPE_WIFI_P2P), service_type) == 0)
+               return W_SERVICE_TYPE_WIFI_P2P;
+       else if (g_strcmp0(XSTR(W_SERVICE_TYPE_WIFI_ADHOC), service_type) == 0)
+               return W_SERVICE_TYPE_WIFI_ADHOC;
+       else if (g_strcmp0(XSTR(W_SERVICE_TYPE_ETHERNET), service_type) == 0)
+               return W_SERVICE_TYPE_ETHERNET;
+
+       return 0x00;
+}
+
+const char *wc_service_type_enum2string(weconn_service_type_e service_type)
+{
+       switch (service_type) {
+       case W_SERVICE_TYPE_BT_HFP:
+               return XSTR(W_SERVICE_TYPE_BT_HFP);
+       case W_SERVICE_TYPE_BT_SPP:
+               return XSTR(W_SERVICE_TYPE_BT_SPP);
+       case W_SERVICE_TYPE_BT_PAN:
+               return XSTR(W_SERVICE_TYPE_BT_PAN);
+       case W_SERVICE_TYPE_BT_GATT:
+               return XSTR(W_SERVICE_TYPE_BT_GATT);
+       case W_SERVICE_TYPE_CELLULAR:
+               return XSTR(W_SERVICE_TYPE_CELLULAR);
+       case W_SERVICE_TYPE_WIFI:
+               return XSTR(W_SERVICE_TYPE_WIFI);
+       case W_SERVICE_TYPE_WIFI_P2P:
+               return XSTR(W_SERVICE_TYPE_WIFI_P2P);
+       case W_SERVICE_TYPE_WIFI_ADHOC:
+               return XSTR(W_SERVICE_TYPE_WIFI_ADHOC);
+       case W_SERVICE_TYPE_ETHERNET:
+               return XSTR(W_SERVICE_TYPE_ETHERNET);
+       default:
+               break;
+       }
+
+       return NULL;
+}
+
+weconn_service_state_e wc_service_state_string2enum(const char *service_state)
+{
+       if (g_strcmp0(XSTR(W_SERVICE_STATE_DISCONNECTED), service_state) == 0)
+               return W_SERVICE_STATE_DISCONNECTED;
+       else if (g_strcmp0(XSTR(W_SERVICE_STATE_CONNECTING), service_state) == 0)
+               return W_SERVICE_STATE_CONNECTING;
+       else if (g_strcmp0(XSTR(W_SERVICE_STATE_CONNECTED), service_state) == 0)
+               return W_SERVICE_STATE_CONNECTED;
+       else if (g_strcmp0(XSTR(W_SERVICE_STATE_DISCONNECTING), service_state) == 0)
+               return W_SERVICE_STATE_DISCONNECTING;
+
+       return 0x00;
+}
+
+const char *wc_service_state_enum2string(weconn_service_state_e service_state)
+{
+       switch (service_state) {
+       case W_SERVICE_STATE_DISCONNECTED:
+               return XSTR(W_SERVICE_STATE_DISCONNECTED);
+       case W_SERVICE_STATE_CONNECTING:
+               return XSTR(W_SERVICE_STATE_CONNECTING);
+       case W_SERVICE_STATE_CONNECTED:
+               return XSTR(W_SERVICE_STATE_CONNECTED);
+       case W_SERVICE_STATE_DISCONNECTING:
+               return XSTR(W_SERVICE_STATE_DISCONNECTING);
+       default:
+               break;
+       }
+
+       return NULL;
+}
+
+weconn_device_type_e wc_device_type_string2enum(const char *device_type)
+{
+       if (g_strcmp0(XSTR(W_DEVICE_TYPE_BT), device_type) == 0)
+               return W_DEVICE_TYPE_BT;
+       else if (g_strcmp0(XSTR(W_DEVICE_TYPE_CELLULAR), device_type) == 0)
+               return W_DEVICE_TYPE_CELLULAR;
+       else if (g_strcmp0(XSTR(W_DEVICE_TYPE_WIFI), device_type) == 0)
+               return W_DEVICE_TYPE_WIFI;
+       else if (g_strcmp0(XSTR(W_DEVICE_TYPE_WIFI_P2P), device_type) == 0)
+               return W_DEVICE_TYPE_WIFI_P2P;
+       else if (g_strcmp0(XSTR(W_DEVICE_TYPE_WIFI_ADHOC), device_type) == 0)
+               return W_DEVICE_TYPE_WIFI_ADHOC;
+       else if (g_strcmp0(XSTR(W_DEVICE_TYPE_ETHERNET), device_type) == 0)
+               return W_DEVICE_TYPE_ETHERNET;
+
+       return 0x00;
+}
+
+const char *wc_device_type_enum2string(weconn_device_type_e device_type)
+{
+       switch (device_type) {
+       case W_DEVICE_TYPE_BT:
+               return XSTR(W_DEVICE_TYPE_BT);
+       case W_DEVICE_TYPE_CELLULAR:
+               return XSTR(W_DEVICE_TYPE_CELLULAR);
+       case W_DEVICE_TYPE_WIFI:
+               return XSTR(W_DEVICE_TYPE_WIFI);
+       case W_DEVICE_TYPE_WIFI_P2P:
+               return XSTR(W_DEVICE_TYPE_WIFI_P2P);
+       case W_DEVICE_TYPE_WIFI_ADHOC:
+               return XSTR(W_DEVICE_TYPE_WIFI_ADHOC);
+       case W_DEVICE_TYPE_ETHERNET:
+               return XSTR(W_DEVICE_TYPE_ETHERNET);
+       default:
+               break;
+       }
+
+       return NULL;
+}
+
+weconn_device_state_e wc_device_state_string2enum(const char *device_state)
+{
+       if (g_strcmp0(XSTR(W_DEVICE_STATE_DISABLED), device_state) == 0)
+               return W_DEVICE_STATE_DISABLED;
+       else if (g_strcmp0(XSTR(W_DEVICE_STATE_ENABLED), device_state) == 0)
+               return W_DEVICE_STATE_ENABLED;
+
+       return 0x00;
+}
+
+const char *wc_device_state_enum2string(weconn_device_state_e device_state)
+{
+       switch (device_state) {
+       case W_DEVICE_STATE_DISABLED:
+               return XSTR(W_DEVICE_STATE_DISABLED);
+       case W_DEVICE_STATE_ENABLED:
+               return XSTR(W_DEVICE_STATE_ENABLED);
+       default:
+               break;
+       }
+
+       return NULL;
+}
+
+weconn_device_type_e wc_device_get_type_from_path(const char *path)
+{
+       if (g_str_has_prefix(path,
+                       CONNMAN_WIFI_SERVICE_PROFILE_PREFIX) == TRUE)
+               return W_DEVICE_TYPE_WIFI;
+       else if (g_str_has_prefix(path,
+                       CONNMAN_CELLULAR_SERVICE_PROFILE_PREFIX) == TRUE)
+               return W_DEVICE_TYPE_CELLULAR;
+       else if (g_str_has_prefix(path,
+                       CONNMAN_ETHERNET_SERVICE_PROFILE_PREFIX) == TRUE)
+               return W_DEVICE_TYPE_ETHERNET;
+       else if (g_str_has_prefix(path,
+                       CONNMAN_BLUETOOTH_SERVICE_PROFILE_PREFIX) == TRUE)
+               return W_DEVICE_TYPE_BT;
+
+       return 0x00;
+}
+
+int wc_launch_popup(weconn_popup_type_e type, service_reply_cb callback,
+               void *user_data)
+{
+       int ret;
+       service_h service = NULL;
+
+       ret = service_create(&service);
+       if (ret != SERVICE_ERROR_NONE) {
+               DBG("failed to create service [%d]", ret);
+               return -1;
+       }
+
+       switch (type) {
+       case WC_POPUP_TYPE_PAN_CONNECT:
+               service_add_extra_data(service, "_WCPOPUP_TYPE_", "pan_connect");
+               break;
+       case WC_POPUP_TYPE_PAN_DISCONNECT:
+               service_add_extra_data(service, "_WCPOPUP_TYPE_", "pan_disconnect");
+               break;
+       default:
+               ERR("Not support popup type [%d]", type);
+               service_destroy(service);
+               return -1;
+       }
+
+       service_set_package(service, "net.wc-popup");
+       ret = service_send_launch_request(service, callback, user_data);
+       if (ret != SERVICE_ERROR_NONE) {
+               DBG("failed service launch request [%d]", ret);
+               return -1;
+       }
+
+       service_destroy(service);
+
+       return 0;
+}
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
new file mode 100644 (file)
index 0000000..52dee07
--- /dev/null
@@ -0,0 +1,22 @@
+SET(weconn_test "${PROJECT_NAME}-test")
+
+SET(dependents "capi-base-common gio-2.0 glib-2.0")
+SET(pc_dependents "capi-base-common")
+
+INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/client/include/)
+
+INCLUDE(FindPkgConfig)
+pkg_check_modules(${weconn_test} REQUIRED ${dependents})
+FOREACH(flag ${${weconn_test}_CFLAGS})
+    SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}")
+ENDFOREACH(flag)
+
+SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} -Wall")
+
+aux_source_directory(. sources)
+FOREACH(src ${sources})
+    GET_FILENAME_COMPONENT(src_name ${src} NAME_WE)
+    MESSAGE("${src_name}")
+    ADD_EXECUTABLE(${src_name} ${src})
+    TARGET_LINK_LIBRARIES(${src_name} weconn ${${weconn_test}_LDFLAGS})
+ENDFOREACH()
diff --git a/test/w_connection_manager_test.c b/test/w_connection_manager_test.c
new file mode 100644 (file)
index 0000000..700d64a
--- /dev/null
@@ -0,0 +1,414 @@
+/*
+ * Wearable device Connection Controller Framework
+ *
+ * Copyright (c) 2013 - 2014 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * 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 <glib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <weconn.h>
+#include <tizen_error.h>
+
+gboolean test_thread(GIOChannel *source, GIOCondition condition, gpointer data);
+
+static weconn_h connection = NULL;
+
+static int __get_service_type(void)
+{
+       int input, rv;
+
+       printf("Input service type:\n");
+       printf("1: W_SERVICE_TYPE_BT_HFP\n");
+       printf("2: W_SERVICE_TYPE_BT_SPP\n");
+       printf("3: W_SERVICE_TYPE_BT_PAN\n");
+       printf("4: W_SERVICE_TYPE_BT_GATT\n");
+       printf("5: W_SERVICE_TYPE_CELLULAR\n");
+       printf("6: W_SERVICE_TYPE_WIFI\n");
+       printf("7: W_SERVICE_TYPE_WIFI_P2P\n");
+       printf("8: W_SERVICE_TYPE_WIFI_ADHOC\n");
+       printf("9: W_SERVICE_TYPE_ETHERNET\n");
+       printf("11: W_SERVICE_TYPE_HOST_TO_WEARABLE_CONNECTIVITY\n");
+       printf("12: W_SERVICE_TYPE_INTERNET_CONNECTIVITY\n");
+
+       rv = scanf("%d", &input);
+       if (rv < 0)
+               return -EINVAL;
+
+       /* convert the real enum of service type */
+       printf("service type %02X\n", input);
+       if (input < 10) {
+               input = input + 0x10;
+               if (W_SERVICE_TYPE_BT_HFP <= input && input <= W_SERVICE_TYPE_ETHERNET)
+                       return input;
+       } else {
+               input = input - 10;
+               if (W_SERVICE_TYPE_HOST_TO_WEARABLE_CONNECTIVITY == input ||
+                               W_SERVICE_TYPE_INTERNET_CONNECTIVITY == input)
+                       return input;
+       }
+
+       return -EINVAL;
+}
+
+static void __print_service_state(weconn_service_state_e state)
+{
+       switch (state) {
+       case W_SERVICE_STATE_DISCONNECTED:
+               printf("Disconnected\n");
+               break;
+       case W_SERVICE_STATE_CONNECTING:
+               printf("Connecting\n");
+               break;
+       case W_SERVICE_STATE_CONNECTED:
+               printf("Connected\n");
+               break;
+       case W_SERVICE_STATE_DISCONNECTING:
+               printf("Disconnected\n");
+               break;
+       default:
+               printf("Unknown\n");
+       }
+}
+
+static int __get_device_type(void)
+{
+       int input, rv;
+
+       printf("Input device type:\n");
+       printf("1: W_DEVICE_TYPE_BT\n");
+       printf("2: W_DEVICE_TYPE_CELLULAR\n");
+       printf("3: W_DEVICE_TYPE_WIFI\n");
+       printf("4: W_DEVICE_TYPE_WIFI_P2P\n");
+       printf("5: W_DEVICE_TYPE_WIFI_ADHOC\n");
+       printf("6: W_DEVICE_TYPE_ETHERNET\n");
+
+       rv = scanf("%d", &input);
+       if (rv < 0)
+               return -EINVAL;
+
+       printf("device type %d\n", input);
+       if (W_DEVICE_TYPE_BT <= input && input <= W_DEVICE_TYPE_ETHERNET)
+               return input;
+
+       return -EINVAL;
+}
+
+static void __print_device_state(weconn_service_state_e state)
+{
+       switch (state) {
+       case W_DEVICE_STATE_DISABLED:
+               printf("Disabled\n");
+               break;
+       case W_DEVICE_STATE_ENABLED:
+               printf("Enabled\n");
+               break;
+       default:
+               printf("Unknown\n");
+       }
+}
+
+static int test_register_client(void)
+{
+       int err = weconn_create(&connection);
+
+       if (err < 0) {
+               printf("Client registration failed [%d]\n", err);
+               return -EIO;
+       }
+
+       printf("Client registered successfully\n");
+
+       return 0;
+}
+
+static int  test_deregister_client(void)
+{
+       int err = 0;
+
+       if (connection != NULL)
+               err = weconn_destroy(connection);
+       else {
+               printf("Cannot de-register: handle is NULL\n");
+               err = -EINVAL;
+       }
+
+       if (err < 0) {
+               printf("Client de-registration fail [%d]\n", err);
+               return err;
+       }
+
+       connection = NULL;
+
+       printf("Client de-registration success\n");
+
+       return 0;
+}
+
+static int test_get_service_state(void)
+{
+       int type, err;
+       weconn_service_state_e state;
+
+       type = __get_service_type();
+
+       err = weconn_get_service_state(connection, type, &state);
+       if (err < 0) {
+               printf("Failed to get service state [%d]", err);
+               return err;
+       }
+
+       __print_service_state(state);
+       return 0;
+}
+
+static int test_get_device_state(void)
+{
+       int type, err;
+       weconn_device_state_e state;
+
+       type = __get_device_type();
+
+       err = weconn_get_device_state(connection, type, &state);
+       if (err < 0) {
+               printf("Failed to get device state [%d]", err);
+               return err;
+       }
+
+       __print_device_state(state);
+       return 0;
+}
+
+static void __test_connect_service_callback(int result, void *user_data)
+{
+       if (result == 0)
+               printf("Succeed to connect\n");
+       else
+               printf("Failed to connect [%d]\n", result);
+}
+
+static void __test_disconnect_service_callback(int result, void *user_data)
+{
+       if (result == 0)
+               printf("Succeed to disconnect\n");
+       else
+               printf("Failed to disconnect [%d]\n", result);
+}
+
+static int test_connect_service(void)
+{
+       int err = 0;
+       weconn_service_type_e type;
+
+       type = __get_service_type();
+
+       err = weconn_connect_service(connection, type,
+                       __test_connect_service_callback, NULL);
+       if (err < 0) {
+               printf("Failed to connect service [%d]", err);
+               return err;
+       }
+
+       return err;
+}
+
+static int test_disconnect_service(void)
+{
+       int err = 0;
+       weconn_service_type_e type;
+
+       type = __get_service_type();
+
+       err = weconn_disconnect_service(connection, type,
+                       __test_disconnect_service_callback, NULL);
+       if (err < 0) {
+               printf("Failed to get device state [%d]", err);
+               return err;
+       }
+
+       return err;
+}
+
+static void _test_wearable_service_state_changed_cb(
+               weconn_service_state_e state, void *user_data)
+{
+       printf("wearable service state changed = %d\n", state);
+}
+
+static void _test_internet_service_state_changed_cb(
+               weconn_service_state_e state, void *user_data)
+{
+       printf("internet service state changed = %d\n", state);
+}
+
+static int test_register_service_connection_cb(void)
+{
+       int err = 0;
+       weconn_service_type_e type;
+
+       type = __get_service_type();
+
+       switch (type) {
+       case W_SERVICE_TYPE_HOST_TO_WEARABLE_CONNECTIVITY:
+               err = weconn_set_service_state_change_cb(connection,
+                               _test_wearable_service_state_changed_cb, type, NULL);
+               if (err < 0) {
+                       printf("Register_service_connectionn failed [%d]\n", err);
+                       return -EIO;
+               }
+               break;
+       case W_SERVICE_TYPE_INTERNET_CONNECTIVITY       :
+               err = weconn_set_service_state_change_cb(connection,
+                               _test_internet_service_state_changed_cb, type, NULL);
+               if (err < 0) {
+                       printf("Register_service_connectionn failed [%d]\n", err);
+                       return -EIO;
+               }
+               break;
+       case W_SERVICE_TYPE_BT_HFP:
+       case W_SERVICE_TYPE_BT_SPP:
+       case W_SERVICE_TYPE_BT_PAN:
+       case W_SERVICE_TYPE_BT_GATT:
+       case W_SERVICE_TYPE_CELLULAR:
+       case W_SERVICE_TYPE_WIFI:
+       case W_SERVICE_TYPE_WIFI_P2P:
+       case W_SERVICE_TYPE_WIFI_ADHOC:
+       case W_SERVICE_TYPE_ETHERNET:
+               printf("Not support service type [%d]\n", type);
+               return -EINVAL;
+       }
+
+       printf("Register_service_connectionn successfully\n");
+
+       return 0;
+}
+
+static int test_unregister_service_connection_cb(void)
+{
+       int err = 0;
+       weconn_service_type_e type;
+
+       type = __get_service_type();
+
+       if (type > W_SERVICE_TYPE_INTERNET_CONNECTIVITY)
+               printf("Not support service type [%d]\n", type);
+
+       err = weconn_unset_service_state_change_cb(connection, type);
+       if (err < 0) {
+               printf("Unregister_service_connectionn failed [%d]\n", err);
+               return -EIO;
+       }
+
+       printf("Unregister_service_connectionn successfully\n");
+
+       return 0;
+}
+
+static void __print_menu(void)
+{
+       printf("\nWearable Connection API Test App\n\n");
+       printf("Options..\n");
+       printf("1       - Create Handle\n");
+       printf("2       - Destroy Handle(unset callbacks automatically)\n");
+       printf("3       - Get wearable service state\n");
+       printf("4       - Get wearable device state\n");
+       printf("5       - Connect wearable service\n");
+       printf("6       - Disconnect wearable service\n");
+       printf("7       - Register wearable service connection callback\n");
+       printf("8       - Unregister wearable service connection callback\n");
+       printf("0       - Exit \n");
+       printf("ENTER  - Show options menu.......\n");
+}
+
+int main(int argc, char **argv)
+{
+       GMainLoop *mainloop;
+       GIOChannel *channel;
+       mainloop = g_main_loop_new (NULL, FALSE);
+
+       channel = g_io_channel_unix_new(0);
+       g_io_add_watch(channel, (G_IO_IN|G_IO_ERR|G_IO_HUP|G_IO_NVAL),
+                                       test_thread,NULL );
+
+       __print_menu();
+
+       g_main_loop_run (mainloop);
+
+       return 0;
+}
+
+gboolean test_thread(GIOChannel *source, GIOCondition condition, gpointer data)
+{
+       int rv = 0;
+       char cmds[100];
+       char cmd;
+
+       memset(cmds, '\0', 100);
+       rv = read(0, cmds, 100);
+
+       cmd = *cmds;
+
+       if (cmd == '\n' || cmd == '\r'){
+               __print_menu();
+
+               return TRUE;
+       }
+
+       switch (cmd) {
+       case '0':
+               if (connection != NULL)
+                       test_deregister_client();
+
+               exit(1);
+       case '1':
+               rv = test_register_client();
+               break;
+       case '2':
+               rv = test_deregister_client();
+               break;
+       case '3':
+               rv = test_get_service_state();
+               break;
+       case '4':
+               rv = test_get_device_state();
+               break;
+       case '5':
+               rv = test_connect_service();
+               break;
+       case '6':
+               rv = test_disconnect_service();
+               break;
+       case '7':
+               rv = test_register_service_connection_cb();
+               break;
+       case '8':
+               rv = test_unregister_service_connection_cb();
+               break;
+       default:
+               break;
+       }
+
+       if (rv == 0)
+               printf("Operation succeeded!\n\n");
+       else
+               printf("Operation failed!\n\n");
+
+       return TRUE;
+}
diff --git a/weconn.manifest b/weconn.manifest
new file mode 100644 (file)
index 0000000..09c7da4
--- /dev/null
@@ -0,0 +1,59 @@
+<manifest>
+       <define>
+               <domain name="weconn"/>
+               <request>
+                       <smack request="dbus" type="rwx"/>
+                       <smack request="connman" type="rwx"/>
+                       <smack request="aul::launch" type="x"/>
+                       <smack request="bt-service::gap" type="rwx"/>
+                       <smack request="bt-service::admin" type="rwx"/>
+                       <smack request="bt-service::manager" type="rwx"/>
+                       <smack request="alarm-server::alarm" type="rwx"/>
+                       <smack request="sys-assert::core" type="rwxat"/>
+                       <smack request="system::use_internet" type="rwx"/>
+                       <smack request="system::vconf" type="rx"/>
+                       <smack request="system::vconf_system" type="rwx"/>
+                       <smack request="system::vconf_network" type="rwx"/>
+                       <smack request="system::vconf_setting" type="rwx"/>
+                       <smack request="telephony_framework::api_private" type="rw"/>
+               </request>
+               <permit>
+                       <smack permit="dbus" type="rwx"/>
+                       <smack permit="system::use_internet" type="rwx"/>
+               </permit>
+       </define>
+       <assign>
+               <filesystem path="/etc/dbus-1/system.d/weconn.conf" label="_"/>
+               <filesystem path="/usr/lib/systemd/system/weconn.service" label="_"/>
+               <filesystem path="/usr/lib/systemd/system/multi-user.target.wants/weconn.service" label="_"/>
+               <filesystem path="/usr/share/dbus-1/services/net.weconn.service" label="_"/>
+               <filesystem path="/etc/opt/upgrade/500.net.weconn.patch.sh" label="_" exec_label="none"/>
+               <filesystem path="/usr/share/appcessory/wearable-connection.xml" label="_"/>
+               <filesystem path="/usr/lib/libweconn.so.0" label="_" exec_label="none"/>
+               <filesystem path="/usr/lib/libweconn.so.0.*" label="_" exec_label="none"/>
+               <filesystem path="/usr/share/license/weconn" label="_"/>
+               <dbus name="net.weconn" own="weconn" bus="system">
+                       <node name="/">
+                       <interface name="net.weconn.Service">
+                               <annotation name="net.weconn.smack" value="weconn"/>
+                       </interface>
+                       <interface name="net.weconn.Technology">
+                               <annotation name="net.weconn.smack" value="weconn"/>
+                       </interface>
+                       </node>
+               </dbus>
+               <dbus name="net.weconn" own="weconn" bus="system">
+                       <node name="/net/weconn/*">
+                       <interface name="net.weconn.Service">
+                               <annotation name="net.weconn.smack" value="weconn"/>
+                       </interface>
+                       <interface name="net.weconn.Technology">
+                               <annotation name="net.weconn.smack" value="weconn"/>
+                       </interface>
+                       </node>
+               </dbus>
+       </assign>
+       <request>
+               <domain name="weconn"/>
+       </request>
+</manifest>