blob: a753b25dc54c1274a90dc3894a891280ee478c36 [file] [log] [blame]
/*
* Copyright (c) 2013, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#define LOG_TAG "QBluetoothAdapterServiceJni"
#define BD_ADDR_LEN 6
#include "com_android_bluetooth.h"
#include "utils/Log.h"
#include "utils/misc.h"
#include "cutils/properties.h"
#include "android_runtime/AndroidRuntime.h"
#include <string.h>
#include <pthread.h>
#include <sys/stat.h>
#include <fcntl.h>
namespace android {
static jmethodID method_advEnableCallback;
static jmethodID method_onLeExtendedScanResultCallback;
static jmethodID method_onLeLppWriteRssiThreshold;
static jmethodID method_onLeLppReadRssiThreshold;
static jmethodID method_onLeLppEnableRssiMonitor;
static jmethodID method_onLeLppRssiThresholdEvent;
static const bt_interface_t *qBluetoothInterface = NULL;
static JNIEnv *qcallbackEnv = NULL;
static jobject qJniCallbacksObj=NULL;
static jfieldID qJniCallbacksField;
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 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);
}
}
static bool checkCallbackThread() {
qcallbackEnv = getCallbackEnv();
JNIEnv* env = AndroidRuntime::getJNIEnv();
if(env==NULL)
ALOGE("checkCallbackThread env is NULL");
if(qcallbackEnv==NULL)
ALOGE("checkCallbackThread qcallbackEnv is NULL");
if(env!=qcallbackEnv)
ALOGE("env and qcallbackEnv dont match");
if (qcallbackEnv != env || qcallbackEnv == NULL) return false;
return true;
}
static void le_adv_enable_callbacks(uint8_t enable, uint8_t advType) {
jbyteArray addr;
if (!checkCallbackThread()) {
ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__);
return;
}
ALOGV("%s: adv enable:%d ", __FUNCTION__, enable);
qcallbackEnv->CallVoidMethod(qJniCallbacksObj, method_advEnableCallback,
(jint)enable, (jint)advType);
checkAndClearExceptionFromCallback(qcallbackEnv, __FUNCTION__);
}
static void le_extended_scan_result_callbacks(bt_bdaddr_t* bda, int rssi, uint8_t* adv_data)
{
char c_address[32];
if (!checkCallbackThread()) {
ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__);
}
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 = qcallbackEnv->NewStringUTF(c_address);
jbyteArray jb = qcallbackEnv->NewByteArray(62);
qcallbackEnv->SetByteArrayRegion(jb, 0, 62, (jbyte *) adv_data);
qcallbackEnv->CallVoidMethod(qJniCallbacksObj, method_onLeExtendedScanResultCallback,
address, rssi, jb);
qcallbackEnv->DeleteLocalRef(address);
qcallbackEnv->DeleteLocalRef(jb);
checkAndClearExceptionFromCallback(qcallbackEnv, __FUNCTION__);
}
void le_lpp_write_rssi_thresh_callbacks(bt_bdaddr_t *bda, int status)
{
char c_address[32] = {0};
if (!checkCallbackThread()) {
ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__);
return;
}
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 = qcallbackEnv->NewStringUTF(c_address);
qcallbackEnv->CallVoidMethod(qJniCallbacksObj, method_onLeLppWriteRssiThreshold,
address, status);
qcallbackEnv->DeleteLocalRef(address);
checkAndClearExceptionFromCallback(qcallbackEnv, __FUNCTION__);
}
void le_lpp_read_rssi_thresh_callbacks(bt_bdaddr_t *bda, int low, int upper,
int alert, int status)
{
char c_address[32] = {0};
if (!checkCallbackThread()) {
ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__);
return;
}
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 = qcallbackEnv->NewStringUTF(c_address);
qcallbackEnv->CallVoidMethod(qJniCallbacksObj, method_onLeLppReadRssiThreshold,
address, low, upper, alert, status);
qcallbackEnv->DeleteLocalRef(address);
checkAndClearExceptionFromCallback(qcallbackEnv, __FUNCTION__);
}
void le_lpp_enable_rssi_monitor_callbacks(bt_bdaddr_t *bda,
int enable, int status)
{
char c_address[32] = {0};
if (!checkCallbackThread()) {
ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__);
return;
}
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 = qcallbackEnv->NewStringUTF(c_address);
qcallbackEnv->CallVoidMethod(qJniCallbacksObj, method_onLeLppEnableRssiMonitor,
address, enable, status);
qcallbackEnv->DeleteLocalRef(address);
checkAndClearExceptionFromCallback(qcallbackEnv, __FUNCTION__);
}
void le_lpp_rssi_threshold_evt_callbacks(bt_bdaddr_t *bda,
int evt_type, int rssi)
{
char c_address[32] = {0};
if (!checkCallbackThread()) {
ALOGE("Callback: '%s' is not called on the correct thread", __FUNCTION__);
return;
}
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 = qcallbackEnv->NewStringUTF(c_address);
qcallbackEnv->CallVoidMethod(qJniCallbacksObj, method_onLeLppRssiThresholdEvent,
address, evt_type, rssi);
qcallbackEnv->DeleteLocalRef(address);
checkAndClearExceptionFromCallback(qcallbackEnv, __FUNCTION__);
}
bt_callbacks_t sQBluetoothCallbacks = {
sizeof(sQBluetoothCallbacks),
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
le_adv_enable_callbacks,
le_extended_scan_result_callbacks,
le_lpp_write_rssi_thresh_callbacks,
le_lpp_read_rssi_thresh_callbacks,
le_lpp_enable_rssi_monitor_callbacks,
le_lpp_rssi_threshold_evt_callbacks,
};
static void classInitNative(JNIEnv* env, jclass clazz) {
int err;
hw_module_t* module;
ALOGV("%s:",__FUNCTION__);
if((qBluetoothInterface=getBluetoothInterface())==NULL){
ALOGE("Bluetooth module is not loaded");
return;
}
jclass jniCallbackClass =
env->FindClass("com/android/bluetooth/btservice/QJniCallbacks");
qJniCallbacksField = env->GetFieldID(clazz, "mJniCallbacks",
"Lcom/android/bluetooth/btservice/QJniCallbacks;");
method_advEnableCallback = env->GetMethodID(jniCallbackClass, "advEnableCallback", "(II)V");
method_onLeExtendedScanResultCallback = env->GetMethodID(jniCallbackClass, "onLeExtendedScanResult", "(Ljava/lang/String;I[B)V");
method_onLeLppWriteRssiThreshold = env->GetMethodID(jniCallbackClass, "onLeLppWriteRssiThreshold", "(Ljava/lang/String;I)V");
method_onLeLppReadRssiThreshold = env->GetMethodID(jniCallbackClass, "onLeLppReadRssiThreshold", "(Ljava/lang/String;IIII)V");
method_onLeLppEnableRssiMonitor = env->GetMethodID(jniCallbackClass, "onLeLppEnableRssiMonitor", "(Ljava/lang/String;II)V");
method_onLeLppRssiThresholdEvent = env->GetMethodID(jniCallbackClass, "onLeLppRssiThresholdEvent", "(Ljava/lang/String;II)V");
}
static bool initNative(JNIEnv* env, jobject obj) {
ALOGV("%s:",__FUNCTION__);
if (qBluetoothInterface) {
qJniCallbacksObj = env->NewGlobalRef(env->GetObjectField(obj, qJniCallbacksField));
int ret = qBluetoothInterface->initq(&sQBluetoothCallbacks);
if (ret != BT_STATUS_SUCCESS) {
ALOGE("Error while setting the callbacks \n");
qBluetoothInterface = NULL;
return JNI_FALSE;
}
return JNI_TRUE;
}
return JNI_FALSE;
}
static bool cleanupNative(JNIEnv *env, jobject obj) {
ALOGV("%s:",__FUNCTION__);
jboolean result = JNI_FALSE;
if (!qBluetoothInterface) return result;
if(qJniCallbacksObj!=NULL){
env->DeleteGlobalRef(qJniCallbacksObj);
qJniCallbacksObj=NULL;
}
return JNI_TRUE;
}
static jboolean setLEAdvModeNative(JNIEnv *env, jobject obj, jint type, jbyteArray value) {
ALOGV("%s:",__FUNCTION__);
jbyte *val;
jboolean result = JNI_FALSE;
if (!qBluetoothInterface) return result;
val = env->GetByteArrayElements(value, NULL);
bt_property_t prop;
prop.type = (bt_property_type_t) type;
prop.len = env->GetArrayLength(value);
prop.val = val;
int ret = qBluetoothInterface->set_adapter_property(&prop);
env->ReleaseByteArrayElements(value, val, 0);
result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
return result;
}
static jboolean setLEadvMaskNative(JNIEnv *env, jobject obj,jint mask){
ALOGV("%s:",__FUNCTION__);
jboolean result = JNI_FALSE;
if (!qBluetoothInterface) return result;
int ret = qBluetoothInterface->le_set_adv_data_mask(mask);
result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
return result;
}
static jboolean setLEscanRespMaskNative(JNIEnv *env, jobject obj,jint mask){
ALOGV("%s:",__FUNCTION__);
jboolean result = JNI_FALSE;
if (!qBluetoothInterface) return result;
int ret = qBluetoothInterface->le_set_scan_resp_mask(mask);
result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
return result;
}
static jboolean setLEManuDataNative(JNIEnv *env, jobject obj,jbyteArray buff){
ALOGV("%s:",__FUNCTION__);
jbyte *manu_data=NULL;
uint8_t size=0;
jboolean result = JNI_FALSE;
manu_data=env->GetByteArrayElements(buff, NULL);
size=env->GetArrayLength(buff);
if (!qBluetoothInterface) return result;
int ret = qBluetoothInterface->le_set_manu_data((uint8_t *)manu_data, size);
result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
return result;
}
static jboolean setLEServiceDataNative(JNIEnv *env, jobject obj,jbyteArray buff){
ALOGV("%s:",__FUNCTION__);
jbyte *service_data=NULL;
uint8_t size=0;
jboolean result = JNI_FALSE;
service_data=env->GetByteArrayElements(buff, NULL);
size=env->GetArrayLength(buff);
if (!qBluetoothInterface) return result;
int ret = qBluetoothInterface->le_set_service_data((uint8_t *)service_data, size);
result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
return result;
}
static jboolean setLEAdvParamsNative(JNIEnv *env, jobject obj, jint min_int, jint max_int, jbyteArray address, jint ad_type){
ALOGV("%s:",__FUNCTION__);
jbyte *addr=NULL;
jboolean result = JNI_FALSE;
addr = env->GetByteArrayElements(address, NULL);
if (!qBluetoothInterface) return result;
int ret = qBluetoothInterface->le_set_adv_params(min_int, max_int, (bt_bdaddr_t *)addr,ad_type);
result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
return result;
}
static void btLeExtendedScanNative(JNIEnv *env, jobject object,
jobjectArray uuids, jboolean start)
{
int i = 0, entries = 0;
uint8_t scan_policy = 0x80; /* 0x80 represent only AD whitelist applied*/
bt_le_service_t *service_list = 0;
entries = env->GetArrayLength(uuids);
if(qBluetoothInterface && (service_list = (bt_le_service_t*)malloc(entries * sizeof(bt_le_service_t))))
{
jclass clazzuuid;
jobject uuid;
jmethodID getlsb, getmsb, gettype;
jlong lsbbits, msbbits;
if ((clazzuuid = env->FindClass("android/bluetooth/BluetoothLEServiceUuid")) != NULL &&
(getlsb = env->GetMethodID(clazzuuid, "getLeastSignificantBits", "()J")) != NULL &&
(getmsb = env->GetMethodID(clazzuuid, "getMostSignificantBits", "()J")) != NULL &&
(gettype = env->GetMethodID(clazzuuid, "getType", "()B")) != NULL)
{
for(i = 0; i < entries; i++)
{
uuid = env->GetObjectArrayElement(uuids, i);
service_list[i].uuidtype = env->CallByteMethod(uuid, gettype);
lsbbits = env->CallLongMethod(uuid, getlsb);
msbbits = env->CallLongMethod(uuid, getmsb);
set_uuid(&service_list[i].uuidval.uu[0], msbbits, lsbbits);
}
qBluetoothInterface->le_extended_scan(service_list, entries, scan_policy, start?1:0);
}
}
free(service_list);
}
static void btLeLppWriteRssiThresholdNative(JNIEnv *env, jobject object,
jstring address, jbyte min, jbyte max)
{
bt_bdaddr_t bda;
if (!qBluetoothInterface) return;
jstr2bdaddr(env, &bda, address);
qBluetoothInterface->le_lpp_write_rssi_threshold(&bda, min, max);
}
static void btLeLppEnableRssiMonitorNative(JNIEnv* env, jobject object,
jstring address, jboolean enable)
{
bt_bdaddr_t bda;
if (!qBluetoothInterface) return;
jstr2bdaddr(env, &bda, address);
qBluetoothInterface->le_lpp_enable_rssi_monitor(&bda, enable);
}
static void btLeLppReadRssiThresholdNative(JNIEnv* env, jobject object,
jstring address)
{
bt_bdaddr_t bda;
if (!qBluetoothInterface) return;
jstr2bdaddr(env, &bda, address);
qBluetoothInterface->le_lpp_read_rssi_threshold(&bda);
}
static JNINativeMethod qMethods[] = {
/* name, signature, funcPtr */
{"classInitNative", "()V", (void *) classInitNative},
{"initNative", "()Z", (void *) initNative},
{"cleanupNative", "()V", (void*) cleanupNative},
{"setLEAdvParamsNative","(II[BI)Z", (void*) setLEAdvParamsNative},
{"setLEadvMaskNative","(I)Z",(void*) setLEadvMaskNative},
{"setLEscanRespMaskNative","(I)Z",(void*) setLEscanRespMaskNative},
{"setLEManuDataNative","([B)Z",(void*) setLEManuDataNative},
{"setLEServiceDataNative","([B)Z",(void*) setLEServiceDataNative},
{"setLEAdvModeNative", "(I[B)Z", (void*) setLEAdvModeNative},
{"btLeExtendedScanNative", "([Landroid/bluetooth/BluetoothLEServiceUuid;Z)V", (void*) btLeExtendedScanNative},
{"btLeLppWriteRssiThresholdNative", "(Ljava/lang/String;BB)V", (void*)btLeLppWriteRssiThresholdNative},
{"btLeLppEnableRssiMonitorNative", "(Ljava/lang/String;Z)V", (void*)btLeLppEnableRssiMonitorNative},
{"btLeLppReadRssiThresholdNative", "(Ljava/lang/String;)V", (void*)btLeLppReadRssiThresholdNative},
};
int register_com_android_bluetooth_btservice_QAdapterService(JNIEnv* env)
{
return jniRegisterNativeMethods(env, "com/android/bluetooth/btservice/QAdapterService",
qMethods, NELEM(qMethods));
}
}