| /* |
| * Copyright (C) 2013 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| |
| #define ALOG_TAG "BtGatt.JNI" |
| |
| #define ALOG_NDEBUG 0 |
| |
| #define CHECK_CALLBACK_ENV \ |
| if (!checkCallbackThread()) { \ |
| error("Callback: '%s' is not called on the correct thread", __FUNCTION__);\ |
| return; \ |
| } |
| |
| #include "com_android_bluetooth.h" |
| #include "hardware/bt_gatt.h" |
| #include "utils/Log.h" |
| #include "android_runtime/AndroidRuntime.h" |
| |
| #include <string.h> |
| |
| #include <cutils/log.h> |
| #define info(fmt, ...) ALOGI ("%s(L%d): " fmt,__FUNCTION__, __LINE__, ## __VA_ARGS__) |
| #define debug(fmt, ...) ALOGD ("%s(L%d): " fmt,__FUNCTION__, __LINE__, ## __VA_ARGS__) |
| #define warn(fmt, ...) ALOGW ("WARNING: %s(L%d): " fmt "##",__FUNCTION__, __LINE__, ## __VA_ARGS__) |
| #define error(fmt, ...) ALOGE ("ERROR: %s(L%d): " fmt "##",__FUNCTION__, __LINE__, ## __VA_ARGS__) |
| #define asrt(s) if(!(s)) ALOGE ("%s(L%d): ASSERT %s failed! ##",__FUNCTION__, __LINE__, #s) |
| |
| #define BD_ADDR_LEN 6 |
| |
| #define UUID_PARAMS(uuid_ptr) \ |
| uuid_lsb(uuid_ptr), uuid_msb(uuid_ptr) |
| |
| #define CHAR_ID_PARAMS(char_ptr) \ |
| char_ptr->inst_id, \ |
| UUID_PARAMS((&char_ptr->uuid)) |
| |
| #define SRVC_ID_PARAMS(srvc_ptr) \ |
| (srvc_ptr->is_primary ? \ |
| BTGATT_SERVICE_TYPE_PRIMARY : BTGATT_SERVICE_TYPE_SECONDARY), \ |
| CHAR_ID_PARAMS((&srvc_ptr->id)) |
| |
| |
| static void set_uuid(uint8_t* uuid, jlong uuid_msb, jlong uuid_lsb) |
| { |
| for (int i = 0; i != 8; ++i) |
| { |
| uuid[i] = (uuid_lsb >> (8 * i)) & 0xFF; |
| uuid[i + 8] = (uuid_msb >> (8 * i)) & 0xFF; |
| } |
| } |
| |
| static uint64_t uuid_lsb(bt_uuid_t* uuid) |
| { |
| uint64_t lsb = 0; |
| int i; |
| |
| for (i = 7; i >= 0; i--) |
| { |
| lsb <<= 8; |
| lsb |= uuid->uu[i]; |
| } |
| |
| return lsb; |
| } |
| |
| static uint64_t uuid_msb(bt_uuid_t* uuid) |
| { |
| uint64_t msb = 0; |
| int i; |
| |
| for (i = 15; i >= 8; i--) |
| { |
| msb <<= 8; |
| msb |= uuid->uu[i]; |
| } |
| |
| return msb; |
| } |
| |
| static void bd_addr_str_to_addr(const char* str, uint8_t *bd_addr) |
| { |
| int i; |
| char c; |
| |
| c = *str++; |
| for (i = 0; i < BD_ADDR_LEN; i++) |
| { |
| if (c >= '0' && c <= '9') |
| bd_addr[i] = c - '0'; |
| else if (c >= 'a' && c <= 'z') |
| bd_addr[i] = c - 'a' + 10; |
| else // (c >= 'A' && c <= 'Z') |
| bd_addr[i] = c - 'A' + 10; |
| |
| c = *str++; |
| if (c != ':') |
| { |
| bd_addr[i] <<= 4; |
| if (c >= '0' && c <= '9') |
| bd_addr[i] |= c - '0'; |
| else if (c >= 'a' && c <= 'z') |
| bd_addr[i] |= c - 'a' + 10; |
| else // (c >= 'A' && c <= 'Z') |
| bd_addr[i] |= c - 'A' + 10; |
| |
| c = *str++; |
| } |
| |
| c = *str++; |
| } |
| } |
| |
| static void jstr2bdaddr(JNIEnv* env, bt_bdaddr_t *bda, jstring address) |
| { |
| const char* c_bda = env->GetStringUTFChars(address, NULL); |
| if (c_bda != NULL && bda != NULL && strlen(c_bda) == 17) |
| { |
| bd_addr_str_to_addr(c_bda, bda->address); |
| env->ReleaseStringUTFChars(address, c_bda); |
| } |
| } |
| |
| namespace android { |
| |
| /** |
| * Client callback methods |
| */ |
| |
| static jmethodID method_onClientRegistered; |
| static jmethodID method_onScanResult; |
| static jmethodID method_onConnected; |
| static jmethodID method_onDisconnected; |
| static jmethodID method_onReadCharacteristic; |
| static jmethodID method_onWriteCharacteristic; |
| static jmethodID method_onExecuteCompleted; |
| static jmethodID method_onSearchCompleted; |
| static jmethodID method_onSearchResult; |
| static jmethodID method_onReadDescrExtProp; |
| static jmethodID method_onReadDescriptor; |
| static jmethodID method_onWriteDescriptor; |
| static jmethodID method_onNotify; |
| static jmethodID method_onGetCharacteristic; |
| static jmethodID method_onGetDescriptor; |
| static jmethodID method_onGetIncludedService; |
| static jmethodID method_onRegisterForNotifications; |
| static jmethodID method_onReadRemoteRssi; |
| |
| /** |
| * Server callback methods |
| */ |
| static jmethodID method_onServerRegistered; |
| static jmethodID method_onClientConnected; |
| static jmethodID method_onServiceAdded; |
| static jmethodID method_onIncludedServiceAdded; |
| static jmethodID method_onCharacteristicAdded; |
| static jmethodID method_onDescriptorAdded; |
| static jmethodID method_onServiceStarted; |
| static jmethodID method_onServiceStopped; |
| static jmethodID method_onServiceDeleted; |
| static jmethodID method_onResponseSendCompleted; |
| static jmethodID method_onAttributeRead; |
| static jmethodID method_onAttributeWrite; |
| static jmethodID method_onExecuteWrite; |
| |
| /** |
| * Static variables |
| */ |
| |
| static const btgatt_interface_t *sGattIf = NULL; |
| static jobject mCallbacksObj = NULL; |
| static JNIEnv *sCallbackEnv = NULL; |
| |
| static bool checkCallbackThread() { |
| sCallbackEnv = getCallbackEnv(); |
| |
| JNIEnv* env = AndroidRuntime::getJNIEnv(); |
| if (sCallbackEnv != env || sCallbackEnv == NULL) return false; |
| return true; |
| } |
| |
| /** |
| * BTA client callbacks |
| */ |
| |
| void btgattc_register_app_cb(int status, int clientIf, bt_uuid_t *app_uuid) |
| { |
| CHECK_CALLBACK_ENV |
| sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onClientRegistered, status, |
| clientIf, UUID_PARAMS(app_uuid)); |
| checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); |
| } |
| |
| void btgattc_scan_result_cb(bt_bdaddr_t* bda, int rssi, uint8_t* adv_data) |
| { |
| CHECK_CALLBACK_ENV |
| |
| char c_address[32]; |
| snprintf(c_address, sizeof(c_address),"%02X:%02X:%02X:%02X:%02X:%02X", |
| bda->address[0], bda->address[1], bda->address[2], |
| bda->address[3], bda->address[4], bda->address[5]); |
| |
| jstring address = sCallbackEnv->NewStringUTF(c_address); |
| jbyteArray jb = sCallbackEnv->NewByteArray(62); |
| sCallbackEnv->SetByteArrayRegion(jb, 0, 62, (jbyte *) adv_data); |
| |
| sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onScanResult |
| , address, rssi, jb); |
| |
| sCallbackEnv->DeleteLocalRef(address); |
| sCallbackEnv->DeleteLocalRef(jb); |
| checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); |
| } |
| |
| void btgattc_open_cb(int conn_id, int status, int clientIf, bt_bdaddr_t* bda) |
| { |
| CHECK_CALLBACK_ENV |
| |
| char c_address[32]; |
| snprintf(c_address, sizeof(c_address),"%02X:%02X:%02X:%02X:%02X:%02X", |
| bda->address[0], bda->address[1], bda->address[2], |
| bda->address[3], bda->address[4], bda->address[5]); |
| |
| jstring address = sCallbackEnv->NewStringUTF(c_address); |
| sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onConnected, |
| clientIf, conn_id, status, address); |
| sCallbackEnv->DeleteLocalRef(address); |
| checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); |
| } |
| |
| void btgattc_close_cb(int conn_id, int status, int clientIf, bt_bdaddr_t* bda) |
| { |
| CHECK_CALLBACK_ENV |
| char c_address[32]; |
| snprintf(c_address, sizeof(c_address),"%02X:%02X:%02X:%02X:%02X:%02X", |
| bda->address[0], bda->address[1], bda->address[2], |
| bda->address[3], bda->address[4], bda->address[5]); |
| |
| jstring address = sCallbackEnv->NewStringUTF(c_address); |
| sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onDisconnected, |
| clientIf, conn_id, status, address); |
| sCallbackEnv->DeleteLocalRef(address); |
| checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); |
| } |
| |
| void btgattc_search_complete_cb(int conn_id, int status) |
| { |
| CHECK_CALLBACK_ENV |
| sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onSearchCompleted, |
| conn_id, status); |
| checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); |
| } |
| |
| void btgattc_search_result_cb(int conn_id, btgatt_srvc_id_t *srvc_id) |
| { |
| CHECK_CALLBACK_ENV |
| sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onSearchResult, conn_id, |
| SRVC_ID_PARAMS(srvc_id)); |
| checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); |
| } |
| |
| void btgattc_get_characteristic_cb(int conn_id, int status, |
| btgatt_srvc_id_t *srvc_id, btgatt_char_id_t *char_id, |
| int char_prop) |
| { |
| CHECK_CALLBACK_ENV |
| sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onGetCharacteristic |
| , conn_id, status, SRVC_ID_PARAMS(srvc_id), CHAR_ID_PARAMS(char_id) |
| , char_prop); |
| checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); |
| } |
| |
| void btgattc_get_descriptor_cb(int conn_id, int status, |
| btgatt_srvc_id_t *srvc_id, btgatt_char_id_t *char_id, |
| bt_uuid_t *descr_id) |
| { |
| CHECK_CALLBACK_ENV |
| sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onGetDescriptor |
| , conn_id, status, SRVC_ID_PARAMS(srvc_id), CHAR_ID_PARAMS(char_id) |
| , UUID_PARAMS(descr_id)); |
| checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); |
| } |
| |
| void btgattc_get_included_service_cb(int conn_id, int status, |
| btgatt_srvc_id_t *srvc_id, btgatt_srvc_id_t *incl_srvc_id) |
| { |
| CHECK_CALLBACK_ENV |
| sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onGetIncludedService |
| , conn_id, status, SRVC_ID_PARAMS(srvc_id), SRVC_ID_PARAMS(incl_srvc_id)); |
| checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); |
| } |
| |
| void btgattc_register_for_notification_cb(int conn_id, int registered, int status, |
| btgatt_srvc_id_t *srvc_id, btgatt_char_id_t *char_id) |
| { |
| CHECK_CALLBACK_ENV |
| sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onRegisterForNotifications |
| , conn_id, status, registered, SRVC_ID_PARAMS(srvc_id), CHAR_ID_PARAMS(char_id)); |
| checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); |
| } |
| |
| void btgattc_notify_cb(int conn_id, btgatt_notify_params_t *p_data) |
| { |
| CHECK_CALLBACK_ENV |
| |
| char c_address[32]; |
| snprintf(c_address, sizeof(c_address), "%02X:%02X:%02X:%02X:%02X:%02X", |
| p_data->bda.address[0], p_data->bda.address[1], p_data->bda.address[2], |
| p_data->bda.address[3], p_data->bda.address[4], p_data->bda.address[5]); |
| |
| jstring address = sCallbackEnv->NewStringUTF(c_address); |
| jbyteArray jb = sCallbackEnv->NewByteArray(p_data->len); |
| sCallbackEnv->SetByteArrayRegion(jb, 0, p_data->len, (jbyte *) p_data->value); |
| |
| sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onNotify |
| , conn_id, address, SRVC_ID_PARAMS((&p_data->srvc_id)) |
| , CHAR_ID_PARAMS((&p_data->char_id)), p_data->is_notify, jb); |
| |
| sCallbackEnv->DeleteLocalRef(address); |
| sCallbackEnv->DeleteLocalRef(jb); |
| checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); |
| } |
| |
| void btgattc_read_characteristic_cb(int conn_id, int status, btgatt_read_params_t *p_data) |
| { |
| CHECK_CALLBACK_ENV |
| |
| jbyteArray jb; |
| if ( status == 0 ) //successful |
| { |
| jb = sCallbackEnv->NewByteArray(p_data->value.len); |
| sCallbackEnv->SetByteArrayRegion(jb, 0, p_data->value.len, |
| (jbyte *) p_data->value.value); |
| } else { |
| uint8_t value = 0; |
| jb = sCallbackEnv->NewByteArray(1); |
| sCallbackEnv->SetByteArrayRegion(jb, 0, 1, (jbyte *) &value); |
| } |
| |
| sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onReadCharacteristic |
| , conn_id, status, SRVC_ID_PARAMS((&p_data->srvc_id)) |
| , CHAR_ID_PARAMS((&p_data->char_id)), p_data->value_type, jb); |
| sCallbackEnv->DeleteLocalRef(jb); |
| checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); |
| } |
| |
| void btgattc_write_characteristic_cb(int conn_id, int status, btgatt_write_params_t *p_data) |
| { |
| CHECK_CALLBACK_ENV |
| sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onWriteCharacteristic |
| , conn_id, status, SRVC_ID_PARAMS((&p_data->srvc_id)) |
| , CHAR_ID_PARAMS((&p_data->char_id))); |
| checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); |
| } |
| |
| void btgattc_execute_write_cb(int conn_id, int status) |
| { |
| CHECK_CALLBACK_ENV |
| sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onExecuteCompleted |
| , conn_id, status); |
| checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); |
| } |
| |
| void btgattc_read_descriptor_cb(int conn_id, int status, btgatt_read_params_t *p_data) |
| { |
| CHECK_CALLBACK_ENV |
| |
| jbyteArray jb; |
| if ( p_data->value.len != 0 ) |
| { |
| jb = sCallbackEnv->NewByteArray(p_data->value.len); |
| sCallbackEnv->SetByteArrayRegion(jb, 0, p_data->value.len, |
| (jbyte *) p_data->value.value); |
| } else { |
| jb = sCallbackEnv->NewByteArray(1); |
| } |
| |
| sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onReadDescriptor |
| , conn_id, status, SRVC_ID_PARAMS((&p_data->srvc_id)) |
| , CHAR_ID_PARAMS((&p_data->char_id)), UUID_PARAMS((&p_data->descr_id)) |
| , p_data->value_type, jb); |
| |
| sCallbackEnv->DeleteLocalRef(jb); |
| checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); |
| } |
| |
| void btgattc_write_descriptor_cb(int conn_id, int status, btgatt_write_params_t *p_data) |
| { |
| CHECK_CALLBACK_ENV |
| sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onWriteDescriptor |
| , conn_id, status, SRVC_ID_PARAMS((&p_data->srvc_id)) |
| , CHAR_ID_PARAMS((&p_data->char_id)), UUID_PARAMS((&p_data->descr_id))); |
| checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); |
| } |
| |
| void btgattc_remote_rssi_cb(int client_if,bt_bdaddr_t* bda, int rssi, int status) |
| { |
| CHECK_CALLBACK_ENV |
| |
| char c_address[32]; |
| snprintf(c_address, sizeof(c_address),"%02X:%02X:%02X:%02X:%02X:%02X", |
| bda->address[0], bda->address[1], bda->address[2], |
| bda->address[3], bda->address[4], bda->address[5]); |
| jstring address = sCallbackEnv->NewStringUTF(c_address); |
| sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onReadRemoteRssi, |
| client_if, address, rssi, status); |
| sCallbackEnv->DeleteLocalRef(address); |
| checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); |
| } |
| |
| static const btgatt_client_callbacks_t sGattClientCallbacks = { |
| btgattc_register_app_cb, |
| btgattc_scan_result_cb, |
| btgattc_open_cb, |
| btgattc_close_cb, |
| btgattc_search_complete_cb, |
| btgattc_search_result_cb, |
| btgattc_get_characteristic_cb, |
| btgattc_get_descriptor_cb, |
| btgattc_get_included_service_cb, |
| btgattc_register_for_notification_cb, |
| btgattc_notify_cb, |
| btgattc_read_characteristic_cb, |
| btgattc_write_characteristic_cb, |
| btgattc_read_descriptor_cb, |
| btgattc_write_descriptor_cb, |
| btgattc_execute_write_cb, |
| btgattc_remote_rssi_cb |
| }; |
| |
| |
| /** |
| * BTA server callbacks |
| */ |
| |
| void btgatts_register_app_cb(int status, int server_if, bt_uuid_t *uuid) |
| { |
| CHECK_CALLBACK_ENV |
| sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onServerRegistered |
| , status, server_if, UUID_PARAMS(uuid)); |
| checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); |
| } |
| |
| void btgatts_connection_cb(int conn_id, int connected, bt_bdaddr_t *bda) |
| { |
| CHECK_CALLBACK_ENV |
| |
| char c_address[32]; |
| sprintf(c_address, "%02X:%02X:%02X:%02X:%02X:%02X", |
| bda->address[0], bda->address[1], bda->address[2], |
| bda->address[3], bda->address[4], bda->address[5]); |
| |
| jstring address = sCallbackEnv->NewStringUTF(c_address); |
| sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onClientConnected, |
| address, connected, conn_id); |
| sCallbackEnv->DeleteLocalRef(address); |
| checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); |
| } |
| |
| void btgatts_service_added_cb(int status, int server_if, |
| btgatt_srvc_id_t *srvc_id, int srvc_handle) |
| { |
| CHECK_CALLBACK_ENV |
| sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onServiceAdded, status, |
| server_if, SRVC_ID_PARAMS(srvc_id), |
| srvc_handle); |
| checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); |
| } |
| |
| void btgatts_included_service_added_cb(int status, int server_if, |
| int srvc_handle, |
| int incl_srvc_handle) |
| { |
| CHECK_CALLBACK_ENV |
| sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onIncludedServiceAdded, |
| status, server_if, srvc_handle, incl_srvc_handle); |
| checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); |
| } |
| |
| void btgatts_characteristic_added_cb(int status, int server_if, bt_uuid_t *char_id, |
| int srvc_handle, int char_handle) |
| { |
| CHECK_CALLBACK_ENV |
| sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onCharacteristicAdded, |
| status, server_if, UUID_PARAMS(char_id), |
| srvc_handle, char_handle); |
| checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); |
| } |
| |
| void btgatts_descriptor_added_cb(int status, int server_if, |
| bt_uuid_t *descr_id, int srvc_handle, |
| int descr_handle) |
| { |
| CHECK_CALLBACK_ENV |
| sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onDescriptorAdded, |
| status, server_if, UUID_PARAMS(descr_id), |
| srvc_handle, descr_handle); |
| checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); |
| } |
| |
| void btgatts_service_started_cb(int status, int server_if, int srvc_handle) |
| { |
| CHECK_CALLBACK_ENV |
| sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onServiceStarted, status, |
| server_if, srvc_handle); |
| checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); |
| } |
| |
| void btgatts_service_stopped_cb(int status, int server_if, int srvc_handle) |
| { |
| CHECK_CALLBACK_ENV |
| sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onServiceStopped, status, |
| server_if, srvc_handle); |
| checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); |
| } |
| |
| void btgatts_service_deleted_cb(int status, int server_if, int srvc_handle) |
| { |
| CHECK_CALLBACK_ENV |
| sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onServiceDeleted, status, |
| server_if, srvc_handle); |
| checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); |
| } |
| |
| void btgatts_request_read_cb(int conn_id, int trans_id, bt_bdaddr_t *bda, |
| int attr_handle, int offset, bool is_long) |
| { |
| CHECK_CALLBACK_ENV |
| |
| char c_address[32]; |
| sprintf(c_address, "%02X:%02X:%02X:%02X:%02X:%02X", |
| bda->address[0], bda->address[1], bda->address[2], |
| bda->address[3], bda->address[4], bda->address[5]); |
| |
| jstring address = sCallbackEnv->NewStringUTF(c_address); |
| sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onAttributeRead, |
| address, conn_id, trans_id, attr_handle, |
| offset, is_long); |
| sCallbackEnv->DeleteLocalRef(address); |
| checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); |
| } |
| |
| void btgatts_request_write_cb(int conn_id, int trans_id, |
| bt_bdaddr_t *bda, int attr_handle, |
| int offset, int length, |
| bool need_rsp, bool is_prep, uint8_t* value) |
| { |
| CHECK_CALLBACK_ENV |
| |
| char c_address[32]; |
| sprintf(c_address, "%02X:%02X:%02X:%02X:%02X:%02X", |
| bda->address[0], bda->address[1], bda->address[2], |
| bda->address[3], bda->address[4], bda->address[5]); |
| |
| jstring address = sCallbackEnv->NewStringUTF(c_address); |
| |
| jbyteArray val = sCallbackEnv->NewByteArray(length); |
| if (val) sCallbackEnv->SetByteArrayRegion(val, 0, length, (jbyte*)value); |
| sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onAttributeWrite, |
| address, conn_id, trans_id, attr_handle, |
| offset, length, need_rsp, is_prep, val); |
| sCallbackEnv->DeleteLocalRef(address); |
| sCallbackEnv->DeleteLocalRef(val); |
| checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); |
| } |
| |
| void btgatts_request_exec_write_cb(int conn_id, int trans_id, |
| bt_bdaddr_t *bda, int exec_write) |
| { |
| CHECK_CALLBACK_ENV |
| |
| char c_address[32]; |
| sprintf(c_address, "%02X:%02X:%02X:%02X:%02X:%02X", |
| bda->address[0], bda->address[1], bda->address[2], |
| bda->address[3], bda->address[4], bda->address[5]); |
| |
| jstring address = sCallbackEnv->NewStringUTF(c_address); |
| sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onExecuteWrite, |
| address, conn_id, trans_id, exec_write); |
| sCallbackEnv->DeleteLocalRef(address); |
| checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); |
| } |
| |
| void btgatts_response_confirmation_cb(int status, int handle) |
| { |
| CHECK_CALLBACK_ENV |
| sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onResponseSendCompleted, |
| status, handle); |
| checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); |
| } |
| |
| static const btgatt_server_callbacks_t sGattServerCallbacks = { |
| btgatts_register_app_cb, |
| btgatts_connection_cb, |
| btgatts_service_added_cb, |
| btgatts_included_service_added_cb, |
| btgatts_characteristic_added_cb, |
| btgatts_descriptor_added_cb, |
| btgatts_service_started_cb, |
| btgatts_service_stopped_cb, |
| btgatts_service_deleted_cb, |
| btgatts_request_read_cb, |
| btgatts_request_write_cb, |
| btgatts_request_exec_write_cb, |
| btgatts_response_confirmation_cb |
| }; |
| |
| /** |
| * GATT callbacks |
| */ |
| |
| static const btgatt_callbacks_t sGattCallbacks = { |
| sizeof(btgatt_callbacks_t), |
| &sGattClientCallbacks, |
| &sGattServerCallbacks |
| }; |
| |
| /** |
| * Native function definitions |
| */ |
| |
| static void classInitNative(JNIEnv* env, jclass clazz) { |
| |
| // Client callbacks |
| |
| method_onClientRegistered = env->GetMethodID(clazz, "onClientRegistered", "(IIJJ)V"); |
| method_onScanResult = env->GetMethodID(clazz, "onScanResult", "(Ljava/lang/String;I[B)V"); |
| method_onConnected = env->GetMethodID(clazz, "onConnected", "(IIILjava/lang/String;)V"); |
| method_onDisconnected = env->GetMethodID(clazz, "onDisconnected", "(IIILjava/lang/String;)V"); |
| method_onReadCharacteristic = env->GetMethodID(clazz, "onReadCharacteristic", "(IIIIJJIJJI[B)V"); |
| method_onWriteCharacteristic = env->GetMethodID(clazz, "onWriteCharacteristic", "(IIIIJJIJJ)V"); |
| method_onExecuteCompleted = env->GetMethodID(clazz, "onExecuteCompleted", "(II)V"); |
| method_onSearchCompleted = env->GetMethodID(clazz, "onSearchCompleted", "(II)V"); |
| method_onSearchResult = env->GetMethodID(clazz, "onSearchResult", "(IIIJJ)V"); |
| method_onReadDescriptor = env->GetMethodID(clazz, "onReadDescriptor", "(IIIIJJIJJJJI[B)V"); |
| method_onWriteDescriptor = env->GetMethodID(clazz, "onWriteDescriptor", "(IIIIJJIJJJJ)V"); |
| method_onNotify = env->GetMethodID(clazz, "onNotify", "(ILjava/lang/String;IIJJIJJZ[B)V"); |
| method_onGetCharacteristic = env->GetMethodID(clazz, "onGetCharacteristic", "(IIIIJJIJJI)V"); |
| method_onGetDescriptor = env->GetMethodID(clazz, "onGetDescriptor", "(IIIIJJIJJJJ)V"); |
| method_onGetIncludedService = env->GetMethodID(clazz, "onGetIncludedService", "(IIIIJJIIJJ)V"); |
| method_onRegisterForNotifications = env->GetMethodID(clazz, "onRegisterForNotifications", "(IIIIIJJIJJ)V"); |
| method_onReadRemoteRssi = env->GetMethodID(clazz, "onReadRemoteRssi", "(ILjava/lang/String;II)V"); |
| |
| // Server callbacks |
| |
| method_onServerRegistered = env->GetMethodID(clazz, "onServerRegistered", "(IIJJ)V"); |
| method_onClientConnected = env->GetMethodID(clazz, "onClientConnected", "(Ljava/lang/String;ZI)V"); |
| method_onServiceAdded = env->GetMethodID(clazz, "onServiceAdded", "(IIIIJJI)V"); |
| method_onIncludedServiceAdded = env->GetMethodID(clazz, "onIncludedServiceAdded", "(IIII)V"); |
| method_onCharacteristicAdded = env->GetMethodID(clazz, "onCharacteristicAdded", "(IIJJII)V"); |
| method_onDescriptorAdded = env->GetMethodID(clazz, "onDescriptorAdded", "(IIJJII)V"); |
| method_onServiceStarted = env->GetMethodID(clazz, "onServiceStarted", "(III)V"); |
| method_onServiceStopped = env->GetMethodID(clazz, "onServiceStopped", "(III)V"); |
| method_onServiceDeleted = env->GetMethodID(clazz, "onServiceDeleted", "(III)V"); |
| method_onResponseSendCompleted = env->GetMethodID(clazz, "onResponseSendCompleted", "(II)V"); |
| method_onAttributeRead= env->GetMethodID(clazz, "onAttributeRead", "(Ljava/lang/String;IIIIZ)V"); |
| method_onAttributeWrite= env->GetMethodID(clazz, "onAttributeWrite", "(Ljava/lang/String;IIIIIZZ[B)V"); |
| method_onExecuteWrite= env->GetMethodID(clazz, "onExecuteWrite", "(Ljava/lang/String;III)V"); |
| |
| info("classInitNative: Success!"); |
| } |
| |
| static const bt_interface_t* btIf; |
| |
| static void initializeNative(JNIEnv *env, jobject object) { |
| if(btIf) |
| return; |
| |
| if ( (btIf = getBluetoothInterface()) == NULL) { |
| error("Bluetooth module is not loaded"); |
| return; |
| } |
| |
| if (sGattIf != NULL) { |
| ALOGW("Cleaning up Bluetooth GATT Interface before initializing..."); |
| sGattIf->cleanup(); |
| sGattIf = NULL; |
| } |
| |
| if (mCallbacksObj != NULL) { |
| ALOGW("Cleaning up Bluetooth GATT callback object"); |
| env->DeleteGlobalRef(mCallbacksObj); |
| mCallbacksObj = NULL; |
| } |
| |
| if ( (sGattIf = (btgatt_interface_t *) |
| btIf->get_profile_interface(BT_PROFILE_GATT_ID)) == NULL) { |
| error("Failed to get Bluetooth GATT Interface"); |
| return; |
| } |
| |
| bt_status_t status; |
| if ( (status = sGattIf->init(&sGattCallbacks)) != BT_STATUS_SUCCESS) { |
| error("Failed to initialize Bluetooth GATT, status: %d", status); |
| sGattIf = NULL; |
| return; |
| } |
| |
| mCallbacksObj = env->NewGlobalRef(object); |
| } |
| |
| static void cleanupNative(JNIEnv *env, jobject object) { |
| bt_status_t status; |
| if (!btIf) return; |
| |
| if (sGattIf != NULL) { |
| sGattIf->cleanup(); |
| sGattIf = NULL; |
| } |
| |
| if (mCallbacksObj != NULL) { |
| env->DeleteGlobalRef(mCallbacksObj); |
| mCallbacksObj = NULL; |
| } |
| btIf = NULL; |
| } |
| |
| /** |
| * Native Client functions |
| */ |
| |
| static int gattClientGetDeviceTypeNative(JNIEnv* env, jobject object, jstring address) |
| { |
| if (!sGattIf) return 0; |
| bt_bdaddr_t bda; |
| jstr2bdaddr(env, &bda, address); |
| return sGattIf->client->get_device_type(&bda); |
| } |
| |
| static void gattClientRegisterAppNative(JNIEnv* env, jobject object, |
| jlong app_uuid_lsb, jlong app_uuid_msb ) |
| { |
| bt_uuid_t uuid; |
| |
| if (!sGattIf) return; |
| set_uuid(uuid.uu, app_uuid_msb, app_uuid_lsb); |
| sGattIf->client->register_client(&uuid); |
| } |
| |
| static void gattClientUnregisterAppNative(JNIEnv* env, jobject object, jint clientIf) |
| { |
| if (!sGattIf) return; |
| sGattIf->client->unregister_client(clientIf); |
| } |
| |
| static void gattClientScanNative(JNIEnv* env, jobject object, jint clientIf, jboolean start) |
| { |
| if (!sGattIf) return; |
| sGattIf->client->scan(clientIf, start); |
| } |
| |
| static void gattClientConnectNative(JNIEnv* env, jobject object, jint clientif, |
| jstring address, jboolean isDirect) |
| { |
| if (!sGattIf) return; |
| |
| bt_bdaddr_t bda; |
| jstr2bdaddr(env, &bda, address); |
| sGattIf->client->connect(clientif, &bda, isDirect); |
| } |
| |
| static void gattClientDisconnectNative(JNIEnv* env, jobject object, jint clientIf, |
| jstring address, jint conn_id) |
| { |
| if (!sGattIf) return; |
| bt_bdaddr_t bda; |
| jstr2bdaddr(env, &bda, address); |
| sGattIf->client->disconnect(clientIf, &bda, conn_id); |
| } |
| |
| static void gattClientRefreshNative(JNIEnv* env, jobject object, jint clientIf, |
| jstring address) |
| { |
| if (!sGattIf) return; |
| |
| bt_bdaddr_t bda; |
| jstr2bdaddr(env, &bda, address); |
| sGattIf->client->refresh(clientIf, &bda); |
| } |
| |
| static void gattClientSearchServiceNative(JNIEnv* env, jobject object, jint conn_id, |
| jboolean search_all, jlong service_uuid_lsb, jlong service_uuid_msb) |
| { |
| if (!sGattIf) return; |
| |
| bt_uuid_t uuid; |
| set_uuid(uuid.uu, service_uuid_msb, service_uuid_lsb); |
| sGattIf->client->search_service(conn_id, search_all ? 0 : &uuid); |
| } |
| |
| static void gattClientGetCharacteristicNative(JNIEnv* env, jobject object, |
| jint conn_id, |
| jint service_type, jint service_id_inst_id, |
| jlong service_id_uuid_lsb, jlong service_id_uuid_msb, |
| jint char_id_inst_id, |
| jlong char_id_uuid_lsb, jlong char_id_uuid_msb) |
| { |
| if (!sGattIf) return; |
| |
| btgatt_srvc_id_t srvc_id; |
| srvc_id.id.inst_id = (uint8_t) service_id_inst_id; |
| srvc_id.is_primary = (service_type == BTGATT_SERVICE_TYPE_PRIMARY ? 1 : 0); |
| |
| set_uuid(srvc_id.id.uuid.uu, service_id_uuid_msb, service_id_uuid_lsb); |
| |
| btgatt_char_id_t char_id; |
| char_id.inst_id = (uint8_t) char_id_inst_id; |
| set_uuid(char_id.uuid.uu, char_id_uuid_msb, char_id_uuid_lsb); |
| |
| if (char_id_uuid_lsb == 0) |
| { |
| sGattIf->client->get_characteristic(conn_id, &srvc_id, 0); |
| } else { |
| sGattIf->client->get_characteristic(conn_id, &srvc_id, &char_id); |
| } |
| } |
| |
| static void gattClientGetDescriptorNative(JNIEnv* env, jobject object, |
| jint conn_id, |
| jint service_type, jint service_id_inst_id, |
| jlong service_id_uuid_lsb, jlong service_id_uuid_msb, |
| jint char_id_inst_id, |
| jlong char_id_uuid_lsb, jlong char_id_uuid_msb, |
| jlong descr_id_uuid_lsb, jlong descr_id_uuid_msb) |
| { |
| if (!sGattIf) return; |
| |
| btgatt_srvc_id_t srvc_id; |
| srvc_id.id.inst_id = (uint8_t) service_id_inst_id; |
| srvc_id.is_primary = (service_type == BTGATT_SERVICE_TYPE_PRIMARY ? 1 : 0); |
| set_uuid(srvc_id.id.uuid.uu, service_id_uuid_msb, service_id_uuid_lsb); |
| |
| btgatt_char_id_t char_id; |
| char_id.inst_id = (uint8_t) char_id_inst_id; |
| set_uuid(char_id.uuid.uu, char_id_uuid_msb, char_id_uuid_lsb); |
| |
| bt_uuid_t descr_id; |
| set_uuid(descr_id.uu, descr_id_uuid_msb, descr_id_uuid_lsb); |
| |
| if (descr_id_uuid_lsb == 0) |
| { |
| sGattIf->client->get_descriptor(conn_id, &srvc_id, &char_id, 0); |
| } else { |
| sGattIf->client->get_descriptor(conn_id, &srvc_id, &char_id, &descr_id); |
| } |
| } |
| |
| static void gattClientGetIncludedServiceNative(JNIEnv* env, jobject object, |
| jint conn_id, jint service_type, jint service_id_inst_id, |
| jlong service_id_uuid_lsb, jlong service_id_uuid_msb, |
| jint incl_service_id_inst_id, jint incl_service_type, |
| jlong incl_service_id_uuid_lsb, jlong incl_service_id_uuid_msb) |
| { |
| if (!sGattIf) return; |
| |
| btgatt_srvc_id_t srvc_id; |
| srvc_id.id.inst_id = (uint8_t) service_id_inst_id; |
| srvc_id.is_primary = (service_type == BTGATT_SERVICE_TYPE_PRIMARY ? 1 : 0); |
| set_uuid(srvc_id.id.uuid.uu, service_id_uuid_msb, service_id_uuid_lsb); |
| |
| btgatt_srvc_id_t incl_srvc_id; |
| incl_srvc_id.id.inst_id = (uint8_t) incl_service_id_inst_id; |
| incl_srvc_id.is_primary = (incl_service_type == BTGATT_SERVICE_TYPE_PRIMARY ? 1 : 0); |
| set_uuid(incl_srvc_id.id.uuid.uu, incl_service_id_uuid_msb, incl_service_id_uuid_lsb); |
| |
| if (incl_service_id_uuid_lsb == 0) |
| { |
| sGattIf->client->get_included_service(conn_id, &srvc_id, 0); |
| } else { |
| sGattIf->client->get_included_service(conn_id, &srvc_id, &incl_srvc_id); |
| } |
| } |
| |
| static void gattClientReadCharacteristicNative(JNIEnv* env, jobject object, |
| jint conn_id, jint service_type, jint service_id_inst_id, |
| jlong service_id_uuid_lsb, jlong service_id_uuid_msb, |
| jint char_id_inst_id, |
| jlong char_id_uuid_lsb, jlong char_id_uuid_msb, |
| jint authReq) |
| { |
| if (!sGattIf) return; |
| |
| btgatt_srvc_id_t srvc_id; |
| srvc_id.id.inst_id = (uint8_t) service_id_inst_id; |
| srvc_id.is_primary = (service_type == BTGATT_SERVICE_TYPE_PRIMARY ? 1 : 0); |
| set_uuid(srvc_id.id.uuid.uu, service_id_uuid_msb, service_id_uuid_lsb); |
| |
| btgatt_char_id_t char_id; |
| char_id.inst_id = (uint8_t) char_id_inst_id; |
| set_uuid(char_id.uuid.uu, char_id_uuid_msb, char_id_uuid_lsb); |
| |
| sGattIf->client->read_characteristic(conn_id, &srvc_id, &char_id, authReq); |
| } |
| |
| static void gattClientReadDescriptorNative(JNIEnv* env, jobject object, |
| jint conn_id, jint service_type, jint service_id_inst_id, |
| jlong service_id_uuid_lsb, jlong service_id_uuid_msb, |
| jint char_id_inst_id, |
| jlong char_id_uuid_lsb, jlong char_id_uuid_msb, |
| jlong descr_id_uuid_lsb, jlong descr_id_uuid_msb, |
| jint authReq) |
| { |
| if (!sGattIf) return; |
| |
| btgatt_srvc_id_t srvc_id; |
| srvc_id.id.inst_id = (uint8_t) service_id_inst_id; |
| srvc_id.is_primary = (service_type == BTGATT_SERVICE_TYPE_PRIMARY ? 1 : 0); |
| set_uuid(srvc_id.id.uuid.uu, service_id_uuid_msb, service_id_uuid_lsb); |
| |
| btgatt_char_id_t char_id; |
| char_id.inst_id = (uint8_t) char_id_inst_id; |
| set_uuid(char_id.uuid.uu, char_id_uuid_msb, char_id_uuid_lsb); |
| |
| bt_uuid_t descr_id; |
| set_uuid(descr_id.uu, descr_id_uuid_msb, descr_id_uuid_lsb); |
| |
| sGattIf->client->read_descriptor(conn_id, &srvc_id, &char_id, &descr_id, authReq); |
| } |
| |
| static void gattClientWriteCharacteristicNative(JNIEnv* env, jobject object, |
| jint conn_id, jint service_type, jint service_id_inst_id, |
| jlong service_id_uuid_lsb, jlong service_id_uuid_msb, |
| jint char_id_inst_id, |
| jlong char_id_uuid_lsb, jlong char_id_uuid_msb, |
| jint write_type, jint auth_req, jbyteArray value) |
| { |
| if (!sGattIf) return; |
| |
| btgatt_srvc_id_t srvc_id; |
| srvc_id.id.inst_id = (uint8_t) service_id_inst_id; |
| srvc_id.is_primary = (service_type == BTGATT_SERVICE_TYPE_PRIMARY ? 1 : 0); |
| set_uuid(srvc_id.id.uuid.uu, service_id_uuid_msb, service_id_uuid_lsb); |
| |
| btgatt_char_id_t char_id; |
| char_id.inst_id = (uint8_t) char_id_inst_id; |
| set_uuid(char_id.uuid.uu, char_id_uuid_msb, char_id_uuid_lsb); |
| |
| uint16_t len = (uint16_t) env->GetArrayLength(value); |
| jbyte *p_value = env->GetByteArrayElements(value, NULL); |
| if (p_value == NULL) return; |
| |
| sGattIf->client->write_characteristic(conn_id, &srvc_id, &char_id, |
| write_type, len, auth_req, (char*)p_value); |
| env->ReleaseByteArrayElements(value, p_value, 0); |
| } |
| |
| static void gattClientExecuteWriteNative(JNIEnv* env, jobject object, |
| jint conn_id, jboolean execute) |
| { |
| if (!sGattIf) return; |
| sGattIf->client->execute_write(conn_id, execute ? 1 : 0); |
| } |
| |
| static void gattClientWriteDescriptorNative(JNIEnv* env, jobject object, |
| jint conn_id, jint service_type, jint service_id_inst_id, |
| jlong service_id_uuid_lsb, jlong service_id_uuid_msb, |
| jint char_id_inst_id, |
| jlong char_id_uuid_lsb, jlong char_id_uuid_msb, |
| jlong descr_id_uuid_lsb, jlong descr_id_uuid_msb, |
| jint write_type, jint auth_req, jbyteArray value) |
| { |
| if (!sGattIf) return; |
| |
| btgatt_srvc_id_t srvc_id; |
| srvc_id.id.inst_id = (uint8_t) service_id_inst_id; |
| srvc_id.is_primary = (service_type == BTGATT_SERVICE_TYPE_PRIMARY ? 1 : 0); |
| set_uuid(srvc_id.id.uuid.uu, service_id_uuid_msb, service_id_uuid_lsb); |
| |
| btgatt_char_id_t char_id; |
| char_id.inst_id = (uint8_t) char_id_inst_id; |
| set_uuid(char_id.uuid.uu, char_id_uuid_msb, char_id_uuid_lsb); |
| |
| bt_uuid_t descr_id; |
| set_uuid(descr_id.uu, descr_id_uuid_msb, descr_id_uuid_lsb); |
| |
| uint16_t len = (uint16_t) env->GetArrayLength(value); |
| jbyte *p_value = env->GetByteArrayElements(value, NULL); |
| if (p_value == NULL) return; |
| |
| sGattIf->client->write_descriptor(conn_id, &srvc_id, &char_id, &descr_id, |
| write_type, len, auth_req, (char*)p_value); |
| env->ReleaseByteArrayElements(value, p_value, 0); |
| } |
| |
| static void gattClientRegisterForNotificationsNative(JNIEnv* env, jobject object, |
| jint clientIf, jstring address, |
| jint service_type, jint service_id_inst_id, |
| jlong service_id_uuid_lsb, jlong service_id_uuid_msb, |
| jint char_id_inst_id, |
| jlong char_id_uuid_lsb, jlong char_id_uuid_msb, |
| jboolean enable) |
| { |
| if (!sGattIf) return; |
| |
| btgatt_srvc_id_t srvc_id; |
| srvc_id.id.inst_id = (uint8_t) service_id_inst_id; |
| srvc_id.is_primary = (service_type == BTGATT_SERVICE_TYPE_PRIMARY ? 1 : 0); |
| set_uuid(srvc_id.id.uuid.uu, service_id_uuid_msb, service_id_uuid_lsb); |
| |
| btgatt_char_id_t char_id; |
| char_id.inst_id = (uint8_t) char_id_inst_id; |
| set_uuid(char_id.uuid.uu, char_id_uuid_msb, char_id_uuid_lsb); |
| |
| bt_bdaddr_t bd_addr; |
| const char *c_address = env->GetStringUTFChars(address, NULL); |
| bd_addr_str_to_addr(c_address, bd_addr.address); |
| |
| if (enable) |
| sGattIf->client->register_for_notification(clientIf, &bd_addr, &srvc_id, &char_id); |
| else |
| sGattIf->client->deregister_for_notification(clientIf, &bd_addr, &srvc_id, &char_id); |
| } |
| |
| static void gattClientReadRemoteRssiNative(JNIEnv* env, jobject object, jint clientif, |
| jstring address) |
| { |
| if (!sGattIf) return; |
| |
| bt_bdaddr_t bda; |
| jstr2bdaddr(env, &bda, address); |
| |
| sGattIf->client->read_remote_rssi(clientif, &bda); |
| } |
| |
| |
| /** |
| * Native server functions |
| */ |
| static void gattServerRegisterAppNative(JNIEnv* env, jobject object, |
| jlong app_uuid_lsb, jlong app_uuid_msb ) |
| { |
| bt_uuid_t uuid; |
| if (!sGattIf) return; |
| set_uuid(uuid.uu, app_uuid_msb, app_uuid_lsb); |
| sGattIf->server->register_server(&uuid); |
| } |
| |
| static void gattServerUnregisterAppNative(JNIEnv* env, jobject object, jint serverIf) |
| { |
| if (!sGattIf) return; |
| sGattIf->server->unregister_server(serverIf); |
| } |
| |
| static void gattServerConnectNative(JNIEnv *env, jobject object, |
| jint server_if, jstring address, jboolean is_direct) |
| { |
| if (!sGattIf) return; |
| |
| bt_bdaddr_t bd_addr; |
| const char *c_address = env->GetStringUTFChars(address, NULL); |
| bd_addr_str_to_addr(c_address, bd_addr.address); |
| |
| sGattIf->server->connect(server_if, &bd_addr, is_direct); |
| } |
| |
| static void gattServerDisconnectNative(JNIEnv* env, jobject object, jint serverIf, |
| jstring address, jint conn_id) |
| { |
| if (!sGattIf) return; |
| bt_bdaddr_t bda; |
| jstr2bdaddr(env, &bda, address); |
| sGattIf->server->disconnect(serverIf, &bda, conn_id); |
| } |
| |
| static void gattServerAddServiceNative (JNIEnv *env, jobject object, |
| jint server_if, jint service_type, jint service_id_inst_id, |
| jlong service_id_uuid_lsb, jlong service_id_uuid_msb, |
| jint num_handles) |
| { |
| if (!sGattIf) return; |
| |
| btgatt_srvc_id_t srvc_id; |
| srvc_id.id.inst_id = (uint8_t) service_id_inst_id; |
| srvc_id.is_primary = (service_type == BTGATT_SERVICE_TYPE_PRIMARY ? 1 : 0); |
| set_uuid(srvc_id.id.uuid.uu, service_id_uuid_msb, service_id_uuid_lsb); |
| |
| sGattIf->server->add_service(server_if, &srvc_id, num_handles); |
| } |
| |
| static void gattServerAddIncludedServiceNative (JNIEnv *env, jobject object, |
| jint server_if, jint svc_handle, jint included_svc_handle) |
| { |
| if (!sGattIf) return; |
| sGattIf->server->add_included_service(server_if, svc_handle, |
| included_svc_handle); |
| } |
| |
| static void gattServerAddCharacteristicNative (JNIEnv *env, jobject object, |
| jint server_if, jint svc_handle, |
| jlong char_uuid_lsb, jlong char_uuid_msb, |
| jint properties, jint permissions) |
| { |
| if (!sGattIf) return; |
| |
| bt_uuid_t uuid; |
| set_uuid(uuid.uu, char_uuid_msb, char_uuid_lsb); |
| |
| sGattIf->server->add_characteristic(server_if, svc_handle, |
| &uuid, properties, permissions); |
| } |
| |
| static void gattServerAddDescriptorNative (JNIEnv *env, jobject object, |
| jint server_if, jint svc_handle, |
| jlong desc_uuid_lsb, jlong desc_uuid_msb, |
| jint permissions) |
| { |
| if (!sGattIf) return; |
| |
| bt_uuid_t uuid; |
| set_uuid(uuid.uu, desc_uuid_msb, desc_uuid_lsb); |
| |
| sGattIf->server->add_descriptor(server_if, svc_handle, &uuid, permissions); |
| } |
| |
| static void gattServerStartServiceNative (JNIEnv *env, jobject object, |
| jint server_if, jint svc_handle, jint transport ) |
| { |
| if (!sGattIf) return; |
| sGattIf->server->start_service(server_if, svc_handle, transport); |
| } |
| |
| static void gattServerStopServiceNative (JNIEnv *env, jobject object, |
| jint server_if, jint svc_handle) |
| { |
| if (!sGattIf) return; |
| sGattIf->server->stop_service(server_if, svc_handle); |
| } |
| |
| static void gattServerDeleteServiceNative (JNIEnv *env, jobject object, |
| jint server_if, jint svc_handle) |
| { |
| if (!sGattIf) return; |
| sGattIf->server->delete_service(server_if, svc_handle); |
| } |
| |
| static void gattServerSendIndicationNative (JNIEnv *env, jobject object, |
| jint server_if, jint attr_handle, jint conn_id, jbyteArray val) |
| { |
| if (!sGattIf) return; |
| |
| jbyte* array = env->GetByteArrayElements(val, 0); |
| int val_len = env->GetArrayLength(val); |
| |
| sGattIf->server->send_indication(server_if, attr_handle, conn_id, val_len, |
| /*confirm*/ 1, (char*)array); |
| env->ReleaseByteArrayElements(val, array, JNI_ABORT); |
| } |
| |
| static void gattServerSendNotificationNative (JNIEnv *env, jobject object, |
| jint server_if, jint attr_handle, jint conn_id, jbyteArray val) |
| { |
| if (!sGattIf) return; |
| |
| jbyte* array = env->GetByteArrayElements(val, 0); |
| int val_len = env->GetArrayLength(val); |
| |
| sGattIf->server->send_indication(server_if, attr_handle, conn_id, val_len, |
| /*confirm*/ 0, (char*)array); |
| env->ReleaseByteArrayElements(val, array, JNI_ABORT); |
| } |
| |
| static void gattServerSendResponseNative (JNIEnv *env, jobject object, |
| jint server_if, jint conn_id, jint trans_id, jint status, |
| jint handle, jint offset, jbyteArray val, jint auth_req) |
| { |
| if (!sGattIf) return; |
| |
| btgatt_response_t response; |
| |
| response.attr_value.handle = handle; |
| response.attr_value.auth_req = auth_req; |
| response.attr_value.offset = offset; |
| response.attr_value.len = 0; |
| |
| if (val != NULL) |
| { |
| response.attr_value.len = (uint16_t) env->GetArrayLength(val); |
| jbyte* array = env->GetByteArrayElements(val, 0); |
| |
| for (int i = 0; i != response.attr_value.len; ++i) |
| response.attr_value.value[i] = (uint8_t) array[i]; |
| env->ReleaseByteArrayElements(val, array, JNI_ABORT); |
| } |
| |
| sGattIf->server->send_response(conn_id, trans_id, status, &response); |
| } |
| |
| static void gattTestNative(JNIEnv *env, jobject object, jint command, |
| jlong uuid1_lsb, jlong uuid1_msb, jstring bda1, |
| jint p1, jint p2, jint p3, jint p4, jint p5 ) |
| { |
| if (!sGattIf) return; |
| |
| bt_bdaddr_t bt_bda1; |
| jstr2bdaddr(env, &bt_bda1, bda1); |
| |
| bt_uuid_t uuid1; |
| set_uuid(uuid1.uu, uuid1_msb, uuid1_lsb); |
| |
| btgatt_test_params_t params; |
| params.bda1 = &bt_bda1; |
| params.uuid1 = &uuid1; |
| params.u1 = p1; |
| params.u2 = p2; |
| params.u3 = p3; |
| params.u4 = p4; |
| params.u5 = p5; |
| sGattIf->client->test_command(command, ¶ms); |
| } |
| |
| /** |
| * JNI function definitinos |
| */ |
| |
| static JNINativeMethod sMethods[] = { |
| {"classInitNative", "()V", (void *) classInitNative}, |
| {"initializeNative", "()V", (void *) initializeNative}, |
| {"cleanupNative", "()V", (void *) cleanupNative}, |
| |
| {"gattClientGetDeviceTypeNative", "(Ljava/lang/String;)I", (void *) gattClientGetDeviceTypeNative}, |
| {"gattClientRegisterAppNative", "(JJ)V", (void *) gattClientRegisterAppNative}, |
| {"gattClientUnregisterAppNative", "(I)V", (void *) gattClientUnregisterAppNative}, |
| {"gattClientScanNative", "(IZ)V", (void *) gattClientScanNative}, |
| {"gattClientConnectNative", "(ILjava/lang/String;Z)V", (void *) gattClientConnectNative}, |
| {"gattClientDisconnectNative", "(ILjava/lang/String;I)V", (void *) gattClientDisconnectNative}, |
| {"gattClientRefreshNative", "(ILjava/lang/String;)V", (void *) gattClientRefreshNative}, |
| {"gattClientSearchServiceNative", "(IZJJ)V", (void *) gattClientSearchServiceNative}, |
| {"gattClientGetCharacteristicNative", "(IIIJJIJJ)V", (void *) gattClientGetCharacteristicNative}, |
| {"gattClientGetDescriptorNative", "(IIIJJIJJJJ)V", (void *) gattClientGetDescriptorNative}, |
| {"gattClientGetIncludedServiceNative", "(IIIJJIIJJ)V", (void *) gattClientGetIncludedServiceNative}, |
| {"gattClientReadCharacteristicNative", "(IIIJJIJJI)V", (void *) gattClientReadCharacteristicNative}, |
| {"gattClientReadDescriptorNative", "(IIIJJIJJJJI)V", (void *) gattClientReadDescriptorNative}, |
| {"gattClientWriteCharacteristicNative", "(IIIJJIJJII[B)V", (void *) gattClientWriteCharacteristicNative}, |
| {"gattClientWriteDescriptorNative", "(IIIJJIJJJJII[B)V", (void *) gattClientWriteDescriptorNative}, |
| {"gattClientExecuteWriteNative", "(IZ)V", (void *) gattClientExecuteWriteNative}, |
| {"gattClientRegisterForNotificationsNative", "(ILjava/lang/String;IIJJIJJZ)V", (void *) gattClientRegisterForNotificationsNative}, |
| {"gattClientReadRemoteRssiNative", "(ILjava/lang/String;)V", (void *) gattClientReadRemoteRssiNative}, |
| |
| {"gattServerRegisterAppNative", "(JJ)V", (void *) gattServerRegisterAppNative}, |
| {"gattServerUnregisterAppNative", "(I)V", (void *) gattServerUnregisterAppNative}, |
| {"gattServerConnectNative", "(ILjava/lang/String;Z)V", (void *) gattServerConnectNative}, |
| {"gattServerDisconnectNative", "(ILjava/lang/String;I)V", (void *) gattServerDisconnectNative}, |
| {"gattServerAddServiceNative", "(IIIJJI)V", (void *) gattServerAddServiceNative}, |
| {"gattServerAddIncludedServiceNative", "(III)V", (void *) gattServerAddIncludedServiceNative}, |
| {"gattServerAddCharacteristicNative", "(IIJJII)V", (void *) gattServerAddCharacteristicNative}, |
| {"gattServerAddDescriptorNative", "(IIJJI)V", (void *) gattServerAddDescriptorNative}, |
| {"gattServerStartServiceNative", "(III)V", (void *) gattServerStartServiceNative}, |
| {"gattServerStopServiceNative", "(II)V", (void *) gattServerStopServiceNative}, |
| {"gattServerDeleteServiceNative", "(II)V", (void *) gattServerDeleteServiceNative}, |
| {"gattServerSendIndicationNative", "(III[B)V", (void *) gattServerSendIndicationNative}, |
| {"gattServerSendNotificationNative", "(III[B)V", (void *) gattServerSendNotificationNative}, |
| {"gattServerSendResponseNative", "(IIIIII[BI)V", (void *) gattServerSendResponseNative}, |
| |
| {"gattTestNative", "(IJJLjava/lang/String;IIIII)V", (void *) gattTestNative}, |
| }; |
| |
| int register_com_android_bluetooth_gatt(JNIEnv* env) |
| { |
| return jniRegisterNativeMethods(env, "com/android/bluetooth/gatt/GattService", |
| sMethods, NELEM(sMethods)); |
| } |
| |
| } |