1 /* ****************************************************************
3 * Copyright 2016 Samsung Electronics All Rights Reserved.
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
19 ******************************************************************/
23 #include "cautilinterface.h"
24 #include "camanagerleinterface.h"
25 #include "camanagerleutil.h"
26 #include "caleautoconnector.h"
28 #include "cacommonutil.h"
29 #include "camanagerdevice.h"
30 #include "caleclient.h"
31 #include "caleutils.h"
33 #define TAG "OIC_CA_MANAGER_LE"
35 static const jint SUPPORT_ADNROID_API_LEVEL = 18;
36 static const jint AUTH_FAIL = 5;
37 static const jint LINK_LOSS = 8;
38 static const jint ACCEPT_TIMEOUT_EXCEPTION = 16;
39 static const jint REMOTE_DISCONNECT = 19;
40 static const jint LOCAL_DISCONNECT = 22;
41 static const jint CONNECTION_FAILED_TO_BE_EASTABLISHED = 62;
42 static const jint USER_REMOVED_BOND = 68;
43 static JavaVM *g_jvm = NULL;
44 static jobject g_context = NULL;
45 static jobject g_connectedDeviceSet = NULL;
48 CAResult_t CASetLEClientAutoConnectionDeviceInfo(const char* address)
50 OIC_LOG(DEBUG, TAG, "CASetClientAutoConnectionDeviceInfo");
51 VERIFY_NON_NULL(address, TAG, "address");
53 bool isAttached = false;
55 jint res = (*g_jvm)->GetEnv(g_jvm, (void**) &env, JNI_VERSION_1_6);
58 OIC_LOG(DEBUG, TAG, "AttachCurrentThread will be called for JNIEnv pointer");
59 res = (*g_jvm)->AttachCurrentThread(g_jvm, &env, NULL);
63 OIC_LOG(ERROR, TAG, "AttachCurrentThread has failed");
64 return CA_STATUS_FAILED;
69 OIC_LOG_V(DEBUG, TAG, "set [%s] for Auto Connection", address);
70 jstring jni_leAddress = (*env)->NewStringUTF(env, address);
72 if (!CAManagerCheckBTAddress(env, jni_leAddress))
74 OIC_LOG(ERROR, TAG, "this address is not BT address string format");
77 (*g_jvm)->DetachCurrentThread(g_jvm);
79 return CA_STATUS_FAILED;
82 // if there is target address in SharedPreference. it will be reseted.
83 if (CAManagerIsConnectedDeviceAddress(env, g_context,
85 g_connectedDeviceSet))
87 if (!CAManagerRemoveConnectedDeviceAddress(env, g_context,
89 g_connectedDeviceSet))
91 OIC_LOG(ERROR, TAG, "Preference - remove has failed");
95 OIC_LOG(INFO, TAG, "Preference - remove success");
99 // it will be added new target address.
100 if (!CAManagerAddConnectedDeviceAddress(env, g_context,
101 jni_leAddress, g_connectedDeviceSet))
103 OIC_LOG(ERROR, TAG, "Preference - putting has failed");
107 OIC_LOG(INFO, TAG, "Preference - putting success");
112 (*g_jvm)->DetachCurrentThread(g_jvm);
118 CAResult_t CAUnsetLEClientAutoConnectionDeviceInfo(const char* address)
120 OIC_LOG(DEBUG, TAG, "CAUnsetClientAutoConnectionDeviceInfo");
121 VERIFY_NON_NULL(address, TAG, "address");
123 bool isAttached = false;
125 jint res = (*g_jvm)->GetEnv(g_jvm, (void**) &env, JNI_VERSION_1_6);
128 OIC_LOG(DEBUG, TAG, "AttachCurrentThread will be called for JNIEnv pointer");
129 res = (*g_jvm)->AttachCurrentThread(g_jvm, &env, NULL);
133 OIC_LOG(ERROR, TAG, "AttachCurrentThread has failed");
134 return CA_STATUS_FAILED;
139 OIC_LOG_V(DEBUG, TAG, "unset [%s] for Auto Connection", address);
140 jstring jni_leAddress = (*env)->NewStringUTF(env, address);
142 if (!CAManagerCheckBTAddress(env, jni_leAddress))
144 OIC_LOG(ERROR, TAG, "this address is not BT address string format");
147 (*g_jvm)->DetachCurrentThread(g_jvm);
149 return CA_STATUS_FAILED;
152 // if there is target address in SharedPreference. it would be removed
153 if (CAManagerIsConnectedDeviceAddress(env, g_context,
155 g_connectedDeviceSet))
157 if (!CAManagerRemoveConnectedDeviceAddress(env, g_context,
159 g_connectedDeviceSet))
161 OIC_LOG(ERROR, TAG, "Preference - remove has failed");
165 OIC_LOG(INFO, TAG, "Preference - remove success");
169 // remove target device for auto connection
170 CAResult_t ret = CAManagerRemoveData(env, jni_leAddress);
171 if (CA_STATUS_OK != ret)
173 OIC_LOG(ERROR, TAG, "CAManagerRemoveData has failed");
178 (*g_jvm)->DetachCurrentThread(g_jvm);
184 CAResult_t CAManagerLEClientInitialize(JNIEnv *env, JavaVM *jvm, jobject context)
186 OIC_LOG(DEBUG, TAG, "CAManagerClientInitialize");
187 VERIFY_NON_NULL(env, TAG, "env");
188 VERIFY_NON_NULL(jvm, TAG, "jvm");
189 VERIFY_NON_NULL(context, TAG, "context");
191 jint jni_int_sdk = CALEGetBuildVersion(env);
192 if (jni_int_sdk < SUPPORT_ADNROID_API_LEVEL)
194 OIC_LOG_V(ERROR, TAG, "it is not supported (%d)", jni_int_sdk);
195 return CA_STATUS_FAILED;
199 g_context = (*env)->NewGlobalRef(env, context);;
200 CAManagerInitMutexVaraibles();
201 CAManagerInitLEAutoConnection();
203 CAManagerCreateACDataList(env);
205 // get last connected device list
207 set = CAManagerGetConnectedDeviceAddress(env, g_context);
210 // create new set<String> object
211 set = CAManagerCreateSetString(env);
214 OIC_LOG(DEBUG, TAG, "created new SetString");
218 OIC_LOG(ERROR, TAG, "CAManagerCreateSetString has failed");
219 return CA_STATUS_FAILED;
224 OIC_LOG(DEBUG, TAG, "get previous Set<String> object");
227 g_connectedDeviceSet = (jobject)(*env)->NewGlobalRef(env, set);
228 if (!g_connectedDeviceSet)
230 OIC_LOG(ERROR, TAG, "g_connectedDeviceSet is null");
231 return CA_STATUS_FAILED;
237 CAResult_t CAManagerLEClientTerminate(JNIEnv *env)
239 OIC_LOG(DEBUG, TAG, "CAManagerClientTerminate");
240 VERIFY_NON_NULL(env, TAG, "env");
242 // stop gatt connection
243 CAResult_t res = CALEClientDisconnectAll(env);
244 if (CA_STATUS_OK != res)
246 OIC_LOG(ERROR, TAG, "CALEClientDisconnectAll has failed");
249 res = CAManagerRemoveAllData(env);
250 if (CA_STATUS_OK != res)
252 OIC_LOG(ERROR, TAG, "CAManagerRemoveAllData has failed");
255 CAManagerTerminateLEAutoConnection();
256 CAManagerTerminateMutexVariables();
260 (*env)->DeleteGlobalRef(env, g_context);
264 if (g_connectedDeviceSet)
266 (*env)->DeleteGlobalRef(env, g_connectedDeviceSet);
267 g_connectedDeviceSet = NULL;
273 JNIEXPORT void JNICALL
274 Java_org_iotivity_ca_CaLeClientInterface_caManagerAdapterStateChangedCallback(
275 JNIEnv *env, jobject obj, jint state)
277 OIC_LOG(DEBUG, TAG, "caManagerAdapterStateChangedCallback");
278 VERIFY_NON_NULL_VOID(env, TAG, "env");
279 VERIFY_NON_NULL_VOID(obj, TAG, "obj");
281 jint state_on = CALEGetConstantsValue(env, CLASSPATH_BT_ADAPTER, "STATE_ON");
282 jint state_off = CALEGetConstantsValue(env, CLASSPATH_BT_ADAPTER, "STATE_OFF");
283 jint state_turning_off = CALEGetConstantsValue(env, CLASSPATH_BT_ADAPTER, "STATE_TURNING_OFF");
285 if (state_on == state)
287 OIC_LOG(DEBUG, TAG, "AdapterStateChangedCallback : state_on");
289 // when BT state is on. recovery flag has to be reset.
290 CAManagerSetBTRecovery(false);
292 // find target device for autoconnect
293 size_t length = CAManagerGetACDataLength();
294 OIC_LOG_V(DEBUG, TAG, "target device : %d", length);
295 for (size_t idx = 0; idx < length; idx++)
297 jstring leAddress = CAManagerGetLEAddressFromACData(env, idx);
300 CAResult_t res = CAManagerStartAutoConnection(env, leAddress);
301 if (CA_STATUS_OK != res)
303 OIC_LOG(ERROR, TAG, "CAManagerStartAutoConnection has failed");
309 else if (state_off == state)
311 OIC_LOG(DEBUG, TAG, "AdapterStateChangedCallback : state_off");
313 // reset autoconnect flag for all target devices
314 size_t length = CAManagerGetACDataLength();
315 for (size_t idx = 0; idx < length; idx++)
317 jstring address = CAManagerGetLEAddressFromACData(env, idx);
320 CAManagerSetAutoConnectionFlag(env, address, false);
324 // check whether BT recovery is needed or not
325 if (CAManagerIsRecoveryFlagSet())
327 CAManagerProcessRecovery(env, STATE_OFF);
330 else if (state_turning_off == state)
332 OIC_LOG(DEBUG, TAG, "AdapterStateChangedCallback : state_turning_off");
337 OIC_LOG(INFO, TAG, "AdapterStateChangedCallback state is not available");
342 JNIEXPORT void JNICALL
343 Java_org_iotivity_ca_CaLeClientInterface_caManagerBondStateChangedCallback(
344 JNIEnv *env, jobject obj, jobject device)
346 OIC_LOG(DEBUG, TAG, "caManagerBondStateChangedCallback");
347 VERIFY_NON_NULL_VOID(env, TAG, "env");
348 VERIFY_NON_NULL_VOID(obj, TAG, "obj");
349 VERIFY_NON_NULL_VOID(device, TAG, "device");
351 // get ble address from Bluetooth Device object
352 jstring jni_leAddress = CALEClientGetLEAddressFromBTDevice(env, device);
355 OIC_LOG(INFO, TAG, "unbonded : it isn't same device type");
359 char* leAddress = (char*)(*env)->GetStringUTFChars(env, jni_leAddress, NULL);
362 OIC_LOG(ERROR, TAG, "leAddress is null");
366 // if there is no data, CAData will be created.
367 OIC_LOG_V(DEBUG, TAG, "bond none device : %s", leAddress);
369 CAResult_t res = CAManagerRemoveData(env, jni_leAddress);
370 if (CA_STATUS_OK != res)
372 OIC_LOG(ERROR, TAG, "CAManagerRemoveData has failed");
375 (*env)->ReleaseStringUTFChars(env, jni_leAddress, leAddress);
377 if (!CAManagerRemoveConnectedDeviceAddress(env, g_context,
379 g_connectedDeviceSet))
381 OIC_LOG(ERROR, TAG, "CAManagerRemoveConnectedDeviceAddress has failed");
384 OIC_LOG(INFO, TAG, "bonded state changed bone_none");
387 JNIEXPORT void JNICALL
388 Java_org_iotivity_ca_CaLeClientInterface_caManagerLeGattConnectionStateChangeCB(
389 JNIEnv *env, jobject obj, jobject gatt, jint status, jint newState)
391 OIC_LOG_V(DEBUG, TAG, "caManagerLeGattConnectionStateChangeCB-status(%d), newState(%d)",
394 VERIFY_NON_NULL_VOID(env, TAG, "env");
395 VERIFY_NON_NULL_VOID(obj, TAG, "obj");
396 VERIFY_NON_NULL_VOID(gatt, TAG, "gatt");
398 jint state_connected = CALEGetConstantsValue(env, CLASSPATH_BT_PROFILE, "STATE_CONNECTED");
399 jint state_disconnected = CALEGetConstantsValue(env, CLASSPATH_BT_PROFILE, "STATE_DISCONNECTED");
400 jint gatt_success = CALEGetConstantsValue(env, CLASSPATH_BT_GATT, "GATT_SUCCESS");
402 jstring jni_address = CAManagerGetAddressFromGatt(env, gatt);
405 OIC_LOG(ERROR, TAG, "CAManagerGetAddressFromGatt is null");
409 char* address = (char*)(*env)->GetStringUTFChars(env, jni_address, NULL);
412 OIC_LOG(ERROR, TAG, "address is null");
416 OIC_LOG_V(INFO, TAG, "connection state : status(%d), addr:(%s), newState(%d)",
417 status, address, newState);
419 if (gatt_success == status && state_connected == newState) // le connected
421 OIC_LOG(DEBUG, TAG, "LE is connected");
422 CAResult_t res = CAManagerReadRemoteRssi(env, gatt);
423 if (CA_STATUS_OK != res)
425 OIC_LOG(ERROR, TAG, "CAManagerReadRemoteRssi has failed");
426 (*env)->ReleaseStringUTFChars(env, jni_address, address);
430 else if (state_disconnected == newState)// le disconnected
432 if (LINK_LOSS == status || REMOTE_DISCONNECT == status)
434 OIC_LOG(DEBUG, TAG, "LE is disconnected");
436 if (!CAManagerIsMatchedACData(env, jni_address))
438 OIC_LOG_V(DEBUG, TAG, "this[%s] is not target address for Auto Connection",
440 (*env)->ReleaseStringUTFChars(env, jni_address, address);
444 CAManagerSetAutoConnectionFlag(env, jni_address, false);
446 CAResult_t res = CAManagerStartAutoConnection(env, jni_address);
447 if (CA_STATUS_OK != res)
449 (*env)->ReleaseStringUTFChars(env, jni_address, address);
450 OIC_LOG(ERROR, TAG, "CAManagerStartAutoConnection has failed");
454 else if (ACCEPT_TIMEOUT_EXCEPTION == status)
456 CAManagerProcessRecovery(env, START_RECOVERY);
459 (*env)->ReleaseStringUTFChars(env, jni_address, address);
460 (*env)->DeleteLocalRef(env, jni_address);
464 * Class: org_iotivity_ca_jar_caleinterface
465 * Method: caManagerLeServicesDiscoveredCallback
466 * Signature: (Landroid/bluetooth/BluetoothGatt;I)V
468 JNIEXPORT void JNICALL
469 Java_org_iotivity_ca_CaLeClientInterface_caManagerLeServicesDiscoveredCallback(JNIEnv *env,
474 OIC_LOG_V(DEBUG, TAG, "caManagerLeServicesDiscoveredCallback - status %d: ", status);
475 VERIFY_NON_NULL_VOID(env, TAG, "env");
476 VERIFY_NON_NULL_VOID(obj, TAG, "obj");
477 VERIFY_NON_NULL_VOID(gatt, TAG, "gatt");
479 if (GATT_SUCCESS == status)
481 if (!g_connectedDeviceSet)
483 OIC_LOG(ERROR, TAG, "g_connectedDeviceSet is null");
487 jstring jni_address = CAManagerGetAddressFromGatt(env, gatt);
490 OIC_LOG(ERROR, TAG, "CAManagerGetAddressFromGatt is null");
494 char* address = (char*)(*env)->GetStringUTFChars(env, jni_address, NULL);
497 OIC_LOG(ERROR, TAG, "address is null");
498 (*env)->DeleteLocalRef(env, jni_address);
501 OIC_LOG_V(DEBUG, TAG, "ServicesDiscovered device : %s", address);
503 // target address for auto connection will be set in device list.
504 // check set connected address information by user
505 jclass jni_cls_set = (*env)->FindClass(env, "java/util/HashSet");
508 OIC_LOG(ERROR, TAG, "jni_cls_set is null");
509 (*env)->ReleaseStringUTFChars(env, jni_address, address);
510 (*env)->DeleteLocalRef(env, jni_address);
514 jmethodID jni_mid_iterator = (*env)->GetMethodID(env, jni_cls_set, "iterator",
515 "()Ljava/util/Iterator;");
516 if (!jni_mid_iterator)
518 OIC_LOG(ERROR, TAG, "jni_mid_iterator is null");
519 (*env)->DeleteLocalRef(env, jni_cls_set);
520 (*env)->ReleaseStringUTFChars(env, jni_address, address);
521 (*env)->DeleteLocalRef(env, jni_address);
525 jobject jni_obj_iter = (*env)->CallObjectMethod(env, g_connectedDeviceSet, jni_mid_iterator);
528 OIC_LOG(ERROR, TAG, "jni_obj_iter is null");
529 (*env)->DeleteLocalRef(env, jni_cls_set);
530 (*env)->ReleaseStringUTFChars(env, jni_address, address);
531 (*env)->DeleteLocalRef(env, jni_address);
535 // Get the Iterator method IDs
536 jclass jni_cls_iterator = (*env)->FindClass(env, "java/util/Iterator");
537 if (!jni_cls_iterator)
539 OIC_LOG(ERROR, TAG, "jni_cls_iterator is null");
540 (*env)->DeleteLocalRef(env, jni_obj_iter);
541 (*env)->DeleteLocalRef(env, jni_cls_set);
542 (*env)->ReleaseStringUTFChars(env, jni_address, address);
543 (*env)->DeleteLocalRef(env, jni_address);
547 jmethodID jni_mid_hasNext = (*env)->GetMethodID(env, jni_cls_iterator, "hasNext", "()Z");
548 if (!jni_mid_hasNext)
550 OIC_LOG(ERROR, TAG, "jni_mid_hasNext is null");
551 (*env)->DeleteLocalRef(env, jni_cls_iterator);
552 (*env)->DeleteLocalRef(env, jni_obj_iter);
553 (*env)->DeleteLocalRef(env, jni_cls_set);
554 (*env)->ReleaseStringUTFChars(env, jni_address, address);
555 (*env)->DeleteLocalRef(env, jni_address);
559 jmethodID jni_mid_next = (*env)->GetMethodID(env, jni_cls_iterator, "next",
560 "()Ljava/lang/Object;");
563 OIC_LOG(ERROR, TAG, "jni_mid_next is null");
564 (*env)->DeleteLocalRef(env, jni_cls_iterator);
565 (*env)->DeleteLocalRef(env, jni_obj_iter);
566 (*env)->DeleteLocalRef(env, jni_cls_set);
567 (*env)->ReleaseStringUTFChars(env, jni_address, address);
568 (*env)->DeleteLocalRef(env, jni_address);
572 // Iterate over the entry Set
573 while ((*env)->CallBooleanMethod(env, jni_obj_iter, jni_mid_hasNext))
575 jstring jni_str_entry = (jstring)(*env)->CallObjectMethod(env, jni_obj_iter,
579 OIC_LOG(ERROR, TAG, "jni_str_entry is null");
580 (*env)->DeleteLocalRef(env, jni_cls_iterator);
581 (*env)->DeleteLocalRef(env, jni_obj_iter);
582 (*env)->DeleteLocalRef(env, jni_cls_set);
583 (*env)->ReleaseStringUTFChars(env, jni_address, address);
584 (*env)->DeleteLocalRef(env, jni_address);
587 const char* foundAddress = (*env)->GetStringUTFChars(env, jni_str_entry, NULL);
590 OIC_LOG(ERROR, TAG, "addr is null");
591 (*env)->DeleteLocalRef(env, jni_str_entry);
592 (*env)->DeleteLocalRef(env, jni_cls_iterator);
593 (*env)->DeleteLocalRef(env, jni_obj_iter);
594 (*env)->DeleteLocalRef(env, jni_cls_set);
595 (*env)->ReleaseStringUTFChars(env, jni_address, address);
596 (*env)->DeleteLocalRef(env, jni_address);
599 OIC_LOG_V(INFO, TAG, "found last connected address [%s] from SharedPreferences",
602 if (!strcmp(foundAddress, address))
604 // if BLE address is matched each other
605 // this address will be added into auto connection list.
606 OIC_LOG(INFO, TAG, "AC list - address will be added into ACData list");
607 CAManagerAddACData(env, jni_address);
608 CAManagerSetAutoConnectionFlag(env, jni_address, false);
610 // next connection will be requested as JNI_TRUE flag
611 // after first connection
612 CALEClientSetFlagToState(env, jni_str_entry, CA_LE_AUTO_CONNECT_FLAG, JNI_TRUE);
616 OIC_LOG(INFO, TAG, "AC list - device is not matched");
619 (*env)->ReleaseStringUTFChars(env, jni_str_entry, foundAddress);
620 (*env)->DeleteLocalRef(env, jni_str_entry);
623 (*env)->DeleteLocalRef(env, jni_cls_iterator);
624 (*env)->DeleteLocalRef(env, jni_obj_iter);
625 (*env)->DeleteLocalRef(env, jni_cls_set);
626 (*env)->ReleaseStringUTFChars(env, jni_address, address);
627 (*env)->DeleteLocalRef(env, jni_address);
628 OIC_LOG(INFO, TAG, "ServicesDiscovery is successful");
632 OIC_LOG(ERROR, TAG, "ServicesDiscovery has failed");
637 * Class: org_iotivity_ca_jar_caleinterface
638 * Method: caManagerLeRemoteRssiCallback
639 * Signature: (Landroid/bluetooth/BluetoothGatt;I)V
641 JNIEXPORT void JNICALL
642 Java_org_iotivity_ca_CaLeClientInterface_caManagerLeRemoteRssiCallback(JNIEnv *env,
648 OIC_LOG_V(DEBUG, TAG, "caManagerLeRemoteRssiCallback - rssi : %d: ", rssi);
649 OIC_LOG_V(DEBUG, TAG, "caManagerLeRemoteRssiCallback - status : %d: ", status);
650 VERIFY_NON_NULL_VOID(env, TAG, "env");
651 VERIFY_NON_NULL_VOID(obj, TAG, "obj");
652 VERIFY_NON_NULL_VOID(gatt, TAG, "gatt");