Update snapshot(2018-01-04)
[platform/upstream/iotivity.git] / resource / csdk / connectivity / src / bt_le_adapter / android / caleclient.c
index 94d4f8a..87a2d6e 100644 (file)
@@ -23,6 +23,7 @@
 #include <jni.h>
 #include <unistd.h>
 
+#include "calestate.h"
 #include "caleclient.h"
 #include "caleserver.h"
 #include "caleutils.h"
 #include "oic_malloc.h"
 #include "oic_string.h"
 #include "cathreadpool.h" /* for thread pool */
-#include "camutex.h"
+#include "octhread.h"
 #include "uarraylist.h"
 #include "org_iotivity_ca_CaLeClientInterface.h"
 
-#define TAG PCF("OIC_CA_LE_CLIENT")
+//#define TAG PCF("OIC_CA_LE_CLIENT")
+#define TAG BLE_CLIENT_TAG
 
 #define MICROSECS_PER_SEC 1000000
 #define WAIT_TIME_WRITE_CHARACTERISTIC 10 * MICROSECS_PER_SEC
 #define GATT_REQUEST_NOT_SUPPORTED          6
 #define GATT_WRITE_NOT_PERMITTED            3
 
+// samsung
+#define BLE_SCAN_API_LEVEL (100) //(21)
+#define BLE_MIN_API_LEVEL  (18)
+#define HIDDEN_API
+
 static ca_thread_pool_t g_threadPoolHandle = NULL;
 
 JavaVM *g_jvm;
@@ -75,39 +82,45 @@ 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 = NULL;
-static ca_mutex g_threadMutex = NULL;
-static ca_cond g_threadCond = NULL;
-static ca_cond g_deviceDescCond = NULL;
-
-static ca_mutex g_threadSendMutex = NULL;
-static ca_mutex g_threadWriteCharacteristicMutex = NULL;
-static ca_cond g_threadWriteCharacteristicCond = NULL;
+static oc_mutex g_SendFinishMutex = NULL;
+static oc_mutex g_threadMutex = NULL;
+static oc_cond g_threadCond = NULL;
+static oc_cond g_deviceDescCond = NULL;
+
+static oc_mutex g_threadSendMutex = NULL;
+static oc_mutex g_threadWriteCharacteristicMutex = NULL;
+static oc_cond g_threadWriteCharacteristicCond = NULL;
 static bool g_isSignalSetFlag = false;
 
-static ca_mutex g_bleReqRespClientCbMutex = NULL;
-static ca_mutex g_bleServerBDAddressMutex = NULL;
+static oc_mutex g_bleReqRespClientCbMutex = NULL;
+static oc_mutex g_bleServerBDAddressMutex = NULL;
 
-static ca_mutex g_deviceListMutex = NULL;
-static ca_mutex g_gattObjectMutex = NULL;
-static ca_mutex g_deviceStateListMutex = NULL;
+static oc_mutex g_deviceListMutex = NULL;
+static oc_mutex g_gattObjectMutex = NULL;
+static oc_mutex g_deviceStateListMutex = NULL;
 
-static ca_mutex g_deviceScanRetryDelayMutex = NULL;
-static ca_cond g_deviceScanRetryDelayCond = NULL;
+static oc_mutex g_deviceScanRetryDelayMutex = NULL;
+static oc_cond g_deviceScanRetryDelayCond = NULL;
 
-static ca_mutex g_threadScanIntervalMutex = NULL;
-static ca_cond g_threadScanIntervalCond = NULL;
+static oc_mutex g_threadScanIntervalMutex = NULL;
+static oc_cond g_threadScanIntervalCond = NULL;
 
-static ca_mutex g_threadSendStateMutex = NULL;
+static oc_mutex g_threadSendStateMutex = NULL;
+static oc_mutex g_setValueMutex = 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 CALEScanState_t g_curScanningStep = BLE_SCAN_NONE;
+static CALEScanState_t g_nextScanningStep = BLE_SCAN_ENABLE;
 
 static CABLEDataReceivedCallback g_CABLEClientDataReceivedCallback = NULL;
+static int32_t g_jniIntSdk = -1;
 
+static bool g_setHighQoS = true;
+static bool g_setFullScanFlag = true;
+jclass g_LEInterface = 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.
@@ -130,14 +143,33 @@ 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)
+/**
+ * delete global reference for g_sendBuffer
+ * @param[in]   env                   JNI interface pointer.
+ */
+static void CALEDeleteSendBuffer(JNIEnv *env)
+{
+    OIC_LOG(INFO, TAG, "CALEDeleteSendBuffer");
+    oc_mutex_lock(g_setValueMutex);
+    if (g_sendBuffer)
+    {
+        OIC_LOG(INFO, TAG, "delete send buffer");
+        (*env)->DeleteGlobalRef(env, g_sendBuffer);
+        g_sendBuffer = NULL;
+    }
+    oc_mutex_unlock(g_setValueMutex);
+}
+
+void CALEClientSetScanInterval(int32_t intervalTime, int32_t workingCount,
+                               CALEScanState_t nextScanningStep)
 {
-    OIC_LOG_V(DEBUG, TAG, "CALEClientSetScanInterval : %d -> %d",
-              g_scanIntervalTime, intervalTime);
+    OIC_LOG_V(DEBUG, TAG, "CALEClientSetScanInterval : %d -> %d, next scan state will be %d",
+              g_scanIntervalTime, intervalTime, nextScanningStep);
 
     // previous time should be stored.
     if (0 < workingCount)
@@ -146,13 +178,24 @@ void CALEClientSetScanInterval(int32_t intervalTime, int32_t workingCount)
     }
     g_scanIntervalTime = intervalTime;
     g_intervalCount = workingCount;
+    g_nextScanningStep = nextScanningStep;
 }
 
-void CALERestartScanWithInterval(int32_t intervalTime, int32_t workingCount)
+void CALERestartScanWithInterval(int32_t intervalTime, int32_t workingCount,
+                                 CALEScanState_t nextScanningStep)
 {
-    // restart scan with interval
-    CALEClientSetScanInterval(intervalTime, workingCount);
-    ca_cond_signal(g_threadScanIntervalCond);
+    if (intervalTime == g_scanIntervalTime
+            && workingCount == g_intervalCount
+            && nextScanningStep == g_nextScanningStep)
+    {
+        OIC_LOG(DEBUG, TAG, "setting duplicate interval time");
+        return;
+    }
+
+    oc_mutex_lock(g_threadScanIntervalMutex);
+    CALEClientSetScanInterval(intervalTime, workingCount, nextScanningStep);
+    oc_cond_signal(g_threadScanIntervalCond);
+    oc_mutex_unlock(g_threadScanIntervalMutex);
 }
 
 static void CALEScanThread(void* object)
@@ -164,7 +207,6 @@ static void CALEScanThread(void* object)
     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)
@@ -175,11 +217,11 @@ static void CALEScanThread(void* object)
         isAttached = true;
     }
 
-    ca_mutex_lock(g_threadScanIntervalMutex);
+    oc_mutex_lock(g_threadScanIntervalMutex);
     while(g_isWorkingScanThread)
     {
         OIC_LOG(DEBUG, TAG, "scan waiting time out");
-        if (BLE_SCAN_ENABLE == g_scanningStep)
+        if (BLE_SCAN_ENABLE == g_curScanningStep)
         {
             //stop scan
             CAResult_t ret = CALEClientStopScan();
@@ -188,7 +230,7 @@ static void CALEScanThread(void* object)
                 OIC_LOG(INFO, TAG, "CALEClientStopScan has failed");
             }
         }
-        else
+        else if (BLE_SCAN_DISABLE == g_curScanningStep)
         {
             //start scan
             CAResult_t ret = CALEClientStartScan();
@@ -197,39 +239,52 @@ static void CALEScanThread(void* object)
                 OIC_LOG(INFO, TAG, "CALEClientStartScan has failed");
             }
         }
+        else
+        {
+            OIC_LOG(DEBUG, TAG, "scan thread is started");
+            // standby scanning
+            CALEClientSetScanInterval(0, 0, BLE_SCAN_DISABLE);
+        }
 
         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,
+        if (OC_WAIT_SUCCESS == oc_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;
+            if (BLE_SCAN_DISABLE == g_nextScanningStep)
+            {
+                g_curScanningStep = BLE_SCAN_ENABLE;
+            }
+            else
+            {
+                g_curScanningStep = BLE_SCAN_DISABLE;
+            }
         }
         else
         {
-           if (BLE_SCAN_ENABLE == g_scanningStep)
+           if (BLE_SCAN_ENABLE == g_curScanningStep)
            {
                if (g_intervalCount > 0)
                {
                    if (g_intervalCount == 1)
                    {
                        OIC_LOG(DEBUG, TAG, "reset default time");
-                       CALEClientSetScanInterval(g_scanIntervalTimePrev, 0);
+                       CALEClientSetScanInterval(g_scanIntervalTimePrev, 0, BLE_SCAN_ENABLE);
                    }
                    g_intervalCount--;
                    OIC_LOG_V(DEBUG, TAG, "interval count : %d", g_intervalCount);
                }
-               g_scanningStep = BLE_SCAN_DISABLE;
+               g_curScanningStep = BLE_SCAN_DISABLE;
            }
            else
            {
-               g_scanningStep = BLE_SCAN_ENABLE;
+               g_curScanningStep = BLE_SCAN_ENABLE;
            }
         }
     }
-    ca_mutex_unlock(g_threadScanIntervalMutex);
+    oc_mutex_unlock(g_threadScanIntervalMutex);
 
     if (isAttached)
     {
@@ -239,8 +294,6 @@ static void CALEScanThread(void* object)
 
 CAResult_t CALEClientStartScanWithInterval()
 {
-    OIC_LOG(DEBUG, TAG, "IN - CALEClientStartScanWithInterval");
-
     if (g_isWorkingScanThread)
     {
         OIC_LOG(DEBUG, TAG, "scan interval logic already running");
@@ -248,27 +301,26 @@ CAResult_t CALEClientStartScanWithInterval()
     }
 
     // initialize scan flags
-    g_scanningStep = BLE_SCAN_DISABLE;
+    g_curScanningStep = BLE_SCAN_NONE;
     g_isWorkingScanThread = true;
     g_intervalCount = 0;
     g_scanIntervalTime = g_scanIntervalTimePrev;
+    g_nextScanningStep = BLE_SCAN_ENABLE;
 
-    if (CA_STATUS_OK != ca_thread_pool_add_task(g_threadPoolHandle,
-                                                CALEScanThread, NULL))
+    if (CA_STATUS_OK != ca_thread_pool_add_task(g_threadPoolHandle, CALEScanThread, NULL, 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);
+    oc_cond_signal(g_threadScanIntervalCond);
 }
 
 //getting jvm
@@ -305,7 +357,6 @@ CAResult_t CALECreateJniInterfaceObject()
     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)
@@ -331,7 +382,7 @@ CAResult_t CALECreateJniInterfaceObject()
     if (!jApplicationContext)
     {
         OIC_LOG(ERROR, TAG, "Could not get application context");
-        return CA_STATUS_FAILED;
+        goto error_exit;
     }
 
     jclass jni_LEInterface = (*env)->FindClass(env, "org/iotivity/ca/CaLeClientInterface");
@@ -340,6 +391,7 @@ CAResult_t CALECreateJniInterfaceObject()
         OIC_LOG(ERROR, TAG, "Could not get CaLeClientInterface class");
         goto error_exit;
     }
+    g_LEInterface = (jclass)((*env)->NewGlobalRef(env, jni_LEInterface));
 
     jmethodID LeInterfaceConstructorMethod = (*env)->GetMethodID(env, jni_LEInterface, "<init>",
                                                                  "(Landroid/content/Context;)V");
@@ -360,7 +412,7 @@ CAResult_t CALECreateJniInterfaceObject()
     return CA_STATUS_OK;
 
 error_exit:
-
+    CACheckJNIException(env);
     if (isAttached)
     {
         (*g_jvm)->DetachCurrentThread(g_jvm);
@@ -386,7 +438,6 @@ CAResult_t CALEClientInitialize()
     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)
@@ -397,8 +448,8 @@ CAResult_t CALEClientInitialize()
         isAttached = true;
     }
 
-    CAResult_t ret = CALECheckPlatformVersion(env, 18);
-    if (CA_STATUS_OK != ret)
+    g_jniIntSdk = CALEGetBuildVersion(env);
+    if (g_jniIntSdk < BLE_MIN_API_LEVEL)
     {
         OIC_LOG(ERROR, TAG, "it is not supported");
 
@@ -406,11 +457,10 @@ CAResult_t CALEClientInitialize()
         {
             (*g_jvm)->DetachCurrentThread(g_jvm);
         }
-
-        return ret;
+        return CA_STATUS_FAILED;
     }
 
-    ret = CALEClientInitGattMutexVaraibles();
+    CAResult_t ret = CALEClientInitGattMutexVaraibles();
     if (CA_STATUS_OK != ret)
     {
         OIC_LOG(ERROR, TAG, "CALEClientInitGattMutexVaraibles has failed!");
@@ -424,13 +474,13 @@ CAResult_t CALEClientInitialize()
         return ret;
     }
 
-    g_deviceDescCond = ca_cond_new();
+    g_deviceDescCond = oc_cond_new();
 
     // init mutex for send logic
-    g_threadCond = ca_cond_new();
-    g_threadWriteCharacteristicCond = ca_cond_new();
-    g_deviceScanRetryDelayCond = ca_cond_new();
-    g_threadScanIntervalCond =  ca_cond_new();
+    g_threadCond = oc_cond_new();
+    g_threadWriteCharacteristicCond = oc_cond_new();
+    g_deviceScanRetryDelayCond = oc_cond_new();
+    g_threadScanIntervalCond =  oc_cond_new();
 
     CALEClientCreateDeviceList();
     CALEClientJNISetContext();
@@ -485,7 +535,6 @@ void CALEClientTerminate()
     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)
@@ -496,6 +545,13 @@ void CALEClientTerminate()
         isAttached = true;
     }
 
+    // stop scan
+    CAResult_t ret = CALEClientStopScan();
+    if (CA_STATUS_OK != ret)
+    {
+        OIC_LOG(INFO, TAG, "CALEClientStopScan has failed");
+    }
+
     if (g_leScanCallback)
     {
         (*env)->DeleteGlobalRef(env, g_leScanCallback);
@@ -508,24 +564,32 @@ void CALEClientTerminate()
         g_leGattCallback = NULL;
     }
 
-    if (g_sendBuffer)
+    if (g_LEInterface)
     {
-        (*env)->DeleteGlobalRef(env, g_sendBuffer);
-        g_sendBuffer = NULL;
+        (*env)->DeleteGlobalRef(env, g_LEInterface);
+        g_LEInterface = NULL;
     }
 
+    CALEDeleteSendBuffer(env);
+
     if (g_uuidList)
     {
         (*env)->DeleteGlobalRef(env, g_uuidList);
         g_uuidList = NULL;
     }
 
-    CAResult_t ret = CALEClientRemoveAllDeviceState();
+    ret = CALERemoveAllDeviceState(g_deviceStateList,
+                                   g_deviceStateListMutex);
     if (CA_STATUS_OK != ret)
     {
-        OIC_LOG(ERROR, TAG, "CALEClientRemoveAllDeviceState has failed");
+        OIC_LOG(ERROR, TAG, "CALERemoveAllDeviceState has failed");
     }
 
+    oc_mutex_lock(g_deviceStateListMutex);
+    OICFree(g_deviceStateList);
+    g_deviceStateList = NULL;
+    oc_mutex_unlock(g_deviceStateListMutex);
+
     ret = CALEClientRemoveAllScanDevices(env);
     if (CA_STATUS_OK != ret)
     {
@@ -543,11 +607,11 @@ void CALEClientTerminate()
     CALEClientTerminateGattMutexVariables();
     CALEClientDestroyJniInterface();
 
-    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);
+    oc_cond_free(g_deviceDescCond);
+    oc_cond_free(g_threadCond);
+    oc_cond_free(g_threadWriteCharacteristicCond);
+    oc_cond_free(g_deviceScanRetryDelayCond);
+    oc_cond_free(g_threadScanIntervalCond);
 
     g_deviceDescCond = NULL;
     g_threadCond = NULL;
@@ -566,6 +630,74 @@ void CALEClientTerminate()
     }
 }
 
+jobject CALEClientHiddenConnectGatt(jobject btDevice, const char* address, jboolean autoconnect)
+{
+    OIC_LOG(INFO, TAG, "IN - CALEClientHiddenConnectGatt");
+
+    if (!g_jvm)
+    {
+        OIC_LOG(ERROR, TAG, "g_jvm is null");
+        return NULL;
+    }
+
+    bool isAttached = false;
+    JNIEnv* env = NULL;
+    jint res = (*g_jvm)->GetEnv(g_jvm, (void**) &env, JNI_VERSION_1_6);
+    if (JNI_OK != res)
+    {
+        res = (*g_jvm)->AttachCurrentThread(g_jvm, &env, NULL);
+
+        if (JNI_OK != res)
+        {
+            OIC_LOG(ERROR, TAG, "AttachCurrentThread has failed");
+            return NULL;
+        }
+        isAttached = true;
+    }
+
+    jstring jni_address = (*env)->NewStringUTF(env, address);
+    jmethodID jni_connectGattHiddenMethod = (*env)->GetStaticMethodID(env, g_LEInterface,
+                                                                     "connectGattforHidden",
+                                                                     "(Landroid/bluetooth/BluetoothDevice;"
+                                                                     "Ljava/lang/String;Z)"
+                                                                     "Landroid/bluetooth/BluetoothGatt;");
+    if (!jni_connectGattHiddenMethod)
+    {
+        OIC_LOG(ERROR, TAG, "Could not get jni_connectGatt Hidden Method");
+        goto error_exit;
+    }
+
+    jobject gatt = (*env)->CallStaticObjectMethod(env, g_LEInterface,
+                                                  jni_connectGattHiddenMethod,
+                                                  btDevice, jni_address, autoconnect);
+
+    if (CACheckJNIException(env))
+    {
+        OIC_LOG(ERROR, TAG, "connectGattforHidden has failed");
+        goto detach_thread;
+    }
+
+    OIC_LOG(INFO, TAG, "OUT - CALEClientHiddenConnectGatt");
+
+    if (isAttached)
+    {
+        (*g_jvm)->DetachCurrentThread(g_jvm);
+    }
+
+    return gatt;
+
+error_exit:
+    CACheckJNIException(env);
+
+detach_thread:
+    if (isAttached)
+    {
+        (*g_jvm)->DetachCurrentThread(g_jvm);
+    }
+
+    return NULL;
+}
+
 CAResult_t CALEClientDestroyJniInterface()
 {
     OIC_LOG(DEBUG, TAG, "CALEClientDestroyJniInterface");
@@ -581,7 +713,6 @@ CAResult_t CALEClientDestroyJniInterface()
     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)
@@ -610,12 +741,10 @@ CAResult_t CALEClientDestroyJniInterface()
 
     (*env)->CallStaticVoidMethod(env, jni_LeInterface, jni_InterfaceDestroyMethod);
 
-    if ((*env)->ExceptionCheck(env))
+    if (CACheckJNIException(env))
     {
         OIC_LOG(ERROR, TAG, "destroyLeInterface has failed");
-        (*env)->ExceptionDescribe(env);
-        (*env)->ExceptionClear(env);
-        goto error_exit;
+        goto detach_thread;
     }
 
     OIC_LOG(DEBUG, TAG, "Destroy instance for CaLeClientInterface");
@@ -628,7 +757,9 @@ CAResult_t CALEClientDestroyJniInterface()
     return CA_STATUS_OK;
 
 error_exit:
+    CACheckJNIException(env);
 
+detach_thread:
     if (isAttached)
     {
         (*g_jvm)->DetachCurrentThread(g_jvm);
@@ -653,11 +784,17 @@ void CALEClientSendFinish(JNIEnv *env, jobject gatt)
     CALEClientUpdateSendCnt(env);
 }
 
+CAResult_t CALEClientSendNegotiationMessage(const char* address)
+{
+    VERIFY_NON_NULL(address, TAG, "address is null");
+
+    return CALEClientSendUnicastMessageImpl(address, NULL, 0);
+}
+
 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");
 
@@ -681,7 +818,6 @@ CAResult_t CALEClientSendMulticastMessage(const uint8_t* data,
     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)
@@ -749,6 +885,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;
     }
 
@@ -764,19 +901,20 @@ CAResult_t CALEClientIsThereScannedDevices(JNIEnv *env, const char* address)
             2 * MICROSECS_PER_SEC;  // Microseconds
 
         // set scan interval and start scan
-        CALERestartScanWithInterval(WAIT_TIME_SCANNED_CHECKING, 1);
+        CALERestartScanWithInterval(WAIT_TIME_SCANNED_CHECKING, 1, BLE_SCAN_ENABLE);
 
         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,
+            if (oc_cond_wait_for(g_deviceDescCond,
                                  g_threadSendMutex,
-                                 TIMEOUT) == CA_WAIT_SUCCESS)
+                                 TIMEOUT) == OC_WAIT_SUCCESS)
             {
-                ca_mutex_lock(g_deviceListMutex);
+                OIC_LOG(DEBUG, TAG, "time out");
+                oc_mutex_lock(g_deviceListMutex);
                 size_t scannedDeviceLen = u_arraylist_length(g_deviceList);
-                ca_mutex_unlock(g_deviceListMutex);
+                oc_mutex_unlock(g_deviceListMutex);
 
                 if (0 < scannedDeviceLen)
                 {
@@ -792,16 +930,16 @@ CAResult_t CALEClientIsThereScannedDevices(JNIEnv *env, const char* address)
                         {
                             OIC_LOG(INFO, TAG, "waiting..");
 
-                            ca_mutex_lock(g_deviceScanRetryDelayMutex);
-                            if (ca_cond_wait_for(g_deviceScanRetryDelayCond,
+                            oc_mutex_lock(g_deviceScanRetryDelayMutex);
+                            if (oc_cond_wait_for(g_deviceScanRetryDelayCond,
                                                  g_deviceScanRetryDelayMutex,
-                                                 MICROSECS_PER_SEC) == CA_WAIT_SUCCESS)
+                                                 MICROSECS_PER_SEC) == OC_WAIT_SUCCESS)
                             {
                                 OIC_LOG(INFO, TAG, "finish to waiting for target device");
-                                ca_mutex_unlock(g_deviceScanRetryDelayMutex);
+                                oc_mutex_unlock(g_deviceScanRetryDelayMutex);
                                 break;
                             }
-                            ca_mutex_unlock(g_deviceScanRetryDelayMutex);
+                            oc_mutex_unlock(g_deviceScanRetryDelayMutex);
                             // time out
 
                             // checking whether a target device is found while waiting for time-out.
@@ -817,7 +955,7 @@ CAResult_t CALEClientIsThereScannedDevices(JNIEnv *env, const char* address)
         }
 
         // reset scan interval time after checking scanned devices
-        CALERestartScanWithInterval(g_scanIntervalTimePrev, 0);
+        CALERestartScanWithInterval(0, 0, BLE_SCAN_DISABLE);
 
         // time out for scanning devices
         if (!devicesDiscovered)
@@ -825,6 +963,10 @@ CAResult_t CALEClientIsThereScannedDevices(JNIEnv *env, const char* address)
             return CA_STATUS_FAILED;
         }
     }
+    else
+    {
+        OIC_LOG(DEBUG, TAG, "there is a target device in the scanned devices");
+    }
 
     return CA_STATUS_OK;
 }
@@ -833,10 +975,10 @@ CAResult_t CALEClientIsThereScannedDevices(JNIEnv *env, const char* address)
 CAResult_t CALEClientSendUnicastMessageImpl(const char* address, const uint8_t* data,
                                             const uint32_t dataLen)
 {
+    OIC_LOG(INFO, TAG, "CALEClientSendUnicastMessageImpl in");
     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");
 
     if (!g_jvm)
     {
@@ -849,7 +991,6 @@ CAResult_t CALEClientSendUnicastMessageImpl(const char* address, const uint8_t*
     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)
         {
@@ -859,7 +1000,7 @@ CAResult_t CALEClientSendUnicastMessageImpl(const char* address, const uint8_t*
         isAttached = true;
     }
 
-    ca_mutex_lock(g_threadSendMutex);
+    oc_mutex_lock(g_threadSendMutex);
 
     CALEClientSetSendFinishFlag(false);
 
@@ -893,27 +1034,26 @@ CAResult_t CALEClientSendUnicastMessageImpl(const char* address, const uint8_t*
             if (!setAddress)
             {
                 OIC_LOG(ERROR, TAG, "setAddress is null");
+                CACheckJNIException(env);
                 goto error_exit;
             }
 
-            OIC_LOG_V(DEBUG, TAG, "remote device address is %s", setAddress);
-
-            if (!strcmp(setAddress, address))
+            if (!strcasecmp(setAddress, address))
             {
                 (*env)->ReleaseStringUTFChars(env, jni_setAddress, setAddress);
                 (*env)->DeleteLocalRef(env, jni_setAddress);
 
-                // stop scan while sending
-                CALEClientStopScanWithInterval();
+                CALEDeleteSendBuffer(env);
 
-                if (g_sendBuffer)
+                if (data && dataLen > 0)
                 {
-                    (*env)->DeleteGlobalRef(env, g_sendBuffer);
-                    g_sendBuffer = NULL;
+                    jbyteArray jni_arr = (*env)->NewByteArray(env, dataLen);
+                    CACheckJNIException(env);
+                    (*env)->SetByteArrayRegion(env, jni_arr, 0, dataLen, (jbyte*) data);
+                    CACheckJNIException(env);
+                    g_sendBuffer = (jbyteArray)(*env)->NewGlobalRef(env, jni_arr);
+                    CACheckJNIException(env);
                 }
-                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;
@@ -937,47 +1077,52 @@ CAResult_t CALEClientSendUnicastMessageImpl(const char* address, const uint8_t*
 
     // wait for finish to send data through "CALeGattServicesDiscoveredCallback"
     // if there is no connection state.
-    ca_mutex_lock(g_threadMutex);
+    oc_mutex_lock(g_threadMutex);
     if (!g_isFinishedSendData)
     {
         OIC_LOG(DEBUG, TAG, "waiting send finish signal");
-        ca_cond_wait(g_threadCond, g_threadMutex);
-        OIC_LOG(DEBUG, TAG, "the data was sent");
+        oc_cond_wait(g_threadCond, g_threadMutex);
+        OIC_LOG(DEBUG, TAG, "connection / send is finished for unicast");
     }
-    ca_mutex_unlock(g_threadMutex);
+    oc_mutex_unlock(g_threadMutex);
 
     if (isAttached)
     {
         (*g_jvm)->DetachCurrentThread(g_jvm);
     }
 
-    // start LE Scan again
-    ret = CALEClientStartScanWithInterval();
-    if (CA_STATUS_OK != ret)
+    oc_mutex_unlock(g_threadSendMutex);
+    OIC_LOG(INFO, TAG, "unicast - send logic has finished");
+    if (CALEIsValidState(address, CA_LE_SEND_STATE,
+                         STATE_SEND_SUCCESS,
+                         g_deviceStateList,
+                         g_deviceStateListMutex))
     {
-        OIC_LOG(ERROR, TAG, "CALEClientStartScanWithInterval has failed");
-        ca_mutex_unlock(g_threadSendMutex);
-        return ret;
+        OIC_LOG(INFO, TAG, "send success");
+        ret = CA_STATUS_OK;
     }
-
-    ca_mutex_unlock(g_threadSendMutex);
-    OIC_LOG(INFO, TAG, "unicast - send logic has finished");
-    if (CALEClientIsValidState(address, CA_LE_SEND_STATE,
-                               STATE_SEND_SUCCESS))
+    else if (CALEIsValidState(address, CA_LE_SEND_STATE,
+                              STATE_SEND_MTU_NEGO_SUCCESS,
+                              g_deviceStateList,
+                              g_deviceStateListMutex))
     {
+        OIC_LOG(INFO, TAG, "mtu nego success");
         ret = CA_STATUS_OK;
     }
     else
     {
+        OIC_LOG(ERROR, TAG, "send failure");
         ret = CA_SEND_FAILED;
     }
 
     // reset send state
-    CAResult_t resetRet = CALEClientUpdateDeviceState(address, CA_LE_SEND_STATE,
-                                                      STATE_SEND_NONE);
+    CAResult_t resetRet = CALEUpdateDeviceState(address, CA_LE_SEND_STATE,
+                                                STATE_SEND_NONE,
+                                                g_deviceStateList,
+                                                g_deviceStateListMutex);
     if (CA_STATUS_OK != resetRet)
     {
-        OIC_LOG_V(ERROR, TAG, "CALEClientUpdateDeviceState has failed (%d)", resetRet);
+        OIC_LOG_V(ERROR, TAG, "CALEUpdateDeviceState has failed (%d)", resetRet);
         ret = CA_SEND_FAILED;
     }
 
@@ -985,26 +1130,12 @@ CAResult_t CALEClientSendUnicastMessageImpl(const char* address, const uint8_t*
 
     // error label.
 error_exit:
-
-    // start LE Scan again
-    ret = CALEClientStartScanWithInterval();
-    if (CA_STATUS_OK != ret)
-    {
-        OIC_LOG(ERROR, TAG, "CALEClientStartScanWithInterval has failed");
-        ca_mutex_unlock(g_threadSendMutex);
-        if (isAttached)
-        {
-            (*g_jvm)->DetachCurrentThread(g_jvm);
-        }
-        return ret;
-    }
-
     if (isAttached)
     {
         (*g_jvm)->DetachCurrentThread(g_jvm);
     }
 
-    ca_mutex_unlock(g_threadSendMutex);
+    oc_mutex_unlock(g_threadSendMutex);
     return CA_SEND_FAILED;
 }
 
@@ -1021,16 +1152,12 @@ CAResult_t CALEClientSendMulticastMessageImpl(JNIEnv *env, const uint8_t* data,
         return CA_STATUS_FAILED;
     }
 
-    ca_mutex_lock(g_threadSendMutex);
+    oc_mutex_lock(g_threadSendMutex);
 
     CALEClientSetSendFinishFlag(false);
 
     OIC_LOG(DEBUG, TAG, "set byteArray for data");
-    if (g_sendBuffer)
-    {
-        (*env)->DeleteGlobalRef(env, g_sendBuffer);
-        g_sendBuffer = NULL;
-    }
+    CALEDeleteSendBuffer(env);
 
     CAResult_t res = CALEClientIsThereScannedDevices(env, NULL);
     if (CA_STATUS_OK != res)
@@ -1039,9 +1166,6 @@ CAResult_t CALEClientSendMulticastMessageImpl(JNIEnv *env, const uint8_t* data,
         goto error_exit;
     }
 
-    // stop scan while sending
-    CALEClientStopScanWithInterval();
-
     uint32_t length = u_arraylist_length(g_deviceList);
     g_targetCnt = length;
 
@@ -1068,39 +1192,21 @@ CAResult_t CALEClientSendMulticastMessageImpl(JNIEnv *env, const uint8_t* data,
     OIC_LOG(DEBUG, TAG, "connection routine is finished for multicast");
 
     // wait for finish to send data through "CALeGattServicesDiscoveredCallback"
-    ca_mutex_lock(g_threadMutex);
+    oc_mutex_lock(g_threadMutex);
     if (!g_isFinishedSendData)
     {
         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);
-
-    // start LE Scan again
-    res = CALEClientStartScanWithInterval();
-    if (CA_STATUS_OK != res)
-    {
-        OIC_LOG(ERROR, TAG, "CALEClientStartScanWithInterval has failed");
-        ca_mutex_unlock(g_threadSendMutex);
-        return res;
+        oc_cond_wait(g_threadCond, g_threadMutex);
+        OIC_LOG(DEBUG, TAG, "connection / send is finished for multicast");
     }
-
-    ca_mutex_unlock(g_threadSendMutex);
+    oc_mutex_unlock(g_threadMutex);
+    oc_mutex_unlock(g_threadSendMutex);
     OIC_LOG(DEBUG, TAG, "OUT - CALEClientSendMulticastMessageImpl");
     return CA_STATUS_OK;
 
 error_exit:
-    res = CALEClientStartScanWithInterval();
-    if (CA_STATUS_OK != res)
-    {
-        OIC_LOG(ERROR, TAG, "CALEClientStartScanWithInterval has failed");
-        ca_mutex_unlock(g_threadSendMutex);
-        return res;
-    }
-
-    ca_mutex_unlock(g_threadSendMutex);
-    OIC_LOG(DEBUG, TAG, "OUT - CALEClientSendMulticastMessageImpl");
+    oc_mutex_unlock(g_threadSendMutex);
+    OIC_LOG(ERROR, TAG, "OUT - CALEClientSendMulticastMessageImpl");
     return CA_SEND_FAILED;
 }
 
@@ -1121,11 +1227,28 @@ CAResult_t CALEClientSendData(JNIEnv *env, jobject device)
         if (!address)
         {
             OIC_LOG(ERROR, TAG, "address is not available");
+            CACheckJNIException(env);
             return CA_STATUS_FAILED;
         }
-        ca_mutex_lock(g_deviceStateListMutex);
-        state = CALEClientGetStateInfo(address);
-        ca_mutex_unlock(g_deviceStateListMutex);
+        oc_mutex_lock(g_deviceStateListMutex);
+        state = CALEGetStateInfo(address, g_deviceStateList);
+        oc_mutex_unlock(g_deviceStateListMutex);
+    }
+
+    // Since disconnect event can be caused from BT stack while connection step is running.
+    // DeviceState has to have current status for processing send failure.
+    OIC_LOG(INFO, TAG, "set STATE_SEND_PREPARING");
+    CAResult_t res = CALEClientUpdateDeviceStateWithBtDevice(env, device,
+                                                             CA_LE_SEND_STATE,
+                                                             STATE_SEND_PREPARING);
+    if (CA_STATUS_OK != res)
+    {
+        OIC_LOG(ERROR, TAG, "CALEClientUpdateDeviceStateWithBtDevice has failed");
+        if (address)
+        {
+            (*env)->ReleaseStringUTFChars(env, jni_address, address);
+        }
+        return CA_STATUS_FAILED;
     }
 
     if (!state)
@@ -1159,8 +1282,10 @@ CAResult_t CALEClientSendData(JNIEnv *env, jobject device)
     }
     else
     {
-        if (CALEClientIsValidState(address, CA_LE_CONNECTION_STATE,
-                                   STATE_SERVICE_CONNECTED))
+        if (CALEIsValidState(address, CA_LE_CONNECTION_STATE,
+                             STATE_SERVICE_CONNECTED,
+                             g_deviceStateList,
+                             g_deviceStateListMutex))
         {
             OIC_LOG(INFO, TAG, "GATT has already connected");
 
@@ -1181,13 +1306,17 @@ CAResult_t CALEClientSendData(JNIEnv *env, jobject device)
             }
             (*env)->ReleaseStringUTFChars(env, jni_address, address);
         }
-        else if(CALEClientIsValidState(address, CA_LE_CONNECTION_STATE,
-                                       STATE_CONNECTED))
+        else if(CALEIsValidState(address, CA_LE_CONNECTION_STATE,
+                                 STATE_CONNECTED,
+                                 g_deviceStateList,
+                                 g_deviceStateListMutex))
         {
             OIC_LOG(INFO, TAG, "service connecting...");
         }
-        else if(CALEClientIsValidState(address, CA_LE_CONNECTION_STATE,
-                                       STATE_DISCONNECTED))
+        else if(CALEIsValidState(address, CA_LE_CONNECTION_STATE,
+                                 STATE_DISCONNECTED,
+                                 g_deviceStateList,
+                                 g_deviceStateListMutex))
         {
             OIC_LOG(INFO, TAG, "STATE_DISCONNECTED - start to connect LE");
 
@@ -1209,8 +1338,10 @@ CAResult_t CALEClientSendData(JNIEnv *env, jobject device)
 
             OIC_LOG(DEBUG, TAG, "start to connect LE");
             jobject gatt = CALEClientConnect(env, device,
-                                             CALEClientGetFlagFromState(env, jni_address,
-                                                                        CA_LE_AUTO_CONNECT_FLAG));
+                                             CALEGetFlagFromState(env, jni_address,
+                                                                  CA_LE_AUTO_CONNECT_FLAG,
+                                                                  g_deviceStateList,
+                                                                  g_deviceStateListMutex));
 
             if (NULL == gatt)
             {
@@ -1240,6 +1371,7 @@ jstring CALEClientGetAddressFromGattObj(JNIEnv *env, jobject gatt)
     if (!jni_obj_device)
     {
         OIC_LOG(ERROR, TAG, "jni_obj_device is null");
+        CACheckJNIException(env);
         return NULL;
     }
 
@@ -1247,6 +1379,7 @@ jstring CALEClientGetAddressFromGattObj(JNIEnv *env, jobject gatt)
     if (!jni_address)
     {
         OIC_LOG(ERROR, TAG, "jni_address is null");
+        CACheckJNIException(env);
         return NULL;
     }
 
@@ -1276,11 +1409,9 @@ CAResult_t CALEClientGattClose(JNIEnv *env, jobject bluetoothGatt)
     OIC_LOG(DEBUG, TAG, "request to close GATT");
     (*env)->CallVoidMethod(env, bluetoothGatt, jni_mid_closeGatt);
 
-    if ((*env)->ExceptionCheck(env))
+    if (CACheckJNIException(env))
     {
         OIC_LOG(ERROR, TAG, "closeGATT has failed");
-        (*env)->ExceptionDescribe(env);
-        (*env)->ExceptionClear(env);
         return CA_STATUS_FAILED;
     }
 
@@ -1306,8 +1437,6 @@ CAResult_t CALEClientStartScan()
     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)
         {
@@ -1323,11 +1452,31 @@ CAResult_t CALEClientStartScan()
     // scan gatt server with UUID
     if (g_leScanCallback && g_uuidList)
     {
-#ifdef UUID_SCAN
-        ret = CALEClientStartScanWithUUIDImpl(env, g_uuidList, g_leScanCallback);
-#else
-        ret = CALEClientStartScanImpl(env, g_leScanCallback);
-#endif
+        if (g_jniIntSdk >= BLE_SCAN_API_LEVEL)
+        {
+            if (!g_setFullScanFlag)
+            {
+                //new uuid scan with callback
+                ret = CALEClientStartScanWithUUIDImplForV21(env, g_uuidList, g_leScanCallback);
+            }
+            else
+            {
+                //new full scan with callback
+                ret = CALEClientStartScanImplForV21(env, g_leScanCallback);
+            }
+        }
+        else
+        {
+            if (!g_setFullScanFlag)
+            {
+                ret = CALEClientStartScanWithUUIDImpl(env, g_uuidList, g_leScanCallback);
+            }
+            else
+            {
+                ret = CALEClientStartScanImpl(env, g_leScanCallback);
+            }
+        }
+
         if (CA_STATUS_OK != ret)
         {
             if (CA_ADAPTER_NOT_ENABLED == ret)
@@ -1351,6 +1500,7 @@ CAResult_t CALEClientStartScan()
 
 CAResult_t CALEClientStartScanImpl(JNIEnv *env, jobject callback)
 {
+    OIC_LOG(DEBUG, TAG, "CALEClientStartScanImpl IN");
     VERIFY_NON_NULL(callback, TAG, "callback is null");
     VERIFY_NON_NULL(env, TAG, "env is null");
 
@@ -1365,6 +1515,7 @@ CAResult_t CALEClientStartScanImpl(JNIEnv *env, jobject callback)
     if (!jni_cid_BTAdapter)
     {
         OIC_LOG(ERROR, TAG, "getState From BTAdapter: jni_cid_BTAdapter is null");
+        CACheckJNIException(env);
         return CA_STATUS_FAILED;
     }
 
@@ -1375,6 +1526,7 @@ CAResult_t CALEClientStartScanImpl(JNIEnv *env, jobject callback)
     if (!jni_mid_getDefaultAdapter)
     {
         OIC_LOG(ERROR, TAG, "jni_mid_getDefaultAdapter is null");
+        CACheckJNIException(env);
         (*env)->DeleteLocalRef(env, jni_cid_BTAdapter);
         return CA_STATUS_FAILED;
     }
@@ -1386,6 +1538,7 @@ CAResult_t CALEClientStartScanImpl(JNIEnv *env, jobject callback)
     if (!jni_mid_startLeScan)
     {
         OIC_LOG(ERROR, TAG, "startLeScan: jni_mid_startLeScan is null");
+        CACheckJNIException(env);
         (*env)->DeleteLocalRef(env, jni_cid_BTAdapter);
         return CA_STATUS_FAILED;
     }
@@ -1396,6 +1549,7 @@ CAResult_t CALEClientStartScanImpl(JNIEnv *env, jobject callback)
     if (!jni_obj_BTAdapter)
     {
         OIC_LOG(ERROR, TAG, "getState From BTAdapter: jni_obj_BTAdapter is null");
+        CACheckJNIException(env);
         (*env)->DeleteLocalRef(env, jni_cid_BTAdapter);
         return CA_STATUS_FAILED;
     }
@@ -1407,6 +1561,7 @@ CAResult_t CALEClientStartScanImpl(JNIEnv *env, jobject callback)
     if (!jni_obj_startLeScan)
     {
         OIC_LOG(INFO, TAG, "startLeScan has failed");
+        CACheckJNIException(env);
     }
     else
     {
@@ -1418,8 +1573,113 @@ CAResult_t CALEClientStartScanImpl(JNIEnv *env, jobject callback)
     return CA_STATUS_OK;
 }
 
+CAResult_t CALEClientStartScanImplForV21(JNIEnv *env, jobject callback)
+{
+    OIC_LOG(DEBUG, TAG, "CALEClientStartScanImplForV21 IN");
+    VERIFY_NON_NULL(callback, TAG, "callback is null");
+    VERIFY_NON_NULL(env, TAG, "env is null");
+
+    if (!CALEIsEnableBTAdapter(env))
+    {
+        OIC_LOG(INFO, TAG, "BT adapter is not enabled");
+        return CA_ADAPTER_NOT_ENABLED;
+    }
+
+    CAResult_t res = CA_STATUS_FAILED;
+    // get default bt adapter class
+    jclass jni_cid_BTAdapter = (*env)->FindClass(env, CLASSPATH_BT_ADAPTER);
+    if (!jni_cid_BTAdapter)
+    {
+        OIC_LOG(ERROR, TAG, "getState From BTAdapter: jni_cid_BTAdapter is null");
+        CACheckJNIException(env);
+        return CA_STATUS_FAILED;
+    }
+
+    jmethodID jni_mid_getDefaultAdapter = (*env)->GetStaticMethodID(env, jni_cid_BTAdapter,
+                                                                    "getDefaultAdapter",
+                                                                    "()Landroid/bluetooth/"
+                                                                    "BluetoothAdapter;");
+    if (!jni_mid_getDefaultAdapter)
+    {
+        OIC_LOG(ERROR, TAG, "jni_mid_getDefaultAdapter is null");
+        (*env)->DeleteLocalRef(env, jni_cid_BTAdapter);
+        return CA_STATUS_FAILED;
+    }
+
+    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");
+        (*env)->DeleteLocalRef(env, jni_cid_BTAdapter);
+        return CA_STATUS_FAILED;
+    }
+
+    // get bluetoothLeScanner class
+    jclass jni_cid_leScanner = (*env)->FindClass(env, CLASSPATH_LE_SCANNER);
+    if (!jni_cid_leScanner)
+    {
+        OIC_LOG(ERROR, TAG, "getState From leScanner: jni_cid_leScanner is null");
+        CACheckJNIException(env);
+        (*env)->DeleteLocalRef(env, jni_cid_BTAdapter);
+        (*env)->DeleteLocalRef(env, jni_obj_BTAdapter);
+        return CA_STATUS_FAILED;
+    }
+
+    // get remote bt adapter method
+    jmethodID jni_mid_getBluetoothLeScanner = (*env)->GetMethodID(env, jni_cid_BTAdapter,
+                                                                  "getBluetoothLeScanner",
+                                                                  "()Landroid/bluetooth/"
+                                                                  "le/BluetoothLeScanner;");
+    if (!jni_mid_getBluetoothLeScanner)
+    {
+        OIC_LOG(ERROR, TAG, "jni_mid_getBluetoothLeScanner is null");
+        CACheckJNIException(env);
+        goto error_exit;
+    }
+
+    // get startScan(ScanCallback callback) method
+    jmethodID jni_mid_startScan = (*env)->GetMethodID(env, jni_cid_leScanner, "startScan",
+                                                      "(Landroid/bluetooth/le/ScanCallback;)V");
+    if (!jni_mid_startScan)
+    {
+        OIC_LOG(ERROR, TAG, "startScan: jni_mid_startScan is null");
+        CACheckJNIException(env);
+        goto error_exit;
+    }
+
+    // gat le scanner object
+    jobject jni_obj_leScanner = (*env)->CallObjectMethod(env, jni_obj_BTAdapter,
+                                                         jni_mid_getBluetoothLeScanner);
+    if (!jni_obj_leScanner)
+    {
+        OIC_LOG(ERROR, TAG, "getState From BTAdapter: jni_obj_leScanner is null");
+        CACheckJNIException(env);
+        goto error_exit;
+    }
+
+    // call startScan method
+    OIC_LOG(INFO, TAG, "CALL API - startScan(for level21)");
+    (*env)->CallVoidMethod(env, jni_obj_leScanner, jni_mid_startScan, callback);
+    if (CACheckJNIException(env))
+    {
+        OIC_LOG(INFO, TAG, "startScan has failed");
+        (*env)->DeleteLocalRef(env, jni_obj_leScanner);
+        goto error_exit;
+    }
+    res = CA_STATUS_OK;
+    (*env)->DeleteLocalRef(env, jni_obj_leScanner);
+
+error_exit:
+    (*env)->DeleteLocalRef(env, jni_cid_BTAdapter);
+    (*env)->DeleteLocalRef(env, jni_obj_BTAdapter);
+    (*env)->DeleteLocalRef(env, jni_cid_leScanner);
+    return res;
+}
+
 CAResult_t CALEClientStartScanWithUUIDImpl(JNIEnv *env, jobjectArray uuids, jobject callback)
 {
+    OIC_LOG(DEBUG, TAG, "CALEClientStartScanWithUUIDImpl IN");
     VERIFY_NON_NULL(callback, TAG, "callback is null");
     VERIFY_NON_NULL(uuids, TAG, "uuids is null");
     VERIFY_NON_NULL(env, TAG, "env is null");
@@ -1434,6 +1694,7 @@ CAResult_t CALEClientStartScanWithUUIDImpl(JNIEnv *env, jobjectArray uuids, jobj
     if (!jni_cid_BTAdapter)
     {
         OIC_LOG(ERROR, TAG, "getState From BTAdapter: jni_cid_BTAdapter is null");
+        CACheckJNIException(env);
         return CA_STATUS_FAILED;
     }
 
@@ -1444,6 +1705,7 @@ CAResult_t CALEClientStartScanWithUUIDImpl(JNIEnv *env, jobjectArray uuids, jobj
     if (!jni_mid_getDefaultAdapter)
     {
         OIC_LOG(ERROR, TAG, "jni_mid_getDefaultAdapter is null");
+        CACheckJNIException(env);
         (*env)->DeleteLocalRef(env, jni_cid_BTAdapter);
         return CA_STATUS_FAILED;
     }
@@ -1455,6 +1717,7 @@ CAResult_t CALEClientStartScanWithUUIDImpl(JNIEnv *env, jobjectArray uuids, jobj
     if (!jni_mid_startLeScan)
     {
         OIC_LOG(ERROR, TAG, "startLeScan: jni_mid_startLeScan is null");
+        CACheckJNIException(env);
         (*env)->DeleteLocalRef(env, jni_cid_BTAdapter);
         return CA_STATUS_FAILED;
     }
@@ -1465,6 +1728,7 @@ CAResult_t CALEClientStartScanWithUUIDImpl(JNIEnv *env, jobjectArray uuids, jobj
     if (!jni_obj_BTAdapter)
     {
         OIC_LOG(ERROR, TAG, "getState From BTAdapter: jni_obj_BTAdapter is null");
+        CACheckJNIException(env);
         (*env)->DeleteLocalRef(env, jni_cid_BTAdapter);
         return CA_STATUS_FAILED;
     }
@@ -1476,6 +1740,7 @@ CAResult_t CALEClientStartScanWithUUIDImpl(JNIEnv *env, jobjectArray uuids, jobj
     if (!jni_obj_startLeScan)
     {
         OIC_LOG(INFO, TAG, "startLeScan has failed");
+        CACheckJNIException(env);
     }
     else
     {
@@ -1487,38 +1752,416 @@ CAResult_t CALEClientStartScanWithUUIDImpl(JNIEnv *env, jobjectArray uuids, jobj
     return CA_STATUS_OK;
 }
 
-jobject CALEClientGetUUIDObject(JNIEnv *env, const char* uuid)
+CAResult_t CALEClientStartScanWithUUIDImplForV21(JNIEnv *env, jobjectArray uuids, jobject callback)
 {
-    VERIFY_NON_NULL_RET(uuid, TAG, "uuid is null", NULL);
-    VERIFY_NON_NULL_RET(env, TAG, "env is null", NULL);
+    OIC_LOG(DEBUG, TAG, "CALEClientStartScanWithUUIDImplForV21 IN");
+    VERIFY_NON_NULL(callback, TAG, "callback is null");
+    VERIFY_NON_NULL(uuids, TAG, "uuids is null");
+    VERIFY_NON_NULL(env, TAG, "env is null");
 
-    // setting UUID
-    jclass jni_cid_uuid = (*env)->FindClass(env, CLASSPATH_BT_UUID);
-    if (!jni_cid_uuid)
+    if (!CALEIsEnableBTAdapter(env))
     {
-        OIC_LOG(ERROR, TAG, "jni_cid_uuid is null");
-        return NULL;
+        OIC_LOG(INFO, TAG, "BT adapter is not enabled");
+        return CA_ADAPTER_NOT_ENABLED;
     }
 
-    jmethodID jni_mid_fromString = (*env)->GetStaticMethodID(env, jni_cid_uuid, "fromString",
-                                                             "(Ljava/lang/String;)"
-                                                             "Ljava/util/UUID;");
-    if (!jni_mid_fromString)
+    // get bluetoothLeScanner class
+    jclass jni_cid_leScanner = (*env)->FindClass(env, CLASSPATH_LE_SCANNER);
+    if (!jni_cid_leScanner)
     {
-        OIC_LOG(ERROR, TAG, "jni_mid_fromString is null");
-        return NULL;
+        OIC_LOG(ERROR, TAG, "getState From leScanner: jni_cid_leScanner is null");
+        CACheckJNIException(env);
+        return CA_STATUS_FAILED;
     }
 
-    jstring jni_uuid = (*env)->NewStringUTF(env, uuid);
+    // get startScan(with UUID) method
+    jmethodID jni_mid_startScan = (*env)->GetMethodID(env, jni_cid_leScanner,
+                                                      "startScan",
+                                                      "(Ljava/util/List;"
+                                                      "Landroid/bluetooth/le/ScanSettings;"
+                                                      "Landroid/bluetooth/le/ScanCallback;"
+                                                      ")V");
+    if (!jni_mid_startScan)
+    {
+        OIC_LOG(ERROR, TAG, "startScan: jni_mid_startScan is null");
+        CACheckJNIException(env);
+        (*env)->DeleteLocalRef(env, jni_cid_leScanner);
+        return CA_STATUS_FAILED;
+    }
+    (*env)->DeleteLocalRef(env, jni_cid_leScanner);
+
+    // get scanfilter.Builder class id
+    jclass jni_cid_scanfilterBuilder = (*env)->FindClass(env,
+                                                         "android/bluetooth/le/"
+                                                         "ScanFilter$Builder");
+    if (!jni_cid_scanfilterBuilder)
+    {
+        OIC_LOG(ERROR, TAG, "scanfilter: jni_cid_scanfilterBuilder is null");
+        CACheckJNIException(env);
+        return CA_STATUS_FAILED;
+    }
+
+    // get scanfilter.Builder(ctor) method id
+    jmethodID jni_mid_scanfilterBuilderCtor = (*env)->GetMethodID(env, jni_cid_scanfilterBuilder,
+                                                                  "<init>", "()V");
+    if (!jni_mid_scanfilterBuilderCtor)
+    {
+        OIC_LOG(ERROR, TAG, "scanfilter: jni_cid_scanfilterBuilderCtor is null");
+        CACheckJNIException(env);
+        (*env)->DeleteLocalRef(env, jni_cid_scanfilterBuilder);
+        return CA_STATUS_FAILED;
+    }
+
+    // call scanfilter.Builder()
+    jobject jni_obj_scanfilterBuilder = (*env)->NewObject(env, jni_cid_scanfilterBuilder,
+                                                          jni_mid_scanfilterBuilderCtor);
+    if (!jni_obj_scanfilterBuilder)
+    {
+        OIC_LOG(ERROR, TAG, "scanfilter: jni_obj_scanfilterBuilder is null");
+        CACheckJNIException(env);
+        (*env)->DeleteLocalRef(env, jni_cid_scanfilterBuilder);
+        return CA_STATUS_FAILED;
+    }
+
+    // get scanfilter.Builder.setServiceUuid method id
+    jmethodID jni_mid_setServiceUuid = (*env)->GetMethodID(env, jni_cid_scanfilterBuilder,
+                                                           "setServiceUuid",
+                                                           "(Landroid/os/ParcelUuid;)Landroid/"
+                                                           "bluetooth/le/ScanFilter$Builder;");
+    if (!jni_mid_setServiceUuid)
+    {
+        OIC_LOG(ERROR, TAG, "scanfilter: jni_mid_setServiceUuid is null");
+        CACheckJNIException(env);
+        (*env)->DeleteLocalRef(env, jni_cid_scanfilterBuilder);
+        (*env)->DeleteLocalRef(env, jni_obj_scanfilterBuilder);
+        return CA_STATUS_FAILED;
+    }
+
+    // get scanfilter.Builder.build method id
+    jmethodID jni_mid_build_scanfilterBuilder = (*env)->GetMethodID(env,
+                                                                    jni_cid_scanfilterBuilder,
+                                                                    "build",
+                                                                    "()Landroid/bluetooth/le/"
+                                                                    "ScanFilter;");
+    if (!jni_mid_build_scanfilterBuilder)
+    {
+        OIC_LOG(ERROR, TAG, "scanfilter: jni_mid_build_scanfilterBuilder is null");
+        CACheckJNIException(env);
+        (*env)->DeleteLocalRef(env, jni_cid_scanfilterBuilder);
+        (*env)->DeleteLocalRef(env, jni_obj_scanfilterBuilder);
+        return CA_STATUS_FAILED;
+    }
+    (*env)->DeleteLocalRef(env, jni_cid_scanfilterBuilder);
+
+    // call ParcelUuid.fromSting(uuid)
+    jobject jni_obj_parcelUuid = CALEGetParcelUuidFromString(env, OIC_GATT_SERVICE_UUID);
+    if (!jni_obj_parcelUuid)
+    {
+        OIC_LOG(ERROR, TAG, "scanSettings: jni_obj_parcelUuid is null");
+        CACheckJNIException(env);
+        (*env)->DeleteLocalRef(env, jni_obj_scanfilterBuilder);
+        return CA_STATUS_FAILED;
+    }
+
+    // call setServiceUuid(uuid)
+    jobject jni_obj_setServiceUuid = (*env)->CallObjectMethod(env,
+                                                              jni_obj_scanfilterBuilder,
+                                                              jni_mid_setServiceUuid,
+                                                              jni_obj_parcelUuid);
+    if (!jni_obj_setServiceUuid)
+    {
+        OIC_LOG(ERROR, TAG, "scanfilter: jni_obj_setServiceUuid is null");
+        CACheckJNIException(env);
+        (*env)->DeleteLocalRef(env, jni_obj_scanfilterBuilder);
+        (*env)->DeleteLocalRef(env, jni_obj_parcelUuid);
+        return CA_STATUS_FAILED;
+    }
+    (*env)->DeleteLocalRef(env, jni_obj_parcelUuid);
+    (*env)->DeleteLocalRef(env, jni_obj_setServiceUuid);
+
+    // call build()
+    jobject jni_obj_scanfilter = (*env)->CallObjectMethod(env,
+                                                          jni_obj_scanfilterBuilder,
+                                                          jni_mid_build_scanfilterBuilder);
+    if (!jni_obj_scanfilter)
+    {
+        OIC_LOG(ERROR, TAG, "scanfilter: jni_obj_scanfilter is null");
+        CACheckJNIException(env);
+        (*env)->DeleteLocalRef(env, jni_obj_scanfilterBuilder);
+        return CA_STATUS_FAILED;
+    }
+    (*env)->DeleteLocalRef(env, jni_obj_scanfilterBuilder);
+
+    // get scanSettings.Builder class id
+    jclass jni_cid_scanSettingsBuilder = (*env)->FindClass(env,
+                                                          "android/bluetooth/le/"
+                                                          "ScanSettings$Builder");
+    if (!jni_cid_scanSettingsBuilder)
+    {
+        OIC_LOG(ERROR, TAG, "scanSettings: jni_cid_scanSettingsBuilder is null");
+        CACheckJNIException(env);
+        (*env)->DeleteLocalRef(env, jni_obj_scanfilter);
+        return CA_STATUS_FAILED;
+    }
+
+    // get scanSettings.Builder(ctor) method id
+    jmethodID jni_mid_scanSettingsBuilderCtor = (*env)->GetMethodID(env, jni_cid_scanSettingsBuilder,
+                                                                    "<init>", "()V");
+    if (!jni_mid_scanSettingsBuilderCtor)
+    {
+        OIC_LOG(ERROR, TAG, "scanSettings: jni_mid_scanSettingsBuilderCtor is null");
+        CACheckJNIException(env);
+        (*env)->DeleteLocalRef(env, jni_obj_scanfilter);
+        (*env)->DeleteLocalRef(env, jni_cid_scanSettingsBuilder);
+        return CA_STATUS_FAILED;
+    }
+
+    // get scanSettings.Builder.setScanMode method id
+    jmethodID jni_mid_setScanMode = (*env)->GetMethodID(env, jni_cid_scanSettingsBuilder,
+                                                        "setScanMode",
+                                                         "(I)Landroid/"
+                                                         "bluetooth/le/ScanSettings$Builder;");
+    if (!jni_mid_setScanMode)
+    {
+        OIC_LOG(ERROR, TAG, "scanSettings: jni_mid_setScanMode is null");
+        CACheckJNIException(env);
+        (*env)->DeleteLocalRef(env, jni_obj_scanfilter);
+        (*env)->DeleteLocalRef(env, jni_cid_scanSettingsBuilder);
+        return CA_STATUS_FAILED;
+    }
+
+    // get scanSettings.Builder.build method id
+    jmethodID jni_mid_build_scanSettings = (*env)->GetMethodID(env,
+                                                               jni_cid_scanSettingsBuilder,
+                                                               "build",
+                                                               "()Landroid/bluetooth/le/"
+                                                               "ScanSettings;");
+    if (!jni_mid_build_scanSettings)
+    {
+        OIC_LOG(ERROR, TAG, "scanSettings: jni_mid_build_scanSettings is null");
+        CACheckJNIException(env);
+        (*env)->DeleteLocalRef(env, jni_obj_scanfilter);
+        (*env)->DeleteLocalRef(env, jni_cid_scanSettingsBuilder);
+        return CA_STATUS_FAILED;
+    }
+
+    // call scanSettings.Builder()
+    jobject jni_obj_scanSettingBuilder = (*env)->NewObject(env, jni_cid_scanSettingsBuilder,
+                                                           jni_mid_scanSettingsBuilderCtor);
+    if (!jni_obj_scanSettingBuilder)
+    {
+        OIC_LOG(ERROR, TAG, "scanfilter: jni_obj_scanSettingBuilder is null");
+        CACheckJNIException(env);
+        (*env)->DeleteLocalRef(env, jni_obj_scanfilter);
+        (*env)->DeleteLocalRef(env, jni_cid_scanSettingsBuilder);
+        return CA_STATUS_FAILED;
+    }
+    (*env)->DeleteLocalRef(env, jni_cid_scanSettingsBuilder);
+
+    jclass jni_cid_arrayList = (*env)->FindClass(env, "java/util/ArrayList");
+    if (!jni_cid_arrayList)
+    {
+        OIC_LOG(ERROR, TAG, "ArrayList: jni_cid_arrayList is null");
+        CACheckJNIException(env);
+        (*env)->DeleteLocalRef(env, jni_obj_scanfilter);
+        (*env)->DeleteLocalRef(env, jni_obj_scanSettingBuilder);
+        return CA_STATUS_FAILED;
+    }
+
+    jmethodID jni_mid_arrayListCtor = (*env)->GetMethodID(env, jni_cid_arrayList, "<init>", "()V");
+    if (!jni_mid_arrayListCtor)
+    {
+        OIC_LOG(ERROR, TAG, "ArrayList: jni_mid_arrayListCtor is null");
+        CACheckJNIException(env);
+        (*env)->DeleteLocalRef(env, jni_obj_scanfilter);
+        (*env)->DeleteLocalRef(env, jni_cid_arrayList);
+        (*env)->DeleteLocalRef(env, jni_obj_scanSettingBuilder);
+        return CA_STATUS_FAILED;
+    }
+
+    jmethodID jni_mid_arrayListAdd = (*env)->GetMethodID(env, jni_cid_arrayList,
+                                                         "add", "(Ljava/lang/Object;)Z");
+    if (!jni_mid_arrayListAdd)
+    {
+        OIC_LOG(ERROR, TAG, "ArrayList: jni_mid_arrayListAdd is null");
+        CACheckJNIException(env);
+        (*env)->DeleteLocalRef(env, jni_obj_scanfilter);
+        (*env)->DeleteLocalRef(env, jni_cid_arrayList);
+        (*env)->DeleteLocalRef(env, jni_obj_scanSettingBuilder);
+        return CA_STATUS_FAILED;
+    }
+
+    jobject jni_obj_filterList = (*env)->NewObject(env, jni_cid_arrayList, jni_mid_arrayListCtor);
+    if (!jni_obj_filterList)
+    {
+        OIC_LOG(ERROR, TAG, "ArrayList: jni_obj_filterList is null");
+        (*env)->DeleteLocalRef(env, jni_obj_scanfilter);
+        (*env)->DeleteLocalRef(env, jni_cid_arrayList);
+        (*env)->DeleteLocalRef(env, jni_obj_scanSettingBuilder);
+        return CA_STATUS_FAILED;
+    }
+    (*env)->DeleteLocalRef(env, jni_cid_arrayList);
+
+    jboolean jni_bool_arrayListIsAdded = (*env)->CallBooleanMethod(env, jni_obj_filterList,
+                                                                   jni_mid_arrayListAdd,
+                                                                   jni_obj_scanfilter);
+    if (!jni_bool_arrayListIsAdded)
+    {
+        OIC_LOG(ERROR, TAG, "ArrayList: jni_bool_arrayListIsAdded is null");
+        (*env)->DeleteLocalRef(env, jni_obj_filterList);
+        (*env)->DeleteLocalRef(env, jni_obj_scanfilter);
+        (*env)->DeleteLocalRef(env, jni_obj_scanSettingBuilder);
+        return CA_STATUS_FAILED;
+    }
+    (*env)->DeleteLocalRef(env, jni_obj_scanfilter);
+
+    // get ScanSettings.SCAN_MODE_BALANCED jint value
+    jint jni_int_scanBalancedMode = CALEGetConstantsValue(env, CLASSPATH_LE_SCANSETTINGS,
+                                                          "SCAN_MODE_BALANCED");
+    CACheckJNIException(env);
+
+    // call setScanMode(SCAN_MODE_BALANCED)
+    jobject jni_obj_setScanMode = (*env)->CallObjectMethod(env, jni_obj_scanSettingBuilder,
+                                                           jni_mid_setScanMode,
+                                                           jni_int_scanBalancedMode);
+    if (!jni_obj_setScanMode)
+    {
+        OIC_LOG(ERROR, TAG, "scanfilter: jni_obj_setScanMode is null");
+        CACheckJNIException(env);
+        (*env)->DeleteLocalRef(env, jni_obj_scanSettingBuilder);
+        (*env)->DeleteLocalRef(env, jni_obj_filterList);
+        return CA_STATUS_FAILED;
+    }
+
+    // call build
+    jobject jni_obj_scanSettings = (*env)->CallObjectMethod(env, jni_obj_scanSettingBuilder,
+                                                                 jni_mid_build_scanSettings);
+    if (!jni_obj_scanSettings)
+    {
+        OIC_LOG(ERROR, TAG, "scanfilter: jni_obj_scanSettings is null");
+        (*env)->DeleteLocalRef(env, jni_obj_scanSettingBuilder);
+        (*env)->DeleteLocalRef(env, jni_obj_filterList);
+        return CA_STATUS_FAILED;
+    }
+    (*env)->DeleteLocalRef(env, jni_obj_scanSettingBuilder);
+
+    CAResult_t res = CA_STATUS_FAILED;
+    // get default bt adapter class
+    jclass jni_cid_BTAdapter = (*env)->FindClass(env, CLASSPATH_BT_ADAPTER);
+    if (!jni_cid_BTAdapter)
+    {
+        OIC_LOG(ERROR, TAG, "getState From BTAdapter: jni_cid_BTAdapter is null");
+        CACheckJNIException(env);
+        goto error_exit;
+    }
+
+    jmethodID jni_mid_getDefaultAdapter = (*env)->GetStaticMethodID(env, jni_cid_BTAdapter,
+                                                                    "getDefaultAdapter",
+                                                                    "()Landroid/bluetooth/"
+                                                                    "BluetoothAdapter;");
+    if (!jni_mid_getDefaultAdapter)
+    {
+        OIC_LOG(ERROR, TAG, "jni_mid_getDefaultAdapter is null");
+        CACheckJNIException(env);
+        (*env)->DeleteLocalRef(env, jni_cid_BTAdapter);
+        goto error_exit;
+    }
+
+    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");
+        CACheckJNIException(env);
+        (*env)->DeleteLocalRef(env, jni_cid_BTAdapter);
+        goto error_exit;
+    }
+
+    // get remote bt adapter method
+    jmethodID jni_mid_getBluetoothLeScanner = (*env)->GetMethodID(env, jni_cid_BTAdapter,
+                                                                  "getBluetoothLeScanner",
+                                                                  "()Landroid/bluetooth/"
+                                                                  "le/BluetoothLeScanner;");
+    if (!jni_mid_getBluetoothLeScanner)
+    {
+        OIC_LOG(ERROR, TAG, "jni_mid_getBluetoothLeScanner is null");
+        CACheckJNIException(env);
+        (*env)->DeleteLocalRef(env, jni_cid_BTAdapter);
+        (*env)->DeleteLocalRef(env, jni_obj_BTAdapter);
+        goto error_exit;
+    }
+
+    // get le scanner object
+    jobject jni_obj_leScanner = (*env)->CallObjectMethod(env, jni_obj_BTAdapter,
+                                                         jni_mid_getBluetoothLeScanner);
+    if (!jni_obj_leScanner)
+    {
+        OIC_LOG(ERROR, TAG, "jni_obj_leScanner is null");
+        CACheckJNIException(env);
+        (*env)->DeleteLocalRef(env, jni_cid_BTAdapter);
+        (*env)->DeleteLocalRef(env, jni_obj_BTAdapter);
+        goto error_exit;
+    }
+    (*env)->DeleteLocalRef(env, jni_cid_BTAdapter);
+    (*env)->DeleteLocalRef(env, jni_obj_BTAdapter);
+
+    // call startScan method
+    OIC_LOG(INFO, TAG, "CALL API - startScanWithUUID(for level 21)");
+    (*env)->CallVoidMethod(env, jni_obj_leScanner, jni_mid_startScan, jni_obj_filterList,
+                           jni_obj_scanSettings, callback);
+    if (CACheckJNIException(env))
+    {
+        OIC_LOG(INFO, TAG, "startScan has failed");
+    }
+    else
+    {
+        res = CA_STATUS_OK;
+    }
+    (*env)->DeleteLocalRef(env, jni_obj_leScanner);
+
+error_exit:
+    (*env)->DeleteLocalRef(env, jni_obj_scanSettings);
+    (*env)->DeleteLocalRef(env, jni_obj_filterList);
+    return res;
+}
+
+jobject CALEClientGetUUIDObject(JNIEnv *env, const char* uuid)
+{
+    VERIFY_NON_NULL_RET(uuid, TAG, "uuid is null", NULL);
+    VERIFY_NON_NULL_RET(env, TAG, "env is null", NULL);
+
+    // setting UUID
+    jclass jni_cid_uuid = (*env)->FindClass(env, CLASSPATH_BT_UUID);
+    if (!jni_cid_uuid)
+    {
+        OIC_LOG(ERROR, TAG, "jni_cid_uuid is null");
+        goto error_exit;
+    }
+
+    jmethodID jni_mid_fromString = (*env)->GetStaticMethodID(env, jni_cid_uuid, "fromString",
+                                                             "(Ljava/lang/String;)"
+                                                             "Ljava/util/UUID;");
+    if (!jni_mid_fromString)
+    {
+        OIC_LOG(ERROR, TAG, "jni_mid_fromString is null");
+        goto error_exit;
+    }
+
+    jstring jni_uuid = (*env)->NewStringUTF(env, uuid);
+    CACheckJNIException(env);
     jobject jni_obj_uuid = (*env)->CallStaticObjectMethod(env, jni_cid_uuid, jni_mid_fromString,
                                                           jni_uuid);
     if (!jni_obj_uuid)
     {
         OIC_LOG(ERROR, TAG, "jni_obj_uuid is null");
-        return NULL;
+        goto error_exit;
     }
 
     return jni_obj_uuid;
+
+error_exit:
+    CACheckJNIException(env);
+    return NULL;
 }
 
 CAResult_t CALEClientStopScan()
@@ -1534,7 +2177,6 @@ CAResult_t CALEClientStopScan()
     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)
         {
@@ -1544,7 +2186,17 @@ CAResult_t CALEClientStopScan()
         isAttached = true;
     }
 
-    CAResult_t ret = CALEClientStopScanImpl(env, g_leScanCallback);
+    CAResult_t ret = CA_STATUS_FAILED;
+
+    if (g_jniIntSdk >= BLE_SCAN_API_LEVEL)
+    {
+        ret = CALEClientStopScanImplForV21(env, g_leScanCallback);
+    }
+    else
+    {
+        ret = CALEClientStopScanImpl(env, g_leScanCallback);
+    }
+
     if (CA_STATUS_OK != ret)
     {
         if (CA_ADAPTER_NOT_ENABLED == ret)
@@ -1567,7 +2219,7 @@ CAResult_t CALEClientStopScan()
 
 CAResult_t CALEClientStopScanImpl(JNIEnv *env, jobject callback)
 {
-    OIC_LOG(DEBUG, TAG, "CALEClientStopScanImpl");
+    OIC_LOG(DEBUG, TAG, "CALEClientStopScanImpl IN");
     VERIFY_NON_NULL(callback, TAG, "callback is null");
     VERIFY_NON_NULL(env, TAG, "env is null");
 
@@ -1582,6 +2234,7 @@ CAResult_t CALEClientStopScanImpl(JNIEnv *env, jobject callback)
     if (!jni_cid_BTAdapter)
     {
         OIC_LOG(ERROR, TAG, "getState From BTAdapter: jni_cid_BTAdapter is null");
+        CACheckJNIException(env);
         return CA_STATUS_FAILED;
     }
 
@@ -1592,6 +2245,7 @@ CAResult_t CALEClientStopScanImpl(JNIEnv *env, jobject callback)
     if (!jni_mid_getDefaultAdapter)
     {
         OIC_LOG(ERROR, TAG, "jni_mid_getDefaultAdapter is null");
+        CACheckJNIException(env);
         (*env)->DeleteLocalRef(env, jni_cid_BTAdapter);
         return CA_STATUS_FAILED;
     }
@@ -1603,16 +2257,18 @@ CAResult_t CALEClientStopScanImpl(JNIEnv *env, jobject callback)
     if (!jni_mid_stopLeScan)
     {
         OIC_LOG(ERROR, TAG, "stopLeScan: jni_mid_stopLeScan is null");
+        CACheckJNIException(env);
         (*env)->DeleteLocalRef(env, jni_cid_BTAdapter);
         return CA_STATUS_FAILED;
     }
 
-    // gat bt adapter object
+    // get 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");
+        CACheckJNIException(env);
         (*env)->DeleteLocalRef(env, jni_cid_BTAdapter);
         return CA_STATUS_FAILED;
     }
@@ -1620,13 +2276,11 @@ CAResult_t CALEClientStopScanImpl(JNIEnv *env, jobject callback)
     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))
+    if (CACheckJNIException(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;
     }
 
@@ -1635,94 +2289,111 @@ CAResult_t CALEClientStopScanImpl(JNIEnv *env, jobject callback)
     return CA_STATUS_OK;
 }
 
-CAResult_t CALEClientSetFlagToState(JNIEnv *env, jstring jni_address, jint state_idx, jboolean flag)
+CAResult_t CALEClientStopScanImplForV21(JNIEnv *env, jobject callback)
 {
-    OIC_LOG(DEBUG, TAG, "IN - CALEClientSetFlagToState");
-    VERIFY_NON_NULL(env, TAG, "env");
-    VERIFY_NON_NULL(jni_address, TAG, "jni_address");
+    OIC_LOG(DEBUG, TAG, "CALEClientStopScanImplForV21 IN");
+    VERIFY_NON_NULL(callback, TAG, "callback is null");
+    VERIFY_NON_NULL(env, TAG, "env is null");
 
-    ca_mutex_lock(g_deviceStateListMutex);
+    if (!CALEIsEnableBTAdapter(env))
+    {
+        OIC_LOG(INFO, TAG, "BT adapter is not enabled");
+        return CA_ADAPTER_NOT_ENABLED;
+    }
 
-    char* address = (char*)(*env)->GetStringUTFChars(env, jni_address, NULL);
-    if (!address)
+    // get default bt adapter class
+    jclass jni_cid_BTAdapter = (*env)->FindClass(env, CLASSPATH_BT_ADAPTER);
+    if (!jni_cid_BTAdapter)
     {
-        OIC_LOG(ERROR, TAG, "address is not available");
+        OIC_LOG(ERROR, TAG, "getState From BTAdapter: jni_cid_BTAdapter is null");
+        CACheckJNIException(env);
         return CA_STATUS_FAILED;
     }
 
-    if (CALEClientIsDeviceInList(address))
+    jmethodID jni_mid_getDefaultAdapter = (*env)->GetStaticMethodID(env, jni_cid_BTAdapter,
+                                                                    "getDefaultAdapter",
+                                                                    "()Landroid/bluetooth/"
+                                                                    "BluetoothAdapter;");
+    if (!jni_mid_getDefaultAdapter)
     {
-        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, "%d flag is set : %d", state_idx, 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;
-        }
+        OIC_LOG(ERROR, TAG, "jni_mid_getDefaultAdapter is null");
+        CACheckJNIException(env);
+        (*env)->DeleteLocalRef(env, jni_cid_BTAdapter);
+        return CA_STATUS_FAILED;
     }
 
-    (*env)->ReleaseStringUTFChars(env, jni_address, address);
-    ca_mutex_unlock(g_deviceStateListMutex);
-    OIC_LOG(DEBUG, TAG, "OUT - CALEClientSetFlagToState");
-    return CA_STATUS_OK;
-}
+    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");
+        CACheckJNIException(env);
+        (*env)->DeleteLocalRef(env, jni_cid_BTAdapter);
+        return CA_STATUS_FAILED;
+    }
 
-jboolean CALEClientGetFlagFromState(JNIEnv *env, jstring jni_address, jint state_idx)
-{
-    OIC_LOG(DEBUG, TAG, "IN - CALEClientGetFlagFromState");
-    VERIFY_NON_NULL_RET(env, TAG, "env", false);
-    VERIFY_NON_NULL_RET(jni_address, TAG, "jni_address", false);
+    // get bluetoothLeScanner class
+    jclass jni_cid_leScanner = (*env)->FindClass(env, CLASSPATH_LE_SCANNER);
+    if (!jni_cid_leScanner)
+    {
+        OIC_LOG(ERROR, TAG, "getState From leScanner: jni_cid_leScanner is null");
+        CACheckJNIException(env);
+        (*env)->DeleteLocalRef(env, jni_cid_BTAdapter);
+        (*env)->DeleteLocalRef(env, jni_obj_BTAdapter);
+        return CA_STATUS_FAILED;
+    }
 
-    ca_mutex_lock(g_deviceStateListMutex);
+    // get remote bt adapter method
+    jmethodID jni_mid_getBluetoothLeScanner = (*env)->GetMethodID(env, jni_cid_BTAdapter,
+                                                                  "getBluetoothLeScanner",
+                                                                  "()Landroid/bluetooth/"
+                                                                  "le/BluetoothLeScanner;");
+    if (!jni_mid_getBluetoothLeScanner)
+    {
+        OIC_LOG(ERROR, TAG, "jni_mid_getBluetoothLeScanner is null");
+        CACheckJNIException(env);
+        (*env)->DeleteLocalRef(env, jni_cid_BTAdapter);
+        (*env)->DeleteLocalRef(env, jni_obj_BTAdapter);
+        (*env)->DeleteLocalRef(env, jni_cid_leScanner);
+        return CA_STATUS_FAILED;
+    }
+    (*env)->DeleteLocalRef(env, jni_cid_BTAdapter);
 
-    char* address = (char*)(*env)->GetStringUTFChars(env, jni_address, NULL);
-    if (!address)
+    // get stopScan(ScanCallback callback) method
+    jmethodID jni_mid_stopScan = (*env)->GetMethodID(env, jni_cid_leScanner, "stopScan",
+                                                      "(Landroid/bluetooth/le/ScanCallback;)V");
+    if (!jni_mid_stopScan)
     {
-        OIC_LOG(ERROR, TAG, "address is not available");
-        ca_mutex_unlock(g_deviceStateListMutex);
-        return JNI_FALSE;
+        OIC_LOG(ERROR, TAG, "stopScan: jni_mid_stopScan is null");
+        CACheckJNIException(env);
+        (*env)->DeleteLocalRef(env, jni_obj_BTAdapter);
+        (*env)->DeleteLocalRef(env, jni_cid_leScanner);
+        return CA_STATUS_FAILED;
     }
+    (*env)->DeleteLocalRef(env, jni_cid_leScanner);
 
-    CALEState_t* curState = CALEClientGetStateInfo(address);
-    (*env)->ReleaseStringUTFChars(env, jni_address, address);
-    if(!curState)
+    // gat le scanner object
+    jobject jni_obj_leScanner = (*env)->CallObjectMethod(env, jni_obj_BTAdapter,
+                                                         jni_mid_getBluetoothLeScanner);
+    if (!jni_obj_leScanner)
     {
-        OIC_LOG(INFO, TAG, "there is no information. auto connect flag is false");
-        ca_mutex_unlock(g_deviceStateListMutex);
-        return JNI_FALSE;
+        OIC_LOG(ERROR, TAG, "getState From BTAdapter: jni_obj_leScanner is null");
+        CACheckJNIException(env);
+        return CA_STATUS_FAILED;
     }
 
-    jboolean ret = JNI_FALSE;
-    switch(state_idx)
+    // call stopScan method
+    OIC_LOG(INFO, TAG, "CALL API - stopScan for level 21");
+    (*env)->CallVoidMethod(env, jni_obj_leScanner, jni_mid_stopScan, callback);
+    if (CACheckJNIException(env))
     {
-        case CA_LE_AUTO_CONNECT_FLAG:
-            ret = curState->autoConnectFlag;
-            break;
-        case CA_LE_DESCRIPTOR_FOUND:
-            ret = curState->isDescriptorFound;
-            break;
-        default:
-            break;
+        OIC_LOG(INFO, TAG, "stopScan for level 21 has failed");
+        (*env)->DeleteLocalRef(env, jni_obj_leScanner);
+        return CA_STATUS_FAILED;
     }
-    ca_mutex_unlock(g_deviceStateListMutex);
 
-    OIC_LOG_V(INFO, TAG, "%d flag is %d", state_idx, ret);
-    OIC_LOG(DEBUG, TAG, "OUT - CALEClientGetFlagFromState");
-    return ret;
+    (*env)->DeleteLocalRef(env, jni_obj_leScanner);
+    return CA_STATUS_OK;
 }
 
 CAResult_t CALEClientDirectConnect(JNIEnv *env, jobject bluetoothDevice, jboolean autoconnect)
@@ -1731,13 +2402,13 @@ CAResult_t CALEClientDirectConnect(JNIEnv *env, jobject bluetoothDevice, jboolea
     VERIFY_NON_NULL(env, TAG, "env is null");
     VERIFY_NON_NULL(bluetoothDevice, TAG, "bluetoothDevice is null");
 
-    ca_mutex_lock(g_threadSendMutex);
+    oc_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);
+        oc_mutex_unlock(g_threadSendMutex);
         return CA_STATUS_FAILED;
     }
 
@@ -1745,13 +2416,16 @@ CAResult_t CALEClientDirectConnect(JNIEnv *env, jobject bluetoothDevice, jboolea
     if (!address)
     {
         OIC_LOG(ERROR, TAG, "address is not available");
-        ca_mutex_unlock(g_threadSendMutex);
+        CACheckJNIException(env);
+        oc_mutex_unlock(g_threadSendMutex);
         return CA_STATUS_FAILED;
     }
 
     CAResult_t res = CA_STATUS_OK;
-    if(CALEClientIsValidState(address, CA_LE_CONNECTION_STATE,
-                              STATE_DISCONNECTED))
+    if(CALEIsValidState(address, CA_LE_CONNECTION_STATE,
+                        STATE_DISCONNECTED,
+                        g_deviceStateList,
+                        g_deviceStateListMutex))
     {
         jobject newGatt = CALEClientConnect(env, bluetoothDevice, autoconnect);
         if (NULL == newGatt)
@@ -1760,7 +2434,7 @@ CAResult_t CALEClientDirectConnect(JNIEnv *env, jobject bluetoothDevice, jboolea
             res = CA_STATUS_FAILED;
         }
     }
-    ca_mutex_unlock(g_threadSendMutex);
+    oc_mutex_unlock(g_threadSendMutex);
 
     return res;
 }
@@ -1771,6 +2445,14 @@ jobject CALEClientConnect(JNIEnv *env, jobject bluetoothDevice, jboolean autocon
     VERIFY_NON_NULL_RET(env, TAG, "env is null", NULL);
     VERIFY_NON_NULL_RET(bluetoothDevice, TAG, "bluetoothDevice is null", NULL);
 
+    // reset scan interval time after checking scanned devices
+    CALERestartScanWithInterval(0, 0, BLE_SCAN_DISABLE);
+
+    // since there is no callback related stop success
+    // and scanning should be stopped before connectGatt is called.
+    // it should wait a few micro seconds.
+    usleep(100000);
+
     // get gatt object from Bluetooth Device object for closeProfileProxy(..)
     jstring jni_address = CALEClientGetLEAddressFromBTDevice(env, bluetoothDevice);
     if (jni_address)
@@ -1849,38 +2531,104 @@ jobject CALEClientGattConnect(JNIEnv *env, jobject bluetoothDevice, jboolean aut
         return NULL;
     }
 
-    // get BluetoothDevice method
-    OIC_LOG(DEBUG, TAG, "get BluetoothDevice method");
-    jmethodID jni_mid_connectGatt = CAGetJNIMethodID(env, "android/bluetooth/BluetoothDevice",
-                                                     "connectGatt",
-                                                     "(Landroid/content/Context;ZLandroid/"
-                                                     "bluetooth/BluetoothGattCallback;)"
-                                                     "Landroid/bluetooth/BluetoothGatt;");
-    if (!jni_mid_connectGatt)
+    jobject jni_obj_connectGatt = NULL;
+    jint jni_int_sdk = CALEGetBuildVersion(env);
+    OIC_LOG_V(INFO, TAG, "API level is %d", jni_int_sdk);
+    if (jni_int_sdk >= 23) // upper than API level 23
     {
-        OIC_LOG(ERROR, TAG, "bleConnect: jni_mid_connectGatt is null");
-        return NULL;
-    }
+        jmethodID jni_mid_connectGatt = CAGetJNIMethodID(env, "android/bluetooth/BluetoothDevice",
+                                                         "connectGatt",
+                                                         "(Landroid/content/Context;ZLandroid/"
+                                                         "bluetooth/BluetoothGattCallback;I)"
+                                                         "Landroid/bluetooth/BluetoothGatt;");
+        if (!jni_mid_connectGatt)
+        {
+            OIC_LOG(ERROR, TAG, "bleConnect: jni_mid_connectGatt is null");
+            return NULL;
+        }
 
-    OIC_LOG(INFO, TAG, "CALL API - connectGatt");
-    jobject jni_obj_connectGatt = (*env)->CallObjectMethod(env, bluetoothDevice,
-                                                           jni_mid_connectGatt,
-                                                           NULL,
-                                                           autoconnect, g_leGattCallback);
-    if (!jni_obj_connectGatt)
-    {
-        OIC_LOG(ERROR, TAG, "connectGatt was failed..it will be removed");
-        CALEClientRemoveDeviceInScanDeviceList(env, jni_address);
-        CALEClientUpdateSendCnt(env);
-        return NULL;
+        jint jni_transport_le = CALEGetConstantsValue(env, CLASSPATH_BT_DEVICE, "TRANSPORT_LE");
+        OIC_LOG_V(INFO, TAG, "CALL API - connectGatt with transport LE(%d)", jni_transport_le);
+        jni_obj_connectGatt = (*env)->CallObjectMethod(env, bluetoothDevice,
+                                                       jni_mid_connectGatt, NULL,
+                                                       autoconnect, g_leGattCallback,
+                                                       jni_transport_le);
+        if (!jni_obj_connectGatt)
+        {
+            OIC_LOG(ERROR, TAG, "connectGatt was failed..it will be removed");
+            CACheckJNIException(env);
+            CALEClientRemoveDeviceInScanDeviceList(env, jni_address);
+            CALEClientUpdateSendCnt(env);
+            return NULL;
+        }
+        else
+        {
+            OIC_LOG(DEBUG, TAG, "le connecting..please wait..");
+        }
     }
-    else
+    else // lower than API level 23
     {
-        OIC_LOG(DEBUG, TAG, "le connecting..please wait..");
+#ifdef HIDDEN_API
+        const char* address = (*env)->GetStringUTFChars(env, jni_address, NULL);
+        if (!address)
+        {
+            OIC_LOG(ERROR, TAG, "GetStringUTFChars has failed");
+            return NULL;
+        }
+        OIC_LOG(INFO, TAG, "CALL API - connectGatt for hidden");
+        jni_obj_connectGatt = CALEClientHiddenConnectGatt(bluetoothDevice, address, autoconnect);
+
+#else
+
+        jmethodID jni_mid_connectGatt = CAGetJNIMethodID(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 NULL;
+        }
+
+        OIC_LOG(INFO, TAG, "CALL API - connectGatt");
+        jni_obj_connectGatt = (*env)->CallObjectMethod(env, bluetoothDevice,
+                                                               jni_mid_connectGatt,
+                                                               NULL,
+                                                               autoconnect, g_leGattCallback);
+#endif
+        if (!jni_obj_connectGatt)
+        {
+            OIC_LOG(ERROR, TAG, "connectGatt was failed..it will be removed");
+            CACheckJNIException(env);
+            CALEClientRemoveDeviceInScanDeviceList(env, jni_address);
+            CALEClientUpdateSendCnt(env);
+            return NULL;
+        }
+        else
+        {
+            OIC_LOG(DEBUG, TAG, "le connecting..please wait..");
+        }
+
     }
+
     return jni_obj_connectGatt;
 }
 
+bool CALEClientIsConnected(const char* address)
+{
+    if (CALEIsValidState(address, CA_LE_CONNECTION_STATE,
+                         STATE_SERVICE_CONNECTED,
+                         g_deviceStateList,
+                         g_deviceStateListMutex))
+    {
+        OIC_LOG(DEBUG, TAG, "current state is connected");
+        return true;
+    }
+    OIC_LOG(DEBUG, TAG, "current state is not connected");
+    return false;
+}
+
 CAResult_t CALEClientCloseProfileProxy(JNIEnv *env, jobject gatt)
 {
     OIC_LOG(DEBUG, TAG, "IN - CALEClientCloseProfileProxy");
@@ -1892,7 +2640,7 @@ CAResult_t CALEClientCloseProfileProxy(JNIEnv *env, jobject gatt)
     if (!jni_cid_BTAdapter)
     {
         OIC_LOG(ERROR, TAG, "jni_cid_BTAdapter is null");
-        return CA_STATUS_FAILED;
+        goto error_exit;
     }
 
     // get remote bt adapter method
@@ -1902,7 +2650,7 @@ CAResult_t CALEClientCloseProfileProxy(JNIEnv *env, jobject gatt)
     if (!jni_mid_getDefaultAdapter)
     {
         OIC_LOG(ERROR, TAG, "jni_mid_getDefaultAdapter is null");
-        return CA_STATUS_FAILED;
+        goto error_exit;
     }
 
     // gat bt adapter object
@@ -1911,7 +2659,7 @@ CAResult_t CALEClientCloseProfileProxy(JNIEnv *env, jobject gatt)
     if (!jni_obj_BTAdapter)
     {
         OIC_LOG(ERROR, TAG, "jni_obj_BTAdapter is null");
-        return CA_STATUS_FAILED;
+        goto error_exit;
     }
 
     // get closeProfileProxy method
@@ -1922,14 +2670,14 @@ CAResult_t CALEClientCloseProfileProxy(JNIEnv *env, jobject gatt)
     if (!jni_mid_closeProfileProxy)
     {
         OIC_LOG(ERROR, TAG, "jni_mid_closeProfileProxy is null");
-        return CA_STATUS_FAILED;
+        goto error_exit;
     }
 
     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;
+        goto error_exit;
     }
 
     // GATT - Constant value : 7 (0x00000007)
@@ -1938,23 +2686,26 @@ CAResult_t CALEClientCloseProfileProxy(JNIEnv *env, jobject gatt)
     if (!id_gatt)
     {
         OIC_LOG(ERROR, TAG, "id_gatt is null");
-        return CA_STATUS_FAILED;
+        goto error_exit;
     }
 
     jint jni_gatt = (*env)->GetStaticIntField(env, jni_cid_BTProfile, id_gatt);
+    CACheckJNIException(env);
 
     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))
+    if (CACheckJNIException(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;
+
+error_exit:
+    CACheckJNIException(env);
+    return CA_STATUS_FAILED;
 }
 
 
@@ -1977,11 +2728,9 @@ CAResult_t CALEClientDisconnect(JNIEnv *env, jobject bluetoothGatt)
     // call disconnect gatt method
     OIC_LOG(INFO, TAG, "CALL API - disconnect");
     (*env)->CallVoidMethod(env, bluetoothGatt, jni_mid_disconnectGatt);
-    if ((*env)->ExceptionCheck(env))
+    if (CACheckJNIException(env))
     {
         OIC_LOG(ERROR, TAG, "disconnect has failed");
-        (*env)->ExceptionDescribe(env);
-        (*env)->ExceptionClear(env);
         return CA_STATUS_FAILED;
     }
 
@@ -2038,6 +2787,7 @@ CAResult_t CALEClientDisconnectforAddress(JNIEnv *env, jstring remote_address)
     if (!address)
     {
         OIC_LOG(ERROR, TAG, "address is null");
+        CACheckJNIException(env);
         return CA_STATUS_FAILED;
     }
 
@@ -2063,12 +2813,13 @@ CAResult_t CALEClientDisconnectforAddress(JNIEnv *env, jstring remote_address)
         if (!setAddress)
         {
             OIC_LOG(ERROR, TAG, "setAddress is null");
+            CACheckJNIException(env);
             (*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))
+        if (!strcasecmp(address, setAddress))
         {
             CAResult_t res = CALEClientDisconnect(env, jarrayObj);
             if (CA_STATUS_OK != res)
@@ -2090,6 +2841,40 @@ CAResult_t CALEClientDisconnectforAddress(JNIEnv *env, jstring remote_address)
     return CA_STATUS_OK;
 }
 
+CAResult_t CALEClientRequestMTU(JNIEnv *env, jobject bluetoothGatt, jint size)
+{
+    VERIFY_NON_NULL(env, TAG, "env is null");
+    VERIFY_NON_NULL(bluetoothGatt, TAG, "bluetoothGatt is null");
+
+    if (!CALEIsEnableBTAdapter(env))
+    {
+        OIC_LOG(INFO, TAG, "BT adapter is not enabled");
+        return CA_ADAPTER_NOT_ENABLED;
+    }
+
+    // get BluetoothGatt.requestMtu method
+    OIC_LOG(DEBUG, TAG, "get BluetoothGatt.requestMtu method");
+    jmethodID jni_mid_requestMtu = CAGetJNIMethodID(env, CLASSPATH_BT_GATT,
+                                                    "requestMtu", "(I)Z");
+    if (!jni_mid_requestMtu)
+    {
+        OIC_LOG(ERROR, TAG, "jni_mid_requestMtu is null");
+        return CA_STATUS_FAILED;
+    }
+
+    // call requestMtu
+    OIC_LOG(INFO, TAG, "CALL API - requestMtu");
+    jboolean ret = (*env)->CallBooleanMethod(env, bluetoothGatt, jni_mid_requestMtu, size);
+    if (!ret)
+    {
+        OIC_LOG(ERROR, TAG, "requestMtu has failed");
+        CACheckJNIException(env);
+        return CA_STATUS_FAILED;
+    }
+
+    return CA_STATUS_OK;
+}
+
 CAResult_t CALEClientDiscoverServices(JNIEnv *env, jobject bluetoothGatt)
 {
     VERIFY_NON_NULL(env, TAG, "env is null");
@@ -2117,6 +2902,7 @@ CAResult_t CALEClientDiscoverServices(JNIEnv *env, jobject bluetoothGatt)
     if (!ret)
     {
         OIC_LOG(ERROR, TAG, "discoverServices has not been started");
+        CACheckJNIException(env);
         return CA_STATUS_FAILED;
     }
 
@@ -2132,7 +2918,6 @@ static void CALEWriteCharacteristicThread(void* object)
     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)
@@ -2173,42 +2958,71 @@ CAResult_t CALESetValueAndWriteCharacteristic(JNIEnv* env, jobject gatt)
     const char* address = (*env)->GetStringUTFChars(env, jni_address, NULL);
     if (!address)
     {
+        CACheckJNIException(env);
         CALEClientSendFinish(env, gatt);
         return CA_STATUS_FAILED;
     }
 
-    ca_mutex_lock(g_threadSendStateMutex);
+    oc_mutex_lock(g_threadSendStateMutex);
 
-    if (CALEClientIsValidState(address, CA_LE_SEND_STATE, STATE_SENDING))
+    if (CALEIsValidState(address, CA_LE_SEND_STATE, STATE_SENDING,
+                         g_deviceStateList,
+                         g_deviceStateListMutex))
     {
         OIC_LOG(INFO, TAG, "current state is SENDING");
         (*env)->ReleaseStringUTFChars(env, jni_address, address);
-        ca_mutex_unlock(g_threadSendStateMutex);
+        oc_mutex_unlock(g_threadSendStateMutex);
         return CA_STATUS_OK;
     }
 
-    if (CA_STATUS_OK != CALEClientUpdateDeviceState(address, CA_LE_SEND_STATE,
-                                                    STATE_SENDING))
+    if (CA_STATUS_OK != CALEUpdateDeviceState(address, CA_LE_SEND_STATE,
+                                              STATE_SENDING,
+                                              g_deviceStateList,
+                                              g_deviceStateListMutex))
     {
-        OIC_LOG(ERROR, TAG, "CALEClientUpdateDeviceState has failed");
+        OIC_LOG(ERROR, TAG, "CALEUpdateDeviceState has failed");
         (*env)->ReleaseStringUTFChars(env, jni_address, address);
         CALEClientSendFinish(env, gatt);
-        ca_mutex_unlock(g_threadSendStateMutex);
+        oc_mutex_unlock(g_threadSendStateMutex);
         return CA_STATUS_FAILED;
     }
 
     (*env)->ReleaseStringUTFChars(env, jni_address, address);
 
-    ca_mutex_unlock(g_threadSendStateMutex);
+    oc_mutex_unlock(g_threadSendStateMutex);
+
+    jbyteArray sendData = NULL;
+    oc_mutex_lock(g_setValueMutex);
+    if (g_sendBuffer)
+    {
+        OIC_LOG(INFO, TAG, "alloc local reference for data");
+        sendData = (jbyteArray)(*env)->NewLocalRef(env, g_sendBuffer);
+    }
+    else
+    {
+        OIC_LOG(ERROR, TAG, "send Buffer is empty");
+        oc_mutex_unlock(g_setValueMutex);
+        return CA_STATUS_FAILED;
+    }
+    oc_mutex_unlock(g_setValueMutex);
 
     // send data
-    jobject jni_obj_character = CALEClientCreateGattCharacteristic(env, gatt, g_sendBuffer);
+    jobject jni_obj_character = CALEClientCreateGattCharacteristic(env, gatt, sendData);
     if (!jni_obj_character)
     {
+        if (sendData)
+        {
+            (*env)->DeleteLocalRef(env, sendData);
+        }
         CALEClientSendFinish(env, gatt);
         return CA_STATUS_FAILED;
     }
 
+    if (sendData)
+    {
+        (*env)->DeleteLocalRef(env, sendData);
+    }
+
     CAResult_t ret = CALEClientWriteCharacteristicImpl(env, gatt, jni_obj_character);
     if (CA_STATUS_OK != ret)
     {
@@ -2218,23 +3032,23 @@ CAResult_t CALESetValueAndWriteCharacteristic(JNIEnv* env, jobject gatt)
 
     // 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);
+    oc_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,
+        if (OC_WAIT_SUCCESS != oc_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);
+            oc_mutex_unlock(g_threadWriteCharacteristicMutex);
             return CA_STATUS_FAILED;
         }
     }
     // reset flag set by writeCharacteristic Callback
     g_isSignalSetFlag = false;
-    ca_mutex_unlock(g_threadWriteCharacteristicMutex);
+    oc_mutex_unlock(g_threadWriteCharacteristicMutex);
 
     CALEClientUpdateSendCnt(env);
 
@@ -2249,8 +3063,9 @@ CAResult_t CALEClientWriteCharacteristic(JNIEnv *env, jobject gatt)
     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))
+    CACheckJNIException(env);
+    if (CA_STATUS_OK != ca_thread_pool_add_task(g_threadPoolHandle, CALEWriteCharacteristicThread,
+                                                (void*)gattParam, NULL))
     {
         OIC_LOG(ERROR, TAG, "Failed to create read thread!");
         return CA_STATUS_FAILED;
@@ -2297,6 +3112,7 @@ CAResult_t CALEClientWriteCharacteristicImpl(JNIEnv *env, jobject bluetoothGatt,
     }
     else
     {
+        CACheckJNIException(env);
         OIC_LOG(ERROR, TAG, "writeCharacteristic has failed");
         return CA_STATUS_FAILED;
     }
@@ -2319,6 +3135,7 @@ CAResult_t CALEClientReadCharacteristic(JNIEnv *env, jobject bluetoothGatt)
     if (!jni_uuid)
     {
         OIC_LOG(ERROR, TAG, "jni_uuid is null");
+        CACheckJNIException(env);
         return CA_STATUS_FAILED;
     }
 
@@ -2351,6 +3168,7 @@ CAResult_t CALEClientReadCharacteristic(JNIEnv *env, jobject bluetoothGatt)
     else
     {
         OIC_LOG(ERROR, TAG, "readCharacteristic has failed");
+        CACheckJNIException(env);
         return CA_STATUS_FAILED;
     }
 
@@ -2392,6 +3210,7 @@ CAResult_t CALEClientSetCharacteristicNotification(JNIEnv *env, jobject bluetoot
     else
     {
         OIC_LOG(ERROR, TAG, "setCharacteristicNotification has failed");
+        CACheckJNIException(env);
         return CA_STATUS_FAILED;
     }
 
@@ -2436,6 +3255,7 @@ jobject CALEClientGetGattService(JNIEnv *env, jobject bluetoothGatt, jstring cha
     if (!jni_obj_gattService)
     {
         OIC_LOG(ERROR, TAG, "jni_obj_gattService is null");
+        CACheckJNIException(env);
         return NULL;
     }
 
@@ -2456,6 +3276,7 @@ jobject CALEClientGetGattService(JNIEnv *env, jobject bluetoothGatt, jstring cha
     if (!uuid)
     {
         OIC_LOG(ERROR, TAG, "uuid is null");
+        CACheckJNIException(env);
         return NULL;
     }
 
@@ -2467,10 +3288,16 @@ jobject CALEClientGetGattService(JNIEnv *env, jobject bluetoothGatt, jstring cha
         return NULL;
     }
 
-    OIC_LOG(DEBUG, TAG, "request to get Characteristic");
+    OIC_LOG(DEBUG, TAG, "CALL API getCharacteristic");
     jobject jni_obj_GattCharacteristic = (*env)->CallObjectMethod(env, jni_obj_gattService,
                                                                   jni_mid_getCharacteristic,
                                                                   jni_obj_tx_uuid);
+    if (!jni_obj_GattCharacteristic)
+    {
+        OIC_LOG(ERROR, TAG, "getCharacteristic has failed");
+        CACheckJNIException(env);
+        return NULL;
+    }
 
     (*env)->ReleaseStringUTFChars(env, characterUUID, uuid);
     return jni_obj_GattCharacteristic;
@@ -2493,7 +3320,7 @@ jobject CALEClientCreateGattCharacteristic(JNIEnv *env, jobject bluetoothGatt, j
     if (!jni_uuid)
     {
         OIC_LOG(ERROR, TAG, "jni_uuid is null");
-        return NULL;
+        goto error_exit;
     }
 
     jobject jni_obj_GattCharacteristic = CALEClientGetGattService(env, bluetoothGatt, jni_uuid);
@@ -2508,7 +3335,7 @@ jobject CALEClientCreateGattCharacteristic(JNIEnv *env, jobject bluetoothGatt, j
     if (!jni_cid_BTGattCharacteristic)
     {
         OIC_LOG(ERROR, TAG, "jni_cid_BTGattCharacteristic is null");
-        return NULL;
+        goto error_exit;
     }
 
     OIC_LOG(DEBUG, TAG, "set value in Characteristic");
@@ -2517,9 +3344,10 @@ jobject CALEClientCreateGattCharacteristic(JNIEnv *env, jobject bluetoothGatt, j
     if (!jni_mid_setValue)
     {
         OIC_LOG(ERROR, TAG, "jni_mid_setValue is null");
-        return NULL;
+        goto error_exit;
     }
 
+    OIC_LOG(DEBUG, TAG, "CALL API - setValue");
     jboolean ret = (*env)->CallBooleanMethod(env, jni_obj_GattCharacteristic, jni_mid_setValue,
                                              data);
     if (JNI_TRUE == ret)
@@ -2529,32 +3357,49 @@ jobject CALEClientCreateGattCharacteristic(JNIEnv *env, jobject bluetoothGatt, j
     else
     {
         OIC_LOG(ERROR, TAG, "the locally stored value hasn't been set");
-        return NULL;
+        goto error_exit;
     }
 
-    // set Write Type
-    jmethodID jni_mid_setWriteType = (*env)->GetMethodID(env, jni_cid_BTGattCharacteristic,
-                                                         "setWriteType", "(I)V");
-    if (!jni_mid_setWriteType)
+    if (!g_setHighQoS)
     {
-        OIC_LOG(ERROR, TAG, "jni_mid_setWriteType is null");
-        return NULL;
-    }
+        OIC_LOG(DEBUG, TAG, "setWriteType with WRITE_TYPE_NO_RESPONSE");
+        // set Write Type
+        jmethodID jni_mid_setWriteType = (*env)->GetMethodID(env, jni_cid_BTGattCharacteristic,
+                                                             "setWriteType", "(I)V");
+        if (!jni_mid_setWriteType)
+        {
+            OIC_LOG(ERROR, TAG, "jni_mid_setWriteType is null");
+            goto error_exit;
+        }
 
-    jfieldID jni_fid_no_response = (*env)->GetStaticFieldID(env, jni_cid_BTGattCharacteristic,
-                                                            "WRITE_TYPE_NO_RESPONSE", "I");
-    if (!jni_fid_no_response)
-    {
-        OIC_LOG(ERROR, TAG, "jni_fid_no_response is not available");
-        return NULL;
-    }
+        jfieldID jni_fid_no_response = (*env)->GetStaticFieldID(env, jni_cid_BTGattCharacteristic,
+                                                                "WRITE_TYPE_NO_RESPONSE", "I");
+        if (!jni_fid_no_response)
+        {
+            OIC_LOG(ERROR, TAG, "jni_fid_no_response is not available");
+            goto error_exit;
+        }
 
-    jint jni_int_val = (*env)->GetStaticIntField(env, jni_cid_BTGattCharacteristic,
-                                                 jni_fid_no_response);
+        jint jni_int_val = (*env)->GetStaticIntField(env, jni_cid_BTGattCharacteristic,
+                                                     jni_fid_no_response);
+        CACheckJNIException(env);
 
-    (*env)->CallVoidMethod(env, jni_obj_GattCharacteristic, jni_mid_setWriteType, jni_int_val);
+        (*env)->CallVoidMethod(env, jni_obj_GattCharacteristic, jni_mid_setWriteType, jni_int_val);
+        if (CACheckJNIException(env))
+        {
+            OIC_LOG(ERROR, TAG, "setWriteType has failed");
+        }
+    }
+    else
+    {
+        OIC_LOG(DEBUG, TAG, "It will run with response property");
+    }
 
     return jni_obj_GattCharacteristic;
+
+error_exit:
+    CACheckJNIException(env);
+    return NULL;
 }
 
 jbyteArray CALEClientGetValueFromCharacteristic(JNIEnv *env, jobject characteristic)
@@ -2579,6 +3424,7 @@ jbyteArray CALEClientGetValueFromCharacteristic(JNIEnv *env, jobject characteris
 
     jbyteArray jni_obj_data_array = (*env)->CallObjectMethod(env, characteristic,
                                                              jni_mid_getValue);
+    CACheckJNIException(env);
     return jni_obj_data_array;
 }
 
@@ -2595,7 +3441,6 @@ CAResult_t CALEClientCreateUUIDList()
     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)
@@ -2611,6 +3456,7 @@ CAResult_t CALEClientCreateUUIDList()
     if (!jni_cid_uuid_list)
     {
         OIC_LOG(ERROR, TAG, "jni_cid_uuid_list is null");
+        CACheckJNIException(env);
         goto error_exit;
     }
 
@@ -2619,6 +3465,7 @@ CAResult_t CALEClientCreateUUIDList()
     if (!jni_obj_uuid_list)
     {
         OIC_LOG(ERROR, TAG, "jni_obj_uuid_list is null");
+        CACheckJNIException(env);
         goto error_exit;
     }
 
@@ -2632,6 +3479,7 @@ CAResult_t CALEClientCreateUUIDList()
     (*env)->SetObjectArrayElement(env, jni_obj_uuid_list, 0, jni_obj_uuid);
 
     g_uuidList = (jobjectArray)(*env)->NewGlobalRef(env, jni_obj_uuid_list);
+    CACheckJNIException(env);
 
     if (isAttached)
     {
@@ -2679,7 +3527,6 @@ CAResult_t CALEClientSetUUIDToDescriptor(JNIEnv *env, jobject bluetoothGatt,
     if (!jni_obj_cc_uuid)
     {
         OIC_LOG(ERROR, TAG, "jni_obj_cc_uuid is null");
-        return CA_STATUS_FAILED;
     }
 
     OIC_LOG(DEBUG, TAG, "request to get descriptor");
@@ -2688,7 +3535,7 @@ CAResult_t CALEClientSetUUIDToDescriptor(JNIEnv *env, jobject bluetoothGatt,
     if (!jni_obj_descriptor)
     {
         OIC_LOG(INFO, TAG, "jni_obj_descriptor is null");
-        return CA_NOT_SUPPORTED;
+        goto error_exit;
     }
 
     OIC_LOG(DEBUG, TAG, "set value in descriptor");
@@ -2697,25 +3544,39 @@ CAResult_t CALEClientSetUUIDToDescriptor(JNIEnv *env, jobject bluetoothGatt,
     if (!jni_cid_descriptor)
     {
         OIC_LOG(ERROR, TAG, "jni_cid_descriptor is null");
-        return CA_STATUS_FAILED;
+        goto error_exit;
     }
 
     jmethodID jni_mid_setValue = (*env)->GetMethodID(env, jni_cid_descriptor, "setValue", "([B)Z");
     if (!jni_mid_setValue)
     {
         OIC_LOG(ERROR, TAG, "jni_mid_setValue is null");
-        return CA_STATUS_FAILED;
+        goto error_exit;
     }
 
-    jfieldID jni_fid_NotiValue = (*env)->GetStaticFieldID(env, jni_cid_descriptor,
-                                                          "ENABLE_NOTIFICATION_VALUE", "[B");
-    if (!jni_fid_NotiValue)
+    jfieldID jni_fid_NotiValue = NULL;
+    if (g_setHighQoS)
     {
-        OIC_LOG(ERROR, TAG, "jni_fid_NotiValue is null");
-        return CA_STATUS_FAILED;
+        OIC_LOG(DEBUG, TAG, "get ENABLE_INDICATION_VALUE");
+        jni_fid_NotiValue = (*env)->GetStaticFieldID(env, jni_cid_descriptor,
+                                                     "ENABLE_INDICATION_VALUE", "[B");
+        if (!jni_fid_NotiValue)
+        {
+            OIC_LOG(ERROR, TAG, "jni_fid_NotiValue is null");
+            goto error_exit;
+        }
+    }
+    else
+    {
+        OIC_LOG(DEBUG, TAG, "get ENABLE_NOTIFICATION_VALUE");
+        jni_fid_NotiValue = (*env)->GetStaticFieldID(env, jni_cid_descriptor,
+                                                     "ENABLE_NOTIFICATION_VALUE", "[B");
+        if (!jni_fid_NotiValue)
+        {
+            OIC_LOG(ERROR, TAG, "jni_fid_NotiValue is null");
+            goto error_exit;
+        }
     }
-
-    OIC_LOG(DEBUG, TAG, "get ENABLE_NOTIFICATION_VALUE");
 
     jboolean jni_setvalue = (*env)->CallBooleanMethod(
             env, jni_obj_descriptor, jni_mid_setValue,
@@ -2727,7 +3588,7 @@ CAResult_t CALEClientSetUUIDToDescriptor(JNIEnv *env, jobject bluetoothGatt,
     else
     {
         OIC_LOG(ERROR, TAG, "setValue has failed");
-        return CA_STATUS_FAILED;
+        goto error_exit;
     }
 
     jmethodID jni_mid_writeDescriptor  = CAGetJNIMethodID(env, "android/bluetooth/BluetoothGatt",
@@ -2750,10 +3611,14 @@ CAResult_t CALEClientSetUUIDToDescriptor(JNIEnv *env, jobject bluetoothGatt,
     else
     {
         OIC_LOG(ERROR, TAG, "writeDescriptor has failed");
-        return CA_STATUS_FAILED;
+        goto error_exit;
     }
 
     return CA_STATUS_OK;
+
+error_exit:
+    CACheckJNIException(env);
+    return CA_STATUS_FAILED;
 }
 
 void CALEClientCreateScanDeviceList(JNIEnv *env)
@@ -2761,7 +3626,7 @@ void CALEClientCreateScanDeviceList(JNIEnv *env)
     OIC_LOG(DEBUG, TAG, "CALEClientCreateScanDeviceList");
     VERIFY_NON_NULL_VOID(env, TAG, "env is null");
 
-    ca_mutex_lock(g_deviceListMutex);
+    oc_mutex_lock(g_deviceListMutex);
     // create new object array
     if (g_deviceList == NULL)
     {
@@ -2769,7 +3634,7 @@ void CALEClientCreateScanDeviceList(JNIEnv *env)
 
         g_deviceList = u_arraylist_create();
     }
-    ca_mutex_unlock(g_deviceListMutex);
+    oc_mutex_unlock(g_deviceListMutex);
 }
 
 CAResult_t CALEClientAddScanDeviceToList(JNIEnv *env, jobject device)
@@ -2777,14 +3642,12 @@ CAResult_t CALEClientAddScanDeviceToList(JNIEnv *env, jobject device)
     VERIFY_NON_NULL(device, TAG, "device is null");
     VERIFY_NON_NULL(env, TAG, "env is null");
 
-    ca_mutex_lock(g_deviceListMutex);
+    oc_mutex_lock(g_deviceListMutex);
 
     if (!g_deviceList)
     {
         OIC_LOG(ERROR, TAG, "gdevice_list is null");
-        CALEClientStopScanWithInterval();
-
-        ca_mutex_unlock(g_deviceListMutex);
+        oc_mutex_unlock(g_deviceListMutex);
         return CA_STATUS_FAILED;
     }
 
@@ -2792,7 +3655,7 @@ CAResult_t CALEClientAddScanDeviceToList(JNIEnv *env, jobject device)
     if (!jni_remoteAddress)
     {
         OIC_LOG(ERROR, TAG, "jni_remoteAddress is null");
-        ca_mutex_unlock(g_deviceListMutex);
+        oc_mutex_unlock(g_deviceListMutex);
         return CA_STATUS_FAILED;
     }
 
@@ -2800,22 +3663,24 @@ CAResult_t CALEClientAddScanDeviceToList(JNIEnv *env, jobject device)
     if (!remoteAddress)
     {
         OIC_LOG(ERROR, TAG, "remoteAddress is null");
+        CACheckJNIException(env);
         (*env)->DeleteLocalRef(env, jni_remoteAddress);
-        ca_mutex_unlock(g_deviceListMutex);
+        oc_mutex_unlock(g_deviceListMutex);
         return CA_STATUS_FAILED;
     }
 
     if (!CALEClientIsDeviceInScanDeviceList(env, remoteAddress))
     {
         jobject gdevice = (*env)->NewGlobalRef(env, device);
+        CACheckJNIException(env);
         u_arraylist_add(g_deviceList, gdevice);
-        ca_cond_signal(g_deviceDescCond);
+        oc_cond_signal(g_deviceDescCond);
         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);
+    oc_mutex_unlock(g_deviceListMutex);
 
     return CA_STATUS_OK;
 }
@@ -2852,11 +3717,12 @@ bool CALEClientIsDeviceInScanDeviceList(JNIEnv *env, const char* remoteAddress)
         if (!setAddress)
         {
             OIC_LOG(ERROR, TAG, "setAddress is null");
+            CACheckJNIException(env);
             (*env)->DeleteLocalRef(env, jni_setAddress);
             return true;
         }
 
-        if (!strcmp(remoteAddress, setAddress))
+        if (!strcasecmp(remoteAddress, setAddress))
         {
             (*env)->ReleaseStringUTFChars(env, jni_setAddress, setAddress);
             (*env)->DeleteLocalRef(env, jni_setAddress);
@@ -2865,10 +3731,7 @@ bool CALEClientIsDeviceInScanDeviceList(JNIEnv *env, const char* remoteAddress)
 
         (*env)->ReleaseStringUTFChars(env, jni_setAddress, setAddress);
         (*env)->DeleteLocalRef(env, jni_setAddress);
-    }
-
-    OIC_LOG_V(DEBUG, TAG, "[%s] doesn't exist in scanned device list", remoteAddress);
-
+    }
     return false;
 }
 
@@ -2877,12 +3740,12 @@ CAResult_t CALEClientRemoveAllScanDevices(JNIEnv *env)
     OIC_LOG(DEBUG, TAG, "CALEClientRemoveAllScanDevices");
     VERIFY_NON_NULL(env, TAG, "env is null");
 
-    ca_mutex_lock(g_deviceListMutex);
+    oc_mutex_lock(g_deviceListMutex);
 
     if (!g_deviceList)
     {
         OIC_LOG(ERROR, TAG, "g_deviceList is null");
-        ca_mutex_unlock(g_deviceListMutex);
+        oc_mutex_unlock(g_deviceListMutex);
         return CA_STATUS_FAILED;
     }
 
@@ -2902,7 +3765,7 @@ CAResult_t CALEClientRemoveAllScanDevices(JNIEnv *env)
     OICFree(g_deviceList);
     g_deviceList = NULL;
 
-    ca_mutex_unlock(g_deviceListMutex);
+    oc_mutex_unlock(g_deviceListMutex);
     return CA_STATUS_OK;
 }
 
@@ -2912,12 +3775,12 @@ CAResult_t CALEClientRemoveDeviceInScanDeviceList(JNIEnv *env, jstring address)
     VERIFY_NON_NULL(address, TAG, "address is null");
     VERIFY_NON_NULL(env, TAG, "env is null");
 
-    ca_mutex_lock(g_deviceListMutex);
+    oc_mutex_lock(g_deviceListMutex);
 
     if (!g_deviceList)
     {
         OIC_LOG(ERROR, TAG, "g_deviceList is null");
-        ca_mutex_unlock(g_deviceListMutex);
+        oc_mutex_unlock(g_deviceListMutex);
         return CA_STATUS_FAILED;
     }
 
@@ -2928,7 +3791,7 @@ CAResult_t CALEClientRemoveDeviceInScanDeviceList(JNIEnv *env, jstring address)
         if (!jarrayObj)
         {
             OIC_LOG(ERROR, TAG, "jarrayObj is null");
-            ca_mutex_unlock(g_deviceListMutex);
+            oc_mutex_unlock(g_deviceListMutex);
             return CA_STATUS_FAILED;
         }
 
@@ -2936,7 +3799,7 @@ CAResult_t CALEClientRemoveDeviceInScanDeviceList(JNIEnv *env, jstring address)
         if (!jni_setAddress)
         {
             OIC_LOG(ERROR, TAG, "jni_setAddress is null");
-            ca_mutex_unlock(g_deviceListMutex);
+            oc_mutex_unlock(g_deviceListMutex);
             return CA_STATUS_FAILED;
         }
 
@@ -2944,7 +3807,8 @@ CAResult_t CALEClientRemoveDeviceInScanDeviceList(JNIEnv *env, jstring address)
         if (!setAddress)
         {
             OIC_LOG(ERROR, TAG, "setAddress is null");
-            ca_mutex_unlock(g_deviceListMutex);
+            CACheckJNIException(env);
+            oc_mutex_unlock(g_deviceListMutex);
             return CA_STATUS_FAILED;
         }
 
@@ -2952,12 +3816,13 @@ CAResult_t CALEClientRemoveDeviceInScanDeviceList(JNIEnv *env, jstring address)
         if (!remoteAddress)
         {
             OIC_LOG(ERROR, TAG, "remoteAddress is null");
+            CACheckJNIException(env);
             (*env)->ReleaseStringUTFChars(env, jni_setAddress, setAddress);
-            ca_mutex_unlock(g_deviceListMutex);
+            oc_mutex_unlock(g_deviceListMutex);
             return CA_STATUS_FAILED;
         }
 
-        if (!strcmp(setAddress, remoteAddress))
+        if (!strcasecmp(setAddress, remoteAddress))
         {
             OIC_LOG_V(DEBUG, TAG, "remove object : %s", remoteAddress);
             (*env)->DeleteGlobalRef(env, jarrayObj);
@@ -2968,17 +3833,17 @@ CAResult_t CALEClientRemoveDeviceInScanDeviceList(JNIEnv *env, jstring address)
             if (NULL == u_arraylist_remove(g_deviceList, index))
             {
                 OIC_LOG(ERROR, TAG, "List removal failed.");
-                ca_mutex_unlock(g_deviceListMutex);
+                oc_mutex_unlock(g_deviceListMutex);
                 return CA_STATUS_FAILED;
             }
-            ca_mutex_unlock(g_deviceListMutex);
+            oc_mutex_unlock(g_deviceListMutex);
             return CA_STATUS_OK;
         }
         (*env)->ReleaseStringUTFChars(env, jni_setAddress, setAddress);
         (*env)->ReleaseStringUTFChars(env, address, remoteAddress);
     }
 
-    ca_mutex_unlock(g_deviceListMutex);
+    oc_mutex_unlock(g_deviceListMutex);
     OIC_LOG(DEBUG, TAG, "There are no object in the device list");
 
     return CA_STATUS_OK;
@@ -2994,12 +3859,12 @@ CAResult_t CALEClientAddGattobjToList(JNIEnv *env, jobject gatt)
     VERIFY_NON_NULL(env, TAG, "env is null");
     VERIFY_NON_NULL(gatt, TAG, "gatt is null");
 
-    ca_mutex_lock(g_gattObjectMutex);
+    oc_mutex_lock(g_gattObjectMutex);
 
     if (!g_gattObjectList)
     {
         OIC_LOG(ERROR, TAG, "g_gattObjectList is not available");
-        ca_mutex_unlock(g_gattObjectMutex);
+        oc_mutex_unlock(g_gattObjectMutex);
         return CA_STATUS_FAILED;
     }
 
@@ -3007,7 +3872,7 @@ CAResult_t CALEClientAddGattobjToList(JNIEnv *env, jobject gatt)
     if (!jni_remoteAddress)
     {
         OIC_LOG(ERROR, TAG, "jni_remoteAddress is null");
-        ca_mutex_unlock(g_gattObjectMutex);
+        oc_mutex_unlock(g_gattObjectMutex);
         return CA_STATUS_FAILED;
     }
 
@@ -3015,7 +3880,9 @@ CAResult_t CALEClientAddGattobjToList(JNIEnv *env, jobject gatt)
     if (!remoteAddress)
     {
         OIC_LOG(ERROR, TAG, "remoteAddress is null");
-        ca_mutex_unlock(g_gattObjectMutex);
+        CACheckJNIException(env);
+        (*env)->DeleteLocalRef(env, jni_remoteAddress);
+        oc_mutex_unlock(g_gattObjectMutex);
         return CA_STATUS_FAILED;
     }
 
@@ -3028,20 +3895,19 @@ CAResult_t CALEClientAddGattobjToList(JNIEnv *env, jobject gatt)
     }
 
     (*env)->ReleaseStringUTFChars(env, jni_remoteAddress, remoteAddress);
-    ca_mutex_unlock(g_gattObjectMutex);
+    (*env)->DeleteLocalRef(env, jni_remoteAddress);
+    oc_mutex_unlock(g_gattObjectMutex);
     return CA_STATUS_OK;
 }
 
 bool CALEClientIsGattObjInList(JNIEnv *env, const char* remoteAddress)
 {
-    OIC_LOG(DEBUG, TAG, "CALEClientIsGattObjInList");
     VERIFY_NON_NULL(env, TAG, "env is null");
     VERIFY_NON_NULL_RET(remoteAddress, TAG, "remoteAddress is null", true);
 
     uint32_t length = u_arraylist_length(g_gattObjectList);
     for (uint32_t index = 0; index < length; index++)
     {
-
         jobject jarrayObj = (jobject) u_arraylist_get(g_gattObjectList, index);
         if (!jarrayObj)
         {
@@ -3060,20 +3926,20 @@ bool CALEClientIsGattObjInList(JNIEnv *env, const char* remoteAddress)
         if (!setAddress)
         {
             OIC_LOG(ERROR, TAG, "setAddress is null");
+            CACheckJNIException(env);
+            (*env)->DeleteLocalRef(env, jni_setAddress);
             return true;
         }
 
-        if (!strcmp(remoteAddress, setAddress))
+        if (!strcasecmp(remoteAddress, setAddress))
         {
             OIC_LOG(DEBUG, TAG, "the device is already set");
             (*env)->ReleaseStringUTFChars(env, jni_setAddress, setAddress);
+            (*env)->DeleteLocalRef(env, jni_setAddress);
             return true;
         }
-        else
-        {
-            (*env)->ReleaseStringUTFChars(env, jni_setAddress, setAddress);
-            continue;
-        }
+        (*env)->ReleaseStringUTFChars(env, jni_setAddress, setAddress);
+        (*env)->DeleteLocalRef(env, jni_setAddress);
     }
 
     OIC_LOG(DEBUG, TAG, "There are no GATT object in list. it can be added");
@@ -3086,7 +3952,7 @@ jobject CALEClientGetGattObjInList(JNIEnv *env, const char* remoteAddress)
     VERIFY_NON_NULL_RET(env, TAG, "env is null", NULL);
     VERIFY_NON_NULL_RET(remoteAddress, TAG, "remoteAddress is null", NULL);
 
-    ca_mutex_lock(g_gattObjectMutex);
+    oc_mutex_lock(g_gattObjectMutex);
     uint32_t length = u_arraylist_length(g_gattObjectList);
     for (uint32_t index = 0; index < length; index++)
     {
@@ -3094,7 +3960,7 @@ jobject CALEClientGetGattObjInList(JNIEnv *env, const char* remoteAddress)
         if (!jarrayObj)
         {
             OIC_LOG(ERROR, TAG, "jarrayObj is null");
-            ca_mutex_unlock(g_gattObjectMutex);
+            oc_mutex_unlock(g_gattObjectMutex);
             return NULL;
         }
 
@@ -3102,7 +3968,7 @@ jobject CALEClientGetGattObjInList(JNIEnv *env, const char* remoteAddress)
         if (!jni_setAddress)
         {
             OIC_LOG(ERROR, TAG, "jni_setAddress is null");
-            ca_mutex_unlock(g_gattObjectMutex);
+            oc_mutex_unlock(g_gattObjectMutex);
             return NULL;
         }
 
@@ -3110,21 +3976,24 @@ jobject CALEClientGetGattObjInList(JNIEnv *env, const char* remoteAddress)
         if (!setAddress)
         {
             OIC_LOG(ERROR, TAG, "setAddress is null");
-            ca_mutex_unlock(g_gattObjectMutex);
+            CACheckJNIException(env);
+            (*env)->DeleteLocalRef(env, jni_setAddress);
+            oc_mutex_unlock(g_gattObjectMutex);
             return NULL;
         }
 
-        if (!strcmp(remoteAddress, setAddress))
+        if (!strcasecmp(remoteAddress, setAddress))
         {
             OIC_LOG(DEBUG, TAG, "the device is already set");
             (*env)->ReleaseStringUTFChars(env, jni_setAddress, setAddress);
-            ca_mutex_unlock(g_gattObjectMutex);
+            oc_mutex_unlock(g_gattObjectMutex);
             return jarrayObj;
         }
         (*env)->ReleaseStringUTFChars(env, jni_setAddress, setAddress);
+        (*env)->DeleteLocalRef(env, jni_setAddress);
     }
 
-    ca_mutex_unlock(g_gattObjectMutex);
+    oc_mutex_unlock(g_gattObjectMutex);
     OIC_LOG(DEBUG, TAG, "There are no the gatt object in list");
     return NULL;
 }
@@ -3134,11 +4003,11 @@ CAResult_t CALEClientRemoveAllGattObjs(JNIEnv *env)
     OIC_LOG(DEBUG, TAG, "CALEClientRemoveAllGattObjs");
     VERIFY_NON_NULL(env, TAG, "env is null");
 
-    ca_mutex_lock(g_gattObjectMutex);
+    oc_mutex_lock(g_gattObjectMutex);
     if (!g_gattObjectList)
     {
         OIC_LOG(DEBUG, TAG, "already removed for g_gattObjectList");
-        ca_mutex_unlock(g_gattObjectMutex);
+        oc_mutex_unlock(g_gattObjectMutex);
         return CA_STATUS_OK;
     }
 
@@ -3158,7 +4027,7 @@ CAResult_t CALEClientRemoveAllGattObjs(JNIEnv *env)
     OICFree(g_gattObjectList);
     g_gattObjectList = NULL;
     OIC_LOG(INFO, TAG, "g_gattObjectList is removed");
-    ca_mutex_unlock(g_gattObjectMutex);
+    oc_mutex_unlock(g_gattObjectMutex);
     return CA_STATUS_OK;
 }
 
@@ -3168,11 +4037,11 @@ CAResult_t CALEClientRemoveGattObj(JNIEnv *env, jobject gatt)
     VERIFY_NON_NULL(gatt, TAG, "gatt is null");
     VERIFY_NON_NULL(env, TAG, "env is null");
 
-    ca_mutex_lock(g_gattObjectMutex);
+    oc_mutex_lock(g_gattObjectMutex);
     if (!g_gattObjectList)
     {
         OIC_LOG(DEBUG, TAG, "already removed for g_gattObjectList");
-        ca_mutex_unlock(g_gattObjectMutex);
+        oc_mutex_unlock(g_gattObjectMutex);
         return CA_STATUS_OK;
     }
 
@@ -3183,7 +4052,7 @@ CAResult_t CALEClientRemoveGattObj(JNIEnv *env, jobject gatt)
         if (!jarrayObj)
         {
             OIC_LOG(ERROR, TAG, "jarrayObj is null");
-            ca_mutex_unlock(g_gattObjectMutex);
+            oc_mutex_unlock(g_gattObjectMutex);
             return CA_STATUS_FAILED;
         }
 
@@ -3191,7 +4060,7 @@ CAResult_t CALEClientRemoveGattObj(JNIEnv *env, jobject gatt)
         if (!jni_setAddress)
         {
             OIC_LOG(ERROR, TAG, "jni_setAddress is null");
-            ca_mutex_unlock(g_gattObjectMutex);
+            oc_mutex_unlock(g_gattObjectMutex);
             return CA_STATUS_FAILED;
         }
 
@@ -3199,7 +4068,8 @@ CAResult_t CALEClientRemoveGattObj(JNIEnv *env, jobject gatt)
         if (!setAddress)
         {
             OIC_LOG(ERROR, TAG, "setAddress is null");
-            ca_mutex_unlock(g_gattObjectMutex);
+            CACheckJNIException(env);
+            oc_mutex_unlock(g_gattObjectMutex);
             return CA_STATUS_FAILED;
         }
 
@@ -3208,7 +4078,7 @@ CAResult_t CALEClientRemoveGattObj(JNIEnv *env, jobject gatt)
         {
             OIC_LOG(ERROR, TAG, "jni_remoteAddress is null");
             (*env)->ReleaseStringUTFChars(env, jni_setAddress, setAddress);
-            ca_mutex_unlock(g_gattObjectMutex);
+            oc_mutex_unlock(g_gattObjectMutex);
             return CA_STATUS_FAILED;
         }
 
@@ -3216,12 +4086,13 @@ CAResult_t CALEClientRemoveGattObj(JNIEnv *env, jobject gatt)
         if (!remoteAddress)
         {
             OIC_LOG(ERROR, TAG, "remoteAddress is null");
+            CACheckJNIException(env);
             (*env)->ReleaseStringUTFChars(env, jni_setAddress, setAddress);
-            ca_mutex_unlock(g_gattObjectMutex);
+            oc_mutex_unlock(g_gattObjectMutex);
             return CA_STATUS_FAILED;
         }
 
-        if (!strcmp(setAddress, remoteAddress))
+        if (!strcasecmp(setAddress, remoteAddress))
         {
             OIC_LOG_V(DEBUG, TAG, "remove object : %s", remoteAddress);
             (*env)->DeleteGlobalRef(env, jarrayObj);
@@ -3232,17 +4103,17 @@ CAResult_t CALEClientRemoveGattObj(JNIEnv *env, jobject gatt)
             if (NULL == u_arraylist_remove(g_gattObjectList, index))
             {
                 OIC_LOG(ERROR, TAG, "List removal failed.");
-                ca_mutex_unlock(g_gattObjectMutex);
+                oc_mutex_unlock(g_gattObjectMutex);
                 return CA_STATUS_FAILED;
             }
-            ca_mutex_unlock(g_gattObjectMutex);
+            oc_mutex_unlock(g_gattObjectMutex);
             return CA_STATUS_OK;
         }
         (*env)->ReleaseStringUTFChars(env, jni_setAddress, setAddress);
         (*env)->ReleaseStringUTFChars(env, jni_remoteAddress, remoteAddress);
     }
 
-    ca_mutex_unlock(g_gattObjectMutex);
+    oc_mutex_unlock(g_gattObjectMutex);
     OIC_LOG(DEBUG, TAG, "there are no target object");
     return CA_STATUS_OK;
 }
@@ -3253,11 +4124,11 @@ CAResult_t CALEClientRemoveGattObjForAddr(JNIEnv *env, jstring addr)
     VERIFY_NON_NULL(addr, TAG, "addr is null");
     VERIFY_NON_NULL(env, TAG, "env is null");
 
-    ca_mutex_lock(g_gattObjectMutex);
+    oc_mutex_lock(g_gattObjectMutex);
     if (!g_gattObjectList)
     {
         OIC_LOG(DEBUG, TAG, "already removed for g_gattObjectList");
-        ca_mutex_unlock(g_gattObjectMutex);
+        oc_mutex_unlock(g_gattObjectMutex);
         return CA_STATUS_OK;
     }
 
@@ -3268,7 +4139,7 @@ CAResult_t CALEClientRemoveGattObjForAddr(JNIEnv *env, jstring addr)
         if (!jarrayObj)
         {
             OIC_LOG(ERROR, TAG, "jarrayObj is null");
-            ca_mutex_unlock(g_gattObjectMutex);
+            oc_mutex_unlock(g_gattObjectMutex);
             return CA_STATUS_FAILED;
         }
 
@@ -3276,7 +4147,7 @@ CAResult_t CALEClientRemoveGattObjForAddr(JNIEnv *env, jstring addr)
         if (!jni_setAddress)
         {
             OIC_LOG(ERROR, TAG, "jni_setAddress is null");
-            ca_mutex_unlock(g_gattObjectMutex);
+            oc_mutex_unlock(g_gattObjectMutex);
             return CA_STATUS_FAILED;
         }
 
@@ -3284,7 +4155,8 @@ CAResult_t CALEClientRemoveGattObjForAddr(JNIEnv *env, jstring addr)
         if (!setAddress)
         {
             OIC_LOG(ERROR, TAG, "setAddress is null");
-            ca_mutex_unlock(g_gattObjectMutex);
+            CACheckJNIException(env);
+            oc_mutex_unlock(g_gattObjectMutex);
             return CA_STATUS_FAILED;
         }
 
@@ -3293,451 +4165,209 @@ CAResult_t CALEClientRemoveGattObjForAddr(JNIEnv *env, jstring addr)
         {
             OIC_LOG(ERROR, TAG, "remoteAddress is null");
             (*env)->ReleaseStringUTFChars(env, jni_setAddress, setAddress);
-            ca_mutex_unlock(g_gattObjectMutex);
-            return CA_STATUS_FAILED;
-        }
-
-        if (!strcmp(setAddress, remoteAddress))
-        {
-            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 CA_STATUS_OK;
-        }
-        (*env)->ReleaseStringUTFChars(env, jni_setAddress, setAddress);
-        (*env)->ReleaseStringUTFChars(env, addr, remoteAddress);
-    }
-
-    ca_mutex_unlock(g_gattObjectMutex);
-    OIC_LOG(DEBUG, TAG, "there are no target object");
-    return CA_STATUS_FAILED;
-}
-
-jstring CALEClientGetLEAddressFromBTDevice(JNIEnv *env, jobject bluetoothDevice)
-{
-    OIC_LOG(DEBUG, TAG, "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 = CAGetJNIMethodID(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;
-    }
-
-    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;
-        }
-
-        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;
-        }
-
-        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;
-        }
-
-        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, "btAddress : %s (idx: %d)", btAddress, index);
-        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");
-            }
-            ca_mutex_unlock(g_gattObjectMutex);
-            (*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);
-    }
-    ca_mutex_unlock(g_gattObjectMutex);
-
-    (*env)->ReleaseStringUTFChars(env, jni_btTargetAddress, targetAddress);
-    OIC_LOG_V(DEBUG, TAG, "[%s] doesn't exist in gattObjectList", targetAddress);
-    return NULL;
-}
-
-/**
- * BT State List
- */
-
-CAResult_t CALEClientUpdateDeviceState(const char* address, uint16_t state_type,
-                                       uint16_t target_state)
-{
-    VERIFY_NON_NULL(address, TAG, "address is null");
-    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");
-        return CA_STATUS_FAILED;
-    }
-
-    ca_mutex_lock(g_deviceStateListMutex);
-
-    if (CALEClientIsDeviceInList(address))
-    {
-        CALEState_t* curState = CALEClientGetStateInfo(address);
-        if(!curState)
-        {
-            OIC_LOG(ERROR, TAG, "curState is null");
-            ca_mutex_unlock(g_deviceStateListMutex);
-            return CA_STATUS_FAILED;
-        }
-
-        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)
-        {
-            OIC_LOG(ERROR, TAG, "address is not proper");
-            ca_mutex_unlock(g_deviceStateListMutex);
-            return CA_STATUS_INVALID_PARAM;
-        }
-
-        CALEState_t *newstate = (CALEState_t*) OICCalloc(1, sizeof(*newstate));
-        if (!newstate)
-        {
-            OIC_LOG(ERROR, TAG, "out of memory");
-            ca_mutex_unlock(g_deviceStateListMutex);
-            return CA_MEMORY_ALLOC_FAILED;
-        }
-
-        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;
-}
-
-bool CALEClientIsDeviceInList(const char* remoteAddress)
-{
-    VERIFY_NON_NULL_RET(remoteAddress, TAG, "remoteAddress is null", false);
-
-    if (!g_deviceStateList)
-    {
-        OIC_LOG(ERROR, TAG, "g_deviceStateList is null");
-        return false;
-    }
-
-    uint32_t length = u_arraylist_length(g_deviceStateList);
-    for (uint32_t index = 0; index < length; index++)
-    {
-        CALEState_t* state = (CALEState_t*) u_arraylist_get(g_deviceStateList, index);
-        if (!state)
-        {
-            OIC_LOG(ERROR, TAG, "CALEState_t object is null");
-            return false;
-        }
-
-        if (!strcmp(remoteAddress, state->address))
-        {
-            OIC_LOG(DEBUG, TAG, "the device is already set");
-            return true;
-        }
-        else
-        {
-            continue;
-        }
-    }
-
-    OIC_LOG(DEBUG, TAG, "there are no the device in list.");
-    return false;
-}
-
-CAResult_t CALEClientRemoveAllDeviceState()
-{
-    OIC_LOG(DEBUG, TAG, "CALEClientRemoveAllDeviceState");
-
-    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;
-    }
-
-    uint32_t length = u_arraylist_length(g_deviceStateList);
-    for (uint32_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;
-        }
-        OICFree(state);
-    }
-
-    OICFree(g_deviceStateList);
-    g_deviceStateList = NULL;
-    ca_mutex_unlock(g_deviceStateListMutex);
-
-    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->sendState = STATE_SEND_NONE;
-    }
-    ca_mutex_unlock(g_deviceStateListMutex);
-
-    return CA_STATUS_OK;
-}
-
-CAResult_t CALEClientRemoveDeviceState(const char* remoteAddress)
-{
-    OIC_LOG(DEBUG, TAG, "CALEClientRemoveDeviceState");
-    VERIFY_NON_NULL(remoteAddress, TAG, "remoteAddress is null");
-
-    if (!g_deviceStateList)
-    {
-        OIC_LOG(ERROR, TAG, "g_deviceStateList is null");
-        return CA_STATUS_FAILED;
-    }
-
-    uint32_t length = u_arraylist_length(g_deviceStateList);
-    for (uint32_t index = 0; index < length; index++)
-    {
-        CALEState_t* state = (CALEState_t*) u_arraylist_get(g_deviceStateList, index);
-        if (!state)
-        {
-            OIC_LOG(ERROR, TAG, "CALEState_t object is null");
-            continue;
+            oc_mutex_unlock(g_gattObjectMutex);
+            return CA_STATUS_FAILED;
         }
 
-        if (!strcmp(state->address, remoteAddress))
+        if (!strcasecmp(setAddress, remoteAddress))
         {
-            OIC_LOG_V(DEBUG, TAG, "remove state : %s", state->address);
-
-            CALEState_t* targetState  = (CALEState_t*)u_arraylist_remove(g_deviceStateList,
-                                                                         index);
-            if (NULL == targetState)
+            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.");
+                oc_mutex_unlock(g_gattObjectMutex);
                 return CA_STATUS_FAILED;
             }
-
-            OICFree(targetState);
+            oc_mutex_unlock(g_gattObjectMutex);
             return CA_STATUS_OK;
         }
+        (*env)->ReleaseStringUTFChars(env, jni_setAddress, setAddress);
+        (*env)->ReleaseStringUTFChars(env, addr, remoteAddress);
     }
 
-    return CA_STATUS_OK;
+    oc_mutex_unlock(g_gattObjectMutex);
+    OIC_LOG(DEBUG, TAG, "there are no target object");
+    return CA_STATUS_FAILED;
 }
 
-CALEState_t* CALEClientGetStateInfo(const char* remoteAddress)
+jstring CALEClientGetLEAddressFromBTDevice(JNIEnv *env, jobject bluetoothDevice)
 {
-    VERIFY_NON_NULL_RET(remoteAddress, TAG, "remoteAddress is null", NULL);
+    VERIFY_NON_NULL_RET(env, TAG, "env", NULL);
+    VERIFY_NON_NULL_RET(bluetoothDevice, TAG, "bluetoothDevice", NULL);
 
-    if (!g_deviceStateList)
+    // get Bluetooth Address
+    jstring jni_btTargetAddress = CALEGetAddressFromBTDevice(env, bluetoothDevice);
+    if (!jni_btTargetAddress)
     {
-        OIC_LOG(ERROR, TAG, "g_deviceStateList is null");
+        OIC_LOG(ERROR, TAG, "CALEGetAddressFromBTDevice has failed");
         return NULL;
     }
 
-    uint32_t length = u_arraylist_length(g_deviceStateList);
-    OIC_LOG_V(DEBUG, TAG, "length of deviceStateList : %d", length);
-    OIC_LOG_V(DEBUG, TAG, "target address : %s", remoteAddress);
+    const char* targetAddress = (*env)->GetStringUTFChars(env, jni_btTargetAddress, NULL);
+    if (!targetAddress)
+    {
+        OIC_LOG(ERROR, TAG, "targetAddress is not available");
+        CACheckJNIException(env);
+        return NULL;
+    }
 
-    for (uint32_t index = 0; index < length; index++)
+    // get method ID of getDevice()
+    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");
+        (*env)->ReleaseStringUTFChars(env, jni_btTargetAddress, targetAddress);
+        return NULL;
+    }
+
+    oc_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++)
     {
-        CALEState_t* state = (CALEState_t*) u_arraylist_get(g_deviceStateList, index);
-        if (!state)
+        jobject jarrayObj = (jobject) u_arraylist_get(g_gattObjectList, index);
+        if (!jarrayObj)
         {
-            OIC_LOG(ERROR, TAG, "CALEState_t object is null");
-            continue;
+            oc_mutex_unlock(g_gattObjectMutex);
+            OIC_LOG(ERROR, TAG, "jarrayObj is null");
+            (*env)->ReleaseStringUTFChars(env, jni_btTargetAddress, targetAddress);
+            return NULL;
+        }
+
+        jobject jni_obj_device = (*env)->CallObjectMethod(env, jarrayObj, jni_mid_getDevice);
+        if (!jni_obj_device)
+        {
+            CACheckJNIException(env);
+            oc_mutex_unlock(g_gattObjectMutex);
+            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)
+        {
+            oc_mutex_unlock(g_gattObjectMutex);
+            OIC_LOG(ERROR, TAG, "CALEGetAddressFromBTDevice has failed");
+            (*env)->ReleaseStringUTFChars(env, jni_btTargetAddress, targetAddress);
+            (*env)->DeleteLocalRef(env, jni_obj_device);
+            return NULL;
         }
 
-        OIC_LOG_V(DEBUG, TAG, "state address : %s (idx: %d)", state->address, index);
+        const char* btAddress = (*env)->GetStringUTFChars(env, jni_btAddress, NULL);
+        if (!btAddress)
+        {
+            CACheckJNIException(env);
+            oc_mutex_unlock(g_gattObjectMutex);
+            OIC_LOG(ERROR, TAG, "btAddress is not available");
+            (*env)->ReleaseStringUTFChars(env, jni_btTargetAddress, targetAddress);
+            (*env)->DeleteLocalRef(env, jni_btAddress);
+            (*env)->DeleteLocalRef(env, jni_obj_device);
+            return NULL;
+        }
 
-        if (!strcmp(state->address, remoteAddress))
+        OIC_LOG_V(DEBUG, TAG, "btAddress : %s (idx: %d)", btAddress, index);
+        if (!strcasecmp(targetAddress, btAddress))
         {
-            OIC_LOG(DEBUG, TAG, "found state");
-            return state;
+            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");
+            }
+            oc_mutex_unlock(g_gattObjectMutex);
+            (*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);
     }
+    oc_mutex_unlock(g_gattObjectMutex);
 
-    OIC_LOG_V(DEBUG, TAG, "[%s] doesn't exist in deviceStateList", remoteAddress);
+    (*env)->ReleaseStringUTFChars(env, jni_btTargetAddress, targetAddress);
+    OIC_LOG_V(DEBUG, TAG, "[%s] doesn't exist in gattObjectList", targetAddress);
     return NULL;
 }
 
-bool CALEClientIsValidState(const char* remoteAddress, uint16_t state_type,
-                             uint16_t target_state)
+/**
+ * BT State List
+ */
+CAResult_t CALEClientUpdateDeviceStateWithBtDevice(JNIEnv *env,
+                                                   jobject device,
+                                                   uint16_t state_type,
+                                                   uint16_t target_state)
 {
-    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);
+    VERIFY_NON_NULL(device, TAG, "device is null");
 
-    ca_mutex_lock(g_deviceStateListMutex);
-    if (!g_deviceStateList)
+    // get Bluetooth Address
+    jstring jni_Address = CALEGetAddressFromBTDevice(env, device);
+    if (!jni_Address)
     {
-        OIC_LOG(ERROR, TAG, "g_deviceStateList is null");
-        ca_mutex_unlock(g_deviceStateListMutex);
-        return false;
+        OIC_LOG(ERROR, TAG, "CALEGetAddressFromBTDevice has failed");
+        return CA_STATUS_FAILED;
     }
 
-    CALEState_t* state = CALEClientGetStateInfo(remoteAddress);
-    if (NULL == state)
+    const char* address = (*env)->GetStringUTFChars(env, jni_Address, NULL);
+    if (!address)
     {
-        OIC_LOG(ERROR, TAG, "state is null");
-        ca_mutex_unlock(g_deviceStateListMutex);
-        return false;
+        OIC_LOG(ERROR, TAG, "targetAddress is not available");
+        CACheckJNIException(env);
+        (*env)->DeleteLocalRef(env, jni_Address);
+        return CA_STATUS_FAILED;
     }
 
-    uint16_t curValue = 0;
-    switch(state_type)
+    if (CALEIsValidState(address, state_type, target_state,
+                         g_deviceStateList,
+                         g_deviceStateListMutex))
     {
-        case CA_LE_CONNECTION_STATE:
-            curValue = state->connectedState;
-            break;
-        case CA_LE_SEND_STATE:
-            curValue = state->sendState;
-            break;
-        default:
-            break;
+        (*env)->DeleteLocalRef(env, jni_Address);
+        return CA_STATUS_OK;
     }
 
-    if (target_state == curValue)
-    {
-        ca_mutex_unlock(g_deviceStateListMutex);
-        return true;
-    }
-    else
+    CAResult_t res = CALEUpdateDeviceState(address, state_type,
+                                           target_state,
+                                           g_deviceStateList,
+                                           g_deviceStateListMutex);
+    if (CA_STATUS_OK != res)
     {
-        ca_mutex_unlock(g_deviceStateListMutex);
-        return false;
+        OIC_LOG(ERROR, TAG, "CALEUpdateDeviceState has failed");
     }
+    (*env)->ReleaseStringUTFChars(env, jni_Address, address);
+    (*env)->DeleteLocalRef(env, jni_Address);
 
-    ca_mutex_unlock(g_deviceStateListMutex);
-    return false;
+    return res;
+}
+
+CAResult_t CALEClientSetFlagToState(JNIEnv *env, jstring jni_address,
+                                    jint state_idx, jboolean flag)
+{
+    return CALESetFlagToState(env, jni_address, state_idx, flag,
+                              g_deviceStateList, g_deviceStateListMutex);
+}
+
+jboolean CALEClientGetFlagFromState(JNIEnv *env, jstring jni_address, jint state_idx)
+{
+    return CALEGetFlagFromState(env, jni_address, state_idx, g_deviceStateList,
+                                g_deviceStateListMutex);
+}
+
+uint16_t CALEClientGetMtuSize(const char* address)
+{
+    return CALEGetMtuSize(address, g_deviceStateList, g_deviceStateListMutex);
 }
 
 void CALEClientCreateDeviceList()
@@ -3767,6 +4397,11 @@ void CALEClientCreateDeviceList()
     }
 }
 
+CAResult_t CALEClientResetDeviceStateForAll()
+{
+    return CALEResetDeviceStateForAll(g_deviceStateList, g_deviceStateListMutex);
+}
+
 /**
  * Check Sent Count for remove g_sendBuffer
  */
@@ -3776,7 +4411,7 @@ void CALEClientUpdateSendCnt(JNIEnv *env)
 
     VERIFY_NON_NULL_VOID(env, TAG, "env is null");
     // mutex lock
-    ca_mutex_lock(g_threadMutex);
+    oc_mutex_lock(g_threadMutex);
 
     g_currentSentCnt++;
 
@@ -3785,139 +4420,153 @@ void CALEClientUpdateSendCnt(JNIEnv *env)
         g_targetCnt = 0;
         g_currentSentCnt = 0;
 
-        if (g_sendBuffer)
-        {
-            (*env)->DeleteGlobalRef(env, g_sendBuffer);
-            g_sendBuffer = NULL;
-        }
+        CALEDeleteSendBuffer(env);
+
         // notity the thread
-        ca_cond_signal(g_threadCond);
+        oc_cond_signal(g_threadCond);
+        oc_cond_signal(g_threadWriteCharacteristicCond);
 
         CALEClientSetSendFinishFlag(true);
         OIC_LOG(DEBUG, TAG, "set signal for send data");
     }
+
+#ifdef SCAN_INTERVAL
+    // reset interval scan logic
+    CALERestartScanWithInterval(g_scanIntervalTimePrev, 0, BLE_SCAN_ENABLE);
+#endif
+
     // mutex unlock
-    ca_mutex_unlock(g_threadMutex);
+    oc_mutex_unlock(g_threadMutex);
 }
 
 CAResult_t CALEClientInitGattMutexVaraibles()
 {
     if (NULL == g_bleReqRespClientCbMutex)
     {
-        g_bleReqRespClientCbMutex = ca_mutex_new();
+        g_bleReqRespClientCbMutex = oc_mutex_new();
         if (NULL == g_bleReqRespClientCbMutex)
         {
-            OIC_LOG(ERROR, TAG, "ca_mutex_new has failed");
+            OIC_LOG(ERROR, TAG, "oc_mutex_new has failed");
             return CA_STATUS_FAILED;
         }
     }
 
     if (NULL == g_bleServerBDAddressMutex)
     {
-        g_bleServerBDAddressMutex = ca_mutex_new();
+        g_bleServerBDAddressMutex = oc_mutex_new();
         if (NULL == g_bleServerBDAddressMutex)
         {
-            OIC_LOG(ERROR, TAG, "ca_mutex_new has failed");
+            OIC_LOG(ERROR, TAG, "oc_mutex_new has failed");
             return CA_STATUS_FAILED;
         }
     }
 
     if (NULL == g_threadMutex)
     {
-        g_threadMutex = ca_mutex_new();
+        g_threadMutex = oc_mutex_new();
         if (NULL == g_threadMutex)
         {
-            OIC_LOG(ERROR, TAG, "ca_mutex_new has failed");
+            OIC_LOG(ERROR, TAG, "oc_mutex_new has failed");
             return CA_STATUS_FAILED;
         }
     }
 
     if (NULL == g_threadSendMutex)
     {
-        g_threadSendMutex = ca_mutex_new();
+        g_threadSendMutex = oc_mutex_new();
         if (NULL == g_threadSendMutex)
         {
-            OIC_LOG(ERROR, TAG, "ca_mutex_new has failed");
+            OIC_LOG(ERROR, TAG, "oc_mutex_new has failed");
             return CA_STATUS_FAILED;
         }
     }
 
     if (NULL == g_deviceListMutex)
     {
-        g_deviceListMutex = ca_mutex_new();
+        g_deviceListMutex = oc_mutex_new();
         if (NULL == g_deviceListMutex)
         {
-            OIC_LOG(ERROR, TAG, "ca_mutex_new has failed");
+            OIC_LOG(ERROR, TAG, "oc_mutex_new has failed");
             return CA_STATUS_FAILED;
         }
     }
 
     if (NULL == g_gattObjectMutex)
     {
-        g_gattObjectMutex = ca_mutex_new();
+        g_gattObjectMutex = oc_mutex_new();
         if (NULL == g_gattObjectMutex)
         {
-            OIC_LOG(ERROR, TAG, "ca_mutex_new has failed");
+            OIC_LOG(ERROR, TAG, "oc_mutex_new has failed");
             return CA_STATUS_FAILED;
         }
     }
 
     if (NULL == g_deviceStateListMutex)
     {
-        g_deviceStateListMutex = ca_mutex_new();
+        g_deviceStateListMutex = oc_mutex_new();
         if (NULL == g_deviceStateListMutex)
         {
-            OIC_LOG(ERROR, TAG, "ca_mutex_new has failed");
+            OIC_LOG(ERROR, TAG, "oc_mutex_new has failed");
             return CA_STATUS_FAILED;
         }
     }
 
     if (NULL == g_SendFinishMutex)
     {
-        g_SendFinishMutex = ca_mutex_new();
+        g_SendFinishMutex = oc_mutex_new();
         if (NULL == g_SendFinishMutex)
         {
-            OIC_LOG(ERROR, TAG, "ca_mutex_new has failed");
+            OIC_LOG(ERROR, TAG, "oc_mutex_new has failed");
             return CA_STATUS_FAILED;
         }
     }
 
     if (NULL == g_threadWriteCharacteristicMutex)
     {
-        g_threadWriteCharacteristicMutex = ca_mutex_new();
+        g_threadWriteCharacteristicMutex = oc_mutex_new();
         if (NULL == g_threadWriteCharacteristicMutex)
         {
-            OIC_LOG(ERROR, TAG, "ca_mutex_new has failed");
+            OIC_LOG(ERROR, TAG, "oc_mutex_new has failed");
             return CA_STATUS_FAILED;
         }
     }
 
     if (NULL == g_deviceScanRetryDelayMutex)
     {
-        g_deviceScanRetryDelayMutex = ca_mutex_new();
+        g_deviceScanRetryDelayMutex = oc_mutex_new();
         if (NULL == g_deviceScanRetryDelayMutex)
         {
-            OIC_LOG(ERROR, TAG, "ca_mutex_new has failed");
+            OIC_LOG(ERROR, TAG, "oc_mutex_new has failed");
             return CA_STATUS_FAILED;
         }
     }
 
     if (NULL == g_threadSendStateMutex)
     {
-        g_threadSendStateMutex = ca_mutex_new();
+        g_threadSendStateMutex = oc_mutex_new();
         if (NULL == g_threadSendStateMutex)
         {
-            OIC_LOG(ERROR, TAG, "ca_mutex_new has failed");
+            OIC_LOG(ERROR, TAG, "oc_mutex_new has failed");
             return CA_STATUS_FAILED;
         }
     }
 
     if (NULL == g_threadScanIntervalMutex)
     {
-        g_threadScanIntervalMutex = ca_mutex_new();
+        g_threadScanIntervalMutex = oc_mutex_new();
         if (NULL == g_threadScanIntervalMutex)
         {
-            OIC_LOG(ERROR, TAG, "ca_mutex_new has failed");
+            OIC_LOG(ERROR, TAG, "oc_mutex_new has failed");
+            return CA_STATUS_FAILED;
+        }
+    }
+
+    if (NULL == g_setValueMutex)
+    {
+        g_setValueMutex = oc_mutex_new();
+        if (NULL == g_setValueMutex)
+        {
+            OIC_LOG(ERROR, TAG, "oc_mutex_new has failed");
             return CA_STATUS_FAILED;
         }
     }
@@ -3927,44 +4576,53 @@ CAResult_t CALEClientInitGattMutexVaraibles()
 
 void CALEClientTerminateGattMutexVariables()
 {
-    ca_mutex_free(g_bleReqRespClientCbMutex);
+    oc_mutex_free(g_bleReqRespClientCbMutex);
     g_bleReqRespClientCbMutex = NULL;
 
-    ca_mutex_free(g_bleServerBDAddressMutex);
+    oc_mutex_free(g_bleServerBDAddressMutex);
     g_bleServerBDAddressMutex = NULL;
 
-    ca_mutex_free(g_threadMutex);
+    oc_mutex_free(g_threadMutex);
     g_threadMutex = NULL;
 
-    ca_mutex_free(g_threadSendMutex);
+    oc_mutex_free(g_threadSendMutex);
     g_threadSendMutex = NULL;
 
-    ca_mutex_free(g_deviceListMutex);
+    oc_mutex_free(g_deviceListMutex);
     g_deviceListMutex = NULL;
 
-    ca_mutex_free(g_SendFinishMutex);
+    oc_mutex_free(g_SendFinishMutex);
     g_SendFinishMutex = NULL;
 
-    ca_mutex_free(g_threadWriteCharacteristicMutex);
+    oc_mutex_free(g_threadWriteCharacteristicMutex);
     g_threadWriteCharacteristicMutex = NULL;
 
-    ca_mutex_free(g_deviceScanRetryDelayMutex);
+    oc_mutex_free(g_deviceScanRetryDelayMutex);
     g_deviceScanRetryDelayMutex = NULL;
 
-    ca_mutex_free(g_threadSendStateMutex);
+    oc_mutex_free(g_threadSendStateMutex);
     g_threadSendStateMutex = NULL;
 
-    ca_mutex_free(g_threadScanIntervalMutex);
+    oc_mutex_free(g_threadScanIntervalMutex);
     g_threadScanIntervalMutex = NULL;
+
+    oc_mutex_free(g_gattObjectMutex);
+    g_gattObjectMutex = NULL;
+
+    oc_mutex_free(g_deviceStateListMutex);
+    g_deviceStateListMutex = NULL;
+
+    oc_mutex_free(g_setValueMutex);
+    g_setValueMutex = NULL;
 }
 
 void CALEClientSetSendFinishFlag(bool flag)
 {
     OIC_LOG_V(DEBUG, TAG, "g_isFinishedSendData is %d", flag);
 
-    ca_mutex_lock(g_SendFinishMutex);
+    oc_mutex_lock(g_SendFinishMutex);
     g_isFinishedSendData = flag;
-    ca_mutex_unlock(g_SendFinishMutex);
+    oc_mutex_unlock(g_SendFinishMutex);
 }
 
 /**
@@ -3976,22 +4634,22 @@ CAResult_t CAStartLEGattClient()
     // init mutex for send logic
     if (!g_deviceDescCond)
     {
-        g_deviceDescCond = ca_cond_new();
+        g_deviceDescCond = oc_cond_new();
     }
 
     if (!g_threadCond)
     {
-        g_threadCond = ca_cond_new();
+        g_threadCond = oc_cond_new();
     }
 
     if (!g_threadWriteCharacteristicCond)
     {
-        g_threadWriteCharacteristicCond = ca_cond_new();
+        g_threadWriteCharacteristicCond = oc_cond_new();
     }
 
     if (!g_threadScanIntervalCond)
     {
-        g_threadScanIntervalCond = ca_cond_new();
+        g_threadScanIntervalCond = oc_cond_new();
     }
 
     CAResult_t ret = CALEClientStartScanWithInterval();
@@ -4020,7 +4678,6 @@ void CAStopLEGattClient()
     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)
@@ -4039,32 +4696,37 @@ void CAStopLEGattClient()
 
     CALEClientStopScanWithInterval();
 
-    ca_mutex_lock(g_threadMutex);
-    OIC_LOG(DEBUG, TAG, "signal - connection cond");
-    ca_cond_signal(g_threadCond);
-    CALEClientSetSendFinishFlag(true);
-    ca_mutex_unlock(g_threadMutex);
-
-    ca_mutex_lock(g_threadWriteCharacteristicMutex);
+    oc_mutex_lock(g_threadWriteCharacteristicMutex);
     OIC_LOG(DEBUG, TAG, "signal - WriteCharacteristic cond");
-    ca_cond_signal(g_threadWriteCharacteristicCond);
-    ca_mutex_unlock(g_threadWriteCharacteristicMutex);
+    oc_cond_signal(g_threadWriteCharacteristicCond);
+    oc_mutex_unlock(g_threadWriteCharacteristicMutex);
 
-    ca_mutex_lock(g_deviceScanRetryDelayMutex);
+    CALEClientSetSendFinishFlag(true);
+    oc_mutex_lock(g_threadMutex);
+    OIC_LOG(DEBUG, TAG, "signal - g_threadCond cond");
+    oc_cond_signal(g_threadCond);
+    oc_mutex_unlock(g_threadMutex);
+
+    oc_mutex_lock(g_deviceScanRetryDelayMutex);
     OIC_LOG(DEBUG, TAG, "signal - delay cond");
-    ca_cond_signal(g_deviceScanRetryDelayCond);
-    ca_mutex_unlock(g_deviceScanRetryDelayMutex);
+    oc_cond_signal(g_deviceScanRetryDelayCond);
+    oc_mutex_unlock(g_deviceScanRetryDelayMutex);
 
-    ca_mutex_lock(g_threadScanIntervalMutex);
+    oc_mutex_lock(g_threadScanIntervalMutex);
     OIC_LOG(DEBUG, TAG, "signal - delay cond");
-    ca_cond_signal(g_threadScanIntervalCond);
-    ca_mutex_unlock(g_threadScanIntervalMutex);
+    oc_cond_signal(g_threadScanIntervalCond);
+    oc_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);
+    oc_mutex_lock(g_threadSendMutex);
+    OIC_LOG(DEBUG, TAG, "signal - g_deviceDesc cond");
+    oc_cond_signal(g_deviceDescCond);
+    oc_mutex_unlock(g_threadSendMutex);
+
+    oc_cond_free(g_deviceDescCond);
+    oc_cond_free(g_threadCond);
+    oc_cond_free(g_threadWriteCharacteristicCond);
+    oc_cond_free(g_deviceScanRetryDelayCond);
+    oc_cond_free(g_threadScanIntervalCond);
 
     g_deviceDescCond = NULL;
     g_threadCond = NULL;
@@ -4088,17 +4750,17 @@ CAResult_t CAInitializeLEGattClient()
 
 void CATerminateLEGattClient()
 {
-    OIC_LOG(DEBUG, TAG, "Terminate GATT Client");
+    OIC_LOG(INFO, TAG, "IN - Terminate GATT Client");
     CAStopLEGattClient();
     CALEClientTerminate();
+    OIC_LOG(INFO, TAG, "OUT - Terminate GATT Client");
 }
 
 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");
+    OIC_LOG(INFO, TAG, "call CALEClientSendUnicastMessage");
     VERIFY_NON_NULL(remoteAddress, TAG, "remoteAddress is null");
 
     if (LE_UNICAST != type || position < 0)
@@ -4120,9 +4782,9 @@ CAResult_t CAUpdateCharacteristicsToAllGattServers(const uint8_t *data, uint32_t
 
 void CASetLEReqRespClientCallback(CABLEDataReceivedCallback callback)
 {
-    ca_mutex_lock(g_bleReqRespClientCbMutex);
+    oc_mutex_lock(g_bleReqRespClientCbMutex);
     g_CABLEClientDataReceivedCallback = callback;
-    ca_mutex_unlock(g_bleReqRespClientCbMutex);
+    oc_mutex_unlock(g_bleReqRespClientCbMutex);
 }
 
 void CASetLEClientThreadPoolHandle(ca_thread_pool_t handle)
@@ -4133,7 +4795,6 @@ void CASetLEClientThreadPoolHandle(ca_thread_pool_t handle)
 CAResult_t CAGetLEAddress(char **local_address)
 {
     VERIFY_NON_NULL(local_address, TAG, "local_address");
-    OIC_LOG(INFO, TAG, "CAGetLEAddress is not support");
     return CA_NOT_SUPPORTED;
 }
 
@@ -4147,6 +4808,21 @@ Java_org_iotivity_ca_CaLeClientInterface_caLeRegisterLeScanCallback(JNIEnv *env,
     VERIFY_NON_NULL_VOID(callback, TAG, "callback is null");
 
     g_leScanCallback = (*env)->NewGlobalRef(env, callback);
+    CACheckJNIException(env);
+}
+
+JNIEXPORT void JNICALL
+Java_org_iotivity_ca_CaLeClientInterface_caLeRegisterLeScanCallbackForV21(JNIEnv *env,
+                                                                          jobject obj,
+                                                                          jobject callback)
+{
+    OIC_LOG(DEBUG, TAG, "caLeRegisterLeScanCallbackForV21");
+    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);
+    CACheckJNIException(env);
 }
 
 JNIEXPORT void JNICALL
@@ -4159,6 +4835,7 @@ Java_org_iotivity_ca_CaLeClientInterface_caLeRegisterGattCallback(JNIEnv *env, j
     VERIFY_NON_NULL_VOID(callback, TAG, "callback is null");
 
     g_leGattCallback = (*env)->NewGlobalRef(env, callback);
+    CACheckJNIException(env);
 }
 
 JNIEXPORT void JNICALL
@@ -4176,6 +4853,38 @@ Java_org_iotivity_ca_CaLeClientInterface_caLeScanCallback(JNIEnv *env, jobject o
     }
 }
 
+JNIEXPORT void JNICALL
+Java_org_iotivity_ca_CaLeClientInterface_caLeScanFailedCallback(JNIEnv *env, jobject obj,
+                                                                jint errorCode)
+{
+    VERIFY_NON_NULL_VOID(env, TAG, "env is null");
+    VERIFY_NON_NULL_VOID(obj, TAG, "obj is null");
+
+    switch (errorCode)
+    {
+        case 1:
+            OIC_LOG(ERROR, TAG, "BLE scan has failed, error is SCAN_FAILED_ALREADY_STARTED");
+            break;
+
+        case 2:
+            OIC_LOG(ERROR, TAG,
+                    "BLE scan has failed, error is SCAN_FAILED_APPLICATION_REGISTRATION_FAILED");
+            break;
+
+        case 3:
+            OIC_LOG(ERROR, TAG, "BLE scan has failed, error is SCAN_FAILED_INTERNAL_ERROR");
+            break;
+
+        case 4:
+            OIC_LOG(ERROR, TAG, "BLE scan has failed, error is SCAN_FAILED_FEATURE_UNSUPPORTED");
+            break;
+
+        default:
+            OIC_LOG(ERROR, TAG, "BLE scan has failed with unknown error");
+            break;
+    }
+}
+
 /*
  * Class:     org_iotivity_ca_jar_caleinterface
  * Method:    CALeGattConnectionStateChangeCallback
@@ -4207,6 +4916,7 @@ Java_org_iotivity_ca_CaLeClientInterface_caLeGattConnectionStateChangeCallback(J
     if (!address)
     {
         OIC_LOG(ERROR, TAG, "address is null");
+        CACheckJNIException(env);
         goto error_exit;
     }
     OIC_LOG_V(DEBUG, TAG, "CALeGattConnectionStateChangeCallback - address [%s]", address);
@@ -4216,13 +4926,15 @@ Java_org_iotivity_ca_CaLeClientInterface_caLeGattConnectionStateChangeCallback(J
         OIC_LOG(DEBUG, TAG, "LE is connected");
         if (GATT_SUCCESS == status)
         {
-            CAResult_t res = CALEClientUpdateDeviceState(address,
-                                                         CA_LE_CONNECTION_STATE,
-                                                         STATE_CONNECTED);
+            CAResult_t res = CALEUpdateDeviceState(address,
+                                                   CA_LE_CONNECTION_STATE,
+                                                   STATE_CONNECTED,
+                                                   g_deviceStateList,
+                                                   g_deviceStateListMutex);
             (*env)->ReleaseStringUTFChars(env, jni_address, address);
             if (CA_STATUS_OK != res)
             {
-                OIC_LOG(ERROR, TAG, "CALEClientUpdateDeviceState has failed");
+                OIC_LOG(ERROR, TAG, "CALEUpdateDeviceState has failed");
                 goto error_exit;
             }
 
@@ -4250,15 +4962,30 @@ Java_org_iotivity_ca_CaLeClientInterface_caLeGattConnectionStateChangeCallback(J
     {
         OIC_LOG(DEBUG, TAG, "LE is disconnected");
 
-        CAResult_t res = CALEClientUpdateDeviceState(address,
-                                                     CA_LE_CONNECTION_STATE,
-                                                     STATE_DISCONNECTED);
-        (*env)->ReleaseStringUTFChars(env, jni_address, address);
+        if (CALEIsValidState(address, CA_LE_SEND_STATE, STATE_SEND_PREPARING,
+                             g_deviceStateList, g_deviceStateListMutex))
+        {
+            OIC_LOG(INFO, TAG, "current state is STATE_SEND_PREPARING");
+            CAResult_t res = CALEUpdateDeviceState(address, CA_LE_SEND_STATE,
+                                                   STATE_SEND_FAIL,
+                                                   g_deviceStateList,
+                                                   g_deviceStateListMutex);
+            if (CA_STATUS_OK != res)
+            {
+                OIC_LOG(ERROR, TAG, "CALEUpdateDeviceState has failed");
+            }
+        }
+
+        CAResult_t res = CALEUpdateDeviceState(address,
+                                               CA_LE_CONNECTION_STATE,
+                                               STATE_DISCONNECTED,
+                                               g_deviceStateList,
+                                               g_deviceStateListMutex);
         if (CA_STATUS_OK != res)
         {
-            OIC_LOG(ERROR, TAG, "CALEClientUpdateDeviceState has failed");
-            goto error_exit;
+            OIC_LOG(ERROR, TAG, "CALEUpdateDeviceState has failed");
         }
+        (*env)->ReleaseStringUTFChars(env, jni_address, address);
 
         res = CALEClientGattClose(env, gatt);
         if (CA_STATUS_OK != res)
@@ -4271,22 +4998,14 @@ Java_org_iotivity_ca_CaLeClientInterface_caLeGattConnectionStateChangeCallback(J
             // 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 status or manual disconnected state");
-            CALEClientUpdateSendCnt(env);
-            return;
-        }
-
-        if (g_sendBuffer)
-        {
-            (*env)->DeleteGlobalRef(env, g_sendBuffer);
-            g_sendBuffer = NULL;
         }
+        CALEClientUpdateSendCnt(env);
     }
     return;
 
@@ -4328,6 +5047,7 @@ Java_org_iotivity_ca_CaLeClientInterface_caLeGattServicesDiscoveredCallback(JNIE
     const char* address = (*env)->GetStringUTFChars(env, jni_address, NULL);
     if (!address)
     {
+        CACheckJNIException(env);
         CALEClientSendFinish(env, gatt);
         return;
     }
@@ -4359,41 +5079,47 @@ Java_org_iotivity_ca_CaLeClientInterface_caLeGattServicesDiscoveredCallback(JNIE
     {
         OIC_LOG_V(INFO, TAG, "Descriptor is not found : %d", res);
 
-        res = CALEClientSetFlagToState(env, jni_address, CA_LE_DESCRIPTOR_FOUND, JNI_FALSE);
+        res = CALESetFlagToState(env, jni_address, CA_LE_DESCRIPTOR_FOUND, JNI_FALSE,
+                                 g_deviceStateList, g_deviceStateListMutex);
         if (CA_STATUS_OK != res)
         {
-            OIC_LOG(ERROR, TAG, "CALEClientSetFlagToState has failed");
+            OIC_LOG(ERROR, TAG, "CALESetFlagToState has failed");
             goto error_exit;
         }
 
-        res = CALEClientUpdateDeviceState(address, CA_LE_CONNECTION_STATE,
-                                          STATE_SERVICE_CONNECTED);
+        res = CALEUpdateDeviceState(address, CA_LE_CONNECTION_STATE,
+                                    STATE_SERVICE_CONNECTED,
+                                    g_deviceStateList,
+                                    g_deviceStateListMutex);
         if (CA_STATUS_OK != res)
         {
-            OIC_LOG(ERROR, TAG, "CALEClientUpdateDeviceState has failed");
+            OIC_LOG(ERROR, TAG, "CALEUpdateDeviceState has failed");
             goto error_exit;
         }
 
-        if (g_sendBuffer)
+        res = CALEClientRequestMTU(env, gatt, CA_SUPPORTED_BLE_MTU_SIZE);
+        if (CA_STATUS_OK != res)
         {
-            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, "CALEClientRequestMTU has failed");
+            goto error_exit;
         }
     }
     else
     {
-        res = CALEClientSetFlagToState(env, jni_address, CA_LE_DESCRIPTOR_FOUND, JNI_TRUE);
+        res = CALESetFlagToState(env, jni_address, CA_LE_DESCRIPTOR_FOUND, JNI_TRUE,
+                                 g_deviceStateList, g_deviceStateListMutex);
         if (CA_STATUS_OK != res)
         {
-            OIC_LOG(ERROR, TAG, "CALEClientSetFlagToState has failed");
+            OIC_LOG(ERROR, TAG, "CALESetFlagToState has failed");
             goto error_exit;
         }
     }
 
+#ifdef SCAN_INTERVAL
+    // reset interval scan logic
+    CALERestartScanWithInterval(g_scanIntervalTimePrev, 0, BLE_SCAN_ENABLE);
+#endif
+
     OIC_LOG(INFO, TAG, "ServicesDiscovery is successful");
     (*env)->ReleaseStringUTFChars(env, jni_address, address);
     return;
@@ -4430,6 +5156,7 @@ Java_org_iotivity_ca_CaLeClientInterface_caLeGattCharacteristicWriteCallback(
     const char* address = (*env)->GetStringUTFChars(env, jni_address, NULL);
     if (!address)
     {
+        CACheckJNIException(env);
         goto error_exit;
     }
 
@@ -4442,22 +5169,27 @@ Java_org_iotivity_ca_CaLeClientInterface_caLeGattCharacteristicWriteCallback(
         if (CA_STATUS_OK != res)
         {
             OIC_LOG(ERROR, TAG, "WriteCharacteristic has failed");
-            ca_mutex_lock(g_threadWriteCharacteristicMutex);
+            oc_mutex_lock(g_threadWriteCharacteristicMutex);
             g_isSignalSetFlag = true;
-            ca_cond_signal(g_threadWriteCharacteristicCond);
-            ca_mutex_unlock(g_threadWriteCharacteristicMutex);
+            oc_cond_signal(g_threadWriteCharacteristicCond);
+            oc_mutex_unlock(g_threadWriteCharacteristicMutex);
 
-            CAResult_t res = CALEClientUpdateDeviceState(address, CA_LE_SEND_STATE,
-                                                         STATE_SEND_FAIL);
+            CAResult_t res = CALEUpdateDeviceState(address, CA_LE_SEND_STATE,
+                                                   STATE_SEND_FAIL,
+                                                   g_deviceStateList,
+                                                   g_deviceStateListMutex);
             if (CA_STATUS_OK != res)
             {
-                OIC_LOG(ERROR, TAG, "CALEClientUpdateDeviceState has failed");
+                OIC_LOG(ERROR, TAG, "CALEUpdateDeviceState has failed");
             }
 
             if (g_clientErrorCallback)
             {
                 jint length = (*env)->GetArrayLength(env, data);
+                CACheckJNIException(env);
                 g_clientErrorCallback(address, data, length, CA_SEND_FAILED);
+                CALogSendStateInfo(CA_ADAPTER_GATT_BTLE, address, 0, length,
+                                   false, "writeChar failure");
             }
 
             (*env)->ReleaseStringUTFChars(env, jni_address, address);
@@ -4467,18 +5199,24 @@ Java_org_iotivity_ca_CaLeClientInterface_caLeGattCharacteristicWriteCallback(
     else
     {
         OIC_LOG(DEBUG, TAG, "send success");
-        CAResult_t res = CALEClientUpdateDeviceState(address, CA_LE_SEND_STATE,
-                                                     STATE_SEND_SUCCESS);
+        CAResult_t res = CALEUpdateDeviceState(address, CA_LE_SEND_STATE,
+                                               STATE_SEND_SUCCESS,
+                                               g_deviceStateList,
+                                               g_deviceStateListMutex);
         if (CA_STATUS_OK != res)
         {
-            OIC_LOG(ERROR, TAG, "CALEClientUpdateDeviceState has failed");
+            OIC_LOG(ERROR, TAG, "CALEUpdateDeviceState has failed");
         }
 
-        ca_mutex_lock(g_threadWriteCharacteristicMutex);
+        oc_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);
+        oc_cond_signal(g_threadWriteCharacteristicCond);
+        oc_mutex_unlock(g_threadWriteCharacteristicMutex);
+
+        CALogSendStateInfo(CA_ADAPTER_GATT_BTLE, address, 0,
+                           (*env)->GetArrayLength(env, data),
+                           true, "writeChar success");
     }
 
     (*env)->ReleaseStringUTFChars(env, jni_address, address);
@@ -4500,7 +5238,7 @@ JNIEXPORT void JNICALL
 Java_org_iotivity_ca_CaLeClientInterface_caLeGattCharacteristicChangedCallback(
         JNIEnv *env, jobject obj, jobject gatt, jbyteArray data)
 {
-    OIC_LOG(INFO, TAG, "CALeGattCharacteristicChangedCallback");
+    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");
@@ -4511,9 +5249,7 @@ Java_org_iotivity_ca_CaLeClientInterface_caLeGattCharacteristicChangedCallback(
 
     jboolean isCopy;
     jbyte *jni_byte_responseData = (jbyte*) (*env)->GetByteArrayElements(env, data, &isCopy);
-
-    OIC_LOG_V(DEBUG, TAG, "CALeGattCharacteristicChangedCallback - raw data received : %p",
-            jni_byte_responseData);
+    CACheckJNIException(env);
 
     uint8_t* receivedData = OICMalloc(length);
     if (!receivedData)
@@ -4537,6 +5273,7 @@ Java_org_iotivity_ca_CaLeClientInterface_caLeGattCharacteristicChangedCallback(
     if (!address)
     {
         OIC_LOG(ERROR, TAG, "address is null");
+        CACheckJNIException(env);
         OICFree(receivedData);
         return;
     }
@@ -4545,9 +5282,9 @@ Java_org_iotivity_ca_CaLeClientInterface_caLeGattCharacteristicChangedCallback(
               receivedData, length);
 
     uint32_t sentLength = 0;
-    ca_mutex_lock(g_bleServerBDAddressMutex);
+    oc_mutex_lock(g_bleServerBDAddressMutex);
     g_CABLEClientDataReceivedCallback(address, receivedData, length, &sentLength);
-    ca_mutex_unlock(g_bleServerBDAddressMutex);
+    oc_mutex_unlock(g_bleServerBDAddressMutex);
 
     (*env)->ReleaseStringUTFChars(env, jni_address, address);
 }
@@ -4581,26 +5318,26 @@ Java_org_iotivity_ca_CaLeClientInterface_caLeGattDescriptorWriteCallback(JNIEnv
     const char* address = (*env)->GetStringUTFChars(env, jni_address, NULL);
     if (!address)
     {
+        CACheckJNIException(env);
         goto error_exit;
     }
 
-    CAResult_t res = CALEClientUpdateDeviceState(address, CA_LE_CONNECTION_STATE,
-                                                 STATE_SERVICE_CONNECTED);
+    CAResult_t res = CALEUpdateDeviceState(address, CA_LE_CONNECTION_STATE,
+                                           STATE_SERVICE_CONNECTED,
+                                           g_deviceStateList,
+                                           g_deviceStateListMutex);
     (*env)->ReleaseStringUTFChars(env, jni_address, address);
     if (CA_STATUS_OK != res)
     {
-        OIC_LOG(ERROR, TAG, "CALEClientUpdateDeviceState has failed");
+        OIC_LOG(ERROR, TAG, "CALEUpdateDeviceState has failed");
         goto error_exit;
     }
 
-    if (g_sendBuffer)
+    res = CALEClientRequestMTU(env, gatt, CA_SUPPORTED_BLE_MTU_SIZE);
+    if (CA_STATUS_OK != res)
     {
-        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, "CALEClientRequestMTU has failed");
+        goto error_exit;
     }
     return;
 
@@ -4610,3 +5347,67 @@ error_exit:
     CALEClientSendFinish(env, gatt);
     return;
 }
+
+JNIEXPORT void JNICALL
+Java_org_iotivity_ca_CaLeClientInterface_caLeGattMtuChangedCallback(JNIEnv *env,
+                                                                    jobject obj,
+                                                                    jobject gatt,
+                                                                    jint mtu,
+                                                                    jint status)
+{
+    OIC_LOG_V(INFO, TAG, "caLeGattMtuChangedCallback - status %d, "
+              "mtu[%d-including Header size 3 byte]", status, mtu);
+
+    (void)obj;
+
+    if (0 == status || 133 == status)
+    {
+        if (g_sendBuffer)
+        {
+            CAResult_t res = CALEClientWriteCharacteristic(env, gatt);
+            if (CA_STATUS_OK != res)
+            {
+                OIC_LOG(ERROR, TAG, "CALEClientWriteCharacteristic has failed");
+            }
+        }
+        else
+        {
+            OIC_LOG(INFO, TAG, "mtu nego is done");
+            jstring jni_address = CALEClientGetAddressFromGattObj(env, gatt);
+            if (!jni_address)
+            {
+                CALEClientSendFinish(env, gatt);
+                return;
+            }
+
+            const char* address = (*env)->GetStringUTFChars(env, jni_address, NULL);
+            if (!address)
+            {
+                CACheckJNIException(env);
+                (*env)->DeleteLocalRef(env, jni_address);
+                CALEClientSendFinish(env, gatt);
+                return;
+            }
+
+            // update mtu size
+            CAResult_t res = CALESetMtuSize(address, mtu - CA_BLE_MTU_HEADER_SIZE,
+                                            g_deviceStateList, g_deviceStateListMutex);
+            if (CA_STATUS_OK != res)
+            {
+                OIC_LOG(ERROR, TAG, "CALESetMtuSize has failed");
+            }
+
+            res = CALEUpdateDeviceState(address, CA_LE_SEND_STATE,
+                                        STATE_SEND_MTU_NEGO_SUCCESS,
+                                        g_deviceStateList,
+                                        g_deviceStateListMutex);
+            if (CA_STATUS_OK != res)
+            {
+                OIC_LOG(ERROR, TAG, "CALEUpdateDeviceState has failed");
+            }
+            CALEClientUpdateSendCnt(env);
+            (*env)->ReleaseStringUTFChars(env, jni_address, address);
+            (*env)->DeleteLocalRef(env, jni_address);
+        }
+    }
+}