modified BT on/off monitoring logic in EDR Adapter
[platform/upstream/iotivity.git] / resource / csdk / connectivity / src / bt_edr_adapter / android / caedrclient.c
1 /******************************************************************
2  *
3  * Copyright 2014 Samsung Electronics All Rights Reserved.
4  *
5  *
6  *
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
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
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.
18  *
19  ******************************************************************/
20
21 #include <stdio.h>
22 #include <string.h>
23 #include <jni.h>
24
25 #include "caedrinterface.h"
26 #include "caedrutils.h"
27 #include "caedrclient.h"
28 #include "logger.h"
29 #include "oic_malloc.h"
30 #include "oic_string.h"
31 #include "cathreadpool.h" /* for thread pool */
32 #include "camutex.h"
33 #include "uarraylist.h"
34 #include "caadapterutils.h"
35 #include "caremotehandler.h"
36
37 #define TAG PCF("OIC_CA_EDR_CLIENT")
38
39 static const char METHODID_CONTEXTNONPARAM[] = "()Landroid/content/Context;";
40 static const char METHODID_OBJECTNONPARAM[] = "()Landroid/bluetooth/BluetoothAdapter;";
41 static const char METHODID_OUTPUTNONPARAM[] = "()Ljava/io/OutputStream;";
42 static const char METHODID_STRINGNONPARAM[] = "()Ljava/lang/String;";
43 static const char METHODID_BT_DEVICEPARAM[] =
44         "(Ljava/lang/String;)Landroid/bluetooth/BluetoothDevice;";
45 static const char CLASSPATH_BT_ADPATER[] = "android/bluetooth/BluetoothAdapter";
46 static const char CLASSPATH_BT_DEVICE[] = "android/bluetooth/BluetoothDevice";
47 static const char CLASSPATH_BT_INTERFACE[] = "org/iotivity/ca/CaEdrInterface";
48 static const char CLASSPATH_BT_SOCKET[] = "android/bluetooth/BluetoothSocket";
49 static const char CLASSPATH_BT_UUID[] = "java/util/UUID";
50 static const char CLASSPATH_CONTEXT[] = "android/content/Context";
51 static const char CLASSPATH_OUTPUT[] = "java/io/OutputStream";
52
53 static JavaVM *g_jvm;
54 static jobject g_context;
55
56 /**
57  * @var g_mutexStateList
58  * @brief Mutex to synchronize device state list
59  */
60 static ca_mutex g_mutexStateList = NULL;
61
62 /**
63  * @var g_mutexObjectList
64  * @brief Mutex to synchronize device object list
65  */
66 static ca_mutex g_mutexObjectList = NULL;
67
68 /**
69  * @var g_edrErrorHandler
70  * @brief Error callback to update error in EDR
71  */
72 static CAEDRErrorHandleCallback g_edrErrorHandler = NULL;
73
74 typedef struct send_data
75 {
76     char* address;
77     char* data;
78     uint32_t id;
79 } data_t;
80
81 /**
82  @brief Thread context information for unicast, multicast and secured unicast server
83  */
84 typedef struct
85 {
86     bool *stopFlag;
87     CAAdapterServerType_t type;
88 } CAAdapterReceiveThreadContext_t;
89
90 typedef struct
91 {
92     bool *stopFlag;
93 } CAAdapterAcceptThreadContext_t;
94
95 /**
96  * implement for BT-EDR adapter common method
97  */
98 CAResult_t CAEDRGetInterfaceInformation(CAEndpoint_t **info)
99 {
100     OIC_LOG(DEBUG, TAG, "IN - CAEDRGetInterfaceInformation");
101
102     if (!info)
103     {
104         OIC_LOG(ERROR, TAG, "endpoint info is null");
105         return CA_STATUS_INVALID_PARAM;
106     }
107
108     char *macAddress = NULL;
109     CAResult_t ret = CAEDRGetInterfaceInfo(&macAddress);
110     if (CA_STATUS_OK != ret)
111     {
112         OIC_LOG_V(ERROR, TAG, "Failed to get interface info [%d]", ret);
113         OICFree(macAddress);
114         return ret;
115     }
116
117     if (!macAddress)
118     {
119         OIC_LOG(ERROR, TAG, "mac address is null");
120         return CA_STATUS_FAILED;
121     }
122     OIC_LOG_V(DEBUG, TAG, "address : %s", macAddress);
123
124     // Create local endpoint using util function
125     CAEndpoint_t *endpoint = CACreateEndpointObject(CA_DEFAULT_FLAGS, CA_ADAPTER_RFCOMM_BTEDR,
126                                                     macAddress, 0);
127     if (NULL == endpoint)
128     {
129         OIC_LOG(ERROR, TAG, "Failed to create Local Endpoint!");
130         OICFree(macAddress);
131         return CA_STATUS_FAILED;
132     }
133
134     // copy unicast server information
135     int32_t netInfoSize = 1;
136     CAEndpoint_t *netInfo = (CAEndpoint_t *)OICMalloc(sizeof(CAEndpoint_t) * netInfoSize);
137     if (NULL == netInfo)
138     {
139         OIC_LOG(ERROR, TAG, "Invalid input..");
140         OICFree(macAddress);
141         CAFreeEndpoint(endpoint);
142         return CA_MEMORY_ALLOC_FAILED;
143     }
144     *netInfo = *endpoint;
145     *info = netInfo;
146
147     OICFree(macAddress);
148     CAFreeEndpoint(endpoint);
149
150     OIC_LOG(DEBUG, TAG, "OUT - CAEDRGetInterfaceInformation");
151     return CA_STATUS_OK;
152 }
153
154 void CAEDRClientTerminate()
155 {
156     OIC_LOG(DEBUG, TAG, "IN");
157     CAEDRTerminate();
158     OIC_LOG(DEBUG, TAG, "OUT");
159 }
160
161 CAResult_t CAEDRManagerReadData()
162 {
163     OIC_LOG(DEBUG, TAG, "IN");
164
165     OIC_LOG(DEBUG, TAG, "OUT");
166     return CA_NOT_SUPPORTED;
167 }
168
169 CAResult_t CAEDRClientSendUnicastData(const char *remoteAddress, const uint8_t *data,
170                                       uint32_t dataLength)
171 {
172     VERIFY_NON_NULL(remoteAddress, TAG, "remoteAddress is null");
173     VERIFY_NON_NULL(data, TAG, "data is null");
174
175     CAResult_t result = CAEDRSendUnicastMessage(remoteAddress, data, dataLength);
176     return result;
177 }
178
179 CAResult_t CAEDRClientSendMulticastData(const uint8_t *data, uint32_t dataLength)
180 {
181     VERIFY_NON_NULL(data, TAG, "data is null");
182
183     CAResult_t result = CAEDRSendMulticastMessage(data, dataLength);
184     return result;
185 }
186
187 // It will be updated when android EDR support is added
188 void CAEDRClientUnsetCallbacks()
189 {
190     OIC_LOG(DEBUG, TAG, "IN");
191
192     OIC_LOG(DEBUG, TAG, "OUT");
193 }
194
195 // It will be updated when android EDR support is added
196 void CAEDRClientDisconnectAll()
197 {
198     OIC_LOG(DEBUG, TAG, "IN");
199
200     OIC_LOG(DEBUG, TAG, "OUT");
201 }
202
203 CAResult_t CAEDRGetAdapterEnableState(bool *state)
204 {
205     VERIFY_NON_NULL(state, TAG, "state is null");
206
207     if (!g_jvm)
208     {
209         OIC_LOG(ERROR, TAG, "g_jvm is null");
210         return CA_STATUS_INVALID_PARAM;
211     }
212     bool isAttached = false;
213     JNIEnv* env;
214     jint res = (*g_jvm)->GetEnv(g_jvm, (void**) &env, JNI_VERSION_1_6);
215     if (JNI_OK != res)
216     {
217         OIC_LOG(DEBUG, TAG, "CAEDRGetAdapterEnableState - Could not get JNIEnv pointer");
218         res = (*g_jvm)->AttachCurrentThread(g_jvm, &env, NULL);
219
220         if (JNI_OK != res)
221         {
222             OIC_LOG(ERROR, TAG, "AttachCurrentThread failed");
223             return CA_STATUS_INVALID_PARAM;
224         }
225         isAttached = true;
226     }
227
228     *state = false;
229     jboolean ret = CAEDRNativeIsEnableBTAdapter(env);
230     if (ret)
231     {
232         *state = true;
233     }
234
235     if (isAttached)
236     {
237         (*g_jvm)->DetachCurrentThread(g_jvm);
238     }
239
240     return CA_STATUS_OK;
241 }
242
243 void CAEDRJniInitContext()
244 {
245     OIC_LOG(DEBUG, TAG, "CAEDRJniInitContext");
246
247     g_context = (jobject) CANativeJNIGetContext();
248 }
249
250 CAResult_t CAEDRCreateJNIInterfaceObject(jobject context)
251 {
252     JNIEnv* env;
253     OIC_LOG(DEBUG, TAG, "CAEDRCreateJNIInterfaceObject");
254
255     if ((*g_jvm)->GetEnv(g_jvm, (void**) &env, JNI_VERSION_1_6) != JNI_OK)
256     {
257         OIC_LOG(ERROR, TAG, "Could not get JNIEnv pointer");
258         return CA_STATUS_FAILED;
259     }
260
261     //getApplicationContext
262     jclass contextClass = (*env)->FindClass(env, CLASSPATH_CONTEXT);
263     if (!contextClass)
264     {
265         OIC_LOG(ERROR, TAG, "Could not get context object class");
266         return CA_STATUS_FAILED;
267     }
268
269     jmethodID getApplicationContextMethod = (*env)->GetMethodID(env, contextClass,
270                                                                 "getApplicationContext",
271                                                                 METHODID_CONTEXTNONPARAM);
272     if (!getApplicationContextMethod)
273     {
274         OIC_LOG(ERROR, TAG, "Could not get getApplicationContext method");
275         return CA_STATUS_FAILED;
276     }
277
278     //Create EDRJniInterface instance
279     jclass EDRJniInterface = (*env)->FindClass(env, CLASSPATH_BT_INTERFACE);
280     if (!EDRJniInterface)
281     {
282         OIC_LOG(ERROR, TAG, "Could not get CaEdrInterface class");
283         return CA_STATUS_FAILED;
284     }
285
286     jmethodID EDRInterfaceConstructorMethod = (*env)->GetMethodID(env, EDRJniInterface, "<init>",
287                                                                   "(Landroid/content/Context;)V");
288     if (!EDRInterfaceConstructorMethod)
289     {
290         OIC_LOG(ERROR, TAG, "Could not get CaEdrInterface constructor method");
291         return CA_STATUS_FAILED;
292     }
293
294     (*env)->NewObject(env, EDRJniInterface, EDRInterfaceConstructorMethod, context);
295     OIC_LOG(DEBUG, TAG, "NewObject Success");
296
297     return CA_STATUS_OK;
298 }
299
300 static void CAEDRDestroyMutex()
301 {
302     if (g_mutexStateList)
303     {
304         ca_mutex_free(g_mutexStateList);
305         g_mutexStateList = NULL;
306     }
307
308     if (g_mutexObjectList)
309     {
310         ca_mutex_free(g_mutexObjectList);
311         g_mutexObjectList = NULL;
312     }
313 }
314
315 static CAResult_t CAEDRCreateMutex()
316 {
317     g_mutexStateList = ca_mutex_new();
318     if (!g_mutexStateList)
319     {
320         OIC_LOG(ERROR, TAG, "Failed to created mutex!");
321
322         CAEDRDestroyMutex();
323         return CA_STATUS_FAILED;
324     }
325
326     g_mutexObjectList = ca_mutex_new();
327     if (!g_mutexObjectList)
328     {
329         OIC_LOG(ERROR, TAG, "Failed to created mutex!");
330
331         CAEDRDestroyMutex();
332         return CA_STATUS_FAILED;
333     }
334
335     return CA_STATUS_OK;
336 }
337
338 CAResult_t CAEDRInitialize()
339 {
340     OIC_LOG(DEBUG, TAG, "CAEDRInitialize");
341
342     CAEDRCoreJniInit();
343
344     CAEDRJniInitContext();
345
346     // init mutex
347     CAResult_t result = CAEDRCreateMutex();
348     if(CA_STATUS_OK != result)
349     {
350         OIC_LOG(ERROR, TAG, "CAEDRInitialize - Could not create mutex");
351         return result;
352     }
353
354     bool isAttached = false;
355     JNIEnv* env;
356     jint res = (*g_jvm)->GetEnv(g_jvm, (void**) &env, JNI_VERSION_1_6);
357     if (JNI_OK != res)
358     {
359         OIC_LOG(DEBUG, TAG, "CAEDRInitialize - Could not get JNIEnv pointer");
360         res = (*g_jvm)->AttachCurrentThread(g_jvm, &env, NULL);
361
362         if (JNI_OK != res)
363         {
364             OIC_LOG(ERROR, TAG, "AttachCurrentThread failed");
365             return CA_STATUS_NOT_INITIALIZED;
366         }
367         isAttached = true;
368     }
369     jstring jni_address = CAEDRNativeGetLocalDeviceAddress(env);
370     if (jni_address)
371     {
372         const char* localAddress = (*env)->GetStringUTFChars(env, jni_address, NULL);
373         OIC_LOG_V(DEBUG, TAG, "My BT Address is %s", localAddress);
374         (*env)->ReleaseStringUTFChars(env, jni_address, localAddress);
375     }
376     (*env)->DeleteLocalRef(env, jni_address);
377
378     ca_mutex_lock(g_mutexStateList);
379     CAEDRNativeCreateDeviceStateList();
380     ca_mutex_unlock(g_mutexStateList);
381
382     ca_mutex_lock(g_mutexObjectList);
383     CAEDRNativeCreateDeviceSocketList();
384     ca_mutex_unlock(g_mutexObjectList);
385
386     if (isAttached)
387     {
388         (*g_jvm)->DetachCurrentThread(g_jvm);
389     }
390
391     if (g_context)
392     {
393         CAEDRCreateJNIInterfaceObject(g_context); /* create java CaEdrInterface instance*/
394     }
395
396     OIC_LOG(DEBUG, TAG, "OUT");
397
398     return result;
399 }
400
401 void CAEDRTerminate()
402 {
403     OIC_LOG(DEBUG, TAG, "CAEDRTerminate");
404
405     bool isAttached = false;
406     JNIEnv* env;
407     jint res = (*g_jvm)->GetEnv(g_jvm, (void**) &env, JNI_VERSION_1_6);
408     if (JNI_OK != res)
409     {
410         OIC_LOG(DEBUG, TAG, "CAEDRTerminate - Could not get JNIEnv pointer");
411         res = (*g_jvm)->AttachCurrentThread(g_jvm, &env, NULL);
412
413         if (JNI_OK != res)
414         {
415             OIC_LOG(ERROR, TAG, "AttachCurrentThread failed");
416             return;
417         }
418         isAttached = true;
419     }
420
421     if (isAttached)
422     {
423         (*g_jvm)->DetachCurrentThread(g_jvm);
424     }
425
426     if (g_context)
427     {
428         (*env)->DeleteGlobalRef(env, g_context);
429     }
430
431     CAEDRNativeSocketCloseToAll(env);
432
433     // delete mutex
434     CAEDRDestroyMutex();
435
436     CAEDRNativeRemoveAllDeviceState();
437     CAEDRNativeRemoveAllDeviceSocket(env);
438     CAEDRDestroyJniInterface();
439 }
440
441 CAResult_t CAEDRDestroyJniInterface()
442 {
443     OIC_LOG(DEBUG, TAG, "CAEDRDestroyJniInterface");
444
445     if (!g_jvm)
446     {
447         OIC_LOG(ERROR, TAG, "g_jvm is null");
448         return CA_STATUS_FAILED;
449     }
450
451     bool isAttached = false;
452     JNIEnv* env;
453     jint res = (*g_jvm)->GetEnv(g_jvm, (void**) &env, JNI_VERSION_1_6);
454     if (JNI_OK != res)
455     {
456         OIC_LOG(INFO, TAG, "Could not get JNIEnv pointer");
457         res = (*g_jvm)->AttachCurrentThread(g_jvm, &env, NULL);
458
459         if (JNI_OK != res)
460         {
461             OIC_LOG(ERROR, TAG, "AttachCurrentThread has failed");
462             return CA_STATUS_FAILED;
463         }
464         isAttached = true;
465     }
466
467     jclass jni_EDRJniInterface = (*env)->FindClass(env, CLASSPATH_BT_INTERFACE);
468     if (!jni_EDRJniInterface)
469     {
470         OIC_LOG(ERROR, TAG, "Could not get CaEdrInterface class");
471         goto error_exit;
472     }
473
474     jmethodID jni_EDRInterfaceDestroyMethod = (*env)->GetStaticMethodID(env, jni_EDRJniInterface,
475                                                                         "destroyEdrInterface",
476                                                                         "()V");
477     if (!jni_EDRInterfaceDestroyMethod)
478     {
479         OIC_LOG(ERROR, TAG, "Could not get CaEdrInterface destroy method");
480         goto error_exit;
481     }
482
483     (*env)->CallStaticVoidMethod(env, jni_EDRJniInterface, jni_EDRInterfaceDestroyMethod);
484
485     if ((*env)->ExceptionCheck(env))
486     {
487         OIC_LOG(ERROR, TAG, "destroyEdrInterface has failed");
488         (*env)->ExceptionDescribe(env);
489         (*env)->ExceptionClear(env);
490         goto error_exit;
491     }
492
493     OIC_LOG(DEBUG, TAG, "Destroy instance for CaEdrInterface");
494
495     if (isAttached)
496     {
497         (*g_jvm)->DetachCurrentThread(g_jvm);
498     }
499
500     return CA_STATUS_OK;
501
502 error_exit:
503
504     if (isAttached)
505     {
506         (*g_jvm)->DetachCurrentThread(g_jvm);
507     }
508
509     return CA_STATUS_FAILED;
510 }
511
512 void CAEDRCoreJniInit()
513 {
514     OIC_LOG(DEBUG, TAG, "CAEdrClientJniInit");
515     g_jvm = (JavaVM*) CANativeJNIGetJavaVM();
516 }
517
518 CAResult_t CAEDRSendUnicastMessage(const char* address, const uint8_t* data, uint32_t dataLen)
519 {
520     VERIFY_NON_NULL(address, TAG, "address is null");
521     VERIFY_NON_NULL(data, TAG, "data is null");
522
523     CAResult_t result = CAEDRSendUnicastMessageImpl(address, data, dataLen);
524     return result;
525 }
526
527 CAResult_t CAEDRSendMulticastMessage(const uint8_t* data, uint32_t dataLen)
528 {
529     VERIFY_NON_NULL(data, TAG, "data is null");
530
531     bool isAttached = false;
532     JNIEnv* env;
533     jint res = (*g_jvm)->GetEnv(g_jvm, (void**) &env, JNI_VERSION_1_6);
534     if (JNI_OK != res)
535     {
536         OIC_LOG(DEBUG, TAG, "CAEDRSendMulticastMessage - Could not get JNIEnv pointer");
537         res = (*g_jvm)->AttachCurrentThread(g_jvm, &env, NULL);
538
539         if (JNI_OK != res)
540         {
541             OIC_LOG(ERROR, TAG, "AttachCurrentThread failed");
542             return CA_STATUS_INVALID_PARAM;
543         }
544         isAttached = true;
545     }
546
547     CAResult_t result = CAEDRSendMulticastMessageImpl(env, data, dataLen);
548     if(CA_STATUS_OK != result)
549     {
550         OIC_LOG(ERROR, TAG, "CAEDRSendMulticastMessage - could not send multicast message");
551         return result;
552     }
553
554     if (isAttached)
555     {
556         OIC_LOG(DEBUG, TAG, "DetachCurrentThread");
557         (*g_jvm)->DetachCurrentThread(g_jvm);
558     }
559
560     OIC_LOG(DEBUG, TAG, "OUT - CAEDRSendMulticastMessage");
561     return CA_STATUS_OK;
562 }
563
564 CAResult_t CAEDRGetInterfaceInfo(char **address)
565 {
566     CAEDRGetLocalAddress(address);
567     return CA_STATUS_OK;
568 }
569
570 void CAEDRGetLocalAddress(char **address)
571 {
572     bool isAttached = false;
573     JNIEnv* env;
574     jint res = (*g_jvm)->GetEnv(g_jvm, (void**) &env, JNI_VERSION_1_6);
575     if (JNI_OK != res)
576     {
577         OIC_LOG(DEBUG, TAG, "CAEDRGetLocalAddress - Could not get JNIEnv pointer");
578         res = (*g_jvm)->AttachCurrentThread(g_jvm, &env, NULL);
579         if (JNI_OK != res)
580         {
581             OIC_LOG(ERROR, TAG, "AttachCurrentThread failed");
582             return;
583         }
584         isAttached = true;
585     }
586
587     jstring jni_address = CAEDRNativeGetLocalDeviceAddress(env);
588     if (jni_address)
589     {
590         const char* localAddress = (*env)->GetStringUTFChars(env, jni_address, NULL);
591         *address = OICStrdup(localAddress);
592         if (*address == NULL)
593         {
594             if (isAttached)
595             {
596                 (*g_jvm)->DetachCurrentThread(g_jvm);
597             }
598             (*env)->ReleaseStringUTFChars(env, jni_address, localAddress);
599             (*env)->DeleteLocalRef(env, jni_address);
600             return;
601         }
602
603         (*env)->ReleaseStringUTFChars(env, jni_address, localAddress);
604         (*env)->DeleteLocalRef(env, jni_address);
605     }
606
607     OIC_LOG_V(DEBUG, TAG, "Local Address : %s", *address);
608     if (isAttached)
609     {
610         (*g_jvm)->DetachCurrentThread(g_jvm);
611     }
612 }
613
614 CAResult_t CAEDRSendUnicastMessageImpl(const char* address, const uint8_t* data, uint32_t dataLen)
615 {
616     VERIFY_NON_NULL(address, TAG, "address is null");
617     VERIFY_NON_NULL(data, TAG, "data is null");
618
619     bool isAttached = false;
620     JNIEnv* env;
621     jint res = (*g_jvm)->GetEnv(g_jvm, (void**) &env, JNI_VERSION_1_6);
622     if (JNI_OK != res)
623     {
624         OIC_LOG(DEBUG, TAG, "CAEDRSendUnicastMessageImpl - Could not get JNIEnv pointer");
625         res = (*g_jvm)->AttachCurrentThread(g_jvm, &env, NULL);
626         if (JNI_OK != res)
627         {
628             OIC_LOG(ERROR, TAG, "AttachCurrentThread failed");
629             return CA_STATUS_INVALID_PARAM;
630         }
631         isAttached = true;
632     }
633
634     OIC_LOG(DEBUG, TAG, "set byteArray for data");
635
636     // get bonded device list
637     jobjectArray jni_arrayPairedDevices = CAEDRNativeGetBondedDevices(env);
638     if (!jni_arrayPairedDevices)
639     {
640         OIC_LOG(ERROR, TAG, "jni_arrayPairedDevices is empty");
641         if (isAttached)
642         {
643             (*g_jvm)->DetachCurrentThread(g_jvm);
644         }
645         return CA_STATUS_INVALID_PARAM;
646     }
647     // Get information from array of devices
648     jclass jni_cid_BTDevice = (*env)->FindClass(env, CLASSPATH_BT_DEVICE);
649     jmethodID j_mid_getName = (*env)->GetMethodID(env, jni_cid_BTDevice, "getName",
650                                                   METHODID_STRINGNONPARAM);
651     jmethodID j_mid_getAddress = (*env)->GetMethodID(env, jni_cid_BTDevice, "getAddress",
652                                                      METHODID_STRINGNONPARAM);
653
654     jsize length = (*env)->GetArrayLength(env, jni_arrayPairedDevices);
655     for (jsize i = 0; i < length; i++)
656     {
657         OIC_LOG(DEBUG, TAG, "start to check device");
658         // get name, address from BT device
659         jobject j_obj_device = (*env)->GetObjectArrayElement(env, jni_arrayPairedDevices, i);
660         jstring j_str_name = (*env)->CallObjectMethod(env, j_obj_device, j_mid_getName);
661
662         if (j_str_name)
663         {
664             const char * name = (*env)->GetStringUTFChars(env, j_str_name, NULL);
665             OIC_LOG_V(DEBUG, TAG, "device name is %s", name);
666             (*env)->ReleaseStringUTFChars(env, j_str_name, name);
667             (*env)->DeleteLocalRef(env, j_str_name);
668         }
669
670         jstring j_str_address = (*env)->CallObjectMethod(env, j_obj_device, j_mid_getAddress);
671         const char * remoteAddress = (*env)->GetStringUTFChars(env, j_str_address, NULL);
672         (*env)->DeleteLocalRef(env, j_obj_device);
673         if (!remoteAddress)
674         {
675             OIC_LOG(ERROR, TAG, "remoteAddress is null");
676             if (isAttached)
677             {
678                 (*g_jvm)->DetachCurrentThread(g_jvm);
679             }
680
681             (*env)->DeleteLocalRef(env, j_str_address);
682             (*env)->DeleteLocalRef(env, jni_arrayPairedDevices);
683             (*env)->DeleteLocalRef(env, jni_cid_BTDevice);
684             return CA_STATUS_INVALID_PARAM;
685         }
686         OIC_LOG_V(DEBUG, TAG, "device address is %s", remoteAddress);
687
688         // find address
689         if (!strcmp(remoteAddress, address))
690         {
691             CAResult_t res = CAEDRNativeSendData(env, remoteAddress, data, dataLen);
692             (*env)->ReleaseStringUTFChars(env, j_str_address, remoteAddress);
693             (*env)->DeleteLocalRef(env, j_str_address);
694             if (CA_STATUS_OK != res)
695             {
696                 (*env)->DeleteLocalRef(env, jni_arrayPairedDevices);
697                 (*env)->DeleteLocalRef(env, jni_cid_BTDevice);
698                 return res;
699             }
700             break;
701         }
702         (*env)->ReleaseStringUTFChars(env, j_str_address, remoteAddress);
703         (*env)->DeleteLocalRef(env, j_str_address);
704     }
705
706     (*env)->DeleteLocalRef(env, jni_arrayPairedDevices);
707     (*env)->DeleteLocalRef(env, jni_cid_BTDevice);
708
709     if (isAttached)
710     {
711         (*g_jvm)->DetachCurrentThread(g_jvm);
712     }
713
714     return CA_STATUS_OK;
715 }
716
717 CAResult_t CAEDRSendMulticastMessageImpl(JNIEnv *env, const uint8_t* data, uint32_t dataLen)
718 {
719     VERIFY_NON_NULL(env, TAG, "env is null");
720     VERIFY_NON_NULL(data, TAG, "data is null");
721
722     // get bonded device list
723     jobjectArray jni_arrayPairedDevices = CAEDRNativeGetBondedDevices(env);
724     if (!jni_arrayPairedDevices)
725     {
726         OIC_LOG(ERROR, TAG, "jni_arrayPairedDevices is empty");
727         return CA_STATUS_INVALID_PARAM;
728     }
729     // Get information from array of devices
730     jclass jni_cid_BTDevice = (*env)->FindClass(env, CLASSPATH_BT_DEVICE);
731     jmethodID j_mid_getName = (*env)->GetMethodID(env, jni_cid_BTDevice, "getName",
732                                                   METHODID_STRINGNONPARAM);
733     jmethodID j_mid_getAddress = (*env)->GetMethodID(env, jni_cid_BTDevice, "getAddress",
734                                                      METHODID_STRINGNONPARAM);
735
736     jsize length = (*env)->GetArrayLength(env, jni_arrayPairedDevices);
737     for (jsize i = 0; i < length; i++)
738     {
739         // get name, address from BT device
740         jobject j_obj_device = (*env)->GetObjectArrayElement(env, jni_arrayPairedDevices, i);
741         jstring j_str_name = (*env)->CallObjectMethod(env, j_obj_device, j_mid_getName);
742         jstring j_str_address = (*env)->CallObjectMethod(env, j_obj_device, j_mid_getAddress);
743
744         if (j_str_name && j_str_address)
745         {
746             const char * name = (*env)->GetStringUTFChars(env, j_str_name, NULL);
747             const char * remoteAddress = (*env)->GetStringUTFChars(env, j_str_address, NULL);
748             if (name && remoteAddress)
749             {
750                 OIC_LOG_V(DEBUG, TAG, "device name is %s, address is %s", name, remoteAddress);
751
752                 CAResult_t res = CAEDRNativeSendData(env, remoteAddress, data, dataLen);
753                 if (CA_STATUS_OK != res)
754                 {
755                     OIC_LOG_V(ERROR, TAG, "Failed to send multicast message to : %s",
756                               remoteAddress);
757                     g_edrErrorHandler(remoteAddress, data, dataLen, res);
758                 }
759             }
760             (*env)->ReleaseStringUTFChars(env, j_str_name, name);
761             (*env)->ReleaseStringUTFChars(env, j_str_address, remoteAddress);
762         }
763
764         (*env)->DeleteLocalRef(env, j_obj_device);
765         (*env)->DeleteLocalRef(env, j_str_name);
766         (*env)->DeleteLocalRef(env, j_str_address);
767     }
768
769     (*env)->DeleteLocalRef(env, jni_arrayPairedDevices);
770     (*env)->DeleteLocalRef(env, jni_cid_BTDevice);
771
772     return CA_STATUS_OK;
773 }
774
775 CAResult_t CAEDRNativeSendData(JNIEnv *env, const char *address, const uint8_t *data,
776                                uint32_t dataLength)
777 {
778     VERIFY_NON_NULL(env, TAG, "env is null");
779     VERIFY_NON_NULL(address, TAG, "address is null");
780     VERIFY_NON_NULL(data, TAG, "data is null");
781
782     if (!CAEDRNativeIsEnableBTAdapter(env))
783     {
784         OIC_LOG(INFO, TAG, "BT adapter is not enabled");
785         return CA_ADAPTER_NOT_ENABLED;
786     }
787
788     if (STATE_DISCONNECTED == CAEDRIsConnectedDevice(address))
789     {
790         // connect before send data
791         OIC_LOG_V(DEBUG, TAG, "try to connect with [%s] before sending data", address);
792
793         CAResult_t res = CAEDRNativeConnect(env, address);
794         if (CA_STATUS_OK != res)
795         {
796             return res;
797         }
798     }
799
800     if (STATE_CONNECTED == CAEDRIsConnectedDevice(address))
801     {
802         if (!((*env)->ExceptionCheck(env)))
803         {
804             jclass jni_cid_BTsocket = (*env)->FindClass(env, CLASSPATH_BT_SOCKET);
805             if (!jni_cid_BTsocket)
806             {
807                 OIC_LOG(ERROR, TAG, "jni_cid_BTsocket is null");
808                 return CA_STATUS_FAILED;
809             }
810
811             jmethodID jni_mid_getOutputStream = (*env)->GetMethodID(env, jni_cid_BTsocket,
812                                                                     "getOutputStream",
813                                                                     METHODID_OUTPUTNONPARAM);
814             if (!jni_mid_getOutputStream)
815             {
816                 OIC_LOG(ERROR, TAG, "jni_mid_getOutputStream is null");
817                 (*env)->DeleteLocalRef(env, jni_cid_BTsocket);
818                 return CA_STATUS_FAILED;
819             }
820
821             OIC_LOG(DEBUG, TAG, "Get MethodID for i/o stream");
822
823             jobject jni_obj_socket = CAEDRNativeGetDeviceSocketBaseAddr(env, address);
824             if (!jni_obj_socket)
825             {
826                 OIC_LOG(ERROR, TAG, "jni_socket is not available");
827                 (*env)->DeleteLocalRef(env, jni_cid_BTsocket);
828                 return CA_STATUS_FAILED;
829             }
830
831             jobject jni_obj_outputStream = (*env)->CallObjectMethod(env, jni_obj_socket,
832                                                                     jni_mid_getOutputStream);
833             if (!jni_obj_outputStream)
834             {
835                 OIC_LOG(ERROR, TAG, "jni_obj_outputStream is null");
836                 (*env)->DeleteLocalRef(env, jni_cid_BTsocket);
837                 return CA_STATUS_FAILED;
838             }
839
840             OIC_LOG(DEBUG, TAG, "ready outputStream..");
841
842             jclass jni_cid_OutputStream = (*env)->FindClass(env, CLASSPATH_OUTPUT);
843             if (!jni_cid_OutputStream)
844             {
845                 OIC_LOG(ERROR, TAG, "jni_cid_OutputStream is null");
846                 (*env)->DeleteLocalRef(env, jni_cid_BTsocket);
847                 (*env)->DeleteLocalRef(env, jni_obj_outputStream);
848                 return CA_STATUS_FAILED;
849             }
850
851             jmethodID jni_mid_write = (*env)->GetMethodID(env, jni_cid_OutputStream, "write",
852                                                           "([BII)V");
853             if (!jni_mid_write)
854             {
855                 OIC_LOG(ERROR, TAG, "jni_mid_write is null");
856                 (*env)->DeleteLocalRef(env, jni_cid_BTsocket);
857                 (*env)->DeleteLocalRef(env, jni_obj_outputStream);
858                 (*env)->DeleteLocalRef(env, jni_cid_OutputStream);
859                 return CA_STATUS_FAILED;
860             }
861
862             jbyteArray jbuf = (*env)->NewByteArray(env, dataLength);
863             (*env)->SetByteArrayRegion(env, jbuf, 0, dataLength, (jbyte*) data);
864
865             (*env)->CallVoidMethod(env, jni_obj_outputStream, jni_mid_write, jbuf, (jint) 0,
866                                    (jint) dataLength);
867
868             (*env)->DeleteLocalRef(env, jni_cid_BTsocket);
869             (*env)->DeleteLocalRef(env, jni_obj_outputStream);
870             (*env)->DeleteLocalRef(env, jni_cid_OutputStream);
871             (*env)->DeleteLocalRef(env, jbuf);
872
873             if ((*env)->ExceptionCheck(env))
874             {
875                 OIC_LOG(ERROR, TAG, "Failed to write data in outputStram");
876                 (*env)->ExceptionDescribe(env);
877                 (*env)->ExceptionClear(env);
878                 return CA_STATUS_FAILED;
879             }
880
881             OIC_LOG_V(INFO, TAG, "EDR sendTo is successful: %u bytes, to %s",
882                       dataLength, address);
883         }
884         else
885         {
886             (*env)->ExceptionDescribe(env);
887             (*env)->ExceptionClear(env);
888             OIC_LOG(ERROR, TAG, "error!!");
889             return CA_STATUS_FAILED;
890         }
891     }
892     else
893     {
894         OIC_LOG(DEBUG, TAG, "BT connection is not completed!!");
895     }
896
897     return CA_STATUS_OK;
898 }
899
900 CAResult_t CAEDRNativeConnect(JNIEnv *env, const char *address)
901 {
902     VERIFY_NON_NULL(address, TAG, "address is null");
903
904     if (!CAEDRNativeIsEnableBTAdapter(env))
905     {
906         OIC_LOG(INFO, TAG, "BT adapter is not enabled");
907         return CA_ADAPTER_NOT_ENABLED;
908     }
909
910     jclass jni_cid_BTAdapter = (*env)->FindClass(env, CLASSPATH_BT_ADPATER);
911     if (!jni_cid_BTAdapter)
912     {
913         OIC_LOG(ERROR, TAG, "jni_cid_BTAdapter is null");
914         return CA_STATUS_FAILED;
915     }
916
917     // get BTadpater
918     jmethodID jni_mid_getDefaultAdapter = (*env)->GetStaticMethodID(env, jni_cid_BTAdapter,
919                                                                     "getDefaultAdapter",
920                                                                     METHODID_OBJECTNONPARAM);
921     if (!jni_mid_getDefaultAdapter)
922     {
923         OIC_LOG(ERROR, TAG, "jni_mid_getDefaultAdapter is null");
924         (*env)->DeleteLocalRef(env, jni_cid_BTAdapter);
925         return CA_STATUS_FAILED;
926     }
927
928     jobject jni_obj_BTAdapter = (*env)->CallStaticObjectMethod(env, jni_cid_BTAdapter,
929                                                                jni_mid_getDefaultAdapter);
930     if (!jni_obj_BTAdapter)
931     {
932         OIC_LOG(ERROR, TAG, "jni_obj_BTAdapter is null");
933         (*env)->DeleteLocalRef(env, jni_cid_BTAdapter);
934         return CA_STATUS_FAILED;
935     }
936
937     // get remote bluetooth device
938     jmethodID jni_mid_getRemoteDevice = (*env)->GetMethodID(env, jni_cid_BTAdapter,
939                                                             "getRemoteDevice",
940                                                             METHODID_BT_DEVICEPARAM);
941     (*env)->DeleteLocalRef(env, jni_cid_BTAdapter);
942     if (!jni_mid_getRemoteDevice)
943     {
944         OIC_LOG(ERROR, TAG, "jni_mid_getRemoteDevice is null");
945         (*env)->DeleteLocalRef(env, jni_obj_BTAdapter);
946         return CA_STATUS_FAILED;
947     }
948
949     jstring jni_address = (*env)->NewStringUTF(env, address);
950     jobject jni_obj_remoteBTDevice = (*env)->CallObjectMethod(env, jni_obj_BTAdapter,
951                                                               jni_mid_getRemoteDevice, jni_address);
952     (*env)->DeleteLocalRef(env, jni_address);
953     (*env)->DeleteLocalRef(env, jni_obj_BTAdapter);
954     if (!jni_obj_remoteBTDevice)
955     {
956         OIC_LOG(ERROR, TAG, "jni_obj_remoteBTDevice is null");
957         return CA_STATUS_FAILED;
958     }
959
960     // get create Rfcomm Socket method ID
961     jclass jni_cid_BluetoothDevice = (*env)->FindClass(env, CLASSPATH_BT_DEVICE);
962     if (!jni_cid_BluetoothDevice)
963     {
964         OIC_LOG(ERROR, TAG, "jni_cid_BluetoothDevice is null");
965         (*env)->DeleteLocalRef(env, jni_obj_remoteBTDevice);
966         return CA_STATUS_FAILED;
967     }
968
969     jmethodID jni_mid_createSocket = (*env)->GetMethodID(
970             env, jni_cid_BluetoothDevice, "createInsecureRfcommSocketToServiceRecord",
971             "(Ljava/util/UUID;)Landroid/bluetooth/BluetoothSocket;");
972     (*env)->DeleteLocalRef(env, jni_cid_BluetoothDevice);
973     if (!jni_mid_createSocket)
974     {
975         OIC_LOG(ERROR, TAG, "jni_mid_createSocket is null");
976         (*env)->DeleteLocalRef(env, jni_obj_remoteBTDevice);
977         return CA_STATUS_FAILED;
978     }
979
980     // setting UUID
981     jclass jni_cid_uuid = (*env)->FindClass(env, CLASSPATH_BT_UUID);
982     if (!jni_cid_uuid)
983     {
984         OIC_LOG(ERROR, TAG, "jni_cid_uuid is null");
985         (*env)->DeleteLocalRef(env, jni_obj_remoteBTDevice);
986         return CA_STATUS_FAILED;
987     }
988
989     jmethodID jni_mid_fromString = (*env)->GetStaticMethodID(
990             env, jni_cid_uuid, "fromString", "(Ljava/lang/String;)Ljava/util/UUID;");
991     if (!jni_mid_fromString)
992     {
993         OIC_LOG(ERROR, TAG, "jni_mid_fromString is null");
994         (*env)->DeleteLocalRef(env, jni_cid_uuid);
995         (*env)->DeleteLocalRef(env, jni_obj_remoteBTDevice);
996         return CA_STATUS_FAILED;
997     }
998
999     jstring jni_uuid = (*env)->NewStringUTF(env, OIC_EDR_SERVICE_ID);
1000     if (!jni_uuid)
1001     {
1002         OIC_LOG(ERROR, TAG, "jni_uuid is null");
1003         (*env)->DeleteLocalRef(env, jni_cid_uuid);
1004         (*env)->DeleteLocalRef(env, jni_obj_remoteBTDevice);
1005         return CA_STATUS_FAILED;
1006     }
1007     jobject jni_obj_uuid = (*env)->CallStaticObjectMethod(env, jni_cid_uuid, jni_mid_fromString,
1008                                                           jni_uuid);
1009     (*env)->DeleteLocalRef(env, jni_cid_uuid);
1010     (*env)->DeleteLocalRef(env, jni_uuid);
1011     if (!jni_obj_uuid)
1012     {
1013         OIC_LOG(ERROR, TAG, "jni_obj_uuid is null");
1014         (*env)->DeleteLocalRef(env, jni_obj_remoteBTDevice);
1015         return CA_STATUS_FAILED;
1016     }
1017     // create socket
1018     jobject jni_obj_BTSocket = (*env)->CallObjectMethod(env, jni_obj_remoteBTDevice,
1019                                                         jni_mid_createSocket, jni_obj_uuid);
1020     (*env)->DeleteLocalRef(env, jni_obj_uuid);
1021     (*env)->DeleteLocalRef(env, jni_obj_remoteBTDevice);
1022     if (!jni_obj_BTSocket)
1023     {
1024         OIC_LOG(ERROR, TAG, "jni_obj_BTSocket is null");
1025         return CA_STATUS_FAILED;
1026     }
1027
1028     // connect
1029     jclass jni_cid_BTSocket = (*env)->FindClass(env, CLASSPATH_BT_SOCKET);
1030     if (!jni_cid_BTSocket)
1031     {
1032         OIC_LOG(ERROR, TAG, "jni_cid_BTSocket is null");
1033         (*env)->DeleteLocalRef(env, jni_obj_BTSocket);
1034         return CA_STATUS_FAILED;
1035     }
1036
1037     jmethodID jni_mid_connect = (*env)->GetMethodID(env, jni_cid_BTSocket, "connect", "()V");
1038     (*env)->DeleteLocalRef(env, jni_cid_BTSocket);
1039     if (!jni_mid_connect)
1040     {
1041         OIC_LOG(ERROR, TAG, "jni_mid_connect is null");
1042         (*env)->DeleteLocalRef(env, jni_obj_BTSocket);
1043         return CA_STATUS_FAILED;
1044     }
1045
1046     OIC_LOG(DEBUG, TAG, "initiating connection...");
1047     (*env)->CallVoidMethod(env, jni_obj_BTSocket, jni_mid_connect);
1048
1049     if ((*env)->ExceptionCheck(env))
1050     {
1051         OIC_LOG(ERROR, TAG, "Connect is Failed!!!");
1052         (*env)->ExceptionDescribe(env);
1053         (*env)->ExceptionClear(env);
1054         return CA_STATUS_FAILED;
1055     }
1056
1057     // set socket to list
1058     jobject jni_socket = (*env)->NewGlobalRef(env, jni_obj_BTSocket);
1059     if (!jni_socket)
1060     {
1061         OIC_LOG(ERROR, TAG, "jni_socket is null");
1062         (*env)->DeleteLocalRef(env, jni_obj_BTSocket);
1063         return CA_STATUS_FAILED;
1064     }
1065     ca_mutex_lock(g_mutexObjectList);
1066     CAEDRNativeAddDeviceSocketToList(env, jni_socket);
1067     (*env)->DeleteGlobalRef(env, jni_socket);
1068     (*env)->DeleteLocalRef(env, jni_obj_BTSocket);
1069     ca_mutex_unlock(g_mutexObjectList);
1070
1071     // update state
1072     ca_mutex_lock(g_mutexStateList);
1073     CAEDRUpdateDeviceState(STATE_CONNECTED, address);
1074     ca_mutex_unlock(g_mutexStateList);
1075
1076     OIC_LOG(DEBUG, TAG, "successfully connected");
1077
1078     return CA_STATUS_OK;
1079 }
1080
1081 void CAEDRNativeSocketClose(JNIEnv *env, const char *address)
1082 {
1083     VERIFY_NON_NULL_VOID(address, TAG, "address is null");
1084
1085     jclass jni_cid_BTSocket = (*env)->FindClass(env, "android/bluetooth/BluetoothSocket");
1086     if (!jni_cid_BTSocket)
1087     {
1088         OIC_LOG(ERROR, TAG, "jni_cid_BTSocket is null");
1089         return;
1090     }
1091
1092     jmethodID jni_mid_close = (*env)->GetMethodID(env, jni_cid_BTSocket, "close", "()V");
1093     if (!jni_mid_close)
1094     {
1095         OIC_LOG(ERROR, TAG, "jni_mid_close is null");
1096         return;
1097     }
1098
1099     jobject jni_obj_socket = CAEDRNativeGetDeviceSocketBaseAddr(env, address);
1100     if (!jni_obj_socket)
1101     {
1102         OIC_LOG(ERROR, TAG, "jni_obj_socket is not available");
1103         return;
1104     }
1105
1106     (*env)->CallVoidMethod(env, jni_obj_socket, jni_mid_close);
1107
1108     if ((*env)->ExceptionCheck(env))
1109     {
1110         OIC_LOG(ERROR, TAG, "close is Failed!!!");
1111         (*env)->ExceptionDescribe(env);
1112         (*env)->ExceptionClear(env);
1113         return;
1114     }
1115
1116     // remove socket to list
1117     CAEDRNativeRemoveDeviceSocket(env, jni_obj_socket);
1118
1119     // update state
1120     ca_mutex_lock(g_mutexStateList);
1121     CAEDRUpdateDeviceState(STATE_DISCONNECTED, address);
1122     ca_mutex_unlock(g_mutexStateList);
1123
1124     OIC_LOG_V(DEBUG, TAG, "disconnected with [%s]", address);
1125 }
1126
1127 CAResult_t CAEDRClientInitialize()
1128 {
1129     CAResult_t result = CAEDRInitialize();
1130     return result;
1131 }
1132
1133 void CAEDRSetErrorHandler(CAEDRErrorHandleCallback errorHandleCallback)
1134 {
1135     g_edrErrorHandler = errorHandleCallback;
1136 }