1/*
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
39
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    {"Services", DBUS_TYPE_ARRAY},
47    {"Paired", DBUS_TYPE_BOOLEAN},
48    {"Connected", DBUS_TYPE_BOOLEAN},
49    {"Trusted", DBUS_TYPE_BOOLEAN},
50    {"Blocked", DBUS_TYPE_BOOLEAN},
51    {"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},
56    {"TX", DBUS_TYPE_UINT32},
57    {"Broadcaster", DBUS_TYPE_BOOLEAN}
58};
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},
71    {"UUIDs", DBUS_TYPE_ARRAY},
72};
73
74static Properties input_properties[] = {
75    {"Connected", DBUS_TYPE_BOOLEAN},
76};
77
78static Properties pan_properties[] = {
79    {"Connected", DBUS_TYPE_BOOLEAN},
80    {"Interface", DBUS_TYPE_STRING},
81    {"UUID", DBUS_TYPE_STRING},
82};
83
84static 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
94typedef union {
95    char *str_val;
96    int int_val;
97    char **array_val;
98} property_value;
99
100jfieldID 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        ALOGE("Can't find member %s", member);
105    }
106    return field;
107}
108
109typedef struct {
110    void (*user_cb)(DBusMessage *, void *, void *);
111    void *user;
112    void *nat;
113    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.
128            req->user_cb(msg, req->user, req->nat);
129        }
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
139static dbus_bool_t dbus_func_args_async_valist(JNIEnv *env,
140                                        DBusConnection *conn,
141                                        int timeout_ms,
142                                        void (*user_cb)(DBusMessage *,
143                                                        void *,
144                                                        void*),
145                                        void *user,
146                                        void *nat,
147                                        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        ALOGE("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        ALOGE("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;
179        pending->nat = nat;
180        //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,
201                                 void (*reply)(DBusMessage *, void *, void*),
202                                 void *user,
203                                 void *nat,
204                                 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);
212
213    ret = dbus_func_args_async_valist(env, conn,
214                                      timeout_ms,
215                                      reply, user, nat,
216                                      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 ALOGE'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        ALOGE("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        ALOGE("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
328jint 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
344jint 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
413static 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
451jobjectArray 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
467        //ALOGV("%s: there are %d elements in string array!", __FUNCTION__, len);
468
469        stringClass = env->FindClass("java/lang/String");
470        strArray = env->NewObjectArray(len, stringClass, NULL);
471
472        for (i = 0; i < len; i++)
473            set_object_array_element(env, strArray, list[i], i);
474    } 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)) {
493        //ALOGV("%s: there are %d elements in byte array!", __FUNCTION__, len);
494        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
506void 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
515static 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
564int 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;
568    uint32_t array_type;
569    char *str_val;
570    int i, j, type, int_val;
571
572    if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
573        return -1;
574    dbus_message_iter_get_basic(&iter, &property);
575    if (!dbus_message_iter_next(&iter))
576        return -1;
577    if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
578        return -1;
579    for (i = 0; i <  max_num_properties; i++) {
580        if (!strncmp(property, properties[i].name, strlen(property)))
581            break;
582    }
583    *prop_index = i;
584    if (i == max_num_properties)
585        return -1;
586
587    dbus_message_iter_recurse(&iter, &prop_val);
588    type = properties[*prop_index].type;
589    if (dbus_message_iter_get_arg_type(&prop_val) != type) {
590        ALOGE("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;
593    }
594
595    switch(type) {
596    case DBUS_TYPE_STRING:
597    case DBUS_TYPE_OBJECT_PATH:
598        dbus_message_iter_get_basic(&prop_val, &value->str_val);
599        *len = 1;
600        break;
601    case DBUS_TYPE_UINT32:
602    case DBUS_TYPE_INT16:
603    case DBUS_TYPE_BOOLEAN:
604        dbus_message_iter_get_basic(&prop_val, &int_val);
605        value->int_val = int_val;
606        *len = 1;
607        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);
611        *len = 0;
612        value->array_val = NULL;
613        if (array_type == DBUS_TYPE_OBJECT_PATH ||
614            array_type == DBUS_TYPE_STRING){
615            j = 0;
616            do {
617               j ++;
618            } while(dbus_message_iter_next(&array_val_iter));
619            dbus_message_iter_recurse(&prop_val, &array_val_iter);
620            // Allocate  an array of char *
621            *len = j;
622            char **tmp = (char **)malloc(sizeof(char *) * *len);
623            if (!tmp)
624                return -1;
625            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));
630            value->array_val = tmp;
631        }
632        break;
633    default:
634        return -1;
635    }
636    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    }
775failure:
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
790jobjectArray 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
795jobjectArray 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
800jobjectArray 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
810jobjectArray parse_input_properties(JNIEnv *env, DBusMessageIter *iter) {
811    return parse_properties(env, iter, (Properties *) &input_properties,
812                          sizeof(input_properties) / sizeof(Properties));
813}
814
815jobjectArray 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
830int get_bdaddr(const char *str, bdaddr_t *ba) {
831    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));
837            return -1;
838        }
839        str = endp + 1;
840    }
841    return 0;
842}
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)) {
858        ALOGD("mandatory bluetooth encryption disabled");
859        return true;
860    } else {
861        return false;
862    }
863#endif
864}
865#endif
866
867} /* namespace android */
868