com_android_bluetooth_btservice_AdapterService.cpp revision ff4f17bf64978d0738c66e1b6dd70be8664efc24
1/*
2 * Copyright (C) 2012 Google Inc.
3 */
4
5#define LOG_TAG "BluetoothServiceJni"
6
7#include "JNIHelp.h"
8#include "jni.h"
9#include "hardware/hardware.h"
10#include "hardware/bluetooth.h"
11#include "utils/Log.h"
12#include "utils/misc.h"
13#include "cutils/properties.h"
14#include "android_runtime/AndroidRuntime.h"
15
16#include <string.h>
17#include <pthread.h>
18
19#include <sys/stat.h>
20#include <fcntl.h>
21
22namespace android {
23
24static jmethodID method_stateChangeCallback;
25static jmethodID method_adapterPropertyChangedCallback;
26static jmethodID method_devicePropertyChangedCallback;
27static jmethodID method_deviceFoundCallback;
28static jmethodID method_pinRequestCallback;
29static jmethodID method_passkeyRequestCallback;
30static jmethodID method_sspRequestCallback;
31static jmethodID method_bondStateChangeCallback;
32static jmethodID method_discoveryStateChangeCallback;
33
34static const bt_interface_t *sBluetoothInterface = NULL;
35static JNIEnv *callbackEnv = NULL;
36
37static jobject sJniCallbacksObj;
38static jfieldID sJniCallbacksField;
39
40static void checkAndClearExceptionFromCallback(JNIEnv* env,
41                                               const char* methodName) {
42    if (env->ExceptionCheck()) {
43        LOGE("An exception was thrown by callback '%s'.", methodName);
44        LOGE_EX(env);
45        env->ExceptionClear();
46    }
47}
48
49static bool checkCallbackThread() {
50    JNIEnv* env = AndroidRuntime::getJNIEnv();
51    if (callbackEnv != env || callbackEnv == NULL) return false;
52    return true;
53}
54
55static void adapter_state_change_callback(bt_state_t status) {
56    if (!checkCallbackThread()) {
57       LOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__);
58       return;
59    }
60    LOGV("%s: Status is: %d", __FUNCTION__, status);
61
62    callbackEnv->CallVoidMethod(sJniCallbacksObj, method_stateChangeCallback, (jint)status);
63
64    checkAndClearExceptionFromCallback(callbackEnv, __FUNCTION__);
65}
66
67static int get_properties(int num_properties, bt_property_t *properties, jintArray *types,
68                        jobjectArray *props) {
69    jbyteArray propVal, val;
70    val = (jbyteArray) callbackEnv->NewByteArray(num_properties);
71    if (val == NULL) goto Fail;
72
73    //TODO(BT) Is this the best way to do it ?
74    *props = callbackEnv->NewObjectArray(num_properties, callbackEnv->GetObjectClass(val),
75                                             NULL);
76    if (*props == NULL) goto Fail;
77
78    *types = callbackEnv->NewIntArray(num_properties);
79    if (*types == NULL) goto Fail;
80
81    for (int i = 0; i < num_properties; i++) {
82       propVal = callbackEnv->NewByteArray(properties[i].len);
83       if (propVal == NULL) goto Fail;
84
85       callbackEnv->SetByteArrayRegion(propVal, 0, properties[i].len,
86                                            (jbyte*)properties[i].val);
87       callbackEnv->SetObjectArrayElement(*props, i, propVal);
88
89       callbackEnv->SetIntArrayRegion(*types, i, 1, (jint *)&properties[i].type);
90    }
91    return 0;
92Fail:
93    if (val) callbackEnv->DeleteLocalRef(val);
94    if (propVal) callbackEnv->DeleteLocalRef(propVal);
95    LOGE("Error while allocation of array in %s", __FUNCTION__);
96    return -1;
97}
98
99static void adapter_properties_callback(bt_status_t status, int num_properties,
100                                        bt_property_t *properties) {
101    jobjectArray props;
102    jintArray types;
103    if (!checkCallbackThread()) {
104       LOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__);
105       return;
106    }
107
108    LOGV("%s: Status is: %d, Properties: %d", __FUNCTION__, status, num_properties);
109
110    if (status != BT_STATUS_SUCCESS) {
111        LOGE("%s: Status %d is incorrect", __FUNCTION__, status);
112        return;
113    }
114
115    if (!get_properties(num_properties, properties, &types, &props)) {
116        if (props) callbackEnv->DeleteLocalRef(props);
117        if (types) callbackEnv->DeleteLocalRef(types);
118        return;
119    }
120
121    callbackEnv->CallVoidMethod(sJniCallbacksObj, method_adapterPropertyChangedCallback, types,
122                                props);
123    checkAndClearExceptionFromCallback(callbackEnv, __FUNCTION__);
124    return;
125
126}
127
128static void remote_device_properties_callback(bt_status_t status, bt_bdaddr_t *bd_addr,
129                                              int num_properties, bt_property_t *properties) {
130    jobjectArray props;
131    jbyteArray addr = NULL;
132    jintArray types;
133
134    if (!checkCallbackThread()) {
135       LOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__);
136       return;
137    }
138
139    LOGV("%s: Status is: %d, Properties: %d", __FUNCTION__, status, num_properties);
140
141    if (status != BT_STATUS_SUCCESS) {
142        LOGE("%s: Status %d is incorrect", __FUNCTION__, status);
143        return;
144    }
145
146    addr = callbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
147    if (addr == NULL) goto Fail;
148    if (addr) callbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte*)bd_addr);
149
150    if (!get_properties(num_properties, properties, &types, &props)) {
151        if (props) callbackEnv->DeleteLocalRef(props);
152        if (types) callbackEnv->DeleteLocalRef(types);
153        return;
154    }
155
156    callbackEnv->CallVoidMethod(sJniCallbacksObj, method_devicePropertyChangedCallback, addr,
157                                types, props);
158    checkAndClearExceptionFromCallback(callbackEnv, __FUNCTION__);
159    return;
160
161Fail:
162    LOGE("Error while allocation byte array in %s", __FUNCTION__);
163}
164
165
166static void device_found_callback(int num_properties, bt_property_t *properties) {
167    jbyteArray addr = NULL;
168    int addr_index;
169
170    for (int i = 0; i < num_properties; i++) {
171        if (properties[i].type == BT_PROPERTY_BDADDR) {
172            addr = callbackEnv->NewByteArray(properties[i].len);
173            if (addr) {
174                callbackEnv->SetByteArrayRegion(addr, 0, properties[i].len,
175                                                (jbyte*)properties[i].val);
176                addr_index = i;
177            } else {
178                LOGE("Address is NULL (unable to allocate) in %s", __FUNCTION__);
179                return;
180            }
181        }
182    }
183    if (addr == NULL) {
184        LOGE("Address is NULL in %s", __FUNCTION__);
185        return;
186    }
187
188    LOGV("%s: Properties: %d, Address: %s", __FUNCTION__, num_properties,
189        (const char *)properties[addr_index].val);
190
191    remote_device_properties_callback(BT_STATUS_SUCCESS, (bt_bdaddr_t *)properties[addr_index].val,
192                                      num_properties, properties);
193
194    callbackEnv->CallVoidMethod(sJniCallbacksObj, method_deviceFoundCallback, addr);
195    checkAndClearExceptionFromCallback(callbackEnv, __FUNCTION__);
196}
197
198static void bond_state_changed_callback(bt_status_t status, bt_bdaddr_t *bd_addr,
199                                        bt_bond_state_t state) {
200    jbyteArray addr;
201    int i;
202    if (!checkCallbackThread()) {
203       LOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__);
204       return;
205    }
206    if (!bd_addr) {
207        LOGE("Address is null in %s", __FUNCTION__);
208        return;
209    }
210    addr = callbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
211    if (addr == NULL) {
212       LOGE("Address allocation failed in %s", __FUNCTION__);
213       return;
214    }
215    callbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte *)bd_addr);
216
217    callbackEnv->CallVoidMethod(sJniCallbacksObj, method_bondStateChangeCallback, (jint) status,
218                                addr, (jint)state);
219
220    checkAndClearExceptionFromCallback(callbackEnv, __FUNCTION__);
221}
222
223static void discovery_state_changed_callback(bt_discovery_state_t state) {
224    jbyteArray addr;
225    if (!checkCallbackThread()) {
226       LOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__);
227       return;
228    }
229
230    LOGV("%s: DiscoveryState:%d ", __FUNCTION__, state);
231
232    callbackEnv->CallVoidMethod(sJniCallbacksObj, method_discoveryStateChangeCallback,
233                                (jint)state);
234
235    checkAndClearExceptionFromCallback(callbackEnv, __FUNCTION__);
236}
237
238static void pin_request_callback(bt_bdaddr_t *bd_addr, bt_bdname_t *bdname, uint32_t cod) {
239    jbyteArray addr, devname;
240    if (!checkCallbackThread()) {
241       LOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__);
242       return;
243    }
244    if (!bd_addr) {
245        LOGE("Address is null in %s", __FUNCTION__);
246        return;
247    }
248
249    addr = callbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
250    if (addr == NULL) goto Fail;
251    callbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdname_t), (jbyte*)bd_addr);
252
253    devname = callbackEnv->NewByteArray(sizeof(bt_bdname_t));
254    if (devname == NULL) goto Fail;
255
256    callbackEnv->SetByteArrayRegion(devname, 0, sizeof(bt_bdname_t), (jbyte*)bdname);
257
258    callbackEnv->CallVoidMethod(sJniCallbacksObj, method_pinRequestCallback, addr, devname, cod);
259
260    checkAndClearExceptionFromCallback(callbackEnv, __FUNCTION__);
261    return;
262
263Fail:
264    if (addr) callbackEnv->DeleteLocalRef(addr);
265    if (devname) callbackEnv->DeleteLocalRef(devname);
266    LOGE("Error while allocating in: %s", __FUNCTION__);
267}
268
269static void passkey_request_callback(bt_bdaddr_t *bd_addr, bt_bdname_t *bdname, uint32_t cod) {
270    jbyteArray addr, devname;
271    if (!checkCallbackThread()) {
272       LOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__);
273       return;
274    }
275    if (!bd_addr) {
276        LOGE("Address is null in %s", __FUNCTION__);
277        return;
278    }
279    addr = callbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
280    if (addr == NULL) goto Fail;
281    callbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte*)bd_addr);
282
283    devname = callbackEnv->NewByteArray(sizeof(bt_bdname_t));
284    if (devname == NULL) goto Fail;
285    callbackEnv->SetByteArrayRegion(devname, 0, sizeof(bt_bdname_t), (jbyte*)bdname);
286
287    callbackEnv->CallVoidMethod(sJniCallbacksObj, method_passkeyRequestCallback, addr, devname,
288                                cod);
289
290    checkAndClearExceptionFromCallback(callbackEnv, __FUNCTION__);
291    return;
292
293Fail:
294    if (addr) callbackEnv->DeleteLocalRef(addr);
295    if (devname) callbackEnv->DeleteLocalRef(devname);
296
297    LOGE("Error while allocating in: %s", __FUNCTION__);
298}
299
300static void ssp_request_callback(bt_bdaddr_t *bd_addr, bt_bdname_t *bdname, uint32_t cod,
301                                 bt_ssp_variant_t pairing_variant, uint32_t pass_key) {
302    jbyteArray addr, devname;
303    if (!checkCallbackThread()) {
304       LOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__);
305       return;
306    }
307    if (!bd_addr) {
308        LOGE("Address is null in %s", __FUNCTION__);
309        return;
310    }
311
312    addr = callbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
313    if (addr == NULL) goto Fail;
314    callbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte *)bd_addr);
315
316    devname = callbackEnv->NewByteArray(sizeof(bt_bdname_t));
317    if (devname == NULL) goto Fail;
318    callbackEnv->SetByteArrayRegion(devname, 0, sizeof(bt_bdname_t), (jbyte*)bdname);
319
320    callbackEnv->CallVoidMethod(sJniCallbacksObj, method_sspRequestCallback, addr, devname, cod,
321                                (jint) pairing_variant, pass_key);
322
323    checkAndClearExceptionFromCallback(callbackEnv, __FUNCTION__);
324    return;
325
326Fail:
327    if (addr) callbackEnv->DeleteLocalRef(addr);
328    if (devname) callbackEnv->DeleteLocalRef(devname);
329
330    LOGE("Error while allocating in: %s", __FUNCTION__);
331}
332
333static void callback_thread_event(bt_cb_thread_evt event) {
334    JavaVM* vm = AndroidRuntime::getJavaVM();
335    if (event  == ASSOCIATE_JVM) {
336        JavaVMAttachArgs args;
337        char name[] = "BT Service Callback Thread";
338        //TODO(BT)
339        //args.version = nat->envVer;
340        args.name = name;
341        args.group = NULL;
342        vm->AttachCurrentThread(&callbackEnv, &args);
343        LOGV("Callback thread attached: %p", callbackEnv);
344    } else if (event == DISASSOCIATE_JVM) {
345        if (!checkCallbackThread()) {
346            LOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__);
347            return;
348        }
349        vm->DetachCurrentThread();
350    }
351}
352
353bt_callbacks_t sBluetoothCallbacks = {
354    sizeof(sBluetoothCallbacks),
355    adapter_state_change_callback,
356    adapter_properties_callback,
357    remote_device_properties_callback,
358    device_found_callback,
359    discovery_state_changed_callback,
360    pin_request_callback,
361    passkey_request_callback,
362    ssp_request_callback,
363    bond_state_changed_callback,
364    callback_thread_event,
365};
366
367static void classInitNative(JNIEnv* env, jclass clazz) {
368    int err;
369    hw_module_t* module;
370
371    jclass jniCallbackClass =
372        env->FindClass("com/android/bluetooth/btservice/JniCallbacks");
373    sJniCallbacksField = env->GetFieldID(clazz, "mJniCallbacks",
374        "Lcom/android/bluetooth/btservice/JniCallbacks;");
375
376    method_stateChangeCallback = env->GetMethodID(jniCallbackClass, "stateChangeCallback", "(I)V");
377
378    method_adapterPropertyChangedCallback = env->GetMethodID(jniCallbackClass,
379                                                             "adapterPropertyChangedCallback",
380                                                             "([I[[B)V");
381    method_discoveryStateChangeCallback = env->GetMethodID(jniCallbackClass,
382                                                           "discoveryStateChangeCallback", "(I)V");
383
384    method_devicePropertyChangedCallback = env->GetMethodID(jniCallbackClass,
385                                                            "devicePropertyChangedCallback",
386                                                            "([B[I[[B)V");
387    method_deviceFoundCallback = env->GetMethodID(jniCallbackClass, "deviceFoundCallback", "([B)V");
388    method_pinRequestCallback = env->GetMethodID(jniCallbackClass, "pinRequestCallback",
389                                                 "([B[BI)V");
390    method_passkeyRequestCallback = env->GetMethodID(jniCallbackClass, "passkeyRequestCallback",
391                                                     "([B[BI)V");
392    method_sspRequestCallback = env->GetMethodID(jniCallbackClass, "sspRequestCallback",
393                                                 "([B[BIII)V");
394
395    method_bondStateChangeCallback = env->GetMethodID(jniCallbackClass,
396                                                     "bondStateChangeCallback", "(I[BI)V");
397
398    char value[PROPERTY_VALUE_MAX];
399    property_get("bluetooth.mock_stack", value, "");
400
401    const char *id = (strcmp(value, "1")? BT_STACK_MODULE_ID : BT_STACK_TEST_MODULE_ID);
402
403    err = hw_get_module(id, (hw_module_t const**)&module);
404
405    if (err == 0) {
406        hw_device_t* abstraction;
407        err = module->methods->open(module, id, &abstraction);
408        if (err == 0) {
409            bluetooth_module_t* btStack = (bluetooth_module_t *)abstraction;
410            sBluetoothInterface = btStack->get_bluetooth_interface();
411        } else {
412           LOGE("Error while opening Bluetooth library");
413        }
414    } else {
415        LOGE("No Bluetooth Library found");
416    }
417}
418
419static bool initNative(JNIEnv* env, jobject obj) {
420    LOGV("%s:",__FUNCTION__);
421
422    sJniCallbacksObj = env->NewGlobalRef(env->GetObjectField(obj, sJniCallbacksField));
423
424    if (sBluetoothInterface) {
425        int ret = sBluetoothInterface->init(&sBluetoothCallbacks);
426        if (ret != BT_STATUS_SUCCESS) {
427            LOGE("Error while setting the callbacks \n");
428            sBluetoothInterface = NULL;
429            return JNI_FALSE;
430        }
431        return JNI_TRUE;
432    }
433    return JNI_FALSE;
434}
435
436static bool cleanupNative(JNIEnv *env, jobject obj) {
437    LOGV("%s:",__FUNCTION__);
438
439    jboolean result = JNI_FALSE;
440    if (!sBluetoothInterface) return result;
441
442    sBluetoothInterface->cleanup();
443    env->DeleteGlobalRef(sJniCallbacksObj);
444    return JNI_TRUE;
445}
446
447static jboolean enableNative(JNIEnv* env, jobject obj) {
448    LOGV("%s:",__FUNCTION__);
449
450    jboolean result = JNI_FALSE;
451    if (!sBluetoothInterface) return result;
452
453    int ret = sBluetoothInterface->enable();
454    result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
455    return result;
456}
457
458static jboolean disableNative(JNIEnv* env, jobject obj) {
459    LOGV("%s:",__FUNCTION__);
460
461    jboolean result = JNI_FALSE;
462    if (!sBluetoothInterface) return result;
463
464    int ret = sBluetoothInterface->disable();
465    result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
466    return result;
467}
468
469static jboolean startDiscoveryNative(JNIEnv* env, jobject obj) {
470    LOGV("%s:",__FUNCTION__);
471
472    jboolean result = JNI_FALSE;
473    if (!sBluetoothInterface) return result;
474
475    int ret = sBluetoothInterface->start_discovery();
476    result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
477    return result;
478}
479
480static jboolean cancelDiscoveryNative(JNIEnv* env, jobject obj) {
481    LOGV("%s:",__FUNCTION__);
482
483    jboolean result = JNI_FALSE;
484    if (!sBluetoothInterface) return result;
485
486    int ret = sBluetoothInterface->cancel_discovery();
487    result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
488    return result;
489}
490
491static jboolean createBondNative(JNIEnv* env, jobject obj, jbyteArray address) {
492    LOGV("%s:",__FUNCTION__);
493
494    jbyte *addr;
495    jboolean result = JNI_FALSE;
496
497    if (!sBluetoothInterface) return result;
498
499    addr = env->GetByteArrayElements(address, NULL);
500    if (addr == NULL) {
501        jniThrowIOException(env, EINVAL);
502        return result;
503    }
504
505    int ret = sBluetoothInterface->create_bond((bt_bdaddr_t *)addr);
506    env->ReleaseByteArrayElements(address, addr, NULL);
507    result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
508
509    return result;
510}
511
512static jboolean removeBondNative(JNIEnv* env, jobject obj, jbyteArray address) {
513    LOGV("%s:",__FUNCTION__);
514
515    jbyte *addr;
516    jboolean result;
517    if (!sBluetoothInterface) return JNI_FALSE;
518
519    addr = env->GetByteArrayElements(address, NULL);
520    if (addr == NULL) {
521        jniThrowIOException(env, EINVAL);
522        return JNI_FALSE;
523    }
524
525    int ret = sBluetoothInterface->remove_bond((bt_bdaddr_t *)addr);
526    env->ReleaseByteArrayElements(address, addr, NULL);
527    result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
528
529    return result;
530}
531
532static jboolean cancelBondNative(JNIEnv* env, jobject obj, jbyteArray address) {
533    LOGV("%s:",__FUNCTION__);
534
535    jbyte *addr;
536    jboolean result;
537    if (!sBluetoothInterface) return JNI_FALSE;
538
539    addr = env->GetByteArrayElements(address, NULL);
540    if (addr == NULL) {
541        jniThrowIOException(env, EINVAL);
542        return JNI_FALSE;
543    }
544
545    int ret = sBluetoothInterface->cancel_bond((bt_bdaddr_t *)addr);
546    env->ReleaseByteArrayElements(address, addr, NULL);
547    result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
548
549    return result;
550}
551
552static jboolean pinReplyNative(JNIEnv *env, jobject obj, jbyteArray address, jboolean accept,
553                               jint len, jbyteArray pinArray) {
554    LOGV("%s:",__FUNCTION__);
555
556    jbyte *addr, *pinPtr = NULL;
557    jboolean result = JNI_FALSE;
558    if (!sBluetoothInterface) return result;
559
560    addr = env->GetByteArrayElements(address, NULL);
561    if (addr == NULL) {
562        jniThrowIOException(env, EINVAL);
563        return result;
564    }
565
566    if (accept) {
567        pinPtr = env->GetByteArrayElements(pinArray, NULL);
568        if (pinPtr == NULL) {
569           jniThrowIOException(env, EINVAL);
570           env->ReleaseByteArrayElements(address, addr, NULL);
571           return result;
572        }
573    }
574
575    int ret = sBluetoothInterface->pin_reply((bt_bdaddr_t*)addr, accept, len,
576                                              (bt_pin_code_t *) pinPtr);
577    env->ReleaseByteArrayElements(address, addr, NULL);
578    env->ReleaseByteArrayElements(pinArray, pinPtr, NULL);
579    result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
580
581    return result;
582}
583
584static jboolean passkeyReplyNative(JNIEnv *env, jobject obj, jbyteArray address, jboolean accept,
585                               jint len, uint32_t passkey) {
586    LOGV("%s:",__FUNCTION__);
587
588    jbyte *addr = NULL;
589    jboolean result = JNI_FALSE;
590    if (!sBluetoothInterface) return result;
591
592    addr = env->GetByteArrayElements(address, NULL);
593    if (addr == NULL) {
594        jniThrowIOException(env, EINVAL);
595        return result;
596    }
597
598    int ret = sBluetoothInterface->passkey_reply((bt_bdaddr_t *)addr, accept, passkey);
599    env->ReleaseByteArrayElements(address, addr, NULL);
600    result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
601
602    return result;
603}
604
605static jboolean sspReplyNative(JNIEnv *env, jobject obj, jbyteArray address,
606                               jboolean accept) {
607    LOGV("%s:",__FUNCTION__);
608
609    jbyte *addr;
610    jboolean result = JNI_FALSE;
611    if (!sBluetoothInterface) return result;
612
613    addr = env->GetByteArrayElements(address, NULL);
614    if (addr == NULL) {
615        jniThrowIOException(env, EINVAL);
616        return result;
617    }
618
619    int ret = sBluetoothInterface->ssp_reply((bt_bdaddr_t *)addr, accept);
620    env->ReleaseByteArrayElements(address, addr, NULL);
621    result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
622
623    return result;
624}
625
626static jboolean setAdapterPropertyNative(JNIEnv *env, jobject obj, jint type, jbyteArray value) {
627    LOGV("%s:",__FUNCTION__);
628
629    jbyte *val;
630    jboolean result = JNI_FALSE;
631    if (!sBluetoothInterface) return result;
632
633    val = env->GetByteArrayElements(value, NULL);
634    bt_property_t prop;
635    prop.type = (bt_property_type_t) type;
636    prop.len = env->GetArrayLength(value);
637    prop.val = val;
638
639    int ret = sBluetoothInterface->set_adapter_property(&prop);
640    env->ReleaseByteArrayElements(value, val, NULL);
641    result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
642
643    return result;
644}
645
646static jboolean getAdapterPropertiesNative(JNIEnv *env, jobject obj) {
647    LOGV("%s:",__FUNCTION__);
648
649    jboolean result = JNI_FALSE;
650    if (!sBluetoothInterface) return result;
651
652    int ret = sBluetoothInterface->get_adapter_properties();
653    result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
654
655    return result;
656}
657
658static jboolean getAdapterPropertyNative(JNIEnv *env, jobject obj, jint type) {
659    LOGV("%s:",__FUNCTION__);
660
661    jboolean result = JNI_FALSE;
662    if (!sBluetoothInterface) return result;
663
664    int ret = sBluetoothInterface->get_adapter_property((bt_property_type_t) type);
665    result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
666
667    return result;
668}
669
670static jboolean getDevicePropertyNative(JNIEnv *env, jobject obj, jbyteArray address, jint type) {
671    LOGV("%s:",__FUNCTION__);
672
673    jbyte *addr = NULL;
674    jboolean result = JNI_FALSE;
675    if (!sBluetoothInterface) return result;
676
677    addr = env->GetByteArrayElements(address, NULL);
678    if (addr == NULL) {
679        jniThrowIOException(env, EINVAL);
680        return result;
681    }
682
683    int ret = sBluetoothInterface->get_remote_device_property((bt_bdaddr_t *)addr,
684                                                              (bt_property_type_t) type);
685    env->ReleaseByteArrayElements(address, addr, NULL);
686    result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
687
688    return result;
689}
690
691static jboolean setDevicePropertyNative(JNIEnv *env, jobject obj, jbyteArray address,
692                                        jint type, jbyteArray value) {
693    LOGV("%s:",__FUNCTION__);
694
695    jbyte *val, *addr;
696    jboolean result = JNI_FALSE;
697    if (!sBluetoothInterface) return result;
698
699    val = env->GetByteArrayElements(value, NULL);
700    if (val == NULL) {
701        jniThrowIOException(env, EINVAL);
702        return result;
703    }
704
705    addr = env->GetByteArrayElements(address, NULL);
706    if (addr == NULL) {
707        env->ReleaseByteArrayElements(value, val, NULL);
708        jniThrowIOException(env, EINVAL);
709        return result;
710    }
711
712
713    bt_property_t prop;
714    prop.type = (bt_property_type_t) type;
715    prop.len = env->GetArrayLength(value);
716    prop.val = val;
717
718    int ret = sBluetoothInterface->set_remote_device_property((bt_bdaddr_t *)addr, &prop);
719    env->ReleaseByteArrayElements(value, val, NULL);
720    env->ReleaseByteArrayElements(address, addr, NULL);
721
722    result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
723
724    return result;
725}
726
727static JNINativeMethod sMethods[] = {
728     /* name, signature, funcPtr */
729    {"classInitNative", "()V", (void *) classInitNative},
730    {"initNative", "()Z", (void *) initNative},
731    {"cleanupNative", "()V", (void*) cleanupNative},
732    {"enableNative", "()Z",  (void*) enableNative},
733    {"disableNative", "()Z",  (void*) disableNative},
734    {"setAdapterPropertyNative", "(I[B)Z", (void*) setAdapterPropertyNative},
735    {"getAdapterPropertiesNative", "()Z", (void*) getAdapterPropertiesNative},
736    {"getAdapterPropertyNative", "(I)Z", (void*) getAdapterPropertyNative},
737    {"getDevicePropertyNative", "([BI)Z", (void*) getDevicePropertyNative},
738    {"setDevicePropertyNative", "([BI[B)Z", (void*) setDevicePropertyNative},
739    {"startDiscoveryNative", "()Z", (void*) startDiscoveryNative},
740    {"cancelDiscoveryNative", "()Z", (void*) cancelDiscoveryNative},
741    {"createBondNative", "([B)Z", (void*) createBondNative},
742    {"removeBondNative", "([B)Z", (void*) removeBondNative},
743    {"cancelBondNative", "([B)Z", (void*) cancelBondNative},
744    {"pinReplyNative", "([BZI[B)Z", (void*) pinReplyNative},
745    {"passkeyReplyNative", "([BZII)Z", (void*) passkeyReplyNative},
746    {"sspReplyNative", "([BZ)Z", (void*) sspReplyNative},
747};
748
749int register_com_android_bluetooth_btservice_AdapterService(JNIEnv* env)
750{
751    return jniRegisterNativeMethods(env, "com/android/bluetooth/btservice/AdapterService",
752                                    sMethods, NELEM(sMethods));
753}
754
755} /* namespace android */
756
757
758/*
759 * JNI Initialization
760 */
761jint JNI_OnLoad(JavaVM *jvm, void *reserved)
762{
763   JNIEnv *e;
764
765   LOGV("Bluetooth Adapter Service : loading JNI\n");
766
767   // Check JNI version
768   if(jvm->GetEnv((void **)&e, JNI_VERSION_1_6))
769      return JNI_ERR;
770
771   if (android::register_com_android_bluetooth_btservice_AdapterService(e) == -1)
772      return JNI_ERR;
773   return JNI_VERSION_1_6;
774}
775