summaryrefslogtreecommitdiffstats
path: root/core/jni/android_server_BluetoothEventLoop.cpp
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2008-10-21 07:00:00 -0700
committerThe Android Open Source Project <initial-contribution@android.com>2008-10-21 07:00:00 -0700
commit54b6cfa9a9e5b861a9930af873580d6dc20f773c (patch)
tree35051494d2af230dce54d6b31c6af8fc24091316 /core/jni/android_server_BluetoothEventLoop.cpp
downloadframeworks_base-54b6cfa9a9e5b861a9930af873580d6dc20f773c.zip
frameworks_base-54b6cfa9a9e5b861a9930af873580d6dc20f773c.tar.gz
frameworks_base-54b6cfa9a9e5b861a9930af873580d6dc20f773c.tar.bz2
Initial Contribution
Diffstat (limited to 'core/jni/android_server_BluetoothEventLoop.cpp')
-rw-r--r--core/jni/android_server_BluetoothEventLoop.cpp642
1 files changed, 642 insertions, 0 deletions
diff --git a/core/jni/android_server_BluetoothEventLoop.cpp b/core/jni/android_server_BluetoothEventLoop.cpp
new file mode 100644
index 0000000..395a45c
--- /dev/null
+++ b/core/jni/android_server_BluetoothEventLoop.cpp
@@ -0,0 +1,642 @@
+/*
+** Copyright 2008, 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 "BluetoothEventLoop.cpp"
+
+#include "android_bluetooth_common.h"
+#include "android_runtime/AndroidRuntime.h"
+#include "JNIHelp.h"
+#include "jni.h"
+#include "utils/Log.h"
+#include "utils/misc.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+
+#ifdef HAVE_BLUETOOTH
+#include <dbus/dbus.h>
+#endif
+
+namespace android {
+
+#ifdef HAVE_BLUETOOTH
+static jfieldID field_mNativeData;
+
+static jmethodID method_onModeChanged;
+static jmethodID method_onDiscoveryStarted;
+static jmethodID method_onDiscoveryCompleted;
+static jmethodID method_onRemoteDeviceFound;
+static jmethodID method_onRemoteDeviceDisappeared;
+static jmethodID method_onRemoteClassUpdated;
+static jmethodID method_onRemoteNameUpdated;
+static jmethodID method_onRemoteNameFailed;
+static jmethodID method_onRemoteAliasChanged;
+static jmethodID method_onRemoteAliasCleared;
+static jmethodID method_onRemoteDeviceConnected;
+static jmethodID method_onRemoteDeviceDisconnectRequested;
+static jmethodID method_onRemoteDeviceDisconnected;
+static jmethodID method_onBondingCreated;
+static jmethodID method_onBondingRemoved;
+
+static jmethodID method_onCreateBondingResult;
+static jmethodID method_onGetRemoteServiceChannelResult;
+
+static jmethodID method_onPasskeyAgentRequest;
+static jmethodID method_onPasskeyAgentCancel;
+
+struct native_data_t {
+ DBusConnection *conn;
+ /* These variables are set in waitForAndDispatchEventNative() and are
+ valid only within the scope of this function. At any other time, they
+ are NULL. */
+ jobject me;
+ JNIEnv *env;
+};
+
+// Only valid during waitForAndDispatchEventNative()
+static native_data_t *event_loop_nat;
+
+static inline native_data_t * get_native_data(JNIEnv *env, jobject object) {
+ return (native_data_t *)(env->GetIntField(object,
+ field_mNativeData));
+}
+
+#endif
+static void classInitNative(JNIEnv* env, jclass clazz) {
+ LOGV(__FUNCTION__);
+
+#ifdef HAVE_BLUETOOTH
+ method_onModeChanged = env->GetMethodID(clazz, "onModeChanged", "(Ljava/lang/String;)V");
+ method_onDiscoveryStarted = env->GetMethodID(clazz, "onDiscoveryStarted", "()V");
+ method_onDiscoveryCompleted = env->GetMethodID(clazz, "onDiscoveryCompleted", "()V");
+ method_onRemoteDeviceFound = env->GetMethodID(clazz, "onRemoteDeviceFound", "(Ljava/lang/String;IS)V");
+ method_onRemoteDeviceDisappeared = env->GetMethodID(clazz, "onRemoteDeviceDisappeared", "(Ljava/lang/String;)V");
+ method_onRemoteClassUpdated = env->GetMethodID(clazz, "onRemoteClassUpdated", "(Ljava/lang/String;I)V");
+ method_onRemoteNameUpdated = env->GetMethodID(clazz, "onRemoteNameUpdated", "(Ljava/lang/String;Ljava/lang/String;)V");
+ method_onRemoteNameFailed = env->GetMethodID(clazz, "onRemoteNameFailed", "(Ljava/lang/String;)V");
+ method_onRemoteAliasChanged = env->GetMethodID(clazz, "onRemoteAliasChanged", "(Ljava/lang/String;Ljava/lang/String;)V");
+ method_onRemoteDeviceConnected = env->GetMethodID(clazz, "onRemoteDeviceConnected", "(Ljava/lang/String;)V");
+ method_onRemoteDeviceDisconnectRequested = env->GetMethodID(clazz, "onRemoteDeviceDisconnectRequested", "(Ljava/lang/String;)V");
+ method_onRemoteDeviceDisconnected = env->GetMethodID(clazz, "onRemoteDeviceDisconnected", "(Ljava/lang/String;)V");
+ method_onBondingCreated = env->GetMethodID(clazz, "onBondingCreated", "(Ljava/lang/String;)V");
+ method_onBondingRemoved = env->GetMethodID(clazz, "onBondingRemoved", "(Ljava/lang/String;)V");
+
+ method_onCreateBondingResult = env->GetMethodID(clazz, "onCreateBondingResult", "(Ljava/lang/String;Z)V");
+
+ method_onPasskeyAgentRequest = env->GetMethodID(clazz, "onPasskeyAgentRequest", "(Ljava/lang/String;I)V");
+ method_onPasskeyAgentCancel = env->GetMethodID(clazz, "onPasskeyAgentCancel", "(Ljava/lang/String;)V");
+ method_onGetRemoteServiceChannelResult = env->GetMethodID(clazz, "onGetRemoteServiceChannelResult", "(Ljava/lang/String;I)V");
+
+ field_mNativeData = env->GetFieldID(clazz, "mNativeData", "I");
+#endif
+}
+
+static void initializeNativeDataNative(JNIEnv* env, jobject object) {
+ LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+ native_data_t *nat = (native_data_t *)calloc(1, sizeof(native_data_t));
+ if (NULL == nat) {
+ LOGE("%s: out of memory!", __FUNCTION__);
+ return;
+ }
+ env->SetIntField(object, field_mNativeData, (jint)nat);
+
+ {
+ DBusError err;
+ dbus_error_init(&err);
+ dbus_threads_init_default();
+ nat->conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
+ if (dbus_error_is_set(&err)) {
+ LOGE("%s: Could not get onto the system bus!", __FUNCTION__);
+ dbus_error_free(&err);
+ }
+ }
+#endif
+}
+
+static void cleanupNativeDataNative(JNIEnv* env, jobject object) {
+ LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+ native_data_t *nat =
+ (native_data_t *)env->GetIntField(object, field_mNativeData);
+ if (nat) {
+ free(nat);
+ }
+#endif
+}
+
+#ifdef HAVE_BLUETOOTH
+static jboolean add_adapter_event_match(JNIEnv *env, native_data_t *nat);
+static void remove_adapter_event_match(JNIEnv *env, native_data_t *nat);
+static DBusHandlerResult event_filter(DBusConnection *conn, DBusMessage *msg,
+ void *data);
+static DBusHandlerResult passkey_agent_event_filter(DBusConnection *conn,
+ DBusMessage *msg,
+ void *data);
+
+static const DBusObjectPathVTable passkey_agent_vtable = {
+ NULL, passkey_agent_event_filter, NULL, NULL, NULL, NULL
+};
+#endif
+
+static jboolean setUpEventLoopNative(JNIEnv *env, jobject object) {
+#ifdef HAVE_BLUETOOTH
+ LOGV(__FUNCTION__);
+ dbus_threads_init_default();
+ native_data_t *nat = get_native_data(env, object);
+ if (nat != NULL && nat->conn != NULL) {
+ if (!dbus_connection_add_filter(nat->conn, event_filter, nat, NULL)){
+ return JNI_FALSE;
+ }
+
+ if (add_adapter_event_match(env, nat) != JNI_TRUE) {
+ return JNI_FALSE;
+ }
+
+ const char *path = "/android/bluetooth/PasskeyAgent";
+ if (!dbus_connection_register_object_path(nat->conn, path,
+ &passkey_agent_vtable, NULL)) {
+ LOGE("%s: Can't register object path %s for agent!",
+ __FUNCTION__, path);
+ return JNI_FALSE;
+ }
+
+ DBusError err;
+ dbus_error_init(&err);
+
+ // RegisterDefaultPasskeyAgent() will fail until hcid is up, so keep
+ // trying for 10 seconds.
+ int attempt;
+ for (attempt = 1000; attempt > 0; attempt--) {
+ DBusMessage *reply = dbus_func_args_error(env, nat->conn, &err,
+ BLUEZ_DBUS_BASE_PATH,
+ "org.bluez.Security", "RegisterDefaultPasskeyAgent",
+ DBUS_TYPE_STRING, &path,
+ DBUS_TYPE_INVALID);
+ if (reply) {
+ // Success
+ dbus_message_unref(reply);
+ return JNI_TRUE;
+ } else if (dbus_error_has_name(&err,
+ "org.freedesktop.DBus.Error.ServiceUnknown")) {
+ // hcid is still down, retry
+ dbus_error_free(&err);
+ usleep(10000); // 10 ms
+ } else {
+ // Some other error we weren't expecting
+ LOG_AND_FREE_DBUS_ERROR(&err);
+ return JNI_FALSE;
+ }
+ }
+ LOGE("Time-out trying to call RegisterDefaultPasskeyAgent(), "
+ "is hcid running?");
+ return JNI_FALSE;
+ }
+
+#endif
+ return JNI_FALSE;
+}
+
+static void tearDownEventLoopNative(JNIEnv *env, jobject object) {
+ LOGV(__FUNCTION__);
+#ifdef HAVE_BLUETOOTH
+ native_data_t *nat = get_native_data(env, object);
+ if (nat != NULL && nat->conn != NULL) {
+
+ const char *path = "/android/bluetooth/PasskeyAgent";
+ DBusMessage *reply =
+ dbus_func_args(env, nat->conn, BLUEZ_DBUS_BASE_PATH,
+ "org.bluez.Security", "UnregisterDefaultPasskeyAgent",
+ DBUS_TYPE_STRING, &path,
+ DBUS_TYPE_INVALID);
+ if (reply) dbus_message_unref(reply);
+
+ DBusError err;
+ dbus_error_init(&err);
+ (void)dbus_connection_remove_filter(nat->conn,
+ event_filter,
+ nat);
+
+ dbus_connection_unregister_object_path(nat->conn, path);
+
+ remove_adapter_event_match(env, nat);
+ }
+#endif
+}
+
+#ifdef HAVE_BLUETOOTH
+static const char *const adapter_event_match =
+ "type='signal',interface='"BLUEZ_DBUS_BASE_IFC".Adapter'";
+
+static jboolean add_adapter_event_match(JNIEnv *env, native_data_t *nat) {
+ if (nat == NULL || nat->conn == NULL) {
+ LOGE("%s: Not connected to d-bus!", __FUNCTION__);
+ return JNI_FALSE;
+ }
+ DBusError err;
+ dbus_error_init(&err);
+ dbus_bus_add_match(nat->conn, adapter_event_match, &err);
+ if (dbus_error_is_set(&err)) {
+ LOG_AND_FREE_DBUS_ERROR(&err);
+ return JNI_FALSE;
+ }
+ return JNI_TRUE;
+}
+
+static void remove_adapter_event_match(JNIEnv *env, native_data_t *nat) {
+ if (nat->conn == NULL) {
+ LOGE("%s: Not connected to d-bus!", __FUNCTION__);
+ return;
+ }
+ DBusError err;
+ dbus_error_init(&err);
+ dbus_bus_remove_match(nat->conn, adapter_event_match, &err);
+ if (dbus_error_is_set(&err)) {
+ LOG_AND_FREE_DBUS_ERROR(&err);
+ }
+}
+
+// Called by dbus during WaitForAndDispatchEventNative()
+static DBusHandlerResult event_filter(DBusConnection *conn, DBusMessage *msg,
+ void *data) {
+ native_data_t *nat;
+ JNIEnv *env;
+ DBusError err;
+
+ dbus_error_init(&err);
+
+ nat = (native_data_t *)data;
+ env = nat->env;
+ if (dbus_message_get_type(msg) != DBUS_MESSAGE_TYPE_SIGNAL) {
+ LOGV("%s: not interested (not a signal).", __FUNCTION__);
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+
+ LOGV("%s: Received signal %s:%s", __FUNCTION__,
+ dbus_message_get_interface(msg), dbus_message_get_member(msg));
+
+ if (dbus_message_is_signal(msg,
+ "org.bluez.Adapter",
+ "RemoteDeviceFound")) {
+ char *c_address;
+ int n_class;
+ short n_rssi;
+ if (dbus_message_get_args(msg, &err,
+ DBUS_TYPE_STRING, &c_address,
+ DBUS_TYPE_UINT32, &n_class,
+ DBUS_TYPE_INT16, &n_rssi,
+ DBUS_TYPE_INVALID)) {
+ LOGV("... address = %s class = %#X rssi = %hd", c_address, n_class,
+ n_rssi);
+ env->CallVoidMethod(nat->me,
+ method_onRemoteDeviceFound,
+ env->NewStringUTF(c_address),
+ (jint)n_class,
+ (jshort)n_rssi);
+ } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
+ return DBUS_HANDLER_RESULT_HANDLED;
+ } else if (dbus_message_is_signal(msg,
+ "org.bluez.Adapter",
+ "DiscoveryStarted")) {
+ LOGI("DiscoveryStarted signal received");
+ env->CallVoidMethod(nat->me, method_onDiscoveryStarted);
+ return DBUS_HANDLER_RESULT_HANDLED;
+ } else if (dbus_message_is_signal(msg,
+ "org.bluez.Adapter",
+ "DiscoveryCompleted")) {
+ LOGI("DiscoveryCompleted signal received");
+ env->CallVoidMethod(nat->me, method_onDiscoveryCompleted);
+ return DBUS_HANDLER_RESULT_HANDLED;
+ } else if (dbus_message_is_signal(msg,
+ "org.bluez.Adapter",
+ "RemoteDeviceDisappeared")) {
+ char *c_address;
+ if (dbus_message_get_args(msg, &err,
+ DBUS_TYPE_STRING, &c_address,
+ DBUS_TYPE_INVALID)) {
+ LOGV("... address = %s", c_address);
+ env->CallVoidMethod(nat->me, method_onRemoteDeviceDisappeared,
+ env->NewStringUTF(c_address));
+ } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
+ return DBUS_HANDLER_RESULT_HANDLED;
+ } else if (dbus_message_is_signal(msg,
+ "org.bluez.Adapter",
+ "RemoteClassUpdated")) {
+ char *c_address;
+ int n_class;
+ if (dbus_message_get_args(msg, &err,
+ DBUS_TYPE_STRING, &c_address,
+ DBUS_TYPE_UINT32, &n_class,
+ DBUS_TYPE_INVALID)) {
+ LOGV("... address = %s", c_address);
+ env->CallVoidMethod(nat->me, method_onRemoteClassUpdated,
+ env->NewStringUTF(c_address), (jint)n_class);
+ } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
+ return DBUS_HANDLER_RESULT_HANDLED;
+ } else if (dbus_message_is_signal(msg,
+ "org.bluez.Adapter",
+ "RemoteNameUpdated")) {
+ char *c_address;
+ char *c_name;
+ if (dbus_message_get_args(msg, &err,
+ DBUS_TYPE_STRING, &c_address,
+ DBUS_TYPE_STRING, &c_name,
+ DBUS_TYPE_INVALID)) {
+ LOGV("... address = %s, name = %s", c_address, c_name);
+ env->CallVoidMethod(nat->me,
+ method_onRemoteNameUpdated,
+ env->NewStringUTF(c_address),
+ env->NewStringUTF(c_name));
+ } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
+ return DBUS_HANDLER_RESULT_HANDLED;
+ } else if (dbus_message_is_signal(msg,
+ "org.bluez.Adapter",
+ "RemoteNameFailed")) {
+ char *c_address;
+ if (dbus_message_get_args(msg, &err,
+ DBUS_TYPE_STRING, &c_address,
+ DBUS_TYPE_INVALID)) {
+ LOGV("... address = %s", c_address);
+ env->CallVoidMethod(nat->me,
+ method_onRemoteNameFailed,
+ env->NewStringUTF(c_address));
+ } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
+ return DBUS_HANDLER_RESULT_HANDLED;
+ } else if (dbus_message_is_signal(msg,
+ "org.bluez.Adapter",
+ "RemoteAliasChanged")) {
+ char *c_address, *c_alias;
+ if (dbus_message_get_args(msg, &err,
+ DBUS_TYPE_STRING, &c_address,
+ DBUS_TYPE_STRING, &c_alias,
+ DBUS_TYPE_INVALID)) {
+ LOGV("... address = %s, alias = %s", c_address, c_alias);
+ env->CallVoidMethod(nat->me,
+ method_onRemoteAliasChanged,
+ env->NewStringUTF(c_address),
+ env->NewStringUTF(c_alias));
+ } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
+ return DBUS_HANDLER_RESULT_HANDLED;
+ } else if (dbus_message_is_signal(msg,
+ "org.bluez.Adapter",
+ "RemoteAliasCleared")) {
+ char *c_address;
+ if (dbus_message_get_args(msg, &err,
+ DBUS_TYPE_STRING, &c_address,
+ DBUS_TYPE_INVALID)) {
+ LOGV("... address = %s", c_address);
+ env->CallVoidMethod(nat->me,
+ method_onRemoteAliasCleared,
+ env->NewStringUTF(c_address));
+ } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
+ return DBUS_HANDLER_RESULT_HANDLED;
+ } else if (dbus_message_is_signal(msg,
+ "org.bluez.Adapter",
+ "RemoteDeviceConnected")) {
+ char *c_address;
+ if (dbus_message_get_args(msg, &err,
+ DBUS_TYPE_STRING, &c_address,
+ DBUS_TYPE_INVALID)) {
+ LOGV("... address = %s", c_address);
+ env->CallVoidMethod(nat->me,
+ method_onRemoteDeviceConnected,
+ env->NewStringUTF(c_address));
+ } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
+ return DBUS_HANDLER_RESULT_HANDLED;
+ } else if (dbus_message_is_signal(msg,
+ "org.bluez.Adapter",
+ "RemoteDeviceDisconnectRequested")) {
+ char *c_address;
+ if (dbus_message_get_args(msg, &err,
+ DBUS_TYPE_STRING, &c_address,
+ DBUS_TYPE_INVALID)) {
+ LOGV("... address = %s", c_address);
+ env->CallVoidMethod(nat->me,
+ method_onRemoteDeviceDisconnectRequested,
+ env->NewStringUTF(c_address));
+ } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
+ return DBUS_HANDLER_RESULT_HANDLED;
+ } else if (dbus_message_is_signal(msg,
+ "org.bluez.Adapter",
+ "RemoteDeviceDisconnected")) {
+ char *c_address;
+ if (dbus_message_get_args(msg, &err,
+ DBUS_TYPE_STRING, &c_address,
+ DBUS_TYPE_INVALID)) {
+ LOGV("... address = %s", c_address);
+ env->CallVoidMethod(nat->me,
+ method_onRemoteDeviceDisconnected,
+ env->NewStringUTF(c_address));
+ } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
+ return DBUS_HANDLER_RESULT_HANDLED;
+ } else if (dbus_message_is_signal(msg,
+ "org.bluez.Adapter",
+ "BondingCreated")) {
+ char *c_address;
+ if (dbus_message_get_args(msg, &err,
+ DBUS_TYPE_STRING, &c_address,
+ DBUS_TYPE_INVALID)) {
+ LOGV("... address = %s", c_address);
+ env->CallVoidMethod(nat->me,
+ method_onBondingCreated,
+ env->NewStringUTF(c_address));
+ } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
+ return DBUS_HANDLER_RESULT_HANDLED;
+ } else if (dbus_message_is_signal(msg,
+ "org.bluez.Adapter",
+ "BondingRemoved")) {
+ char *c_address;
+ if (dbus_message_get_args(msg, &err,
+ DBUS_TYPE_STRING, &c_address,
+ DBUS_TYPE_INVALID)) {
+ LOGV("... address = %s", c_address);
+ env->CallVoidMethod(nat->me,
+ method_onBondingRemoved,
+ env->NewStringUTF(c_address));
+ } else LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
+ return DBUS_HANDLER_RESULT_HANDLED;
+ } else {
+ LOGV("... ignored");
+ }
+
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+// Called by dbus during WaitForAndDispatchEventNative()
+static DBusHandlerResult passkey_agent_event_filter(DBusConnection *conn,
+ DBusMessage *msg,
+ void *data) {
+ native_data_t *nat = event_loop_nat;
+ JNIEnv *env;
+
+
+ env = nat->env;
+ if (dbus_message_get_type(msg) != DBUS_MESSAGE_TYPE_METHOD_CALL) {
+ LOGV("%s: not interested (not a method call).", __FUNCTION__);
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+ LOGV("%s: Received method %s:%s", __FUNCTION__,
+ dbus_message_get_interface(msg), dbus_message_get_member(msg));
+
+ if (dbus_message_is_method_call(msg,
+ "org.bluez.PasskeyAgent", "Request")) {
+
+ const char *adapter;
+ const char *address;
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_STRING, &adapter,
+ DBUS_TYPE_STRING, &address,
+ DBUS_TYPE_INVALID)) {
+ LOGE("%s: Invalid arguments for Request() method", __FUNCTION__);
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+
+ LOGV("... address = %s", address);
+
+ dbus_message_ref(msg); // increment refcount because we pass to java
+
+ env->CallVoidMethod(nat->me, method_onPasskeyAgentRequest,
+ env->NewStringUTF(address), (int)msg);
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+
+ } else if (dbus_message_is_method_call(msg,
+ "org.bluez.PasskeyAgent", "Cancel")) {
+
+ const char *adapter;
+ const char *address;
+ if (!dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_STRING, &adapter,
+ DBUS_TYPE_STRING, &address,
+ DBUS_TYPE_INVALID)) {
+ LOGE("%s: Invalid arguments for Cancel() method", __FUNCTION__);
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+
+ LOGV("... address = %s", address);
+
+ env->CallVoidMethod(nat->me, method_onPasskeyAgentCancel,
+ env->NewStringUTF(address));
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+
+ } else if (dbus_message_is_method_call(msg,
+ "org.bluez.PasskeyAgent", "Release")) {
+ LOGE("We are no longer the passkey agent!");
+ } else {
+ LOGV("... ignored");
+ }
+
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+#endif
+
+static jboolean waitForAndDispatchEventNative(JNIEnv *env, jobject object,
+ jint timeout_ms) {
+#ifdef HAVE_BLUETOOTH
+ //LOGV("%s: %8d (pid %d tid %d)",__FUNCTION__, time(NULL), getpid(), gettid()); // too chatty
+ native_data_t *nat = get_native_data(env, object);
+ if (nat != NULL && nat->conn != NULL) {
+ jboolean ret;
+ nat->me = object;
+ nat->env = env;
+ event_loop_nat = nat;
+ ret = dbus_connection_read_write_dispatch(nat->conn,
+ timeout_ms) == TRUE ?
+ JNI_TRUE : JNI_FALSE;
+ event_loop_nat = NULL;
+ nat->me = NULL;
+ nat->env = NULL;
+ return ret;
+ }
+#endif
+ return JNI_FALSE;
+}
+
+#ifdef HAVE_BLUETOOTH
+void onCreateBondingResult(DBusMessage *msg, void *user) {
+ LOGV(__FUNCTION__);
+
+ const char *address = (const char *)user;
+ DBusError err;
+ dbus_error_init(&err);
+ JNIEnv *env = event_loop_nat->env;
+
+ LOGV("... address = %s", address);
+
+ jboolean result = JNI_TRUE;
+ if (dbus_set_error_from_message(&err, msg)) {
+ /* if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.AuthenticationFailed")) */
+ LOGE("%s: D-Bus error: %s (%s)\n", __FUNCTION__, err.name, err.message);
+ result = JNI_FALSE;
+ dbus_error_free(&err);
+ }
+
+ env->CallVoidMethod(event_loop_nat->me,
+ method_onCreateBondingResult,
+ env->NewStringUTF(address),
+ result);
+ free(user);
+}
+
+void onGetRemoteServiceChannelResult(DBusMessage *msg, void *user) {
+ LOGV(__FUNCTION__);
+
+ const char *address = (const char *) user;
+ DBusError err;
+ dbus_error_init(&err);
+ JNIEnv *env = event_loop_nat->env;
+ jint channel = -2;
+
+ LOGV("... address = %s", context->address);
+
+ if (dbus_set_error_from_message(&err, msg) ||
+ !dbus_message_get_args(msg, &err,
+ DBUS_TYPE_INT32, &channel,
+ DBUS_TYPE_INVALID)) {
+ /* if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.AuthenticationFailed")) */
+ LOGE("%s: D-Bus error: %s (%s)\n", __FUNCTION__, err.name, err.message);
+ dbus_error_free(&err);
+ }
+
+done:
+ env->CallVoidMethod(event_loop_nat->me,
+ method_onGetRemoteServiceChannelResult,
+ env->NewStringUTF(address),
+ channel);
+ free(user);
+}
+#endif
+
+static JNINativeMethod sMethods[] = {
+ /* name, signature, funcPtr */
+ {"classInitNative", "()V", (void *)classInitNative},
+ {"initializeNativeDataNative", "()V", (void *)initializeNativeDataNative},
+ {"cleanupNativeDataNative", "()V", (void *)cleanupNativeDataNative},
+ {"setUpEventLoopNative", "()Z", (void *)setUpEventLoopNative},
+ {"tearDownEventLoopNative", "()V", (void *)tearDownEventLoopNative},
+ {"waitForAndDispatchEventNative", "(I)Z", (void *)waitForAndDispatchEventNative}
+};
+
+int register_android_server_BluetoothEventLoop(JNIEnv *env) {
+ return AndroidRuntime::registerNativeMethods(env,
+ "android/server/BluetoothEventLoop", sMethods, NELEM(sMethods));
+}
+
+} /* namespace android */