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     method_onConnectStateChanged = env->GetMethodID(clazz, "onConnectStateChanged",
     98                                                     "([BIIII)V");
     99     method_onControlStateChanged = env->GetMethodID(clazz, "onControlStateChanged",
    100                                                     "(IIILjava/lang/String;)V");
    101 
    102     info("succeeds");
    103 }
    104 static const bt_interface_t* btIf;
    105 
    106 static void initializeNative(JNIEnv *env, jobject object) {
    107     debug("pan");
    108     if(btIf)
    109         return;
    110 
    111     if ( (btIf = getBluetoothInterface()) == NULL) {
    112         error("Bluetooth module is not loaded");
    113         return;
    114     }
    115 
    116     if (sPanIf !=NULL) {
    117          ALOGW("Cleaning up Bluetooth PAN Interface before initializing...");
    118          sPanIf->cleanup();
    119          sPanIf = NULL;
    120     }
    121 
    122     if (mCallbacksObj != NULL) {
    123          ALOGW("Cleaning up Bluetooth PAN callback object");
    124          env->DeleteGlobalRef(mCallbacksObj);
    125          mCallbacksObj = NULL;
    126     }
    127 
    128     if ( (sPanIf = (btpan_interface_t *)
    129           btIf->get_profile_interface(BT_PROFILE_PAN_ID)) == NULL) {
    130         error("Failed to get Bluetooth PAN Interface");
    131         return;
    132     }
    133 
    134     mCallbacksObj = env->NewGlobalRef(object);
    135 
    136     bt_status_t status;
    137     if ( (status = sPanIf->init(&sBluetoothPanCallbacks)) != BT_STATUS_SUCCESS) {
    138         error("Failed to initialize Bluetooth PAN, status: %d", status);
    139         sPanIf = NULL;
    140         if (mCallbacksObj != NULL) {
    141             ALOGW("initialization failed: Cleaning up Bluetooth PAN callback object");
    142             env->DeleteGlobalRef(mCallbacksObj);
    143             mCallbacksObj = NULL;
    144         }
    145         return;
    146     }
    147 }
    148 
    149 static void cleanupNative(JNIEnv *env, jobject object) {
    150     if (!btIf) return;
    151 
    152     if (sPanIf !=NULL) {
    153         ALOGW("Cleaning up Bluetooth PAN Interface...");
    154         sPanIf->cleanup();
    155         sPanIf = NULL;
    156     }
    157 
    158     if (mCallbacksObj != NULL) {
    159         ALOGW("Cleaning up Bluetooth PAN callback object");
    160         env->DeleteGlobalRef(mCallbacksObj);
    161         mCallbacksObj = NULL;
    162     }
    163     btIf = NULL;
    164 }
    165 
    166 static jboolean enablePanNative(JNIEnv *env, jobject object, jint local_role) {
    167     bt_status_t status = BT_STATUS_FAIL;
    168     debug("in");
    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     if (sPanIf)
    178         local_role  = sPanIf->get_local_role();
    179     debug("out");
    180     return (jint)local_role;
    181 }
    182 
    183 
    184 
    185 static jboolean connectPanNative(JNIEnv *env, jobject object, jbyteArray address,
    186                                  jint src_role, jint dest_role) {
    187     debug("in");
    188     bt_status_t status;
    189     jbyte *addr;
    190     jboolean ret = JNI_TRUE;
    191     if (!sPanIf) return JNI_FALSE;
    192 
    193     addr = env->GetByteArrayElements(address, NULL);
    194     if (!addr) {
    195         error("Bluetooth device address null");
    196         return JNI_FALSE;
    197     }
    198 
    199     if ((status = sPanIf->connect((bt_bdaddr_t *) addr, src_role, dest_role)) !=
    200          BT_STATUS_SUCCESS) {
    201         error("Failed PAN channel connection, status: %d", status);
    202         ret = JNI_FALSE;
    203     }
    204     env->ReleaseByteArrayElements(address, addr, 0);
    205 
    206     return ret;
    207 }
    208 
    209 static jboolean disconnectPanNative(JNIEnv *env, jobject object, jbyteArray address) {
    210     bt_status_t status;
    211     jbyte *addr;
    212     jboolean ret = JNI_TRUE;
    213     if (!sPanIf) return JNI_FALSE;
    214 
    215     addr = env->GetByteArrayElements(address, NULL);
    216     if (!addr) {
    217         error("Bluetooth device address null");
    218         return JNI_FALSE;
    219     }
    220 
    221     if ( (status = sPanIf->disconnect((bt_bdaddr_t *) addr)) !=
    222          BT_STATUS_SUCCESS) {
    223         error("Failed disconnect pan channel, status: %d", status);
    224         ret = JNI_FALSE;
    225     }
    226     env->ReleaseByteArrayElements(address, addr, 0);
    227 
    228     return ret;
    229 }
    230 
    231 static JNINativeMethod sMethods[] = {
    232     {"classInitNative", "()V", (void *) classInitNative},
    233     {"initializeNative", "()V", (void *) initializeNative},
    234     {"cleanupNative", "()V", (void *) cleanupNative},
    235     {"connectPanNative", "([BII)Z", (void *) connectPanNative},
    236     {"enablePanNative", "(I)Z", (void *) enablePanNative},
    237     {"getPanLocalRoleNative", "()I", (void *) getPanLocalRoleNative},
    238     {"disconnectPanNative", "([B)Z", (void *) disconnectPanNative},
    239     // TBD cleanup
    240 };
    241 
    242 int register_com_android_bluetooth_pan(JNIEnv* env)
    243 {
    244     return jniRegisterNativeMethods(env, "com/android/bluetooth/pan/PanService",
    245                                     sMethods, NELEM(sMethods));
    246 }
    247 
    248 }
    249