blob: b02a19b135a4204a4e803a6ded997cfccf75a085 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2** Copyright 2006, 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
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -070017#define DBUS_ADAPTER_IFACE BLUEZ_DBUS_BASE_IFC ".Adapter"
18#define DBUS_DEVICE_IFACE BLUEZ_DBUS_BASE_IFC ".Device"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080019#define LOG_TAG "BluetoothDeviceService.cpp"
20
21#include "android_bluetooth_common.h"
22#include "android_runtime/AndroidRuntime.h"
23#include "JNIHelp.h"
24#include "jni.h"
25#include "utils/Log.h"
26#include "utils/misc.h"
27
28#include <ctype.h>
29#include <stdio.h>
30#include <string.h>
31#include <stdlib.h>
32#include <errno.h>
33#include <unistd.h>
34
35#include <sys/socket.h>
36#include <sys/ioctl.h>
37#include <fcntl.h>
38
39#ifdef HAVE_BLUETOOTH
40#include <dbus/dbus.h>
41#include <bluedroid/bluetooth.h>
42#endif
43
44#include <cutils/properties.h>
45
46namespace android {
47
Nick Pelly2b5be072009-03-31 14:42:33 -070048#define BLUETOOTH_CLASS_ERROR 0xFF000000
49
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080050#ifdef HAVE_BLUETOOTH
51// We initialize these variables when we load class
52// android.server.BluetoothDeviceService
53static jfieldID field_mNativeData;
Robert Greenwalt28d139f2009-04-02 22:41:08 -070054static jfieldID field_mEventLoop;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080055
56typedef struct {
57 JNIEnv *env;
58 DBusConnection *conn;
59 const char *adapter; // dbus object name of the local adapter
60} native_data_t;
61
Robert Greenwalt28d139f2009-04-02 22:41:08 -070062extern event_loop_native_data_t *get_EventLoop_native_data(JNIEnv *,
63 jobject);
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -070064extern DBusHandlerResult agent_event_filter(DBusConnection *conn,
65 DBusMessage *msg,
66 void *data);
67void onCreatePairedDeviceResult(DBusMessage *msg, void *user, void *nat);
68
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080069
70/** Get native data stored in the opaque (Java code maintained) pointer mNativeData
71 * Perform quick sanity check, if there are any problems return NULL
72 */
73static inline native_data_t * get_native_data(JNIEnv *env, jobject object) {
74 native_data_t *nat =
75 (native_data_t *)(env->GetIntField(object, field_mNativeData));
76 if (nat == NULL || nat->conn == NULL) {
77 LOGE("Uninitialized native data\n");
78 return NULL;
79 }
80 return nat;
81}
82#endif
83
84static void classInitNative(JNIEnv* env, jclass clazz) {
85 LOGV(__FUNCTION__);
86#ifdef HAVE_BLUETOOTH
87 field_mNativeData = get_field(env, clazz, "mNativeData", "I");
Robert Greenwalt28d139f2009-04-02 22:41:08 -070088 field_mEventLoop = get_field(env, clazz, "mEventLoop",
89 "Landroid/server/BluetoothEventLoop;");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080090#endif
91}
92
93/* Returns true on success (even if adapter is present but disabled).
94 * Return false if dbus is down, or another serious error (out of memory)
95*/
96static bool initializeNativeDataNative(JNIEnv* env, jobject object) {
97 LOGV(__FUNCTION__);
98#ifdef HAVE_BLUETOOTH
99 native_data_t *nat = (native_data_t *)calloc(1, sizeof(native_data_t));
100 if (NULL == nat) {
101 LOGE("%s: out of memory!", __FUNCTION__);
102 return false;
103 }
104 nat->env = env;
105
106 env->SetIntField(object, field_mNativeData, (jint)nat);
107 DBusError err;
108 dbus_error_init(&err);
109 dbus_threads_init_default();
110 nat->conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
111 if (dbus_error_is_set(&err)) {
112 LOGE("Could not get onto the system bus: %s", err.message);
113 dbus_error_free(&err);
114 return false;
115 }
Nick Pelly9e0a1952009-06-17 15:27:59 -0700116 dbus_connection_set_exit_on_disconnect(nat->conn, FALSE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800117#endif /*HAVE_BLUETOOTH*/
118 return true;
119}
120
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700121static const char *get_adapter_path(JNIEnv* env, jobject object) {
Jaikumar Ganesh82aea4a2009-06-09 23:23:20 -0700122#ifdef HAVE_BLUETOOTH
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700123 event_loop_native_data_t *event_nat =
124 get_EventLoop_native_data(env, env->GetObjectField(object,
125 field_mEventLoop));
126 if (event_nat == NULL)
127 return NULL;
128 return event_nat->adapter;
Jaikumar Ganesh82aea4a2009-06-09 23:23:20 -0700129#else
130 return NULL;
131#endif
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700132}
133
134// This function is called when the adapter is enabled.
135static jboolean setupNativeDataNative(JNIEnv* env, jobject object) {
136 LOGV(__FUNCTION__);
137#ifdef HAVE_BLUETOOTH
138 native_data_t *nat =
139 (native_data_t *)env->GetIntField(object, field_mNativeData);
140 event_loop_native_data_t *event_nat =
141 get_EventLoop_native_data(env, env->GetObjectField(object,
142 field_mEventLoop));
143 // Register agent for remote devices.
144 const char *device_agent_path = "/android/bluetooth/remote_device_agent";
145 static const DBusObjectPathVTable agent_vtable = {
146 NULL, agent_event_filter, NULL, NULL, NULL, NULL };
147
148 if (!dbus_connection_register_object_path(nat->conn, device_agent_path,
149 &agent_vtable, event_nat)) {
150 LOGE("%s: Can't register object path %s for remote device agent!",
151 __FUNCTION__, device_agent_path);
152 return JNI_FALSE;
153 }
154#endif /*HAVE_BLUETOOTH*/
155 return JNI_TRUE;
156}
157
158static jboolean tearDownNativeDataNative(JNIEnv *env, jobject object) {
159 LOGV(__FUNCTION__);
160#ifdef HAVE_BLUETOOTH
161 native_data_t *nat =
162 (native_data_t *)env->GetIntField(object, field_mNativeData);
163 if (nat != NULL) {
164 const char *device_agent_path =
165 "/android/bluetooth/remote_device_agent";
166 dbus_connection_unregister_object_path (nat->conn, device_agent_path);
167 }
168#endif /*HAVE_BLUETOOTH*/
169 return JNI_TRUE;
170}
171
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800172static void cleanupNativeDataNative(JNIEnv* env, jobject object) {
173 LOGV(__FUNCTION__);
174#ifdef HAVE_BLUETOOTH
175 native_data_t *nat =
176 (native_data_t *)env->GetIntField(object, field_mNativeData);
177 if (nat) {
178 free(nat);
179 nat = NULL;
180 }
181#endif
182}
183
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800184static jstring getAdapterPathNative(JNIEnv *env, jobject object) {
185 LOGV(__FUNCTION__);
186#ifdef HAVE_BLUETOOTH
187 native_data_t *nat = get_native_data(env, object);
188 if (nat) {
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700189 return (env->NewStringUTF(get_adapter_path(env, object)));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800190 }
191#endif
192 return NULL;
193}
194
195
196static jboolean startDiscoveryNative(JNIEnv *env, jobject object) {
197 LOGV(__FUNCTION__);
198#ifdef HAVE_BLUETOOTH
199 DBusMessage *msg = NULL;
200 DBusMessage *reply = NULL;
201 DBusError err;
202 const char *name;
203 jboolean ret = JNI_FALSE;
204
205 native_data_t *nat = get_native_data(env, object);
206 if (nat == NULL) {
207 goto done;
208 }
209
210 dbus_error_init(&err);
211
212 /* Compose the command */
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700213 msg = dbus_message_new_method_call(BLUEZ_DBUS_BASE_IFC,
214 get_adapter_path(env, object),
215 DBUS_ADAPTER_IFACE, "StartDiscovery");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800216
217 if (msg == NULL) {
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700218 if (dbus_error_is_set(&err)) {
219 LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
220 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800221 goto done;
222 }
223
224 /* Send the command. */
225 reply = dbus_connection_send_with_reply_and_block(nat->conn, msg, -1, &err);
226 if (dbus_error_is_set(&err)) {
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700227 LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
228 ret = JNI_FALSE;
229 goto done;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800230 }
231
232 ret = JNI_TRUE;
233done:
234 if (reply) dbus_message_unref(reply);
235 if (msg) dbus_message_unref(msg);
236 return ret;
237#else
238 return JNI_FALSE;
239#endif
240}
241
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700242static void stopDiscoveryNative(JNIEnv *env, jobject object) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800243 LOGV(__FUNCTION__);
244#ifdef HAVE_BLUETOOTH
245 DBusMessage *msg = NULL;
246 DBusMessage *reply = NULL;
247 DBusError err;
248 const char *name;
249 jstring ret;
250 native_data_t *nat;
251
252 dbus_error_init(&err);
253
254 nat = get_native_data(env, object);
255 if (nat == NULL) {
256 goto done;
257 }
258
259 /* Compose the command */
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700260 msg = dbus_message_new_method_call(BLUEZ_DBUS_BASE_IFC,
261 get_adapter_path(env, object),
262 DBUS_ADAPTER_IFACE, "StopDiscovery");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800263 if (msg == NULL) {
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700264 if (dbus_error_is_set(&err))
265 LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800266 goto done;
267 }
268
269 /* Send the command. */
270 reply = dbus_connection_send_with_reply_and_block(nat->conn, msg, -1, &err);
271 if (dbus_error_is_set(&err)) {
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700272 if(strncmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.NotAuthorized",
273 strlen(BLUEZ_DBUS_BASE_IFC ".Error.NotAuthorized")) == 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800274 // hcid sends this if there is no active discovery to cancel
275 LOGV("%s: There was no active discovery to cancel", __FUNCTION__);
276 dbus_error_free(&err);
277 } else {
278 LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
279 }
280 }
281
282done:
283 if (msg) dbus_message_unref(msg);
284 if (reply) dbus_message_unref(reply);
285#endif
286}
287
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700288static jboolean createPairedDeviceNative(JNIEnv *env, jobject object,
289 jstring address, jint timeout_ms) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800290 LOGV(__FUNCTION__);
291#ifdef HAVE_BLUETOOTH
292 native_data_t *nat = get_native_data(env, object);
Robert Greenwalt28d139f2009-04-02 22:41:08 -0700293 jobject eventLoop = env->GetObjectField(object, field_mEventLoop);
294 struct event_loop_native_data_t *eventLoopNat =
295 get_EventLoop_native_data(env, eventLoop);
296
297 if (nat && eventLoopNat) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800298 const char *c_address = env->GetStringUTFChars(address, NULL);
299 LOGV("... address = %s", c_address);
300 char *context_address = (char *)calloc(BTADDR_SIZE, sizeof(char));
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700301 const char *capabilities = "DisplayYesNo";
302 const char *agent_path = "/android/bluetooth/remote_device_agent";
303
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800304 strlcpy(context_address, c_address, BTADDR_SIZE); // for callback
305 bool ret = dbus_func_args_async(env, nat->conn, (int)timeout_ms,
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700306 onCreatePairedDeviceResult, // callback
Robert Greenwalt28d139f2009-04-02 22:41:08 -0700307 context_address,
308 eventLoopNat,
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700309 get_adapter_path(env, object),
310 DBUS_ADAPTER_IFACE,
311 "CreatePairedDevice",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800312 DBUS_TYPE_STRING, &c_address,
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700313 DBUS_TYPE_OBJECT_PATH, &agent_path,
314 DBUS_TYPE_STRING, &capabilities,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800315 DBUS_TYPE_INVALID);
316 env->ReleaseStringUTFChars(address, c_address);
317 return ret ? JNI_TRUE : JNI_FALSE;
318
319 }
320#endif
321 return JNI_FALSE;
322}
323
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700324static jint getDeviceServiceChannelNative(JNIEnv *env, jobject object,
325 jstring path,
326 jstring pattern, jint attr_id) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800327#ifdef HAVE_BLUETOOTH
328 LOGV(__FUNCTION__);
329 native_data_t *nat = get_native_data(env, object);
Robert Greenwalt28d139f2009-04-02 22:41:08 -0700330 jobject eventLoop = env->GetObjectField(object, field_mEventLoop);
331 struct event_loop_native_data_t *eventLoopNat =
332 get_EventLoop_native_data(env, eventLoop);
333 if (nat && eventLoopNat) {
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700334 const char *c_pattern = env->GetStringUTFChars(pattern, NULL);
335 const char *c_path = env->GetStringUTFChars(path, NULL);
336 LOGV("... pattern = %s", c_pattern);
337 LOGV("... attr_id = %#X", attr_id);
338 DBusMessage *reply =
339 dbus_func_args(env, nat->conn, c_path,
340 DBUS_DEVICE_IFACE, "GetServiceAttributeValue",
341 DBUS_TYPE_STRING, &c_pattern,
342 DBUS_TYPE_UINT16, &attr_id,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800343 DBUS_TYPE_INVALID);
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700344 env->ReleaseStringUTFChars(pattern, c_pattern);
345 env->ReleaseStringUTFChars(path, c_path);
346 return reply ? dbus_returns_int32(env, reply) : -1;
347 }
348#endif
349 return -1;
350}
351
352static jboolean cancelDeviceCreationNative(JNIEnv *env, jobject object,
353 jstring address) {
354 LOGV(__FUNCTION__);
355 jboolean result = JNI_FALSE;
356#ifdef HAVE_BLUETOOTH
357 native_data_t *nat = get_native_data(env, object);
358 if (nat) {
359 const char *c_address = env->GetStringUTFChars(address, NULL);
360 DBusError err;
361 dbus_error_init(&err);
362 LOGV("... address = %s", c_address);
363 DBusMessage *reply =
364 dbus_func_args_timeout(env, nat->conn, -1,
365 get_adapter_path(env, object),
366 DBUS_ADAPTER_IFACE, "CancelDeviceCreation",
367 DBUS_TYPE_STRING, &c_address,
368 DBUS_TYPE_INVALID);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800369 env->ReleaseStringUTFChars(address, c_address);
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700370 if (!reply) {
371 if (dbus_error_is_set(&err)) {
372 LOG_AND_FREE_DBUS_ERROR(&err);
373 } else
374 LOGE("DBus reply is NULL in function %s", __FUNCTION__);
375 return JNI_FALSE;
376 } else {
377 result = JNI_TRUE;
378 }
379 dbus_message_unref(reply);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800380 }
381#endif
382 return JNI_FALSE;
383}
384
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700385static jboolean removeDeviceNative(JNIEnv *env, jobject object, jstring object_path) {
386 LOGV(__FUNCTION__);
387 jboolean result = JNI_FALSE;
388#ifdef HAVE_BLUETOOTH
389 native_data_t *nat = get_native_data(env, object);
390 if (nat) {
391 const char *c_object_path = env->GetStringUTFChars(object_path, NULL);
392 DBusError err;
393 dbus_error_init(&err);
394 DBusMessage *reply =
395 dbus_func_args_error(env, nat->conn, &err,
396 get_adapter_path(env, object),
397 DBUS_ADAPTER_IFACE, "RemoveDevice",
398 DBUS_TYPE_OBJECT_PATH, &c_object_path,
399 DBUS_TYPE_INVALID);
400 if (!reply) {
401 if (dbus_error_is_set(&err)) {
402 LOG_AND_FREE_DBUS_ERROR(&err);
403 } else
404 LOGE("DBus reply is NULL in function %s", __FUNCTION__);
405 result = JNI_FALSE;
406 } else {
407 result = JNI_TRUE;
408 }
409 env->ReleaseStringUTFChars(object_path, c_object_path);
410 if (reply) dbus_message_unref(reply);
411 }
412#endif
413 return result;
414}
415
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800416static jint enableNative(JNIEnv *env, jobject object) {
417#ifdef HAVE_BLUETOOTH
418 LOGV(__FUNCTION__);
419 return bt_enable();
420#endif
421 return -1;
422}
423
424static jint disableNative(JNIEnv *env, jobject object) {
425#ifdef HAVE_BLUETOOTH
426 LOGV(__FUNCTION__);
427 return bt_disable();
428#endif
429 return -1;
430}
431
432static jint isEnabledNative(JNIEnv *env, jobject object) {
433#ifdef HAVE_BLUETOOTH
434 LOGV(__FUNCTION__);
435 return bt_is_enabled();
436#endif
437 return -1;
438}
439
440static jboolean setPinNative(JNIEnv *env, jobject object, jstring address,
441 jstring pin, int nativeData) {
442#ifdef HAVE_BLUETOOTH
443 LOGV(__FUNCTION__);
444 native_data_t *nat = get_native_data(env, object);
445 if (nat) {
446 DBusMessage *msg = (DBusMessage *)nativeData;
447 DBusMessage *reply = dbus_message_new_method_return(msg);
448 if (!reply) {
449 LOGE("%s: Cannot create message reply to return PIN code to "
450 "D-Bus\n", __FUNCTION__);
451 dbus_message_unref(msg);
452 return JNI_FALSE;
453 }
454
455 const char *c_pin = env->GetStringUTFChars(pin, NULL);
456
457 dbus_message_append_args(reply, DBUS_TYPE_STRING, &c_pin,
458 DBUS_TYPE_INVALID);
459
460 dbus_connection_send(nat->conn, reply, NULL);
461 dbus_message_unref(msg);
462 dbus_message_unref(reply);
463 env->ReleaseStringUTFChars(pin, c_pin);
464 return JNI_TRUE;
465 }
466#endif
467 return JNI_FALSE;
468}
469
Jaikumar Ganesh12cae392009-07-17 14:45:22 -0700470static jboolean cancelPinNative(JNIEnv *env, jobject object, jstring address,
471 int nativeData) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800472#ifdef HAVE_BLUETOOTH
473 LOGV(__FUNCTION__);
474 native_data_t *nat = get_native_data(env, object);
475 if (nat) {
476 DBusMessage *msg = (DBusMessage *)nativeData;
477 DBusMessage *reply = dbus_message_new_error(msg,
Jaikumar Ganesh12cae392009-07-17 14:45:22 -0700478 "org.bluez.Error.Canceled", "PIN Entry was canceled");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800479 if (!reply) {
Jaikumar Ganesh12cae392009-07-17 14:45:22 -0700480 LOGE("%s: Cannot create message reply to return PIN cancel to "
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800481 "D-BUS\n", __FUNCTION__);
482 dbus_message_unref(msg);
483 return JNI_FALSE;
484 }
485
486 dbus_connection_send(nat->conn, reply, NULL);
487 dbus_message_unref(msg);
488 dbus_message_unref(reply);
489 return JNI_TRUE;
490 }
491#endif
492 return JNI_FALSE;
493}
494
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700495static jobjectArray getDevicePropertiesNative(JNIEnv *env, jobject object,
496 jstring path)
497{
498#ifdef HAVE_BLUETOOTH
499 LOGV(__FUNCTION__);
500 native_data_t *nat = get_native_data(env, object);
501 if (nat) {
502 DBusMessage *msg, *reply;
503 DBusError err;
504 dbus_error_init(&err);
505
506 const char *c_path = env->GetStringUTFChars(path, NULL);
507 reply = dbus_func_args_timeout(env,
508 nat->conn, -1, c_path,
509 DBUS_DEVICE_IFACE, "GetProperties",
510 DBUS_TYPE_INVALID);
511 env->ReleaseStringUTFChars(path, c_path);
512
513 if (!reply) {
514 if (dbus_error_is_set(&err)) {
515 LOG_AND_FREE_DBUS_ERROR(&err);
516 } else
517 LOGE("DBus reply is NULL in function %s", __FUNCTION__);
518 return NULL;
519 }
520 DBusMessageIter iter;
521 jobjectArray str_array = NULL;
522 if (dbus_message_iter_init(reply, &iter))
523 str_array = parse_remote_device_properties(env, &iter);
524 dbus_message_unref(reply);
525 return str_array;
526 }
527#endif
528 return NULL;
529}
530
531static jobjectArray getAdapterPropertiesNative(JNIEnv *env, jobject object) {
532#ifdef HAVE_BLUETOOTH
533 LOGV(__FUNCTION__);
534 native_data_t *nat = get_native_data(env, object);
535 if (nat) {
536 DBusMessage *msg, *reply;
537 DBusError err;
538 dbus_error_init(&err);
539
540 reply = dbus_func_args_timeout(env,
541 nat->conn, -1, get_adapter_path(env, object),
542 DBUS_ADAPTER_IFACE, "GetProperties",
543 DBUS_TYPE_INVALID);
544 if (!reply) {
545 if (dbus_error_is_set(&err)) {
546 LOG_AND_FREE_DBUS_ERROR(&err);
547 } else
548 LOGE("DBus reply is NULL in function %s", __FUNCTION__);
549 return NULL;
550 }
551 DBusMessageIter iter;
552 jobjectArray str_array = NULL;
553 if (dbus_message_iter_init(reply, &iter))
554 str_array = parse_adapter_properties(env, &iter);
555 dbus_message_unref(reply);
556 return str_array;
557 }
558#endif
559 return NULL;
560}
561
562static jboolean setAdapterPropertyNative(JNIEnv *env, jobject object, jstring key,
563 void *value, jint type) {
564#ifdef HAVE_BLUETOOTH
565 LOGV(__FUNCTION__);
566 native_data_t *nat = get_native_data(env, object);
567 if (nat) {
568 DBusMessage *reply, *msg;
569 DBusMessageIter iter;
570 DBusError err;
571 const char *c_key = env->GetStringUTFChars(key, NULL);
572 dbus_error_init(&err);
573
574 msg = dbus_message_new_method_call(BLUEZ_DBUS_BASE_IFC,
575 get_adapter_path(env, object),
576 DBUS_ADAPTER_IFACE, "SetProperty");
577 if (!msg) {
578 LOGE("%s: Can't allocate new method call for GetProperties!",
579 __FUNCTION__);
580 return JNI_FALSE;
581 }
582
583 dbus_message_append_args(msg, DBUS_TYPE_STRING, &c_key, DBUS_TYPE_INVALID);
584 dbus_message_iter_init_append(msg, &iter);
585 append_variant(&iter, type, value);
586
587 reply = dbus_connection_send_with_reply_and_block(nat->conn, msg, -1, &err);
588 dbus_message_unref(msg);
589
590 env->ReleaseStringUTFChars(key, c_key);
591
592 if (!reply) {
593 if (dbus_error_is_set(&err)) {
594 LOG_AND_FREE_DBUS_ERROR(&err);
595 } else
596 LOGE("DBus reply is NULL in function %s", __FUNCTION__);
597 return JNI_FALSE;
598 }
599 return JNI_TRUE;
600 }
601#endif
602 return JNI_FALSE;
603}
604
605static jboolean setAdapterPropertyStringNative(JNIEnv *env, jobject object, jstring key,
606 jstring value) {
Jaikumar Ganeshd4613492009-06-09 23:32:42 -0700607#ifdef HAVE_BLUETOOTH
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700608 const char *c_value = env->GetStringUTFChars(value, NULL);
609 jboolean ret = setAdapterPropertyNative(env, object, key, (void *)&c_value, DBUS_TYPE_STRING);
610 env->ReleaseStringUTFChars(value, (char *)c_value);
611 return ret;
Jaikumar Ganeshd4613492009-06-09 23:32:42 -0700612#else
613 return JNI_FALSE;
614#endif
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700615}
616
617static jboolean setAdapterPropertyIntegerNative(JNIEnv *env, jobject object, jstring key,
618 jint value) {
Jaikumar Ganeshd4613492009-06-09 23:32:42 -0700619#ifdef HAVE_BLUETOOTH
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700620 return setAdapterPropertyNative(env, object, key, (void *)&value, DBUS_TYPE_UINT32);
Jaikumar Ganeshd4613492009-06-09 23:32:42 -0700621#else
622 return JNI_FALSE;
623#endif
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700624}
625
626static jboolean setAdapterPropertyBooleanNative(JNIEnv *env, jobject object, jstring key,
627 jint value) {
Jaikumar Ganeshd4613492009-06-09 23:32:42 -0700628#ifdef HAVE_BLUETOOTH
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700629 return setAdapterPropertyNative(env, object, key, (void *)&value, DBUS_TYPE_BOOLEAN);
Jaikumar Ganeshd4613492009-06-09 23:32:42 -0700630#else
631 return JNI_FALSE;
632#endif
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700633}
634
635
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800636static JNINativeMethod sMethods[] = {
637 /* name, signature, funcPtr */
638 {"classInitNative", "()V", (void*)classInitNative},
639 {"initializeNativeDataNative", "()V", (void *)initializeNativeDataNative},
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700640 {"setupNativeDataNative", "()Z", (void *)setupNativeDataNative},
641 {"tearDownNativeDataNative", "()Z", (void *)tearDownNativeDataNative},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800642 {"cleanupNativeDataNative", "()V", (void *)cleanupNativeDataNative},
643 {"getAdapterPathNative", "()Ljava/lang/String;", (void*)getAdapterPathNative},
644
645 {"isEnabledNative", "()I", (void *)isEnabledNative},
646 {"enableNative", "()I", (void *)enableNative},
647 {"disableNative", "()I", (void *)disableNative},
648
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700649 {"getAdapterPropertiesNative", "()[Ljava/lang/Object;", (void *)getAdapterPropertiesNative},
650 {"getDevicePropertiesNative", "(Ljava/lang/String;)[Ljava/lang/Object;",
651 (void *)getDevicePropertiesNative},
652 {"setAdapterPropertyStringNative", "(Ljava/lang/String;Ljava/lang/String;)Z",
653 (void *)setAdapterPropertyStringNative},
654 {"setAdapterPropertyBooleanNative", "(Ljava/lang/String;I)Z",
655 (void *)setAdapterPropertyBooleanNative},
656 {"setAdapterPropertyIntegerNative", "(Ljava/lang/String;I)Z",
657 (void *)setAdapterPropertyIntegerNative},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800658
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700659 {"startDiscoveryNative", "()Z", (void*)startDiscoveryNative},
660 {"stopDiscoveryNative", "()Z", (void *)stopDiscoveryNative},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800661
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700662 {"createPairedDeviceNative", "(Ljava/lang/String;I)Z", (void *)createPairedDeviceNative},
663 {"cancelDeviceCreationNative", "(Ljava/lang/String;)Z", (void *)cancelDeviceCreationNative},
664 {"removeDeviceNative", "(Ljava/lang/String;)Z", (void *)removeDeviceNative},
665 {"getDeviceServiceChannelNative", "(Ljava/lang/String;Ljava/lang/String;I)I",
666 (void *)getDeviceServiceChannelNative},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800667
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800668 {"setPinNative", "(Ljava/lang/String;Ljava/lang/String;I)Z", (void *)setPinNative},
Jaikumar Ganesh12cae392009-07-17 14:45:22 -0700669 {"cancelPinNative", "(Ljava/lang/String;I)Z", (void *)cancelPinNative},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800670};
671
672int register_android_server_BluetoothDeviceService(JNIEnv *env) {
673 return AndroidRuntime::registerNativeMethods(env,
674 "android/server/BluetoothDeviceService", sMethods, NELEM(sMethods));
675}
676
677} /* namespace android */