X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=resource%2Fcsdk%2Fconnectivity%2Fsrc%2Fbt_le_adapter%2Fandroid%2Fcaleclient.c;h=bb622eda726e015d41345bc2d007aaf18f6b278a;hb=53427ddcd8a79536638ce85e61a6630a9e6b3139;hp=f97d59b8a4c150f04d60d701bf2e2dc014cb3b6d;hpb=46563ba950bce914454aea923d0bb3761043fd2c;p=platform%2Fupstream%2Fiotivity.git diff --git a/resource/csdk/connectivity/src/bt_le_adapter/android/caleclient.c b/resource/csdk/connectivity/src/bt_le_adapter/android/caleclient.c index f97d59b..87a2d6e 100644 --- a/resource/csdk/connectivity/src/bt_le_adapter/android/caleclient.c +++ b/resource/csdk/connectivity/src/bt_le_adapter/android/caleclient.c @@ -23,6 +23,7 @@ #include #include +#include "calestate.h" #include "caleclient.h" #include "caleserver.h" #include "caleutils.h" @@ -31,17 +32,36 @@ #include "logger.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("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 WAIT_TIME_SCAN_INTERVAL_DEFAULT 10 +#define WAIT_TIME_SCANNED_CHECKING 30 + +#define GATT_CONNECTION_PRIORITY_BALANCED 0 +#define GATT_FAILURE 257 +#define GATT_INSUFFICIENT_AUTHENTICATION 5 +#define GATT_INSUFFICIENT_ENCRYPTION 15 +#define GATT_INVALID_ATTRIBUTE_LENGTH 13 +#define GATT_INVALID_OFFSET 7 +#define GATT_READ_NOT_PERMITTED 2 +#define GATT_REQUEST_NOT_SUPPORTED 6 +#define GATT_WRITE_NOT_PERMITTED 3 + +// samsung +#define BLE_SCAN_API_LEVEL (100) //(21) +#define BLE_MIN_API_LEVEL (18) +#define HIDDEN_API -static const char METHODID_OBJECTNONPARAM[] = "()Landroid/bluetooth/BluetoothAdapter;"; -static const char CLASSPATH_BT_ADAPTER[] = "android/bluetooth/BluetoothAdapter"; -static const char CLASSPATH_BT_UUID[] = "java/util/UUID"; -static const char CLASSPATH_BT_GATT[] = "android/bluetooth/BluetoothGatt"; +static ca_thread_pool_t g_threadPoolHandle = NULL; JavaVM *g_jvm; static u_arraylist_t *g_deviceList = NULL; // device list to have same UUID @@ -50,7 +70,6 @@ static u_arraylist_t *g_deviceStateList = NULL; static CAPacketReceiveCallback g_packetReceiveCallback = NULL; static CABLEErrorHandleCallback g_clientErrorCallback; -static ca_thread_pool_t g_threadPoolHandle = NULL; static jobject g_leScanCallback = NULL; static jobject g_leGattCallback = NULL; static jobject g_context = NULL; @@ -58,27 +77,251 @@ static jobjectArray g_uuidList = NULL; // it will be prevent to start send logic when adapter has stopped. static bool g_isStartedLEClient = false; -static bool g_isStartedMulticastServer = false; -static bool g_isStartedScan = false; static jbyteArray g_sendBuffer = NULL; static uint32_t g_targetCnt = 0; static uint32_t g_currentSentCnt = 0; static bool g_isFinishedSendData = false; -static ca_mutex g_SendFinishMutex = NULL; -static ca_mutex g_threadMutex = NULL; -static ca_cond g_threadCond = 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 oc_mutex g_bleReqRespClientCbMutex = NULL; +static oc_mutex g_bleServerBDAddressMutex = NULL; -static ca_mutex g_threadSendMutex = NULL; +static oc_mutex g_deviceListMutex = NULL; +static oc_mutex g_gattObjectMutex = NULL; +static oc_mutex g_deviceStateListMutex = NULL; -static ca_mutex g_bleReqRespClientCbMutex = NULL; -static ca_mutex g_bleServerBDAddressMutex = NULL; +static oc_mutex g_deviceScanRetryDelayMutex = NULL; +static oc_cond g_deviceScanRetryDelayCond = NULL; -static ca_mutex g_deviceListMutex = NULL; -static ca_mutex g_gattObjectMutex = NULL; -static ca_mutex g_deviceStateListMutex = NULL; +static oc_mutex g_threadScanIntervalMutex = NULL; +static oc_cond g_threadScanIntervalCond = 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_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. + * since there is no retry logic for this error reason in this client. + * @param state constant value of bluetoothgatt. + * @return true - waiting for background connection in BT platform. + * false - connection routine has to be stopped. + */ +static bool CALECheckConnectionStateValue(jint state) +{ + switch(state) + { + case GATT_CONNECTION_PRIORITY_BALANCED: + case GATT_FAILURE: + case GATT_INSUFFICIENT_AUTHENTICATION: + case GATT_INSUFFICIENT_ENCRYPTION: + case GATT_INVALID_ATTRIBUTE_LENGTH: + case GATT_INVALID_OFFSET: + case GATT_READ_NOT_PERMITTED: + case GATT_REQUEST_NOT_SUPPORTED: + case GATT_WRITE_NOT_PERMITTED: + return true; + default: + return false; + } +} + +/** + * 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, next scan state will be %d", + g_scanIntervalTime, intervalTime, nextScanningStep); + + // previous time should be stored. + if (0 < workingCount) + { + g_scanIntervalTimePrev = g_scanIntervalTime; + } + g_scanIntervalTime = intervalTime; + g_intervalCount = workingCount; + g_nextScanningStep = nextScanningStep; +} + +void CALERestartScanWithInterval(int32_t intervalTime, int32_t workingCount, + CALEScanState_t nextScanningStep) +{ + 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) +{ + (void)object; + + bool isAttached = false; + JNIEnv* env = NULL; + jint res = (*g_jvm)->GetEnv(g_jvm, (void**) &env, JNI_VERSION_1_6); + if (JNI_OK != res) + { + res = (*g_jvm)->AttachCurrentThread(g_jvm, &env, NULL); + + if (JNI_OK != res) + { + OIC_LOG(ERROR, TAG, "AttachCurrentThread has failed"); + return; + } + isAttached = true; + } + + oc_mutex_lock(g_threadScanIntervalMutex); + while(g_isWorkingScanThread) + { + OIC_LOG(DEBUG, TAG, "scan waiting time out"); + if (BLE_SCAN_ENABLE == g_curScanningStep) + { + //stop scan + CAResult_t ret = CALEClientStopScan(); + if (CA_STATUS_OK != ret) + { + OIC_LOG(INFO, TAG, "CALEClientStopScan has failed"); + } + } + else if (BLE_SCAN_DISABLE == g_curScanningStep) + { + //start scan + CAResult_t ret = CALEClientStartScan(); + if (CA_STATUS_OK != ret) + { + 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 (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"); + if (BLE_SCAN_DISABLE == g_nextScanningStep) + { + g_curScanningStep = BLE_SCAN_ENABLE; + } + else + { + g_curScanningStep = BLE_SCAN_DISABLE; + } + } + else + { + 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, BLE_SCAN_ENABLE); + } + g_intervalCount--; + OIC_LOG_V(DEBUG, TAG, "interval count : %d", g_intervalCount); + } + g_curScanningStep = BLE_SCAN_DISABLE; + } + else + { + g_curScanningStep = BLE_SCAN_ENABLE; + } + } + } + oc_mutex_unlock(g_threadScanIntervalMutex); + + if (isAttached) + { + (*g_jvm)->DetachCurrentThread(g_jvm); + } +} + +CAResult_t CALEClientStartScanWithInterval() +{ + if (g_isWorkingScanThread) + { + OIC_LOG(DEBUG, TAG, "scan interval logic already running"); + return CA_STATUS_OK; + } + + // initialize scan flags + 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, NULL)) + { + OIC_LOG(ERROR, TAG, "Failed to create read thread!"); + g_isWorkingScanThread = false; + return CA_STATUS_FAILED; + } + + return CA_STATUS_OK; +} + +void CALEClientStopScanWithInterval() +{ + g_isWorkingScanThread = false; + oc_cond_signal(g_threadScanIntervalCond); +} //getting jvm void CALEClientJniInit() @@ -110,11 +353,10 @@ CAResult_t CALECreateJniInterfaceObject() } bool isAttached = false; - JNIEnv* env; + JNIEnv* env = NULL; jint res = (*g_jvm)->GetEnv(g_jvm, (void**) &env, JNI_VERSION_1_6); if (JNI_OK != res) { - OIC_LOG(INFO, TAG, "Could not get JNIEnv pointer"); res = (*g_jvm)->AttachCurrentThread(g_jvm, &env, NULL); if (JNI_OK != res) @@ -125,12 +367,31 @@ CAResult_t CALECreateJniInterfaceObject() isAttached = true; } + jmethodID mid_getApplicationContext = CAGetJNIMethodID(env, "android/content/Context", + "getApplicationContext", + "()Landroid/content/Context;"); + + if (!mid_getApplicationContext) + { + OIC_LOG(ERROR, TAG, "Could not get getApplicationContext method"); + return CA_STATUS_FAILED; + } + + jobject jApplicationContext = (*env)->CallObjectMethod(env, g_context, + mid_getApplicationContext); + if (!jApplicationContext) + { + OIC_LOG(ERROR, TAG, "Could not get application context"); + goto error_exit; + } + jclass jni_LEInterface = (*env)->FindClass(env, "org/iotivity/ca/CaLeClientInterface"); if (!jni_LEInterface) { 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, "", "(Landroid/content/Context;)V"); @@ -140,7 +401,7 @@ CAResult_t CALECreateJniInterfaceObject() goto error_exit; } - (*env)->NewObject(env, jni_LEInterface, LeInterfaceConstructorMethod, g_context); + (*env)->NewObject(env, jni_LEInterface, LeInterfaceConstructorMethod, jApplicationContext); OIC_LOG(DEBUG, TAG, "Create instance for CaLeClientInterface"); if (isAttached) @@ -151,7 +412,7 @@ CAResult_t CALECreateJniInterfaceObject() return CA_STATUS_OK; error_exit: - + CACheckJNIException(env); if (isAttached) { (*g_jvm)->DetachCurrentThread(g_jvm); @@ -160,7 +421,7 @@ error_exit: return CA_STATUS_FAILED; } -CAResult_t CALEClientInitialize(ca_thread_pool_t handle) +CAResult_t CALEClientInitialize() { OIC_LOG(DEBUG, TAG, "CALEClientInitialize"); @@ -173,11 +434,10 @@ CAResult_t CALEClientInitialize(ca_thread_pool_t handle) } bool isAttached = false; - JNIEnv* env; + JNIEnv* env = NULL; jint res = (*g_jvm)->GetEnv(g_jvm, (void**) &env, JNI_VERSION_1_6); if (JNI_OK != res) { - OIC_LOG(INFO, TAG, "Could not get JNIEnv pointer"); res = (*g_jvm)->AttachCurrentThread(g_jvm, &env, NULL); if (JNI_OK != res) @@ -188,8 +448,8 @@ CAResult_t CALEClientInitialize(ca_thread_pool_t handle) 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"); @@ -197,13 +457,10 @@ CAResult_t CALEClientInitialize(ca_thread_pool_t handle) { (*g_jvm)->DetachCurrentThread(g_jvm); } - - return ret; + return CA_STATUS_FAILED; } - g_threadPoolHandle = handle; - - ret = CALEClientInitGattMutexVaraibles(); + CAResult_t ret = CALEClientInitGattMutexVaraibles(); if (CA_STATUS_OK != ret) { OIC_LOG(ERROR, TAG, "CALEClientInitGattMutexVaraibles has failed!"); @@ -217,8 +474,13 @@ CAResult_t CALEClientInitialize(ca_thread_pool_t handle) return ret; } + g_deviceDescCond = oc_cond_new(); + // init mutex for send logic - g_threadCond = 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(); @@ -250,6 +512,11 @@ CAResult_t CALEClientInitialize(ca_thread_pool_t handle) } g_isStartedLEClient = true; + if (isAttached) + { + (*g_jvm)->DetachCurrentThread(g_jvm); + } + return CA_STATUS_OK; } @@ -264,11 +531,10 @@ void CALEClientTerminate() } bool isAttached = false; - JNIEnv* env; + JNIEnv* env = NULL; jint res = (*g_jvm)->GetEnv(g_jvm, (void**) &env, JNI_VERSION_1_6); if (JNI_OK != res) { - OIC_LOG(INFO, TAG, "Could not get JNIEnv pointer"); res = (*g_jvm)->AttachCurrentThread(g_jvm, &env, NULL); if (JNI_OK != res) @@ -279,32 +545,51 @@ 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); + g_leScanCallback = NULL; } if (g_leGattCallback) { (*env)->DeleteGlobalRef(env, g_leGattCallback); + g_leGattCallback = NULL; } - if (g_sendBuffer) + if (g_LEInterface) { - (*env)->DeleteGlobalRef(env, g_sendBuffer); + (*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) { @@ -317,103 +602,105 @@ void CALEClientTerminate() OIC_LOG(ERROR, TAG, "CALEClientRemoveAllGattObjs has failed"); } - g_isStartedMulticastServer = false; - g_isStartedScan = false; - CALEClientSetSendFinishFlag(false); + CALEClientSetSendFinishFlag(true); CALEClientTerminateGattMutexVariables(); + CALEClientDestroyJniInterface(); - ca_cond_free(g_threadCond); + 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); - if (isAttached) - { - (*g_jvm)->DetachCurrentThread(g_jvm); - } -} + g_deviceDescCond = NULL; + g_threadCond = NULL; + g_threadWriteCharacteristicCond = NULL; + g_deviceScanRetryDelayCond = NULL; + g_threadScanIntervalCond = NULL; -void CALEClientSendFinish(JNIEnv *env, jobject gatt) -{ - OIC_LOG(DEBUG, TAG, "CALEClientSendFinish"); - VERIFY_NON_NULL_VOID(env, TAG, "env is null"); + g_isSignalSetFlag = false; - if (gatt) + // stop scanning + CALEClientStopScanWithInterval(); + + if (isAttached) { - CAResult_t res = CALEClientDisconnect(env, gatt); - if (CA_STATUS_OK != res) - { - OIC_LOG(ERROR, TAG, "CALEClientDisconnect has failed"); - } + (*g_jvm)->DetachCurrentThread(g_jvm); } - CALEClientUpdateSendCnt(env); -} - -CAResult_t CALEClientSendUnicastMessage(const char* address, const char* data, - const uint32_t dataLen) -{ - OIC_LOG_V(DEBUG, TAG, "CALEClientSendUnicastMessage(%s, %s)", address, data); - VERIFY_NON_NULL(address, TAG, "address is null"); - VERIFY_NON_NULL(data, TAG, "data is null"); - - return CALEClientSendUnicastMessageImpl(address, data, dataLen); } -CAResult_t CALEClientSendMulticastMessage(const char* data, const uint32_t dataLen) +jobject CALEClientHiddenConnectGatt(jobject btDevice, const char* address, jboolean autoconnect) { - OIC_LOG_V(DEBUG, TAG, "CALEClientSendMulticastMessage(%s)", data); - VERIFY_NON_NULL(data, TAG, "data is null"); + OIC_LOG(INFO, TAG, "IN - CALEClientHiddenConnectGatt"); if (!g_jvm) { OIC_LOG(ERROR, TAG, "g_jvm is null"); - return CA_STATUS_FAILED; + return NULL; } bool isAttached = false; - JNIEnv* env; + JNIEnv* env = NULL; jint res = (*g_jvm)->GetEnv(g_jvm, (void**) &env, JNI_VERSION_1_6); if (JNI_OK != res) { - OIC_LOG(INFO, TAG, "Could not get JNIEnv pointer"); res = (*g_jvm)->AttachCurrentThread(g_jvm, &env, NULL); if (JNI_OK != res) { OIC_LOG(ERROR, TAG, "AttachCurrentThread has failed"); - return CA_STATUS_FAILED; + return NULL; } isAttached = true; } - CAResult_t ret = CALEClientSendMulticastMessageImpl(env, data, dataLen); - if (CA_STATUS_OK != ret) + 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, "CALEClientSendMulticastMessageImpl has failed"); + 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 ret; -} + return gatt; -CAResult_t CALEClientStartUnicastServer(const char* address) -{ - OIC_LOG_V(DEBUG, TAG, "it is not needed in this platform (%s)", address); +error_exit: + CACheckJNIException(env); - return CA_NOT_SUPPORTED; +detach_thread: + if (isAttached) + { + (*g_jvm)->DetachCurrentThread(g_jvm); + } + + return NULL; } -CAResult_t CALEClientStartMulticastServer() +CAResult_t CALEClientDestroyJniInterface() { - OIC_LOG(DEBUG, TAG, "CALEClientStartMulticastServer"); - - if (g_isStartedMulticastServer) - { - OIC_LOG(ERROR, TAG, "server is already started..it will be skipped"); - return CA_STATUS_FAILED; - } + OIC_LOG(DEBUG, TAG, "CALEClientDestroyJniInterface"); if (!g_jvm) { @@ -422,11 +709,10 @@ CAResult_t CALEClientStartMulticastServer() } bool isAttached = false; - JNIEnv* env; + JNIEnv* env = NULL; jint res = (*g_jvm)->GetEnv(g_jvm, (void**) &env, JNI_VERSION_1_6); if (JNI_OK != res) { - OIC_LOG(INFO, TAG, "Could not get JNIEnv pointer"); res = (*g_jvm)->AttachCurrentThread(g_jvm, &env, NULL); if (JNI_OK != res) @@ -437,60 +723,88 @@ CAResult_t CALEClientStartMulticastServer() isAttached = true; } - g_isStartedMulticastServer = true; - CAResult_t ret = CALEClientStartScan(); - if (CA_STATUS_OK != ret) + jclass jni_LeInterface = (*env)->FindClass(env, "org/iotivity/ca/CaLeClientInterface"); + if (!jni_LeInterface) + { + OIC_LOG(ERROR, TAG, "Could not get CaLeClientInterface class"); + goto error_exit; + } + + jmethodID jni_InterfaceDestroyMethod = (*env)->GetStaticMethodID(env, jni_LeInterface, + "destroyLeInterface", + "()V"); + if (!jni_InterfaceDestroyMethod) + { + OIC_LOG(ERROR, TAG, "Could not get CaLeClientInterface destroy method"); + goto error_exit; + } + + (*env)->CallStaticVoidMethod(env, jni_LeInterface, jni_InterfaceDestroyMethod); + + if (CACheckJNIException(env)) { - OIC_LOG(ERROR, TAG, "CALEClientStartScan has failed"); + OIC_LOG(ERROR, TAG, "destroyLeInterface has failed"); + goto detach_thread; } + OIC_LOG(DEBUG, TAG, "Destroy instance for CaLeClientInterface"); + if (isAttached) { (*g_jvm)->DetachCurrentThread(g_jvm); } - return ret; -} + return CA_STATUS_OK; -void CALEClientStopUnicastServer() -{ - OIC_LOG(DEBUG, TAG, "CALEClientStopUnicastServer"); -} +error_exit: + CACheckJNIException(env); -void CALEClientStopMulticastServer() -{ - OIC_LOG(DEBUG, TAG, "CALEClientStopMulticastServer"); - g_isStartedMulticastServer = false; - CAResult_t res = CALEClientStopScan(); - if (CA_STATUS_OK != res) +detach_thread: + if (isAttached) { - OIC_LOG(ERROR, TAG, "CALEClientStartScan has failed"); - return; + (*g_jvm)->DetachCurrentThread(g_jvm); } + + return CA_STATUS_FAILED; } -void CALEClientSetCallback(CAPacketReceiveCallback callback) +void CALEClientSendFinish(JNIEnv *env, jobject gatt) { - g_packetReceiveCallback = callback; + OIC_LOG(DEBUG, TAG, "CALEClientSendFinish"); + VERIFY_NON_NULL_VOID(env, TAG, "env is null"); + + if (gatt) + { + CAResult_t res = CALEClientDisconnect(env, gatt); + if (CA_STATUS_OK != res) + { + OIC_LOG(ERROR, TAG, "CALEClientDisconnect has failed"); + } + } + CALEClientUpdateSendCnt(env); } -void CASetBLEClientErrorHandleCallback(CABLEErrorHandleCallback callback) +CAResult_t CALEClientSendNegotiationMessage(const char* address) { - g_clientErrorCallback = callback; + VERIFY_NON_NULL(address, TAG, "address is null"); + + return CALEClientSendUnicastMessageImpl(address, NULL, 0); } -CAResult_t CALEClientGetInterfaceInfo(char **address) +CAResult_t CALEClientSendUnicastMessage(const char* address, + const uint8_t* data, + const uint32_t dataLen) { - OIC_LOG(INFO, TAG, "CALEClientGetInterfaceInfo is not supported"); - return CA_NOT_SUPPORTED; + VERIFY_NON_NULL(address, TAG, "address is null"); + VERIFY_NON_NULL(data, TAG, "data is null"); + + return CALEClientSendUnicastMessageImpl(address, data, dataLen); } -CAResult_t CALEClientSendUnicastMessageImpl(const char* address, const char* data, - const uint32_t dataLen) +CAResult_t CALEClientSendMulticastMessage(const uint8_t* data, + const uint32_t dataLen) { - OIC_LOG_V(DEBUG, TAG, "CALEClientSendUnicastMessageImpl, address: %s, data: %s", address, - data); - VERIFY_NON_NULL(address, TAG, "address is null"); + OIC_LOG_V(DEBUG, TAG, "CALEClientSendMulticastMessage(%p)", data); VERIFY_NON_NULL(data, TAG, "data is null"); if (!g_jvm) @@ -500,12 +814,12 @@ CAResult_t CALEClientSendUnicastMessageImpl(const char* address, const char* dat } bool isAttached = false; - JNIEnv* env; + JNIEnv* env = NULL; jint res = (*g_jvm)->GetEnv(g_jvm, (void**) &env, JNI_VERSION_1_6); if (JNI_OK != res) { - OIC_LOG(INFO, TAG, "Could not get JNIEnv pointer"); res = (*g_jvm)->AttachCurrentThread(g_jvm, &env, NULL); + if (JNI_OK != res) { OIC_LOG(ERROR, TAG, "AttachCurrentThread has failed"); @@ -514,12 +828,192 @@ CAResult_t CALEClientSendUnicastMessageImpl(const char* address, const char* dat isAttached = true; } - ca_mutex_lock(g_threadSendMutex); - - CAResult_t ret = CA_STATUS_OK; - if (g_context && g_deviceList) + CAResult_t ret = CALEClientSendMulticastMessageImpl(env, data, dataLen); + if (CA_STATUS_OK != ret) { - uint32_t length = u_arraylist_length(g_deviceList); + OIC_LOG(ERROR, TAG, "CALEClientSendMulticastMessageImpl has failed"); + } + + if (isAttached) + { + (*g_jvm)->DetachCurrentThread(g_jvm); + } + + return ret; +} + +CAResult_t CALEClientStartUnicastServer(const char* address) +{ +#ifndef TB_LOG + (void)address; +#endif + OIC_LOG_V(DEBUG, TAG, "it is not needed in this platform (%s)", address); + + return CA_NOT_SUPPORTED; +} + +CAResult_t CALEClientStartMulticastServer() +{ + OIC_LOG(DEBUG, TAG, "it is not needed in this platform"); + + return CA_NOT_SUPPORTED; +} + +void CALEClientStopUnicastServer() +{ + OIC_LOG(DEBUG, TAG, "CALEClientStopUnicastServer"); +} + +void CALEClientStopMulticastServer() +{ + OIC_LOG(DEBUG, TAG, "CALEClientStopMulticastServer"); +} + +void CALEClientSetCallback(CAPacketReceiveCallback callback) +{ + g_packetReceiveCallback = callback; +} + +void CASetBLEClientErrorHandleCallback(CABLEErrorHandleCallback callback) +{ + g_clientErrorCallback = callback; +} + +CAResult_t CALEClientIsThereScannedDevices(JNIEnv *env, const char* address) +{ + VERIFY_NON_NULL(env, TAG, "env"); + + if (!g_deviceList) + { + OIC_LOG(ERROR, TAG, "g_deviceList is not available"); + return CA_STATUS_FAILED; + } + + if (0 == u_arraylist_length(g_deviceList) // multicast + || (address && !CALEClientIsDeviceInScanDeviceList(env, address))) // unicast + { + // Wait for LE peripherals to be discovered. + + // Number of times to wait for discovery to complete. + static size_t const RETRIES = 5; + + static uint64_t const TIMEOUT = + 2 * MICROSECS_PER_SEC; // Microseconds + + // set scan interval and start scan + 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 (oc_cond_wait_for(g_deviceDescCond, + g_threadSendMutex, + TIMEOUT) == OC_WAIT_SUCCESS) + { + OIC_LOG(DEBUG, TAG, "time out"); + oc_mutex_lock(g_deviceListMutex); + size_t scannedDeviceLen = u_arraylist_length(g_deviceList); + oc_mutex_unlock(g_deviceListMutex); + + if (0 < scannedDeviceLen) + { + if (!address // multicast + || (address && CALEClientIsDeviceInScanDeviceList(env, address))) // unicast + { + devicesDiscovered = true; + break; + } + else + { + if (address) + { + OIC_LOG(INFO, TAG, "waiting.."); + + oc_mutex_lock(g_deviceScanRetryDelayMutex); + if (oc_cond_wait_for(g_deviceScanRetryDelayCond, + g_deviceScanRetryDelayMutex, + MICROSECS_PER_SEC) == OC_WAIT_SUCCESS) + { + OIC_LOG(INFO, TAG, "finish to waiting for target device"); + oc_mutex_unlock(g_deviceScanRetryDelayMutex); + break; + } + oc_mutex_unlock(g_deviceScanRetryDelayMutex); + // time out + + // checking whether a target device is found while waiting for time-out. + if (CALEClientIsDeviceInScanDeviceList(env, address)) + { + devicesDiscovered = true; + break; + } + } + } + } + } + } + + // reset scan interval time after checking scanned devices + CALERestartScanWithInterval(0, 0, BLE_SCAN_DISABLE); + + // time out for scanning devices + if (!devicesDiscovered) + { + return CA_STATUS_FAILED; + } + } + else + { + OIC_LOG(DEBUG, TAG, "there is a target device in the scanned devices"); + } + + return CA_STATUS_OK; +} + + +CAResult_t CALEClientSendUnicastMessageImpl(const char* address, const uint8_t* data, + const uint32_t dataLen) +{ + 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"); + + if (!g_jvm) + { + OIC_LOG(ERROR, TAG, "g_jvm is null"); + return CA_STATUS_FAILED; + } + + 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 CA_STATUS_FAILED; + } + isAttached = true; + } + + oc_mutex_lock(g_threadSendMutex); + + CALEClientSetSendFinishFlag(false); + + CAResult_t ret = CALEClientIsThereScannedDevices(env, address); + if (CA_STATUS_OK != ret) + { + OIC_LOG(INFO, TAG, "there is no scanned device"); + goto error_exit; + } + + if (g_context && g_deviceList) + { + uint32_t length = u_arraylist_length(g_deviceList); for (uint32_t index = 0; index < length; index++) { jobject jarrayObj = (jobject) u_arraylist_get(g_deviceList, index); @@ -540,30 +1034,29 @@ CAResult_t CALEClientSendUnicastMessageImpl(const char* address, const char* dat 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); - // connect to gatt server - ret = CALEClientStopScan(); - if (CA_STATUS_OK != ret) - { - OIC_LOG(ERROR, TAG, "CALEClientStopScan has failed"); - goto error_exit; - } + CALEDeleteSendBuffer(env); - if (g_sendBuffer) + if (data && dataLen > 0) { - (*env)->DeleteGlobalRef(env, g_sendBuffer); + 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; ret = CALEClientSendData(env, jarrayObj); if (CA_STATUS_OK != ret) @@ -576,58 +1069,80 @@ CAResult_t CALEClientSendUnicastMessageImpl(const char* address, const char* dat break; } (*env)->ReleaseStringUTFChars(env, jni_setAddress, setAddress); + (*env)->DeleteLocalRef(env, jni_setAddress); } } + OIC_LOG(DEBUG, TAG, "connection routine is finished for unicast"); + + // wait for finish to send data through "CALeGattServicesDiscoveredCallback" + // if there is no connection state. + oc_mutex_lock(g_threadMutex); + if (!g_isFinishedSendData) + { + OIC_LOG(DEBUG, TAG, "waiting send finish signal"); + oc_cond_wait(g_threadCond, g_threadMutex); + OIC_LOG(DEBUG, TAG, "connection / send is finished for unicast"); + } + oc_mutex_unlock(g_threadMutex); + if (isAttached) { (*g_jvm)->DetachCurrentThread(g_jvm); } - ret = CALECheckSendState(address); - 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, "send has failed"); - goto error_exit; + OIC_LOG(INFO, TAG, "send success"); + ret = CA_STATUS_OK; + } + 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; } - // start LE Scan again - ret = CALEClientStartScan(); - if (CA_STATUS_OK != ret) + // reset send state + CAResult_t resetRet = CALEUpdateDeviceState(address, CA_LE_SEND_STATE, + STATE_SEND_NONE, + g_deviceStateList, + g_deviceStateListMutex); + if (CA_STATUS_OK != resetRet) { - OIC_LOG(ERROR, TAG, "CALEClientStartScan has failed"); - ca_mutex_unlock(g_threadSendMutex); - return res; + OIC_LOG_V(ERROR, TAG, "CALEUpdateDeviceState has failed (%d)", resetRet); + ret = CA_SEND_FAILED; } - ca_mutex_unlock(g_threadSendMutex); - OIC_LOG(INFO, TAG, "unicast - send success"); - return CA_STATUS_OK; + return ret; // error label. error_exit: - - // start LE Scan again - ret = CALEClientStartScan(); - if (CA_STATUS_OK != ret) - { - OIC_LOG(ERROR, TAG, "CALEClientStartScan has failed"); - ca_mutex_unlock(g_threadSendMutex); - return res; - } - if (isAttached) { (*g_jvm)->DetachCurrentThread(g_jvm); } - ca_mutex_unlock(g_threadSendMutex); + + oc_mutex_unlock(g_threadSendMutex); return CA_SEND_FAILED; } -CAResult_t CALEClientSendMulticastMessageImpl(JNIEnv *env, const char* data, +CAResult_t CALEClientSendMulticastMessageImpl(JNIEnv *env, const uint8_t* data, const uint32_t dataLen) { - OIC_LOG_V(DEBUG, TAG, "CASendMulticastMessageImpl, send to, data: %s, %d", data, dataLen); + OIC_LOG_V(DEBUG, TAG, "CASendMulticastMessageImpl, send to, data: %p, %u", data, dataLen); VERIFY_NON_NULL(data, TAG, "data is null"); VERIFY_NON_NULL(env, TAG, "env is null"); @@ -637,34 +1152,26 @@ CAResult_t CALEClientSendMulticastMessageImpl(JNIEnv *env, const char* 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); - } - jbyteArray jni_arr = (*env)->NewByteArray(env, dataLen); - (*env)->SetByteArrayRegion(env, jni_arr, 0, dataLen, (jbyte*) data); - g_sendBuffer = (jbyteArray)(*env)->NewGlobalRef(env, jni_arr); + CALEDeleteSendBuffer(env); - // connect to gatt server - CAResult_t res = CALEClientStopScan(); + CAResult_t res = CALEClientIsThereScannedDevices(env, NULL); if (CA_STATUS_OK != res) { - OIC_LOG(ERROR, TAG, "CALEClientStopScan has failed"); - ca_mutex_unlock(g_threadSendMutex); - return res; + OIC_LOG(INFO, TAG, "there is no scanned device"); + goto error_exit; } uint32_t length = u_arraylist_length(g_deviceList); g_targetCnt = length; - if (0 == length) - { - goto error_exit; - } + + jbyteArray jni_arr = (*env)->NewByteArray(env, dataLen); + (*env)->SetByteArrayRegion(env, jni_arr, 0, dataLen, (jbyte*) data); + g_sendBuffer = (jbyteArray)(*env)->NewGlobalRef(env, jni_arr); for (uint32_t index = 0; index < length; index++) { @@ -678,135 +1185,110 @@ CAResult_t CALEClientSendMulticastMessageImpl(JNIEnv *env, const char* data, res = CALEClientSendData(env, jarrayObj); if (res != CA_STATUS_OK) { - OIC_LOG(ERROR, TAG, "BT device[%d] - send has failed"); - } - - jstring jni_address = CALEGetAddressFromBTDevice(env, jarrayObj); - if (!jni_address) - { - OIC_LOG(ERROR, TAG, "CALEGetAddressFromBTDevice has failed"); - continue; - } - - const char* address = (*env)->GetStringUTFChars(env, jni_address, NULL); - if (!address) - { - OIC_LOG(ERROR, TAG, "address is not available"); - continue; - } - - res = CALECheckSendState(address); - if (CA_STATUS_OK != res) - { - OIC_LOG_V(INFO, TAG, "multicast : send has failed for this device[%s]", address); - g_clientErrorCallback(address, data, dataLen, res); - (*env)->ReleaseStringUTFChars(env, jni_address, address); - continue; + OIC_LOG(ERROR, TAG, "BT device - send has failed"); } - - (*env)->ReleaseStringUTFChars(env, jni_address, address); } - OIC_LOG(DEBUG, TAG, "connection routine is finished"); + OIC_LOG(DEBUG, TAG, "connection routine is finished for multicast"); // wait for finish to send data through "CALeGattServicesDiscoveredCallback" + oc_mutex_lock(g_threadMutex); if (!g_isFinishedSendData) { - ca_mutex_lock(g_threadMutex); - ca_cond_wait(g_threadCond, g_threadMutex); - OIC_LOG(DEBUG, TAG, "the data was sent for All devices"); - ca_mutex_unlock(g_threadMutex); - } - - // start LE Scan again - res = CALEClientStartScan(); - if (CA_STATUS_OK != res) - { - OIC_LOG(ERROR, TAG, "CALEClientStartScan has failed"); - ca_mutex_unlock(g_threadSendMutex); - return res; + OIC_LOG(DEBUG, TAG, "waiting send finish signal"); + 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 = CALEClientStartScan(); - if (CA_STATUS_OK != res) - { - OIC_LOG(ERROR, TAG, "CALEClientStartScan has failed"); - ca_mutex_unlock(g_threadSendMutex); - return res; - } - - ca_mutex_unlock(g_threadSendMutex); - OIC_LOG(DEBUG, TAG, "OUT - CALEClientSendMulticastMessageImpl"); + oc_mutex_unlock(g_threadSendMutex); + OIC_LOG(ERROR, TAG, "OUT - CALEClientSendMulticastMessageImpl"); return CA_SEND_FAILED; } -CAResult_t CALECheckSendState(const char* address) -{ - VERIFY_NON_NULL(address, TAG, "address is null"); - - ca_mutex_lock(g_deviceStateListMutex); - CALEState_t* state = CALEClientGetStateInfo(address); - if (NULL == state) - { - OIC_LOG(ERROR, TAG, "state is null"); - ca_mutex_unlock(g_deviceStateListMutex); - return CA_SEND_FAILED; - } - - if (STATE_SEND_SUCCESS != state->sendState) - { - OIC_LOG(ERROR, TAG, "sendstate is not STATE_SEND_SUCCESS"); - ca_mutex_unlock(g_deviceStateListMutex); - return CA_SEND_FAILED; - } - ca_mutex_unlock(g_deviceStateListMutex); - return CA_STATUS_OK; -} - CAResult_t CALEClientSendData(JNIEnv *env, jobject device) { OIC_LOG(DEBUG, TAG, "IN - CALEClientSendData"); VERIFY_NON_NULL(device, TAG, "device is null"); VERIFY_NON_NULL(env, TAG, "env is null"); - jstring jni_address = CALEGetAddressFromBTDevice(env, device); - if (!jni_address) + // get BLE address from bluetooth device object. + char* address = NULL; + CALEState_t* state = NULL; + jstring jni_address = CALEClientGetLEAddressFromBTDevice(env, device); + if (jni_address) { - OIC_LOG(ERROR, TAG, "CALEGetAddressFromBTDevice has failed"); - return CA_STATUS_FAILED; + OIC_LOG(INFO, TAG, "there is gatt object..it's not first connection"); + address = (char*)(*env)->GetStringUTFChars(env, jni_address, NULL); + if (!address) + { + OIC_LOG(ERROR, TAG, "address is not available"); + CACheckJNIException(env); + return CA_STATUS_FAILED; + } + oc_mutex_lock(g_deviceStateListMutex); + state = CALEGetStateInfo(address, g_deviceStateList); + oc_mutex_unlock(g_deviceStateListMutex); } - const char* address = (*env)->GetStringUTFChars(env, jni_address, NULL); - if (!address) + // 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, "address is not available"); + OIC_LOG(ERROR, TAG, "CALEClientUpdateDeviceStateWithBtDevice has failed"); + if (address) + { + (*env)->ReleaseStringUTFChars(env, jni_address, address); + } return CA_STATUS_FAILED; } - ca_mutex_lock(g_deviceStateListMutex); - CALEState_t* state = CALEClientGetStateInfo(address); - ca_mutex_unlock(g_deviceStateListMutex); if (!state) { OIC_LOG(DEBUG, TAG, "state is empty..start to connect LE"); - CAResult_t ret = CALEClientConnect(env, device, JNI_FALSE, g_leGattCallback); - if (CA_STATUS_OK != ret) + + // cancel previous connection request before connection + // if there is gatt object in g_gattObjectList. + if (jni_address) { - OIC_LOG(ERROR, TAG, "CALEClientConnect has failed"); + jobject gatt = CALEClientGetGattObjInList(env, address); + if (gatt) + { + CAResult_t res = CALEClientDisconnect(env, gatt); + if (CA_STATUS_OK != res) + { + OIC_LOG(INFO, TAG, "there is no gatt object"); + } + } (*env)->ReleaseStringUTFChars(env, jni_address, address); - return ret; + } + + // connection request + jobject newGatt = CALEClientConnect(env, device, + JNI_FALSE); + if (NULL == newGatt) + { + OIC_LOG(ERROR, TAG, "CALEClientConnect has failed"); + return CA_STATUS_FAILED; } } else { - if (STATE_CONNECTED == state->connectedState) + if (CALEIsValidState(address, CA_LE_CONNECTION_STATE, + STATE_SERVICE_CONNECTED, + g_deviceStateList, + g_deviceStateListMutex)) { OIC_LOG(INFO, TAG, "GATT has already connected"); + jobject gatt = CALEClientGetGattObjInList(env, address); if (!gatt) { @@ -815,28 +1297,60 @@ CAResult_t CALEClientSendData(JNIEnv *env, jobject device) return CA_STATUS_FAILED; } - CAResult_t ret = CALEClientWriteCharacteristic(env, gatt); + CAResult_t ret = CALESetValueAndWriteCharacteristic(env, gatt); if (CA_STATUS_OK != ret) { - OIC_LOG(ERROR, TAG, "CALEClientWriteCharacteristic has failed"); + OIC_LOG(ERROR, TAG, "CALESetValueAndWriteCharacteristic has failed"); (*env)->ReleaseStringUTFChars(env, jni_address, address); return ret; } + (*env)->ReleaseStringUTFChars(env, jni_address, address); } - else + else if(CALEIsValidState(address, CA_LE_CONNECTION_STATE, + STATE_CONNECTED, + g_deviceStateList, + g_deviceStateListMutex)) + { + OIC_LOG(INFO, TAG, "service connecting..."); + } + else if(CALEIsValidState(address, CA_LE_CONNECTION_STATE, + STATE_DISCONNECTED, + g_deviceStateList, + g_deviceStateListMutex)) { + OIC_LOG(INFO, TAG, "STATE_DISCONNECTED - start to connect LE"); + + // cancel previous connection request before connection + // if there is gatt object in g_gattObjectList. + if (jni_address) + { + jobject gatt = CALEClientGetGattObjInList(env, address); + if (gatt) + { + CAResult_t res = CALEClientDisconnect(env, gatt); + if (CA_STATUS_OK != res) + { + OIC_LOG(INFO, TAG, "there is no gatt object"); + } + } + (*env)->ReleaseStringUTFChars(env, jni_address, address); + } + OIC_LOG(DEBUG, TAG, "start to connect LE"); - CAResult_t ret = CALEClientConnect(env, device, JNI_FALSE, g_leGattCallback); - if (CA_STATUS_OK != ret) + jobject gatt = CALEClientConnect(env, device, + CALEGetFlagFromState(env, jni_address, + CA_LE_AUTO_CONNECT_FLAG, + g_deviceStateList, + g_deviceStateListMutex)); + + if (NULL == gatt) { OIC_LOG(ERROR, TAG, "CALEClientConnect has failed"); - (*env)->ReleaseStringUTFChars(env, jni_address, address); - return ret; + return CA_STATUS_FAILED; } } } - (*env)->ReleaseStringUTFChars(env, jni_address, address); return CA_STATUS_OK; } @@ -845,15 +1359,8 @@ jstring CALEClientGetAddressFromGattObj(JNIEnv *env, jobject gatt) VERIFY_NON_NULL_RET(gatt, TAG, "gatt is null", NULL); VERIFY_NON_NULL_RET(env, TAG, "env is null", NULL); - jclass jni_cid_gattdevice_list = (*env)->FindClass(env, CLASSPATH_BT_GATT); - if (!jni_cid_gattdevice_list) - { - OIC_LOG(ERROR, TAG, "jni_cid_gattdevice_list is null"); - return NULL; - } - - jmethodID jni_mid_getDevice = (*env)->GetMethodID(env, jni_cid_gattdevice_list, "getDevice", - "()Landroid/bluetooth/BluetoothDevice;"); + jmethodID jni_mid_getDevice = CAGetJNIMethodID(env, CLASSPATH_BT_GATT, "getDevice", + "()Landroid/bluetooth/BluetoothDevice;"); if (!jni_mid_getDevice) { OIC_LOG(ERROR, TAG, "jni_mid_getDevice is null"); @@ -864,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; } @@ -871,6 +1379,7 @@ jstring CALEClientGetAddressFromGattObj(JNIEnv *env, jobject gatt) if (!jni_address) { OIC_LOG(ERROR, TAG, "jni_address is null"); + CACheckJNIException(env); return NULL; } @@ -887,16 +1396,9 @@ CAResult_t CALEClientGattClose(JNIEnv *env, jobject bluetoothGatt) VERIFY_NON_NULL(bluetoothGatt, TAG, "bluetoothGatt is null"); VERIFY_NON_NULL(env, TAG, "env is null"); - // get BluetoothGatt class - OIC_LOG(DEBUG, TAG, "get BluetoothGatt class"); - jclass jni_cid_BluetoothGatt = (*env)->FindClass(env, CLASSPATH_BT_GATT); - if (!jni_cid_BluetoothGatt) - { - OIC_LOG(ERROR, TAG, "jni_cid_BluetoothGatt is null"); - return CA_STATUS_FAILED; - } - - jmethodID jni_mid_closeGatt = (*env)->GetMethodID(env, jni_cid_BluetoothGatt, "close", "()V"); + // get BluetoothGatt method + OIC_LOG(DEBUG, TAG, "get BluetoothGatt method"); + jmethodID jni_mid_closeGatt = CAGetJNIMethodID(env, CLASSPATH_BT_GATT, "close", "()V"); if (!jni_mid_closeGatt) { OIC_LOG(ERROR, TAG, "jni_mid_closeGatt is null"); @@ -907,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; } @@ -920,12 +1420,6 @@ CAResult_t CALEClientGattClose(JNIEnv *env, jobject bluetoothGatt) CAResult_t CALEClientStartScan() { - if (!g_isStartedMulticastServer) - { - OIC_LOG(ERROR, TAG, "server is not started yet..scan will be passed"); - return CA_STATUS_FAILED; - } - if (!g_isStartedLEClient) { OIC_LOG(ERROR, TAG, "LE client is not started"); @@ -938,19 +1432,11 @@ CAResult_t CALEClientStartScan() return CA_STATUS_FAILED; } - if (g_isStartedScan) - { - OIC_LOG(INFO, TAG, "scanning is already started"); - return CA_STATUS_OK; - } - bool isAttached = false; - JNIEnv* env; + JNIEnv* env = NULL; jint res = (*g_jvm)->GetEnv(g_jvm, (void**) &env, JNI_VERSION_1_6); if (JNI_OK != res) { - OIC_LOG(INFO, TAG, "Could not get JNIEnv pointer"); - res = (*g_jvm)->AttachCurrentThread(g_jvm, &env, NULL); if (JNI_OK != res) { @@ -966,19 +1452,42 @@ CAResult_t CALEClientStartScan() // scan gatt server with UUID if (g_leScanCallback && g_uuidList) { -#ifdef UUID_SCAN - ret = CALEClientStartScanWithUUIDImpl(env, g_uuidList, g_leScanCallback); - if(CA_STATUS_OK != ret) + if (g_jniIntSdk >= BLE_SCAN_API_LEVEL) { - OIC_LOG(ERROR, TAG, "CALEClientStartScanWithUUIDImpl has failed"); + 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 - ret = CALEClientStartScanImpl(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) { - OIC_LOG(ERROR, TAG, "CALEClientStartScanImpl has failed"); + if (CA_ADAPTER_NOT_ENABLED == ret) + { + OIC_LOG(DEBUG, TAG, "Adapter is disabled"); + } + else + { + OIC_LOG(ERROR, TAG, "start scan has failed"); + } } -#endif } if (isAttached) @@ -991,12 +1500,13 @@ 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"); if (!CALEIsEnableBTAdapter(env)) { - OIC_LOG(ERROR, TAG, "BT adapter is not enabled"); + OIC_LOG(INFO, TAG, "BT adapter is not enabled"); return CA_ADAPTER_NOT_ENABLED; } @@ -1005,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; } @@ -1015,6 +1526,8 @@ 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; } @@ -1025,6 +1538,8 @@ 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; } @@ -1034,35 +1549,144 @@ 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; } // call start le scan method + OIC_LOG(INFO, TAG, "CALL API - startLeScan"); jboolean jni_obj_startLeScan = (*env)->CallBooleanMethod(env, jni_obj_BTAdapter, jni_mid_startLeScan, callback); if (!jni_obj_startLeScan) { - OIC_LOG(ERROR, TAG, "startLeScan is failed"); - return CA_STATUS_FAILED; + OIC_LOG(INFO, TAG, "startLeScan has failed"); + CACheckJNIException(env); } else { - OIC_LOG(DEBUG, TAG, "startLeScan is started"); - g_isStartedScan = true; + OIC_LOG(DEBUG, TAG, "LeScan has started"); } + (*env)->DeleteLocalRef(env, jni_cid_BTAdapter); + (*env)->DeleteLocalRef(env, jni_obj_BTAdapter); 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"); if (!CALEIsEnableBTAdapter(env)) { - OIC_LOG(ERROR, TAG, "BT adapter is not enabled"); + OIC_LOG(INFO, TAG, "BT adapter is not enabled"); return CA_ADAPTER_NOT_ENABLED; } @@ -1070,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; } @@ -1080,6 +1705,8 @@ 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; } @@ -1090,6 +1717,8 @@ 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; } @@ -1099,26 +1728,403 @@ 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; } // call start le scan method + OIC_LOG(INFO, TAG, "CALL API - startLeScan (with UUID)"); jboolean jni_obj_startLeScan = (*env)->CallBooleanMethod(env, jni_obj_BTAdapter, jni_mid_startLeScan, uuids, callback); if (!jni_obj_startLeScan) { - OIC_LOG(ERROR, TAG, "startLeScan With UUID is failed"); - return CA_STATUS_FAILED; + OIC_LOG(INFO, TAG, "startLeScan has failed"); + CACheckJNIException(env); } else { - OIC_LOG(DEBUG, TAG, "startLeScan With UUID is started"); - g_isStartedScan = true; + OIC_LOG(DEBUG, TAG, "LeScan has started"); } + (*env)->DeleteLocalRef(env, jni_cid_BTAdapter); + (*env)->DeleteLocalRef(env, jni_obj_BTAdapter); return CA_STATUS_OK; } +CAResult_t CALEClientStartScanWithUUIDImplForV21(JNIEnv *env, jobjectArray uuids, jobject callback) +{ + 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"); + + if (!CALEIsEnableBTAdapter(env)) + { + OIC_LOG(INFO, TAG, "BT adapter is not enabled"); + return CA_ADAPTER_NOT_ENABLED; + } + + // 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); + return CA_STATUS_FAILED; + } + + // 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, + "", "()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, + "", "()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, "", "()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); @@ -1129,7 +2135,7 @@ jobject CALEClientGetUUIDObject(JNIEnv *env, const char* uuid) if (!jni_cid_uuid) { OIC_LOG(ERROR, TAG, "jni_cid_uuid is null"); - return NULL; + goto error_exit; } jmethodID jni_mid_fromString = (*env)->GetStaticMethodID(env, jni_cid_uuid, "fromString", @@ -1138,19 +2144,24 @@ jobject CALEClientGetUUIDObject(JNIEnv *env, const char* uuid) if (!jni_mid_fromString) { OIC_LOG(ERROR, TAG, "jni_mid_fromString is null"); - return 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() @@ -1161,18 +2172,11 @@ CAResult_t CALEClientStopScan() return CA_STATUS_FAILED; } - if (!g_isStartedScan) - { - OIC_LOG(INFO, TAG, "scanning is already stopped"); - return CA_STATUS_OK; - } - bool isAttached = false; - JNIEnv* env; + JNIEnv* env = NULL; jint res = (*g_jvm)->GetEnv(g_jvm, (void**) &env, JNI_VERSION_1_6); if (JNI_OK != res) { - OIC_LOG(INFO, TAG, "Could not get JNIEnv pointer"); res = (*g_jvm)->AttachCurrentThread(g_jvm, &env, NULL); if (JNI_OK != res) { @@ -1182,14 +2186,27 @@ CAResult_t CALEClientStopScan() isAttached = true; } - CAResult_t ret = CALEClientStopScanImpl(env, g_leScanCallback); - if (CA_STATUS_OK != ret) + CAResult_t ret = CA_STATUS_FAILED; + + if (g_jniIntSdk >= BLE_SCAN_API_LEVEL) { - OIC_LOG(ERROR, TAG, "CALEClientStopScanImpl has failed"); + ret = CALEClientStopScanImplForV21(env, g_leScanCallback); } else { - g_isStartedScan = false; + ret = CALEClientStopScanImpl(env, g_leScanCallback); + } + + if (CA_STATUS_OK != ret) + { + if (CA_ADAPTER_NOT_ENABLED == ret) + { + OIC_LOG(DEBUG, TAG, "Adapter is disabled"); + } + else + { + OIC_LOG(ERROR, TAG, "CALEClientStopScanImpl has failed"); + } } if (isAttached) @@ -1202,13 +2219,13 @@ 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"); if (!CALEIsEnableBTAdapter(env)) { - OIC_LOG(ERROR, TAG, "BT adapter is not enabled"); + OIC_LOG(INFO, TAG, "BT adapter is not enabled"); return CA_ADAPTER_NOT_ENABLED; } @@ -1217,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; } @@ -1227,246 +2245,838 @@ 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; } - // get start le scan method - jmethodID jni_mid_stopLeScan = (*env)->GetMethodID(env, jni_cid_BTAdapter, "stopLeScan", - "(Landroid/bluetooth/" - "BluetoothAdapter$LeScanCallback;)V"); - if (!jni_mid_stopLeScan) + // get start le scan method + jmethodID jni_mid_stopLeScan = (*env)->GetMethodID(env, jni_cid_BTAdapter, "stopLeScan", + "(Landroid/bluetooth/" + "BluetoothAdapter$LeScanCallback;)V"); + 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; + } + + // 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; + } + + OIC_LOG(INFO, TAG, "CALL API - stopLeScan"); + // call start le scan method + (*env)->CallVoidMethod(env, jni_obj_BTAdapter, jni_mid_stopLeScan, callback); + if (CACheckJNIException(env)) + { + OIC_LOG(ERROR, TAG, "stopLeScan has failed"); + (*env)->DeleteLocalRef(env, jni_cid_BTAdapter); + (*env)->DeleteLocalRef(env, jni_obj_BTAdapter); + return CA_STATUS_FAILED; + } + + (*env)->DeleteLocalRef(env, jni_cid_BTAdapter); + (*env)->DeleteLocalRef(env, jni_obj_BTAdapter); + return CA_STATUS_OK; +} + +CAResult_t CALEClientStopScanImplForV21(JNIEnv *env, jobject callback) +{ + OIC_LOG(DEBUG, TAG, "CALEClientStopScanImplForV21 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; + } + + // 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"); + CACheckJNIException(env); + (*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"); + CACheckJNIException(env); + (*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); + (*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); + + // 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, "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); + + // 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); + return CA_STATUS_FAILED; + } + + // 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)) + { + OIC_LOG(INFO, TAG, "stopScan for level 21 has failed"); + (*env)->DeleteLocalRef(env, jni_obj_leScanner); + return CA_STATUS_FAILED; + } + + (*env)->DeleteLocalRef(env, jni_obj_leScanner); + return CA_STATUS_OK; +} + +CAResult_t CALEClientDirectConnect(JNIEnv *env, jobject bluetoothDevice, jboolean autoconnect) +{ + OIC_LOG(DEBUG, TAG, "CALEClientDirectConnect"); + VERIFY_NON_NULL(env, TAG, "env is null"); + VERIFY_NON_NULL(bluetoothDevice, TAG, "bluetoothDevice is null"); + + oc_mutex_lock(g_threadSendMutex); + + jstring jni_address = CALEGetAddressFromBTDevice(env, bluetoothDevice); + if (!jni_address) + { + OIC_LOG(ERROR, TAG, "jni_address is not available"); + oc_mutex_unlock(g_threadSendMutex); + return CA_STATUS_FAILED; + } + + const char* address = (*env)->GetStringUTFChars(env, jni_address, NULL); + if (!address) + { + OIC_LOG(ERROR, TAG, "address is not available"); + CACheckJNIException(env); + oc_mutex_unlock(g_threadSendMutex); + return CA_STATUS_FAILED; + } + + CAResult_t res = CA_STATUS_OK; + if(CALEIsValidState(address, CA_LE_CONNECTION_STATE, + STATE_DISCONNECTED, + g_deviceStateList, + g_deviceStateListMutex)) + { + jobject newGatt = CALEClientConnect(env, bluetoothDevice, autoconnect); + if (NULL == newGatt) + { + OIC_LOG(INFO, TAG, "newGatt is not available"); + res = CA_STATUS_FAILED; + } + } + oc_mutex_unlock(g_threadSendMutex); + + return res; +} + +jobject CALEClientConnect(JNIEnv *env, jobject bluetoothDevice, jboolean autoconnect) +{ + OIC_LOG(DEBUG, TAG, "CALEClientConnect"); + VERIFY_NON_NULL_RET(env, TAG, "env is null", NULL); + VERIFY_NON_NULL_RET(bluetoothDevice, TAG, "bluetoothDevice is null", NULL); + + // 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) + { + const char* address = (*env)->GetStringUTFChars(env, jni_address, NULL); + if (!address) + { + OIC_LOG(ERROR, TAG, "address is not available"); + return NULL; + } + + // close the gatt service + jobject gatt = CALEClientGetGattObjInList(env, address); + if (gatt) + { + CAResult_t res = CALEClientCloseProfileProxy(env, gatt); + if (CA_STATUS_OK != res) + { + OIC_LOG(ERROR, TAG, "CALEClientCloseProfileProxy has failed"); + (*env)->ReleaseStringUTFChars(env, jni_address, address); + return NULL; + } + + // clean previous gatt object after close profile service + res = CALEClientRemoveGattObjForAddr(env, jni_address); + if (CA_STATUS_OK != res) + { + OIC_LOG(ERROR, TAG, "CALEClientRemoveGattObjForAddr has failed"); + (*env)->ReleaseStringUTFChars(env, jni_address, address); + return NULL; + } + } + (*env)->ReleaseStringUTFChars(env, jni_address, address); + } + + jobject newGatt = CALEClientGattConnect(env, bluetoothDevice, autoconnect); + if (!newGatt) + { + OIC_LOG(DEBUG, TAG, "re-connection will be started"); + return NULL; + } + + // add new gatt object into g_gattObjectList + CAResult_t res = CALEClientAddGattobjToList(env, newGatt); + if (CA_STATUS_OK != res) + { + OIC_LOG(ERROR, TAG, "CALEClientAddGattobjToList has failed"); + return NULL; + } + + return newGatt; +} + +jobject CALEClientGattConnect(JNIEnv *env, jobject bluetoothDevice, jboolean autoconnect) +{ + OIC_LOG(DEBUG, TAG, "GATT CONNECT"); + VERIFY_NON_NULL_RET(env, TAG, "env is null", NULL); + VERIFY_NON_NULL_RET(bluetoothDevice, TAG, "bluetoothDevice is null", NULL); + + if (!g_leGattCallback) + { + OIC_LOG(INFO, TAG, "g_leGattCallback is null"); + return NULL; + } + + if (!CALEIsEnableBTAdapter(env)) + { + OIC_LOG(INFO, TAG, "BT adapter is not enabled"); + return NULL; + } + + jstring jni_address = CALEGetAddressFromBTDevice(env, bluetoothDevice); + if (!jni_address) + { + OIC_LOG(ERROR, TAG, "bleConnect: CALEGetAddressFromBTDevice is null"); + return NULL; + } + + 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 + { + 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; + } + + 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 // lower than API level 23 + { +#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"); + + VERIFY_NON_NULL(env, TAG, "env is null"); + VERIFY_NON_NULL(gatt, TAG, "gatt is null"); + + jclass jni_cid_BTAdapter = (*env)->FindClass(env, CLASSPATH_BT_ADAPTER); + if (!jni_cid_BTAdapter) + { + OIC_LOG(ERROR, TAG, "jni_cid_BTAdapter is null"); + goto error_exit; + } + + // get remote bt adapter method + jmethodID jni_mid_getDefaultAdapter = (*env)->GetStaticMethodID(env, jni_cid_BTAdapter, + "getDefaultAdapter", + METHODID_OBJECTNONPARAM); + if (!jni_mid_getDefaultAdapter) + { + OIC_LOG(ERROR, TAG, "jni_mid_getDefaultAdapter is null"); + goto error_exit; + } + + // gat bt adapter object + jobject jni_obj_BTAdapter = (*env)->CallStaticObjectMethod(env, jni_cid_BTAdapter, + jni_mid_getDefaultAdapter); + if (!jni_obj_BTAdapter) + { + OIC_LOG(ERROR, TAG, "jni_obj_BTAdapter is null"); + goto error_exit; + } + + // get closeProfileProxy method + jmethodID jni_mid_closeProfileProxy = (*env)->GetMethodID(env, jni_cid_BTAdapter, + "closeProfileProxy", + "(ILandroid/bluetooth/" + "BluetoothProfile;)V"); + if (!jni_mid_closeProfileProxy) + { + OIC_LOG(ERROR, TAG, "jni_mid_closeProfileProxy is null"); + 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"); + goto error_exit; + } + + // GATT - Constant value : 7 (0x00000007) + jfieldID id_gatt = (*env)->GetStaticFieldID(env, jni_cid_BTProfile, + "GATT", "I"); + if (!id_gatt) + { + OIC_LOG(ERROR, TAG, "id_gatt is null"); + 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 (CACheckJNIException(env)) + { + OIC_LOG(ERROR, TAG, "closeProfileProxy has failed"); + return CA_STATUS_FAILED; + } + + OIC_LOG(DEBUG, TAG, "OUT - CALEClientCloseProfileProxy"); + return CA_STATUS_OK; + +error_exit: + CACheckJNIException(env); + return CA_STATUS_FAILED; +} + + +CAResult_t CALEClientDisconnect(JNIEnv *env, jobject bluetoothGatt) +{ + OIC_LOG(DEBUG, TAG, "GATT DISCONNECT"); + VERIFY_NON_NULL(env, TAG, "env is null"); + VERIFY_NON_NULL(bluetoothGatt, TAG, "bluetoothGatt is null"); + + // get BluetoothGatt method + OIC_LOG(DEBUG, TAG, "get gatt disconnect method"); + jmethodID jni_mid_disconnectGatt = CAGetJNIMethodID(env, CLASSPATH_BT_GATT, + "disconnect", "()V"); + if (!jni_mid_disconnectGatt) + { + OIC_LOG(ERROR, TAG, "jni_mid_disconnectGatt is null"); + return CA_STATUS_FAILED; + } + + // call disconnect gatt method + OIC_LOG(INFO, TAG, "CALL API - disconnect"); + (*env)->CallVoidMethod(env, bluetoothGatt, jni_mid_disconnectGatt); + if (CACheckJNIException(env)) + { + OIC_LOG(ERROR, TAG, "disconnect has failed"); + return CA_STATUS_FAILED; + } + + OIC_LOG(DEBUG, TAG, "disconnecting Gatt..."); + + return CA_STATUS_OK; +} + +CAResult_t CALEClientDisconnectAll(JNIEnv *env) +{ + OIC_LOG(DEBUG, TAG, "CALEClientDisconnectAll"); + VERIFY_NON_NULL(env, TAG, "env is null"); + + if (!g_gattObjectList) + { + OIC_LOG(DEBUG, TAG, "already removed for g_gattObjectList"); + return CA_STATUS_OK; + } + + uint32_t length = u_arraylist_length(g_gattObjectList); + OIC_LOG_V(DEBUG, TAG, "list length : %d", length); + for (uint32_t index = 0; index < length; index++) + { + OIC_LOG(DEBUG, TAG, "start CALEClientDisconnectAll"); + jobject jarrayObj = (jobject) u_arraylist_get(g_gattObjectList, index); + if (!jarrayObj) + { + OIC_LOG(ERROR, TAG, "jarrayObj is null"); + continue; + } + CAResult_t res = CALEClientDisconnect(env, jarrayObj); + if (CA_STATUS_OK != res) + { + OIC_LOG(ERROR, TAG, "CALEClientDisconnect has failed"); + continue; + } + } + + return CA_STATUS_OK; +} + +CAResult_t CALEClientDisconnectforAddress(JNIEnv *env, jstring remote_address) +{ + OIC_LOG(DEBUG, TAG, "IN-CALEClientDisconnectforAddress"); + VERIFY_NON_NULL(env, TAG, "env is null"); + + if (!g_gattObjectList) + { + OIC_LOG(DEBUG, TAG, "already removed for g_gattObjectList"); + return CA_STATUS_OK; + } + + char* address = (char*)(*env)->GetStringUTFChars(env, remote_address, NULL); + if (!address) + { + OIC_LOG(ERROR, TAG, "address is null"); + CACheckJNIException(env); + return CA_STATUS_FAILED; + } + + 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) + { + OIC_LOG(ERROR, TAG, "jarrayObj is null"); + continue; + } + + jstring jni_setAddress = CALEClientGetAddressFromGattObj(env, jarrayObj); + if (!jni_setAddress) + { + OIC_LOG(ERROR, TAG, "jni_setAddress is null"); + (*env)->ReleaseStringUTFChars(env, remote_address, address); + return CA_STATUS_FAILED; + } + + const char* setAddress = (*env)->GetStringUTFChars(env, jni_setAddress, NULL); + 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 (!strcasecmp(address, setAddress)) + { + CAResult_t res = CALEClientDisconnect(env, jarrayObj); + if (CA_STATUS_OK != res) + { + OIC_LOG(ERROR, TAG, "CALEClientDisconnect has failed"); + (*env)->ReleaseStringUTFChars(env, jni_setAddress, setAddress); + (*env)->ReleaseStringUTFChars(env, remote_address, address); + return CA_STATUS_FAILED; + } + (*env)->ReleaseStringUTFChars(env, jni_setAddress, setAddress); + (*env)->ReleaseStringUTFChars(env, remote_address, address); + return CA_STATUS_OK; + } + (*env)->ReleaseStringUTFChars(env, jni_setAddress, setAddress); + } + (*env)->ReleaseStringUTFChars(env, remote_address, address); + + OIC_LOG(DEBUG, TAG, "OUT-CALEClientDisconnectforAddress"); + return CA_STATUS_OK; +} + +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(ERROR, TAG, "stopLeScan: jni_mid_stopLeScan is null"); - return CA_STATUS_FAILED; + OIC_LOG(INFO, TAG, "BT adapter is not enabled"); + return CA_ADAPTER_NOT_ENABLED; } - // gat bt adapter object - jobject jni_obj_BTAdapter = (*env)->CallStaticObjectMethod(env, jni_cid_BTAdapter, - jni_mid_getDefaultAdapter); - if (!jni_obj_BTAdapter) + // 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_obj_BTAdapter is null"); + OIC_LOG(ERROR, TAG, "jni_mid_requestMtu is null"); return CA_STATUS_FAILED; } - OIC_LOG(DEBUG, TAG, "CALL API - request to stop LE Scan"); - // call start le scan method - (*env)->CallVoidMethod(env, jni_obj_BTAdapter, jni_mid_stopLeScan, callback); - if ((*env)->ExceptionCheck(env)) + // 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, "stopLeScan has failed"); - (*env)->ExceptionDescribe(env); - (*env)->ExceptionClear(env); + OIC_LOG(ERROR, TAG, "requestMtu has failed"); + CACheckJNIException(env); return CA_STATUS_FAILED; } return CA_STATUS_OK; } -CAResult_t CALEClientConnect(JNIEnv *env, jobject bluetoothDevice, jboolean autoconnect, - jobject callback) +CAResult_t CALEClientDiscoverServices(JNIEnv *env, jobject bluetoothGatt) { - OIC_LOG(DEBUG, TAG, "GATT CONNECT"); VERIFY_NON_NULL(env, TAG, "env is null"); - VERIFY_NON_NULL(bluetoothDevice, TAG, "bluetoothDevice is null"); - VERIFY_NON_NULL(callback, TAG, "callback is null"); + VERIFY_NON_NULL(bluetoothGatt, TAG, "bluetoothGatt is null"); if (!CALEIsEnableBTAdapter(env)) { - OIC_LOG(ERROR, TAG, "BT adapter is not enabled"); + OIC_LOG(INFO, TAG, "BT adapter is not enabled"); return CA_ADAPTER_NOT_ENABLED; } - jstring jni_address = CALEGetAddressFromBTDevice(env, bluetoothDevice); - if (!jni_address) + // get BluetoothGatt.discoverServices method + OIC_LOG(DEBUG, TAG, "get BluetoothGatt.discoverServices method"); + jmethodID jni_mid_discoverServices = CAGetJNIMethodID(env, CLASSPATH_BT_GATT, + "discoverServices", "()Z"); + if (!jni_mid_discoverServices) { - OIC_LOG(ERROR, TAG, "bleConnect: CALEGetAddressFromBTDevice is null"); + OIC_LOG(ERROR, TAG, "jni_mid_discoverServices is null"); return CA_STATUS_FAILED; } - // get BluetoothDevice class - OIC_LOG(DEBUG, TAG, "get BluetoothDevice class"); - jclass jni_cid_BluetoothDevice = (*env)->FindClass(env, "android/bluetooth/BluetoothDevice"); - if (!jni_cid_BluetoothDevice) + // call disconnect gatt method + OIC_LOG(INFO, TAG, "CALL API - discoverServices"); + jboolean ret = (*env)->CallBooleanMethod(env, bluetoothGatt, jni_mid_discoverServices); + if (!ret) { - OIC_LOG(ERROR, TAG, "bleConnect: jni_cid_BluetoothDevice is null"); + OIC_LOG(ERROR, TAG, "discoverServices has not been started"); + CACheckJNIException(env); return CA_STATUS_FAILED; } - // get connectGatt method - OIC_LOG(DEBUG, TAG, "get connectGatt method"); - jmethodID jni_mid_connectGatt = (*env)->GetMethodID(env, jni_cid_BluetoothDevice, "connectGatt", - "(Landroid/content/Context;ZLandroid/" - "bluetooth/BluetoothGattCallback;)" - "Landroid/bluetooth/BluetoothGatt;"); - if (!jni_mid_connectGatt) + return CA_STATUS_OK; +} + +static void CALEWriteCharacteristicThread(void* object) +{ + VERIFY_NON_NULL_VOID(object, TAG, "object is null"); + + bool isAttached = false; + JNIEnv* env = NULL; + jint res = (*g_jvm)->GetEnv(g_jvm, (void**) &env, JNI_VERSION_1_6); + if (JNI_OK != res) { - OIC_LOG(ERROR, TAG, "bleConnect: jni_mid_connectGatt is null"); - return CA_STATUS_FAILED; + res = (*g_jvm)->AttachCurrentThread(g_jvm, &env, NULL); + + if (JNI_OK != res) + { + OIC_LOG(ERROR, TAG, "AttachCurrentThread has failed"); + return; + } + isAttached = true; } - OIC_LOG(DEBUG, TAG, "Call object method - connectGatt"); - jobject jni_obj_connectGatt = (*env)->CallObjectMethod(env, bluetoothDevice, - jni_mid_connectGatt, - NULL, - autoconnect, callback); - if (!jni_obj_connectGatt) + jobject gatt = (jobject)object; + CAResult_t ret = CALESetValueAndWriteCharacteristic(env, gatt); + if (CA_STATUS_OK != ret) { - OIC_LOG(ERROR, TAG, "CALL API - connectGatt was failed..it will be removed"); - CALEClientRemoveDeviceInScanDeviceList(env, jni_address); - CALEClientUpdateSendCnt(env); - return CA_STATUS_FAILED; + OIC_LOG(ERROR, TAG, "CALESetValueAndWriteCharacteristic has failed"); } - else + + if (isAttached) { - OIC_LOG(DEBUG, TAG, "le connecting..please wait.."); + (*g_jvm)->DetachCurrentThread(g_jvm); } - return CA_STATUS_OK; } -CAResult_t CALEClientDisconnect(JNIEnv *env, jobject bluetoothGatt) +CAResult_t CALESetValueAndWriteCharacteristic(JNIEnv* env, jobject gatt) { - OIC_LOG(DEBUG, TAG, "GATT DISCONNECT"); + OIC_LOG(DEBUG, TAG, "CALESetValueAndWriteCharacteristic"); + + VERIFY_NON_NULL(gatt, TAG, "gatt is null"); VERIFY_NON_NULL(env, TAG, "env is null"); - VERIFY_NON_NULL(bluetoothGatt, TAG, "bluetoothGatt is null"); - if (!CALEIsEnableBTAdapter(env)) + jstring jni_address = CALEClientGetAddressFromGattObj(env, gatt); + if (!jni_address) { - OIC_LOG(ERROR, TAG, "BT adapter is not enabled"); - return CA_ADAPTER_NOT_ENABLED; + CALEClientSendFinish(env, gatt); + return CA_STATUS_FAILED; } - // get BluetoothGatt class - jclass jni_cid_BluetoothGatt = (*env)->FindClass(env, CLASSPATH_BT_GATT); - if (!jni_cid_BluetoothGatt) + const char* address = (*env)->GetStringUTFChars(env, jni_address, NULL); + if (!address) { - OIC_LOG(ERROR, TAG, "jni_cid_BluetoothGatt is null"); + CACheckJNIException(env); + CALEClientSendFinish(env, gatt); return CA_STATUS_FAILED; } - OIC_LOG(DEBUG, TAG, "get gatt disconnect method"); - jmethodID jni_mid_disconnectGatt = (*env)->GetMethodID(env, jni_cid_BluetoothGatt, - "disconnect", "()V"); - if (!jni_mid_disconnectGatt) + oc_mutex_lock(g_threadSendStateMutex); + + if (CALEIsValidState(address, CA_LE_SEND_STATE, STATE_SENDING, + g_deviceStateList, + g_deviceStateListMutex)) { - OIC_LOG(ERROR, TAG, "jni_mid_disconnectGatt is null"); - return CA_STATUS_FAILED; + OIC_LOG(INFO, TAG, "current state is SENDING"); + (*env)->ReleaseStringUTFChars(env, jni_address, address); + oc_mutex_unlock(g_threadSendStateMutex); + return CA_STATUS_OK; } - // call disconnect gatt method - (*env)->CallVoidMethod(env, bluetoothGatt, jni_mid_disconnectGatt); - if ((*env)->ExceptionCheck(env)) + if (CA_STATUS_OK != CALEUpdateDeviceState(address, CA_LE_SEND_STATE, + STATE_SENDING, + g_deviceStateList, + g_deviceStateListMutex)) { - OIC_LOG(ERROR, TAG, "disconnect has failed"); - (*env)->ExceptionDescribe(env); - (*env)->ExceptionClear(env); + OIC_LOG(ERROR, TAG, "CALEUpdateDeviceState has failed"); + (*env)->ReleaseStringUTFChars(env, jni_address, address); + CALEClientSendFinish(env, gatt); + oc_mutex_unlock(g_threadSendStateMutex); return CA_STATUS_FAILED; } - OIC_LOG(DEBUG, TAG, "disconnecting Gatt..."); - - return CA_STATUS_OK; -} + (*env)->ReleaseStringUTFChars(env, jni_address, address); -CAResult_t CALEClientDisconnectAll(JNIEnv *env) -{ - OIC_LOG(DEBUG, TAG, "CALEClientDisconnectAll"); - VERIFY_NON_NULL(env, TAG, "env is null"); + oc_mutex_unlock(g_threadSendStateMutex); - if (!g_gattObjectList) + 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, "g_gattObjectList is null"); + OIC_LOG(ERROR, TAG, "send Buffer is empty"); + oc_mutex_unlock(g_setValueMutex); return CA_STATUS_FAILED; } + oc_mutex_unlock(g_setValueMutex); - uint32_t length = u_arraylist_length(g_gattObjectList); - for (uint32_t index = 0; index < length; index++) + // send data + jobject jni_obj_character = CALEClientCreateGattCharacteristic(env, gatt, sendData); + if (!jni_obj_character) { - jobject jarrayObj = (jobject) u_arraylist_get(g_gattObjectList, index); - if (!jarrayObj) - { - OIC_LOG(ERROR, TAG, "jarrayObj is null"); - continue; - } - CAResult_t res = CALEClientDisconnect(env, jarrayObj); - if (CA_STATUS_OK != res) + if (sendData) { - OIC_LOG(ERROR, TAG, "CALEClientDisconnect has failed"); - continue; + (*env)->DeleteLocalRef(env, sendData); } + CALEClientSendFinish(env, gatt); + return CA_STATUS_FAILED; } - OICFree(g_gattObjectList); - g_gattObjectList = NULL; - - return CA_STATUS_OK; -} - -CAResult_t CALEClientDiscoverServices(JNIEnv *env, jobject bluetoothGatt) -{ - VERIFY_NON_NULL(env, TAG, "env is null"); - VERIFY_NON_NULL(bluetoothGatt, TAG, "bluetoothGatt is null"); - - if (!CALEIsEnableBTAdapter(env)) + if (sendData) { - OIC_LOG(ERROR, TAG, "BT adapter is not enabled"); - return CA_ADAPTER_NOT_ENABLED; + (*env)->DeleteLocalRef(env, sendData); } - // get BluetoothGatt class - OIC_LOG(DEBUG, TAG, "get BluetoothGatt class"); - jclass jni_cid_BluetoothGatt = (*env)->FindClass(env, CLASSPATH_BT_GATT); - if (!jni_cid_BluetoothGatt) + CAResult_t ret = CALEClientWriteCharacteristicImpl(env, gatt, jni_obj_character); + if (CA_STATUS_OK != ret) { - OIC_LOG(ERROR, TAG, "jni_cid_BluetoothGatt is null"); + CALEClientSendFinish(env, gatt); return CA_STATUS_FAILED; } - OIC_LOG(DEBUG, TAG, "discovery gatt services method"); - jmethodID jni_mid_discoverServices = (*env)->GetMethodID(env, jni_cid_BluetoothGatt, - "discoverServices", "()Z"); - if (!jni_mid_discoverServices) - { - OIC_LOG(ERROR, TAG, "jni_mid_discoverServices is null"); - return CA_STATUS_FAILED; - } - // call disconnect gatt method - OIC_LOG(DEBUG, TAG, "CALL API - request discovery gatt services"); - jboolean ret = (*env)->CallBooleanMethod(env, bluetoothGatt, jni_mid_discoverServices); - if (!ret) + // wait for callback for write Characteristic with success to sent data + OIC_LOG_V(DEBUG, TAG, "callback flag is %d", g_isSignalSetFlag); + oc_mutex_lock(g_threadWriteCharacteristicMutex); + if (!g_isSignalSetFlag) { - OIC_LOG(ERROR, TAG, "discoverServices has not been started"); - return CA_STATUS_FAILED; + OIC_LOG(DEBUG, TAG, "wait for callback to notify writeCharacteristic is success"); + 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; + oc_mutex_unlock(g_threadWriteCharacteristicMutex); + return CA_STATUS_FAILED; + } } + // reset flag set by writeCharacteristic Callback + g_isSignalSetFlag = false; + oc_mutex_unlock(g_threadWriteCharacteristicMutex); + + CALEClientUpdateSendCnt(env); + OIC_LOG(INFO, TAG, "writeCharacteristic success!!"); return CA_STATUS_OK; } CAResult_t CALEClientWriteCharacteristic(JNIEnv *env, jobject gatt) { + OIC_LOG(DEBUG, TAG, "IN - CALEClientWriteCharacteristic"); VERIFY_NON_NULL(env, TAG, "env is null"); VERIFY_NON_NULL(gatt, TAG, "gatt is null"); - // send data - jobject jni_obj_character = CALEClientCreateGattCharacteristic(env, gatt, g_sendBuffer); - if (!jni_obj_character) + jobject gattParam = (*env)->NewGlobalRef(env, gatt); + CACheckJNIException(env); + if (CA_STATUS_OK != ca_thread_pool_add_task(g_threadPoolHandle, CALEWriteCharacteristicThread, + (void*)gattParam, NULL)) { - CALEClientSendFinish(env, gatt); + OIC_LOG(ERROR, TAG, "Failed to create read thread!"); return CA_STATUS_FAILED; } - CAResult_t ret = CALEClientWriteCharacteristicImpl(env, gatt, jni_obj_character); - if (CA_STATUS_OK != ret) - { - CALEClientSendFinish(env, gatt); - return ret; - } - + OIC_LOG(DEBUG, TAG, "OUT - CALEClientWriteCharacteristic"); return CA_STATUS_OK; } CAResult_t CALEClientWriteCharacteristicImpl(JNIEnv *env, jobject bluetoothGatt, - jobject gattCharacteristic) + jobject gattCharacteristic) { OIC_LOG(DEBUG, TAG, "WRITE GATT CHARACTERISTIC"); VERIFY_NON_NULL(env, TAG, "env is null"); @@ -1475,24 +3085,16 @@ CAResult_t CALEClientWriteCharacteristicImpl(JNIEnv *env, jobject bluetoothGatt, if (!CALEIsEnableBTAdapter(env)) { - OIC_LOG(ERROR, TAG, "BT adapter is not enabled"); - return CA_STATUS_FAILED; - } - - // get BluetoothGatt class - OIC_LOG(DEBUG, TAG, "get BluetoothGatt class"); - jclass jni_cid_BluetoothGatt = (*env)->FindClass(env, CLASSPATH_BT_GATT); - if (!jni_cid_BluetoothGatt) - { - OIC_LOG(ERROR, TAG, "jni_cid_BluetoothGatt is null"); + OIC_LOG(INFO, TAG, "BT adapter is not enabled"); return CA_STATUS_FAILED; } + // get BluetoothGatt.write characteristic method OIC_LOG(DEBUG, TAG, "write characteristic method"); - jmethodID jni_mid_writeCharacteristic = (*env)->GetMethodID(env, jni_cid_BluetoothGatt, - "writeCharacteristic", - "(Landroid/bluetooth/" - "BluetoothGattCharacteristic;)Z"); + jmethodID jni_mid_writeCharacteristic = CAGetJNIMethodID(env, CLASSPATH_BT_GATT, + "writeCharacteristic", + "(Landroid/bluetooth/" + "BluetoothGattCharacteristic;)Z"); if (!jni_mid_writeCharacteristic) { OIC_LOG(ERROR, TAG, "jni_mid_writeCharacteristic is null"); @@ -1500,16 +3102,17 @@ CAResult_t CALEClientWriteCharacteristicImpl(JNIEnv *env, jobject bluetoothGatt, } // call disconnect gatt method - OIC_LOG(DEBUG, TAG, "CALL API - request to write gatt characteristic"); + OIC_LOG(INFO, TAG, "CALL API - writeCharacteristic"); jboolean ret = (jboolean)(*env)->CallBooleanMethod(env, bluetoothGatt, jni_mid_writeCharacteristic, gattCharacteristic); if (ret) { - OIC_LOG(DEBUG, TAG, "writeCharacteristic success"); + OIC_LOG(DEBUG, TAG, "writeCharacteristic is called successfully"); } else { + CACheckJNIException(env); OIC_LOG(ERROR, TAG, "writeCharacteristic has failed"); return CA_STATUS_FAILED; } @@ -1524,14 +3127,7 @@ CAResult_t CALEClientReadCharacteristic(JNIEnv *env, jobject bluetoothGatt) if (!CALEIsEnableBTAdapter(env)) { - OIC_LOG(ERROR, TAG, "BT adapter is not enabled"); - return CA_STATUS_FAILED; - } - - jclass jni_cid_BluetoothGatt = (*env)->FindClass(env, CLASSPATH_BT_GATT); - if (!jni_cid_BluetoothGatt) - { - OIC_LOG(ERROR, TAG, "jni_cid_BluetoothGatt is null"); + OIC_LOG(INFO, TAG, "BT adapter is not enabled"); return CA_STATUS_FAILED; } @@ -1539,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; } @@ -1550,10 +3147,10 @@ CAResult_t CALEClientReadCharacteristic(JNIEnv *env, jobject bluetoothGatt) } OIC_LOG(DEBUG, TAG, "read characteristic method"); - jmethodID jni_mid_readCharacteristic = (*env)->GetMethodID(env, jni_cid_BluetoothGatt, - "readCharacteristic", - "(Landroid/bluetooth/" - "BluetoothGattCharacteristic;)Z"); + jmethodID jni_mid_readCharacteristic = CAGetJNIMethodID(env, CLASSPATH_BT_GATT, + "readCharacteristic", + "(Landroid/bluetooth/" + "BluetoothGattCharacteristic;)Z"); if (!jni_mid_readCharacteristic) { OIC_LOG(ERROR, TAG, "jni_mid_readCharacteristic is null"); @@ -1561,7 +3158,7 @@ CAResult_t CALEClientReadCharacteristic(JNIEnv *env, jobject bluetoothGatt) } // call disconnect gatt method - OIC_LOG(DEBUG, TAG, "CALL API - request to read gatt characteristic"); + OIC_LOG(INFO, TAG, "CALL API - readCharacteristic"); jboolean ret = (*env)->CallBooleanMethod(env, bluetoothGatt, jni_mid_readCharacteristic, jni_obj_GattCharacteristic); if (ret) @@ -1571,6 +3168,7 @@ CAResult_t CALEClientReadCharacteristic(JNIEnv *env, jobject bluetoothGatt) else { OIC_LOG(ERROR, TAG, "readCharacteristic has failed"); + CACheckJNIException(env); return CA_STATUS_FAILED; } @@ -1586,39 +3184,33 @@ CAResult_t CALEClientSetCharacteristicNotification(JNIEnv *env, jobject bluetoot if (!CALEIsEnableBTAdapter(env)) { - OIC_LOG(ERROR, TAG, "BT adapter is not enabled"); + OIC_LOG(INFO, TAG, "BT adapter is not enabled"); return CA_ADAPTER_NOT_ENABLED; } - // get BluetoothGatt class + // get BluetoothGatt.setCharacteristicNotification method OIC_LOG(DEBUG, TAG, "CALEClientSetCharacteristicNotification"); - jclass jni_cid_BluetoothGatt = (*env)->FindClass(env, CLASSPATH_BT_GATT); - if (!jni_cid_BluetoothGatt) - { - OIC_LOG(ERROR, TAG, "jni_cid_BluetoothGatt is null"); - return CA_STATUS_FAILED; - } - - // set Characteristic Notification - jmethodID jni_mid_setNotification = (*env)->GetMethodID(env, jni_cid_BluetoothGatt, - "setCharacteristicNotification", - "(Landroid/bluetooth/" - "BluetoothGattCharacteristic;Z)Z"); + jmethodID jni_mid_setNotification = CAGetJNIMethodID(env, CLASSPATH_BT_GATT, + "setCharacteristicNotification", + "(Landroid/bluetooth/" + "BluetoothGattCharacteristic;Z)Z"); if (!jni_mid_setNotification) { OIC_LOG(ERROR, TAG, "jni_mid_getService is null"); return CA_STATUS_FAILED; } + OIC_LOG(INFO, TAG, "CALL API - setCharacteristicNotification"); jboolean ret = (*env)->CallBooleanMethod(env, bluetoothGatt, jni_mid_setNotification, characteristic, JNI_TRUE); if (JNI_TRUE == ret) { - OIC_LOG(DEBUG, TAG, "CALL API - setCharacteristicNotification success"); + OIC_LOG(DEBUG, TAG, "setCharacteristicNotification success"); } else { - OIC_LOG(ERROR, TAG, "CALL API - setCharacteristicNotification has failed"); + OIC_LOG(ERROR, TAG, "setCharacteristicNotification has failed"); + CACheckJNIException(env); return CA_STATUS_FAILED; } @@ -1633,22 +3225,16 @@ jobject CALEClientGetGattService(JNIEnv *env, jobject bluetoothGatt, jstring cha if (!CALEIsEnableBTAdapter(env)) { - OIC_LOG(ERROR, TAG, "BT adapter is not enabled"); + OIC_LOG(INFO, TAG, "BT adapter is not enabled"); return NULL; } - // get BluetoothGatt class - OIC_LOG(DEBUG, TAG, "CALEClientGetGattService"); - jclass jni_cid_BluetoothGatt = (*env)->FindClass(env, CLASSPATH_BT_GATT); - if (!jni_cid_BluetoothGatt) - { - OIC_LOG(ERROR, TAG, "jni_cid_BluetoothGatt is null"); - return NULL; - } - - jmethodID jni_mid_getService = (*env)->GetMethodID( - env, jni_cid_BluetoothGatt, "getService", - "(Ljava/util/UUID;)Landroid/bluetooth/BluetoothGattService;"); + // get BluetoothGatt.getService method + OIC_LOG(DEBUG, TAG, "BluetoothGatt.getService"); + jmethodID jni_mid_getService = CAGetJNIMethodID(env, CLASSPATH_BT_GATT, + "getService", + "(Ljava/util/UUID;)Landroid/bluetooth/" + "BluetoothGattService;"); if (!jni_mid_getService) { OIC_LOG(ERROR, TAG, "jni_mid_getService is null"); @@ -1669,24 +3255,17 @@ 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; } - // get bluetooth gatt service class - jclass jni_cid_BluetoothGattService = (*env)->FindClass( - env, "android/bluetooth/BluetoothGattService"); - if (!jni_cid_BluetoothGattService) - { - OIC_LOG(ERROR, TAG, "jni_cid_BluetoothGattService is null"); - return NULL; - } - - OIC_LOG(DEBUG, TAG, "get gatt getCharacteristic method"); - jmethodID jni_mid_getCharacteristic = (*env)->GetMethodID(env, jni_cid_BluetoothGattService, - "getCharacteristic", - "(Ljava/util/UUID;)" - "Landroid/bluetooth/" - "BluetoothGattCharacteristic;"); + // get bluetooth gatt service method + jmethodID jni_mid_getCharacteristic = CAGetJNIMethodID(env, "android/bluetooth/" + "BluetoothGattService", + "getCharacteristic", + "(Ljava/util/UUID;)" + "Landroid/bluetooth/" + "BluetoothGattCharacteristic;"); if (!jni_mid_getCharacteristic) { OIC_LOG(ERROR, TAG, "jni_mid_getCharacteristic is null"); @@ -1697,6 +3276,7 @@ jobject CALEClientGetGattService(JNIEnv *env, jobject bluetoothGatt, jstring cha if (!uuid) { OIC_LOG(ERROR, TAG, "uuid is null"); + CACheckJNIException(env); return NULL; } @@ -1708,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; @@ -1726,7 +3312,7 @@ jobject CALEClientCreateGattCharacteristic(JNIEnv *env, jobject bluetoothGatt, j if (!CALEIsEnableBTAdapter(env)) { - OIC_LOG(ERROR, TAG, "BT adapter is not enabled"); + OIC_LOG(INFO, TAG, "BT adapter is not enabled"); return NULL; } @@ -1734,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); @@ -1749,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"); @@ -1758,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) @@ -1770,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) @@ -1805,21 +3409,13 @@ jbyteArray CALEClientGetValueFromCharacteristic(JNIEnv *env, jobject characteris if (!CALEIsEnableBTAdapter(env)) { - OIC_LOG(ERROR, TAG, "BT adapter is not enabled"); + OIC_LOG(INFO, TAG, "BT adapter is not enabled"); return NULL; } - jclass jni_cid_BTGattCharacteristic = (*env)->FindClass(env, "android/bluetooth/" - "BluetoothGattCharacteristic"); - if (!jni_cid_BTGattCharacteristic) - { - OIC_LOG(ERROR, TAG, "jni_cid_BTGattCharacteristic is null"); - return NULL; - } - - OIC_LOG(DEBUG, TAG, "get value in Characteristic"); - jmethodID jni_mid_getValue = (*env)->GetMethodID(env, jni_cid_BTGattCharacteristic, "getValue", - "()[B"); + jmethodID jni_mid_getValue = CAGetJNIMethodID(env, "android/bluetooth/" + "BluetoothGattCharacteristic", + "getValue", "()[B"); if (!jni_mid_getValue) { OIC_LOG(ERROR, TAG, "jni_mid_getValue is null"); @@ -1828,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; } @@ -1840,11 +3437,10 @@ CAResult_t CALEClientCreateUUIDList() } bool isAttached = false; - JNIEnv* env; + JNIEnv* env = NULL; jint res = (*g_jvm)->GetEnv(g_jvm, (void**) &env, JNI_VERSION_1_6); if (JNI_OK != res) { - OIC_LOG(INFO, TAG, "Could not get JNIEnv pointer"); res = (*g_jvm)->AttachCurrentThread(g_jvm, &env, NULL); if (JNI_OK != res) @@ -1860,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; } @@ -1868,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; } @@ -1881,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) { @@ -1908,24 +3507,16 @@ CAResult_t CALEClientSetUUIDToDescriptor(JNIEnv *env, jobject bluetoothGatt, if (!CALEIsEnableBTAdapter(env)) { - OIC_LOG(ERROR, TAG, "BT adapter is not enabled"); + OIC_LOG(INFO, TAG, "BT adapter is not enabled"); return CA_ADAPTER_NOT_ENABLED; } OIC_LOG(DEBUG, TAG, "CALEClientSetUUIDToDescriptor"); - jclass jni_cid_BTGattCharacteristic = (*env)->FindClass(env, "android/bluetooth/" - "BluetoothGattCharacteristic"); - if (!jni_cid_BTGattCharacteristic) - { - OIC_LOG(ERROR, TAG, "jni_cid_BTGattCharacteristic is null"); - return CA_STATUS_FAILED; - } - - OIC_LOG(DEBUG, TAG, "set value in Characteristic"); - jmethodID jni_mid_getDescriptor = (*env)->GetMethodID(env, jni_cid_BTGattCharacteristic, - "getDescriptor", - "(Ljava/util/UUID;)Landroid/bluetooth/" - "BluetoothGattDescriptor;"); + jmethodID jni_mid_getDescriptor = CAGetJNIMethodID(env, "android/bluetooth/" + "BluetoothGattCharacteristic", + "getDescriptor", + "(Ljava/util/UUID;)Landroid/bluetooth/" + "BluetoothGattDescriptor;"); if (!jni_mid_getDescriptor) { OIC_LOG(ERROR, TAG, "jni_mid_getDescriptor is null"); @@ -1936,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"); @@ -1944,8 +3534,8 @@ CAResult_t CALEClientSetUUIDToDescriptor(JNIEnv *env, jobject bluetoothGatt, jni_mid_getDescriptor, jni_obj_cc_uuid); if (!jni_obj_descriptor) { - OIC_LOG(ERROR, TAG, "jni_obj_descriptor is null"); - return CA_STATUS_FAILED; + OIC_LOG(INFO, TAG, "jni_obj_descriptor is null"); + goto error_exit; } OIC_LOG(DEBUG, TAG, "set value in descriptor"); @@ -1954,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, @@ -1984,27 +3588,20 @@ CAResult_t CALEClientSetUUIDToDescriptor(JNIEnv *env, jobject bluetoothGatt, else { OIC_LOG(ERROR, TAG, "setValue has failed"); - return CA_STATUS_FAILED; - } - - jclass jni_cid_gatt = (*env)->FindClass(env, "android/bluetooth/BluetoothGatt"); - if (!jni_cid_gatt) - { - OIC_LOG(ERROR, TAG, "jni_cid_gatt is null"); - return CA_STATUS_FAILED; + goto error_exit; } - OIC_LOG(DEBUG, TAG, "write Descriptor in gatt object"); - jmethodID jni_mid_writeDescriptor = (*env)->GetMethodID(env, jni_cid_gatt, "writeDescriptor", - "(Landroid/bluetooth/" - "BluetoothGattDescriptor;)Z"); + jmethodID jni_mid_writeDescriptor = CAGetJNIMethodID(env, "android/bluetooth/BluetoothGatt", + "writeDescriptor", + "(Landroid/bluetooth/" + "BluetoothGattDescriptor;)Z"); if (!jni_mid_writeDescriptor) { OIC_LOG(ERROR, TAG, "jni_mid_writeDescriptor is null"); return CA_STATUS_FAILED; } - OIC_LOG(DEBUG, TAG, "request to write descriptor"); + OIC_LOG(INFO, TAG, "CALL API - writeDescriptor"); jboolean jni_ret = (*env)->CallBooleanMethod(env, bluetoothGatt, jni_mid_writeDescriptor, jni_obj_descriptor); if (jni_ret) @@ -2014,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) @@ -2025,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) { @@ -2033,21 +3634,20 @@ 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) { - OIC_LOG(DEBUG, TAG, "IN - CALEClientAddScanDeviceToList"); 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"); - ca_mutex_unlock(g_deviceListMutex); + oc_mutex_unlock(g_deviceListMutex); return CA_STATUS_FAILED; } @@ -2055,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; } @@ -2063,28 +3663,31 @@ CAResult_t CALEClientAddScanDeviceToList(JNIEnv *env, jobject device) if (!remoteAddress) { OIC_LOG(ERROR, TAG, "remoteAddress is null"); - ca_mutex_unlock(g_deviceListMutex); + CACheckJNIException(env); + (*env)->DeleteLocalRef(env, jni_remoteAddress); + 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); - OIC_LOG(DEBUG, TAG, "Set Object to Array as Element"); + 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); - OIC_LOG(DEBUG, TAG, "OUT - CALEClientAddScanDeviceToList"); return CA_STATUS_OK; } bool CALEClientIsDeviceInScanDeviceList(JNIEnv *env, const char* remoteAddress) { - OIC_LOG(DEBUG, TAG, "IN - CALEClientIsDeviceInScanDeviceList"); - VERIFY_NON_NULL_RET(env, TAG, "env is null", NULL); + VERIFY_NON_NULL_RET(env, TAG, "env is null", true); VERIFY_NON_NULL_RET(remoteAddress, TAG, "remoteAddress is null", true); if (!g_deviceList) @@ -2114,22 +3717,21 @@ 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)) { - OIC_LOG(DEBUG, TAG, "the device is already set"); (*env)->ReleaseStringUTFChars(env, jni_setAddress, setAddress); + (*env)->DeleteLocalRef(env, jni_setAddress); return true; } (*env)->ReleaseStringUTFChars(env, jni_setAddress, setAddress); + (*env)->DeleteLocalRef(env, jni_setAddress); } - - OIC_LOG(DEBUG, TAG, "OUT - CALEClientIsDeviceInScanDeviceList"); - OIC_LOG(DEBUG, TAG, "there are no the device in list. we can add"); - return false; } @@ -2138,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; } @@ -2157,12 +3759,13 @@ CAResult_t CALEClientRemoveAllScanDevices(JNIEnv *env) continue; } (*env)->DeleteGlobalRef(env, jarrayObj); + jarrayObj = NULL; } OICFree(g_deviceList); g_deviceList = NULL; - ca_mutex_unlock(g_deviceListMutex); + oc_mutex_unlock(g_deviceListMutex); return CA_STATUS_OK; } @@ -2172,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; } @@ -2188,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; } @@ -2196,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; } @@ -2204,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; } @@ -2212,27 +3816,34 @@ 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); + jarrayObj = NULL; (*env)->ReleaseStringUTFChars(env, jni_setAddress, setAddress); (*env)->ReleaseStringUTFChars(env, address, remoteAddress); - CALEClientReorderingList(index, g_deviceList); - ca_mutex_unlock(g_deviceListMutex); + if (NULL == u_arraylist_remove(g_deviceList, index)) + { + OIC_LOG(ERROR, TAG, "List removal failed."); + oc_mutex_unlock(g_deviceListMutex); + return CA_STATUS_FAILED; + } + 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; @@ -2248,13 +3859,20 @@ 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"); + oc_mutex_unlock(g_gattObjectMutex); + return CA_STATUS_FAILED; + } jstring jni_remoteAddress = CALEClientGetAddressFromGattObj(env, 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; } @@ -2262,32 +3880,34 @@ 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; } + OIC_LOG_V(DEBUG, TAG, "remote address : %s", remoteAddress); if (!CALEClientIsGattObjInList(env, remoteAddress)) { jobject newGatt = (*env)->NewGlobalRef(env, gatt); u_arraylist_add(g_gattObjectList, newGatt); - OIC_LOG(DEBUG, TAG, "Set GATT Object to Array as Element"); + OIC_LOG(INFO, TAG, "added a newGatt object to gattObjectList"); } (*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) { @@ -2306,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"); @@ -2332,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++) { @@ -2340,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; } @@ -2348,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; } @@ -2356,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; } @@ -2380,12 +4003,12 @@ 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(ERROR, TAG, "g_gattObjectList is null"); - ca_mutex_unlock(g_gattObjectMutex); - return CA_STATUS_FAILED; + OIC_LOG(DEBUG, TAG, "already removed for g_gattObjectList"); + oc_mutex_unlock(g_gattObjectMutex); + return CA_STATUS_OK; } uint32_t length = u_arraylist_length(g_gattObjectList); @@ -2398,11 +4021,13 @@ CAResult_t CALEClientRemoveAllGattObjs(JNIEnv *env) continue; } (*env)->DeleteGlobalRef(env, jarrayObj); + jarrayObj = NULL; } OICFree(g_gattObjectList); g_gattObjectList = NULL; - ca_mutex_unlock(g_gattObjectMutex); + OIC_LOG(INFO, TAG, "g_gattObjectList is removed"); + oc_mutex_unlock(g_gattObjectMutex); return CA_STATUS_OK; } @@ -2412,12 +4037,12 @@ 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(ERROR, TAG, "g_gattObjectList is null"); - ca_mutex_unlock(g_gattObjectMutex); - return CA_STATUS_FAILED; + OIC_LOG(DEBUG, TAG, "already removed for g_gattObjectList"); + oc_mutex_unlock(g_gattObjectMutex); + return CA_STATUS_OK; } uint32_t length = u_arraylist_length(g_gattObjectList); @@ -2427,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; } @@ -2435,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; } @@ -2443,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; } @@ -2452,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; } @@ -2460,25 +4086,34 @@ 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); + jarrayObj = NULL; (*env)->ReleaseStringUTFChars(env, jni_setAddress, setAddress); (*env)->ReleaseStringUTFChars(env, jni_remoteAddress, remoteAddress); - ca_mutex_unlock(g_gattObjectMutex); - return CALEClientReorderingList(index, g_gattObjectList); + + if (NULL == u_arraylist_remove(g_gattObjectList, index)) + { + OIC_LOG(ERROR, TAG, "List removal failed."); + oc_mutex_unlock(g_gattObjectMutex); + return CA_STATUS_FAILED; + } + 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; } @@ -2489,12 +4124,12 @@ 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(ERROR, TAG, "g_gattObjectList is null"); - ca_mutex_unlock(g_gattObjectMutex); - return CA_STATUS_FAILED; + OIC_LOG(DEBUG, TAG, "already removed for g_gattObjectList"); + oc_mutex_unlock(g_gattObjectMutex); + return CA_STATUS_OK; } uint32_t length = u_arraylist_length(g_gattObjectList); @@ -2504,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; } @@ -2512,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; } @@ -2520,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; } @@ -2529,324 +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); + 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); - + jarrayObj = NULL; (*env)->ReleaseStringUTFChars(env, jni_setAddress, setAddress); (*env)->ReleaseStringUTFChars(env, addr, remoteAddress); - ca_mutex_unlock(g_gattObjectMutex); - return CALEClientReorderingList(index, g_gattObjectList); + if (NULL == u_arraylist_remove(g_gattObjectList, index)) + { + OIC_LOG(ERROR, TAG, "List removal failed."); + oc_mutex_unlock(g_gattObjectMutex); + return CA_STATUS_FAILED; + } + oc_mutex_unlock(g_gattObjectMutex); + return CA_STATUS_OK; } (*env)->ReleaseStringUTFChars(env, jni_setAddress, setAddress); (*env)->ReleaseStringUTFChars(env, addr, remoteAddress); } - ca_mutex_unlock(g_gattObjectMutex); + oc_mutex_unlock(g_gattObjectMutex); OIC_LOG(DEBUG, TAG, "there are no target object"); return CA_STATUS_FAILED; } -/** - * BT State List - */ - -CAResult_t CALEClientUpdateDeviceState(const char* address, uint32_t connectedState, - uint16_t notificationState, uint16_t sendState) +jstring CALEClientGetLEAddressFromBTDevice(JNIEnv *env, jobject bluetoothDevice) { - VERIFY_NON_NULL(address, TAG, "address is null"); + VERIFY_NON_NULL_RET(env, TAG, "env", NULL); + VERIFY_NON_NULL_RET(bluetoothDevice, TAG, "bluetoothDevice", NULL); - CALEState_t *newstate = (CALEState_t*) OICMalloc(sizeof(CALEState_t)); - if (!newstate) + // get Bluetooth Address + jstring jni_btTargetAddress = CALEGetAddressFromBTDevice(env, bluetoothDevice); + if (!jni_btTargetAddress) { - OIC_LOG(ERROR, TAG, "out of memory"); - return CA_MEMORY_ALLOC_FAILED; + OIC_LOG(ERROR, TAG, "CALEGetAddressFromBTDevice has failed"); + return NULL; } - if (strlen(address) > CA_MACADDR_SIZE) + const char* targetAddress = (*env)->GetStringUTFChars(env, jni_btTargetAddress, NULL); + if (!targetAddress) { - OIC_LOG(ERROR, TAG, "address is not proper"); - OICFree(newstate); - return CA_STATUS_FAILED; + OIC_LOG(ERROR, TAG, "targetAddress is not available"); + CACheckJNIException(env); + return NULL; } - OICStrcpy(newstate->address, sizeof(newstate->address), address); - newstate->connectedState = connectedState; - newstate->notificationState = notificationState; - newstate->sendState = sendState; - return CALEClientAddDeviceStateToList(newstate); -} - -CAResult_t CALEClientAddDeviceStateToList(CALEState_t* state) -{ - VERIFY_NON_NULL(state, TAG, "state is null"); - - ca_mutex_lock(g_deviceStateListMutex); - - if (!g_deviceStateList) + // 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, "gdevice_list is null"); - ca_mutex_unlock(g_deviceStateListMutex); - return CA_STATUS_FAILED; + OIC_LOG(ERROR, TAG, "jni_mid_getDevice is null"); + (*env)->ReleaseStringUTFChars(env, jni_btTargetAddress, targetAddress); + return NULL; } - if (CALEClientIsDeviceInList(state->address)) + 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* curState = CALEClientGetStateInfo(state->address); - if(!curState) + jobject jarrayObj = (jobject) u_arraylist_get(g_gattObjectList, index); + if (!jarrayObj) { - OIC_LOG(ERROR, TAG, "curState is null"); - ca_mutex_unlock(g_deviceStateListMutex); - return CA_STATUS_FAILED; + oc_mutex_unlock(g_gattObjectMutex); + OIC_LOG(ERROR, TAG, "jarrayObj is null"); + (*env)->ReleaseStringUTFChars(env, jni_btTargetAddress, targetAddress); + return NULL; } - if (STATE_CHARACTER_NO_CHANGE == state->notificationState) + jobject jni_obj_device = (*env)->CallObjectMethod(env, jarrayObj, jni_mid_getDevice); + if (!jni_obj_device) { - state->notificationState = curState->notificationState; + CACheckJNIException(env); + oc_mutex_unlock(g_gattObjectMutex); + OIC_LOG(ERROR, TAG, "jni_obj_device is null"); + (*env)->ReleaseStringUTFChars(env, jni_btTargetAddress, targetAddress); + return NULL; } - // delete previous state for update new state - CAResult_t res = CALEClientRemoveDeviceState(state->address); - if (CA_STATUS_OK != res) + jstring jni_btAddress = CALEGetAddressFromBTDevice(env, jni_obj_device); + if (!jni_btAddress) { - OIC_LOG(ERROR, TAG, "CALEClientRemoveDeviceState has failed"); - ca_mutex_unlock(g_deviceStateListMutex); - return res; + 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; } - } - u_arraylist_add(g_deviceStateList, state); // update new state - OIC_LOG_V(DEBUG, TAG, "Set State Info to List : %d, %d", - state->connectedState, state->notificationState); - - 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) + const char* btAddress = (*env)->GetStringUTFChars(env, jni_btAddress, NULL); + if (!btAddress) { - OIC_LOG(ERROR, TAG, "CALEState_t object is null"); - return false; + 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(remoteAddress, state->address)) - { - OIC_LOG(DEBUG, TAG, "the device is already set"); - return true; - } - else + OIC_LOG_V(DEBUG, TAG, "btAddress : %s (idx: %d)", btAddress, index); + if (!strcasecmp(targetAddress, btAddress)) { - continue; + 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(DEBUG, TAG, "there are no the device in list."); - return false; + (*env)->ReleaseStringUTFChars(env, jni_btTargetAddress, targetAddress); + OIC_LOG_V(DEBUG, TAG, "[%s] doesn't exist in gattObjectList", targetAddress); + return NULL; } -CAResult_t CALEClientRemoveAllDeviceState() +/** + * BT State List + */ +CAResult_t CALEClientUpdateDeviceStateWithBtDevice(JNIEnv *env, + jobject device, + uint16_t state_type, + uint16_t target_state) { - OIC_LOG(DEBUG, TAG, "CALENativeRemoveAllDevices"); + 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); + OIC_LOG(ERROR, TAG, "CALEGetAddressFromBTDevice has failed"); return CA_STATUS_FAILED; } - uint32_t length = u_arraylist_length(g_deviceStateList); - for (uint32_t index = 0; index < length; index++) + const char* address = (*env)->GetStringUTFChars(env, jni_Address, NULL); + if (!address) { - CALEState_t* state = (CALEState_t*) u_arraylist_get(g_deviceStateList, index); - if (!state) - { - OIC_LOG(ERROR, TAG, "jarrayObj is null"); - continue; - } - OICFree(state); + OIC_LOG(ERROR, TAG, "targetAddress is not available"); + CACheckJNIException(env); + (*env)->DeleteLocalRef(env, jni_Address); + return CA_STATUS_FAILED; } - OICFree(g_deviceStateList); - g_deviceStateList = NULL; - 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) + if (CALEIsValidState(address, state_type, target_state, + g_deviceStateList, + g_deviceStateListMutex)) { - OIC_LOG(ERROR, TAG, "g_deviceStateList is null"); - return CA_STATUS_FAILED; + (*env)->DeleteLocalRef(env, jni_Address); + return CA_STATUS_OK; } - uint32_t length = u_arraylist_length(g_deviceStateList); - for (uint32_t index = 0; index < length; index++) + CAResult_t res = CALEUpdateDeviceState(address, state_type, + target_state, + g_deviceStateList, + g_deviceStateListMutex); + if (CA_STATUS_OK != res) { - CALEState_t* state = (CALEState_t*) u_arraylist_get(g_deviceStateList, index); - if (!state) - { - OIC_LOG(ERROR, TAG, "CALEState_t object is null"); - continue; - } - - if (!strcmp(state->address, remoteAddress)) - { - OIC_LOG_V(DEBUG, TAG, "remove state : %s", remoteAddress); - OICFree(state); - - CAResult_t res = CALEClientReorderingList(index, g_deviceStateList); - if(CA_STATUS_OK != res) - { - OIC_LOG(ERROR, TAG, "CALEClientReorderingList has failed"); - return res; - } - return CA_STATUS_OK; - } + OIC_LOG(ERROR, TAG, "CALEUpdateDeviceState has failed"); } + (*env)->ReleaseStringUTFChars(env, jni_Address, address); + (*env)->DeleteLocalRef(env, jni_Address); - return CA_STATUS_FAILED; + return res; } -CALEState_t* CALEClientGetStateInfo(const char* remoteAddress) +CAResult_t CALEClientSetFlagToState(JNIEnv *env, jstring jni_address, + jint state_idx, jboolean flag) { - OIC_LOG(DEBUG, TAG, "CALEClientGetStateInfo"); - VERIFY_NON_NULL_RET(remoteAddress, TAG, "remoteAddress is null", NULL); - - if (!g_deviceStateList) - { - OIC_LOG(ERROR, TAG, "g_deviceStateList is null"); - return NULL; - } - - 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; - } - - if (!strcmp(state->address, remoteAddress)) - { - OIC_LOG_V(DEBUG, TAG, "get state : %s", remoteAddress); - return state; - } - } - return NULL; + return CALESetFlagToState(env, jni_address, state_idx, flag, + g_deviceStateList, g_deviceStateListMutex); } -bool CALEClientIsConnectedDevice(const char* remoteAddress) +jboolean CALEClientGetFlagFromState(JNIEnv *env, jstring jni_address, jint state_idx) { - OIC_LOG(DEBUG, TAG, "CALEClientIsConnectedDevice"); - VERIFY_NON_NULL_RET(remoteAddress, TAG, "remoteAddress is null", false); - - ca_mutex_lock(g_deviceStateListMutex); - if (!g_deviceStateList) - { - OIC_LOG(ERROR, TAG, "g_deviceStateList is null"); - ca_mutex_unlock(g_deviceStateListMutex); - 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"); - continue; - } - - if (!strcmp(state->address, remoteAddress)) - { - OIC_LOG(DEBUG, TAG, "check whether it is connected or not"); - - if (STATE_CONNECTED == state->connectedState) - { - ca_mutex_unlock(g_deviceStateListMutex); - return true; - } - else - { - ca_mutex_unlock(g_deviceStateListMutex); - return false; - } - } - } - ca_mutex_unlock(g_deviceStateListMutex); - return false; + return CALEGetFlagFromState(env, jni_address, state_idx, g_deviceStateList, + g_deviceStateListMutex); } -bool CALEClientIsSetCharacteristic(const char* remoteAddress) +uint16_t CALEClientGetMtuSize(const char* address) { - OIC_LOG(DEBUG, TAG, "CALEClientIsSetCharacteristic"); - VERIFY_NON_NULL_RET(remoteAddress, TAG, "remoteAddress is null", false); - - ca_mutex_lock(g_deviceStateListMutex); - if (!g_deviceStateList) - { - OIC_LOG(ERROR, TAG, "g_deviceStateList is null"); - ca_mutex_unlock(g_deviceStateListMutex); - 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"); - continue; - } - - if (!strcmp(state->address, remoteAddress)) - { - OIC_LOG_V(DEBUG, TAG, "check whether it was set or not:%d", state->notificationState); - - if (STATE_CHARACTER_SET == state->notificationState) - { - ca_mutex_unlock(g_deviceStateListMutex); - return true; - } - else - { - ca_mutex_unlock(g_deviceStateListMutex); - return false; - } - } - } - - ca_mutex_unlock(g_deviceStateListMutex); - return false; + return CALEGetMtuSize(address, g_deviceStateList, g_deviceStateListMutex); } void CALEClientCreateDeviceList() @@ -2876,30 +4397,9 @@ void CALEClientCreateDeviceList() } } -CAResult_t CALEClientReorderingList(uint32_t index, u_arraylist_t *list) +CAResult_t CALEClientResetDeviceStateForAll() { - if (!list) - { - OIC_LOG(ERROR, TAG, "list is null"); - return CA_STATUS_FAILED; - } - - if (index >= list->length) - { - OIC_LOG(ERROR, TAG, "index is not available"); - return CA_STATUS_FAILED; - } - - if (index < list->length - 1) - { - memmove(&list->data[index], &list->data[index + 1], - (list->length - index - 1) * sizeof(void *)); - } - - list->size--; - list->length--; - - return CA_STATUS_OK; + return CALEResetDeviceStateForAll(g_deviceStateList, g_deviceStateListMutex); } /** @@ -2907,9 +4407,11 @@ CAResult_t CALEClientReorderingList(uint32_t index, u_arraylist_t *list) */ void CALEClientUpdateSendCnt(JNIEnv *env) { + OIC_LOG(DEBUG, TAG, "CALEClientUpdateSendCnt"); + VERIFY_NON_NULL_VOID(env, TAG, "env is null"); // mutex lock - ca_mutex_lock(g_threadMutex); + oc_mutex_lock(g_threadMutex); g_currentSentCnt++; @@ -2918,140 +4420,209 @@ 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() { - OIC_LOG(DEBUG, TAG, "IN"); - 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 = oc_mutex_new(); + if (NULL == g_threadWriteCharacteristicMutex) + { + OIC_LOG(ERROR, TAG, "oc_mutex_new has failed"); + return CA_STATUS_FAILED; + } + } + + if (NULL == g_deviceScanRetryDelayMutex) + { + g_deviceScanRetryDelayMutex = oc_mutex_new(); + if (NULL == g_deviceScanRetryDelayMutex) + { + OIC_LOG(ERROR, TAG, "oc_mutex_new has failed"); + return CA_STATUS_FAILED; + } + } + + if (NULL == g_threadSendStateMutex) + { + g_threadSendStateMutex = oc_mutex_new(); + if (NULL == g_threadSendStateMutex) + { + OIC_LOG(ERROR, TAG, "oc_mutex_new has failed"); + return CA_STATUS_FAILED; + } + } + + if (NULL == g_threadScanIntervalMutex) + { + g_threadScanIntervalMutex = oc_mutex_new(); + if (NULL == g_threadScanIntervalMutex) + { + 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; } } - OIC_LOG(DEBUG, TAG, "OUT"); return CA_STATUS_OK; } void CALEClientTerminateGattMutexVariables() { - OIC_LOG(DEBUG, TAG, "IN"); - - 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; - OIC_LOG(DEBUG, TAG, "OUT"); + oc_mutex_free(g_threadWriteCharacteristicMutex); + g_threadWriteCharacteristicMutex = NULL; + + oc_mutex_free(g_deviceScanRetryDelayMutex); + g_deviceScanRetryDelayMutex = NULL; + + oc_mutex_free(g_threadSendStateMutex); + g_threadSendStateMutex = NULL; + + 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); } /** @@ -3060,17 +4631,36 @@ void CALEClientSetSendFinishFlag(bool flag) CAResult_t CAStartLEGattClient() { - CAResult_t res = CALEClientStartMulticastServer(); - if (CA_STATUS_OK != res) + // init mutex for send logic + if (!g_deviceDescCond) + { + g_deviceDescCond = oc_cond_new(); + } + + if (!g_threadCond) + { + g_threadCond = oc_cond_new(); + } + + if (!g_threadWriteCharacteristicCond) + { + g_threadWriteCharacteristicCond = oc_cond_new(); + } + + if (!g_threadScanIntervalCond) { - OIC_LOG(ERROR, TAG, "CALEClientStartMulticastServer has failed"); + g_threadScanIntervalCond = oc_cond_new(); } - else + + CAResult_t ret = CALEClientStartScanWithInterval(); + if (CA_STATUS_OK != ret) { - g_isStartedLEClient = true; + OIC_LOG(ERROR, TAG, "CALEClientStartScanWithInterval has failed"); + return ret; } - return res; + g_isStartedLEClient = true; + return CA_STATUS_OK; } void CAStopLEGattClient() @@ -3084,11 +4674,10 @@ void CAStopLEGattClient() } bool isAttached = false; - JNIEnv* env; + JNIEnv* env = NULL; jint res = (*g_jvm)->GetEnv(g_jvm, (void**) &env, JNI_VERSION_1_6); if (JNI_OK != res) { - OIC_LOG(INFO, TAG, "Could not get JNIEnv pointer"); res = (*g_jvm)->AttachCurrentThread(g_jvm, &env, NULL); if (JNI_OK != res) @@ -3105,13 +4694,45 @@ void CAStopLEGattClient() OIC_LOG(ERROR, TAG, "CALEClientDisconnectAll has failed"); } - ret = CALEClientStopScan(); - if(CA_STATUS_OK != ret) - { - OIC_LOG(ERROR, TAG, "CALEClientStopScan has failed"); - } + CALEClientStopScanWithInterval(); + + oc_mutex_lock(g_threadWriteCharacteristicMutex); + OIC_LOG(DEBUG, TAG, "signal - WriteCharacteristic cond"); + oc_cond_signal(g_threadWriteCharacteristicCond); + oc_mutex_unlock(g_threadWriteCharacteristicMutex); + + 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"); + oc_cond_signal(g_deviceScanRetryDelayCond); + oc_mutex_unlock(g_deviceScanRetryDelayMutex); - ca_cond_signal(g_threadCond); + oc_mutex_lock(g_threadScanIntervalMutex); + OIC_LOG(DEBUG, TAG, "signal - delay cond"); + oc_cond_signal(g_threadScanIntervalCond); + oc_mutex_unlock(g_threadScanIntervalMutex); + + 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; + g_threadWriteCharacteristicCond = NULL; + g_deviceScanRetryDelayCond = NULL; + g_threadScanIntervalCond = NULL; if (isAttached) { @@ -3120,24 +4741,38 @@ void CAStopLEGattClient() } +CAResult_t CAInitializeLEGattClient() +{ + OIC_LOG(DEBUG, TAG, "Initialize GATT Client"); + CALEClientInitialize(); + return CA_STATUS_OK; +} + 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 char *data, - uint32_t dataLen, CALETransferType_t type, - int32_t position) +CAResult_t CAUpdateCharacteristicsToGattServer(const char *remoteAddress, const uint8_t *data, + uint32_t dataLen, CALETransferType_t type, + int32_t position) { - OIC_LOG(DEBUG, TAG, "call CALEClientSendUnicastMessage"); - VERIFY_NON_NULL(data, TAG, "data is null"); + OIC_LOG(INFO, TAG, "call CALEClientSendUnicastMessage"); VERIFY_NON_NULL(remoteAddress, TAG, "remoteAddress is null"); + if (LE_UNICAST != type || position < 0) + { + OIC_LOG(ERROR, TAG, "this request is not unicast"); + return CA_STATUS_INVALID_PARAM; + } + return CALEClientSendUnicastMessage(remoteAddress, data, dataLen); } -CAResult_t CAUpdateCharacteristicsToAllGattServers(const char *data, uint32_t dataLen) +CAResult_t CAUpdateCharacteristicsToAllGattServers(const uint8_t *data, uint32_t dataLen) { OIC_LOG(DEBUG, TAG, "call CALEClientSendMulticastMessage"); VERIFY_NON_NULL(data, TAG, "data is null"); @@ -3147,37 +4782,20 @@ CAResult_t CAUpdateCharacteristicsToAllGattServers(const char *data, uint32_t da void CASetLEReqRespClientCallback(CABLEDataReceivedCallback callback) { - OIC_LOG(DEBUG, TAG, "IN"); - - ca_mutex_lock(g_bleReqRespClientCbMutex); + oc_mutex_lock(g_bleReqRespClientCbMutex); g_CABLEClientDataReceivedCallback = callback; - ca_mutex_unlock(g_bleReqRespClientCbMutex); - - OIC_LOG(DEBUG, TAG, "OUT"); + oc_mutex_unlock(g_bleReqRespClientCbMutex); } void CASetLEClientThreadPoolHandle(ca_thread_pool_t handle) { - OIC_LOG(DEBUG, TAG, "IN"); - - CALEClientInitialize(handle); - - OIC_LOG(DEBUG, TAG, "OUT"); + g_threadPoolHandle = handle; } CAResult_t CAGetLEAddress(char **local_address) { - OIC_LOG(DEBUG, TAG, "IN"); - - VERIFY_NON_NULL(local_address, TAG, "local_address is null"); - CAResult_t res = CALEClientGetInterfaceInfo(local_address); - if (CA_STATUS_OK != res) - { - OIC_LOG(INFO, TAG, "it didn't get local address"); - } - - OIC_LOG(DEBUG, TAG, "OUT"); - return CA_STATUS_OK; + VERIFY_NON_NULL(local_address, TAG, "local_address"); + return CA_NOT_SUPPORTED; } JNIEXPORT void JNICALL @@ -3186,9 +4804,25 @@ Java_org_iotivity_ca_CaLeClientInterface_caLeRegisterLeScanCallback(JNIEnv *env, { OIC_LOG(DEBUG, TAG, "CaLeRegisterLeScanCallback"); VERIFY_NON_NULL_VOID(env, TAG, "env is null"); + VERIFY_NON_NULL_VOID(obj, TAG, "obj is null"); + VERIFY_NON_NULL_VOID(callback, TAG, "callback is null"); + + g_leScanCallback = (*env)->NewGlobalRef(env, callback); + 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 @@ -3197,17 +4831,19 @@ Java_org_iotivity_ca_CaLeClientInterface_caLeRegisterGattCallback(JNIEnv *env, j { OIC_LOG(DEBUG, TAG, "CaLeRegisterGattCallback"); VERIFY_NON_NULL_VOID(env, TAG, "env is null"); + VERIFY_NON_NULL_VOID(obj, TAG, "obj is null"); VERIFY_NON_NULL_VOID(callback, TAG, "callback is null"); g_leGattCallback = (*env)->NewGlobalRef(env, callback); + CACheckJNIException(env); } JNIEXPORT void JNICALL Java_org_iotivity_ca_CaLeClientInterface_caLeScanCallback(JNIEnv *env, jobject obj, - jobject device, jint rssi, - jbyteArray scanRecord) + jobject device) { VERIFY_NON_NULL_VOID(env, TAG, "env is null"); + VERIFY_NON_NULL_VOID(obj, TAG, "obj is null"); VERIFY_NON_NULL_VOID(device, TAG, "device is null"); CAResult_t res = CALEClientAddScanDeviceToList(env, device); @@ -3217,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 @@ -3224,123 +4892,125 @@ Java_org_iotivity_ca_CaLeClientInterface_caLeScanCallback(JNIEnv *env, jobject o */ JNIEXPORT void JNICALL Java_org_iotivity_ca_CaLeClientInterface_caLeGattConnectionStateChangeCallback(JNIEnv *env, - jobject obj, - jobject gatt, - jint status, - jint newstate) + jobject obj, + jobject gatt, + jint status, + jint newstate) { - OIC_LOG_V(DEBUG, TAG, "CALeGattConnectionStateChangeCallback - status %d, newstate %d", status, - newstate); + OIC_LOG_V(INFO, TAG, "CALeGattConnectionStateChangeCallback - status %d, newstate %d", status, + newstate); VERIFY_NON_NULL_VOID(env, TAG, "env is null"); + VERIFY_NON_NULL_VOID(obj, TAG, "obj is null"); VERIFY_NON_NULL_VOID(gatt, TAG, "gatt is null"); - if (GATT_SUCCESS == status && STATE_CONNECTED == newstate) // le connected + jint state_connected = CALEGetConstantsValue(env, CLASSPATH_BT_PROFILE, "STATE_CONNECTED"); + + jstring jni_address = CALEClientGetAddressFromGattObj(env, gatt); + if (!jni_address) { - jstring jni_address = CALEClientGetAddressFromGattObj(env, gatt); - if (!jni_address) - { - goto error_exit; - } + OIC_LOG(ERROR, TAG, "CALEClientGetAddressFromGattObj has failed"); + goto error_exit; + } - const char* address = (*env)->GetStringUTFChars(env, jni_address, NULL); - if (address) + const char* address = (*env)->GetStringUTFChars(env, jni_address, NULL); + if (!address) + { + OIC_LOG(ERROR, TAG, "address is null"); + CACheckJNIException(env); + goto error_exit; + } + OIC_LOG_V(DEBUG, TAG, "CALeGattConnectionStateChangeCallback - address [%s]", address); + + if (state_connected == newstate) + { + OIC_LOG(DEBUG, TAG, "LE is connected"); + if (GATT_SUCCESS == status) { - CAResult_t res = CALEClientUpdateDeviceState(address, STATE_CONNECTED, - STATE_CHARACTER_NO_CHANGE, - STATE_SEND_NONE); + CAResult_t res = 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"); - (*env)->ReleaseStringUTFChars(env, jni_address, address); + OIC_LOG(ERROR, TAG, "CALEUpdateDeviceState has failed"); goto error_exit; } - (*env)->ReleaseStringUTFChars(env, jni_address, address); - } - - CAResult_t res = CALEClientAddGattobjToList(env, gatt); - if (CA_STATUS_OK != res) - { - OIC_LOG(ERROR, TAG, "CALEClientAddGattobjToList has failed"); - goto error_exit; - } - - res = CALEClientDiscoverServices(env, gatt); - if (CA_STATUS_OK != res) - { - OIC_LOG(ERROR, TAG, "CALEClientDiscoverServices has failed"); - goto error_exit; - } - } - else if (GATT_SUCCESS == status && STATE_DISCONNECTED == newstate) // le disconnected - { - CAResult_t res = CALEClientStartScan(); - if (CA_STATUS_OK != res) - { - OIC_LOG(ERROR, TAG, "CALEClientStartScan has failed"); - } - jstring jni_address = CALEClientGetAddressFromGattObj(env, gatt); - if (!jni_address) - { - OIC_LOG(ERROR, TAG, "CALEClientGetAddressFromGattObj has failed"); - } + res = CALEClientAddGattobjToList(env, gatt); + if (CA_STATUS_OK != res) + { + OIC_LOG(ERROR, TAG, "CALEClientAddGattobjToList has failed"); + goto error_exit; + } - const char* address = (*env)->GetStringUTFChars(env, jni_address, NULL); - if (address) - { - res = CALEClientUpdateDeviceState(address, STATE_DISCONNECTED, - STATE_CHARACTER_NO_CHANGE, - STATE_SEND_NONE); + res = CALEClientDiscoverServices(env, gatt); if (CA_STATUS_OK != res) { - OIC_LOG(ERROR, TAG, "CALEClientUpdateDeviceState has failed"); + OIC_LOG(ERROR, TAG, "CALEClientDiscoverServices has failed"); + goto error_exit; } - (*env)->ReleaseStringUTFChars(env, jni_address, address); } - - res = CALEClientGattClose(env, gatt); - if (CA_STATUS_OK != res) + else { - OIC_LOG(ERROR, TAG, "CALEClientGattClose has failed"); + OIC_LOG(INFO, TAG, "unknown status"); + (*env)->ReleaseStringUTFChars(env, jni_address, address); } } - else // error + else // STATE_DISCONNECTED == newstate { - // update state - jstring jni_address = CALEClientGetAddressFromGattObj(env, gatt); - if (!jni_address) - { - OIC_LOG(ERROR, TAG, "jni_address is null"); - goto error_exit; - - } + OIC_LOG(DEBUG, TAG, "LE is disconnected"); - const char* address = (*env)->GetStringUTFChars(env, jni_address, NULL); - if (address) + if (CALEIsValidState(address, CA_LE_SEND_STATE, STATE_SEND_PREPARING, + g_deviceStateList, g_deviceStateListMutex)) { - CAResult_t res = CALEClientUpdateDeviceState(address, STATE_DISCONNECTED, - STATE_CHARACTER_NO_CHANGE, - STATE_SEND_FAILED); + 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, "CALEClientUpdateDeviceState has failed"); + 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, "CALEUpdateDeviceState has failed"); + } (*env)->ReleaseStringUTFChars(env, jni_address, address); - CAResult_t res = CALEClientGattClose(env, gatt); + res = CALEClientGattClose(env, gatt); if (CA_STATUS_OK != res) { OIC_LOG(ERROR, TAG, "CALEClientGattClose has failed"); } - goto error_exit; + if (CALECheckConnectionStateValue(status)) + { + // this state is unexpected reason to disconnect + // if the reason is suitable, connection logic of the device will be destroyed. + OIC_LOG(INFO, TAG, "connection logic destroy"); + } + 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; // error label. error_exit: - CALEClientSendFinish(env, gatt); return; } @@ -3352,15 +5022,16 @@ error_exit: */ JNIEXPORT void JNICALL Java_org_iotivity_ca_CaLeClientInterface_caLeGattServicesDiscoveredCallback(JNIEnv *env, - jobject obj, - jobject gatt, - jint status) + jobject obj, + jobject gatt, + jint status) { - OIC_LOG_V(DEBUG, TAG, "CALeGattServicesDiscoveredCallback - status %d: ", status); + OIC_LOG_V(INFO, TAG, "CALeGattServicesDiscoveredCallback - status %d", status); VERIFY_NON_NULL_VOID(env, TAG, "env is null"); + VERIFY_NON_NULL_VOID(obj, TAG, "obj is null"); VERIFY_NON_NULL_VOID(gatt, TAG, "gatt is null"); - if (0 != status) // discovery error + if (GATT_SUCCESS != status) // discovery error { CALEClientSendFinish(env, gatt); return; @@ -3376,63 +5047,86 @@ Java_org_iotivity_ca_CaLeClientInterface_caLeGattServicesDiscoveredCallback(JNIE const char* address = (*env)->GetStringUTFChars(env, jni_address, NULL); if (!address) { + CACheckJNIException(env); CALEClientSendFinish(env, gatt); return; } - if (!CALEClientIsSetCharacteristic(address)) + jstring jni_uuid = (*env)->NewStringUTF(env, OIC_GATT_CHARACTERISTIC_RESPONSE_UUID); + if (!jni_uuid) { - jstring jni_uuid = (*env)->NewStringUTF(env, OIC_GATT_CHARACTERISTIC_RESPONSE_UUID); - if (!jni_uuid) - { - OIC_LOG(ERROR, TAG, "jni_uuid is null"); - goto error_exit; - } + OIC_LOG(ERROR, TAG, "jni_uuid is null"); + goto error_exit; + } - jobject jni_obj_GattCharacteristic = CALEClientGetGattService(env, gatt, jni_uuid); - if (!jni_obj_GattCharacteristic) - { - OIC_LOG(ERROR, TAG, "jni_obj_GattCharacteristic is null"); - goto error_exit; - } + jobject jni_obj_GattCharacteristic = CALEClientGetGattService(env, gatt, jni_uuid); + if (!jni_obj_GattCharacteristic) + { + OIC_LOG(ERROR, TAG, "jni_obj_GattCharacteristic is null"); + goto error_exit; + } - CAResult_t res = CALEClientSetCharacteristicNotification(env, gatt, - jni_obj_GattCharacteristic); + CAResult_t res = CALEClientSetCharacteristicNotification(env, gatt, + jni_obj_GattCharacteristic); + if (CA_STATUS_OK != res) + { + OIC_LOG(ERROR, TAG, "CALEClientSetCharacteristicNotification has failed"); + goto error_exit; + } + + res = CALEClientSetUUIDToDescriptor(env, gatt, jni_obj_GattCharacteristic); + if (CA_STATUS_OK != res) + { + OIC_LOG_V(INFO, TAG, "Descriptor is not found : %d", res); + + res = CALESetFlagToState(env, jni_address, CA_LE_DESCRIPTOR_FOUND, JNI_FALSE, + g_deviceStateList, g_deviceStateListMutex); if (CA_STATUS_OK != res) { - OIC_LOG(ERROR, TAG, "CALEClientSetCharacteristicNotification has failed"); + OIC_LOG(ERROR, TAG, "CALESetFlagToState has failed"); goto error_exit; } - res = CALEClientSetUUIDToDescriptor(env, gatt, jni_obj_GattCharacteristic); + res = CALEUpdateDeviceState(address, CA_LE_CONNECTION_STATE, + STATE_SERVICE_CONNECTED, + g_deviceStateList, + g_deviceStateListMutex); if (CA_STATUS_OK != res) { - OIC_LOG(ERROR, TAG, "CALEClientSetUUIDToDescriptor has failed"); + OIC_LOG(ERROR, TAG, "CALEUpdateDeviceState has failed"); goto error_exit; } - res = CALEClientUpdateDeviceState(address, STATE_CONNECTED, STATE_CHARACTER_SET, - STATE_SEND_NONE); + res = CALEClientRequestMTU(env, gatt, CA_SUPPORTED_BLE_MTU_SIZE); if (CA_STATUS_OK != res) { - OIC_LOG(ERROR, TAG, "CALEClientUpdateDeviceState has failed"); + OIC_LOG(ERROR, TAG, "CALEClientRequestMTU has failed"); goto error_exit; } } else { - CAResult_t res = CALEClientWriteCharacteristic(env, gatt); + res = CALESetFlagToState(env, jni_address, CA_LE_DESCRIPTOR_FOUND, JNI_TRUE, + g_deviceStateList, g_deviceStateListMutex); if (CA_STATUS_OK != res) { - OIC_LOG(ERROR, TAG, "CALEClientWriteCharacteristic 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; // error label. error_exit: + OIC_LOG(ERROR, TAG, "ServicesDiscovery has failed"); (*env)->ReleaseStringUTFChars(env, jni_address, address); CALEClientSendFinish(env, gatt); return; @@ -3440,39 +5134,18 @@ error_exit: /* * Class: org_iotivity_ca_jar_caleinterface - * Method: CALeGattCharacteristicReadCallback - * Signature: (Landroid/bluetooth/BluetoothGatt;Landroid/bluetooth/BluetoothGattCharacteristic;I)V - */ -JNIEXPORT void JNICALL -Java_org_iotivity_ca_CaLeClientInterface_caLeGattCharacteristicReadCallback(JNIEnv *env, - jobject obj, - jobject gatt, - jobject characteristic, - jbyteArray data, - jint status) -{ - OIC_LOG_V(DEBUG, TAG, "CALeGattCharacteristicReadCallback - status : %d", status); -} - -/* - * Class: org_iotivity_ca_jar_caleinterface * Method: CALeGattCharacteristicWritjclasseCallback * Signature: (Landroid/bluetooth/BluetoothGatt;Landroid/bluetooth/BluetoothGattCharacteristic;I)V */ JNIEXPORT void JNICALL Java_org_iotivity_ca_CaLeClientInterface_caLeGattCharacteristicWriteCallback( - JNIEnv *env, jobject obj, jobject gatt, jobject characteristic, jbyteArray data, - jint status) + JNIEnv *env, jobject obj, jobject gatt, jbyteArray data, jint status) { - OIC_LOG_V(DEBUG, TAG, "CALeGattCharacteristicWriteCallback - status : %d", status); + OIC_LOG_V(INFO, TAG, "CALeGattCharacteristicWriteCallback - status : %d", status); VERIFY_NON_NULL_VOID(env, TAG, "env is null"); + VERIFY_NON_NULL_VOID(obj, TAG, "obj is null"); VERIFY_NON_NULL_VOID(gatt, TAG, "gatt is null"); - jboolean isCopy; - char* wroteData = (char*) (*env)->GetByteArrayElements(env, data, &isCopy); - - OIC_LOG_V(DEBUG, TAG, "CALeGattCharacteristicWriteCallback - write data : %s", wroteData); - // send success & signal jstring jni_address = CALEClientGetAddressFromGattObj(env, gatt); if (!jni_address) @@ -3483,30 +5156,67 @@ Java_org_iotivity_ca_CaLeClientInterface_caLeGattCharacteristicWriteCallback( const char* address = (*env)->GetStringUTFChars(env, jni_address, NULL); if (!address) { + CACheckJNIException(env); goto error_exit; } if (GATT_SUCCESS != status) // error case { OIC_LOG(ERROR, TAG, "send failure"); - CAResult_t res = CALEClientUpdateDeviceState(address, STATE_CONNECTED, STATE_CHARACTER_SET, - STATE_SEND_FAILED); + + // retry to write + CAResult_t res = CALEClientWriteCharacteristic(env, gatt); if (CA_STATUS_OK != res) { - OIC_LOG(ERROR, TAG, "CALEClientUpdateDeviceState has failed"); + OIC_LOG(ERROR, TAG, "WriteCharacteristic has failed"); + oc_mutex_lock(g_threadWriteCharacteristicMutex); + g_isSignalSetFlag = true; + oc_cond_signal(g_threadWriteCharacteristicCond); + oc_mutex_unlock(g_threadWriteCharacteristicMutex); + + 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"); + } + + 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); + goto error_exit; } - CALEClientSendFinish(env, gatt); } else { OIC_LOG(DEBUG, TAG, "send success"); - CAResult_t res = CALEClientUpdateDeviceState(address, STATE_CONNECTED, STATE_CHARACTER_SET, - 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"); } - CALEClientUpdateSendCnt(env); + + oc_mutex_lock(g_threadWriteCharacteristicMutex); + OIC_LOG(DEBUG, TAG, "g_isSignalSetFlag is set true and signal"); + g_isSignalSetFlag = true; + 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); @@ -3526,31 +5236,29 @@ error_exit: */ JNIEXPORT void JNICALL Java_org_iotivity_ca_CaLeClientInterface_caLeGattCharacteristicChangedCallback( - JNIEnv *env, jobject obj, jobject gatt, jobject characteristic, jbyteArray data) + JNIEnv *env, jobject obj, jobject gatt, jbyteArray data) { OIC_LOG(DEBUG, TAG, "CALeGattCharacteristicChangedCallback"); VERIFY_NON_NULL_VOID(env, TAG, "env is null"); + VERIFY_NON_NULL_VOID(obj, TAG, "obj is null"); VERIFY_NON_NULL_VOID(gatt, TAG, "gatt is null"); VERIFY_NON_NULL_VOID(data, TAG, "data is null"); - // get Byte Array and covert to char* + // get Byte Array and convert to uint8_t* jint length = (*env)->GetArrayLength(env, data); jboolean isCopy; jbyte *jni_byte_responseData = (jbyte*) (*env)->GetByteArrayElements(env, data, &isCopy); + CACheckJNIException(env); - OIC_LOG_V(DEBUG, TAG, "CALeGattCharacteristicChangedCallback - raw data received : %s", - jni_byte_responseData); - - char* receivedData = (char*) OICMalloc(sizeof(char) * length + 1); + uint8_t* receivedData = OICMalloc(length); if (!receivedData) { - OIC_LOG(ERROR, TAG, "recevicedData is null"); + OIC_LOG(ERROR, TAG, "receivedData is null"); return; } - memcpy(receivedData, (const char*) jni_byte_responseData, length); - receivedData[length] = '\0'; + memcpy(receivedData, jni_byte_responseData, length); (*env)->ReleaseByteArrayElements(env, data, jni_byte_responseData, JNI_ABORT); jstring jni_address = CALEClientGetAddressFromGattObj(env, gatt); @@ -3565,55 +5273,70 @@ Java_org_iotivity_ca_CaLeClientInterface_caLeGattCharacteristicChangedCallback( if (!address) { OIC_LOG(ERROR, TAG, "address is null"); + CACheckJNIException(env); OICFree(receivedData); return; } - OIC_LOG_V(DEBUG, TAG, "CALeGattCharacteristicChangedCallback - data. : %s, %d", + OIC_LOG_V(DEBUG, TAG, "CALeGattCharacteristicChangedCallback - data. : %p, %d", receivedData, length); - ca_mutex_lock(g_bleServerBDAddressMutex); uint32_t sentLength = 0; - g_CABLEClientDataReceivedCallback(address, receivedData, length, - &sentLength); - ca_mutex_unlock(g_bleServerBDAddressMutex); + oc_mutex_lock(g_bleServerBDAddressMutex); + g_CABLEClientDataReceivedCallback(address, receivedData, length, &sentLength); + oc_mutex_unlock(g_bleServerBDAddressMutex); (*env)->ReleaseStringUTFChars(env, jni_address, address); } /* * Class: org_iotivity_ca_jar_caleinterface - * Method: CALeGattDescriptorReadCallback - * Signature: (Landroid/bluetooth/BluetoothGatt;Landroid/bluetooth/BluetoothGattDescriptor;I)V - */ -JNIEXPORT void JNICALL -Java_org_iotivity_ca_CaLeClientInterface_caLeGattDescriptorReadCallback(JNIEnv *env, jobject obj, - jobject gatt, - jobject descriptor, - jint status) -{ - OIC_LOG_V(DEBUG, TAG, "CALeGattDescriptorReadCallback - status %d: ", status); -} - -/* - * Class: org_iotivity_ca_jar_caleinterface * Method: CALeGattDescriptorWriteCallback * Signature: (Landroid/bluetooth/BluetoothGatt;Landroid/bluetooth/BluetoothGattDescriptor;I)V */ JNIEXPORT void JNICALL Java_org_iotivity_ca_CaLeClientInterface_caLeGattDescriptorWriteCallback(JNIEnv *env, jobject obj, - jobject gatt, - jobject descriptor, - jint status) + jobject gatt, + jint status) { - OIC_LOG_V(DEBUG, TAG, "CALeGattDescriptorWriteCallback - status %d: ", status); + OIC_LOG_V(INFO, TAG, "CALeGattDescriptorWriteCallback - status %d", status); VERIFY_NON_NULL_VOID(env, TAG, "env is null"); + VERIFY_NON_NULL_VOID(obj, TAG, "obj is null"); VERIFY_NON_NULL_VOID(gatt, TAG, "gatt is null"); - CAResult_t res = CALEClientWriteCharacteristic(env, gatt); + if (GATT_SUCCESS != status) // error + { + goto error_exit; + } + + jstring jni_address = CALEClientGetAddressFromGattObj(env, gatt); + if (!jni_address) + { + goto error_exit; + } + + const char* address = (*env)->GetStringUTFChars(env, jni_address, NULL); + if (!address) + { + CACheckJNIException(env); + goto error_exit; + } + + 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, "CALEUpdateDeviceState has failed"); + goto error_exit; + } + + res = CALEClientRequestMTU(env, gatt, CA_SUPPORTED_BLE_MTU_SIZE); if (CA_STATUS_OK != res) { - OIC_LOG(ERROR, TAG, "CALEClientWriteCharacteristic has failed"); + OIC_LOG(ERROR, TAG, "CALEClientRequestMTU has failed"); goto error_exit; } return; @@ -3625,29 +5348,66 @@ error_exit: return; } -/* - * Class: org_iotivity_ca_jar_caleinterface - * Method: CALeGattReliableWriteCompletedCallback - * Signature: (Landroid/bluetooth/BluetoothGatt;I)V - */ JNIEXPORT void JNICALL -Java_org_iotivity_ca_CaLeClientInterface_caLeGattReliableWriteCompletedCallback(JNIEnv *env, - jobject obj, - jobject gatt, - jint status) +Java_org_iotivity_ca_CaLeClientInterface_caLeGattMtuChangedCallback(JNIEnv *env, + jobject obj, + jobject gatt, + jint mtu, + jint status) { - OIC_LOG_V(DEBUG, TAG, "CALeGattReliableWriteCompletedCallback - status %d: ", status); -} + OIC_LOG_V(INFO, TAG, "caLeGattMtuChangedCallback - status %d, " + "mtu[%d-including Header size 3 byte]", status, mtu); -/* - * Class: org_iotivity_ca_jar_caleinterface - * Method: CALeGattReadRemoteRssiCallback - * Signature: (Landroid/bluetooth/BluetoothGatt;II)V - */ -JNIEXPORT void JNICALL -Java_org_iotivity_ca_CaLeClientInterface_caLeGattReadRemoteRssiCallback(JNIEnv *env, jobject obj, - jobject gatt, jint rssi, - jint status) -{ - OIC_LOG_V(DEBUG, TAG, "CALeGattReadRemoteRssiCallback - rssi %d, status %d: ", rssi, status); + (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); + } + } }