[IOT-1391] fix BLE scan logic which create thread.
[platform/upstream/iotivity.git] / resource / csdk / connectivity / src / bt_le_adapter / android / caleclient.c
index f463d38..d66408d 100644 (file)
@@ -41,6 +41,8 @@
 
 #define MICROSECS_PER_SEC 1000000
 #define WAIT_TIME_WRITE_CHARACTERISTIC 10 * MICROSECS_PER_SEC
+#define WAIT_TIME_SCAN_INTERVAL_DEFAULT 10
+#define WAIT_TIME_SCANNED_CHECKING 30
 
 #define GATT_CONNECTION_PRIORITY_BALANCED   0
 #define GATT_FAILURE                        257
@@ -68,7 +70,6 @@ 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_isStartedScan = false;
 
 static jbyteArray g_sendBuffer = NULL;
 static uint32_t g_targetCnt = 0;
@@ -94,7 +95,16 @@ static ca_mutex g_deviceStateListMutex = NULL;
 static ca_mutex g_deviceScanRetryDelayMutex = NULL;
 static ca_cond g_deviceScanRetryDelayCond = NULL;
 
-static ca_mutex g_scanMutex = NULL;
+static ca_mutex g_threadScanIntervalMutex = NULL;
+static ca_cond g_threadScanIntervalCond = NULL;
+
+static ca_mutex g_threadSendStateMutex = NULL;
+
+static int32_t g_scanIntervalTime = WAIT_TIME_SCAN_INTERVAL_DEFAULT;
+static int32_t g_scanIntervalTimePrev = WAIT_TIME_SCAN_INTERVAL_DEFAULT;
+static int32_t g_intervalCount = 0;
+static bool g_isWorkingScanThread = false;
+static CALEScanState_t g_scanningStep = BLE_SCAN_DISABLE;
 
 static CABLEDataReceivedCallback g_CABLEClientDataReceivedCallback = NULL;
 
@@ -120,8 +130,146 @@ static bool CALECheckConnectionStateValue(jint state)
         case GATT_REQUEST_NOT_SUPPORTED:
         case GATT_WRITE_NOT_PERMITTED:
             return true;
+        default:
+            return false;
     }
-    return false;
+}
+
+void CALEClientSetScanInterval(int32_t intervalTime, int32_t workingCount)
+{
+    OIC_LOG_V(DEBUG, TAG, "CALEClientSetScanInterval : %d -> %d",
+              g_scanIntervalTime, intervalTime);
+
+    // previous time should be stored.
+    if (0 < workingCount)
+    {
+        g_scanIntervalTimePrev = g_scanIntervalTime;
+    }
+    g_scanIntervalTime = intervalTime;
+    g_intervalCount = workingCount;
+}
+
+void CALERestartScanWithInterval(int32_t intervalTime, int32_t workingCount)
+{
+    // restart scan with interval
+    CALEClientSetScanInterval(intervalTime, workingCount);
+    ca_cond_signal(g_threadScanIntervalCond);
+}
+
+static void CALEScanThread(void* object)
+{
+    (void)object;
+
+    bool isAttached = false;
+    JNIEnv* env = NULL;
+    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;
+    }
+
+    ca_mutex_lock(g_threadScanIntervalMutex);
+    while(g_isWorkingScanThread)
+    {
+        OIC_LOG(DEBUG, TAG, "scan waiting time out");
+        if (BLE_SCAN_ENABLE == g_scanningStep)
+        {
+            //stop scan
+            CAResult_t ret = CALEClientStopScan();
+            if (CA_STATUS_OK != ret)
+            {
+                OIC_LOG(INFO, TAG, "CALEClientStopScan has failed");
+            }
+        }
+        else
+        {
+            //start scan
+            CAResult_t ret = CALEClientStartScan();
+            if (CA_STATUS_OK != ret)
+            {
+                OIC_LOG(INFO, TAG, "CALEClientStartScan has failed");
+            }
+        }
+
+        OIC_LOG_V(DEBUG, TAG, "wait for Scan Interval Time during %d sec", g_scanIntervalTime);
+        if (CA_WAIT_SUCCESS == ca_cond_wait_for(g_threadScanIntervalCond,
+                                                g_threadScanIntervalMutex,
+                                                g_scanIntervalTime * MICROSECS_PER_SEC))
+        {
+            // called signal scan thread will be terminated
+            OIC_LOG(DEBUG, TAG, "signal scanInterval waiting");
+            g_scanningStep = BLE_SCAN_DISABLE;
+        }
+        else
+        {
+           if (BLE_SCAN_ENABLE == g_scanningStep)
+           {
+               if (g_intervalCount > 0)
+               {
+                   if (g_intervalCount == 1)
+                   {
+                       OIC_LOG(DEBUG, TAG, "reset default time");
+                       CALEClientSetScanInterval(g_scanIntervalTimePrev, 0);
+                   }
+                   g_intervalCount--;
+                   OIC_LOG_V(DEBUG, TAG, "interval count : %d", g_intervalCount);
+               }
+               g_scanningStep = BLE_SCAN_DISABLE;
+           }
+           else
+           {
+               g_scanningStep = BLE_SCAN_ENABLE;
+           }
+        }
+    }
+    ca_mutex_unlock(g_threadScanIntervalMutex);
+
+    if (isAttached)
+    {
+        (*g_jvm)->DetachCurrentThread(g_jvm);
+    }
+}
+
+CAResult_t CALEClientStartScanWithInterval()
+{
+    OIC_LOG(DEBUG, TAG, "IN - CALEClientStartScanWithInterval");
+
+    if (g_isWorkingScanThread)
+    {
+        OIC_LOG(DEBUG, TAG, "scan interval logic already running");
+        return CA_STATUS_OK;
+    }
+
+    // initialize scan flags
+    g_scanningStep = BLE_SCAN_DISABLE;
+    g_isWorkingScanThread = true;
+    g_intervalCount = 0;
+    g_scanIntervalTime = g_scanIntervalTimePrev;
+
+    if (CA_STATUS_OK != ca_thread_pool_add_task(g_threadPoolHandle,
+                                                CALEScanThread, NULL))
+    {
+        OIC_LOG(ERROR, TAG, "Failed to create read thread!");
+        g_isWorkingScanThread = false;
+        return CA_STATUS_FAILED;
+    }
+
+    OIC_LOG(DEBUG, TAG, "OUT - CALEClientStartScanWithInterval");
+    return CA_STATUS_OK;
+}
+
+void CALEClientStopScanWithInterval()
+{
+    g_isWorkingScanThread = false;
+    ca_cond_signal(g_threadScanIntervalCond);
 }
 
 //getting jvm
@@ -154,7 +302,7 @@ CAResult_t CALECreateJniInterfaceObject()
     }
 
     bool isAttached = false;
-    JNIEnv* env;
+    JNIEnv* env = NULL;
     jint res = (*g_jvm)->GetEnv(g_jvm, (void**) &env, JNI_VERSION_1_6);
     if (JNI_OK != res)
     {
@@ -235,7 +383,7 @@ CAResult_t CALEClientInitialize()
     }
 
     bool isAttached = false;
-    JNIEnv* env;
+    JNIEnv* env = NULL;
     jint res = (*g_jvm)->GetEnv(g_jvm, (void**) &env, JNI_VERSION_1_6);
     if (JNI_OK != res)
     {
@@ -283,6 +431,7 @@ CAResult_t CALEClientInitialize()
     g_threadCond = ca_cond_new();
     g_threadWriteCharacteristicCond = ca_cond_new();
     g_deviceScanRetryDelayCond = ca_cond_new();
+    g_threadScanIntervalCond =  ca_cond_new();
 
     CALEClientCreateDeviceList();
     CALEClientJNISetContext();
@@ -333,7 +482,7 @@ void CALEClientTerminate()
     }
 
     bool isAttached = false;
-    JNIEnv* env;
+    JNIEnv* env = NULL;
     jint res = (*g_jvm)->GetEnv(g_jvm, (void**) &env, JNI_VERSION_1_6);
     if (JNI_OK != res)
     {
@@ -390,7 +539,6 @@ void CALEClientTerminate()
         OIC_LOG(ERROR, TAG, "CALEClientRemoveAllGattObjs has failed");
     }
 
-    CALEClientSetScanFlag(false);
     CALEClientSetSendFinishFlag(true);
 
     CALEClientTerminateGattMutexVariables();
@@ -400,14 +548,19 @@ void CALEClientTerminate()
     ca_cond_free(g_threadCond);
     ca_cond_free(g_threadWriteCharacteristicCond);
     ca_cond_free(g_deviceScanRetryDelayCond);
+    ca_cond_free(g_threadScanIntervalCond);
 
     g_deviceDescCond = NULL;
     g_threadCond = NULL;
     g_threadWriteCharacteristicCond = NULL;
     g_deviceScanRetryDelayCond = NULL;
+    g_threadScanIntervalCond = NULL;
 
     g_isSignalSetFlag = false;
 
+    // stop scanning
+    CALEClientStopScanWithInterval();
+
     if (isAttached)
     {
         (*g_jvm)->DetachCurrentThread(g_jvm);
@@ -425,7 +578,7 @@ CAResult_t CALEClientDestroyJniInterface()
     }
 
     bool isAttached = false;
-    JNIEnv* env;
+    JNIEnv* env = NULL;
     jint res = (*g_jvm)->GetEnv(g_jvm, (void**) &env, JNI_VERSION_1_6);
     if (JNI_OK != res)
     {
@@ -525,7 +678,7 @@ CAResult_t CALEClientSendMulticastMessage(const uint8_t* data,
     }
 
     bool isAttached = false;
-    JNIEnv* env;
+    JNIEnv* env = NULL;
     jint res = (*g_jvm)->GetEnv(g_jvm, (void**) &env, JNI_VERSION_1_6);
     if (JNI_OK != res)
     {
@@ -556,6 +709,9 @@ CAResult_t CALEClientSendMulticastMessage(const uint8_t* data,
 
 CAResult_t CALEClientStartUnicastServer(const char* address)
 {
+#ifndef TB_LOG
+    (void)address;
+#endif
     OIC_LOG_V(DEBUG, TAG, "it is not needed in this platform (%s)", address);
 
     return CA_NOT_SUPPORTED;
@@ -594,6 +750,7 @@ CAResult_t CALEClientIsThereScannedDevices(JNIEnv *env, const char* address)
 
     if (!g_deviceList)
     {
+        OIC_LOG(ERROR, TAG, "g_deviceList is not available");
         return CA_STATUS_FAILED;
     }
 
@@ -608,6 +765,9 @@ CAResult_t CALEClientIsThereScannedDevices(JNIEnv *env, const char* address)
         static uint64_t const TIMEOUT =
             2 * MICROSECS_PER_SEC;  // Microseconds
 
+        // set scan interval and start scan
+        CALERestartScanWithInterval(WAIT_TIME_SCANNED_CHECKING, 1);
+
         bool devicesDiscovered = false;
         for (size_t i = 0; i < RETRIES; ++i)
         {
@@ -658,19 +818,26 @@ CAResult_t CALEClientIsThereScannedDevices(JNIEnv *env, const char* address)
             }
         }
 
+        // reset scan interval time after checking scanned devices
+        CALERestartScanWithInterval(g_scanIntervalTimePrev, 0);
+
         // time out for scanning devices
         if (!devicesDiscovered)
         {
             return CA_STATUS_FAILED;
         }
     }
+    else
+    {
+        OIC_LOG(DEBUG, TAG, "there is a target device in the scanned devices");
+    }
 
     return CA_STATUS_OK;
 }
 
 
 CAResult_t CALEClientSendUnicastMessageImpl(const char* address, const uint8_t* data,
-                                      const uint32_t dataLen)
+                                            const uint32_t dataLen)
 {
     OIC_LOG_V(DEBUG, TAG, "CALEClientSendUnicastMessageImpl, address: %s, data: %p", address,
               data);
@@ -684,7 +851,7 @@ CAResult_t CALEClientSendUnicastMessageImpl(const char* address, const uint8_t*
     }
 
     bool isAttached = false;
-    JNIEnv* env;
+    JNIEnv* env = NULL;
     jint res = (*g_jvm)->GetEnv(g_jvm, (void**) &env, JNI_VERSION_1_6);
     if (JNI_OK != res)
     {
@@ -740,14 +907,7 @@ CAResult_t CALEClientSendUnicastMessageImpl(const char* address, const uint8_t*
             if (!strcmp(setAddress, address))
             {
                 (*env)->ReleaseStringUTFChars(env, jni_setAddress, setAddress);
-
-                // connect to gatt server
-                ret = CALEClientStopScan();
-                if (CA_STATUS_OK != ret)
-                {
-                    OIC_LOG(ERROR, TAG, "CALEClientStopScan has failed");
-                    goto error_exit;
-                }
+                (*env)->DeleteLocalRef(env, jni_setAddress);
 
                 if (g_sendBuffer)
                 {
@@ -772,6 +932,7 @@ CAResult_t CALEClientSendUnicastMessageImpl(const char* address, const uint8_t*
                 break;
             }
             (*env)->ReleaseStringUTFChars(env, jni_setAddress, setAddress);
+            (*env)->DeleteLocalRef(env, jni_setAddress);
         }
     }
 
@@ -793,44 +954,36 @@ CAResult_t CALEClientSendUnicastMessageImpl(const char* address, const uint8_t*
         (*g_jvm)->DetachCurrentThread(g_jvm);
     }
 
-    // start LE Scan again
-    ret = CALEClientStartScan();
-    if (CA_STATUS_OK != ret)
-    {
-        OIC_LOG(ERROR, TAG, "CALEClientStartScan has failed");
-        ca_mutex_unlock(g_threadSendMutex);
-        return res;
-    }
-
     ca_mutex_unlock(g_threadSendMutex);
     OIC_LOG(INFO, TAG, "unicast - send logic has finished");
-    return CALECheckSendState(address);
-
-    // error label.
-error_exit:
+    if (CALEClientIsValidState(address, CA_LE_SEND_STATE,
+                               STATE_SEND_SUCCESS))
+    {
+        ret = CA_STATUS_OK;
+    }
+    else
+    {
+        ret = CA_SEND_FAILED;
+    }
 
-    // start LE Scan again
-    ret = CALEClientStartScan();
-    if (CA_STATUS_OK != ret)
+    // reset send state
+    CAResult_t resetRet = CALEClientUpdateDeviceState(address, CA_LE_SEND_STATE,
+                                                      STATE_SEND_NONE);
+    if (CA_STATUS_OK != resetRet)
     {
-        OIC_LOG(ERROR, TAG, "CALEClientStartScan has failed");
-        ca_mutex_unlock(g_threadSendMutex);
-        if (isAttached)
-        {
-            (*g_jvm)->DetachCurrentThread(g_jvm);
-        }
-        return res;
+        OIC_LOG_V(ERROR, TAG, "CALEClientUpdateDeviceState has failed (%d)", resetRet);
+        ret = CA_SEND_FAILED;
     }
 
+    return ret;
+
+    // error label.
+error_exit:
     if (isAttached)
     {
         (*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;
 }
@@ -866,14 +1019,6 @@ CAResult_t CALEClientSendMulticastMessageImpl(JNIEnv *env, const uint8_t* data,
         goto error_exit;
     }
 
-    // connect to gatt server
-    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;
 
@@ -895,22 +1040,6 @@ CAResult_t CALEClientSendMulticastMessageImpl(JNIEnv *env, const uint8_t* data,
         {
             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");
-            continue;
-        }
-
-        const char* address = (*env)->GetStringUTFChars(env, jni_address, NULL);
-        if (!address)
-        {
-            OIC_LOG(ERROR, TAG, "address is not available");
-            continue;
-        }
-
-        (*env)->ReleaseStringUTFChars(env, jni_address, address);
     }
 
     OIC_LOG(DEBUG, TAG, "connection routine is finished for multicast");
@@ -924,59 +1053,16 @@ CAResult_t CALEClientSendMulticastMessageImpl(JNIEnv *env, const uint8_t* data,
         OIC_LOG(DEBUG, TAG, "the data was sent");
     }
     ca_mutex_unlock(g_threadMutex);
-
-    // start LE Scan again
-    res = CALEClientStartScan();
-    if (CA_STATUS_OK != res)
-    {
-        OIC_LOG(ERROR, TAG, "CALEClientStartScan has failed");
-        ca_mutex_unlock(g_threadSendMutex);
-        return res;
-    }
-
     ca_mutex_unlock(g_threadSendMutex);
     OIC_LOG(DEBUG, TAG, "OUT - CALEClientSendMulticastMessageImpl");
     return CA_STATUS_OK;
 
 error_exit:
-    res = CALEClientStartScan();
-    if (CA_STATUS_OK != res)
-    {
-        OIC_LOG(ERROR, TAG, "CALEClientStartScan has failed");
-        ca_mutex_unlock(g_threadSendMutex);
-        return res;
-    }
-
     ca_mutex_unlock(g_threadSendMutex);
-    OIC_LOG(DEBUG, TAG, "OUT - CALEClientSendMulticastMessageImpl");
+    OIC_LOG(ERROR, TAG, "OUT - CALEClientSendMulticastMessageImpl");
     return CA_SEND_FAILED;
 }
 
-CAResult_t CALECheckSendState(const char* address)
-{
-    VERIFY_NON_NULL(address, TAG, "address is null");
-
-    ca_mutex_lock(g_deviceStateListMutex);
-    CALEState_t* state = CALEClientGetStateInfo(address);
-    if (NULL == state)
-    {
-        OIC_LOG(ERROR, TAG, "state is null");
-        ca_mutex_unlock(g_deviceStateListMutex);
-        return CA_SEND_FAILED;
-    }
-
-    if (STATE_SEND_SUCCESS != state->sendState)
-    {
-        OIC_LOG(ERROR, TAG, "sendstate is not STATE_SEND_SUCCESS");
-        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;
-}
-
 CAResult_t CALEClientSendData(JNIEnv *env, jobject device)
 {
     OIC_LOG(DEBUG, TAG, "IN - CALEClientSendData");
@@ -999,7 +1085,6 @@ CAResult_t CALEClientSendData(JNIEnv *env, jobject device)
         ca_mutex_lock(g_deviceStateListMutex);
         state = CALEClientGetStateInfo(address);
         ca_mutex_unlock(g_deviceStateListMutex);
-        (*env)->ReleaseStringUTFChars(env, jni_address, address);
     }
 
     if (!state)
@@ -1010,13 +1095,6 @@ CAResult_t CALEClientSendData(JNIEnv *env, jobject device)
         // 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)
             {
@@ -1040,21 +1118,10 @@ CAResult_t CALEClientSendData(JNIEnv *env, jobject device)
     }
     else
     {
-        if (STATE_CONNECTED == state->connectedState)
+        if (CALEClientIsValidState(address, CA_LE_CONNECTION_STATE,
+                                   STATE_SERVICE_CONNECTED))
         {
             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)
@@ -1073,7 +1140,13 @@ CAResult_t CALEClientSendData(JNIEnv *env, jobject device)
             }
             (*env)->ReleaseStringUTFChars(env, jni_address, address);
         }
-        else
+        else if(CALEClientIsValidState(address, CA_LE_CONNECTION_STATE,
+                                       STATE_CONNECTED))
+        {
+            OIC_LOG(INFO, TAG, "service connecting...");
+        }
+        else if(CALEClientIsValidState(address, CA_LE_CONNECTION_STATE,
+                                       STATE_DISCONNECTED))
         {
             OIC_LOG(INFO, TAG, "STATE_DISCONNECTED - start to connect LE");
 
@@ -1081,13 +1154,6 @@ CAResult_t CALEClientSendData(JNIEnv *env, jobject device)
             // 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)
                 {
@@ -1102,7 +1168,9 @@ CAResult_t CALEClientSendData(JNIEnv *env, jobject device)
 
             OIC_LOG(DEBUG, TAG, "start to connect LE");
             jobject gatt = CALEClientConnect(env, device,
-                                             CALEClientGetAutoConnectFlag(env, jni_address));
+                                             CALEClientGetFlagFromState(env, jni_address,
+                                                                        CA_LE_AUTO_CONNECT_FLAG));
+
             if (NULL == gatt)
             {
                 OIC_LOG(ERROR, TAG, "CALEClientConnect has failed");
@@ -1192,14 +1260,8 @@ CAResult_t CALEClientStartScan()
         return CA_STATUS_FAILED;
     }
 
-    if (g_isStartedScan)
-    {
-        OIC_LOG(INFO, TAG, "scanning is already started");
-        return CA_STATUS_OK;
-    }
-
     bool isAttached = false;
-    JNIEnv* env;
+    JNIEnv* env = NULL;
     jint res = (*g_jvm)->GetEnv(g_jvm, (void**) &env, JNI_VERSION_1_6);
     if (JNI_OK != res)
     {
@@ -1272,6 +1334,7 @@ CAResult_t CALEClientStartScanImpl(JNIEnv *env, jobject callback)
     if (!jni_mid_getDefaultAdapter)
     {
         OIC_LOG(ERROR, TAG, "jni_mid_getDefaultAdapter is null");
+        (*env)->DeleteLocalRef(env, jni_cid_BTAdapter);
         return CA_STATUS_FAILED;
     }
 
@@ -1282,6 +1345,7 @@ CAResult_t CALEClientStartScanImpl(JNIEnv *env, jobject callback)
     if (!jni_mid_startLeScan)
     {
         OIC_LOG(ERROR, TAG, "startLeScan: jni_mid_startLeScan is null");
+        (*env)->DeleteLocalRef(env, jni_cid_BTAdapter);
         return CA_STATUS_FAILED;
     }
 
@@ -1291,22 +1355,25 @@ CAResult_t CALEClientStartScanImpl(JNIEnv *env, jobject callback)
     if (!jni_obj_BTAdapter)
     {
         OIC_LOG(ERROR, TAG, "getState From BTAdapter: jni_obj_BTAdapter is null");
+        (*env)->DeleteLocalRef(env, jni_cid_BTAdapter);
         return CA_STATUS_FAILED;
     }
 
     // call start le scan method
+    OIC_LOG(INFO, TAG, "CALL API - startLeScan");
     jboolean jni_obj_startLeScan = (*env)->CallBooleanMethod(env, jni_obj_BTAdapter,
                                                              jni_mid_startLeScan, callback);
     if (!jni_obj_startLeScan)
     {
-        OIC_LOG(INFO, TAG, "startLeScan is failed");
+        OIC_LOG(INFO, TAG, "startLeScan has failed");
     }
     else
     {
-        OIC_LOG(DEBUG, TAG, "startLeScan is started");
-        CALEClientSetScanFlag(true);
+        OIC_LOG(DEBUG, TAG, "LeScan has started");
     }
 
+    (*env)->DeleteLocalRef(env, jni_cid_BTAdapter);
+    (*env)->DeleteLocalRef(env, jni_obj_BTAdapter);
     return CA_STATUS_OK;
 }
 
@@ -1336,6 +1403,7 @@ CAResult_t CALEClientStartScanWithUUIDImpl(JNIEnv *env, jobjectArray uuids, jobj
     if (!jni_mid_getDefaultAdapter)
     {
         OIC_LOG(ERROR, TAG, "jni_mid_getDefaultAdapter is null");
+        (*env)->DeleteLocalRef(env, jni_cid_BTAdapter);
         return CA_STATUS_FAILED;
     }
 
@@ -1346,6 +1414,7 @@ CAResult_t CALEClientStartScanWithUUIDImpl(JNIEnv *env, jobjectArray uuids, jobj
     if (!jni_mid_startLeScan)
     {
         OIC_LOG(ERROR, TAG, "startLeScan: jni_mid_startLeScan is null");
+        (*env)->DeleteLocalRef(env, jni_cid_BTAdapter);
         return CA_STATUS_FAILED;
     }
 
@@ -1355,22 +1424,25 @@ CAResult_t CALEClientStartScanWithUUIDImpl(JNIEnv *env, jobjectArray uuids, jobj
     if (!jni_obj_BTAdapter)
     {
         OIC_LOG(ERROR, TAG, "getState From BTAdapter: jni_obj_BTAdapter is null");
+        (*env)->DeleteLocalRef(env, jni_cid_BTAdapter);
         return CA_STATUS_FAILED;
     }
 
     // call start le scan method
+    OIC_LOG(INFO, TAG, "CALL API - startLeScan (with UUID)");
     jboolean jni_obj_startLeScan = (*env)->CallBooleanMethod(env, jni_obj_BTAdapter,
                                                              jni_mid_startLeScan, uuids, callback);
     if (!jni_obj_startLeScan)
     {
-        OIC_LOG(INFO, TAG, "startLeScan With UUID is failed");
+        OIC_LOG(INFO, TAG, "startLeScan has failed");
     }
     else
     {
-        OIC_LOG(DEBUG, TAG, "startLeScan With UUID is started");
-        CALEClientSetScanFlag(true);
+        OIC_LOG(DEBUG, TAG, "LeScan has started");
     }
 
+    (*env)->DeleteLocalRef(env, jni_cid_BTAdapter);
+    (*env)->DeleteLocalRef(env, jni_obj_BTAdapter);
     return CA_STATUS_OK;
 }
 
@@ -1416,14 +1488,8 @@ CAResult_t CALEClientStopScan()
         return CA_STATUS_FAILED;
     }
 
-    if (!g_isStartedScan)
-    {
-        OIC_LOG(INFO, TAG, "scanning is already stopped");
-        return CA_STATUS_OK;
-    }
-
     bool isAttached = false;
-    JNIEnv* env;
+    JNIEnv* env = NULL;
     jint res = (*g_jvm)->GetEnv(g_jvm, (void**) &env, JNI_VERSION_1_6);
     if (JNI_OK != res)
     {
@@ -1449,10 +1515,6 @@ CAResult_t CALEClientStopScan()
             OIC_LOG(ERROR, TAG, "CALEClientStopScanImpl has failed");
         }
     }
-    else
-    {
-        CALEClientSetScanFlag(false);
-    }
 
     if (isAttached)
     {
@@ -1462,13 +1524,6 @@ 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");
@@ -1496,6 +1551,7 @@ CAResult_t CALEClientStopScanImpl(JNIEnv *env, jobject callback)
     if (!jni_mid_getDefaultAdapter)
     {
         OIC_LOG(ERROR, TAG, "jni_mid_getDefaultAdapter is null");
+        (*env)->DeleteLocalRef(env, jni_cid_BTAdapter);
         return CA_STATUS_FAILED;
     }
 
@@ -1506,6 +1562,7 @@ CAResult_t CALEClientStopScanImpl(JNIEnv *env, jobject callback)
     if (!jni_mid_stopLeScan)
     {
         OIC_LOG(ERROR, TAG, "stopLeScan: jni_mid_stopLeScan is null");
+        (*env)->DeleteLocalRef(env, jni_cid_BTAdapter);
         return CA_STATUS_FAILED;
     }
 
@@ -1515,26 +1572,31 @@ CAResult_t CALEClientStopScanImpl(JNIEnv *env, jobject callback)
     if (!jni_obj_BTAdapter)
     {
         OIC_LOG(ERROR, TAG, "jni_obj_BTAdapter is null");
+        (*env)->DeleteLocalRef(env, jni_cid_BTAdapter);
         return CA_STATUS_FAILED;
     }
 
-    OIC_LOG(DEBUG, TAG, "CALL API - request to stop LE Scan");
+    OIC_LOG(INFO, TAG, "CALL API - stopLeScan");
     // call start le scan method
     (*env)->CallVoidMethod(env, jni_obj_BTAdapter, jni_mid_stopLeScan, callback);
     if ((*env)->ExceptionCheck(env))
     {
         OIC_LOG(ERROR, TAG, "stopLeScan has failed");
+        (*env)->DeleteLocalRef(env, jni_cid_BTAdapter);
+        (*env)->DeleteLocalRef(env, jni_obj_BTAdapter);
         (*env)->ExceptionDescribe(env);
         (*env)->ExceptionClear(env);
         return CA_STATUS_FAILED;
     }
 
+    (*env)->DeleteLocalRef(env, jni_cid_BTAdapter);
+    (*env)->DeleteLocalRef(env, jni_obj_BTAdapter);
     return CA_STATUS_OK;
 }
 
-CAResult_t CALEClientSetAutoConnectFlag(JNIEnv *env, jstring jni_address, jboolean flag)
+CAResult_t CALEClientSetFlagToState(JNIEnv *env, jstring jni_address, jint state_idx, jboolean flag)
 {
-    OIC_LOG(DEBUG, TAG, "IN - CALEClientSetAutoConnectFlag");
+    OIC_LOG(DEBUG, TAG, "IN - CALEClientSetFlagToState");
     VERIFY_NON_NULL(env, TAG, "env");
     VERIFY_NON_NULL(jni_address, TAG, "jni_address");
 
@@ -1557,20 +1619,30 @@ CAResult_t CALEClientSetAutoConnectFlag(JNIEnv *env, jstring jni_address, jboole
             ca_mutex_unlock(g_deviceStateListMutex);
             return CA_STATUS_FAILED;
         }
-        OIC_LOG_V(INFO, TAG, "auto connect flag is set %d", flag);
+        OIC_LOG_V(INFO, TAG, "%d flag is set : %d", state_idx, flag);
 
-        curState->autoConnectFlag = flag;
+        switch(state_idx)
+        {
+            case CA_LE_AUTO_CONNECT_FLAG:
+                curState->autoConnectFlag = flag;
+                break;
+            case CA_LE_DESCRIPTOR_FOUND:
+                curState->isDescriptorFound = flag;
+                break;
+            default:
+                break;
+        }
     }
 
     (*env)->ReleaseStringUTFChars(env, jni_address, address);
     ca_mutex_unlock(g_deviceStateListMutex);
-    OIC_LOG(DEBUG, TAG, "OUT - CALEClientSetAutoConnectFlag");
+    OIC_LOG(DEBUG, TAG, "OUT - CALEClientSetFlagToState");
     return CA_STATUS_OK;
 }
 
-jboolean CALEClientGetAutoConnectFlag(JNIEnv *env, jstring jni_address)
+jboolean CALEClientGetFlagFromState(JNIEnv *env, jstring jni_address, jint state_idx)
 {
-    OIC_LOG(DEBUG, TAG, "IN - CALEClientGetAutoConnectFlag");
+    OIC_LOG(DEBUG, TAG, "IN - CALEClientGetFlagFromState");
     VERIFY_NON_NULL_RET(env, TAG, "env", false);
     VERIFY_NON_NULL_RET(jni_address, TAG, "jni_address", false);
 
@@ -1580,24 +1652,76 @@ jboolean CALEClientGetAutoConnectFlag(JNIEnv *env, jstring jni_address)
     if (!address)
     {
         OIC_LOG(ERROR, TAG, "address is not available");
+        ca_mutex_unlock(g_deviceStateListMutex);
         return JNI_FALSE;
     }
 
     CALEState_t* curState = CALEClientGetStateInfo(address);
+    (*env)->ReleaseStringUTFChars(env, jni_address, 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);
+    jboolean ret = JNI_FALSE;
+    switch(state_idx)
+    {
+        case CA_LE_AUTO_CONNECT_FLAG:
+            ret = curState->autoConnectFlag;
+            break;
+        case CA_LE_DESCRIPTOR_FOUND:
+            ret = curState->isDescriptorFound;
+            break;
+        default:
+            break;
+    }
     ca_mutex_unlock(g_deviceStateListMutex);
 
-    OIC_LOG(DEBUG, TAG, "OUT - CALEClientGetAutoConnectFlag");
-    return curState->autoConnectFlag;
+    OIC_LOG_V(INFO, TAG, "%d flag is %d", state_idx, ret);
+    OIC_LOG(DEBUG, TAG, "OUT - CALEClientGetFlagFromState");
+    return ret;
+}
+
+CAResult_t CALEClientDirectConnect(JNIEnv *env, jobject bluetoothDevice, jboolean autoconnect)
+{
+    OIC_LOG(DEBUG, TAG, "CALEClientDirectConnect");
+    VERIFY_NON_NULL(env, TAG, "env is null");
+    VERIFY_NON_NULL(bluetoothDevice, TAG, "bluetoothDevice is null");
+
+    ca_mutex_lock(g_threadSendMutex);
+
+    jstring jni_address = CALEGetAddressFromBTDevice(env, bluetoothDevice);
+    if (!jni_address)
+    {
+        OIC_LOG(ERROR, TAG, "jni_address is not available");
+        ca_mutex_unlock(g_threadSendMutex);
+        return CA_STATUS_FAILED;
+    }
+
+    const char* address = (*env)->GetStringUTFChars(env, jni_address, NULL);
+    if (!address)
+    {
+        OIC_LOG(ERROR, TAG, "address is not available");
+        ca_mutex_unlock(g_threadSendMutex);
+        return CA_STATUS_FAILED;
+    }
+
+    CAResult_t res = CA_STATUS_OK;
+    if(CALEClientIsValidState(address, CA_LE_CONNECTION_STATE,
+                              STATE_DISCONNECTED))
+    {
+        jobject newGatt = CALEClientConnect(env, bluetoothDevice, autoconnect);
+        if (NULL == newGatt)
+        {
+            OIC_LOG(INFO, TAG, "newGatt is not available");
+            res = CA_STATUS_FAILED;
+        }
+    }
+    ca_mutex_unlock(g_threadSendMutex);
+
+    return res;
 }
 
 jobject CALEClientConnect(JNIEnv *env, jobject bluetoothDevice, jboolean autoconnect)
@@ -1810,7 +1934,7 @@ CAResult_t CALEClientDisconnect(JNIEnv *env, jobject bluetoothGatt)
     }
 
     // call disconnect gatt method
-    OIC_LOG(DEBUG, TAG, "CALL API - request disconnect gatt");
+    OIC_LOG(INFO, TAG, "CALL API - disconnect");
     (*env)->CallVoidMethod(env, bluetoothGatt, jni_mid_disconnectGatt);
     if ((*env)->ExceptionCheck(env))
     {
@@ -1947,7 +2071,7 @@ CAResult_t CALEClientDiscoverServices(JNIEnv *env, jobject bluetoothGatt)
     }
 
     // call disconnect gatt method
-    OIC_LOG(DEBUG, TAG, "CALL API - request discovery gatt services");
+    OIC_LOG(INFO, TAG, "CALL API - discoverServices");
     jboolean ret = (*env)->CallBooleanMethod(env, bluetoothGatt, jni_mid_discoverServices);
     if (!ret)
     {
@@ -1963,7 +2087,7 @@ static void CALEWriteCharacteristicThread(void* object)
     VERIFY_NON_NULL_VOID(object, TAG, "object is null");
 
     bool isAttached = false;
-    JNIEnv* env;
+    JNIEnv* env = NULL;
     jint res = (*g_jvm)->GetEnv(g_jvm, (void**) &env, JNI_VERSION_1_6);
     if (JNI_OK != res)
     {
@@ -1993,36 +2117,76 @@ static void CALEWriteCharacteristicThread(void* object)
 
 CAResult_t CALESetValueAndWriteCharacteristic(JNIEnv* env, jobject gatt)
 {
+    OIC_LOG(DEBUG, TAG, "CALESetValueAndWriteCharacteristic");
+
     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)
+    jstring jni_address = CALEClientGetAddressFromGattObj(env, gatt);
+    if (!jni_address)
     {
         CALEClientSendFinish(env, gatt);
         return CA_STATUS_FAILED;
     }
 
-    CAResult_t ret = CALEClientWriteCharacteristicImpl(env, gatt, jni_obj_character);
-    if (CA_STATUS_OK != ret)
+    const char* address = (*env)->GetStringUTFChars(env, jni_address, NULL);
+    if (!address)
     {
         CALEClientSendFinish(env, gatt);
         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)
+    ca_mutex_lock(g_threadSendStateMutex);
+
+    if (CALEClientIsValidState(address, CA_LE_SEND_STATE, STATE_SENDING))
     {
-        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;
+        OIC_LOG(INFO, TAG, "current state is SENDING");
+        (*env)->ReleaseStringUTFChars(env, jni_address, address);
+        ca_mutex_unlock(g_threadSendStateMutex);
+        return CA_STATUS_OK;
+    }
+
+    if (CA_STATUS_OK != CALEClientUpdateDeviceState(address, CA_LE_SEND_STATE,
+                                                    STATE_SENDING))
+    {
+        OIC_LOG(ERROR, TAG, "CALEClientUpdateDeviceState has failed");
+        (*env)->ReleaseStringUTFChars(env, jni_address, address);
+        CALEClientSendFinish(env, gatt);
+        ca_mutex_unlock(g_threadSendStateMutex);
+        return CA_STATUS_FAILED;
+    }
+
+    (*env)->ReleaseStringUTFChars(env, jni_address, address);
+
+    ca_mutex_unlock(g_threadSendStateMutex);
+
+    // send data
+    jobject jni_obj_character = CALEClientCreateGattCharacteristic(env, gatt, g_sendBuffer);
+    if (!jni_obj_character)
+    {
+        CALEClientSendFinish(env, gatt);
+        return CA_STATUS_FAILED;
+    }
+
+    CAResult_t ret = CALEClientWriteCharacteristicImpl(env, gatt, jni_obj_character);
+    if (CA_STATUS_OK != ret)
+    {
+        CALEClientSendFinish(env, gatt);
+        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;
         }
@@ -2031,6 +2195,8 @@ CAResult_t CALESetValueAndWriteCharacteristic(JNIEnv* env, jobject gatt)
     g_isSignalSetFlag = false;
     ca_mutex_unlock(g_threadWriteCharacteristicMutex);
 
+    CALEClientUpdateSendCnt(env);
+
     OIC_LOG(INFO, TAG, "writeCharacteristic success!!");
     return CA_STATUS_OK;
 }
@@ -2080,7 +2246,7 @@ CAResult_t CALEClientWriteCharacteristicImpl(JNIEnv *env, jobject bluetoothGatt,
     }
 
     // call disconnect gatt method
-    OIC_LOG(DEBUG, TAG, "CALL API - request to write gatt characteristic");
+    OIC_LOG(INFO, TAG, "CALL API - writeCharacteristic");
     jboolean ret = (jboolean)(*env)->CallBooleanMethod(env, bluetoothGatt,
                                                        jni_mid_writeCharacteristic,
                                                        gattCharacteristic);
@@ -2134,7 +2300,7 @@ CAResult_t CALEClientReadCharacteristic(JNIEnv *env, jobject bluetoothGatt)
     }
 
     // call disconnect gatt method
-    OIC_LOG(DEBUG, TAG, "CALL API - request to read gatt characteristic");
+    OIC_LOG(INFO, TAG, "CALL API - readCharacteristic");
     jboolean ret = (*env)->CallBooleanMethod(env, bluetoothGatt, jni_mid_readCharacteristic,
                                              jni_obj_GattCharacteristic);
     if (ret)
@@ -2175,15 +2341,16 @@ CAResult_t CALEClientSetCharacteristicNotification(JNIEnv *env, jobject bluetoot
         return CA_STATUS_FAILED;
     }
 
+    OIC_LOG(INFO, TAG, "CALL API - setCharacteristicNotification");
     jboolean ret = (*env)->CallBooleanMethod(env, bluetoothGatt, jni_mid_setNotification,
                                              characteristic, JNI_TRUE);
     if (JNI_TRUE == ret)
     {
-        OIC_LOG(DEBUG, TAG, "CALL API - setCharacteristicNotification success");
+        OIC_LOG(DEBUG, TAG, "setCharacteristicNotification success");
     }
     else
     {
-        OIC_LOG(ERROR, TAG, "CALL API - setCharacteristicNotification has failed");
+        OIC_LOG(ERROR, TAG, "setCharacteristicNotification has failed");
         return CA_STATUS_FAILED;
     }
 
@@ -2383,7 +2550,7 @@ CAResult_t CALEClientCreateUUIDList()
     }
 
     bool isAttached = false;
-    JNIEnv* env;
+    JNIEnv* env = NULL;
     jint res = (*g_jvm)->GetEnv(g_jvm, (void**) &env, JNI_VERSION_1_6);
     if (JNI_OK != res)
     {
@@ -2532,7 +2699,7 @@ CAResult_t CALEClientSetUUIDToDescriptor(JNIEnv *env, jobject bluetoothGatt,
         return CA_STATUS_FAILED;
     }
 
-    OIC_LOG(DEBUG, TAG, "request to write descriptor");
+    OIC_LOG(INFO, TAG, "CALL API - writeDescriptor");
     jboolean jni_ret = (*env)->CallBooleanMethod(env, bluetoothGatt, jni_mid_writeDescriptor,
                                                  jni_obj_descriptor);
     if (jni_ret)
@@ -2574,13 +2741,6 @@ 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;
     }
@@ -2597,6 +2757,7 @@ CAResult_t CALEClientAddScanDeviceToList(JNIEnv *env, jobject device)
     if (!remoteAddress)
     {
         OIC_LOG(ERROR, TAG, "remoteAddress is null");
+        (*env)->DeleteLocalRef(env, jni_remoteAddress);
         ca_mutex_unlock(g_deviceListMutex);
         return CA_STATUS_FAILED;
     }
@@ -2606,9 +2767,10 @@ CAResult_t CALEClientAddScanDeviceToList(JNIEnv *env, jobject device)
         jobject gdevice = (*env)->NewGlobalRef(env, device);
         u_arraylist_add(g_deviceList, gdevice);
         ca_cond_signal(g_deviceDescCond);
-        OIC_LOG_V(DEBUG, TAG, "Added this BT Device[%s] in the List", remoteAddress);
+        OIC_LOG_V(DEBUG, TAG, "Added a new BT Device in deviceList [%s]", remoteAddress);
     }
     (*env)->ReleaseStringUTFChars(env, jni_remoteAddress, remoteAddress);
+    (*env)->DeleteLocalRef(env, jni_remoteAddress);
 
     ca_mutex_unlock(g_deviceListMutex);
 
@@ -2647,19 +2809,22 @@ bool CALEClientIsDeviceInScanDeviceList(JNIEnv *env, const char* remoteAddress)
         if (!setAddress)
         {
             OIC_LOG(ERROR, TAG, "setAddress is null");
+            (*env)->DeleteLocalRef(env, jni_setAddress);
             return true;
         }
 
         if (!strcmp(remoteAddress, setAddress))
         {
             (*env)->ReleaseStringUTFChars(env, jni_setAddress, setAddress);
+            (*env)->DeleteLocalRef(env, jni_setAddress);
             return true;
         }
 
         (*env)->ReleaseStringUTFChars(env, jni_setAddress, setAddress);
+        (*env)->DeleteLocalRef(env, jni_setAddress);
     }
 
-    OIC_LOG(DEBUG, TAG, "there are no the device in list. we can add");
+    OIC_LOG_V(DEBUG, TAG, "[%s] doesn't exist in scanned device list", remoteAddress);
 
     return false;
 }
@@ -2782,7 +2947,7 @@ CAResult_t CALEClientRemoveDeviceInScanDeviceList(JNIEnv *env, jstring address)
 
 CAResult_t CALEClientAddGattobjToList(JNIEnv *env, jobject gatt)
 {
-    OIC_LOG(INFO, TAG, "CALEClientAddGattobjToList");
+    OIC_LOG(DEBUG, TAG, "CALEClientAddGattobjToList");
     VERIFY_NON_NULL(env, TAG, "env is null");
     VERIFY_NON_NULL(gatt, TAG, "gatt is null");
 
@@ -2811,12 +2976,12 @@ CAResult_t CALEClientAddGattobjToList(JNIEnv *env, jobject gatt)
         return CA_STATUS_FAILED;
     }
 
-    OIC_LOG_V(INFO, TAG, "remote address : %s", remoteAddress);
+    OIC_LOG_V(DEBUG, TAG, "remote address : %s", remoteAddress);
     if (!CALEClientIsGattObjInList(env, remoteAddress))
     {
         jobject newGatt = (*env)->NewGlobalRef(env, gatt);
         u_arraylist_add(g_gattObjectList, newGatt);
-        OIC_LOG(INFO, TAG, "Set GATT Object to Array as Element");
+        OIC_LOG(INFO, TAG, "added a newGatt object to gattObjectList");
     }
 
     (*env)->ReleaseStringUTFChars(env, jni_remoteAddress, remoteAddress);
@@ -3116,7 +3281,7 @@ CAResult_t CALEClientRemoveGattObjForAddr(JNIEnv *env, jstring addr)
 
 jstring CALEClientGetLEAddressFromBTDevice(JNIEnv *env, jobject bluetoothDevice)
 {
-    OIC_LOG(DEBUG, TAG, "IN - CALEClientGetLEAddressFromBTDevice");
+    OIC_LOG(DEBUG, TAG, "CALEClientGetLEAddressFromBTDevice");
 
     VERIFY_NON_NULL_RET(env, TAG, "env", NULL);
     VERIFY_NON_NULL_RET(bluetoothDevice, TAG, "bluetoothDevice", NULL);
@@ -3146,21 +3311,27 @@ jstring CALEClientGetLEAddressFromBTDevice(JNIEnv *env, jobject bluetoothDevice)
         return NULL;
     }
 
+    ca_mutex_lock(g_gattObjectMutex);
+
     size_t length = u_arraylist_length(g_gattObjectList);
+    OIC_LOG_V(DEBUG, TAG, "length of gattObjectList : %d", length);
+    OIC_LOG_V(DEBUG, TAG, "targetAddress : %s", targetAddress);
+
     for (size_t index = 0; index < length; index++)
     {
         jobject jarrayObj = (jobject) u_arraylist_get(g_gattObjectList, index);
         if (!jarrayObj)
         {
+            ca_mutex_unlock(g_gattObjectMutex);
             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)
         {
+            ca_mutex_unlock(g_gattObjectMutex);
             OIC_LOG(ERROR, TAG, "jni_obj_device is null");
             (*env)->ReleaseStringUTFChars(env, jni_btTargetAddress, targetAddress);
             return NULL;
@@ -3169,6 +3340,7 @@ jstring CALEClientGetLEAddressFromBTDevice(JNIEnv *env, jobject bluetoothDevice)
         jstring jni_btAddress = CALEGetAddressFromBTDevice(env, jni_obj_device);
         if (!jni_btAddress)
         {
+            ca_mutex_unlock(g_gattObjectMutex);
             OIC_LOG(ERROR, TAG, "CALEGetAddressFromBTDevice has failed");
             (*env)->ReleaseStringUTFChars(env, jni_btTargetAddress, targetAddress);
             return NULL;
@@ -3177,13 +3349,13 @@ jstring CALEClientGetLEAddressFromBTDevice(JNIEnv *env, jobject bluetoothDevice)
         const char* btAddress = (*env)->GetStringUTFChars(env, jni_btAddress, NULL);
         if (!btAddress)
         {
+            ca_mutex_unlock(g_gattObjectMutex);
             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);
+        OIC_LOG_V(DEBUG, TAG, "btAddress : %s (idx: %d)", btAddress, index);
         if (!strcmp(targetAddress, btAddress))
         {
             OIC_LOG(DEBUG, TAG, "Found Gatt object from BT device");
@@ -3194,6 +3366,7 @@ jstring CALEClientGetLEAddressFromBTDevice(JNIEnv *env, jobject bluetoothDevice)
             {
                 OIC_LOG(ERROR, TAG, "jni_LEAddress is null");
             }
+            ca_mutex_unlock(g_gattObjectMutex);
             (*env)->ReleaseStringUTFChars(env, jni_btTargetAddress, targetAddress);
             (*env)->ReleaseStringUTFChars(env, jni_btAddress, btAddress);
             (*env)->DeleteLocalRef(env, jni_btAddress);
@@ -3204,8 +3377,10 @@ jstring CALEClientGetLEAddressFromBTDevice(JNIEnv *env, jobject bluetoothDevice)
         (*env)->DeleteLocalRef(env, jni_btAddress);
         (*env)->DeleteLocalRef(env, jni_obj_device);
     }
+    ca_mutex_unlock(g_gattObjectMutex);
 
-    OIC_LOG(DEBUG, TAG, "OUT - CALEClientGetLEAddressFromBTDevice");
+    (*env)->ReleaseStringUTFChars(env, jni_btTargetAddress, targetAddress);
+    OIC_LOG_V(DEBUG, TAG, "[%s] doesn't exist in gattObjectList", targetAddress);
     return NULL;
 }
 
@@ -3213,48 +3388,24 @@ jstring CALEClientGetLEAddressFromBTDevice(JNIEnv *env, jobject bluetoothDevice)
  * BT State List
  */
 
-CAResult_t CALEClientUpdateDeviceState(const char* address, uint32_t connectedState,
-                                       uint16_t notificationState, uint16_t sendState)
+CAResult_t CALEClientUpdateDeviceState(const char* address, uint16_t state_type,
+                                       uint16_t target_state)
 {
     VERIFY_NON_NULL(address, TAG, "address is null");
-
-    CALEState_t *newstate = (CALEState_t*) OICCalloc(1, sizeof(*newstate));
-    if (!newstate)
-    {
-        OIC_LOG(ERROR, TAG, "out of memory");
-        return CA_MEMORY_ALLOC_FAILED;
-    }
-
-    if (strlen(address) > CA_MACADDR_SIZE)
-    {
-        OIC_LOG(ERROR, TAG, "address is not proper");
-        OICFree(newstate);
-        return CA_STATUS_FAILED;
-    }
-
-    OICStrcpy(newstate->address, sizeof(newstate->address), address);
-    newstate->connectedState = connectedState;
-    newstate->notificationState = notificationState;
-    newstate->sendState = sendState;
-    return CALEClientAddDeviceStateToList(newstate);
-}
-
-CAResult_t CALEClientAddDeviceStateToList(CALEState_t* state)
-{
-    VERIFY_NON_NULL(state, TAG, "state is null");
-
-    ca_mutex_lock(g_deviceStateListMutex);
+    VERIFY_NON_NULL(address, TAG, "state_type is null");
+    VERIFY_NON_NULL(address, TAG, "target_state is null");
 
     if (!g_deviceStateList)
     {
         OIC_LOG(ERROR, TAG, "gdevice_list is null");
-        ca_mutex_unlock(g_deviceStateListMutex);
         return CA_STATUS_FAILED;
     }
 
-    if (CALEClientIsDeviceInList(state->address))
+    ca_mutex_lock(g_deviceStateListMutex);
+
+    if (CALEClientIsDeviceInList(address))
     {
-        CALEState_t* curState = CALEClientGetStateInfo(state->address);
+        CALEState_t* curState = CALEClientGetStateInfo(address);
         if(!curState)
         {
             OIC_LOG(ERROR, TAG, "curState is null");
@@ -3262,27 +3413,61 @@ CAResult_t CALEClientAddDeviceStateToList(CALEState_t* state)
             return CA_STATUS_FAILED;
         }
 
-        if (STATE_CHARACTER_NO_CHANGE == state->notificationState)
+        switch(state_type)
+        {
+            case CA_LE_CONNECTION_STATE:
+                curState->connectedState = target_state;
+                break;
+            case CA_LE_SEND_STATE:
+                curState->sendState = target_state;
+                break;
+            default:
+                break;
+        }
+        OIC_LOG_V(INFO, TAG, "update state - addr : %s, conn : %d, send : %d, ACFlag : %d",
+                  curState->address, curState->connectedState, curState->sendState,
+                  curState->autoConnectFlag);
+    }
+    else /** state is added newly **/
+    {
+        if (strlen(address) > CA_MACADDR_SIZE)
         {
-            state->notificationState = curState->notificationState;
+            OIC_LOG(ERROR, TAG, "address is not proper");
+            ca_mutex_unlock(g_deviceStateListMutex);
+            return CA_STATUS_INVALID_PARAM;
         }
-        state->autoConnectFlag = curState->autoConnectFlag;
 
-        // delete previous state for update new state
-        CAResult_t res = CALEClientRemoveDeviceState(state->address);
-        if (CA_STATUS_OK != res)
+        CALEState_t *newstate = (CALEState_t*) OICCalloc(1, sizeof(*newstate));
+        if (!newstate)
         {
-            OIC_LOG(ERROR, TAG, "CALEClientRemoveDeviceState has failed");
+            OIC_LOG(ERROR, TAG, "out of memory");
             ca_mutex_unlock(g_deviceStateListMutex);
-            return res;
+            return CA_MEMORY_ALLOC_FAILED;
         }
-    }
-    u_arraylist_add(g_deviceStateList, state); // update new state
-    OIC_LOG_V(INFO, TAG, "Set State Info to List : %d, %d, %s, %d",
-              state->connectedState, state->notificationState,
-              state->address, state->autoConnectFlag);
 
+        OICStrcpy(newstate->address, sizeof(newstate->address), address);
+
+        switch(state_type)
+        {
+            case CA_LE_CONNECTION_STATE:
+                newstate->connectedState = target_state;
+                newstate->sendState = STATE_SEND_NONE;
+                break;
+            case CA_LE_SEND_STATE:
+                newstate->connectedState = STATE_DISCONNECTED;
+                newstate->sendState = target_state;
+                break;
+            default:
+                break;
+        }
+        OIC_LOG_V(INFO, TAG, "add a new state to List - addr : %s, "
+                  "conn : %d, send : %d, ACFlag : %d",
+                  newstate->address, newstate->connectedState, newstate->sendState,
+                  newstate->autoConnectFlag);
+        u_arraylist_add(g_deviceStateList, newstate); // update new state
+    }
     ca_mutex_unlock(g_deviceStateListMutex);
+
     return CA_STATUS_OK;
 }
 
@@ -3377,7 +3562,6 @@ CAResult_t CALEClientResetDeviceStateForAll()
         // 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);
@@ -3428,7 +3612,6 @@ CAResult_t CALEClientRemoveDeviceState(const char* remoteAddress)
 
 CALEState_t* CALEClientGetStateInfo(const char* remoteAddress)
 {
-    OIC_LOG(DEBUG, TAG, "CALEClientGetStateInfo");
     VERIFY_NON_NULL_RET(remoteAddress, TAG, "remoteAddress is null", NULL);
 
     if (!g_deviceStateList)
@@ -3438,7 +3621,8 @@ CALEState_t* CALEClientGetStateInfo(const char* remoteAddress)
     }
 
     uint32_t length = u_arraylist_length(g_deviceStateList);
-    OIC_LOG_V(DEBUG, TAG, "CALEClientGetStateInfo : %d", length);
+    OIC_LOG_V(DEBUG, TAG, "length of deviceStateList : %d", length);
+    OIC_LOG_V(DEBUG, TAG, "target address : %s", remoteAddress);
 
     for (uint32_t index = 0; index < length; index++)
     {
@@ -3449,21 +3633,24 @@ 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);
+        OIC_LOG_V(DEBUG, TAG, "state address : %s (idx: %d)", state->address, index);
 
         if (!strcmp(state->address, remoteAddress))
         {
-            OIC_LOG_V(DEBUG, TAG, "get state : %s", remoteAddress);
+            OIC_LOG(DEBUG, TAG, "found state");
             return state;
         }
     }
+
+    OIC_LOG_V(DEBUG, TAG, "[%s] doesn't exist in deviceStateList", remoteAddress);
     return NULL;
 }
 
-bool CALEClientIsConnectedDevice(const char* remoteAddress)
+bool CALEClientIsValidState(const char* remoteAddress, uint16_t state_type,
+                             uint16_t target_state)
 {
-    OIC_LOG(DEBUG, TAG, "CALEClientIsConnectedDevice");
+    OIC_LOG_V(DEBUG, TAG, "CALEClientIsValidState : type[%d], target state[%d]",
+              state_type, target_state);
     VERIFY_NON_NULL_RET(remoteAddress, TAG, "remoteAddress is null", false);
 
     ca_mutex_lock(g_deviceStateListMutex);
@@ -3474,74 +3661,36 @@ bool CALEClientIsConnectedDevice(const char* remoteAddress)
         return false;
     }
 
-    uint32_t length = u_arraylist_length(g_deviceStateList);
-    for (uint32_t index = 0; index < length; index++)
+    CALEState_t* state = CALEClientGetStateInfo(remoteAddress);
+    if (NULL == state)
     {
-        CALEState_t* state = (CALEState_t*) u_arraylist_get(g_deviceStateList, index);
-        if (!state)
-        {
-            OIC_LOG(ERROR, TAG, "CALEState_t object is null");
-            continue;
-        }
-
-        if (!strcmp(state->address, remoteAddress))
-        {
-            OIC_LOG(DEBUG, TAG, "check whether it is connected or not");
-
-            if (STATE_CONNECTED == state->connectedState)
-            {
-                ca_mutex_unlock(g_deviceStateListMutex);
-                return true;
-            }
-            else
-            {
-                ca_mutex_unlock(g_deviceStateListMutex);
-                return false;
-            }
-        }
+        OIC_LOG(ERROR, TAG, "state is null");
+        ca_mutex_unlock(g_deviceStateListMutex);
+        return false;
     }
-    ca_mutex_unlock(g_deviceStateListMutex);
-    return false;
-}
 
-bool CALEClientIsSetCharacteristic(const char* remoteAddress)
-{
-    OIC_LOG(DEBUG, TAG, "CALEClientIsSetCharacteristic");
-    VERIFY_NON_NULL_RET(remoteAddress, TAG, "remoteAddress is null", false);
+    uint16_t curValue = 0;
+    switch(state_type)
+    {
+        case CA_LE_CONNECTION_STATE:
+            curValue = state->connectedState;
+            break;
+        case CA_LE_SEND_STATE:
+            curValue = state->sendState;
+            break;
+        default:
+            break;
+    }
 
-    ca_mutex_lock(g_deviceStateListMutex);
-    if (!g_deviceStateList)
+    if (target_state == curValue)
     {
-        OIC_LOG(ERROR, TAG, "g_deviceStateList is null");
         ca_mutex_unlock(g_deviceStateListMutex);
-        return false;
+        return true;
     }
-
-    uint32_t length = u_arraylist_length(g_deviceStateList);
-    for (uint32_t index = 0; index < length; index++)
+    else
     {
-        CALEState_t* state = (CALEState_t*) u_arraylist_get(g_deviceStateList, index);
-        if (!state)
-        {
-            OIC_LOG(ERROR, TAG, "CALEState_t object is null");
-            continue;
-        }
-
-        if (!strcmp(state->address, remoteAddress))
-        {
-            OIC_LOG_V(DEBUG, TAG, "check whether it was set or not:%d", state->notificationState);
-
-            if (STATE_CHARACTER_SET == state->notificationState)
-            {
-                ca_mutex_unlock(g_deviceStateListMutex);
-                return true;
-            }
-            else
-            {
-                ca_mutex_unlock(g_deviceStateListMutex);
-                return false;
-            }
-        }
+        ca_mutex_unlock(g_deviceStateListMutex);
+        return false;
     }
 
     ca_mutex_unlock(g_deviceStateListMutex);
@@ -3690,30 +3839,40 @@ CAResult_t CALEClientInitGattMutexVaraibles()
         }
     }
 
-    if (NULL == g_scanMutex)
+    if (NULL == g_threadWriteCharacteristicMutex)
     {
-        g_scanMutex = ca_mutex_new();
-        if (NULL == g_scanMutex)
+        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_threadWriteCharacteristicMutex)
+    if (NULL == g_deviceScanRetryDelayMutex)
     {
-        g_threadWriteCharacteristicMutex = ca_mutex_new();
-        if (NULL == g_threadWriteCharacteristicMutex)
+        g_deviceScanRetryDelayMutex = ca_mutex_new();
+        if (NULL == g_deviceScanRetryDelayMutex)
         {
             OIC_LOG(ERROR, TAG, "ca_mutex_new has failed");
             return CA_STATUS_FAILED;
         }
     }
 
-    if (NULL == g_deviceScanRetryDelayMutex)
+    if (NULL == g_threadSendStateMutex)
     {
-        g_deviceScanRetryDelayMutex = ca_mutex_new();
-        if (NULL == g_deviceScanRetryDelayMutex)
+        g_threadSendStateMutex = ca_mutex_new();
+        if (NULL == g_threadSendStateMutex)
+        {
+            OIC_LOG(ERROR, TAG, "ca_mutex_new has failed");
+            return CA_STATUS_FAILED;
+        }
+    }
+
+    if (NULL == g_threadScanIntervalMutex)
+    {
+        g_threadScanIntervalMutex = ca_mutex_new();
+        if (NULL == g_threadScanIntervalMutex)
         {
             OIC_LOG(ERROR, TAG, "ca_mutex_new has failed");
             return CA_STATUS_FAILED;
@@ -3743,14 +3902,17 @@ void CALEClientTerminateGattMutexVariables()
     ca_mutex_free(g_SendFinishMutex);
     g_SendFinishMutex = NULL;
 
-    ca_mutex_free(g_scanMutex);
-    g_scanMutex = NULL;
-
     ca_mutex_free(g_threadWriteCharacteristicMutex);
     g_threadWriteCharacteristicMutex = NULL;
 
     ca_mutex_free(g_deviceScanRetryDelayMutex);
     g_deviceScanRetryDelayMutex = NULL;
+
+    ca_mutex_free(g_threadSendStateMutex);
+    g_threadSendStateMutex = NULL;
+
+    ca_mutex_free(g_threadScanIntervalMutex);
+    g_threadScanIntervalMutex = NULL;
 }
 
 void CALEClientSetSendFinishFlag(bool flag)
@@ -3784,10 +3946,15 @@ CAResult_t CAStartLEGattClient()
         g_threadWriteCharacteristicCond = ca_cond_new();
     }
 
-    CAResult_t ret = CALEClientStartScan();
+    if (!g_threadScanIntervalCond)
+    {
+        g_threadScanIntervalCond = ca_cond_new();
+    }
+
+    CAResult_t ret = CALEClientStartScanWithInterval();
     if (CA_STATUS_OK != ret)
     {
-        OIC_LOG(ERROR, TAG, "CALEClientStartScan has failed");
+        OIC_LOG(ERROR, TAG, "CALEClientStartScanWithInterval has failed");
         return ret;
     }
 
@@ -3806,7 +3973,7 @@ void CAStopLEGattClient()
     }
 
     bool isAttached = false;
-    JNIEnv* env;
+    JNIEnv* env = NULL;
     jint res = (*g_jvm)->GetEnv(g_jvm, (void**) &env, JNI_VERSION_1_6);
     if (JNI_OK != res)
     {
@@ -3827,11 +3994,7 @@ void CAStopLEGattClient()
         OIC_LOG(ERROR, TAG, "CALEClientDisconnectAll has failed");
     }
 
-    ret = CALEClientStopScan();
-    if(CA_STATUS_OK != ret)
-    {
-        OIC_LOG(ERROR, TAG, "CALEClientStopScan has failed");
-    }
+    CALEClientStopScanWithInterval();
 
     ca_mutex_lock(g_threadMutex);
     OIC_LOG(DEBUG, TAG, "signal - connection cond");
@@ -3849,15 +4012,22 @@ void CAStopLEGattClient()
     ca_cond_signal(g_deviceScanRetryDelayCond);
     ca_mutex_unlock(g_deviceScanRetryDelayMutex);
 
+    ca_mutex_lock(g_threadScanIntervalMutex);
+    OIC_LOG(DEBUG, TAG, "signal - delay cond");
+    ca_cond_signal(g_threadScanIntervalCond);
+    ca_mutex_unlock(g_threadScanIntervalMutex);
+
     ca_cond_free(g_deviceDescCond);
     ca_cond_free(g_threadCond);
     ca_cond_free(g_threadWriteCharacteristicCond);
     ca_cond_free(g_deviceScanRetryDelayCond);
+    ca_cond_free(g_threadScanIntervalCond);
 
     g_deviceDescCond = NULL;
     g_threadCond = NULL;
     g_threadWriteCharacteristicCond = NULL;
     g_deviceScanRetryDelayCond = NULL;
+    g_threadScanIntervalCond = NULL;
 
     if (isAttached)
     {
@@ -3880,9 +4050,9 @@ void CATerminateLEGattClient()
     CALEClientTerminate();
 }
 
-CAResult_t  CAUpdateCharacteristicsToGattServer(const char *remoteAddress, const uint8_t  *data,
-                                                uint32_t dataLen, CALETransferType_t type,
-                                                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");
@@ -3963,39 +4133,6 @@ Java_org_iotivity_ca_CaLeClientInterface_caLeScanCallback(JNIEnv *env, jobject o
     }
 }
 
-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 = CAGetJNIMethodID(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_ca_jar_caleinterface
  * Method:    CALeGattConnectionStateChangeCallback
@@ -4003,157 +4140,103 @@ static jstring CALEClientGetAddressFromGatt(JNIEnv *env, jobject gatt)
  */
 JNIEXPORT void JNICALL
 Java_org_iotivity_ca_CaLeClientInterface_caLeGattConnectionStateChangeCallback(JNIEnv *env,
-                                                                                jobject obj,
-                                                                                jobject gatt,
-                                                                                jint status,
-                                                                                jint newstate)
+                                                                               jobject obj,
+                                                                               jobject gatt,
+                                                                               jint status,
+                                                                               jint newstate)
 {
-    OIC_LOG_V(DEBUG, TAG, "CALeGattConnectionStateChangeCallback - status %d, newstate %d", status,
-            newstate);
+    OIC_LOG_V(INFO, 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");
 
     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)
     {
-        jstring jni_address = CALEClientGetAddressFromGattObj(env, gatt);
-        if (!jni_address)
-        {
-            goto error_exit;
-        }
+        OIC_LOG(ERROR, TAG, "CALEClientGetAddressFromGattObj has failed");
+        goto error_exit;
+    }
 
-        const char* address = (*env)->GetStringUTFChars(env, jni_address, NULL);
-        if (address)
+    const char* address = (*env)->GetStringUTFChars(env, jni_address, NULL);
+    if (!address)
+    {
+        OIC_LOG(ERROR, TAG, "address is null");
+        goto error_exit;
+    }
+    OIC_LOG_V(DEBUG, TAG, "CALeGattConnectionStateChangeCallback - address [%s]", address);
+
+    if (state_connected == newstate)
+    {
+        OIC_LOG(DEBUG, TAG, "LE is connected");
+        if (GATT_SUCCESS == status)
         {
-            CAResult_t res = CALEClientUpdateDeviceState(address, STATE_CONNECTED,
-                                                         STATE_CHARACTER_NO_CHANGE,
-                                                         STATE_SEND_NONE);
+            CAResult_t res = CALEClientUpdateDeviceState(address,
+                                                         CA_LE_CONNECTION_STATE,
+                                                         STATE_CONNECTED);
+            (*env)->ReleaseStringUTFChars(env, jni_address, address);
             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 = CALEClientAddGattobjToList(env, gatt);
+            if (CA_STATUS_OK != res)
+            {
+                OIC_LOG(ERROR, TAG, "CALEClientAddGattobjToList has failed");
+                goto error_exit;
+            }
 
-        CAResult_t res = CALEClientAddGattobjToList(env, gatt);
-        if (CA_STATUS_OK != res)
-        {
-            OIC_LOG(ERROR, TAG, "CALEClientAddGattobjToList has failed");
-            goto error_exit;
+            res = CALEClientDiscoverServices(env, gatt);
+            if (CA_STATUS_OK != res)
+            {
+                OIC_LOG(ERROR, TAG, "CALEClientDiscoverServices has failed");
+                goto error_exit;
+            }
         }
-
-        res = CALEClientDiscoverServices(env, gatt);
-        if (CA_STATUS_OK != res)
+        else
         {
-            OIC_LOG(ERROR, TAG, "CALEClientDiscoverServices has failed");
-            goto error_exit;
+            OIC_LOG(INFO, TAG, "unknown status");
+            (*env)->ReleaseStringUTFChars(env, jni_address, address);
         }
     }
-    else if (state_disconnected == newstate) // le disconnected
+    else // STATE_DISCONNECTED == newstate
     {
-        jstring jni_address = CALEClientGetAddressFromGattObj(env, gatt);
-        if (!jni_address)
-        {
-            OIC_LOG(ERROR, TAG, "CALEClientGetAddressFromGattObj has failed");
-            goto error_exit;
-        }
+        OIC_LOG(DEBUG, TAG, "LE is disconnected");
 
-        const char* address = (*env)->GetStringUTFChars(env, jni_address, NULL);
-        if (address)
+        CAResult_t res = CALEClientUpdateDeviceState(address,
+                                                     CA_LE_CONNECTION_STATE,
+                                                     STATE_DISCONNECTED);
+        (*env)->ReleaseStringUTFChars(env, jni_address, address);
+        if (CA_STATUS_OK != res)
         {
-            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);
+            OIC_LOG(ERROR, TAG, "CALEClientUpdateDeviceState has failed");
+            goto error_exit;
         }
 
-        CAResult_t res = CALEClientGattClose(env, gatt);
+        res = CALEClientGattClose(env, gatt);
         if (CA_STATUS_OK != res)
         {
             OIC_LOG(ERROR, TAG, "CALEClientGattClose has failed");
         }
 
-        if (gatt_success == status)
-        {
-            // that state is a general reason to disconnect BLE.
-            // its means manual disconnected message from BT platform.
-            // in this case Scanning has to start again and clean previous data.
-            CAResult_t res = CALEClientStartScan();
-            if (CA_STATUS_OK != res)
-            {
-                if (CA_ADAPTER_NOT_ENABLED == res)
-                {
-                    // scan will be started with start server when adapter is enabled
-                    OIC_LOG(INFO, TAG, "Adapter was disabled");
-                }
-                else
-                {
-                    OIC_LOG(ERROR, TAG, "CALEClientStartScan has failed");
-                    goto error_exit;
-                }
-            }
-        }
-        else if (GATT_ERROR == status)
+        if (CALECheckConnectionStateValue(status))
         {
-            // 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;
-            }
-
-            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;
+            // 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
         {
-            if (CALECheckConnectionStateValue(status))
-            {
-                // 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;
-            }
+            // other reason except for gatt_success is expected to running
+            // background connection in BT platform.
+            OIC_LOG(INFO, TAG, "unknown status or manual disconnected state");
+            CALEClientUpdateSendCnt(env);
+            return;
         }
 
         if (g_sendBuffer)
@@ -4166,7 +4249,6 @@ Java_org_iotivity_ca_CaLeClientInterface_caLeGattConnectionStateChangeCallback(J
 
     // error label.
 error_exit:
-
     CALEClientSendFinish(env, gatt);
     return;
 }
@@ -4178,16 +4260,16 @@ error_exit:
  */
 JNIEXPORT void JNICALL
 Java_org_iotivity_ca_CaLeClientInterface_caLeGattServicesDiscoveredCallback(JNIEnv *env,
-                                                                             jobject obj,
-                                                                             jobject gatt,
-                                                                             jint status)
+                                                                            jobject obj,
+                                                                            jobject gatt,
+                                                                            jint status)
 {
-    OIC_LOG_V(DEBUG, TAG, "CALeGattServicesDiscoveredCallback - status %d: ", status);
+    OIC_LOG_V(INFO, 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
+    if (GATT_SUCCESS != status) // discovery error
     {
         CALEClientSendFinish(env, gatt);
         return;
@@ -4207,55 +4289,48 @@ Java_org_iotivity_ca_CaLeClientInterface_caLeGattServicesDiscoveredCallback(JNIE
         return;
     }
 
-    if (!CALEClientIsSetCharacteristic(address))
+    jstring jni_uuid = (*env)->NewStringUTF(env, OIC_GATT_CHARACTERISTIC_RESPONSE_UUID);
+    if (!jni_uuid)
     {
-        jstring jni_uuid = (*env)->NewStringUTF(env, OIC_GATT_CHARACTERISTIC_RESPONSE_UUID);
-        if (!jni_uuid)
-        {
-            OIC_LOG(ERROR, TAG, "jni_uuid is null");
-            goto error_exit;
-        }
+        OIC_LOG(ERROR, TAG, "jni_uuid is null");
+        goto error_exit;
+    }
 
-        jobject jni_obj_GattCharacteristic = CALEClientGetGattService(env, gatt, jni_uuid);
-        if (!jni_obj_GattCharacteristic)
-        {
-            OIC_LOG(ERROR, TAG, "jni_obj_GattCharacteristic is null");
-            goto error_exit;
-        }
+    jobject jni_obj_GattCharacteristic = CALEClientGetGattService(env, gatt, jni_uuid);
+    if (!jni_obj_GattCharacteristic)
+    {
+        OIC_LOG(ERROR, TAG, "jni_obj_GattCharacteristic is null");
+        goto error_exit;
+    }
 
-        CAResult_t res = CALEClientSetCharacteristicNotification(env, gatt,
-                                                                 jni_obj_GattCharacteristic);
-        if (CA_STATUS_OK != res)
-        {
-            OIC_LOG(ERROR, TAG, "CALEClientSetCharacteristicNotification has failed");
-            goto error_exit;
-        }
+    CAResult_t res = CALEClientSetCharacteristicNotification(env, gatt,
+                                                             jni_obj_GattCharacteristic);
+    if (CA_STATUS_OK != res)
+    {
+        OIC_LOG(ERROR, TAG, "CALEClientSetCharacteristicNotification has failed");
+        goto error_exit;
+    }
 
-        res = CALEClientSetUUIDToDescriptor(env, gatt, jni_obj_GattCharacteristic);
+    res = CALEClientSetUUIDToDescriptor(env, gatt, jni_obj_GattCharacteristic);
+    if (CA_STATUS_OK != res)
+    {
+        OIC_LOG_V(INFO, TAG, "Descriptor is not found : %d", res);
+
+        res = CALEClientSetFlagToState(env, jni_address, CA_LE_DESCRIPTOR_FOUND, JNI_FALSE);
         if (CA_STATUS_OK != res)
         {
-            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;
-                }
-            }
+            OIC_LOG(ERROR, TAG, "CALEClientSetFlagToState has failed");
+            goto error_exit;
         }
 
-        res = CALEClientUpdateDeviceState(address, STATE_CONNECTED, STATE_CHARACTER_SET,
-                                          STATE_SEND_NONE);
+        res = CALEClientUpdateDeviceState(address, CA_LE_CONNECTION_STATE,
+                                          STATE_SERVICE_CONNECTED);
         if (CA_STATUS_OK != res)
         {
             OIC_LOG(ERROR, TAG, "CALEClientUpdateDeviceState has failed");
             goto error_exit;
         }
-    }
-    else
-    {
+
         if (g_sendBuffer)
         {
             CAResult_t res = CALEClientWriteCharacteristic(env, gatt);
@@ -4266,6 +4341,16 @@ Java_org_iotivity_ca_CaLeClientInterface_caLeGattServicesDiscoveredCallback(JNIE
             }
         }
     }
+    else
+    {
+        res = CALEClientSetFlagToState(env, jni_address, CA_LE_DESCRIPTOR_FOUND, JNI_TRUE);
+        if (CA_STATUS_OK != res)
+        {
+            OIC_LOG(ERROR, TAG, "CALEClientSetFlagToState has failed");
+            goto error_exit;
+        }
+    }
+
     OIC_LOG(INFO, TAG, "ServicesDiscovery is successful");
     (*env)->ReleaseStringUTFChars(env, jni_address, address);
     return;
@@ -4285,10 +4370,9 @@ error_exit:
  */
 JNIEXPORT void JNICALL
 Java_org_iotivity_ca_CaLeClientInterface_caLeGattCharacteristicWriteCallback(
-        JNIEnv *env, jobject obj, jobject gatt, jbyteArray data,
-        jint status)
+        JNIEnv *env, jobject obj, jobject gatt, jbyteArray data, jint status)
 {
-    OIC_LOG_V(DEBUG, TAG, "CALeGattCharacteristicWriteCallback - status : %d", status);
+    OIC_LOG_V(INFO, 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");
@@ -4306,8 +4390,7 @@ Java_org_iotivity_ca_CaLeClientInterface_caLeGattCharacteristicWriteCallback(
         goto error_exit;
     }
 
-    jint gatt_success = CALEGetConstantsValue(env, CLASSPATH_BT_GATT, "GATT_SUCCESS");
-    if (gatt_success != status) // error case
+    if (GATT_SUCCESS != status) // error case
     {
         OIC_LOG(ERROR, TAG, "send failure");
 
@@ -4321,9 +4404,8 @@ Java_org_iotivity_ca_CaLeClientInterface_caLeGattCharacteristicWriteCallback(
             ca_cond_signal(g_threadWriteCharacteristicCond);
             ca_mutex_unlock(g_threadWriteCharacteristicMutex);
 
-            CAResult_t res = CALEClientUpdateDeviceState(address, STATE_CONNECTED,
-                                                         STATE_CHARACTER_SET,
-                                                         STATE_SEND_FAILED);
+            CAResult_t res = CALEClientUpdateDeviceState(address, CA_LE_SEND_STATE,
+                                                         STATE_SEND_FAIL);
             if (CA_STATUS_OK != res)
             {
                 OIC_LOG(ERROR, TAG, "CALEClientUpdateDeviceState has failed");
@@ -4335,14 +4417,14 @@ Java_org_iotivity_ca_CaLeClientInterface_caLeGattCharacteristicWriteCallback(
                 g_clientErrorCallback(address, data, length, CA_SEND_FAILED);
             }
 
-            CALEClientSendFinish(env, gatt);
+            (*env)->ReleaseStringUTFChars(env, jni_address, address);
             goto error_exit;
         }
     }
     else
     {
         OIC_LOG(DEBUG, TAG, "send success");
-        CAResult_t res = CALEClientUpdateDeviceState(address, STATE_CONNECTED, STATE_CHARACTER_SET,
+        CAResult_t res = CALEClientUpdateDeviceState(address, CA_LE_SEND_STATE,
                                                      STATE_SEND_SUCCESS);
         if (CA_STATUS_OK != res)
         {
@@ -4354,8 +4436,6 @@ Java_org_iotivity_ca_CaLeClientInterface_caLeGattCharacteristicWriteCallback(
         g_isSignalSetFlag = true;
         ca_cond_signal(g_threadWriteCharacteristicCond);
         ca_mutex_unlock(g_threadWriteCharacteristicMutex);
-
-        CALEClientUpdateSendCnt(env);
     }
 
     (*env)->ReleaseStringUTFChars(env, jni_address, address);
@@ -4377,7 +4457,7 @@ JNIEXPORT void JNICALL
 Java_org_iotivity_ca_CaLeClientInterface_caLeGattCharacteristicChangedCallback(
         JNIEnv *env, jobject obj, jobject gatt, jbyteArray data)
 {
-    OIC_LOG(DEBUG, TAG, "CALeGattCharacteristicChangedCallback");
+    OIC_LOG(INFO, 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");
@@ -4421,10 +4501,9 @@ Java_org_iotivity_ca_CaLeClientInterface_caLeGattCharacteristicChangedCallback(
     OIC_LOG_V(DEBUG, TAG, "CALeGattCharacteristicChangedCallback - data. : %p, %d",
               receivedData, length);
 
-    ca_mutex_lock(g_bleServerBDAddressMutex);
     uint32_t sentLength = 0;
-    g_CABLEClientDataReceivedCallback(address, receivedData, length,
-                                      &sentLength);
+    ca_mutex_lock(g_bleServerBDAddressMutex);
+    g_CABLEClientDataReceivedCallback(address, receivedData, length, &sentLength);
     ca_mutex_unlock(g_bleServerBDAddressMutex);
 
     (*env)->ReleaseStringUTFChars(env, jni_address, address);
@@ -4440,14 +4519,34 @@ Java_org_iotivity_ca_CaLeClientInterface_caLeGattDescriptorWriteCallback(JNIEnv
                                                                          jobject gatt,
                                                                          jint status)
 {
-    OIC_LOG_V(DEBUG, TAG, "CALeGattDescriptorWriteCallback - status %d: ", status);
+    OIC_LOG_V(INFO, 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");
 
-    jint gatt_success = CALEGetConstantsValue(env, CLASSPATH_BT_GATT, "GATT_SUCCESS");
-    if (gatt_success != status) // error
+    if (GATT_SUCCESS != status) // error
+    {
+        goto error_exit;
+    }
+
+    jstring jni_address = CALEClientGetAddressFromGattObj(env, gatt);
+    if (!jni_address)
+    {
+        goto error_exit;
+    }
+
+    const char* address = (*env)->GetStringUTFChars(env, jni_address, NULL);
+    if (!address)
+    {
+        goto error_exit;
+    }
+
+    CAResult_t res = CALEClientUpdateDeviceState(address, CA_LE_CONNECTION_STATE,
+                                                 STATE_SERVICE_CONNECTED);
+    (*env)->ReleaseStringUTFChars(env, jni_address, address);
+    if (CA_STATUS_OK != res)
     {
+        OIC_LOG(ERROR, TAG, "CALEClientUpdateDeviceState has failed");
         goto error_exit;
     }