Imported Upstream version 1.1.0
[platform/upstream/iotivity.git] / resource / csdk / connectivity / src / bt_le_adapter / android / caleclient.c
index 06c1c05..dd953de 100644 (file)
 
 #include "logger.h"
 #include "oic_malloc.h"
+#include "oic_string.h"
 #include "cathreadpool.h" /* for thread pool */
 #include "camutex.h"
 #include "uarraylist.h"
-#include "org_iotivity_jar_caleclientinterface.h"
+#include "org_iotivity_ca_CaLeClientInterface.h"
 
-#define TAG PCF("CA_LE_CLIENT")
+#define TAG PCF("OIC_CA_LE_CLIENT")
 
-static const char METHODID_OBJECTNONPARAM[] = "()Landroid/bluetooth/BluetoothAdapter;";
-static const char CLASSPATH_BT_ADAPTER[] = "android/bluetooth/BluetoothAdapter";
-static const char CLASSPATH_BT_UUID[] = "java/util/UUID";
-static const char CLASSPATH_BT_GATT[] = "android/bluetooth/BluetoothGatt";
+#define MICROSECS_PER_SEC 1000000
+#define WAIT_TIME_WRITE_CHARACTERISTIC 10 * MICROSECS_PER_SEC
+
+#define GATT_CONNECTION_PRIORITY_BALANCED   0
+#define GATT_FAILURE                        257
+#define GATT_INSUFFICIENT_AUTHENTICATION    5
+#define GATT_INSUFFICIENT_ENCRYPTION        15
+#define GATT_INVALID_ATTRIBUTE_LENGTH       13
+#define GATT_INVALID_OFFSET                 7
+#define GATT_READ_NOT_PERMITTED             2
+#define GATT_REQUEST_NOT_SUPPORTED          6
+#define GATT_WRITE_NOT_PERMITTED            3
+
+static ca_thread_pool_t g_threadPoolHandle = NULL;
 
 JavaVM *g_jvm;
 static u_arraylist_t *g_deviceList = NULL; // device list to have same UUID
@@ -49,7 +60,7 @@ static u_arraylist_t *g_gattObjectList = NULL;
 static u_arraylist_t *g_deviceStateList = NULL;
 
 static CAPacketReceiveCallback g_packetReceiveCallback = NULL;
-static ca_thread_pool_t g_threadPoolHandle = NULL;
+static CABLEErrorHandleCallback g_clientErrorCallback;
 static jobject g_leScanCallback = NULL;
 static jobject g_leGattCallback = NULL;
 static jobject g_context = NULL;
@@ -57,26 +68,21 @@ static jobjectArray g_uuidList = NULL;
 
 // it will be prevent to start send logic when adapter has stopped.
 static bool g_isStartedLEClient = false;
-static bool g_isStartedMulticastServer = false;
 static bool g_isStartedScan = false;
 
 static jbyteArray g_sendBuffer = NULL;
 static uint32_t g_targetCnt = 0;
 static uint32_t g_currentSentCnt = 0;
 static bool g_isFinishedSendData = false;
-static ca_mutex g_SendFinishMutex = false;
+static ca_mutex g_SendFinishMutex = NULL;
 static ca_mutex g_threadMutex = NULL;
 static ca_cond g_threadCond = NULL;
-
-static bool g_isRequestedSend = false;
-static bool g_isReceivedWriteCB = false;
-static ca_mutex g_writeCharacteristicCBMutex = false;
-static ca_mutex g_theSendRequestMutex = false;
-static ca_mutex g_threadSendCBMutex = NULL;
-static ca_cond g_threadSendCBCond = NULL;
+static ca_cond g_deviceDescCond = NULL;
 
 static ca_mutex g_threadSendMutex = NULL;
-static ca_cond g_threadSendCond = NULL;
+static ca_mutex g_threadWriteCharacteristicMutex = NULL;
+static ca_cond g_threadWriteCharacteristicCond = NULL;
+static bool g_isSignalSetFlag = false;
 
 static ca_mutex g_bleReqRespClientCbMutex = NULL;
 static ca_mutex g_bleServerBDAddressMutex = NULL;
@@ -85,7 +91,38 @@ static ca_mutex g_deviceListMutex = NULL;
 static ca_mutex g_gattObjectMutex = NULL;
 static ca_mutex g_deviceStateListMutex = NULL;
 
-static CABLEClientDataReceivedCallback g_CABLEClientDataReceivedCallback = NULL;
+static ca_mutex g_deviceScanRetryDelayMutex = NULL;
+static ca_cond g_deviceScanRetryDelayCond = NULL;
+
+static ca_mutex g_scanMutex = NULL;
+
+static CABLEDataReceivedCallback g_CABLEClientDataReceivedCallback = NULL;
+
+/**
+ * check if retry logic for connection routine has to be stopped or not.
+ * in case of error value including this method, connection routine has to be stopped.
+ * since there is no retry logic for this error reason in this client.
+ * @param state constant value of bluetoothgatt.
+ * @return true - waiting for background connection in BT platform.
+ *         false - connection routine has to be stopped.
+ */
+static bool CALECheckConnectionStateValue(jint state)
+{
+    switch(state)
+    {
+        case GATT_CONNECTION_PRIORITY_BALANCED:
+        case GATT_FAILURE:
+        case GATT_INSUFFICIENT_AUTHENTICATION:
+        case GATT_INSUFFICIENT_ENCRYPTION:
+        case GATT_INVALID_ATTRIBUTE_LENGTH:
+        case GATT_INVALID_OFFSET:
+        case GATT_READ_NOT_PERMITTED:
+        case GATT_REQUEST_NOT_SUPPORTED:
+        case GATT_WRITE_NOT_PERMITTED:
+            return true;
+    }
+    return false;
+}
 
 //getting jvm
 void CALEClientJniInit()
@@ -132,10 +169,10 @@ CAResult_t CALECreateJniInterfaceObject()
         isAttached = true;
     }
 
-    jclass jni_LEInterface = (*env)->FindClass(env, "org/iotivity/jar/caleclientinterface");
+    jclass jni_LEInterface = (*env)->FindClass(env, "org/iotivity/ca/CaLeClientInterface");
     if (!jni_LEInterface)
     {
-        OIC_LOG(ERROR, TAG, "Could not get caleclientinterface class");
+        OIC_LOG(ERROR, TAG, "Could not get CaLeClientInterface class");
         goto error_exit;
     }
 
@@ -143,12 +180,12 @@ CAResult_t CALECreateJniInterfaceObject()
                                                                  "(Landroid/content/Context;)V");
     if (!LeInterfaceConstructorMethod)
     {
-        OIC_LOG(ERROR, TAG, "Could not get caleclientinterface constructor method");
+        OIC_LOG(ERROR, TAG, "Could not get CaLeClientInterface constructor method");
         goto error_exit;
     }
 
     (*env)->NewObject(env, jni_LEInterface, LeInterfaceConstructorMethod, g_context);
-    OIC_LOG(DEBUG, TAG, "Create instance for caleclientinterface");
+    OIC_LOG(DEBUG, TAG, "Create instance for CaLeClientInterface");
 
     if (isAttached)
     {
@@ -167,7 +204,7 @@ error_exit:
     return CA_STATUS_FAILED;
 }
 
-CAResult_t CALEClientInitialize(ca_thread_pool_t handle)
+CAResult_t CALEClientInitialize()
 {
     OIC_LOG(DEBUG, TAG, "CALEClientInitialize");
 
@@ -208,8 +245,6 @@ CAResult_t CALEClientInitialize(ca_thread_pool_t handle)
         return ret;
     }
 
-    g_threadPoolHandle = handle;
-
     ret = CALEClientInitGattMutexVaraibles();
     if (CA_STATUS_OK != ret)
     {
@@ -224,10 +259,12 @@ CAResult_t CALEClientInitialize(ca_thread_pool_t handle)
         return ret;
     }
 
+    g_deviceDescCond = ca_cond_new();
+
     // init mutex for send logic
     g_threadCond = ca_cond_new();
-    g_threadSendCond = ca_cond_new();
-    g_threadSendCBCond = ca_cond_new();
+    g_threadWriteCharacteristicCond = ca_cond_new();
+    g_deviceScanRetryDelayCond = ca_cond_new();
 
     CALEClientCreateDeviceList();
     CALEClientJNISetContext();
@@ -259,6 +296,11 @@ CAResult_t CALEClientInitialize(ca_thread_pool_t handle)
     }
     g_isStartedLEClient = true;
 
+    if (isAttached)
+    {
+        (*g_jvm)->DetachCurrentThread(g_jvm);
+    }
+
     return CA_STATUS_OK;
 }
 
@@ -291,21 +333,25 @@ void CALEClientTerminate()
     if (g_leScanCallback)
     {
         (*env)->DeleteGlobalRef(env, g_leScanCallback);
+        g_leScanCallback = NULL;
     }
 
     if (g_leGattCallback)
     {
         (*env)->DeleteGlobalRef(env, g_leGattCallback);
+        g_leGattCallback = NULL;
     }
 
     if (g_sendBuffer)
     {
         (*env)->DeleteGlobalRef(env, g_sendBuffer);
+        g_sendBuffer = NULL;
     }
 
     if (g_uuidList)
     {
         (*env)->DeleteGlobalRef(env, g_uuidList);
+        g_uuidList = NULL;
     }
 
     CAResult_t ret = CALEClientRemoveAllDeviceState();
@@ -326,54 +372,33 @@ void CALEClientTerminate()
         OIC_LOG(ERROR, TAG, "CALEClientRemoveAllGattObjs has failed");
     }
 
-    g_isStartedMulticastServer = false;
-    g_isStartedScan = false;
-    CALEClientSetSendFinishFlag(false);
-    CALEClientSetTheSendRequestFlag(false);
-    CALEClientSetWriteCharacteristicCBFlag(false);
+    CALEClientSetScanFlag(false);
+    CALEClientSetSendFinishFlag(true);
 
     CALEClientTerminateGattMutexVariables();
+    CALEClientDestroyJniInterface();
 
+    ca_cond_free(g_deviceDescCond);
     ca_cond_free(g_threadCond);
-    ca_cond_free(g_threadSendCond);
-    ca_cond_free(g_threadSendCBCond);
+    ca_cond_free(g_threadWriteCharacteristicCond);
+    ca_cond_free(g_deviceScanRetryDelayCond);
 
-    if (isAttached)
-    {
-        (*g_jvm)->DetachCurrentThread(g_jvm);
-    }
-}
+    g_deviceDescCond = NULL;
+    g_threadCond = NULL;
+    g_threadWriteCharacteristicCond = NULL;
+    g_deviceScanRetryDelayCond = NULL;
 
-void CALEClientSendFinish(JNIEnv *env, jobject gatt)
-{
-    OIC_LOG(DEBUG, TAG, "CALEClientSendFinish");
-    VERIFY_NON_NULL_VOID(env, TAG, "env is null");
+    g_isSignalSetFlag = false;
 
-    if (gatt)
+    if (isAttached)
     {
-        CAResult_t res = CALEClientDisconnect(env, gatt);
-        if (CA_STATUS_OK != res)
-        {
-            OIC_LOG(ERROR, TAG, "CALEClientDisconnect has failed");
-        }
+        (*g_jvm)->DetachCurrentThread(g_jvm);
     }
-    CALEClientUpdateSendCnt(env);
-}
-
-CAResult_t CALEClientSendUnicastMessage(const char* address, const char* data,
-                                        const uint32_t dataLen)
-{
-    OIC_LOG_V(DEBUG, TAG, "CALEClientSendUnicastMessage(%s, %s)", address, data);
-    VERIFY_NON_NULL(address, TAG, "address is null");
-    VERIFY_NON_NULL(data, TAG, "data is null");
-
-    return CALEClientSendUnicastMessageImpl(address, data, dataLen);
 }
 
-CAResult_t CALEClientSendMulticastMessage(const char* data, const uint32_t dataLen)
+CAResult_t CALEClientDestroyJniInterface()
 {
-    OIC_LOG_V(DEBUG, TAG, "CALEClientSendMulticastMessage(%s)", data);
-    VERIFY_NON_NULL(data, TAG, "data is null");
+    OIC_LOG(DEBUG, TAG, "CALEClientDestroyJniInterface");
 
     if (!g_jvm)
     {
@@ -397,36 +422,83 @@ CAResult_t CALEClientSendMulticastMessage(const char* data, const uint32_t dataL
         isAttached = true;
     }
 
-    CAResult_t ret = CALEClientSendMulticastMessageImpl(env, data, dataLen);
-    if (CA_STATUS_OK != ret)
+    jclass jni_LeInterface = (*env)->FindClass(env, "org/iotivity/ca/CaLeClientInterface");
+    if (!jni_LeInterface)
     {
-        OIC_LOG(ERROR, TAG, "CALEClientSendMulticastMessageImpl has failed");
+        OIC_LOG(ERROR, TAG, "Could not get CaLeClientInterface class");
+        goto error_exit;
+    }
+
+    jmethodID jni_InterfaceDestroyMethod = (*env)->GetStaticMethodID(env, jni_LeInterface,
+                                                                     "destroyLeInterface",
+                                                                     "()V");
+    if (!jni_InterfaceDestroyMethod)
+    {
+        OIC_LOG(ERROR, TAG, "Could not get CaLeClientInterface destroy method");
+        goto error_exit;
+    }
+
+    (*env)->CallStaticVoidMethod(env, jni_LeInterface, jni_InterfaceDestroyMethod);
+
+    if ((*env)->ExceptionCheck(env))
+    {
+        OIC_LOG(ERROR, TAG, "destroyLeInterface has failed");
+        (*env)->ExceptionDescribe(env);
+        (*env)->ExceptionClear(env);
+        goto error_exit;
     }
 
+    OIC_LOG(DEBUG, TAG, "Destroy instance for CaLeClientInterface");
+
     if (isAttached)
     {
         (*g_jvm)->DetachCurrentThread(g_jvm);
     }
 
-    return ret;
-}
+    return CA_STATUS_OK;
 
-CAResult_t CALEClientStartUnicastServer(const char* address)
-{
-    OIC_LOG_V(DEBUG, TAG, "it is not needed in this platform (%s)", address);
+error_exit:
 
-    return CA_NOT_SUPPORTED;
+    if (isAttached)
+    {
+        (*g_jvm)->DetachCurrentThread(g_jvm);
+    }
+
+    return CA_STATUS_FAILED;
 }
 
-CAResult_t CALEClientStartMulticastServer()
+void CALEClientSendFinish(JNIEnv *env, jobject gatt)
 {
-    OIC_LOG(DEBUG, TAG, "CALEClientStartMulticastServer");
+    OIC_LOG(DEBUG, TAG, "CALEClientSendFinish");
+    VERIFY_NON_NULL_VOID(env, TAG, "env is null");
 
-    if (g_isStartedMulticastServer)
+    if (gatt)
     {
-        OIC_LOG(ERROR, TAG, "server is already started..it will be skipped");
-        return CA_STATUS_FAILED;
+        CAResult_t res = CALEClientDisconnect(env, gatt);
+        if (CA_STATUS_OK != res)
+        {
+            OIC_LOG(ERROR, TAG, "CALEClientDisconnect has failed");
+        }
     }
+    CALEClientUpdateSendCnt(env);
+}
+
+CAResult_t CALEClientSendUnicastMessage(const char* address,
+                                        const uint8_t* data,
+                                        const uint32_t dataLen)
+{
+    OIC_LOG_V(DEBUG, TAG, "CALEClientSendUnicastMessage(%s, %p)", address, data);
+    VERIFY_NON_NULL(address, TAG, "address is null");
+    VERIFY_NON_NULL(data, TAG, "data is null");
+
+    return CALEClientSendUnicastMessageImpl(address, data, dataLen);
+}
+
+CAResult_t CALEClientSendMulticastMessage(const uint8_t* data,
+                                          const uint32_t dataLen)
+{
+    OIC_LOG_V(DEBUG, TAG, "CALEClientSendMulticastMessage(%p)", data);
+    VERIFY_NON_NULL(data, TAG, "data is null");
 
     if (!g_jvm)
     {
@@ -450,11 +522,10 @@ CAResult_t CALEClientStartMulticastServer()
         isAttached = true;
     }
 
-    g_isStartedMulticastServer = true;
-    CAResult_t ret = CALEClientStartScan();
+    CAResult_t ret = CALEClientSendMulticastMessageImpl(env, data, dataLen);
     if (CA_STATUS_OK != ret)
     {
-        OIC_LOG(ERROR, TAG, "CALEClientStartScan has failed");
+        OIC_LOG(ERROR, TAG, "CALEClientSendMulticastMessageImpl has failed");
     }
 
     if (isAttached)
@@ -465,6 +536,20 @@ CAResult_t CALEClientStartMulticastServer()
     return ret;
 }
 
+CAResult_t CALEClientStartUnicastServer(const char* address)
+{
+    OIC_LOG_V(DEBUG, TAG, "it is not needed in this platform (%s)", address);
+
+    return CA_NOT_SUPPORTED;
+}
+
+CAResult_t CALEClientStartMulticastServer()
+{
+    OIC_LOG(DEBUG, TAG, "it is not needed in this platform");
+
+    return CA_NOT_SUPPORTED;
+}
+
 void CALEClientStopUnicastServer()
 {
     OIC_LOG(DEBUG, TAG, "CALEClientStopUnicastServer");
@@ -473,13 +558,6 @@ void CALEClientStopUnicastServer()
 void CALEClientStopMulticastServer()
 {
     OIC_LOG(DEBUG, TAG, "CALEClientStopMulticastServer");
-    g_isStartedMulticastServer = false;
-    CAResult_t res = CALEClientStopScan();
-    if (CA_STATUS_OK != res)
-    {
-        OIC_LOG(ERROR, TAG, "CALEClientStartScan has failed");
-        return;
-    }
 }
 
 void CALEClientSetCallback(CAPacketReceiveCallback callback)
@@ -487,16 +565,96 @@ void CALEClientSetCallback(CAPacketReceiveCallback callback)
     g_packetReceiveCallback = callback;
 }
 
-CAResult_t CALEClientGetInterfaceInfo(char **address)
+void CASetBLEClientErrorHandleCallback(CABLEErrorHandleCallback callback)
 {
-    OIC_LOG(INFO, TAG, "CALEClientGetInterfaceInfo is not supported");
-    return CA_NOT_SUPPORTED;
+    g_clientErrorCallback = callback;
+}
+
+CAResult_t CALEClientIsThereScannedDevices(JNIEnv *env, const char* address)
+{
+    VERIFY_NON_NULL(env, TAG, "env");
+
+    if (!g_deviceList)
+    {
+        return CA_STATUS_FAILED;
+    }
+
+    if (0 == u_arraylist_length(g_deviceList) // multicast
+            || (address && !CALEClientIsDeviceInScanDeviceList(env, address))) // unicast
+    {
+        // Wait for LE peripherals to be discovered.
+
+        // Number of times to wait for discovery to complete.
+        static size_t const RETRIES = 5;
+
+        static uint64_t const TIMEOUT =
+            2 * MICROSECS_PER_SEC;  // Microseconds
+
+        bool devicesDiscovered = false;
+        for (size_t i = 0; i < RETRIES; ++i)
+        {
+            OIC_LOG(DEBUG, TAG, "waiting for target device");
+            if (ca_cond_wait_for(g_deviceDescCond,
+                                 g_threadSendMutex,
+                                 TIMEOUT) == CA_WAIT_SUCCESS)
+            {
+                ca_mutex_lock(g_deviceListMutex);
+                size_t scannedDeviceLen = u_arraylist_length(g_deviceList);
+                ca_mutex_unlock(g_deviceListMutex);
+
+                if (0 < scannedDeviceLen)
+                {
+                    if (!address  // multicast
+                        || (address && CALEClientIsDeviceInScanDeviceList(env, address))) // unicast
+                    {
+                      devicesDiscovered = true;
+                      break;
+                    }
+                    else
+                    {
+                        if (address)
+                        {
+                            OIC_LOG(INFO, TAG, "waiting..");
+
+                            ca_mutex_lock(g_deviceScanRetryDelayMutex);
+                            if (ca_cond_wait_for(g_deviceScanRetryDelayCond,
+                                                 g_deviceScanRetryDelayMutex,
+                                                 MICROSECS_PER_SEC) == CA_WAIT_SUCCESS)
+                            {
+                                OIC_LOG(INFO, TAG, "finish to waiting for target device");
+                                ca_mutex_unlock(g_deviceScanRetryDelayMutex);
+                                break;
+                            }
+                            ca_mutex_unlock(g_deviceScanRetryDelayMutex);
+                            // time out
+
+                            // checking whether a target device is found while waiting for time-out.
+                            if (CALEClientIsDeviceInScanDeviceList(env, address))
+                            {
+                                devicesDiscovered = true;
+                                break;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        // time out for scanning devices
+        if (!devicesDiscovered)
+        {
+            return CA_STATUS_FAILED;
+        }
+    }
+
+    return CA_STATUS_OK;
 }
 
-CAResult_t CALEClientSendUnicastMessageImpl(const char* address, const char* data,
+
+CAResult_t CALEClientSendUnicastMessageImpl(const char* address, const uint8_t* data,
                                       const uint32_t dataLen)
 {
-    OIC_LOG_V(DEBUG, TAG, "CALEClientSendUnicastMessageImpl, address: %s, data: %s", address,
+    OIC_LOG_V(DEBUG, TAG, "CALEClientSendUnicastMessageImpl, address: %s, data: %p", address,
               data);
     VERIFY_NON_NULL(address, TAG, "address is null");
     VERIFY_NON_NULL(data, TAG, "data is null");
@@ -524,7 +682,15 @@ CAResult_t CALEClientSendUnicastMessageImpl(const char* address, const char* dat
 
     ca_mutex_lock(g_threadSendMutex);
 
-    CAResult_t ret = CA_STATUS_OK;
+    CALEClientSetSendFinishFlag(false);
+
+    CAResult_t ret = CALEClientIsThereScannedDevices(env, address);
+    if (CA_STATUS_OK != ret)
+    {
+        OIC_LOG(INFO, TAG, "there is no scanned device");
+        goto error_exit;
+    }
+
     if (g_context && g_deviceList)
     {
         uint32_t length = u_arraylist_length(g_deviceList);
@@ -568,32 +734,21 @@ CAResult_t CALEClientSendUnicastMessageImpl(const char* address, const char* dat
                 if (g_sendBuffer)
                 {
                     (*env)->DeleteGlobalRef(env, g_sendBuffer);
+                    g_sendBuffer = NULL;
                 }
                 jbyteArray jni_arr = (*env)->NewByteArray(env, dataLen);
                 (*env)->SetByteArrayRegion(env, jni_arr, 0, dataLen, (jbyte*) data);
                 g_sendBuffer = (jbyteArray)(*env)->NewGlobalRef(env, jni_arr);
 
+                // Target device to send message is just one.
+                g_targetCnt = 1;
+
                 ret = CALEClientSendData(env, jarrayObj);
                 if (CA_STATUS_OK != ret)
                 {
                     OIC_LOG(ERROR, TAG, "CALEClientSendData in unicast is failed");
                     goto error_exit;
                 }
-                else
-                {
-                    CALEClientSetTheSendRequestFlag(true);
-                    ca_cond_signal(g_threadSendCBCond);
-
-                    if (!g_isReceivedWriteCB)
-                    {
-                        OIC_LOG(INFO, TAG, "wait..(unicast)");
-                        ca_cond_wait(g_threadSendCond, g_threadSendMutex);
-                    }
-                    else
-                    {
-                        CALEClientSetWriteCharacteristicCBFlag(false);
-                    }
-                }
 
                 OIC_LOG(INFO, TAG, "wake up");
                 break;
@@ -602,16 +757,22 @@ CAResult_t CALEClientSendUnicastMessageImpl(const char* address, const char* dat
         }
     }
 
-    if (isAttached)
+    OIC_LOG(DEBUG, TAG, "connection routine is finished for unicast");
+
+    // wait for finish to send data through "CALeGattServicesDiscoveredCallback"
+    // if there is no connection state.
+    ca_mutex_lock(g_threadMutex);
+    if (!g_isFinishedSendData)
     {
-        (*g_jvm)->DetachCurrentThread(g_jvm);
+        OIC_LOG(DEBUG, TAG, "waiting send finish signal");
+        ca_cond_wait(g_threadCond, g_threadMutex);
+        OIC_LOG(DEBUG, TAG, "the data was sent");
     }
+    ca_mutex_unlock(g_threadMutex);
 
-    ret = CALECheckSendState(address);
-    if(CA_STATUS_OK != ret)
+    if (isAttached)
     {
-        OIC_LOG(ERROR, TAG, "send has failed");
-        goto error_exit;
+        (*g_jvm)->DetachCurrentThread(g_jvm);
     }
 
     // start LE Scan again
@@ -624,8 +785,8 @@ CAResult_t CALEClientSendUnicastMessageImpl(const char* address, const char* dat
     }
 
     ca_mutex_unlock(g_threadSendMutex);
-    OIC_LOG(INFO, TAG, "unicast - send success");
-    return CA_STATUS_OK;
+    OIC_LOG(INFO, TAG, "unicast - send logic has finished");
+    return CALECheckSendState(address);
 
     // error label.
 error_exit:
@@ -636,6 +797,10 @@ error_exit:
     {
         OIC_LOG(ERROR, TAG, "CALEClientStartScan has failed");
         ca_mutex_unlock(g_threadSendMutex);
+        if (isAttached)
+        {
+            (*g_jvm)->DetachCurrentThread(g_jvm);
+        }
         return res;
     }
 
@@ -643,14 +808,19 @@ error_exit:
     {
         (*g_jvm)->DetachCurrentThread(g_jvm);
     }
+
+    if (g_clientErrorCallback)
+    {
+        g_clientErrorCallback(address, data, dataLen, CA_SEND_FAILED);
+    }
     ca_mutex_unlock(g_threadSendMutex);
     return CA_SEND_FAILED;
 }
 
-CAResult_t CALEClientSendMulticastMessageImpl(JNIEnv *env, const char* data,
+CAResult_t CALEClientSendMulticastMessageImpl(JNIEnv *env, const uint8_t* data,
                                               const uint32_t dataLen)
 {
-    OIC_LOG_V(DEBUG, TAG, "CASendMulticastMessageImpl, send to, data: %s, %d", data, dataLen);
+    OIC_LOG_V(DEBUG, TAG, "CASendMulticastMessageImpl, send to, data: %p, %u", data, dataLen);
     VERIFY_NON_NULL(data, TAG, "data is null");
     VERIFY_NON_NULL(env, TAG, "env is null");
 
@@ -668,95 +838,74 @@ CAResult_t CALEClientSendMulticastMessageImpl(JNIEnv *env, const char* data,
     if (g_sendBuffer)
     {
         (*env)->DeleteGlobalRef(env, g_sendBuffer);
+        g_sendBuffer = NULL;
+    }
+
+    CAResult_t res = CALEClientIsThereScannedDevices(env, NULL);
+    if (CA_STATUS_OK != res)
+    {
+        OIC_LOG(INFO, TAG, "there is no scanned device");
+        goto error_exit;
     }
-    jbyteArray jni_arr = (*env)->NewByteArray(env, dataLen);
-    (*env)->SetByteArrayRegion(env, jni_arr, 0, dataLen, (jbyte*) data);
-    g_sendBuffer = (jbyteArray)(*env)->NewGlobalRef(env, jni_arr);
 
     // connect to gatt server
-    CAResult_t res = CALEClientStopScan();
+    res = CALEClientStopScan();
     if (CA_STATUS_OK != res)
     {
         OIC_LOG(ERROR, TAG, "CALEClientStopScan has failed");
         ca_mutex_unlock(g_threadSendMutex);
         return res;
     }
-
     uint32_t length = u_arraylist_length(g_deviceList);
     g_targetCnt = length;
-    if (0 == length)
-    {
-        goto error_exit;
-    }
 
-    uint32_t index = 0;
-    while (index < length)
+    jbyteArray jni_arr = (*env)->NewByteArray(env, dataLen);
+    (*env)->SetByteArrayRegion(env, jni_arr, 0, dataLen, (jbyte*) data);
+    g_sendBuffer = (jbyteArray)(*env)->NewGlobalRef(env, jni_arr);
+
+    for (uint32_t index = 0; index < length; index++)
     {
         jobject jarrayObj = (jobject) u_arraylist_get(g_deviceList, index);
         if (!jarrayObj)
         {
-            OIC_LOG(ERROR, TAG, "jarrayObj is null");
+            OIC_LOG(ERROR, TAG, "jarrayObj is not available");
             continue;
         }
 
         res = CALEClientSendData(env, jarrayObj);
         if (res != CA_STATUS_OK)
         {
-            OIC_LOG(ERROR, TAG, "BT device[%d] - send has failed");
-        }
-        else
-        {
-            CALEClientSetTheSendRequestFlag(true);
-            ca_cond_signal(g_threadSendCBCond);
-
-            if (!g_isReceivedWriteCB)
-            {
-                OIC_LOG(INFO, TAG, "wait..(multicast)");
-                ca_cond_wait(g_threadSendCond, g_threadSendMutex);
-            }
-            else
-            {
-                CALEClientSetWriteCharacteristicCBFlag(false);
-            }
+            OIC_LOG(ERROR, TAG, "BT device - send has failed");
         }
 
         jstring jni_address = CALEGetAddressFromBTDevice(env, jarrayObj);
         if (!jni_address)
         {
             OIC_LOG(ERROR, TAG, "CALEGetAddressFromBTDevice has failed");
-            goto error_exit;
+            continue;
         }
 
         const char* address = (*env)->GetStringUTFChars(env, jni_address, NULL);
         if (!address)
         {
             OIC_LOG(ERROR, TAG, "address is not available");
-            goto error_exit;
-        }
-
-        res = CALECheckSendState(address);
-        if (CA_STATUS_OK != res)
-        {
-            OIC_LOG(ERROR, TAG, "send has failed");
-            (*env)->ReleaseStringUTFChars(env, jni_address, address);
-            goto error_exit;
+            continue;
         }
 
         (*env)->ReleaseStringUTFChars(env, jni_address, address);
-
-        index++;
     }
 
-    OIC_LOG(DEBUG, TAG, "connection routine is finished");
+    OIC_LOG(DEBUG, TAG, "connection routine is finished for multicast");
 
     // wait for finish to send data through "CALeGattServicesDiscoveredCallback"
+    ca_mutex_lock(g_threadMutex);
     if (!g_isFinishedSendData)
     {
-        ca_mutex_lock(g_threadMutex);
+        OIC_LOG(DEBUG, TAG, "waiting send finish signal");
         ca_cond_wait(g_threadCond, g_threadMutex);
-        OIC_LOG(DEBUG, TAG, "the data was sent for All devices");
-        ca_mutex_unlock(g_threadMutex);
+        OIC_LOG(DEBUG, TAG, "the data was sent");
     }
+    ca_mutex_unlock(g_threadMutex);
 
     // start LE Scan again
     res = CALEClientStartScan();
@@ -804,6 +953,8 @@ CAResult_t CALECheckSendState(const char* address)
         ca_mutex_unlock(g_deviceStateListMutex);
         return CA_SEND_FAILED;
     }
+
+    OIC_LOG(INFO, TAG, "sendstate is STATE_SEND_SUCCESS");
     ca_mutex_unlock(g_deviceStateListMutex);
     return CA_STATUS_OK;
 }
@@ -814,32 +965,59 @@ CAResult_t CALEClientSendData(JNIEnv *env, jobject device)
     VERIFY_NON_NULL(device, TAG, "device is null");
     VERIFY_NON_NULL(env, TAG, "env is null");
 
-    jstring jni_address = CALEGetAddressFromBTDevice(env, device);
-    if (!jni_address)
-    {
-        OIC_LOG(ERROR, TAG, "CALEGetAddressFromBTDevice has failed");
-        return CA_STATUS_FAILED;
-    }
-
-    const char* address = (*env)->GetStringUTFChars(env, jni_address, NULL);
-    if (!address)
+    // get BLE address from bluetooth device object.
+    char* address = NULL;
+    CALEState_t* state = NULL;
+    jstring jni_address = CALEClientGetLEAddressFromBTDevice(env, device);
+    if (jni_address)
     {
-        OIC_LOG(ERROR, TAG, "address is not available");
-        return CA_STATUS_FAILED;
+        OIC_LOG(INFO, TAG, "there is gatt object..it's not first connection");
+        address = (char*)(*env)->GetStringUTFChars(env, jni_address, NULL);
+        if (!address)
+        {
+            OIC_LOG(ERROR, TAG, "address is not available");
+            return CA_STATUS_FAILED;
+        }
+        ca_mutex_lock(g_deviceStateListMutex);
+        state = CALEClientGetStateInfo(address);
+        ca_mutex_unlock(g_deviceStateListMutex);
+        (*env)->ReleaseStringUTFChars(env, jni_address, address);
     }
 
-    ca_mutex_lock(g_deviceStateListMutex);
-    CALEState_t* state = CALEClientGetStateInfo(address);
-    ca_mutex_unlock(g_deviceStateListMutex);
     if (!state)
     {
         OIC_LOG(DEBUG, TAG, "state is empty..start to connect LE");
-        CAResult_t ret = CALEClientConnect(env, device, JNI_FALSE, g_leGattCallback);
-        if (CA_STATUS_OK != ret)
+
+        // cancel previous connection request before connection
+        // if there is gatt object in g_gattObjectList.
+        if (jni_address)
         {
-            OIC_LOG(ERROR, TAG, "CALEClientConnect has failed");
+            address = (char*)(*env)->GetStringUTFChars(env, jni_address, NULL);
+            if (!address)
+            {
+                OIC_LOG(ERROR, TAG, "address is not available");
+                return CA_STATUS_FAILED;
+            }
+
+            jobject gatt = CALEClientGetGattObjInList(env, address);
+            if (gatt)
+            {
+                CAResult_t res = CALEClientDisconnect(env, gatt);
+                if (CA_STATUS_OK != res)
+                {
+                    OIC_LOG(INFO, TAG, "there is no gatt object");
+                }
+            }
             (*env)->ReleaseStringUTFChars(env, jni_address, address);
-            return ret;
+        }
+
+        // connection request
+        jobject newGatt = CALEClientConnect(env, device,
+                                            JNI_FALSE);
+        if (NULL == newGatt)
+        {
+            OIC_LOG(ERROR, TAG, "CALEClientConnect has failed");
+            return CA_STATUS_FAILED;
         }
     }
     else
@@ -847,6 +1025,19 @@ CAResult_t CALEClientSendData(JNIEnv *env, jobject device)
         if (STATE_CONNECTED == state->connectedState)
         {
             OIC_LOG(INFO, TAG, "GATT has already connected");
+            if (!jni_address)
+            {
+                OIC_LOG(ERROR, TAG, "jni_address is not available");
+                return CA_STATUS_FAILED;
+            }
+
+            address = (char*)(*env)->GetStringUTFChars(env, jni_address, NULL);
+            if (!address)
+            {
+                OIC_LOG(ERROR, TAG, "address is not available");
+                return CA_STATUS_FAILED;
+            }
+
             jobject gatt = CALEClientGetGattObjInList(env, address);
             if (!gatt)
             {
@@ -855,28 +1046,53 @@ CAResult_t CALEClientSendData(JNIEnv *env, jobject device)
                 return CA_STATUS_FAILED;
             }
 
-            CAResult_t ret = CALEClientWriteCharacteristic(env, gatt);
+            CAResult_t ret = CALESetValueAndWriteCharacteristic(env, gatt);
             if (CA_STATUS_OK != ret)
             {
-                OIC_LOG(ERROR, TAG, "CALEClientWriteCharacteristic has failed");
+                OIC_LOG(ERROR, TAG, "CALESetValueAndWriteCharacteristic has failed");
                 (*env)->ReleaseStringUTFChars(env, jni_address, address);
                 return ret;
             }
+            (*env)->ReleaseStringUTFChars(env, jni_address, address);
         }
         else
         {
+            OIC_LOG(INFO, TAG, "STATE_DISCONNECTED - start to connect LE");
+
+            // cancel previous connection request before connection
+            // if there is gatt object in g_gattObjectList.
+            if (jni_address)
+            {
+                address = (char*)(*env)->GetStringUTFChars(env, jni_address, NULL);
+                if (!address)
+                {
+                    OIC_LOG(ERROR, TAG, "address is not available");
+                    return CA_STATUS_FAILED;
+                }
+
+                jobject gatt = CALEClientGetGattObjInList(env, address);
+                if (gatt)
+                {
+                    CAResult_t res = CALEClientDisconnect(env, gatt);
+                    if (CA_STATUS_OK != res)
+                    {
+                        OIC_LOG(INFO, TAG, "there is no gatt object");
+                    }
+                }
+                (*env)->ReleaseStringUTFChars(env, jni_address, address);
+            }
+
             OIC_LOG(DEBUG, TAG, "start to connect LE");
-            CAResult_t ret = CALEClientConnect(env, device, JNI_FALSE, g_leGattCallback);
-            if (CA_STATUS_OK != ret)
+            jobject gatt = CALEClientConnect(env, device,
+                                             CALEClientGetAutoConnectFlag(env, jni_address));
+            if (NULL == gatt)
             {
                 OIC_LOG(ERROR, TAG, "CALEClientConnect has failed");
-                (*env)->ReleaseStringUTFChars(env, jni_address, address);
-                return ret;
+                return CA_STATUS_FAILED;
             }
         }
     }
 
-    (*env)->ReleaseStringUTFChars(env, jni_address, address);
     return CA_STATUS_OK;
 }
 
@@ -885,15 +1101,8 @@ jstring CALEClientGetAddressFromGattObj(JNIEnv *env, jobject gatt)
     VERIFY_NON_NULL_RET(gatt, TAG, "gatt is null", NULL);
     VERIFY_NON_NULL_RET(env, TAG, "env is null", NULL);
 
-    jclass jni_cid_gattdevice_list = (*env)->FindClass(env, CLASSPATH_BT_GATT);
-    if (!jni_cid_gattdevice_list)
-    {
-        OIC_LOG(ERROR, TAG, "jni_cid_gattdevice_list is null");
-        return NULL;
-    }
-
-    jmethodID jni_mid_getDevice = (*env)->GetMethodID(env, jni_cid_gattdevice_list, "getDevice",
-                                                      "()Landroid/bluetooth/BluetoothDevice;");
+    jmethodID jni_mid_getDevice = CALEGetJNIMethodID(env, CLASSPATH_BT_GATT, "getDevice",
+                                                     "()Landroid/bluetooth/BluetoothDevice;");
     if (!jni_mid_getDevice)
     {
         OIC_LOG(ERROR, TAG, "jni_mid_getDevice is null");
@@ -927,16 +1136,9 @@ CAResult_t CALEClientGattClose(JNIEnv *env, jobject bluetoothGatt)
     VERIFY_NON_NULL(bluetoothGatt, TAG, "bluetoothGatt is null");
     VERIFY_NON_NULL(env, TAG, "env is null");
 
-    // get BluetoothGatt class
-    OIC_LOG(DEBUG, TAG, "get BluetoothGatt class");
-    jclass jni_cid_BluetoothGatt = (*env)->FindClass(env, CLASSPATH_BT_GATT);
-    if (!jni_cid_BluetoothGatt)
-    {
-        OIC_LOG(ERROR, TAG, "jni_cid_BluetoothGatt is null");
-        return CA_STATUS_FAILED;
-    }
-
-    jmethodID jni_mid_closeGatt = (*env)->GetMethodID(env, jni_cid_BluetoothGatt, "close", "()V");
+    // get BluetoothGatt method
+    OIC_LOG(DEBUG, TAG, "get BluetoothGatt method");
+    jmethodID jni_mid_closeGatt = CALEGetJNIMethodID(env, CLASSPATH_BT_GATT, "close", "()V");
     if (!jni_mid_closeGatt)
     {
         OIC_LOG(ERROR, TAG, "jni_mid_closeGatt is null");
@@ -960,12 +1162,6 @@ CAResult_t CALEClientGattClose(JNIEnv *env, jobject bluetoothGatt)
 
 CAResult_t CALEClientStartScan()
 {
-    if (!g_isStartedMulticastServer)
-    {
-        OIC_LOG(ERROR, TAG, "server is not started yet..scan will be passed");
-        return CA_STATUS_FAILED;
-    }
-
     if (!g_isStartedLEClient)
     {
         OIC_LOG(ERROR, TAG, "LE client is not started");
@@ -1006,19 +1202,22 @@ CAResult_t CALEClientStartScan()
     // scan gatt server with UUID
     if (g_leScanCallback && g_uuidList)
     {
-#ifndef FULL_SCAN
+#ifdef UUID_SCAN
         ret = CALEClientStartScanWithUUIDImpl(env, g_uuidList, g_leScanCallback);
-        if(CA_STATUS_OK != ret)
-        {
-            OIC_LOG(ERROR, TAG, "CALEClientStartScanWithUUIDImpl has failed");
-        }
 #else
         ret = CALEClientStartScanImpl(env, g_leScanCallback);
+#endif
         if (CA_STATUS_OK != ret)
         {
-            OIC_LOG(ERROR, TAG, "CALEClientStartScanImpl has failed");
+            if (CA_ADAPTER_NOT_ENABLED == ret)
+            {
+                OIC_LOG(DEBUG, TAG, "Adapter is disabled");
+            }
+            else
+            {
+                OIC_LOG(ERROR, TAG, "start scan has failed");
+            }
         }
-#endif
     }
 
     if (isAttached)
@@ -1036,7 +1235,7 @@ CAResult_t CALEClientStartScanImpl(JNIEnv *env, jobject callback)
 
     if (!CALEIsEnableBTAdapter(env))
     {
-        OIC_LOG(ERROR, TAG, "BT adapter is not enabled");
+        OIC_LOG(INFO, TAG, "BT adapter is not enabled");
         return CA_ADAPTER_NOT_ENABLED;
     }
 
@@ -1082,13 +1281,12 @@ CAResult_t CALEClientStartScanImpl(JNIEnv *env, jobject callback)
                                                              jni_mid_startLeScan, callback);
     if (!jni_obj_startLeScan)
     {
-        OIC_LOG(ERROR, TAG, "startLeScan is failed");
-        return CA_STATUS_FAILED;
+        OIC_LOG(INFO, TAG, "startLeScan is failed");
     }
     else
     {
         OIC_LOG(DEBUG, TAG, "startLeScan is started");
-        g_isStartedScan = true;
+        CALEClientSetScanFlag(true);
     }
 
     return CA_STATUS_OK;
@@ -1102,7 +1300,7 @@ CAResult_t CALEClientStartScanWithUUIDImpl(JNIEnv *env, jobjectArray uuids, jobj
 
     if (!CALEIsEnableBTAdapter(env))
     {
-        OIC_LOG(ERROR, TAG, "BT adapter is not enabled");
+        OIC_LOG(INFO, TAG, "BT adapter is not enabled");
         return CA_ADAPTER_NOT_ENABLED;
     }
 
@@ -1147,13 +1345,12 @@ CAResult_t CALEClientStartScanWithUUIDImpl(JNIEnv *env, jobjectArray uuids, jobj
                                                              jni_mid_startLeScan, uuids, callback);
     if (!jni_obj_startLeScan)
     {
-        OIC_LOG(ERROR, TAG, "startLeScan With UUID is failed");
-        return CA_STATUS_FAILED;
+        OIC_LOG(INFO, TAG, "startLeScan With UUID is failed");
     }
     else
     {
         OIC_LOG(DEBUG, TAG, "startLeScan With UUID is started");
-        g_isStartedScan = true;
+        CALEClientSetScanFlag(true);
     }
 
     return CA_STATUS_OK;
@@ -1225,11 +1422,18 @@ CAResult_t CALEClientStopScan()
     CAResult_t ret = CALEClientStopScanImpl(env, g_leScanCallback);
     if (CA_STATUS_OK != ret)
     {
-        OIC_LOG(ERROR, TAG, "CALEClientStopScanImpl has failed");
+        if (CA_ADAPTER_NOT_ENABLED == ret)
+        {
+            OIC_LOG(DEBUG, TAG, "Adapter is disabled");
+        }
+        else
+        {
+            OIC_LOG(ERROR, TAG, "CALEClientStopScanImpl has failed");
+        }
     }
     else
     {
-        g_isStartedScan = false;
+        CALEClientSetScanFlag(false);
     }
 
     if (isAttached)
@@ -1240,6 +1444,13 @@ CAResult_t CALEClientStopScan()
     return ret;
 }
 
+void CALEClientSetScanFlag(bool flag)
+{
+    ca_mutex_lock(g_scanMutex);
+    g_isStartedScan = flag;
+    ca_mutex_unlock(g_scanMutex);
+}
+
 CAResult_t CALEClientStopScanImpl(JNIEnv *env, jobject callback)
 {
     OIC_LOG(DEBUG, TAG, "CALEClientStopScanImpl");
@@ -1248,7 +1459,7 @@ CAResult_t CALEClientStopScanImpl(JNIEnv *env, jobject callback)
 
     if (!CALEIsEnableBTAdapter(env))
     {
-        OIC_LOG(ERROR, TAG, "BT adapter is not enabled");
+        OIC_LOG(INFO, TAG, "BT adapter is not enabled");
         return CA_ADAPTER_NOT_ENABLED;
     }
 
@@ -1303,89 +1514,276 @@ CAResult_t CALEClientStopScanImpl(JNIEnv *env, jobject callback)
     return CA_STATUS_OK;
 }
 
-CAResult_t CALEClientConnect(JNIEnv *env, jobject bluetoothDevice, jboolean autoconnect,
-                             jobject callback)
+CAResult_t CALEClientSetAutoConnectFlag(JNIEnv *env, jstring jni_address, jboolean flag)
+{
+    OIC_LOG(DEBUG, TAG, "IN - CALEClientSetAutoConnectFlag");
+    VERIFY_NON_NULL(env, TAG, "env");
+    VERIFY_NON_NULL(jni_address, TAG, "jni_address");
+
+    ca_mutex_lock(g_deviceStateListMutex);
+
+    char* address = (char*)(*env)->GetStringUTFChars(env, jni_address, NULL);
+    if (!address)
+    {
+        OIC_LOG(ERROR, TAG, "address is not available");
+        return CA_STATUS_FAILED;
+    }
+
+    if (CALEClientIsDeviceInList(address))
+    {
+        CALEState_t* curState = CALEClientGetStateInfo(address);
+        if(!curState)
+        {
+            OIC_LOG(ERROR, TAG, "curState is null");
+            (*env)->ReleaseStringUTFChars(env, jni_address, address);
+            ca_mutex_unlock(g_deviceStateListMutex);
+            return CA_STATUS_FAILED;
+        }
+        OIC_LOG_V(INFO, TAG, "auto connect flag is set %d", flag);
+
+        curState->autoConnectFlag = flag;
+    }
+
+    (*env)->ReleaseStringUTFChars(env, jni_address, address);
+    ca_mutex_unlock(g_deviceStateListMutex);
+    OIC_LOG(DEBUG, TAG, "OUT - CALEClientSetAutoConnectFlag");
+    return CA_STATUS_OK;
+}
+
+jboolean CALEClientGetAutoConnectFlag(JNIEnv *env, jstring jni_address)
+{
+    OIC_LOG(DEBUG, TAG, "IN - CALEClientGetAutoConnectFlag");
+    VERIFY_NON_NULL_RET(env, TAG, "env", false);
+    VERIFY_NON_NULL_RET(jni_address, TAG, "jni_address", false);
+
+    ca_mutex_lock(g_deviceStateListMutex);
+
+    char* address = (char*)(*env)->GetStringUTFChars(env, jni_address, NULL);
+    if (!address)
+    {
+        OIC_LOG(ERROR, TAG, "address is not available");
+        return JNI_FALSE;
+    }
+
+    CALEState_t* curState = CALEClientGetStateInfo(address);
+    if(!curState)
+    {
+        OIC_LOG(INFO, TAG, "there is no information. auto connect flag is false");
+        (*env)->ReleaseStringUTFChars(env, jni_address, address);
+        ca_mutex_unlock(g_deviceStateListMutex);
+        return JNI_FALSE;
+    }
+    OIC_LOG_V(INFO, TAG, "auto connect flag is %d", curState->autoConnectFlag);
+
+    (*env)->ReleaseStringUTFChars(env, jni_address, address);
+    ca_mutex_unlock(g_deviceStateListMutex);
+
+    OIC_LOG(DEBUG, TAG, "OUT - CALEClientGetAutoConnectFlag");
+    return curState->autoConnectFlag;
+}
+
+jobject CALEClientConnect(JNIEnv *env, jobject bluetoothDevice, jboolean autoconnect)
+{
+    OIC_LOG(DEBUG, TAG, "CALEClientConnect");
+    VERIFY_NON_NULL_RET(env, TAG, "env is null", NULL);
+    VERIFY_NON_NULL_RET(bluetoothDevice, TAG, "bluetoothDevice is null", NULL);
+
+    // get gatt object from Bluetooth Device object for closeProfileProxy(..)
+    jstring jni_address = CALEClientGetLEAddressFromBTDevice(env, bluetoothDevice);
+    if (jni_address)
+    {
+        const char* address = (*env)->GetStringUTFChars(env, jni_address, NULL);
+        if (!address)
+        {
+            OIC_LOG(ERROR, TAG, "address is not available");
+            return NULL;
+        }
+
+        // close the gatt service
+        jobject gatt = CALEClientGetGattObjInList(env, address);
+        if (gatt)
+        {
+            CAResult_t res = CALEClientCloseProfileProxy(env, gatt);
+            if (CA_STATUS_OK != res)
+            {
+                OIC_LOG(ERROR, TAG, "CALEClientCloseProfileProxy has failed");
+                (*env)->ReleaseStringUTFChars(env, jni_address, address);
+                return NULL;
+            }
+
+            // clean previous gatt object after close profile service
+            res = CALEClientRemoveGattObjForAddr(env, jni_address);
+            if (CA_STATUS_OK != res)
+            {
+                OIC_LOG(ERROR, TAG, "CALEClientRemoveGattObjForAddr has failed");
+                (*env)->ReleaseStringUTFChars(env, jni_address, address);
+                return NULL;
+            }
+        }
+        (*env)->ReleaseStringUTFChars(env, jni_address, address);
+    }
+
+    jobject newGatt = CALEClientGattConnect(env, bluetoothDevice, autoconnect);
+    if (!newGatt)
+    {
+        OIC_LOG(DEBUG, TAG, "re-connection will be started");
+        return NULL;
+    }
+
+    // add new gatt object into g_gattObjectList
+    CAResult_t res = CALEClientAddGattobjToList(env, newGatt);
+    if (CA_STATUS_OK != res)
+    {
+        OIC_LOG(ERROR, TAG, "CALEClientAddGattobjToList has failed");
+        return NULL;
+    }
+
+    return newGatt;
+}
+
+jobject CALEClientGattConnect(JNIEnv *env, jobject bluetoothDevice, jboolean autoconnect)
 {
     OIC_LOG(DEBUG, TAG, "GATT CONNECT");
-    VERIFY_NON_NULL(env, TAG, "env is null");
-    VERIFY_NON_NULL(bluetoothDevice, TAG, "bluetoothDevice is null");
-    VERIFY_NON_NULL(callback, TAG, "callback is null");
+    VERIFY_NON_NULL_RET(env, TAG, "env is null", NULL);
+    VERIFY_NON_NULL_RET(bluetoothDevice, TAG, "bluetoothDevice is null", NULL);
+
+    if (!g_leGattCallback)
+    {
+        OIC_LOG(INFO, TAG, "g_leGattCallback is null");
+        return NULL;
+    }
 
     if (!CALEIsEnableBTAdapter(env))
     {
-        OIC_LOG(ERROR, TAG, "BT adapter is not enabled");
-        return CA_ADAPTER_NOT_ENABLED;
+        OIC_LOG(INFO, TAG, "BT adapter is not enabled");
+        return NULL;
     }
 
     jstring jni_address = CALEGetAddressFromBTDevice(env, bluetoothDevice);
     if (!jni_address)
     {
         OIC_LOG(ERROR, TAG, "bleConnect: CALEGetAddressFromBTDevice is null");
-        return CA_STATUS_FAILED;
-    }
-
-    // get BluetoothDevice class
-    OIC_LOG(DEBUG, TAG, "get BluetoothDevice class");
-    jclass jni_cid_BluetoothDevice = (*env)->FindClass(env, "android/bluetooth/BluetoothDevice");
-    if (!jni_cid_BluetoothDevice)
-    {
-        OIC_LOG(ERROR, TAG, "bleConnect: jni_cid_BluetoothDevice is null");
-        return CA_STATUS_FAILED;
+        return NULL;
     }
 
-    // get connectGatt method
-    OIC_LOG(DEBUG, TAG, "get connectGatt method");
-    jmethodID jni_mid_connectGatt = (*env)->GetMethodID(env, jni_cid_BluetoothDevice, "connectGatt",
-                                                        "(Landroid/content/Context;ZLandroid/"
-                                                        "bluetooth/BluetoothGattCallback;)"
-                                                        "Landroid/bluetooth/BluetoothGatt;");
+    // get BluetoothDevice method
+    OIC_LOG(DEBUG, TAG, "get BluetoothDevice method");
+    jmethodID jni_mid_connectGatt = CALEGetJNIMethodID(env, "android/bluetooth/BluetoothDevice",
+                                                       "connectGatt",
+                                                       "(Landroid/content/Context;ZLandroid/"
+                                                       "bluetooth/BluetoothGattCallback;)"
+                                                       "Landroid/bluetooth/BluetoothGatt;");
     if (!jni_mid_connectGatt)
     {
         OIC_LOG(ERROR, TAG, "bleConnect: jni_mid_connectGatt is null");
-        return CA_STATUS_FAILED;
+        return NULL;
     }
 
-    OIC_LOG(DEBUG, TAG, "Call object method - connectGatt");
+    OIC_LOG(INFO, TAG, "CALL API - connectGatt");
     jobject jni_obj_connectGatt = (*env)->CallObjectMethod(env, bluetoothDevice,
                                                            jni_mid_connectGatt,
                                                            NULL,
-                                                           autoconnect, callback);
+                                                           autoconnect, g_leGattCallback);
     if (!jni_obj_connectGatt)
     {
-        OIC_LOG(ERROR, TAG, "CALL API - connectGatt was failed..it will be removed");
+        OIC_LOG(ERROR, TAG, "connectGatt was failed..it will be removed");
         CALEClientRemoveDeviceInScanDeviceList(env, jni_address);
         CALEClientUpdateSendCnt(env);
-        return CA_STATUS_FAILED;
+        return NULL;
     }
     else
     {
         OIC_LOG(DEBUG, TAG, "le connecting..please wait..");
     }
-    return CA_STATUS_OK;
+    return jni_obj_connectGatt;
 }
 
-CAResult_t CALEClientDisconnect(JNIEnv *env, jobject bluetoothGatt)
+CAResult_t CALEClientCloseProfileProxy(JNIEnv *env, jobject gatt)
 {
-    OIC_LOG(DEBUG, TAG, "GATT DISCONNECT");
+    OIC_LOG(DEBUG, TAG, "IN - CALEClientCloseProfileProxy");
+
     VERIFY_NON_NULL(env, TAG, "env is null");
-    VERIFY_NON_NULL(bluetoothGatt, TAG, "bluetoothGatt is null");
+    VERIFY_NON_NULL(gatt, TAG, "gatt is null");
 
-    if (!CALEIsEnableBTAdapter(env))
+    jclass jni_cid_BTAdapter = (*env)->FindClass(env, CLASSPATH_BT_ADAPTER);
+    if (!jni_cid_BTAdapter)
     {
-        OIC_LOG(ERROR, TAG, "BT adapter is not enabled");
-        return CA_ADAPTER_NOT_ENABLED;
+        OIC_LOG(ERROR, TAG, "jni_cid_BTAdapter is null");
+        return CA_STATUS_FAILED;
     }
 
-    // get BluetoothGatt class
-    jclass jni_cid_BluetoothGatt = (*env)->FindClass(env, CLASSPATH_BT_GATT);
-    if (!jni_cid_BluetoothGatt)
+    // get remote bt adapter method
+    jmethodID jni_mid_getDefaultAdapter = (*env)->GetStaticMethodID(env, jni_cid_BTAdapter,
+                                                                    "getDefaultAdapter",
+                                                                    METHODID_OBJECTNONPARAM);
+    if (!jni_mid_getDefaultAdapter)
+    {
+        OIC_LOG(ERROR, TAG, "jni_mid_getDefaultAdapter is null");
+        return CA_STATUS_FAILED;
+    }
+
+    // gat bt adapter object
+    jobject jni_obj_BTAdapter = (*env)->CallStaticObjectMethod(env, jni_cid_BTAdapter,
+                                                               jni_mid_getDefaultAdapter);
+    if (!jni_obj_BTAdapter)
+    {
+        OIC_LOG(ERROR, TAG, "jni_obj_BTAdapter is null");
+        return CA_STATUS_FAILED;
+    }
+
+    // get closeProfileProxy method
+    jmethodID jni_mid_closeProfileProxy = (*env)->GetMethodID(env, jni_cid_BTAdapter,
+                                                              "closeProfileProxy",
+                                                              "(ILandroid/bluetooth/"
+                                                              "BluetoothProfile;)V");
+    if (!jni_mid_closeProfileProxy)
+    {
+        OIC_LOG(ERROR, TAG, "jni_mid_closeProfileProxy is null");
+        return CA_STATUS_FAILED;
+    }
+
+    jclass jni_cid_BTProfile = (*env)->FindClass(env, CLASSPATH_BT_PROFILE);
+    if (!jni_cid_BTProfile)
+    {
+        OIC_LOG(ERROR, TAG, "jni_cid_BTProfile is null");
+        return CA_STATUS_FAILED;
+    }
+
+    // GATT - Constant value : 7 (0x00000007)
+    jfieldID id_gatt = (*env)->GetStaticFieldID(env, jni_cid_BTProfile,
+                                                "GATT", "I");
+    if (!id_gatt)
     {
-        OIC_LOG(ERROR, TAG, "jni_cid_BluetoothGatt is null");
+        OIC_LOG(ERROR, TAG, "id_gatt is null");
         return CA_STATUS_FAILED;
     }
 
+    jint jni_gatt = (*env)->GetStaticIntField(env, jni_cid_BTProfile, id_gatt);
+
+    OIC_LOG(DEBUG, TAG, "CALL API - close the connection of the profile proxy to the Service");
+    (*env)->CallVoidMethod(env, jni_obj_BTAdapter, jni_mid_closeProfileProxy, jni_gatt, gatt);
+    if ((*env)->ExceptionCheck(env))
+    {
+        OIC_LOG(ERROR, TAG, "closeProfileProxy has failed");
+        (*env)->ExceptionDescribe(env);
+        (*env)->ExceptionClear(env);
+        return CA_STATUS_FAILED;
+    }
+
+    OIC_LOG(DEBUG, TAG, "OUT - CALEClientCloseProfileProxy");
+    return CA_STATUS_OK;
+}
+
+
+CAResult_t CALEClientDisconnect(JNIEnv *env, jobject bluetoothGatt)
+{
+    OIC_LOG(DEBUG, TAG, "GATT DISCONNECT");
+    VERIFY_NON_NULL(env, TAG, "env is null");
+    VERIFY_NON_NULL(bluetoothGatt, TAG, "bluetoothGatt is null");
+
+    // get BluetoothGatt method
     OIC_LOG(DEBUG, TAG, "get gatt disconnect method");
-    jmethodID jni_mid_disconnectGatt = (*env)->GetMethodID(env, jni_cid_BluetoothGatt,
+    jmethodID jni_mid_disconnectGatt  = CALEGetJNIMethodID(env, CLASSPATH_BT_GATT,
                                                            "disconnect", "()V");
     if (!jni_mid_disconnectGatt)
     {
@@ -1394,6 +1792,7 @@ CAResult_t CALEClientDisconnect(JNIEnv *env, jobject bluetoothGatt)
     }
 
     // call disconnect gatt method
+    OIC_LOG(DEBUG, TAG, "CALL API - request disconnect gatt");
     (*env)->CallVoidMethod(env, bluetoothGatt, jni_mid_disconnectGatt);
     if ((*env)->ExceptionCheck(env))
     {
@@ -1403,19 +1802,59 @@ CAResult_t CALEClientDisconnect(JNIEnv *env, jobject bluetoothGatt)
         return CA_STATUS_FAILED;
     }
 
-    OIC_LOG(DEBUG, TAG, "disconnecting Gatt...");
-
+    OIC_LOG(DEBUG, TAG, "disconnecting Gatt...");
+
+    return CA_STATUS_OK;
+}
+
+CAResult_t CALEClientDisconnectAll(JNIEnv *env)
+{
+    OIC_LOG(DEBUG, TAG, "CALEClientDisconnectAll");
+    VERIFY_NON_NULL(env, TAG, "env is null");
+
+    if (!g_gattObjectList)
+    {
+        OIC_LOG(DEBUG, TAG, "already removed for g_gattObjectList");
+        return CA_STATUS_OK;
+    }
+
+    uint32_t length = u_arraylist_length(g_gattObjectList);
+    OIC_LOG_V(DEBUG, TAG, "list length : %d", length);
+    for (uint32_t index = 0; index < length; index++)
+    {
+        OIC_LOG(DEBUG, TAG, "start CALEClientDisconnectAll");
+        jobject jarrayObj = (jobject) u_arraylist_get(g_gattObjectList, index);
+        if (!jarrayObj)
+        {
+            OIC_LOG(ERROR, TAG, "jarrayObj is null");
+            continue;
+        }
+        CAResult_t res = CALEClientDisconnect(env, jarrayObj);
+        if (CA_STATUS_OK != res)
+        {
+            OIC_LOG(ERROR, TAG, "CALEClientDisconnect has failed");
+            continue;
+        }
+    }
+
     return CA_STATUS_OK;
 }
 
-CAResult_t CALEClientDisconnectAll(JNIEnv *env)
+CAResult_t CALEClientDisconnectforAddress(JNIEnv *env, jstring remote_address)
 {
-    OIC_LOG(DEBUG, TAG, "CALEClientDisconnectAll");
+    OIC_LOG(DEBUG, TAG, "IN-CALEClientDisconnectforAddress");
     VERIFY_NON_NULL(env, TAG, "env is null");
 
     if (!g_gattObjectList)
     {
-        OIC_LOG(ERROR, TAG, "g_gattObjectList is null");
+        OIC_LOG(DEBUG, TAG, "already removed for g_gattObjectList");
+        return CA_STATUS_OK;
+    }
+
+    char* address = (char*)(*env)->GetStringUTFChars(env, remote_address, NULL);
+    if (!address)
+    {
+        OIC_LOG(ERROR, TAG, "address is null");
         return CA_STATUS_FAILED;
     }
 
@@ -1428,17 +1867,43 @@ CAResult_t CALEClientDisconnectAll(JNIEnv *env)
             OIC_LOG(ERROR, TAG, "jarrayObj is null");
             continue;
         }
-        CAResult_t res = CALEClientDisconnect(env, jarrayObj);
-        if (CA_STATUS_OK != res)
+
+        jstring jni_setAddress = CALEClientGetAddressFromGattObj(env, jarrayObj);
+        if (!jni_setAddress)
         {
-            OIC_LOG(ERROR, TAG, "CALEClientDisconnect has failed");
-            continue;
+            OIC_LOG(ERROR, TAG, "jni_setAddress is null");
+            (*env)->ReleaseStringUTFChars(env, remote_address, address);
+            return CA_STATUS_FAILED;
         }
-    }
 
-    OICFree(g_gattObjectList);
-    g_gattObjectList = NULL;
+        const char* setAddress = (*env)->GetStringUTFChars(env, jni_setAddress, NULL);
+        if (!setAddress)
+        {
+            OIC_LOG(ERROR, TAG, "setAddress is null");
+            (*env)->ReleaseStringUTFChars(env, remote_address, address);
+            return CA_STATUS_FAILED;
+        }
+
+        OIC_LOG_V(DEBUG, TAG, "target address : %s, set address : %s", address, setAddress);
+        if (!strcmp(address, setAddress))
+        {
+            CAResult_t res = CALEClientDisconnect(env, jarrayObj);
+            if (CA_STATUS_OK != res)
+            {
+                OIC_LOG(ERROR, TAG, "CALEClientDisconnect has failed");
+                (*env)->ReleaseStringUTFChars(env, jni_setAddress, setAddress);
+                (*env)->ReleaseStringUTFChars(env, remote_address, address);
+                return CA_STATUS_FAILED;
+            }
+            (*env)->ReleaseStringUTFChars(env, jni_setAddress, setAddress);
+            (*env)->ReleaseStringUTFChars(env, remote_address, address);
+            return CA_STATUS_OK;
+        }
+        (*env)->ReleaseStringUTFChars(env, jni_setAddress, setAddress);
+    }
+    (*env)->ReleaseStringUTFChars(env, remote_address, address);
 
+    OIC_LOG(DEBUG, TAG, "OUT-CALEClientDisconnectforAddress");
     return CA_STATUS_OK;
 }
 
@@ -1449,27 +1914,20 @@ CAResult_t CALEClientDiscoverServices(JNIEnv *env, jobject bluetoothGatt)
 
     if (!CALEIsEnableBTAdapter(env))
     {
-        OIC_LOG(ERROR, TAG, "BT adapter is not enabled");
+        OIC_LOG(INFO, TAG, "BT adapter is not enabled");
         return CA_ADAPTER_NOT_ENABLED;
     }
 
-    // get BluetoothGatt class
-    OIC_LOG(DEBUG, TAG, "get BluetoothGatt class");
-    jclass jni_cid_BluetoothGatt = (*env)->FindClass(env, CLASSPATH_BT_GATT);
-    if (!jni_cid_BluetoothGatt)
-    {
-        OIC_LOG(ERROR, TAG, "jni_cid_BluetoothGatt is null");
-        return CA_STATUS_FAILED;
-    }
-
-    OIC_LOG(DEBUG, TAG, "discovery gatt services method");
-    jmethodID jni_mid_discoverServices = (*env)->GetMethodID(env, jni_cid_BluetoothGatt,
-                                                             "discoverServices", "()Z");
+    // get BluetoothGatt.discoverServices method
+    OIC_LOG(DEBUG, TAG, "get BluetoothGatt.discoverServices method");
+    jmethodID jni_mid_discoverServices = CALEGetJNIMethodID(env, CLASSPATH_BT_GATT,
+                                                            "discoverServices", "()Z");
     if (!jni_mid_discoverServices)
     {
         OIC_LOG(ERROR, TAG, "jni_mid_discoverServices is null");
         return CA_STATUS_FAILED;
     }
+
     // call disconnect gatt method
     OIC_LOG(DEBUG, TAG, "CALL API - request discovery gatt services");
     jboolean ret = (*env)->CallBooleanMethod(env, bluetoothGatt, jni_mid_discoverServices);
@@ -1482,17 +1940,49 @@ CAResult_t CALEClientDiscoverServices(JNIEnv *env, jobject bluetoothGatt)
     return CA_STATUS_OK;
 }
 
-CAResult_t CALEClientWriteCharacteristic(JNIEnv *env, jobject gatt)
+static void CALEWriteCharacteristicThread(void* object)
+{
+    VERIFY_NON_NULL_VOID(object, TAG, "object is null");
+
+    bool isAttached = false;
+    JNIEnv* env;
+    jint res = (*g_jvm)->GetEnv(g_jvm, (void**) &env, JNI_VERSION_1_6);
+    if (JNI_OK != res)
+    {
+        OIC_LOG(INFO, TAG, "Could not get JNIEnv pointer");
+        res = (*g_jvm)->AttachCurrentThread(g_jvm, &env, NULL);
+
+        if (JNI_OK != res)
+        {
+            OIC_LOG(ERROR, TAG, "AttachCurrentThread has failed");
+            return;
+        }
+        isAttached = true;
+    }
+
+    jobject gatt = (jobject)object;
+    CAResult_t ret = CALESetValueAndWriteCharacteristic(env, gatt);
+    if (CA_STATUS_OK != ret)
+    {
+        OIC_LOG(ERROR, TAG, "CALESetValueAndWriteCharacteristic has failed");
+    }
+
+    if (isAttached)
+    {
+        (*g_jvm)->DetachCurrentThread(g_jvm);
+    }
+}
+
+CAResult_t CALESetValueAndWriteCharacteristic(JNIEnv* env, jobject gatt)
 {
-    VERIFY_NON_NULL(env, TAG, "env is null");
     VERIFY_NON_NULL(gatt, TAG, "gatt is null");
+    VERIFY_NON_NULL(env, TAG, "env is null");
 
     // send data
     jobject jni_obj_character = CALEClientCreateGattCharacteristic(env, gatt, g_sendBuffer);
     if (!jni_obj_character)
     {
         CALEClientSendFinish(env, gatt);
-        ca_cond_signal(g_threadSendCond);
         return CA_STATUS_FAILED;
     }
 
@@ -1500,15 +1990,53 @@ CAResult_t CALEClientWriteCharacteristic(JNIEnv *env, jobject gatt)
     if (CA_STATUS_OK != ret)
     {
         CALEClientSendFinish(env, gatt);
-        ca_cond_signal(g_threadSendCond);
-        return ret;
+        return CA_STATUS_FAILED;
+    }
+
+    // wait for callback for write Characteristic with success to sent data
+    OIC_LOG_V(DEBUG, TAG, "callback flag is %d", g_isSignalSetFlag);
+    ca_mutex_lock(g_threadWriteCharacteristicMutex);
+    if (!g_isSignalSetFlag)
+    {
+        OIC_LOG(DEBUG, TAG, "wait for callback to notify writeCharacteristic is success");
+        if (CA_WAIT_SUCCESS != ca_cond_wait_for(g_threadWriteCharacteristicCond,
+                                  g_threadWriteCharacteristicMutex,
+                                  WAIT_TIME_WRITE_CHARACTERISTIC))
+        {
+            OIC_LOG(ERROR, TAG, "there is no response. write has failed");
+            g_isSignalSetFlag = false;
+            ca_mutex_unlock(g_threadWriteCharacteristicMutex);
+            return CA_STATUS_FAILED;
+        }
+    }
+    // reset flag set by writeCharacteristic Callback
+    g_isSignalSetFlag = false;
+    ca_mutex_unlock(g_threadWriteCharacteristicMutex);
+
+    OIC_LOG(INFO, TAG, "writeCharacteristic success!!");
+    return CA_STATUS_OK;
+}
+
+CAResult_t CALEClientWriteCharacteristic(JNIEnv *env, jobject gatt)
+{
+    OIC_LOG(DEBUG, TAG, "IN - CALEClientWriteCharacteristic");
+    VERIFY_NON_NULL(env, TAG, "env is null");
+    VERIFY_NON_NULL(gatt, TAG, "gatt is null");
+
+    jobject gattParam = (*env)->NewGlobalRef(env, gatt);
+    if (CA_STATUS_OK != ca_thread_pool_add_task(g_threadPoolHandle,
+                                                CALEWriteCharacteristicThread, (void*)gattParam))
+    {
+        OIC_LOG(ERROR, TAG, "Failed to create read thread!");
+        return CA_STATUS_FAILED;
     }
 
+    OIC_LOG(DEBUG, TAG, "OUT - CALEClientWriteCharacteristic");
     return CA_STATUS_OK;
 }
 
 CAResult_t CALEClientWriteCharacteristicImpl(JNIEnv *env, jobject bluetoothGatt,
-                                           jobject gattCharacteristic)
+                                             jobject gattCharacteristic)
 {
     OIC_LOG(DEBUG, TAG, "WRITE GATT CHARACTERISTIC");
     VERIFY_NON_NULL(env, TAG, "env is null");
@@ -1517,24 +2045,16 @@ CAResult_t CALEClientWriteCharacteristicImpl(JNIEnv *env, jobject bluetoothGatt,
 
     if (!CALEIsEnableBTAdapter(env))
     {
-        OIC_LOG(ERROR, TAG, "BT adapter is not enabled");
-        return CA_STATUS_FAILED;
-    }
-
-    // get BluetoothGatt class
-    OIC_LOG(DEBUG, TAG, "get BluetoothGatt class");
-    jclass jni_cid_BluetoothGatt = (*env)->FindClass(env, CLASSPATH_BT_GATT);
-    if (!jni_cid_BluetoothGatt)
-    {
-        OIC_LOG(ERROR, TAG, "jni_cid_BluetoothGatt is null");
+        OIC_LOG(INFO, TAG, "BT adapter is not enabled");
         return CA_STATUS_FAILED;
     }
 
+    // get BluetoothGatt.write characteristic method
     OIC_LOG(DEBUG, TAG, "write characteristic method");
-    jmethodID jni_mid_writeCharacteristic = (*env)->GetMethodID(env, jni_cid_BluetoothGatt,
-                                                                "writeCharacteristic",
-                                                                "(Landroid/bluetooth/"
-                                                                "BluetoothGattCharacteristic;)Z");
+    jmethodID jni_mid_writeCharacteristic = CALEGetJNIMethodID(env, CLASSPATH_BT_GATT,
+                                                               "writeCharacteristic",
+                                                               "(Landroid/bluetooth/"
+                                                               "BluetoothGattCharacteristic;)Z");
     if (!jni_mid_writeCharacteristic)
     {
         OIC_LOG(ERROR, TAG, "jni_mid_writeCharacteristic is null");
@@ -1548,7 +2068,7 @@ CAResult_t CALEClientWriteCharacteristicImpl(JNIEnv *env, jobject bluetoothGatt,
                                                        gattCharacteristic);
     if (ret)
     {
-        OIC_LOG(DEBUG, TAG, "writeCharacteristic success");
+        OIC_LOG(DEBUG, TAG, "writeCharacteristic is called successfully");
     }
     else
     {
@@ -1566,14 +2086,7 @@ CAResult_t CALEClientReadCharacteristic(JNIEnv *env, jobject bluetoothGatt)
 
     if (!CALEIsEnableBTAdapter(env))
     {
-        OIC_LOG(ERROR, TAG, "BT adapter is not enabled");
-        return CA_STATUS_FAILED;
-    }
-
-    jclass jni_cid_BluetoothGatt = (*env)->FindClass(env, CLASSPATH_BT_GATT);
-    if (!jni_cid_BluetoothGatt)
-    {
-        OIC_LOG(ERROR, TAG, "jni_cid_BluetoothGatt is null");
+        OIC_LOG(INFO, TAG, "BT adapter is not enabled");
         return CA_STATUS_FAILED;
     }
 
@@ -1592,10 +2105,10 @@ CAResult_t CALEClientReadCharacteristic(JNIEnv *env, jobject bluetoothGatt)
     }
 
     OIC_LOG(DEBUG, TAG, "read characteristic method");
-    jmethodID jni_mid_readCharacteristic = (*env)->GetMethodID(env, jni_cid_BluetoothGatt,
-                                                               "readCharacteristic",
-                                                               "(Landroid/bluetooth/"
-                                                               "BluetoothGattCharacteristic;)Z");
+    jmethodID jni_mid_readCharacteristic = CALEGetJNIMethodID(env, CLASSPATH_BT_GATT,
+                                                              "readCharacteristic",
+                                                              "(Landroid/bluetooth/"
+                                                              "BluetoothGattCharacteristic;)Z");
     if (!jni_mid_readCharacteristic)
     {
         OIC_LOG(ERROR, TAG, "jni_mid_readCharacteristic is null");
@@ -1628,24 +2141,16 @@ CAResult_t CALEClientSetCharacteristicNotification(JNIEnv *env, jobject bluetoot
 
     if (!CALEIsEnableBTAdapter(env))
     {
-        OIC_LOG(ERROR, TAG, "BT adapter is not enabled");
+        OIC_LOG(INFO, TAG, "BT adapter is not enabled");
         return CA_ADAPTER_NOT_ENABLED;
     }
 
-    // get BluetoothGatt class
+    // get BluetoothGatt.setCharacteristicNotification method
     OIC_LOG(DEBUG, TAG, "CALEClientSetCharacteristicNotification");
-    jclass jni_cid_BluetoothGatt = (*env)->FindClass(env, CLASSPATH_BT_GATT);
-    if (!jni_cid_BluetoothGatt)
-    {
-        OIC_LOG(ERROR, TAG, "jni_cid_BluetoothGatt is null");
-        return CA_STATUS_FAILED;
-    }
-
-    // set Characteristic Notification
-    jmethodID jni_mid_setNotification = (*env)->GetMethodID(env, jni_cid_BluetoothGatt,
-                                                            "setCharacteristicNotification",
-                                                            "(Landroid/bluetooth/"
-                                                            "BluetoothGattCharacteristic;Z)Z");
+    jmethodID jni_mid_setNotification = CALEGetJNIMethodID(env, CLASSPATH_BT_GATT,
+                                                              "setCharacteristicNotification",
+                                                              "(Landroid/bluetooth/"
+                                                              "BluetoothGattCharacteristic;Z)Z");
     if (!jni_mid_setNotification)
     {
         OIC_LOG(ERROR, TAG, "jni_mid_getService is null");
@@ -1675,22 +2180,16 @@ jobject CALEClientGetGattService(JNIEnv *env, jobject bluetoothGatt, jstring cha
 
     if (!CALEIsEnableBTAdapter(env))
     {
-        OIC_LOG(ERROR, TAG, "BT adapter is not enabled");
-        return NULL;
-    }
-
-    // get BluetoothGatt class
-    OIC_LOG(DEBUG, TAG, "CALEClientGetGattService");
-    jclass jni_cid_BluetoothGatt = (*env)->FindClass(env, CLASSPATH_BT_GATT);
-    if (!jni_cid_BluetoothGatt)
-    {
-        OIC_LOG(ERROR, TAG, "jni_cid_BluetoothGatt is null");
+        OIC_LOG(INFO, TAG, "BT adapter is not enabled");
         return NULL;
     }
 
-    jmethodID jni_mid_getService = (*env)->GetMethodID(
-            env, jni_cid_BluetoothGatt, "getService",
-            "(Ljava/util/UUID;)Landroid/bluetooth/BluetoothGattService;");
+    // get BluetoothGatt.getService method
+    OIC_LOG(DEBUG, TAG, "BluetoothGatt.getService");
+    jmethodID jni_mid_getService = CALEGetJNIMethodID(env, CLASSPATH_BT_GATT,
+                                                      "getService",
+                                                      "(Ljava/util/UUID;)Landroid/bluetooth/"
+                                                      "BluetoothGattService;");
     if (!jni_mid_getService)
     {
         OIC_LOG(ERROR, TAG, "jni_mid_getService is null");
@@ -1714,21 +2213,13 @@ jobject CALEClientGetGattService(JNIEnv *env, jobject bluetoothGatt, jstring cha
         return NULL;
     }
 
-    // get bluetooth gatt service class
-    jclass jni_cid_BluetoothGattService = (*env)->FindClass(
-            env, "android/bluetooth/BluetoothGattService");
-    if (!jni_cid_BluetoothGattService)
-    {
-        OIC_LOG(ERROR, TAG, "jni_cid_BluetoothGattService is null");
-        return NULL;
-    }
-
-    OIC_LOG(DEBUG, TAG, "get gatt getCharacteristic method");
-    jmethodID jni_mid_getCharacteristic = (*env)->GetMethodID(env, jni_cid_BluetoothGattService,
-                                                              "getCharacteristic",
-                                                              "(Ljava/util/UUID;)"
-                                                              "Landroid/bluetooth/"
-                                                              "BluetoothGattCharacteristic;");
+    // get bluetooth gatt service method
+    jmethodID jni_mid_getCharacteristic = CALEGetJNIMethodID(env, "android/bluetooth/"
+                                                      "BluetoothGattService",
+                                                      "getCharacteristic",
+                                                      "(Ljava/util/UUID;)"
+                                                      "Landroid/bluetooth/"
+                                                      "BluetoothGattCharacteristic;");
     if (!jni_mid_getCharacteristic)
     {
         OIC_LOG(ERROR, TAG, "jni_mid_getCharacteristic is null");
@@ -1768,7 +2259,7 @@ jobject CALEClientCreateGattCharacteristic(JNIEnv *env, jobject bluetoothGatt, j
 
     if (!CALEIsEnableBTAdapter(env))
     {
-        OIC_LOG(ERROR, TAG, "BT adapter is not enabled");
+        OIC_LOG(INFO, TAG, "BT adapter is not enabled");
         return NULL;
     }
 
@@ -1847,21 +2338,13 @@ jbyteArray CALEClientGetValueFromCharacteristic(JNIEnv *env, jobject characteris
 
     if (!CALEIsEnableBTAdapter(env))
     {
-        OIC_LOG(ERROR, TAG, "BT adapter is not enabled");
-        return NULL;
-    }
-
-    jclass jni_cid_BTGattCharacteristic = (*env)->FindClass(env, "android/bluetooth/"
-                                                            "BluetoothGattCharacteristic");
-    if (!jni_cid_BTGattCharacteristic)
-    {
-        OIC_LOG(ERROR, TAG, "jni_cid_BTGattCharacteristic is null");
+        OIC_LOG(INFO, TAG, "BT adapter is not enabled");
         return NULL;
     }
 
-    OIC_LOG(DEBUG, TAG, "get value in Characteristic");
-    jmethodID jni_mid_getValue = (*env)->GetMethodID(env, jni_cid_BTGattCharacteristic, "getValue",
-                                                     "()[B");
+    jmethodID jni_mid_getValue  = CALEGetJNIMethodID(env, "android/bluetooth/"
+                                                     "BluetoothGattCharacteristic",
+                                                     "getValue", "()[B");
     if (!jni_mid_getValue)
     {
         OIC_LOG(ERROR, TAG, "jni_mid_getValue is null");
@@ -1950,21 +2433,13 @@ CAResult_t CALEClientSetUUIDToDescriptor(JNIEnv *env, jobject bluetoothGatt,
 
     if (!CALEIsEnableBTAdapter(env))
     {
-        OIC_LOG(ERROR, TAG, "BT adapter is not enabled");
+        OIC_LOG(INFO, TAG, "BT adapter is not enabled");
         return CA_ADAPTER_NOT_ENABLED;
     }
 
     OIC_LOG(DEBUG, TAG, "CALEClientSetUUIDToDescriptor");
-    jclass jni_cid_BTGattCharacteristic = (*env)->FindClass(env, "android/bluetooth/"
-                                                            "BluetoothGattCharacteristic");
-    if (!jni_cid_BTGattCharacteristic)
-    {
-        OIC_LOG(ERROR, TAG, "jni_cid_BTGattCharacteristic is null");
-        return CA_STATUS_FAILED;
-    }
-
-    OIC_LOG(DEBUG, TAG, "set value in Characteristic");
-    jmethodID jni_mid_getDescriptor = (*env)->GetMethodID(env, jni_cid_BTGattCharacteristic,
+    jmethodID jni_mid_getDescriptor  = CALEGetJNIMethodID(env, "android/bluetooth/"
+                                                          "BluetoothGattCharacteristic",
                                                           "getDescriptor",
                                                           "(Ljava/util/UUID;)Landroid/bluetooth/"
                                                           "BluetoothGattDescriptor;");
@@ -1986,8 +2461,8 @@ CAResult_t CALEClientSetUUIDToDescriptor(JNIEnv *env, jobject bluetoothGatt,
                                                           jni_mid_getDescriptor, jni_obj_cc_uuid);
     if (!jni_obj_descriptor)
     {
-        OIC_LOG(ERROR, TAG, "jni_obj_descriptor is null");
-        return CA_STATUS_FAILED;
+        OIC_LOG(INFO, TAG, "jni_obj_descriptor is null");
+        return CA_NOT_SUPPORTED;
     }
 
     OIC_LOG(DEBUG, TAG, "set value in descriptor");
@@ -2029,15 +2504,8 @@ CAResult_t CALEClientSetUUIDToDescriptor(JNIEnv *env, jobject bluetoothGatt,
         return CA_STATUS_FAILED;
     }
 
-    jclass jni_cid_gatt = (*env)->FindClass(env, "android/bluetooth/BluetoothGatt");
-    if (!jni_cid_gatt)
-    {
-        OIC_LOG(ERROR, TAG, "jni_cid_gatt is null");
-        return CA_STATUS_FAILED;
-    }
-
-    OIC_LOG(DEBUG, TAG, "write Descriptor in gatt object");
-    jmethodID jni_mid_writeDescriptor = (*env)->GetMethodID(env, jni_cid_gatt, "writeDescriptor",
+    jmethodID jni_mid_writeDescriptor  = CALEGetJNIMethodID(env, "android/bluetooth/BluetoothGatt",
+                                                            "writeDescriptor",
                                                             "(Landroid/bluetooth/"
                                                             "BluetoothGattDescriptor;)Z");
     if (!jni_mid_writeDescriptor)
@@ -2080,7 +2548,6 @@ void CALEClientCreateScanDeviceList(JNIEnv *env)
 
 CAResult_t CALEClientAddScanDeviceToList(JNIEnv *env, jobject device)
 {
-    OIC_LOG(DEBUG, TAG, "IN - CALEClientAddScanDeviceToList");
     VERIFY_NON_NULL(device, TAG, "device is null");
     VERIFY_NON_NULL(env, TAG, "env is null");
 
@@ -2089,6 +2556,13 @@ CAResult_t CALEClientAddScanDeviceToList(JNIEnv *env, jobject device)
     if (!g_deviceList)
     {
         OIC_LOG(ERROR, TAG, "gdevice_list is null");
+
+        CALEClientSetScanFlag(false);
+        if(CA_STATUS_OK != CALEClientStopScan())
+        {
+            OIC_LOG(ERROR, TAG, "CALEClientStopScan has failed");
+        }
+
         ca_mutex_unlock(g_deviceListMutex);
         return CA_STATUS_FAILED;
     }
@@ -2113,20 +2587,19 @@ CAResult_t CALEClientAddScanDeviceToList(JNIEnv *env, jobject device)
     {
         jobject gdevice = (*env)->NewGlobalRef(env, device);
         u_arraylist_add(g_deviceList, gdevice);
-        OIC_LOG(DEBUG, TAG, "Set Object to Array as Element");
+        ca_cond_signal(g_deviceDescCond);
+        OIC_LOG_V(DEBUG, TAG, "Added this BT Device[%s] in the List", remoteAddress);
     }
     (*env)->ReleaseStringUTFChars(env, jni_remoteAddress, remoteAddress);
 
     ca_mutex_unlock(g_deviceListMutex);
 
-    OIC_LOG(DEBUG, TAG, "OUT - CALEClientAddScanDeviceToList");
     return CA_STATUS_OK;
 }
 
 bool CALEClientIsDeviceInScanDeviceList(JNIEnv *env, const char* remoteAddress)
 {
-    OIC_LOG(DEBUG, TAG, "IN - CALEClientIsDeviceInScanDeviceList");
-    VERIFY_NON_NULL_RET(env, TAG, "env is null", NULL);
+    VERIFY_NON_NULL_RET(env, TAG, "env is null", true);
     VERIFY_NON_NULL_RET(remoteAddress, TAG, "remoteAddress is null", true);
 
     if (!g_deviceList)
@@ -2161,7 +2634,6 @@ bool CALEClientIsDeviceInScanDeviceList(JNIEnv *env, const char* remoteAddress)
 
         if (!strcmp(remoteAddress, setAddress))
         {
-            OIC_LOG(DEBUG, TAG, "the device is already set");
             (*env)->ReleaseStringUTFChars(env, jni_setAddress, setAddress);
             return true;
         }
@@ -2169,7 +2641,6 @@ bool CALEClientIsDeviceInScanDeviceList(JNIEnv *env, const char* remoteAddress)
         (*env)->ReleaseStringUTFChars(env, jni_setAddress, setAddress);
     }
 
-    OIC_LOG(DEBUG, TAG, "OUT - CALEClientIsDeviceInScanDeviceList");
     OIC_LOG(DEBUG, TAG, "there are no the device in list. we can add");
 
     return false;
@@ -2199,6 +2670,7 @@ CAResult_t CALEClientRemoveAllScanDevices(JNIEnv *env)
             continue;
         }
         (*env)->DeleteGlobalRef(env, jarrayObj);
+        jarrayObj = NULL;
     }
 
     OICFree(g_deviceList);
@@ -2263,10 +2735,16 @@ CAResult_t CALEClientRemoveDeviceInScanDeviceList(JNIEnv *env, jstring address)
         {
             OIC_LOG_V(DEBUG, TAG, "remove object : %s", remoteAddress);
             (*env)->DeleteGlobalRef(env, jarrayObj);
+            jarrayObj = NULL;
             (*env)->ReleaseStringUTFChars(env, jni_setAddress, setAddress);
             (*env)->ReleaseStringUTFChars(env, address, remoteAddress);
 
-            CALEClientReorderingList(index, g_deviceList);
+            if (NULL == u_arraylist_remove(g_deviceList, index))
+            {
+                OIC_LOG(ERROR, TAG, "List removal failed.");
+                ca_mutex_unlock(g_deviceListMutex);
+                return CA_STATUS_FAILED;
+            }
             ca_mutex_unlock(g_deviceListMutex);
             return CA_STATUS_OK;
         }
@@ -2286,12 +2764,19 @@ CAResult_t CALEClientRemoveDeviceInScanDeviceList(JNIEnv *env, jstring address)
 
 CAResult_t CALEClientAddGattobjToList(JNIEnv *env, jobject gatt)
 {
-    OIC_LOG(DEBUG, TAG, "CALEClientAddGattobjToList");
+    OIC_LOG(INFO, TAG, "CALEClientAddGattobjToList");
     VERIFY_NON_NULL(env, TAG, "env is null");
     VERIFY_NON_NULL(gatt, TAG, "gatt is null");
 
     ca_mutex_lock(g_gattObjectMutex);
 
+    if (!g_gattObjectList)
+    {
+        OIC_LOG(ERROR, TAG, "g_gattObjectList is not available");
+        ca_mutex_unlock(g_gattObjectMutex);
+        return CA_STATUS_FAILED;
+    }
+
     jstring jni_remoteAddress = CALEClientGetAddressFromGattObj(env, gatt);
     if (!jni_remoteAddress)
     {
@@ -2308,11 +2793,12 @@ CAResult_t CALEClientAddGattobjToList(JNIEnv *env, jobject gatt)
         return CA_STATUS_FAILED;
     }
 
+    OIC_LOG_V(INFO, TAG, "remote address : %s", remoteAddress);
     if (!CALEClientIsGattObjInList(env, remoteAddress))
     {
         jobject newGatt = (*env)->NewGlobalRef(env, gatt);
         u_arraylist_add(g_gattObjectList, newGatt);
-        OIC_LOG(DEBUG, TAG, "Set GATT Object to Array as Element");
+        OIC_LOG(INFO, TAG, "Set GATT Object to Array as Element");
     }
 
     (*env)->ReleaseStringUTFChars(env, jni_remoteAddress, remoteAddress);
@@ -2425,9 +2911,9 @@ CAResult_t CALEClientRemoveAllGattObjs(JNIEnv *env)
     ca_mutex_lock(g_gattObjectMutex);
     if (!g_gattObjectList)
     {
-        OIC_LOG(ERROR, TAG, "g_gattObjectList is null");
+        OIC_LOG(DEBUG, TAG, "already removed for g_gattObjectList");
         ca_mutex_unlock(g_gattObjectMutex);
-        return CA_STATUS_FAILED;
+        return CA_STATUS_OK;
     }
 
     uint32_t length = u_arraylist_length(g_gattObjectList);
@@ -2440,10 +2926,12 @@ CAResult_t CALEClientRemoveAllGattObjs(JNIEnv *env)
             continue;
         }
         (*env)->DeleteGlobalRef(env, jarrayObj);
+        jarrayObj = NULL;
     }
 
     OICFree(g_gattObjectList);
     g_gattObjectList = NULL;
+    OIC_LOG(INFO, TAG, "g_gattObjectList is removed");
     ca_mutex_unlock(g_gattObjectMutex);
     return CA_STATUS_OK;
 }
@@ -2457,9 +2945,9 @@ CAResult_t CALEClientRemoveGattObj(JNIEnv *env, jobject gatt)
     ca_mutex_lock(g_gattObjectMutex);
     if (!g_gattObjectList)
     {
-        OIC_LOG(ERROR, TAG, "g_gattObjectList is null");
+        OIC_LOG(DEBUG, TAG, "already removed for g_gattObjectList");
         ca_mutex_unlock(g_gattObjectMutex);
-        return CA_STATUS_FAILED;
+        return CA_STATUS_OK;
     }
 
     uint32_t length = u_arraylist_length(g_gattObjectList);
@@ -2511,10 +2999,18 @@ CAResult_t CALEClientRemoveGattObj(JNIEnv *env, jobject gatt)
         {
             OIC_LOG_V(DEBUG, TAG, "remove object : %s", remoteAddress);
             (*env)->DeleteGlobalRef(env, jarrayObj);
+            jarrayObj = NULL;
             (*env)->ReleaseStringUTFChars(env, jni_setAddress, setAddress);
             (*env)->ReleaseStringUTFChars(env, jni_remoteAddress, remoteAddress);
+
+            if (NULL == u_arraylist_remove(g_gattObjectList, index))
+            {
+                OIC_LOG(ERROR, TAG, "List removal failed.");
+                ca_mutex_unlock(g_gattObjectMutex);
+                return CA_STATUS_FAILED;
+            }
             ca_mutex_unlock(g_gattObjectMutex);
-            return CALEClientReorderingList(index, g_gattObjectList);
+            return CA_STATUS_OK;
         }
         (*env)->ReleaseStringUTFChars(env, jni_setAddress, setAddress);
         (*env)->ReleaseStringUTFChars(env, jni_remoteAddress, remoteAddress);
@@ -2534,9 +3030,9 @@ CAResult_t CALEClientRemoveGattObjForAddr(JNIEnv *env, jstring addr)
     ca_mutex_lock(g_gattObjectMutex);
     if (!g_gattObjectList)
     {
-        OIC_LOG(ERROR, TAG, "g_gattObjectList is null");
+        OIC_LOG(DEBUG, TAG, "already removed for g_gattObjectList");
         ca_mutex_unlock(g_gattObjectMutex);
-        return CA_STATUS_FAILED;
+        return CA_STATUS_OK;
     }
 
     uint32_t length = u_arraylist_length(g_gattObjectList);
@@ -2579,11 +3075,17 @@ CAResult_t CALEClientRemoveGattObjForAddr(JNIEnv *env, jstring addr)
         {
             OIC_LOG_V(DEBUG, TAG, "remove object : %s", remoteAddress);
             (*env)->DeleteGlobalRef(env, jarrayObj);
-
+            jarrayObj = NULL;
             (*env)->ReleaseStringUTFChars(env, jni_setAddress, setAddress);
             (*env)->ReleaseStringUTFChars(env, addr, remoteAddress);
+            if (NULL == u_arraylist_remove(g_gattObjectList, index))
+            {
+                OIC_LOG(ERROR, TAG, "List removal failed.");
+                ca_mutex_unlock(g_gattObjectMutex);
+                return CA_STATUS_FAILED;
+            }
             ca_mutex_unlock(g_gattObjectMutex);
-            return CALEClientReorderingList(index, g_gattObjectList);
+            return CA_STATUS_OK;
         }
         (*env)->ReleaseStringUTFChars(env, jni_setAddress, setAddress);
         (*env)->ReleaseStringUTFChars(env, addr, remoteAddress);
@@ -2594,6 +3096,101 @@ CAResult_t CALEClientRemoveGattObjForAddr(JNIEnv *env, jstring addr)
     return CA_STATUS_FAILED;
 }
 
+jstring CALEClientGetLEAddressFromBTDevice(JNIEnv *env, jobject bluetoothDevice)
+{
+    OIC_LOG(DEBUG, TAG, "IN - CALEClientGetLEAddressFromBTDevice");
+
+    VERIFY_NON_NULL_RET(env, TAG, "env", NULL);
+    VERIFY_NON_NULL_RET(bluetoothDevice, TAG, "bluetoothDevice", NULL);
+
+    // get Bluetooth Address
+    jstring jni_btTargetAddress = CALEGetAddressFromBTDevice(env, bluetoothDevice);
+    if (!jni_btTargetAddress)
+    {
+        OIC_LOG(ERROR, TAG, "CALEGetAddressFromBTDevice has failed");
+        return NULL;
+    }
+
+    const char* targetAddress = (*env)->GetStringUTFChars(env, jni_btTargetAddress, NULL);
+    if (!targetAddress)
+    {
+        OIC_LOG(ERROR, TAG, "targetAddress is not available");
+        return NULL;
+    }
+
+    // get method ID of getDevice()
+    jmethodID jni_mid_getDevice = CALEGetJNIMethodID(env, CLASSPATH_BT_GATT,
+                                                     "getDevice", METHODID_BT_DEVICE);
+    if (!jni_mid_getDevice)
+    {
+        OIC_LOG(ERROR, TAG, "jni_mid_getDevice is null");
+        (*env)->ReleaseStringUTFChars(env, jni_btTargetAddress, targetAddress);
+        return NULL;
+    }
+
+    size_t length = u_arraylist_length(g_gattObjectList);
+    for (size_t index = 0; index < length; index++)
+    {
+        jobject jarrayObj = (jobject) u_arraylist_get(g_gattObjectList, index);
+        if (!jarrayObj)
+        {
+            OIC_LOG(ERROR, TAG, "jarrayObj is null");
+            (*env)->ReleaseStringUTFChars(env, jni_btTargetAddress, targetAddress);
+            return NULL;
+        }
+
+        OIC_LOG(DEBUG, TAG, "CALL API - bluetoothGatt.getDevice()");
+        jobject jni_obj_device = (*env)->CallObjectMethod(env, jarrayObj, jni_mid_getDevice);
+        if (!jni_obj_device)
+        {
+            OIC_LOG(ERROR, TAG, "jni_obj_device is null");
+            (*env)->ReleaseStringUTFChars(env, jni_btTargetAddress, targetAddress);
+            return NULL;
+        }
+
+        jstring jni_btAddress = CALEGetAddressFromBTDevice(env, jni_obj_device);
+        if (!jni_btAddress)
+        {
+            OIC_LOG(ERROR, TAG, "CALEGetAddressFromBTDevice has failed");
+            (*env)->ReleaseStringUTFChars(env, jni_btTargetAddress, targetAddress);
+            return NULL;
+        }
+
+        const char* btAddress = (*env)->GetStringUTFChars(env, jni_btAddress, NULL);
+        if (!btAddress)
+        {
+            OIC_LOG(ERROR, TAG, "btAddress is not available");
+            (*env)->ReleaseStringUTFChars(env, jni_btTargetAddress, targetAddress);
+            return NULL;
+        }
+
+        OIC_LOG_V(DEBUG, TAG, "targetAddress : %s", targetAddress);
+        OIC_LOG_V(DEBUG, TAG, "btAddress : %s", btAddress);
+        if (!strcmp(targetAddress, btAddress))
+        {
+            OIC_LOG(DEBUG, TAG, "Found Gatt object from BT device");
+
+            // get LE address
+            jstring jni_LEAddress = CALEClientGetAddressFromGattObj(env, jarrayObj);
+            if (!jni_LEAddress)
+            {
+                OIC_LOG(ERROR, TAG, "jni_LEAddress is null");
+            }
+            (*env)->ReleaseStringUTFChars(env, jni_btTargetAddress, targetAddress);
+            (*env)->ReleaseStringUTFChars(env, jni_btAddress, btAddress);
+            (*env)->DeleteLocalRef(env, jni_btAddress);
+            (*env)->DeleteLocalRef(env, jni_obj_device);
+            return jni_LEAddress;
+        }
+        (*env)->ReleaseStringUTFChars(env, jni_btAddress, btAddress);
+        (*env)->DeleteLocalRef(env, jni_btAddress);
+        (*env)->DeleteLocalRef(env, jni_obj_device);
+    }
+
+    OIC_LOG(DEBUG, TAG, "OUT - CALEClientGetLEAddressFromBTDevice");
+    return NULL;
+}
+
 /**
  * BT State List
  */
@@ -2603,7 +3200,7 @@ CAResult_t CALEClientUpdateDeviceState(const char* address, uint32_t connectedSt
 {
     VERIFY_NON_NULL(address, TAG, "address is null");
 
-    CALEState_t *newstate = (CALEState_t*) OICMalloc(sizeof(CALEState_t));
+    CALEState_t *newstate = (CALEState_t*) OICCalloc(1, sizeof(*newstate));
     if (!newstate)
     {
         OIC_LOG(ERROR, TAG, "out of memory");
@@ -2617,7 +3214,7 @@ CAResult_t CALEClientUpdateDeviceState(const char* address, uint32_t connectedSt
         return CA_STATUS_FAILED;
     }
 
-    strcpy(newstate->address, address);
+    OICStrcpy(newstate->address, sizeof(newstate->address), address);
     newstate->connectedState = connectedState;
     newstate->notificationState = notificationState;
     newstate->sendState = sendState;
@@ -2651,6 +3248,7 @@ CAResult_t CALEClientAddDeviceStateToList(CALEState_t* state)
         {
             state->notificationState = curState->notificationState;
         }
+        state->autoConnectFlag = curState->autoConnectFlag;
 
         // delete previous state for update new state
         CAResult_t res = CALEClientRemoveDeviceState(state->address);
@@ -2662,8 +3260,9 @@ CAResult_t CALEClientAddDeviceStateToList(CALEState_t* state)
         }
     }
     u_arraylist_add(g_deviceStateList, state); // update new state
-    OIC_LOG_V(DEBUG, TAG, "Set State Info to List : %d, %d",
-              state->connectedState, state->notificationState);
+    OIC_LOG_V(INFO, TAG, "Set State Info to List : %d, %d, %s, %d",
+              state->connectedState, state->notificationState,
+              state->address, state->autoConnectFlag);
 
     ca_mutex_unlock(g_deviceStateListMutex);
     return CA_STATUS_OK;
@@ -2706,7 +3305,7 @@ bool CALEClientIsDeviceInList(const char* remoteAddress)
 
 CAResult_t CALEClientRemoveAllDeviceState()
 {
-    OIC_LOG(DEBUG, TAG, "CALENativeRemoveAllDevices");
+    OIC_LOG(DEBUG, TAG, "CALEClientRemoveAllDeviceState");
 
     ca_mutex_lock(g_deviceStateListMutex);
     if (!g_deviceStateList)
@@ -2735,6 +3334,39 @@ CAResult_t CALEClientRemoveAllDeviceState()
     return CA_STATUS_OK;
 }
 
+CAResult_t CALEClientResetDeviceStateForAll()
+{
+    OIC_LOG(DEBUG, TAG, "CALEClientResetDeviceStateForAll");
+
+    ca_mutex_lock(g_deviceStateListMutex);
+    if (!g_deviceStateList)
+    {
+        OIC_LOG(ERROR, TAG, "g_deviceStateList is null");
+        ca_mutex_unlock(g_deviceStateListMutex);
+        return CA_STATUS_FAILED;
+    }
+
+    size_t length = u_arraylist_length(g_deviceStateList);
+    for (size_t index = 0; index < length; index++)
+    {
+        CALEState_t* state = (CALEState_t*) u_arraylist_get(g_deviceStateList, index);
+        if (!state)
+        {
+            OIC_LOG(ERROR, TAG, "jarrayObj is null");
+            continue;
+        }
+
+        // autoConnectFlag value will be not changed,
+        // since it has reset only termination case.
+        state->connectedState = STATE_DISCONNECTED;
+        state->notificationState = STATE_CHARACTER_UNSET;
+        state->sendState = STATE_SEND_NONE;
+    }
+    ca_mutex_unlock(g_deviceStateListMutex);
+
+    return CA_STATUS_OK;
+}
+
 CAResult_t CALEClientRemoveDeviceState(const char* remoteAddress)
 {
     OIC_LOG(DEBUG, TAG, "CALEClientRemoveDeviceState");
@@ -2758,20 +3390,22 @@ CAResult_t CALEClientRemoveDeviceState(const char* remoteAddress)
 
         if (!strcmp(state->address, remoteAddress))
         {
-            OIC_LOG_V(DEBUG, TAG, "remove state : %s", remoteAddress);
-            OICFree(state);
+            OIC_LOG_V(DEBUG, TAG, "remove state : %s", state->address);
 
-            CAResult_t res = CALEClientReorderingList(index, g_deviceStateList);
-            if(CA_STATUS_OK != res)
+            CALEState_t* targetState  = (CALEState_t*)u_arraylist_remove(g_deviceStateList,
+                                                                         index);
+            if (NULL == targetState)
             {
-                OIC_LOG(ERROR, TAG, "CALEClientReorderingList has failed");
-                return res;
+                OIC_LOG(ERROR, TAG, "List removal failed.");
+                return CA_STATUS_FAILED;
             }
+
+            OICFree(targetState);
             return CA_STATUS_OK;
         }
     }
 
-    return CA_STATUS_FAILED;
+    return CA_STATUS_OK;
 }
 
 CALEState_t* CALEClientGetStateInfo(const char* remoteAddress)
@@ -2786,6 +3420,8 @@ CALEState_t* CALEClientGetStateInfo(const char* remoteAddress)
     }
 
     uint32_t length = u_arraylist_length(g_deviceStateList);
+    OIC_LOG_V(DEBUG, TAG, "CALEClientGetStateInfo : %d", length);
+
     for (uint32_t index = 0; index < length; index++)
     {
         CALEState_t* state = (CALEState_t*) u_arraylist_get(g_deviceStateList, index);
@@ -2795,6 +3431,9 @@ CALEState_t* CALEClientGetStateInfo(const char* remoteAddress)
             continue;
         }
 
+        OIC_LOG_V(DEBUG, TAG, "target address : %s", remoteAddress);
+        OIC_LOG_V(DEBUG, TAG, "state address : %s", state->address);
+
         if (!strcmp(state->address, remoteAddress))
         {
             OIC_LOG_V(DEBUG, TAG, "get state : %s", remoteAddress);
@@ -2918,37 +3557,13 @@ void CALEClientCreateDeviceList()
     }
 }
 
-CAResult_t CALEClientReorderingList(uint32_t index, u_arraylist_t *list)
-{
-    if (!list)
-    {
-        OIC_LOG(ERROR, TAG, "list is null");
-        return CA_STATUS_FAILED;
-    }
-
-    if (index >= list->length)
-    {
-        OIC_LOG(ERROR, TAG, "index is not available");
-        return CA_STATUS_FAILED;
-    }
-
-    if (index < list->length - 1)
-    {
-        memmove(&list->data[index], &list->data[index + 1],
-                (list->length - index - 1) * sizeof(void *));
-    }
-
-    list->size--;
-    list->length--;
-
-    return CA_STATUS_OK;
-}
-
 /**
  * Check Sent Count for remove g_sendBuffer
  */
 void CALEClientUpdateSendCnt(JNIEnv *env)
 {
+    OIC_LOG(DEBUG, TAG, "CALEClientUpdateSendCnt");
+
     VERIFY_NON_NULL_VOID(env, TAG, "env is null");
     // mutex lock
     ca_mutex_lock(g_threadMutex);
@@ -2967,6 +3582,7 @@ void CALEClientUpdateSendCnt(JNIEnv *env)
         }
         // notity the thread
         ca_cond_signal(g_threadCond);
+
         CALEClientSetSendFinishFlag(true);
         OIC_LOG(DEBUG, TAG, "set signal for send data");
     }
@@ -2976,8 +3592,6 @@ void CALEClientUpdateSendCnt(JNIEnv *env)
 
 CAResult_t CALEClientInitGattMutexVaraibles()
 {
-    OIC_LOG(DEBUG, TAG, "IN");
-
     if (NULL == g_bleReqRespClientCbMutex)
     {
         g_bleReqRespClientCbMutex = ca_mutex_new();
@@ -3018,16 +3632,6 @@ CAResult_t CALEClientInitGattMutexVaraibles()
         }
     }
 
-    if (NULL == g_threadSendCBMutex)
-    {
-        g_threadSendCBMutex = ca_mutex_new();
-        if (NULL == g_threadSendCBMutex)
-        {
-            OIC_LOG(ERROR, TAG, "ca_mutex_new has failed");
-            return CA_STATUS_FAILED;
-        }
-    }
-
     if (NULL == g_deviceListMutex)
     {
         g_deviceListMutex = ca_mutex_new();
@@ -3068,34 +3672,41 @@ CAResult_t CALEClientInitGattMutexVaraibles()
         }
     }
 
-    if (NULL == g_writeCharacteristicCBMutex)
+    if (NULL == g_scanMutex)
+    {
+        g_scanMutex = ca_mutex_new();
+        if (NULL == g_scanMutex)
+        {
+            OIC_LOG(ERROR, TAG, "ca_mutex_new has failed");
+            return CA_STATUS_FAILED;
+        }
+    }
+
+    if (NULL == g_threadWriteCharacteristicMutex)
     {
-        g_writeCharacteristicCBMutex = ca_mutex_new();
-        if (NULL == g_writeCharacteristicCBMutex)
+        g_threadWriteCharacteristicMutex = ca_mutex_new();
+        if (NULL == g_threadWriteCharacteristicMutex)
         {
             OIC_LOG(ERROR, TAG, "ca_mutex_new has failed");
             return CA_STATUS_FAILED;
         }
     }
 
-    if (NULL == g_theSendRequestMutex)
+    if (NULL == g_deviceScanRetryDelayMutex)
     {
-        g_theSendRequestMutex = ca_mutex_new();
-        if (NULL == g_theSendRequestMutex)
+        g_deviceScanRetryDelayMutex = ca_mutex_new();
+        if (NULL == g_deviceScanRetryDelayMutex)
         {
             OIC_LOG(ERROR, TAG, "ca_mutex_new has failed");
             return CA_STATUS_FAILED;
         }
     }
 
-    OIC_LOG(DEBUG, TAG, "OUT");
     return CA_STATUS_OK;
 }
 
 void CALEClientTerminateGattMutexVariables()
 {
-    OIC_LOG(DEBUG, TAG, "IN");
-
     ca_mutex_free(g_bleReqRespClientCbMutex);
     g_bleReqRespClientCbMutex = NULL;
 
@@ -3108,22 +3719,20 @@ void CALEClientTerminateGattMutexVariables()
     ca_mutex_free(g_threadSendMutex);
     g_threadSendMutex = NULL;
 
-    ca_mutex_free(g_threadSendCBMutex);
-    g_threadSendCBMutex = NULL;
-
     ca_mutex_free(g_deviceListMutex);
     g_deviceListMutex = NULL;
 
     ca_mutex_free(g_SendFinishMutex);
     g_SendFinishMutex = NULL;
 
-    ca_mutex_free(g_writeCharacteristicCBMutex);
-    g_writeCharacteristicCBMutex = NULL;
+    ca_mutex_free(g_scanMutex);
+    g_scanMutex = NULL;
 
-    ca_mutex_free(g_theSendRequestMutex);
-    g_theSendRequestMutex = NULL;
+    ca_mutex_free(g_threadWriteCharacteristicMutex);
+    g_threadWriteCharacteristicMutex = NULL;
 
-    OIC_LOG(DEBUG, TAG, "OUT");
+    ca_mutex_free(g_deviceScanRetryDelayMutex);
+    g_deviceScanRetryDelayMutex = NULL;
 }
 
 void CALEClientSetSendFinishFlag(bool flag)
@@ -3135,44 +3744,40 @@ void CALEClientSetSendFinishFlag(bool flag)
     ca_mutex_unlock(g_SendFinishMutex);
 }
 
-void CALEClientSetWriteCharacteristicCBFlag(bool flag)
-{
-    OIC_LOG_V(DEBUG, TAG, "g_isReceivedWriteCB is %d", flag);
-
-    ca_mutex_lock(g_writeCharacteristicCBMutex);
-    g_isReceivedWriteCB = flag;
-    ca_mutex_unlock(g_writeCharacteristicCBMutex);
-}
-
-void CALEClientSetTheSendRequestFlag(bool flag)
-{
-    OIC_LOG_V(DEBUG, TAG, "g_isRequestedSend is %d", flag);
-
-    ca_mutex_lock(g_theSendRequestMutex);
-    g_isRequestedSend = flag;
-    ca_mutex_unlock(g_theSendRequestMutex);
-}
-
 /**
  * adapter common
  */
 
-CAResult_t CAStartBLEGattClient()
+CAResult_t CAStartLEGattClient()
 {
-    CAResult_t res = CALEClientStartMulticastServer();
-    if (CA_STATUS_OK != res)
+    // init mutex for send logic
+    if (!g_deviceDescCond)
     {
-        OIC_LOG(ERROR, TAG, "CALEClientStartMulticastServer has failed");
+        g_deviceDescCond = ca_cond_new();
     }
-    else
+
+    if (!g_threadCond)
+    {
+        g_threadCond = ca_cond_new();
+    }
+
+    if (!g_threadWriteCharacteristicCond)
+    {
+        g_threadWriteCharacteristicCond = ca_cond_new();
+    }
+
+    CAResult_t ret = CALEClientStartScan();
+    if (CA_STATUS_OK != ret)
     {
-        g_isStartedLEClient = true;
+        OIC_LOG(ERROR, TAG, "CALEClientStartScan has failed");
+        return ret;
     }
 
-    return res;
+    g_isStartedLEClient = true;
+    return CA_STATUS_OK;
 }
 
-void CAStopBLEGattClient()
+void CAStopLEGattClient()
 {
     OIC_LOG(DEBUG, TAG, "CAStopBLEGattClient");
 
@@ -3210,9 +3815,31 @@ void CAStopBLEGattClient()
         OIC_LOG(ERROR, TAG, "CALEClientStopScan has failed");
     }
 
+    ca_mutex_lock(g_threadMutex);
+    OIC_LOG(DEBUG, TAG, "signal - connection cond");
     ca_cond_signal(g_threadCond);
-    ca_cond_signal(g_threadSendCond);
-    g_isStartedLEClient = false;
+    CALEClientSetSendFinishFlag(true);
+    ca_mutex_unlock(g_threadMutex);
+
+    ca_mutex_lock(g_threadWriteCharacteristicMutex);
+    OIC_LOG(DEBUG, TAG, "signal - WriteCharacteristic cond");
+    ca_cond_signal(g_threadWriteCharacteristicCond);
+    ca_mutex_unlock(g_threadWriteCharacteristicMutex);
+
+    ca_mutex_lock(g_deviceScanRetryDelayMutex);
+    OIC_LOG(DEBUG, TAG, "signal - delay cond");
+    ca_cond_signal(g_deviceScanRetryDelayCond);
+    ca_mutex_unlock(g_deviceScanRetryDelayMutex);
+
+    ca_cond_free(g_deviceDescCond);
+    ca_cond_free(g_threadCond);
+    ca_cond_free(g_threadWriteCharacteristicCond);
+    ca_cond_free(g_deviceScanRetryDelayCond);
+
+    g_deviceDescCond = NULL;
+    g_threadCond = NULL;
+    g_threadWriteCharacteristicCond = NULL;
+    g_deviceScanRetryDelayCond = NULL;
 
     if (isAttached)
     {
@@ -3221,24 +3848,38 @@ void CAStopBLEGattClient()
 
 }
 
-void CATerminateBLEGattClient()
+CAResult_t CAInitializeLEGattClient()
+{
+    OIC_LOG(DEBUG, TAG, "Initialize GATT Client");
+    CALEClientInitialize();
+    return CA_STATUS_OK;
+}
+
+void CATerminateLEGattClient()
 {
     OIC_LOG(DEBUG, TAG, "Terminate GATT Client");
+    CAStopLEGattClient();
     CALEClientTerminate();
 }
 
-CAResult_t  CAUpdateCharacteristicsToGattServer(const char *remoteAddress, const char  *data,
-                                                const uint32_t dataLen, CALETransferType_t type,
-                                                const int32_t position)
+CAResult_t  CAUpdateCharacteristicsToGattServer(const char *remoteAddress, const uint8_t  *data,
+                                                uint32_t dataLen, CALETransferType_t type,
+                                                int32_t position)
 {
     OIC_LOG(DEBUG, TAG, "call CALEClientSendUnicastMessage");
     VERIFY_NON_NULL(data, TAG, "data is null");
     VERIFY_NON_NULL(remoteAddress, TAG, "remoteAddress is null");
 
+    if (LE_UNICAST != type || position < 0)
+    {
+        OIC_LOG(ERROR, TAG, "this request is not unicast");
+        return CA_STATUS_INVALID_PARAM;
+    }
+
     return CALEClientSendUnicastMessage(remoteAddress, data, dataLen);
 }
 
-CAResult_t CAUpdateCharacteristicsToAllGattServers(const char *data, uint32_t dataLen)
+CAResult_t CAUpdateCharacteristicsToAllGattServers(const uint8_t *data, uint32_t dataLen)
 {
     OIC_LOG(DEBUG, TAG, "call CALEClientSendMulticastMessage");
     VERIFY_NON_NULL(data, TAG, "data is null");
@@ -3246,69 +3887,55 @@ CAResult_t CAUpdateCharacteristicsToAllGattServers(const char *data, uint32_t da
     return CALEClientSendMulticastMessage(data, dataLen);
 }
 
-void CASetBLEReqRespClientCallback(CABLEClientDataReceivedCallback callback)
+void CASetLEReqRespClientCallback(CABLEDataReceivedCallback callback)
 {
-    OIC_LOG(DEBUG, TAG, "IN");
-
     ca_mutex_lock(g_bleReqRespClientCbMutex);
     g_CABLEClientDataReceivedCallback = callback;
     ca_mutex_unlock(g_bleReqRespClientCbMutex);
-
-    OIC_LOG(DEBUG, TAG, "OUT");
 }
 
-void CASetBleClientThreadPoolHandle(ca_thread_pool_t handle)
+void CASetLEClientThreadPoolHandle(ca_thread_pool_t handle)
 {
-    OIC_LOG(DEBUG, TAG, "IN");
-
-    CALEClientInitialize(handle);
-
-    OIC_LOG(DEBUG, TAG, "OUT");
+    g_threadPoolHandle = handle;
 }
 
 CAResult_t CAGetLEAddress(char **local_address)
 {
-    OIC_LOG(DEBUG, TAG, "IN");
-
-    VERIFY_NON_NULL(local_address, TAG, "local_address is null");
-    CAResult_t res = CALEClientGetInterfaceInfo(local_address);
-    if (CA_STATUS_OK != res)
-    {
-        OIC_LOG(INFO, TAG, "it didn't get local address");
-    }
-
-    OIC_LOG(DEBUG, TAG, "OUT");
-    return CA_STATUS_OK;
+    VERIFY_NON_NULL(local_address, TAG, "local_address");
+    OIC_LOG(INFO, TAG, "CAGetLEAddress is not support");
+    return CA_NOT_SUPPORTED;
 }
 
 JNIEXPORT void JNICALL
-Java_org_iotivity_jar_caleclientinterface_CARegisterLeScanCallback(JNIEnv *env, jobject obj,
-                                                                   jobject callback)
+Java_org_iotivity_ca_CaLeClientInterface_caLeRegisterLeScanCallback(JNIEnv *env, jobject obj,
+                                                                    jobject callback)
 {
-    OIC_LOG(DEBUG, TAG, "CARegisterLeScanCallback");
+    OIC_LOG(DEBUG, TAG, "CaLeRegisterLeScanCallback");
     VERIFY_NON_NULL_VOID(env, TAG, "env is null");
+    VERIFY_NON_NULL_VOID(obj, TAG, "obj is null");
     VERIFY_NON_NULL_VOID(callback, TAG, "callback is null");
 
     g_leScanCallback = (*env)->NewGlobalRef(env, callback);
 }
 
 JNIEXPORT void JNICALL
-Java_org_iotivity_jar_caleclientinterface_CARegisterLeGattCallback(JNIEnv *env, jobject obj,
-                                                                   jobject callback)
+Java_org_iotivity_ca_CaLeClientInterface_caLeRegisterGattCallback(JNIEnv *env, jobject obj,
+                                                                  jobject callback)
 {
-    OIC_LOG(DEBUG, TAG, "CARegisterLeGattCallback");
+    OIC_LOG(DEBUG, TAG, "CaLeRegisterGattCallback");
     VERIFY_NON_NULL_VOID(env, TAG, "env is null");
+    VERIFY_NON_NULL_VOID(obj, TAG, "obj is null");
     VERIFY_NON_NULL_VOID(callback, TAG, "callback is null");
 
     g_leGattCallback = (*env)->NewGlobalRef(env, callback);
 }
 
 JNIEXPORT void JNICALL
-Java_org_iotivity_jar_caleclientinterface_CALeScanCallback(JNIEnv *env, jobject obj,
-                                                           jobject device, jint rssi,
-                                                           jbyteArray scanRecord)
+Java_org_iotivity_ca_CaLeClientInterface_caLeScanCallback(JNIEnv *env, jobject obj,
+                                                          jobject device)
 {
     VERIFY_NON_NULL_VOID(env, TAG, "env is null");
+    VERIFY_NON_NULL_VOID(obj, TAG, "obj is null");
     VERIFY_NON_NULL_VOID(device, TAG, "device is null");
 
     CAResult_t res = CALEClientAddScanDeviceToList(env, device);
@@ -3318,13 +3945,46 @@ Java_org_iotivity_jar_caleclientinterface_CALeScanCallback(JNIEnv *env, jobject
     }
 }
 
+static jstring CALEClientGetAddressFromGatt(JNIEnv *env, jobject gatt)
+{
+    OIC_LOG(DEBUG, TAG, "IN - CAManagerGetAddressFromGatt");
+
+    VERIFY_NON_NULL_RET(env, TAG, "env is null", NULL);
+    VERIFY_NON_NULL_RET(gatt, TAG, "gatt is null", NULL);
+
+    jmethodID jni_mid_getDevice = CALEGetJNIMethodID(env, CLASSPATH_BT_GATT,
+                                                     "getDevice", METHODID_BT_DEVICE);
+    if (!jni_mid_getDevice)
+    {
+        OIC_LOG(ERROR, TAG, "jni_mid_getDevice is null");
+        return NULL;
+    }
+
+    jobject jni_obj_device = (*env)->CallObjectMethod(env, gatt, jni_mid_getDevice);
+    if (!jni_obj_device)
+    {
+        OIC_LOG(ERROR, TAG, "jni_obj_device is null");
+        return NULL;
+    }
+
+    jstring jni_address = CALEGetAddressFromBTDevice(env, jni_obj_device);
+    if (!jni_address)
+    {
+        OIC_LOG(ERROR, TAG, "jni_address is null");
+        return NULL;
+    }
+
+    OIC_LOG(DEBUG, TAG, "OUT - CAManagerGetAddressFromGatt");
+    return jni_address;
+}
+
 /*
- * Class:     org_iotivity_jar_caleinterface
+ * Class:     org_iotivity_ca_jar_caleinterface
  * Method:    CALeGattConnectionStateChangeCallback
  * Signature: (Landroid/bluetooth/BluetoothGatt;II)V
  */
 JNIEXPORT void JNICALL
-Java_org_iotivity_jar_caleclientinterface_CALeGattConnectionStateChangeCallback(JNIEnv *env,
+Java_org_iotivity_ca_CaLeClientInterface_caLeGattConnectionStateChangeCallback(JNIEnv *env,
                                                                                 jobject obj,
                                                                                 jobject gatt,
                                                                                 jint status,
@@ -3333,9 +3993,14 @@ Java_org_iotivity_jar_caleclientinterface_CALeGattConnectionStateChangeCallback(
     OIC_LOG_V(DEBUG, TAG, "CALeGattConnectionStateChangeCallback - status %d, newstate %d", status,
             newstate);
     VERIFY_NON_NULL_VOID(env, TAG, "env is null");
+    VERIFY_NON_NULL_VOID(obj, TAG, "obj is null");
     VERIFY_NON_NULL_VOID(gatt, TAG, "gatt is null");
 
-    if (GATT_SUCCESS == status && STATE_CONNECTED == newstate) // le connected
+    jint state_connected = CALEGetConstantsValue(env, CLASSPATH_BT_PROFILE, "STATE_CONNECTED");
+    jint state_disconnected = CALEGetConstantsValue(env, CLASSPATH_BT_PROFILE, "STATE_DISCONNECTED");
+    jint gatt_success = CALEGetConstantsValue(env, CLASSPATH_BT_GATT, "GATT_SUCCESS");
+
+    if (gatt_success == status && state_connected == newstate) // le connected
     {
         jstring jni_address = CALEClientGetAddressFromGattObj(env, gatt);
         if (!jni_address)
@@ -3355,6 +4020,8 @@ Java_org_iotivity_jar_caleclientinterface_CALeGattConnectionStateChangeCallback(
                 (*env)->ReleaseStringUTFChars(env, jni_address, address);
                 goto error_exit;
             }
+            OIC_LOG_V(INFO, TAG, "ConnectionStateCB - remote address : %s", address);
+
             (*env)->ReleaseStringUTFChars(env, jni_address, address);
         }
 
@@ -3372,66 +4039,90 @@ Java_org_iotivity_jar_caleclientinterface_CALeGattConnectionStateChangeCallback(
             goto error_exit;
         }
     }
-    else if (GATT_SUCCESS == status && STATE_DISCONNECTED == newstate) // le disconnected
+    else if (state_disconnected == newstate) // le disconnected
     {
-        CAResult_t res = CALEClientStartScan();
-        if (CA_STATUS_OK != res)
-        {
-            OIC_LOG(ERROR, TAG, "CALEClientStartScan has failed");
-        }
-
         jstring jni_address = CALEClientGetAddressFromGattObj(env, gatt);
         if (!jni_address)
         {
             OIC_LOG(ERROR, TAG, "CALEClientGetAddressFromGattObj has failed");
+            goto error_exit;
         }
 
         const char* address = (*env)->GetStringUTFChars(env, jni_address, NULL);
         if (address)
         {
-            res = CALEClientUpdateDeviceState(address, STATE_DISCONNECTED,
-                                              STATE_CHARACTER_NO_CHANGE,
-                                              STATE_SEND_NONE);
+            CAResult_t res = CALEClientUpdateDeviceState(address, STATE_DISCONNECTED,
+                                                                  STATE_CHARACTER_UNSET,
+                                                                  STATE_SEND_NONE);
             if (CA_STATUS_OK != res)
             {
                 OIC_LOG(ERROR, TAG, "CALEClientUpdateDeviceState has failed");
+                (*env)->ReleaseStringUTFChars(env, jni_address, address);
+                goto error_exit;
             }
+            OIC_LOG_V(INFO, TAG, "ConnectionStateCB - remote address : %s", address);
+
             (*env)->ReleaseStringUTFChars(env, jni_address, address);
         }
 
-        res = CALEClientGattClose(env, gatt);
+        CAResult_t res = CALEClientGattClose(env, gatt);
         if (CA_STATUS_OK != res)
         {
             OIC_LOG(ERROR, TAG, "CALEClientGattClose has failed");
         }
 
-        ca_cond_signal(g_threadSendCond);
-    }
-    else // error
-    {
-        // update state
-        jstring jni_address = CALEClientGetAddressFromGattObj(env, gatt);
-        if (!jni_address)
+        if (GATT_ERROR == status)
         {
-            OIC_LOG(ERROR, TAG, "jni_address is null");
-            goto error_exit;
+            // when we get GATT ERROR(0x85), gatt connection can be called again.
+            OIC_LOG(INFO, TAG, "retry gatt connect");
 
-        }
+            jstring leAddress = CALEClientGetAddressFromGatt(env, gatt);
+            if (!leAddress)
+            {
+                OIC_LOG(ERROR, TAG, "CALEClientGetAddressFromGatt has failed");
+                goto error_exit;
+            }
 
-        const char* address = (*env)->GetStringUTFChars(env, jni_address, NULL);
-        if (address)
+            jobject btObject = CALEGetRemoteDevice(env, leAddress);
+            if (!btObject)
+            {
+                OIC_LOG(ERROR, TAG, "CALEGetRemoteDevice has failed");
+                goto error_exit;
+            }
+
+            jobject newGatt = CALEClientConnect(env, btObject, JNI_TRUE);
+            if (!newGatt)
+            {
+                OIC_LOG(ERROR, TAG, "CALEClientConnect has failed");
+                goto error_exit;
+            }
+
+            return;
+        }
+        else
         {
-            CAResult_t res = CALEClientUpdateDeviceState(address, STATE_DISCONNECTED,
-                                                         STATE_CHARACTER_NO_CHANGE,
-                                                         STATE_SEND_FAILED);
-            if (CA_STATUS_OK != res)
+            if (CALECheckConnectionStateValue(status))
             {
-                OIC_LOG(ERROR, TAG, "CALEClientUpdateDeviceState has failed");
+                // this state is unexpected reason to disconnect
+                // if the reason is suitable, connection logic of the device will be destroyed.
+                OIC_LOG(INFO, TAG, "connection logic destroy");
+                goto error_exit;
+            }
+            else
+            {
+                // other reason except for gatt_success is expected to running
+                // background connection in BT platform.
+                OIC_LOG(INFO, TAG, "unknown state or manual disconnected state");
+                CALEClientUpdateSendCnt(env);
+                return;
             }
         }
-        (*env)->ReleaseStringUTFChars(env, jni_address, address);
 
-        goto error_exit;
+        if (g_sendBuffer)
+        {
+            (*env)->DeleteGlobalRef(env, g_sendBuffer);
+            g_sendBuffer = NULL;
+        }
     }
     return;
 
@@ -3439,29 +4130,28 @@ Java_org_iotivity_jar_caleclientinterface_CALeGattConnectionStateChangeCallback(
 error_exit:
 
     CALEClientSendFinish(env, gatt);
-    ca_cond_signal(g_threadSendCond);
     return;
 }
 
 /*
- * Class:     org_iotivity_jar_caleinterface
+ * Class:     org_iotivity_ca_jar_caleinterface
  * Method:    CALeGattServicesDiscoveredCallback
  * Signature: (Landroid/bluetooth/BluetoothGatt;I)V
  */
 JNIEXPORT void JNICALL
-Java_org_iotivity_jar_caleclientinterface_CALeGattServicesDiscoveredCallback(JNIEnv *env,
+Java_org_iotivity_ca_CaLeClientInterface_caLeGattServicesDiscoveredCallback(JNIEnv *env,
                                                                              jobject obj,
                                                                              jobject gatt,
                                                                              jint status)
 {
     OIC_LOG_V(DEBUG, TAG, "CALeGattServicesDiscoveredCallback - status %d: ", status);
     VERIFY_NON_NULL_VOID(env, TAG, "env is null");
+    VERIFY_NON_NULL_VOID(obj, TAG, "obj is null");
     VERIFY_NON_NULL_VOID(gatt, TAG, "gatt is null");
 
     if (0 != status) // discovery error
     {
         CALEClientSendFinish(env, gatt);
-        ca_cond_signal(g_threadSendCond);
         return;
     }
 
@@ -3469,7 +4159,6 @@ Java_org_iotivity_jar_caleclientinterface_CALeGattServicesDiscoveredCallback(JNI
     if (!jni_address)
     {
         CALEClientSendFinish(env, gatt);
-        ca_cond_signal(g_threadSendCond);
         return;
     }
 
@@ -3477,7 +4166,6 @@ Java_org_iotivity_jar_caleclientinterface_CALeGattServicesDiscoveredCallback(JNI
     if (!address)
     {
         CALEClientSendFinish(env, gatt);
-        ca_cond_signal(g_threadSendCond);
         return;
     }
 
@@ -3508,8 +4196,16 @@ Java_org_iotivity_jar_caleclientinterface_CALeGattServicesDiscoveredCallback(JNI
         res = CALEClientSetUUIDToDescriptor(env, gatt, jni_obj_GattCharacteristic);
         if (CA_STATUS_OK != res)
         {
-            OIC_LOG(ERROR, TAG, "CALEClientSetUUIDToDescriptor has failed");
-            goto error_exit;
+            OIC_LOG_V(INFO, TAG, "Descriptor is not found : %d", res);
+            if (g_sendBuffer)
+            {
+                CAResult_t res = CALEClientWriteCharacteristic(env, gatt);
+                if (CA_STATUS_OK != res)
+                {
+                    OIC_LOG(ERROR, TAG, "CALEClientWriteCharacteristic has failed");
+                    goto error_exit;
+                }
+            }
         }
 
         res = CALEClientUpdateDeviceState(address, STATE_CONNECTED, STATE_CHARACTER_SET,
@@ -3522,67 +4218,43 @@ Java_org_iotivity_jar_caleclientinterface_CALeGattServicesDiscoveredCallback(JNI
     }
     else
     {
-        CAResult_t res = CALEClientWriteCharacteristic(env, gatt);
-        if (CA_STATUS_OK != res)
+        if (g_sendBuffer)
         {
-            OIC_LOG(ERROR, TAG, "CALEClientWriteCharacteristic has failed");
-            goto error_exit;
+            CAResult_t res = CALEClientWriteCharacteristic(env, gatt);
+            if (CA_STATUS_OK != res)
+            {
+                OIC_LOG(ERROR, TAG, "CALEClientWriteCharacteristic has failed");
+                goto error_exit;
+            }
         }
     }
+    OIC_LOG(INFO, TAG, "ServicesDiscovery is successful");
     (*env)->ReleaseStringUTFChars(env, jni_address, address);
     return;
 
     // error label.
 error_exit:
+    OIC_LOG(ERROR, TAG, "ServicesDiscovery has failed");
     (*env)->ReleaseStringUTFChars(env, jni_address, address);
     CALEClientSendFinish(env, gatt);
-    ca_cond_signal(g_threadSendCond);
     return;
 }
 
 /*
- * Class:     org_iotivity_jar_caleinterface
- * Method:    CALeGattCharacteristicReadCallback
- * Signature: (Landroid/bluetooth/BluetoothGatt;Landroid/bluetooth/BluetoothGattCharacteristic;I)V
- */
-JNIEXPORT void JNICALL
-Java_org_iotivity_jar_caleclientinterface_CALeGattCharacteristicReadCallback(JNIEnv *env,
-                                                                             jobject obj,
-                                                                             jobject gatt,
-                                                                             jobject characteristic,
-                                                                             jbyteArray data,
-                                                                             jint status)
-{
-    OIC_LOG_V(DEBUG, TAG, "CALeGattCharacteristicReadCallback - status : %d", status);
-}
-
-/*
- * Class:     org_iotivity_jar_caleinterface
+ * Class:     org_iotivity_ca_jar_caleinterface
  * Method:    CALeGattCharacteristicWritjclasseCallback
  * Signature: (Landroid/bluetooth/BluetoothGatt;Landroid/bluetooth/BluetoothGattCharacteristic;I)V
  */
 JNIEXPORT void JNICALL
-Java_org_iotivity_jar_caleclientinterface_CALeGattCharacteristicWriteCallback(
-        JNIEnv *env, jobject obj, jobject gatt, jobject characteristic, jbyteArray data,
+Java_org_iotivity_ca_CaLeClientInterface_caLeGattCharacteristicWriteCallback(
+        JNIEnv *env, jobject obj, jobject gatt, jbyteArray data,
         jint status)
 {
     OIC_LOG_V(DEBUG, TAG, "CALeGattCharacteristicWriteCallback - status : %d", status);
     VERIFY_NON_NULL_VOID(env, TAG, "env is null");
+    VERIFY_NON_NULL_VOID(obj, TAG, "obj is null");
     VERIFY_NON_NULL_VOID(gatt, TAG, "gatt is null");
 
-    ca_mutex_lock(g_threadSendCBMutex);
-    if (!g_isRequestedSend)
-    {
-        OIC_LOG(DEBUG, TAG, "CALeGattCharacteristicWriteCallback - waiting");
-        ca_cond_wait(g_threadSendCBCond, g_threadSendCBMutex);
-    }
-    ca_mutex_unlock(g_threadSendCBMutex);
-
-    jboolean isCopy;
-    char* wroteData = (char*) (*env)->GetByteArrayElements(env, data, &isCopy);
-
-    OIC_LOG_V(DEBUG, TAG, "CALeGattCharacteristicWriteCallback - write data : %s", wroteData);
-
     // send success & signal
     jstring jni_address = CALEClientGetAddressFromGattObj(env, gatt);
     if (!jni_address)
@@ -3596,16 +4268,38 @@ Java_org_iotivity_jar_caleclientinterface_CALeGattCharacteristicWriteCallback(
         goto error_exit;
     }
 
-    if (GATT_SUCCESS != status) // error case
+    jint gatt_success = CALEGetConstantsValue(env, CLASSPATH_BT_GATT, "GATT_SUCCESS");
+    if (gatt_success != status) // error case
     {
         OIC_LOG(ERROR, TAG, "send failure");
-        CAResult_t res = CALEClientUpdateDeviceState(address, STATE_CONNECTED, STATE_CHARACTER_SET,
-                                                     STATE_SEND_FAILED);
+
+        // retry to write
+        CAResult_t res = CALEClientWriteCharacteristic(env, gatt);
         if (CA_STATUS_OK != res)
         {
-            OIC_LOG(ERROR, TAG, "CALEClientUpdateDeviceState has failed");
+            OIC_LOG(ERROR, TAG, "WriteCharacteristic has failed");
+            ca_mutex_lock(g_threadWriteCharacteristicMutex);
+            g_isSignalSetFlag = true;
+            ca_cond_signal(g_threadWriteCharacteristicCond);
+            ca_mutex_unlock(g_threadWriteCharacteristicMutex);
+
+            CAResult_t res = CALEClientUpdateDeviceState(address, STATE_CONNECTED,
+                                                         STATE_CHARACTER_SET,
+                                                         STATE_SEND_FAILED);
+            if (CA_STATUS_OK != res)
+            {
+                OIC_LOG(ERROR, TAG, "CALEClientUpdateDeviceState has failed");
+            }
+
+            if (g_clientErrorCallback)
+            {
+                jint length = (*env)->GetArrayLength(env, data);
+                g_clientErrorCallback(address, data, length, CA_SEND_FAILED);
+            }
+
+            CALEClientSendFinish(env, gatt);
+            goto error_exit;
         }
-        CALEClientSendFinish(env, gatt);
     }
     else
     {
@@ -3616,57 +4310,58 @@ Java_org_iotivity_jar_caleclientinterface_CALeGattCharacteristicWriteCallback(
         {
             OIC_LOG(ERROR, TAG, "CALEClientUpdateDeviceState has failed");
         }
+
+        ca_mutex_lock(g_threadWriteCharacteristicMutex);
+        OIC_LOG(DEBUG, TAG, "g_isSignalSetFlag is set true and signal");
+        g_isSignalSetFlag = true;
+        ca_cond_signal(g_threadWriteCharacteristicCond);
+        ca_mutex_unlock(g_threadWriteCharacteristicMutex);
+
         CALEClientUpdateSendCnt(env);
     }
 
-    CALEClientSetWriteCharacteristicCBFlag(true);
-    CALEClientSetTheSendRequestFlag(false);
-    ca_cond_signal(g_threadSendCond);
     (*env)->ReleaseStringUTFChars(env, jni_address, address);
     return;
 
     // error label.
 error_exit:
 
-    CALEClientSetWriteCharacteristicCBFlag(true);
-    CALEClientSetTheSendRequestFlag(false);
     CALEClientSendFinish(env, gatt);
-    ca_cond_signal(g_threadSendCond);
     return;
 }
 
 /*
- * Class:     org_iotivity_jar_caleinterface
+ * Class:     org_iotivity_ca_jar_caleinterface
  * Method:    CALeGattCharacteristicChangedCallback
  * Signature: (Landroid/bluetooth/BluetoothGatt;Landroid/bluetooth/BluetoothGattCharacteristic;)V
  */
 JNIEXPORT void JNICALL
-Java_org_iotivity_jar_caleclientinterface_CALeGattCharacteristicChangedCallback(
-        JNIEnv *env, jobject obj, jobject gatt, jobject characteristic, jbyteArray data)
+Java_org_iotivity_ca_CaLeClientInterface_caLeGattCharacteristicChangedCallback(
+        JNIEnv *env, jobject obj, jobject gatt, jbyteArray data)
 {
     OIC_LOG(DEBUG, TAG, "CALeGattCharacteristicChangedCallback");
     VERIFY_NON_NULL_VOID(env, TAG, "env is null");
+    VERIFY_NON_NULL_VOID(obj, TAG, "obj is null");
     VERIFY_NON_NULL_VOID(gatt, TAG, "gatt is null");
     VERIFY_NON_NULL_VOID(data, TAG, "data is null");
 
-    // get Byte Array and covert to char*
+    // get Byte Array and convert to uint8_t*
     jint length = (*env)->GetArrayLength(env, data);
 
     jboolean isCopy;
     jbyte *jni_byte_responseData = (jbyte*) (*env)->GetByteArrayElements(env, data, &isCopy);
 
-    OIC_LOG_V(DEBUG, TAG, "CALeGattCharacteristicChangedCallback - raw data received : %s",
+    OIC_LOG_V(DEBUG, TAG, "CALeGattCharacteristicChangedCallback - raw data received : %p",
             jni_byte_responseData);
 
-    char* receivedData = (char*) OICMalloc(sizeof(char) * length + 1);
+    uint8_t* receivedData = OICMalloc(length);
     if (!receivedData)
     {
-        OIC_LOG(ERROR, TAG, "recevicedData is null");
+        OIC_LOG(ERROR, TAG, "receivedData is null");
         return;
     }
 
-    memcpy(receivedData, (const char*) jni_byte_responseData, length);
-    receivedData[length] = '\0';
+    memcpy(receivedData, jni_byte_responseData, length);
     (*env)->ReleaseByteArrayElements(env, data, jni_byte_responseData, JNI_ABORT);
 
     jstring jni_address = CALEClientGetAddressFromGattObj(env, gatt);
@@ -3685,12 +4380,12 @@ Java_org_iotivity_jar_caleclientinterface_CALeGattCharacteristicChangedCallback(
         return;
     }
 
-    OIC_LOG_V(DEBUG, TAG, "CALeGattCharacteristicChangedCallback - data. : %s, %d",
+    OIC_LOG_V(DEBUG, TAG, "CALeGattCharacteristicChangedCallback - data. : %p, %d",
               receivedData, length);
 
     ca_mutex_lock(g_bleServerBDAddressMutex);
     uint32_t sentLength = 0;
-    g_CABLEClientDataReceivedCallback(address, OIC_GATT_SERVICE_UUID, receivedData, length,
+    g_CABLEClientDataReceivedCallback(address, receivedData, length,
                                       &sentLength);
     ca_mutex_unlock(g_bleServerBDAddressMutex);
 
@@ -3698,73 +4393,40 @@ Java_org_iotivity_jar_caleclientinterface_CALeGattCharacteristicChangedCallback(
 }
 
 /*
- * Class:     org_iotivity_jar_caleinterface
- * Method:    CALeGattDescriptorReadCallback
+ * Class:     org_iotivity_ca_jar_caleinterface
+ * Method:    CALeGattDescriptorWriteCallback
  * Signature: (Landroid/bluetooth/BluetoothGatt;Landroid/bluetooth/BluetoothGattDescriptor;I)V
  */
 JNIEXPORT void JNICALL
-Java_org_iotivity_jar_caleclientinterface_CALeGattDescriptorReadCallback(JNIEnv *env, jobject obj,
+Java_org_iotivity_ca_CaLeClientInterface_caLeGattDescriptorWriteCallback(JNIEnv *env, jobject obj,
                                                                          jobject gatt,
-                                                                         jobject descriptor,
                                                                          jint status)
 {
-    OIC_LOG_V(DEBUG, TAG, "CALeGattDescriptorReadCallback - status %d: ", status);
-}
-
-/*
- * Class:     org_iotivity_jar_caleinterface
- * Method:    CALeGattDescriptorWriteCallback
- * Signature: (Landroid/bluetooth/BluetoothGatt;Landroid/bluetooth/BluetoothGattDescriptor;I)V
- */
-JNIEXPORT void JNICALL
-Java_org_iotivity_jar_caleclientinterface_CALeGattDescriptorWriteCallback(JNIEnv *env, jobject obj,
-                                                                          jobject gatt,
-                                                                          jobject descriptor,
-                                                                          jint status)
-{
     OIC_LOG_V(DEBUG, TAG, "CALeGattDescriptorWriteCallback - status %d: ", status);
     VERIFY_NON_NULL_VOID(env, TAG, "env is null");
+    VERIFY_NON_NULL_VOID(obj, TAG, "obj is null");
     VERIFY_NON_NULL_VOID(gatt, TAG, "gatt is null");
 
-    CAResult_t res = CALEClientWriteCharacteristic(env, gatt);
-    if (CA_STATUS_OK != res)
+    jint gatt_success = CALEGetConstantsValue(env, CLASSPATH_BT_GATT, "GATT_SUCCESS");
+    if (gatt_success != status) // error
     {
-        OIC_LOG(ERROR, TAG, "CALEClientWriteCharacteristic has failed");
         goto error_exit;
     }
+
+    if (g_sendBuffer)
+    {
+        CAResult_t res = CALEClientWriteCharacteristic(env, gatt);
+        if (CA_STATUS_OK != res)
+        {
+            OIC_LOG(ERROR, TAG, "CALEClientWriteCharacteristic has failed");
+            goto error_exit;
+        }
+    }
     return;
 
 // error label.
 error_exit:
 
     CALEClientSendFinish(env, gatt);
-    ca_cond_signal(g_threadSendCond);
     return;
 }
-
-/*
- * Class:     org_iotivity_jar_caleinterface
- * Method:    CALeGattReliableWriteCompletedCallback
- * Signature: (Landroid/bluetooth/BluetoothGatt;I)V
- */
-JNIEXPORT void JNICALL
-Java_org_iotivity_jar_caleclientinterface_CALeGattReliableWriteCompletedCallback(JNIEnv *env,
-                                                                                 jobject obj,
-                                                                                 jobject gatt,
-                                                                                 jint status)
-{
-    OIC_LOG_V(DEBUG, TAG, "CALeGattReliableWriteCompletedCallback - status %d: ", status);
-}
-
-/*
- * Class:     org_iotivity_jar_caleinterface
- * Method:    CALeGattReadRemoteRssiCallback
- * Signature: (Landroid/bluetooth/BluetoothGatt;II)V
- */
-JNIEXPORT void JNICALL
-Java_org_iotivity_jar_caleclientinterface_CALeGattReadRemoteRssiCallback(JNIEnv *env, jobject obj,
-                                                                         jobject gatt, jint rssi,
-                                                                         jint status)
-{
-    OIC_LOG_V(DEBUG, TAG, "CALeGattReadRemoteRssiCallback - rssi %d,  status %d: ", rssi, status);
-}