blob: aae0f21d5d8755d565dd69384499d086494be76d [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
17#define LOG_TAG "bluetooth_common.cpp"
18
19#include "android_bluetooth_common.h"
20#include "JNIHelp.h"
21#include "jni.h"
22#include "utils/Log.h"
23#include "utils/misc.h"
24
25#include <stdio.h>
26#include <string.h>
27#include <stdlib.h>
28#include <errno.h>
29#include <unistd.h>
30#include <cutils/properties.h>
31
32#ifdef HAVE_BLUETOOTH
33#include <dbus/dbus.h>
34#endif
35
36namespace android {
37
38#ifdef HAVE_BLUETOOTH
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -070039
40static Properties remote_device_properties[] = {
41 {"Address", DBUS_TYPE_STRING},
42 {"Name", DBUS_TYPE_STRING},
43 {"Icon", DBUS_TYPE_STRING},
44 {"Class", DBUS_TYPE_UINT32},
45 {"UUIDs", DBUS_TYPE_ARRAY},
46 {"Paired", DBUS_TYPE_BOOLEAN},
47 {"Connected", DBUS_TYPE_BOOLEAN},
48 {"Trusted", DBUS_TYPE_BOOLEAN},
Jaikumar Ganesh6eb300e2010-08-04 11:26:38 -070049 {"Blocked", DBUS_TYPE_BOOLEAN},
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -070050 {"Alias", DBUS_TYPE_STRING},
51 {"Nodes", DBUS_TYPE_ARRAY},
52 {"Adapter", DBUS_TYPE_OBJECT_PATH},
53 {"LegacyPairing", DBUS_TYPE_BOOLEAN},
54 {"RSSI", DBUS_TYPE_INT16},
55 {"TX", DBUS_TYPE_UINT32}
56};
57
58static Properties adapter_properties[] = {
59 {"Address", DBUS_TYPE_STRING},
60 {"Name", DBUS_TYPE_STRING},
61 {"Class", DBUS_TYPE_UINT32},
62 {"Powered", DBUS_TYPE_BOOLEAN},
63 {"Discoverable", DBUS_TYPE_BOOLEAN},
64 {"DiscoverableTimeout", DBUS_TYPE_UINT32},
65 {"Pairable", DBUS_TYPE_BOOLEAN},
66 {"PairableTimeout", DBUS_TYPE_UINT32},
67 {"Discovering", DBUS_TYPE_BOOLEAN},
68 {"Devices", DBUS_TYPE_ARRAY},
Jaikumar Ganesh94278c92010-05-03 15:45:58 -070069 {"UUIDs", DBUS_TYPE_ARRAY},
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -070070};
71
Jaikumar Ganesh545e6702010-06-04 10:23:03 -070072static Properties input_properties[] = {
73 {"Connected", DBUS_TYPE_BOOLEAN},
74};
75
Danica Chang6fdd0c62010-08-11 14:54:43 -070076static Properties pan_properties[] = {
77 {"Connected", DBUS_TYPE_BOOLEAN},
78 {"Interface", DBUS_TYPE_STRING},
79 {"UUID", DBUS_TYPE_STRING},
80};
81
Jaikumar Ganesh8bc8ce42009-06-24 16:42:51 -070082typedef union {
83 char *str_val;
84 int int_val;
85 char **array_val;
86} property_value;
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -070087
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080088jfieldID get_field(JNIEnv *env, jclass clazz, const char *member,
89 const char *mtype) {
90 jfieldID field = env->GetFieldID(clazz, member, mtype);
91 if (field == NULL) {
92 LOGE("Can't find member %s", member);
93 }
94 return field;
95}
96
97typedef struct {
Robert Greenwalt28d139f2009-04-02 22:41:08 -070098 void (*user_cb)(DBusMessage *, void *, void *);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080099 void *user;
Robert Greenwalt28d139f2009-04-02 22:41:08 -0700100 void *nat;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800101 JNIEnv *env;
102} dbus_async_call_t;
103
104void dbus_func_args_async_callback(DBusPendingCall *call, void *data) {
105
106 dbus_async_call_t *req = (dbus_async_call_t *)data;
107 DBusMessage *msg;
108
109 /* This is guaranteed to be non-NULL, because this function is called only
110 when once the remote method invokation returns. */
111 msg = dbus_pending_call_steal_reply(call);
112
113 if (msg) {
114 if (req->user_cb) {
115 // The user may not deref the message object.
Robert Greenwalt28d139f2009-04-02 22:41:08 -0700116 req->user_cb(msg, req->user, req->nat);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800117 }
118 dbus_message_unref(msg);
119 }
120
121 //dbus_message_unref(req->method);
122 dbus_pending_call_cancel(call);
123 dbus_pending_call_unref(call);
124 free(req);
125}
126
Robert Greenwalt28d139f2009-04-02 22:41:08 -0700127static dbus_bool_t dbus_func_args_async_valist(JNIEnv *env,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800128 DBusConnection *conn,
129 int timeout_ms,
Robert Greenwalt28d139f2009-04-02 22:41:08 -0700130 void (*user_cb)(DBusMessage *,
131 void *,
132 void*),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800133 void *user,
Robert Greenwalt28d139f2009-04-02 22:41:08 -0700134 void *nat,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800135 const char *path,
136 const char *ifc,
137 const char *func,
138 int first_arg_type,
139 va_list args) {
140 DBusMessage *msg = NULL;
141 const char *name;
142 dbus_async_call_t *pending;
143 dbus_bool_t reply = FALSE;
144
145 /* Compose the command */
146 msg = dbus_message_new_method_call(BLUEZ_DBUS_BASE_IFC, path, ifc, func);
147
148 if (msg == NULL) {
149 LOGE("Could not allocate D-Bus message object!");
150 goto done;
151 }
152
153 /* append arguments */
154 if (!dbus_message_append_args_valist(msg, first_arg_type, args)) {
155 LOGE("Could not append argument to method call!");
156 goto done;
157 }
158
159 /* Make the call. */
160 pending = (dbus_async_call_t *)malloc(sizeof(dbus_async_call_t));
161 if (pending) {
162 DBusPendingCall *call;
163
164 pending->env = env;
165 pending->user_cb = user_cb;
166 pending->user = user;
Robert Greenwalt28d139f2009-04-02 22:41:08 -0700167 pending->nat = nat;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800168 //pending->method = msg;
169
170 reply = dbus_connection_send_with_reply(conn, msg,
171 &call,
172 timeout_ms);
173 if (reply == TRUE) {
174 dbus_pending_call_set_notify(call,
175 dbus_func_args_async_callback,
176 pending,
177 NULL);
178 }
179 }
180
181done:
182 if (msg) dbus_message_unref(msg);
183 return reply;
184}
185
186dbus_bool_t dbus_func_args_async(JNIEnv *env,
187 DBusConnection *conn,
188 int timeout_ms,
Robert Greenwalt28d139f2009-04-02 22:41:08 -0700189 void (*reply)(DBusMessage *, void *, void*),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800190 void *user,
Robert Greenwalt28d139f2009-04-02 22:41:08 -0700191 void *nat,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800192 const char *path,
193 const char *ifc,
194 const char *func,
195 int first_arg_type,
196 ...) {
197 dbus_bool_t ret;
198 va_list lst;
199 va_start(lst, first_arg_type);
Danica Chang6fdd0c62010-08-11 14:54:43 -0700200
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800201 ret = dbus_func_args_async_valist(env, conn,
202 timeout_ms,
Robert Greenwalt28d139f2009-04-02 22:41:08 -0700203 reply, user, nat,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800204 path, ifc, func,
205 first_arg_type, lst);
206 va_end(lst);
207 return ret;
208}
209
210// If err is NULL, then any errors will be LOGE'd, and free'd and the reply
211// will be NULL.
212// If err is not NULL, then it is assumed that dbus_error_init was already
213// called, and error's will be returned to the caller without logging. The
214// return value is NULL iff an error was set. The client must free the error if
215// set.
216DBusMessage * dbus_func_args_timeout_valist(JNIEnv *env,
217 DBusConnection *conn,
218 int timeout_ms,
219 DBusError *err,
220 const char *path,
221 const char *ifc,
222 const char *func,
223 int first_arg_type,
224 va_list args) {
225
226 DBusMessage *msg = NULL, *reply = NULL;
227 const char *name;
228 bool return_error = (err != NULL);
229
230 if (!return_error) {
231 err = (DBusError*)malloc(sizeof(DBusError));
232 dbus_error_init(err);
233 }
234
235 /* Compose the command */
236 msg = dbus_message_new_method_call(BLUEZ_DBUS_BASE_IFC, path, ifc, func);
237
238 if (msg == NULL) {
239 LOGE("Could not allocate D-Bus message object!");
240 goto done;
241 }
242
243 /* append arguments */
244 if (!dbus_message_append_args_valist(msg, first_arg_type, args)) {
245 LOGE("Could not append argument to method call!");
246 goto done;
247 }
248
249 /* Make the call. */
250 reply = dbus_connection_send_with_reply_and_block(conn, msg, timeout_ms, err);
251 if (!return_error && dbus_error_is_set(err)) {
252 LOG_AND_FREE_DBUS_ERROR_WITH_MSG(err, msg);
253 }
254
255done:
256 if (!return_error) {
257 free(err);
258 }
259 if (msg) dbus_message_unref(msg);
260 return reply;
261}
262
263DBusMessage * dbus_func_args_timeout(JNIEnv *env,
264 DBusConnection *conn,
265 int timeout_ms,
266 const char *path,
267 const char *ifc,
268 const char *func,
269 int first_arg_type,
270 ...) {
271 DBusMessage *ret;
272 va_list lst;
273 va_start(lst, first_arg_type);
274 ret = dbus_func_args_timeout_valist(env, conn, timeout_ms, NULL,
275 path, ifc, func,
276 first_arg_type, lst);
277 va_end(lst);
278 return ret;
279}
280
281DBusMessage * dbus_func_args(JNIEnv *env,
282 DBusConnection *conn,
283 const char *path,
284 const char *ifc,
285 const char *func,
286 int first_arg_type,
287 ...) {
288 DBusMessage *ret;
289 va_list lst;
290 va_start(lst, first_arg_type);
291 ret = dbus_func_args_timeout_valist(env, conn, -1, NULL,
292 path, ifc, func,
293 first_arg_type, lst);
294 va_end(lst);
295 return ret;
296}
297
298DBusMessage * dbus_func_args_error(JNIEnv *env,
299 DBusConnection *conn,
300 DBusError *err,
301 const char *path,
302 const char *ifc,
303 const char *func,
304 int first_arg_type,
305 ...) {
306 DBusMessage *ret;
307 va_list lst;
308 va_start(lst, first_arg_type);
309 ret = dbus_func_args_timeout_valist(env, conn, -1, err,
310 path, ifc, func,
311 first_arg_type, lst);
312 va_end(lst);
313 return ret;
314}
315
316jint dbus_returns_int32(JNIEnv *env, DBusMessage *reply) {
317
318 DBusError err;
319 jint ret = -1;
320
321 dbus_error_init(&err);
322 if (!dbus_message_get_args(reply, &err,
323 DBUS_TYPE_INT32, &ret,
324 DBUS_TYPE_INVALID)) {
325 LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, reply);
326 }
327 dbus_message_unref(reply);
328 return ret;
329}
330
331jint dbus_returns_uint32(JNIEnv *env, DBusMessage *reply) {
332
333 DBusError err;
334 jint ret = -1;
335
336 dbus_error_init(&err);
337 if (!dbus_message_get_args(reply, &err,
338 DBUS_TYPE_UINT32, &ret,
339 DBUS_TYPE_INVALID)) {
340 LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, reply);
341 }
342 dbus_message_unref(reply);
343 return ret;
344}
345
346jstring dbus_returns_string(JNIEnv *env, DBusMessage *reply) {
347
348 DBusError err;
349 jstring ret = NULL;
350 const char *name;
351
352 dbus_error_init(&err);
353 if (dbus_message_get_args(reply, &err,
354 DBUS_TYPE_STRING, &name,
355 DBUS_TYPE_INVALID)) {
356 ret = env->NewStringUTF(name);
357 } else {
358 LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, reply);
359 }
360 dbus_message_unref(reply);
361
362 return ret;
363}
364
365jboolean dbus_returns_boolean(JNIEnv *env, DBusMessage *reply) {
366 DBusError err;
367 jboolean ret = JNI_FALSE;
368 dbus_bool_t val = FALSE;
369
370 dbus_error_init(&err);
371
372 /* Check the return value. */
373 if (dbus_message_get_args(reply, &err,
374 DBUS_TYPE_BOOLEAN, &val,
375 DBUS_TYPE_INVALID)) {
376 ret = val == TRUE ? JNI_TRUE : JNI_FALSE;
377 } else {
378 LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, reply);
379 }
380
381 dbus_message_unref(reply);
382 return ret;
383}
384
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700385static void set_object_array_element(JNIEnv *env, jobjectArray strArray,
386 const char *value, int index) {
387 jstring obj;
388 obj = env->NewStringUTF(value);
389 env->SetObjectArrayElement(strArray, index, obj);
390 env->DeleteLocalRef(obj);
391}
392
393jobjectArray dbus_returns_array_of_object_path(JNIEnv *env,
394 DBusMessage *reply) {
395
396 DBusError err;
397 char **list;
398 int i, len;
399 jobjectArray strArray = NULL;
400
401 dbus_error_init(&err);
402 if (dbus_message_get_args (reply,
403 &err,
404 DBUS_TYPE_ARRAY, DBUS_TYPE_OBJECT_PATH,
405 &list, &len,
406 DBUS_TYPE_INVALID)) {
407 jclass stringClass;
408 jstring classNameStr;
409
410 stringClass = env->FindClass("java/lang/String");
411 strArray = env->NewObjectArray(len, stringClass, NULL);
412
413 for (i = 0; i < len; i++)
414 set_object_array_element(env, strArray, list[i], i);
415 } else {
416 LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, reply);
417 }
418
419 dbus_message_unref(reply);
420 return strArray;
421}
422
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800423jobjectArray dbus_returns_array_of_strings(JNIEnv *env, DBusMessage *reply) {
424
425 DBusError err;
426 char **list;
427 int i, len;
428 jobjectArray strArray = NULL;
429
430 dbus_error_init(&err);
431 if (dbus_message_get_args (reply,
432 &err,
433 DBUS_TYPE_ARRAY, DBUS_TYPE_STRING,
434 &list, &len,
435 DBUS_TYPE_INVALID)) {
436 jclass stringClass;
437 jstring classNameStr;
438
439 //LOGV("%s: there are %d elements in string array!", __FUNCTION__, len);
440
441 stringClass = env->FindClass("java/lang/String");
442 strArray = env->NewObjectArray(len, stringClass, NULL);
443
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700444 for (i = 0; i < len; i++)
445 set_object_array_element(env, strArray, list[i], i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800446 } else {
447 LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, reply);
448 }
449
450 dbus_message_unref(reply);
451 return strArray;
452}
453
454jbyteArray dbus_returns_array_of_bytes(JNIEnv *env, DBusMessage *reply) {
455
456 DBusError err;
457 int i, len;
458 jbyte *list;
459 jbyteArray byteArray = NULL;
460
461 dbus_error_init(&err);
462 if (dbus_message_get_args(reply, &err,
463 DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &list, &len,
464 DBUS_TYPE_INVALID)) {
465 //LOGV("%s: there are %d elements in byte array!", __FUNCTION__, len);
466 byteArray = env->NewByteArray(len);
467 if (byteArray)
468 env->SetByteArrayRegion(byteArray, 0, len, list);
469
470 } else {
471 LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, reply);
472 }
473
474 dbus_message_unref(reply);
475 return byteArray;
476}
477
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700478void append_variant(DBusMessageIter *iter, int type, void *val)
479{
480 DBusMessageIter value_iter;
481 char var_type[2] = { type, '\0'};
482 dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, var_type, &value_iter);
483 dbus_message_iter_append_basic(&value_iter, type, val);
484 dbus_message_iter_close_container(iter, &value_iter);
485}
486
Jaikumar Ganesh8bc8ce42009-06-24 16:42:51 -0700487int get_property(DBusMessageIter iter, Properties *properties,
488 int max_num_properties, int *prop_index, property_value *value, int *len) {
489 DBusMessageIter prop_val, array_val_iter;
490 char *property = NULL;
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700491 uint32_t array_type;
Jaikumar Ganesh8bc8ce42009-06-24 16:42:51 -0700492 char *str_val;
493 int i, j, type, int_val;
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700494
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700495 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
Jaikumar Ganesh8bc8ce42009-06-24 16:42:51 -0700496 return -1;
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700497 dbus_message_iter_get_basic(&iter, &property);
498 if (!dbus_message_iter_next(&iter))
Jaikumar Ganesh8bc8ce42009-06-24 16:42:51 -0700499 return -1;
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700500 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
Jaikumar Ganesh8bc8ce42009-06-24 16:42:51 -0700501 return -1;
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700502 for (i = 0; i < max_num_properties; i++) {
Jaikumar Ganesh8bc8ce42009-06-24 16:42:51 -0700503 if (!strncmp(property, properties[i].name, strlen(property)))
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700504 break;
505 }
Jaikumar Ganesh8bc8ce42009-06-24 16:42:51 -0700506 *prop_index = i;
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700507 if (i == max_num_properties)
Jaikumar Ganesh8bc8ce42009-06-24 16:42:51 -0700508 return -1;
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700509
510 dbus_message_iter_recurse(&iter, &prop_val);
Jaikumar Ganesh8bc8ce42009-06-24 16:42:51 -0700511 type = properties[*prop_index].type;
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700512 if (dbus_message_iter_get_arg_type(&prop_val) != type) {
Jaikumar Ganesh8bc8ce42009-06-24 16:42:51 -0700513 LOGE("Property type mismatch in get_property: %d, expected:%d, index:%d",
514 dbus_message_iter_get_arg_type(&prop_val), type, *prop_index);
515 return -1;
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700516 }
517
518 switch(type) {
519 case DBUS_TYPE_STRING:
520 case DBUS_TYPE_OBJECT_PATH:
Jaikumar Ganesh8bc8ce42009-06-24 16:42:51 -0700521 dbus_message_iter_get_basic(&prop_val, &value->str_val);
522 *len = 1;
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700523 break;
524 case DBUS_TYPE_UINT32:
525 case DBUS_TYPE_INT16:
526 case DBUS_TYPE_BOOLEAN:
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700527 dbus_message_iter_get_basic(&prop_val, &int_val);
Jaikumar Ganesh8bc8ce42009-06-24 16:42:51 -0700528 value->int_val = int_val;
529 *len = 1;
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700530 break;
531 case DBUS_TYPE_ARRAY:
532 dbus_message_iter_recurse(&prop_val, &array_val_iter);
533 array_type = dbus_message_iter_get_arg_type(&array_val_iter);
Jaikumar Ganesh8bc8ce42009-06-24 16:42:51 -0700534 *len = 0;
535 value->array_val = NULL;
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700536 if (array_type == DBUS_TYPE_OBJECT_PATH ||
537 array_type == DBUS_TYPE_STRING){
Jaikumar Ganesh8bc8ce42009-06-24 16:42:51 -0700538 j = 0;
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700539 do {
Jaikumar Ganesh8bc8ce42009-06-24 16:42:51 -0700540 j ++;
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700541 } while(dbus_message_iter_next(&array_val_iter));
542 dbus_message_iter_recurse(&prop_val, &array_val_iter);
543 // Allocate an array of char *
Jaikumar Ganesh8bc8ce42009-06-24 16:42:51 -0700544 *len = j;
545 char **tmp = (char **)malloc(sizeof(char *) * *len);
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700546 if (!tmp)
Jaikumar Ganesh8bc8ce42009-06-24 16:42:51 -0700547 return -1;
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700548 j = 0;
549 do {
550 dbus_message_iter_get_basic(&array_val_iter, &tmp[j]);
551 j ++;
552 } while(dbus_message_iter_next(&array_val_iter));
Jaikumar Ganesh8bc8ce42009-06-24 16:42:51 -0700553 value->array_val = tmp;
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700554 }
555 break;
556 default:
Jaikumar Ganesh8bc8ce42009-06-24 16:42:51 -0700557 return -1;
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700558 }
Jaikumar Ganesh8bc8ce42009-06-24 16:42:51 -0700559 return 0;
560}
561
562void create_prop_array(JNIEnv *env, jobjectArray strArray, Properties *property,
563 property_value *value, int len, int *array_index ) {
564 char **prop_val = NULL;
565 char buf[32] = {'\0'}, buf1[32] = {'\0'};
566 int i;
567
568 char *name = property->name;
569 int prop_type = property->type;
570
571 set_object_array_element(env, strArray, name, *array_index);
572 *array_index += 1;
573
574 if (prop_type == DBUS_TYPE_UINT32 || prop_type == DBUS_TYPE_INT16) {
575 sprintf(buf, "%d", value->int_val);
576 set_object_array_element(env, strArray, buf, *array_index);
577 *array_index += 1;
578 } else if (prop_type == DBUS_TYPE_BOOLEAN) {
579 sprintf(buf, "%s", value->int_val ? "true" : "false");
580
581 set_object_array_element(env, strArray, buf, *array_index);
582 *array_index += 1;
583 } else if (prop_type == DBUS_TYPE_ARRAY) {
584 // Write the length first
585 sprintf(buf1, "%d", len);
586 set_object_array_element(env, strArray, buf1, *array_index);
587 *array_index += 1;
588
589 prop_val = value->array_val;
590 for (i = 0; i < len; i++) {
591 set_object_array_element(env, strArray, prop_val[i], *array_index);
592 *array_index += 1;
593 }
594 } else {
595 set_object_array_element(env, strArray, (const char *) value->str_val, *array_index);
596 *array_index += 1;
597 }
598}
599
600jobjectArray parse_properties(JNIEnv *env, DBusMessageIter *iter, Properties *properties,
601 const int max_num_properties) {
602 DBusMessageIter dict_entry, dict;
603 jobjectArray strArray = NULL;
604 property_value value;
605 int i, size = 0,array_index = 0;
606 int len = 0, prop_type = DBUS_TYPE_INVALID, prop_index = -1, type;
607 struct {
608 property_value value;
609 int len;
610 bool used;
611 } values[max_num_properties];
612 int t, j;
613
614 jclass stringClass = env->FindClass("java/lang/String");
615 DBusError err;
616 dbus_error_init(&err);
617
618 for (i = 0; i < max_num_properties; i++) {
619 values[i].used = false;
620 }
621
622 if(dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
623 goto failure;
624 dbus_message_iter_recurse(iter, &dict);
625 do {
626 len = 0;
627 if (dbus_message_iter_get_arg_type(&dict) != DBUS_TYPE_DICT_ENTRY)
628 goto failure;
629 dbus_message_iter_recurse(&dict, &dict_entry);
630
631 if (!get_property(dict_entry, properties, max_num_properties, &prop_index,
632 &value, &len)) {
633 size += 2;
634 if (properties[prop_index].type == DBUS_TYPE_ARRAY)
635 size += len;
636 values[prop_index].value = value;
637 values[prop_index].len = len;
638 values[prop_index].used = true;
639 } else {
640 goto failure;
641 }
642 } while(dbus_message_iter_next(&dict));
643
644 strArray = env->NewObjectArray(size, stringClass, NULL);
645
646 for (i = 0; i < max_num_properties; i++) {
647 if (values[i].used) {
648 create_prop_array(env, strArray, &properties[i], &values[i].value, values[i].len,
649 &array_index);
650
651 if (properties[i].type == DBUS_TYPE_ARRAY && values[i].used
652 && values[i].value.array_val != NULL)
653 free(values[i].value.array_val);
654 }
655
656 }
657 return strArray;
658
659failure:
660 if (dbus_error_is_set(&err))
661 LOG_AND_FREE_DBUS_ERROR(&err);
662 for (i = 0; i < max_num_properties; i++)
663 if (properties[i].type == DBUS_TYPE_ARRAY && values[i].used == true
664 && values[i].value.array_val != NULL)
665 free(values[i].value.array_val);
666 return NULL;
667}
668
669jobjectArray parse_property_change(JNIEnv *env, DBusMessage *msg,
670 Properties *properties, int max_num_properties) {
671 DBusMessageIter iter;
672 DBusError err;
673 jobjectArray strArray = NULL;
674 jclass stringClass= env->FindClass("java/lang/String");
675 int len = 0, prop_index = -1;
676 int array_index = 0, size = 0;
677 property_value value;
678
679 dbus_error_init(&err);
680 if (!dbus_message_iter_init(msg, &iter))
681 goto failure;
682
683 if (!get_property(iter, properties, max_num_properties,
684 &prop_index, &value, &len)) {
685 size += 2;
686 if (properties[prop_index].type == DBUS_TYPE_ARRAY)
687 size += len;
688 strArray = env->NewObjectArray(size, stringClass, NULL);
689
690 create_prop_array(env, strArray, &properties[prop_index],
691 &value, len, &array_index);
692
693 if (properties[prop_index].type == DBUS_TYPE_ARRAY && value.array_val != NULL)
694 free(value.array_val);
695
696 return strArray;
697 }
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700698failure:
699 LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
700 return NULL;
701}
702
703jobjectArray parse_adapter_property_change(JNIEnv *env, DBusMessage *msg) {
704 return parse_property_change(env, msg, (Properties *) &adapter_properties,
705 sizeof(adapter_properties) / sizeof(Properties));
706}
707
708jobjectArray parse_remote_device_property_change(JNIEnv *env, DBusMessage *msg) {
709 return parse_property_change(env, msg, (Properties *) &remote_device_properties,
710 sizeof(remote_device_properties) / sizeof(Properties));
711}
712
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700713jobjectArray parse_input_property_change(JNIEnv *env, DBusMessage *msg) {
714 return parse_property_change(env, msg, (Properties *) &input_properties,
715 sizeof(input_properties) / sizeof(Properties));
716}
717
Danica Chang6fdd0c62010-08-11 14:54:43 -0700718jobjectArray parse_pan_property_change(JNIEnv *env, DBusMessage *msg) {
719 return parse_property_change(env, msg, (Properties *) &pan_properties,
720 sizeof(pan_properties) / sizeof(Properties));
721}
722
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700723jobjectArray parse_adapter_properties(JNIEnv *env, DBusMessageIter *iter) {
724 return parse_properties(env, iter, (Properties *) &adapter_properties,
725 sizeof(adapter_properties) / sizeof(Properties));
726}
727
728jobjectArray parse_remote_device_properties(JNIEnv *env, DBusMessageIter *iter) {
729 return parse_properties(env, iter, (Properties *) &remote_device_properties,
730 sizeof(remote_device_properties) / sizeof(Properties));
731}
732
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700733jobjectArray parse_input_properties(JNIEnv *env, DBusMessageIter *iter) {
734 return parse_properties(env, iter, (Properties *) &input_properties,
735 sizeof(input_properties) / sizeof(Properties));
736}
737
Nick Pelly0b6955a2009-05-26 19:13:43 -0700738int get_bdaddr(const char *str, bdaddr_t *ba) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800739 char *d = ((char *)ba) + 5, *endp;
740 int i;
741 for(i = 0; i < 6; i++) {
742 *d-- = strtol(str, &endp, 16);
743 if (*endp != ':' && i != 5) {
744 memset(ba, 0, sizeof(bdaddr_t));
Nick Pelly0b6955a2009-05-26 19:13:43 -0700745 return -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800746 }
747 str = endp + 1;
748 }
Nick Pelly0b6955a2009-05-26 19:13:43 -0700749 return 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800750}
751
752void get_bdaddr_as_string(const bdaddr_t *ba, char *str) {
753 const uint8_t *b = (const uint8_t *)ba;
754 sprintf(str, "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X",
755 b[5], b[4], b[3], b[2], b[1], b[0]);
756}
757
758bool debug_no_encrypt() {
759 return false;
760#if 0
761 char value[PROPERTY_VALUE_MAX] = "";
762
763 property_get("debug.bt.no_encrypt", value, "");
764 if (!strncmp("true", value, PROPERTY_VALUE_MAX) ||
765 !strncmp("1", value, PROPERTY_VALUE_MAX)) {
766 LOGD("mandatory bluetooth encryption disabled");
767 return true;
768 } else {
769 return false;
770 }
771#endif
772}
773#endif
774
775} /* namespace android */