Home | History | Annotate | Download | only in jni
      1 /*
      2  * Copyright (C) 2012 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #define LOG_TAG "BluetoothPanServiceJni"
     18 
     19 #define LOG_NDEBUG 0
     20 
     21 #define CHECK_CALLBACK_ENV                                                      \
     22    if (!checkCallbackThread()) {                                                \
     23        error("Callback: '%s' is not called on the correct thread", __FUNCTION__);\
     24        return;                                                                  \
     25    }
     26 
     27 #include "com_android_bluetooth.h"
     28 #include "hardware/bt_pan.h"
     29 #include "utils/Log.h"
     30 #include "android_runtime/AndroidRuntime.h"
     31 
     32 #include <string.h>
     33 
     34 #include <cutils/log.h>
     35 #define info(fmt, ...)  ALOGI ("%s(L%d): " fmt,__FUNCTION__, __LINE__,  ## __VA_ARGS__)
     36 #define debug(fmt, ...) ALOGD ("%s(L%d): " fmt,__FUNCTION__, __LINE__,  ## __VA_ARGS__)
     37 #define warn(fmt, ...) ALOGW ("## WARNING : %s(L%d): " fmt "##",__FUNCTION__, __LINE__, ## __VA_ARGS__)
     38 #define error(fmt, ...) ALOGE ("## ERROR : %s(L%d): " fmt "##",__FUNCTION__, __LINE__, ## __VA_ARGS__)
     39 #define asrt(s) if(!(s)) ALOGE ("## %s(L%d): ASSERT %s failed! ##",__FUNCTION__, __LINE__, #s)
     40 
     41 
     42 namespace android {
     43 
     44 static jmethodID method_onConnectStateChanged;
     45 static jmethodID method_onControlStateChanged;
     46 
     47 static const btpan_interface_t *sPanIf = NULL;
     48 static jobject mCallbacksObj = NULL;
     49 static JNIEnv *sCallbackEnv = NULL;
     50 
     51 static bool checkCallbackThread() {
     52     sCallbackEnv = getCallbackEnv();
     53 
     54     JNIEnv* env = AndroidRuntime::getJNIEnv();
     55     if (sCallbackEnv != env || sCallbackEnv == NULL) return false;
     56     return true;
     57 }
     58 
     59 static void control_state_callback(btpan_control_state_t state, int local_role, bt_status_t error,
     60                 const char* ifname) {
     61     debug("state:%d, local_role:%d, ifname:%s", state, local_role, ifname);
     62     CHECK_CALLBACK_ENV
     63     jstring js_ifname = sCallbackEnv->NewStringUTF(ifname);
     64     sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onControlStateChanged, (jint)local_role, (jint)state,
     65                                 (jint)error, js_ifname);
     66     sCallbackEnv->DeleteLocalRef(js_ifname);
     67 }
     68 
     69 static void connection_state_callback(btpan_connection_state_t state, bt_status_t error, const bt_bdaddr_t *bd_addr,
     70                                       int local_role, int remote_role) {
     71     jbyteArray addr;
     72     debug("state:%d, local_role:%d, remote_role:%d", state, local_role, remote_role);
     73     CHECK_CALLBACK_ENV
     74     addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t));
     75     if (!addr) {
     76         error("Fail to new jbyteArray bd addr for PAN channel state");
     77         checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
     78         return;
     79     }
     80     sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte *) bd_addr);
     81 
     82     sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onConnectStateChanged, addr, (jint) state,
     83                                     (jint)error, (jint)local_role, (jint)remote_role);
     84     checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__);
     85     sCallbackEnv->DeleteLocalRef(addr);
     86 }
     87 
     88 static btpan_callbacks_t sBluetoothPanCallbacks = {
     89     sizeof(sBluetoothPanCallbacks),
     90     control_state_callback,
     91     connection_state_callback
     92 };
     93 
     94 // Define native functions
     95 
     96 static void classInitNative(JNIEnv* env, jclass clazz) {
     97     int err;
     98     bt_status_t status;
     99 
    100     method_onConnectStateChanged = env->GetMethodID(clazz, "onConnectStateChanged",
    101                                                     "([BIIII)V");
    102     method_onControlStateChanged = env->GetMethodID(clazz, "onControlStateChanged",
    103                                                     "(IIILjava/lang/String;)V");
    104 
    105     info("succeeds");
    106 }
    107 static const bt_interface_t* btIf;
    108 
    109 static void initializeNative(JNIEnv *env, jobject object) {
    110     debug("pan");
    111     if(btIf)
    112         return;
    113 
    114     if ( (btIf = getBluetoothInterface()) == NULL) {
    115         error("Bluetooth module is not loaded");
    116         return;
    117     }
    118 
    119     if (sPanIf !=NULL) {
    120          ALOGW("Cleaning up Bluetooth PAN Interface before initializing...");
    121          sPanIf->cleanup();
    122          sPanIf = NULL;
    123     }
    124 
    125     if (mCallbacksObj != NULL) {
    126          ALOGW("Cleaning up Bluetooth PAN callback object");
    127          env->DeleteGlobalRef(mCallbacksObj);
    128          mCallbacksObj = NULL;
    129     }
    130 
    131     if ( (sPanIf = (btpan_interface_t *)
    132           btIf->get_profile_interface(BT_PROFILE_PAN_ID)) == NULL) {
    133         error("Failed to get Bluetooth PAN Interface");
    134         return;
    135     }
    136 
    137     bt_status_t status;
    138     if ( (status = sPanIf->init(&sBluetoothPanCallbacks)) != BT_STATUS_SUCCESS) {
    139         error("Failed to initialize Bluetooth PAN, status: %d", status);
    140         sPanIf = NULL;
    141         return;
    142     }
    143 
    144     mCallbacksObj = env->NewGlobalRef(object);
    145 }
    146 
    147 static void cleanupNative(JNIEnv *env, jobject object) {
    148     bt_status_t status;
    149     if (!btIf) return;
    150 
    151     if (sPanIf !=NULL) {
    152         ALOGW("Cleaning up Bluetooth PAN Interface...");
    153         sPanIf->cleanup();
    154         sPanIf = NULL;
    155     }
    156 
    157     if (mCallbacksObj != NULL) {
    158         ALOGW("Cleaning up Bluetooth PAN callback object");
    159         env->DeleteGlobalRef(mCallbacksObj);
    160         mCallbacksObj = NULL;
    161     }
    162     btIf = NULL;
    163 }
    164 
    165 static jboolean enablePanNative(JNIEnv *env, jobject object, jint local_role) {
    166     bt_status_t status = BT_STATUS_FAIL;
    167     debug("in");
    168     jbyte *addr;
    169     if (sPanIf)
    170         status = sPanIf->enable(local_role);
    171     debug("out");
    172     return status == BT_STATUS_SUCCESS ? JNI_TRUE : JNI_FALSE;
    173 }
    174 static jint getPanLocalRoleNative(JNIEnv *env, jobject object) {
    175     debug("in");
    176     int local_role = 0;
    177     jbyte *addr;
    178     if (sPanIf)
    179         local_role  = sPanIf->get_local_role();
    180     debug("out");
    181     return (jint)local_role;
    182 }
    183 
    184 
    185 
    186 static jboolean connectPanNative(JNIEnv *env, jobject object, jbyteArray address,
    187                                  jint src_role, jint dest_role) {
    188     debug("in");
    189     bt_status_t status;
    190     jbyte *addr;
    191     jboolean ret = JNI_TRUE;
    192     if (!sPanIf) return JNI_FALSE;
    193 
    194     addr = env->GetByteArrayElements(address, NULL);
    195     if (!addr) {
    196         error("Bluetooth device address null");
    197         return JNI_FALSE;
    198     }
    199 
    200     if ((status = sPanIf->connect((bt_bdaddr_t *) addr, src_role, dest_role)) !=
    201          BT_STATUS_SUCCESS) {
    202         error("Failed PAN channel connection, status: %d", status);
    203         ret = JNI_FALSE;
    204     }
    205     env->ReleaseByteArrayElements(address, addr, 0);
    206 
    207     return ret;
    208 }
    209 
    210 static jboolean disconnectPanNative(JNIEnv *env, jobject object, jbyteArray address) {
    211     bt_status_t status;
    212     jbyte *addr;
    213     jboolean ret = JNI_TRUE;
    214     if (!sPanIf) return JNI_FALSE;
    215 
    216     addr = env->GetByteArrayElements(address, NULL);
    217     if (!addr) {
    218         error("Bluetooth device address null");
    219         return JNI_FALSE;
    220     }
    221 
    222     if ( (status = sPanIf->disconnect((bt_bdaddr_t *) addr)) !=
    223          BT_STATUS_SUCCESS) {
    224         error("Failed disconnect pan channel, status: %d", status);
    225         ret = JNI_FALSE;
    226     }
    227     env->ReleaseByteArrayElements(address, addr, 0);
    228 
    229     return ret;
    230 }
    231 
    232 static JNINativeMethod sMethods[] = {
    233     {"classInitNative", "()V", (void *) classInitNative},
    234     {"initializeNative", "()V", (void *) initializeNative},
    235     {"cleanupNative", "()V", (void *) cleanupNative},
    236     {"connectPanNative", "([BII)Z", (void *) connectPanNative},
    237     {"enablePanNative", "(I)Z", (void *) enablePanNative},
    238     {"getPanLocalRoleNative", "()I", (void *) getPanLocalRoleNative},
    239     {"disconnectPanNative", "([B)Z", (void *) disconnectPanNative},
    240     // TBD cleanup
    241 };
    242 
    243 int register_com_android_bluetooth_pan(JNIEnv* env)
    244 {
    245     return jniRegisterNativeMethods(env, "com/android/bluetooth/pan/PanService",
    246                                     sMethods, NELEM(sMethods));
    247 }
    248 
    249 }
    250