blob: c8dc9c275c8cbf2f7de97677f1eb82b34dc8d112 [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},
Jaikumar Ganesh14faa3b2011-03-30 14:04:42 -070046 {"Services", DBUS_TYPE_ARRAY},
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -070047 {"Paired", DBUS_TYPE_BOOLEAN},
48 {"Connected", DBUS_TYPE_BOOLEAN},
49 {"Trusted", DBUS_TYPE_BOOLEAN},
Jaikumar Ganesh6eb300e2010-08-04 11:26:38 -070050 {"Blocked", DBUS_TYPE_BOOLEAN},
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -070051 {"Alias", DBUS_TYPE_STRING},
52 {"Nodes", DBUS_TYPE_ARRAY},
53 {"Adapter", DBUS_TYPE_OBJECT_PATH},
54 {"LegacyPairing", DBUS_TYPE_BOOLEAN},
55 {"RSSI", DBUS_TYPE_INT16},
Jaikumar Ganesh14faa3b2011-03-30 14:04:42 -070056 {"TX", DBUS_TYPE_UINT32},
57 {"Broadcaster", DBUS_TYPE_BOOLEAN}
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -070058};
59
60static Properties adapter_properties[] = {
61 {"Address", DBUS_TYPE_STRING},
62 {"Name", DBUS_TYPE_STRING},
63 {"Class", DBUS_TYPE_UINT32},
64 {"Powered", DBUS_TYPE_BOOLEAN},
65 {"Discoverable", DBUS_TYPE_BOOLEAN},
66 {"DiscoverableTimeout", DBUS_TYPE_UINT32},
67 {"Pairable", DBUS_TYPE_BOOLEAN},
68 {"PairableTimeout", DBUS_TYPE_UINT32},
69 {"Discovering", DBUS_TYPE_BOOLEAN},
70 {"Devices", DBUS_TYPE_ARRAY},
Jaikumar Ganesh94278c92010-05-03 15:45:58 -070071 {"UUIDs", DBUS_TYPE_ARRAY},
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -070072};
73
Jaikumar Ganesh545e6702010-06-04 10:23:03 -070074static Properties input_properties[] = {
75 {"Connected", DBUS_TYPE_BOOLEAN},
76};
77
Danica Chang6fdd0c62010-08-11 14:54:43 -070078static Properties pan_properties[] = {
79 {"Connected", DBUS_TYPE_BOOLEAN},
80 {"Interface", DBUS_TYPE_STRING},
81 {"UUID", DBUS_TYPE_STRING},
82};
83
Jaikumar Ganesh2ea1e852011-04-01 16:33:09 -070084static Properties health_device_properties[] = {
85 {"MainChannel", DBUS_TYPE_OBJECT_PATH},
86};
87
88static Properties health_channel_properties[] = {
89 {"Type", DBUS_TYPE_STRING},
90 {"Device", DBUS_TYPE_OBJECT_PATH},
91 {"Application", DBUS_TYPE_OBJECT_PATH},
92};
93
Jaikumar Ganesh8bc8ce42009-06-24 16:42:51 -070094typedef union {
95 char *str_val;
96 int int_val;
97 char **array_val;
98} property_value;
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -070099
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800100jfieldID get_field(JNIEnv *env, jclass clazz, const char *member,
101 const char *mtype) {
102 jfieldID field = env->GetFieldID(clazz, member, mtype);
103 if (field == NULL) {
104 LOGE("Can't find member %s", member);
105 }
106 return field;
107}
108
109typedef struct {
Robert Greenwalt28d139f2009-04-02 22:41:08 -0700110 void (*user_cb)(DBusMessage *, void *, void *);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800111 void *user;
Robert Greenwalt28d139f2009-04-02 22:41:08 -0700112 void *nat;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800113 JNIEnv *env;
114} dbus_async_call_t;
115
116void dbus_func_args_async_callback(DBusPendingCall *call, void *data) {
117
118 dbus_async_call_t *req = (dbus_async_call_t *)data;
119 DBusMessage *msg;
120
121 /* This is guaranteed to be non-NULL, because this function is called only
122 when once the remote method invokation returns. */
123 msg = dbus_pending_call_steal_reply(call);
124
125 if (msg) {
126 if (req->user_cb) {
127 // The user may not deref the message object.
Robert Greenwalt28d139f2009-04-02 22:41:08 -0700128 req->user_cb(msg, req->user, req->nat);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800129 }
130 dbus_message_unref(msg);
131 }
132
133 //dbus_message_unref(req->method);
134 dbus_pending_call_cancel(call);
135 dbus_pending_call_unref(call);
136 free(req);
137}
138
Robert Greenwalt28d139f2009-04-02 22:41:08 -0700139static dbus_bool_t dbus_func_args_async_valist(JNIEnv *env,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800140 DBusConnection *conn,
141 int timeout_ms,
Robert Greenwalt28d139f2009-04-02 22:41:08 -0700142 void (*user_cb)(DBusMessage *,
143 void *,
144 void*),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800145 void *user,
Robert Greenwalt28d139f2009-04-02 22:41:08 -0700146 void *nat,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800147 const char *path,
148 const char *ifc,
149 const char *func,
150 int first_arg_type,
151 va_list args) {
152 DBusMessage *msg = NULL;
153 const char *name;
154 dbus_async_call_t *pending;
155 dbus_bool_t reply = FALSE;
156
157 /* Compose the command */
158 msg = dbus_message_new_method_call(BLUEZ_DBUS_BASE_IFC, path, ifc, func);
159
160 if (msg == NULL) {
161 LOGE("Could not allocate D-Bus message object!");
162 goto done;
163 }
164
165 /* append arguments */
166 if (!dbus_message_append_args_valist(msg, first_arg_type, args)) {
167 LOGE("Could not append argument to method call!");
168 goto done;
169 }
170
171 /* Make the call. */
172 pending = (dbus_async_call_t *)malloc(sizeof(dbus_async_call_t));
173 if (pending) {
174 DBusPendingCall *call;
175
176 pending->env = env;
177 pending->user_cb = user_cb;
178 pending->user = user;
Robert Greenwalt28d139f2009-04-02 22:41:08 -0700179 pending->nat = nat;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800180 //pending->method = msg;
181
182 reply = dbus_connection_send_with_reply(conn, msg,
183 &call,
184 timeout_ms);
185 if (reply == TRUE) {
186 dbus_pending_call_set_notify(call,
187 dbus_func_args_async_callback,
188 pending,
189 NULL);
190 }
191 }
192
193done:
194 if (msg) dbus_message_unref(msg);
195 return reply;
196}
197
198dbus_bool_t dbus_func_args_async(JNIEnv *env,
199 DBusConnection *conn,
200 int timeout_ms,
Robert Greenwalt28d139f2009-04-02 22:41:08 -0700201 void (*reply)(DBusMessage *, void *, void*),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800202 void *user,
Robert Greenwalt28d139f2009-04-02 22:41:08 -0700203 void *nat,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800204 const char *path,
205 const char *ifc,
206 const char *func,
207 int first_arg_type,
208 ...) {
209 dbus_bool_t ret;
210 va_list lst;
211 va_start(lst, first_arg_type);
Danica Chang6fdd0c62010-08-11 14:54:43 -0700212
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800213 ret = dbus_func_args_async_valist(env, conn,
214 timeout_ms,
Robert Greenwalt28d139f2009-04-02 22:41:08 -0700215 reply, user, nat,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800216 path, ifc, func,
217 first_arg_type, lst);
218 va_end(lst);
219 return ret;
220}
221
222// If err is NULL, then any errors will be LOGE'd, and free'd and the reply
223// will be NULL.
224// If err is not NULL, then it is assumed that dbus_error_init was already
225// called, and error's will be returned to the caller without logging. The
226// return value is NULL iff an error was set. The client must free the error if
227// set.
228DBusMessage * dbus_func_args_timeout_valist(JNIEnv *env,
229 DBusConnection *conn,
230 int timeout_ms,
231 DBusError *err,
232 const char *path,
233 const char *ifc,
234 const char *func,
235 int first_arg_type,
236 va_list args) {
237
238 DBusMessage *msg = NULL, *reply = NULL;
239 const char *name;
240 bool return_error = (err != NULL);
241
242 if (!return_error) {
243 err = (DBusError*)malloc(sizeof(DBusError));
244 dbus_error_init(err);
245 }
246
247 /* Compose the command */
248 msg = dbus_message_new_method_call(BLUEZ_DBUS_BASE_IFC, path, ifc, func);
249
250 if (msg == NULL) {
251 LOGE("Could not allocate D-Bus message object!");
252 goto done;
253 }
254
255 /* append arguments */
256 if (!dbus_message_append_args_valist(msg, first_arg_type, args)) {
257 LOGE("Could not append argument to method call!");
258 goto done;
259 }
260
261 /* Make the call. */
262 reply = dbus_connection_send_with_reply_and_block(conn, msg, timeout_ms, err);
263 if (!return_error && dbus_error_is_set(err)) {
264 LOG_AND_FREE_DBUS_ERROR_WITH_MSG(err, msg);
265 }
266
267done:
268 if (!return_error) {
269 free(err);
270 }
271 if (msg) dbus_message_unref(msg);
272 return reply;
273}
274
275DBusMessage * dbus_func_args_timeout(JNIEnv *env,
276 DBusConnection *conn,
277 int timeout_ms,
278 const char *path,
279 const char *ifc,
280 const char *func,
281 int first_arg_type,
282 ...) {
283 DBusMessage *ret;
284 va_list lst;
285 va_start(lst, first_arg_type);
286 ret = dbus_func_args_timeout_valist(env, conn, timeout_ms, NULL,
287 path, ifc, func,
288 first_arg_type, lst);
289 va_end(lst);
290 return ret;
291}
292
293DBusMessage * dbus_func_args(JNIEnv *env,
294 DBusConnection *conn,
295 const char *path,
296 const char *ifc,
297 const char *func,
298 int first_arg_type,
299 ...) {
300 DBusMessage *ret;
301 va_list lst;
302 va_start(lst, first_arg_type);
303 ret = dbus_func_args_timeout_valist(env, conn, -1, NULL,
304 path, ifc, func,
305 first_arg_type, lst);
306 va_end(lst);
307 return ret;
308}
309
310DBusMessage * dbus_func_args_error(JNIEnv *env,
311 DBusConnection *conn,
312 DBusError *err,
313 const char *path,
314 const char *ifc,
315 const char *func,
316 int first_arg_type,
317 ...) {
318 DBusMessage *ret;
319 va_list lst;
320 va_start(lst, first_arg_type);
321 ret = dbus_func_args_timeout_valist(env, conn, -1, err,
322 path, ifc, func,
323 first_arg_type, lst);
324 va_end(lst);
325 return ret;
326}
327
Jaikumar Ganesh2ea1e852011-04-01 16:33:09 -0700328jint dbus_returns_unixfd(JNIEnv *env, DBusMessage *reply) {
329
330 DBusError err;
331 jint ret = -1;
332
333 dbus_error_init(&err);
334 if (!dbus_message_get_args(reply, &err,
335 DBUS_TYPE_UNIX_FD, &ret,
336 DBUS_TYPE_INVALID)) {
337 LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, reply);
338 }
339 dbus_message_unref(reply);
340 return ret;
341}
342
343
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800344jint dbus_returns_int32(JNIEnv *env, DBusMessage *reply) {
345
346 DBusError err;
347 jint ret = -1;
348
349 dbus_error_init(&err);
350 if (!dbus_message_get_args(reply, &err,
351 DBUS_TYPE_INT32, &ret,
352 DBUS_TYPE_INVALID)) {
353 LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, reply);
354 }
355 dbus_message_unref(reply);
356 return ret;
357}
358
359jint dbus_returns_uint32(JNIEnv *env, DBusMessage *reply) {
360
361 DBusError err;
362 jint ret = -1;
363
364 dbus_error_init(&err);
365 if (!dbus_message_get_args(reply, &err,
366 DBUS_TYPE_UINT32, &ret,
367 DBUS_TYPE_INVALID)) {
368 LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, reply);
369 }
370 dbus_message_unref(reply);
371 return ret;
372}
373
374jstring dbus_returns_string(JNIEnv *env, DBusMessage *reply) {
375
376 DBusError err;
377 jstring ret = NULL;
378 const char *name;
379
380 dbus_error_init(&err);
381 if (dbus_message_get_args(reply, &err,
382 DBUS_TYPE_STRING, &name,
383 DBUS_TYPE_INVALID)) {
384 ret = env->NewStringUTF(name);
385 } else {
386 LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, reply);
387 }
388 dbus_message_unref(reply);
389
390 return ret;
391}
392
393jboolean dbus_returns_boolean(JNIEnv *env, DBusMessage *reply) {
394 DBusError err;
395 jboolean ret = JNI_FALSE;
396 dbus_bool_t val = FALSE;
397
398 dbus_error_init(&err);
399
400 /* Check the return value. */
401 if (dbus_message_get_args(reply, &err,
402 DBUS_TYPE_BOOLEAN, &val,
403 DBUS_TYPE_INVALID)) {
404 ret = val == TRUE ? JNI_TRUE : JNI_FALSE;
405 } else {
406 LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, reply);
407 }
408
409 dbus_message_unref(reply);
410 return ret;
411}
412
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700413static void set_object_array_element(JNIEnv *env, jobjectArray strArray,
414 const char *value, int index) {
415 jstring obj;
416 obj = env->NewStringUTF(value);
417 env->SetObjectArrayElement(strArray, index, obj);
418 env->DeleteLocalRef(obj);
419}
420
421jobjectArray dbus_returns_array_of_object_path(JNIEnv *env,
422 DBusMessage *reply) {
423
424 DBusError err;
425 char **list;
426 int i, len;
427 jobjectArray strArray = NULL;
428
429 dbus_error_init(&err);
430 if (dbus_message_get_args (reply,
431 &err,
432 DBUS_TYPE_ARRAY, DBUS_TYPE_OBJECT_PATH,
433 &list, &len,
434 DBUS_TYPE_INVALID)) {
435 jclass stringClass;
436 jstring classNameStr;
437
438 stringClass = env->FindClass("java/lang/String");
439 strArray = env->NewObjectArray(len, stringClass, NULL);
440
441 for (i = 0; i < len; i++)
442 set_object_array_element(env, strArray, list[i], i);
443 } else {
444 LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, reply);
445 }
446
447 dbus_message_unref(reply);
448 return strArray;
449}
450
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800451jobjectArray dbus_returns_array_of_strings(JNIEnv *env, DBusMessage *reply) {
452
453 DBusError err;
454 char **list;
455 int i, len;
456 jobjectArray strArray = NULL;
457
458 dbus_error_init(&err);
459 if (dbus_message_get_args (reply,
460 &err,
461 DBUS_TYPE_ARRAY, DBUS_TYPE_STRING,
462 &list, &len,
463 DBUS_TYPE_INVALID)) {
464 jclass stringClass;
465 jstring classNameStr;
466
Steve Block71f2cf12011-10-20 11:56:00 +0100467 //ALOGV("%s: there are %d elements in string array!", __FUNCTION__, len);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800468
469 stringClass = env->FindClass("java/lang/String");
470 strArray = env->NewObjectArray(len, stringClass, NULL);
471
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700472 for (i = 0; i < len; i++)
473 set_object_array_element(env, strArray, list[i], i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800474 } else {
475 LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, reply);
476 }
477
478 dbus_message_unref(reply);
479 return strArray;
480}
481
482jbyteArray dbus_returns_array_of_bytes(JNIEnv *env, DBusMessage *reply) {
483
484 DBusError err;
485 int i, len;
486 jbyte *list;
487 jbyteArray byteArray = NULL;
488
489 dbus_error_init(&err);
490 if (dbus_message_get_args(reply, &err,
491 DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &list, &len,
492 DBUS_TYPE_INVALID)) {
Steve Block71f2cf12011-10-20 11:56:00 +0100493 //ALOGV("%s: there are %d elements in byte array!", __FUNCTION__, len);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800494 byteArray = env->NewByteArray(len);
495 if (byteArray)
496 env->SetByteArrayRegion(byteArray, 0, len, list);
497
498 } else {
499 LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, reply);
500 }
501
502 dbus_message_unref(reply);
503 return byteArray;
504}
505
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700506void append_variant(DBusMessageIter *iter, int type, void *val)
507{
508 DBusMessageIter value_iter;
509 char var_type[2] = { type, '\0'};
510 dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, var_type, &value_iter);
511 dbus_message_iter_append_basic(&value_iter, type, val);
512 dbus_message_iter_close_container(iter, &value_iter);
513}
514
Jaikumar Ganesh2ea1e852011-04-01 16:33:09 -0700515static void dict_append_entry(DBusMessageIter *dict,
516 const char *key, int type, void *val)
517{
518 DBusMessageIter dict_entry;
519 dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
520 NULL, &dict_entry);
521
522 dbus_message_iter_append_basic(&dict_entry, DBUS_TYPE_STRING, &key);
523 append_variant(&dict_entry, type, val);
524 dbus_message_iter_close_container(dict, &dict_entry);
525}
526
527static void append_dict_valist(DBusMessageIter *iterator, const char *first_key,
528 va_list var_args)
529{
530 DBusMessageIter dict;
531 int val_type;
532 const char *val_key;
533 void *val;
534
535 dbus_message_iter_open_container(iterator, DBUS_TYPE_ARRAY,
536 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
537 DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
538 DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
539
540 val_key = first_key;
541 while (val_key) {
542 val_type = va_arg(var_args, int);
543 val = va_arg(var_args, void *);
544 dict_append_entry(&dict, val_key, val_type, val);
545 val_key = va_arg(var_args, char *);
546 }
547
548 dbus_message_iter_close_container(iterator, &dict);
549}
550
551void append_dict_args(DBusMessage *reply, const char *first_key, ...)
552{
553 DBusMessageIter iter;
554 va_list var_args;
555
556 dbus_message_iter_init_append(reply, &iter);
557
558 va_start(var_args, first_key);
559 append_dict_valist(&iter, first_key, var_args);
560 va_end(var_args);
561}
562
563
Jaikumar Ganesh8bc8ce42009-06-24 16:42:51 -0700564int get_property(DBusMessageIter iter, Properties *properties,
565 int max_num_properties, int *prop_index, property_value *value, int *len) {
566 DBusMessageIter prop_val, array_val_iter;
567 char *property = NULL;
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700568 uint32_t array_type;
Jaikumar Ganesh8bc8ce42009-06-24 16:42:51 -0700569 char *str_val;
570 int i, j, type, int_val;
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700571
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700572 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
Jaikumar Ganesh8bc8ce42009-06-24 16:42:51 -0700573 return -1;
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700574 dbus_message_iter_get_basic(&iter, &property);
575 if (!dbus_message_iter_next(&iter))
Jaikumar Ganesh8bc8ce42009-06-24 16:42:51 -0700576 return -1;
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700577 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
Jaikumar Ganesh8bc8ce42009-06-24 16:42:51 -0700578 return -1;
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700579 for (i = 0; i < max_num_properties; i++) {
Jaikumar Ganesh8bc8ce42009-06-24 16:42:51 -0700580 if (!strncmp(property, properties[i].name, strlen(property)))
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700581 break;
582 }
Jaikumar Ganesh8bc8ce42009-06-24 16:42:51 -0700583 *prop_index = i;
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700584 if (i == max_num_properties)
Jaikumar Ganesh8bc8ce42009-06-24 16:42:51 -0700585 return -1;
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700586
587 dbus_message_iter_recurse(&iter, &prop_val);
Jaikumar Ganesh8bc8ce42009-06-24 16:42:51 -0700588 type = properties[*prop_index].type;
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700589 if (dbus_message_iter_get_arg_type(&prop_val) != type) {
Jaikumar Ganesh8bc8ce42009-06-24 16:42:51 -0700590 LOGE("Property type mismatch in get_property: %d, expected:%d, index:%d",
591 dbus_message_iter_get_arg_type(&prop_val), type, *prop_index);
592 return -1;
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700593 }
594
595 switch(type) {
596 case DBUS_TYPE_STRING:
597 case DBUS_TYPE_OBJECT_PATH:
Jaikumar Ganesh8bc8ce42009-06-24 16:42:51 -0700598 dbus_message_iter_get_basic(&prop_val, &value->str_val);
599 *len = 1;
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700600 break;
601 case DBUS_TYPE_UINT32:
602 case DBUS_TYPE_INT16:
603 case DBUS_TYPE_BOOLEAN:
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700604 dbus_message_iter_get_basic(&prop_val, &int_val);
Jaikumar Ganesh8bc8ce42009-06-24 16:42:51 -0700605 value->int_val = int_val;
606 *len = 1;
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700607 break;
608 case DBUS_TYPE_ARRAY:
609 dbus_message_iter_recurse(&prop_val, &array_val_iter);
610 array_type = dbus_message_iter_get_arg_type(&array_val_iter);
Jaikumar Ganesh8bc8ce42009-06-24 16:42:51 -0700611 *len = 0;
612 value->array_val = NULL;
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700613 if (array_type == DBUS_TYPE_OBJECT_PATH ||
614 array_type == DBUS_TYPE_STRING){
Jaikumar Ganesh8bc8ce42009-06-24 16:42:51 -0700615 j = 0;
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700616 do {
Jaikumar Ganesh8bc8ce42009-06-24 16:42:51 -0700617 j ++;
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700618 } while(dbus_message_iter_next(&array_val_iter));
619 dbus_message_iter_recurse(&prop_val, &array_val_iter);
620 // Allocate an array of char *
Jaikumar Ganesh8bc8ce42009-06-24 16:42:51 -0700621 *len = j;
622 char **tmp = (char **)malloc(sizeof(char *) * *len);
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700623 if (!tmp)
Jaikumar Ganesh8bc8ce42009-06-24 16:42:51 -0700624 return -1;
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700625 j = 0;
626 do {
627 dbus_message_iter_get_basic(&array_val_iter, &tmp[j]);
628 j ++;
629 } while(dbus_message_iter_next(&array_val_iter));
Jaikumar Ganesh8bc8ce42009-06-24 16:42:51 -0700630 value->array_val = tmp;
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700631 }
632 break;
633 default:
Jaikumar Ganesh8bc8ce42009-06-24 16:42:51 -0700634 return -1;
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700635 }
Jaikumar Ganesh8bc8ce42009-06-24 16:42:51 -0700636 return 0;
637}
638
639void create_prop_array(JNIEnv *env, jobjectArray strArray, Properties *property,
640 property_value *value, int len, int *array_index ) {
641 char **prop_val = NULL;
642 char buf[32] = {'\0'}, buf1[32] = {'\0'};
643 int i;
644
645 char *name = property->name;
646 int prop_type = property->type;
647
648 set_object_array_element(env, strArray, name, *array_index);
649 *array_index += 1;
650
651 if (prop_type == DBUS_TYPE_UINT32 || prop_type == DBUS_TYPE_INT16) {
652 sprintf(buf, "%d", value->int_val);
653 set_object_array_element(env, strArray, buf, *array_index);
654 *array_index += 1;
655 } else if (prop_type == DBUS_TYPE_BOOLEAN) {
656 sprintf(buf, "%s", value->int_val ? "true" : "false");
657
658 set_object_array_element(env, strArray, buf, *array_index);
659 *array_index += 1;
660 } else if (prop_type == DBUS_TYPE_ARRAY) {
661 // Write the length first
662 sprintf(buf1, "%d", len);
663 set_object_array_element(env, strArray, buf1, *array_index);
664 *array_index += 1;
665
666 prop_val = value->array_val;
667 for (i = 0; i < len; i++) {
668 set_object_array_element(env, strArray, prop_val[i], *array_index);
669 *array_index += 1;
670 }
671 } else {
672 set_object_array_element(env, strArray, (const char *) value->str_val, *array_index);
673 *array_index += 1;
674 }
675}
676
677jobjectArray parse_properties(JNIEnv *env, DBusMessageIter *iter, Properties *properties,
678 const int max_num_properties) {
679 DBusMessageIter dict_entry, dict;
680 jobjectArray strArray = NULL;
681 property_value value;
682 int i, size = 0,array_index = 0;
683 int len = 0, prop_type = DBUS_TYPE_INVALID, prop_index = -1, type;
684 struct {
685 property_value value;
686 int len;
687 bool used;
688 } values[max_num_properties];
689 int t, j;
690
691 jclass stringClass = env->FindClass("java/lang/String");
692 DBusError err;
693 dbus_error_init(&err);
694
695 for (i = 0; i < max_num_properties; i++) {
696 values[i].used = false;
697 }
698
699 if(dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
700 goto failure;
701 dbus_message_iter_recurse(iter, &dict);
702 do {
703 len = 0;
704 if (dbus_message_iter_get_arg_type(&dict) != DBUS_TYPE_DICT_ENTRY)
705 goto failure;
706 dbus_message_iter_recurse(&dict, &dict_entry);
707
708 if (!get_property(dict_entry, properties, max_num_properties, &prop_index,
709 &value, &len)) {
710 size += 2;
711 if (properties[prop_index].type == DBUS_TYPE_ARRAY)
712 size += len;
713 values[prop_index].value = value;
714 values[prop_index].len = len;
715 values[prop_index].used = true;
716 } else {
717 goto failure;
718 }
719 } while(dbus_message_iter_next(&dict));
720
721 strArray = env->NewObjectArray(size, stringClass, NULL);
722
723 for (i = 0; i < max_num_properties; i++) {
724 if (values[i].used) {
725 create_prop_array(env, strArray, &properties[i], &values[i].value, values[i].len,
726 &array_index);
727
728 if (properties[i].type == DBUS_TYPE_ARRAY && values[i].used
729 && values[i].value.array_val != NULL)
730 free(values[i].value.array_val);
731 }
732
733 }
734 return strArray;
735
736failure:
737 if (dbus_error_is_set(&err))
738 LOG_AND_FREE_DBUS_ERROR(&err);
739 for (i = 0; i < max_num_properties; i++)
740 if (properties[i].type == DBUS_TYPE_ARRAY && values[i].used == true
741 && values[i].value.array_val != NULL)
742 free(values[i].value.array_val);
743 return NULL;
744}
745
746jobjectArray parse_property_change(JNIEnv *env, DBusMessage *msg,
747 Properties *properties, int max_num_properties) {
748 DBusMessageIter iter;
749 DBusError err;
750 jobjectArray strArray = NULL;
751 jclass stringClass= env->FindClass("java/lang/String");
752 int len = 0, prop_index = -1;
753 int array_index = 0, size = 0;
754 property_value value;
755
756 dbus_error_init(&err);
757 if (!dbus_message_iter_init(msg, &iter))
758 goto failure;
759
760 if (!get_property(iter, properties, max_num_properties,
761 &prop_index, &value, &len)) {
762 size += 2;
763 if (properties[prop_index].type == DBUS_TYPE_ARRAY)
764 size += len;
765 strArray = env->NewObjectArray(size, stringClass, NULL);
766
767 create_prop_array(env, strArray, &properties[prop_index],
768 &value, len, &array_index);
769
770 if (properties[prop_index].type == DBUS_TYPE_ARRAY && value.array_val != NULL)
771 free(value.array_val);
772
773 return strArray;
774 }
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700775failure:
776 LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, msg);
777 return NULL;
778}
779
780jobjectArray parse_adapter_property_change(JNIEnv *env, DBusMessage *msg) {
781 return parse_property_change(env, msg, (Properties *) &adapter_properties,
782 sizeof(adapter_properties) / sizeof(Properties));
783}
784
785jobjectArray parse_remote_device_property_change(JNIEnv *env, DBusMessage *msg) {
786 return parse_property_change(env, msg, (Properties *) &remote_device_properties,
787 sizeof(remote_device_properties) / sizeof(Properties));
788}
789
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700790jobjectArray parse_input_property_change(JNIEnv *env, DBusMessage *msg) {
791 return parse_property_change(env, msg, (Properties *) &input_properties,
792 sizeof(input_properties) / sizeof(Properties));
793}
794
Danica Chang6fdd0c62010-08-11 14:54:43 -0700795jobjectArray parse_pan_property_change(JNIEnv *env, DBusMessage *msg) {
796 return parse_property_change(env, msg, (Properties *) &pan_properties,
797 sizeof(pan_properties) / sizeof(Properties));
798}
799
Jaikumar Ganeshd5ac1ae2009-05-05 22:26:12 -0700800jobjectArray parse_adapter_properties(JNIEnv *env, DBusMessageIter *iter) {
801 return parse_properties(env, iter, (Properties *) &adapter_properties,
802 sizeof(adapter_properties) / sizeof(Properties));
803}
804
805jobjectArray parse_remote_device_properties(JNIEnv *env, DBusMessageIter *iter) {
806 return parse_properties(env, iter, (Properties *) &remote_device_properties,
807 sizeof(remote_device_properties) / sizeof(Properties));
808}
809
Jaikumar Ganesh545e6702010-06-04 10:23:03 -0700810jobjectArray parse_input_properties(JNIEnv *env, DBusMessageIter *iter) {
811 return parse_properties(env, iter, (Properties *) &input_properties,
812 sizeof(input_properties) / sizeof(Properties));
813}
814
Jaikumar Ganesh2ea1e852011-04-01 16:33:09 -0700815jobjectArray parse_health_device_properties(JNIEnv *env, DBusMessageIter *iter) {
816 return parse_properties(env, iter, (Properties *) &health_device_properties,
817 sizeof(health_device_properties) / sizeof(Properties));
818}
819
820jobjectArray parse_health_device_property_change(JNIEnv *env, DBusMessage *msg) {
821 return parse_property_change(env, msg, (Properties *) &health_device_properties,
822 sizeof(health_device_properties) / sizeof(Properties));
823}
824
825jobjectArray parse_health_channel_properties(JNIEnv *env, DBusMessageIter *iter) {
826 return parse_properties(env, iter, (Properties *) &health_channel_properties,
827 sizeof(health_channel_properties) / sizeof(Properties));
828}
829
Nick Pelly0b6955a2009-05-26 19:13:43 -0700830int get_bdaddr(const char *str, bdaddr_t *ba) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800831 char *d = ((char *)ba) + 5, *endp;
832 int i;
833 for(i = 0; i < 6; i++) {
834 *d-- = strtol(str, &endp, 16);
835 if (*endp != ':' && i != 5) {
836 memset(ba, 0, sizeof(bdaddr_t));
Nick Pelly0b6955a2009-05-26 19:13:43 -0700837 return -1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800838 }
839 str = endp + 1;
840 }
Nick Pelly0b6955a2009-05-26 19:13:43 -0700841 return 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800842}
843
844void get_bdaddr_as_string(const bdaddr_t *ba, char *str) {
845 const uint8_t *b = (const uint8_t *)ba;
846 sprintf(str, "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X",
847 b[5], b[4], b[3], b[2], b[1], b[0]);
848}
849
850bool debug_no_encrypt() {
851 return false;
852#if 0
853 char value[PROPERTY_VALUE_MAX] = "";
854
855 property_get("debug.bt.no_encrypt", value, "");
856 if (!strncmp("true", value, PROPERTY_VALUE_MAX) ||
857 !strncmp("1", value, PROPERTY_VALUE_MAX)) {
Steve Block5baa3a62011-12-20 16:23:08 +0000858 ALOGD("mandatory bluetooth encryption disabled");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800859 return true;
860 } else {
861 return false;
862 }
863#endif
864}
865#endif
866
867} /* namespace android */