/*
* 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 LOG_TAG "BtGatt.JNI"
#define LOG_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 GATT_ID_PARAMS(attr_ptr) \
attr_ptr->inst_id, \
UUID_PARAMS((&attr_ptr->uuid))
#define SRVC_ID_PARAMS(srvc_ptr) \
(srvc_ptr->is_primary ? \
BTGATT_SERVICE_TYPE_PRIMARY : BTGATT_SERVICE_TYPE_SECONDARY), \
GATT_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;
static jmethodID method_onAdvertiseCallback;
/**
* 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_gatt_id_t *char_id,
int char_prop)
{
CHECK_CALLBACK_ENV
sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onGetCharacteristic
, conn_id, status, SRVC_ID_PARAMS(srvc_id), GATT_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_gatt_id_t *char_id,
btgatt_gatt_id_t *descr_id)
{
CHECK_CALLBACK_ENV
sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onGetDescriptor
, conn_id, status, SRVC_ID_PARAMS(srvc_id), GATT_ID_PARAMS(char_id)
, GATT_ID_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_gatt_id_t *char_id)
{
CHECK_CALLBACK_ENV
sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onRegisterForNotifications
, conn_id, status, registered, SRVC_ID_PARAMS(srvc_id), GATT_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))
, GATT_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))
, GATT_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))
, GATT_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))
, GATT_ID_PARAMS((&p_data->char_id)), GATT_ID_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))
, GATT_ID_PARAMS((&p_data->char_id))
, GATT_ID_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__);
}
void btgattc_advertise_cb(int status, int client_if)
{
CHECK_CALLBACK_ENV
sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onAdvertiseCallback, status, client_if);
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,
btgattc_advertise_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 server_if, 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, server_if);
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", "(IIIIJJIJJIJJI[B)V");
method_onWriteDescriptor = env->GetMethodID(clazz, "onWriteDescriptor", "(IIIIJJIJJIJJ)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", "(IIIIJJIJJIJJ)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;ZII)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");
method_onAdvertiseCallback = env->GetMethodID(clazz, "onAdvertiseCallback", "(II)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_gatt_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,
jint descr_id_inst_id,
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_gatt_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);
btgatt_gatt_id_t descr_id;
descr_id.inst_id = (uint8_t) descr_id_inst_id;
set_uuid(descr_id.uuid.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_gatt_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,
jint descr_id_inst_id,
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_gatt_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);
btgatt_gatt_id_t descr_id;
descr_id.inst_id = (uint8_t) descr_id_inst_id;
set_uuid(descr_id.uuid.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_gatt_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,
jint descr_id_inst_id,
jlong descr_id_uuid_lsb, jlong descr_id_uuid_msb,
jint write_type, jint auth_req, jbyteArray value)
{
if (!sGattIf) return;
if (value == NULL) {
warn("gattClientWriteDescriptorNative() ignoring NULL array");
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_gatt_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);
btgatt_gatt_id_t descr_id;
descr_id.inst_id = (uint8_t) descr_id_inst_id;
set_uuid(descr_id.uuid.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_gatt_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);
}
static void gattAdvertiseNative(JNIEnv *env, jobject object,
jint client_if, jboolean start)
{
if (!sGattIf) return;
sGattIf->client->listen(client_if, start);
}
static void gattSetAdvDataNative(JNIEnv *env, jobject object, jint client_if, jboolean setScanRsp,
jboolean inclName, jboolean inclTxPower, jint minInterval, jint maxInterval,
jint appearance, jbyteArray manufacturerData, jbyteArray serviceData,
jbyteArray serviceUuid)
{
if (!sGattIf) return;
jbyte* arr_data = env->GetByteArrayElements(manufacturerData, NULL);
uint16_t arr_len = (uint16_t) env->GetArrayLength(manufacturerData);
jbyte* service_data = env->GetByteArrayElements(serviceData, NULL);
uint16_t service_data_len = (uint16_t) env->GetArrayLength(serviceData);
jbyte* service_uuid = env->GetByteArrayElements(serviceUuid, NULL);
uint16_t service_uuid_len = (uint16_t) env->GetArrayLength(serviceUuid);
sGattIf->client->set_adv_data(client_if, setScanRsp, inclName, inclTxPower,
minInterval, maxInterval, appearance, arr_len, (char*)arr_data,
service_data_len, (char*)service_data, service_uuid_len,
(char*)service_uuid);
env->ReleaseByteArrayElements(manufacturerData, arr_data, JNI_ABORT);
env->ReleaseByteArrayElements(serviceData, service_data, JNI_ABORT);
env->ReleaseByteArrayElements(serviceUuid, service_uuid, JNI_ABORT);
}
/**
* 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", "(IIIJJIJJIJJ)V", (void *) gattClientGetDescriptorNative},
{"gattClientGetIncludedServiceNative", "(IIIJJIIJJ)V", (void *) gattClientGetIncludedServiceNative},
{"gattClientReadCharacteristicNative", "(IIIJJIJJI)V", (void *) gattClientReadCharacteristicNative},
{"gattClientReadDescriptorNative", "(IIIJJIJJIJJI)V", (void *) gattClientReadDescriptorNative},
{"gattClientWriteCharacteristicNative", "(IIIJJIJJII[B)V", (void *) gattClientWriteCharacteristicNative},
{"gattClientWriteDescriptorNative", "(IIIJJIJJIJJII[B)V", (void *) gattClientWriteDescriptorNative},
{"gattClientExecuteWriteNative", "(IZ)V", (void *) gattClientExecuteWriteNative},
{"gattClientRegisterForNotificationsNative", "(ILjava/lang/String;IIJJIJJZ)V", (void *) gattClientRegisterForNotificationsNative},
{"gattClientReadRemoteRssiNative", "(ILjava/lang/String;)V", (void *) gattClientReadRemoteRssiNative},
{"gattAdvertiseNative", "(IZ)V", (void *) gattAdvertiseNative},
{"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},
{"gattSetAdvDataNative", "(IZZZIII[B[B[B)V", (void *) gattSetAdvDataNative},
{"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));
}
}