1 /*
2  * Copyright (C) 2016 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 "BluetoothAvrcpServiceJni"
18 
19 #define LOG_NDEBUG 0
20 
21 #include "android_runtime/AndroidRuntime.h"
22 #include "com_android_bluetooth.h"
23 #include "hardware/bt_rc.h"
24 #include "utils/Log.h"
25 
26 #include <string.h>
27 
28 namespace android {
29 static jmethodID method_getRcFeatures;
30 static jmethodID method_getPlayStatus;
31 static jmethodID method_getElementAttr;
32 static jmethodID method_registerNotification;
33 static jmethodID method_volumeChangeCallback;
34 static jmethodID method_handlePassthroughCmd;
35 static jmethodID method_getFolderItemsCallback;
36 static jmethodID method_setAddressedPlayerCallback;
37 
38 static jmethodID method_setBrowsedPlayerCallback;
39 static jmethodID method_changePathCallback;
40 static jmethodID method_searchCallback;
41 static jmethodID method_playItemCallback;
42 static jmethodID method_getItemAttrCallback;
43 static jmethodID method_addToPlayListCallback;
44 static jmethodID method_getTotalNumOfItemsCallback;
45 
46 static const btrc_interface_t* sBluetoothAvrcpInterface = NULL;
47 static jobject mCallbacksObj = NULL;
48 
49 /* Function declarations */
50 static bool copy_item_attributes(JNIEnv* env, jobject object,
51                                  btrc_folder_items_t* pitem,
52                                  jint* p_attributesIds,
53                                  jobjectArray attributesArray, int item_idx,
54                                  int attribCopiedIndex);
55 
56 static bool copy_jstring(uint8_t* str, int maxBytes, jstring jstr, JNIEnv* env);
57 
58 static void cleanup_items(btrc_folder_items_t* p_items, int numItems);
59 
btavrcp_remote_features_callback(bt_bdaddr_t * bd_addr,btrc_remote_features_t features)60 static void btavrcp_remote_features_callback(bt_bdaddr_t* bd_addr,
61                                              btrc_remote_features_t features) {
62   CallbackEnv sCallbackEnv(__func__);
63   if (!sCallbackEnv.valid()) return;
64 
65   if (!mCallbacksObj) {
66     ALOGE("%s: mCallbacksObj is null", __func__);
67     return;
68   }
69 
70   ScopedLocalRef<jbyteArray> addr(
71       sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t)));
72   if (!addr.get()) {
73     ALOGE("Unable to allocate byte array for bd_addr");
74     return;
75   }
76 
77   sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(bt_bdaddr_t),
78                                    (jbyte*)bd_addr);
79   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_getRcFeatures, addr.get(),
80                                (jint)features);
81 }
82 
83 /** Callback for play status request */
btavrcp_get_play_status_callback(bt_bdaddr_t * bd_addr)84 static void btavrcp_get_play_status_callback(bt_bdaddr_t* bd_addr) {
85   CallbackEnv sCallbackEnv(__func__);
86   if (!sCallbackEnv.valid()) return;
87 
88   if (!mCallbacksObj) {
89     ALOGE("%s: mCallbacksObj is null", __func__);
90     return;
91   }
92 
93   ScopedLocalRef<jbyteArray> addr(
94       sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t)));
95   if (!addr.get()) {
96     ALOGE("Fail to new jbyteArray bd addr for get_play_status command");
97     return;
98   }
99 
100   sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(bt_bdaddr_t),
101                                    (jbyte*)bd_addr);
102   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_getPlayStatus, addr.get());
103 }
104 
btavrcp_get_element_attr_callback(uint8_t num_attr,btrc_media_attr_t * p_attrs,bt_bdaddr_t * bd_addr)105 static void btavrcp_get_element_attr_callback(uint8_t num_attr,
106                                               btrc_media_attr_t* p_attrs,
107                                               bt_bdaddr_t* bd_addr) {
108   CallbackEnv sCallbackEnv(__func__);
109   if (!sCallbackEnv.valid()) return;
110 
111   if (!mCallbacksObj) {
112     ALOGE("%s: mCallbacksObj is null", __func__);
113     return;
114   }
115 
116   ScopedLocalRef<jbyteArray> addr(
117       sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t)));
118   if (!addr.get()) {
119     ALOGE("Fail to new jbyteArray bd addr for get_element_attr command");
120     return;
121   }
122 
123   ScopedLocalRef<jintArray> attrs(
124       sCallbackEnv.get(), (jintArray)sCallbackEnv->NewIntArray(num_attr));
125   if (!attrs.get()) {
126     ALOGE("Fail to new jintArray for attrs");
127     return;
128   }
129 
130   sCallbackEnv->SetIntArrayRegion(attrs.get(), 0, num_attr, (jint*)p_attrs);
131 
132   sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(bt_bdaddr_t),
133                                    (jbyte*)bd_addr);
134   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_getElementAttr, addr.get(),
135                                (jbyte)num_attr, attrs.get());
136 }
137 
btavrcp_register_notification_callback(btrc_event_id_t event_id,uint32_t param,bt_bdaddr_t * bd_addr)138 static void btavrcp_register_notification_callback(btrc_event_id_t event_id,
139                                                    uint32_t param,
140                                                    bt_bdaddr_t* bd_addr) {
141   CallbackEnv sCallbackEnv(__func__);
142   if (!sCallbackEnv.valid()) return;
143 
144   if (!mCallbacksObj) {
145     ALOGE("%s: mCallbacksObj is null", __func__);
146     return;
147   }
148 
149   ScopedLocalRef<jbyteArray> addr(
150       sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t)));
151   if (!addr.get()) {
152     ALOGE("Fail to new jbyteArray bd addr for register_notification command");
153     return;
154   }
155 
156   sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(bt_bdaddr_t),
157                                    (jbyte*)bd_addr);
158   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_registerNotification,
159                                addr.get(), (jint)event_id, (jint)param);
160 }
161 
btavrcp_volume_change_callback(uint8_t volume,uint8_t ctype,bt_bdaddr_t * bd_addr)162 static void btavrcp_volume_change_callback(uint8_t volume, uint8_t ctype,
163                                            bt_bdaddr_t* bd_addr) {
164   CallbackEnv sCallbackEnv(__func__);
165   if (!sCallbackEnv.valid()) return;
166 
167   if (!mCallbacksObj) {
168     ALOGE("%s: mCallbacksObj is null", __func__);
169     return;
170   }
171 
172   ScopedLocalRef<jbyteArray> addr(
173       sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t)));
174   if (!addr.get()) {
175     ALOGE("Fail to new jbyteArray bd addr for volume_change command");
176     return;
177   }
178 
179   sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(bt_bdaddr_t),
180                                    (jbyte*)bd_addr);
181 
182   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_volumeChangeCallback,
183                                addr.get(), (jint)volume, (jint)ctype);
184 }
185 
btavrcp_passthrough_command_callback(int id,int pressed,bt_bdaddr_t * bd_addr)186 static void btavrcp_passthrough_command_callback(int id, int pressed,
187                                                  bt_bdaddr_t* bd_addr) {
188   CallbackEnv sCallbackEnv(__func__);
189   if (!sCallbackEnv.valid()) return;
190 
191   if (!mCallbacksObj) {
192     ALOGE("%s: mCallbacksObj is null", __func__);
193     return;
194   }
195 
196   ScopedLocalRef<jbyteArray> addr(
197       sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t)));
198   if (!addr.get()) {
199     ALOGE("Fail to new jbyteArray bd addr for passthrough_command command");
200     return;
201   }
202   sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(bt_bdaddr_t),
203                                    (jbyte*)bd_addr);
204 
205   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_handlePassthroughCmd,
206                                addr.get(), (jint)id, (jint)pressed);
207 }
208 
btavrcp_set_addressed_player_callback(uint16_t player_id,bt_bdaddr_t * bd_addr)209 static void btavrcp_set_addressed_player_callback(uint16_t player_id,
210                                                   bt_bdaddr_t* bd_addr) {
211   CallbackEnv sCallbackEnv(__func__);
212   if (!sCallbackEnv.valid()) return;
213 
214   if (!mCallbacksObj) {
215     ALOGE("%s: mCallbacksObj is null", __func__);
216     return;
217   }
218 
219   ScopedLocalRef<jbyteArray> addr(
220       sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t)));
221   if (!addr.get()) {
222     ALOGE("Fail to new jbyteArray bd addr for set_addressed_player command");
223     return;
224   }
225 
226   sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(bt_bdaddr_t),
227                                    (jbyte*)bd_addr);
228   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_setAddressedPlayerCallback,
229                                addr.get(), (jint)player_id);
230 }
231 
btavrcp_set_browsed_player_callback(uint16_t player_id,bt_bdaddr_t * bd_addr)232 static void btavrcp_set_browsed_player_callback(uint16_t player_id,
233                                                 bt_bdaddr_t* bd_addr) {
234   CallbackEnv sCallbackEnv(__func__);
235   if (!sCallbackEnv.valid()) return;
236   if (!mCallbacksObj) {
237     ALOGE("%s: mCallbacksObj is null", __func__);
238     return;
239   }
240 
241   ScopedLocalRef<jbyteArray> addr(
242       sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t)));
243   if (!addr.get()) {
244     ALOGE("Fail to new jbyteArray bd addr for set_browsed_player command");
245     return;
246   }
247   sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(bt_bdaddr_t),
248                                    (jbyte*)bd_addr);
249 
250   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_setBrowsedPlayerCallback,
251                                addr.get(), (jint)player_id);
252 }
253 
btavrcp_get_folder_items_callback(uint8_t scope,uint32_t start_item,uint32_t end_item,uint8_t num_attr,uint32_t * p_attr_ids,bt_bdaddr_t * bd_addr)254 static void btavrcp_get_folder_items_callback(
255     uint8_t scope, uint32_t start_item, uint32_t end_item, uint8_t num_attr,
256     uint32_t* p_attr_ids, bt_bdaddr_t* bd_addr) {
257   CallbackEnv sCallbackEnv(__func__);
258   if (!sCallbackEnv.valid()) return;
259 
260   if (!mCallbacksObj) {
261     ALOGE("%s: mCallbacksObj is null", __func__);
262     return;
263   }
264 
265   ScopedLocalRef<jbyteArray> addr(
266       sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t)));
267   if (!addr.get()) {
268     ALOGE("Fail to new jbyteArray bd addr for get_folder_items command");
269     return;
270   }
271 
272   uint32_t* puiAttr = (uint32_t*)p_attr_ids;
273   ScopedLocalRef<jintArray> attr_ids(sCallbackEnv.get(), NULL);
274   sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(bt_bdaddr_t),
275                                    (jbyte*)bd_addr);
276 
277   /* check number of attributes requested by remote device */
278   if ((num_attr != BTRC_NUM_ATTR_ALL) && (num_attr != BTRC_NUM_ATTR_NONE)) {
279     /* allocate memory for attr_ids only if some attributes passed from below
280      * layer */
281     attr_ids.reset((jintArray)sCallbackEnv->NewIntArray(num_attr));
282     if (!attr_ids.get()) {
283       ALOGE("Fail to allocate new jintArray for attrs");
284       return;
285     }
286     sCallbackEnv->SetIntArrayRegion(attr_ids.get(), 0, num_attr,
287                                     (jint*)puiAttr);
288   }
289 
290   sCallbackEnv->CallVoidMethod(
291       mCallbacksObj, method_getFolderItemsCallback, addr.get(), (jbyte)scope,
292       (jlong)start_item, (jlong)end_item, (jbyte)num_attr, attr_ids.get());
293 }
294 
btavrcp_change_path_callback(uint8_t direction,uint8_t * folder_uid,bt_bdaddr_t * bd_addr)295 static void btavrcp_change_path_callback(uint8_t direction, uint8_t* folder_uid,
296                                          bt_bdaddr_t* bd_addr) {
297   CallbackEnv sCallbackEnv(__func__);
298   if (!sCallbackEnv.valid()) return;
299 
300   if (!mCallbacksObj) {
301     ALOGE("%s: mCallbacksObj is null", __func__);
302     return;
303   }
304 
305   ScopedLocalRef<jbyteArray> attrs(sCallbackEnv.get(),
306                                    sCallbackEnv->NewByteArray(BTRC_UID_SIZE));
307   if (!attrs.get()) {
308     ALOGE("Fail to new jintArray for attrs");
309     return;
310   }
311 
312   ScopedLocalRef<jbyteArray> addr(
313       sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t)));
314   if (!addr.get()) {
315     ALOGE("Fail to new jbyteArray bd addr for change_path command");
316     return;
317   }
318 
319   sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(bt_bdaddr_t),
320                                    (jbyte*)bd_addr);
321   sCallbackEnv->SetByteArrayRegion(
322       attrs.get(), 0, sizeof(uint8_t) * BTRC_UID_SIZE, (jbyte*)folder_uid);
323   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_changePathCallback,
324                                addr.get(), (jbyte)direction, attrs.get());
325 }
326 
btavrcp_get_item_attr_callback(uint8_t scope,uint8_t * uid,uint16_t uid_counter,uint8_t num_attr,btrc_media_attr_t * p_attrs,bt_bdaddr_t * bd_addr)327 static void btavrcp_get_item_attr_callback(uint8_t scope, uint8_t* uid,
328                                            uint16_t uid_counter,
329                                            uint8_t num_attr,
330                                            btrc_media_attr_t* p_attrs,
331                                            bt_bdaddr_t* bd_addr) {
332   CallbackEnv sCallbackEnv(__func__);
333   if (!sCallbackEnv.valid()) return;
334 
335   if (!mCallbacksObj) {
336     ALOGE("%s: mCallbacksObj is null", __func__);
337     return;
338   }
339 
340   ScopedLocalRef<jbyteArray> attr_uid(
341       sCallbackEnv.get(), sCallbackEnv->NewByteArray(BTRC_UID_SIZE));
342   if (!attr_uid.get()) {
343     ALOGE("Fail to new jintArray for attr_uid");
344     return;
345   }
346 
347   ScopedLocalRef<jbyteArray> addr(
348       sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t)));
349   if (!addr.get()) {
350     ALOGE("Fail to new jbyteArray bd addr for get_item_attr command");
351     return;
352   }
353 
354   ScopedLocalRef<jintArray> attrs(
355       sCallbackEnv.get(), (jintArray)sCallbackEnv->NewIntArray(num_attr));
356   if (!attrs.get()) {
357     ALOGE("Fail to new jintArray for attrs");
358     return;
359   }
360 
361   sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(bt_bdaddr_t),
362                                    (jbyte*)bd_addr);
363   sCallbackEnv->SetIntArrayRegion(attrs.get(), 0, num_attr, (jint*)p_attrs);
364   sCallbackEnv->SetByteArrayRegion(
365       attr_uid.get(), 0, sizeof(uint8_t) * BTRC_UID_SIZE, (jbyte*)uid);
366 
367   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_getItemAttrCallback,
368                                addr.get(), (jbyte)scope, attr_uid.get(),
369                                (jint)uid_counter, (jbyte)num_attr, attrs.get());
370 }
371 
btavrcp_play_item_callback(uint8_t scope,uint16_t uid_counter,uint8_t * uid,bt_bdaddr_t * bd_addr)372 static void btavrcp_play_item_callback(uint8_t scope, uint16_t uid_counter,
373                                        uint8_t* uid, bt_bdaddr_t* bd_addr) {
374   CallbackEnv sCallbackEnv(__func__);
375   if (!sCallbackEnv.valid()) return;
376   if (!mCallbacksObj) {
377     ALOGE("%s: mCallbacksObj is null", __func__);
378     return;
379   }
380 
381   ScopedLocalRef<jbyteArray> attrs(sCallbackEnv.get(),
382                                    sCallbackEnv->NewByteArray(BTRC_UID_SIZE));
383   if (!attrs.get()) {
384     ALOGE("%s: Fail to new jByteArray attrs for play_item command", __func__);
385     return;
386   }
387 
388   ScopedLocalRef<jbyteArray> addr(
389       sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t)));
390   if (!addr.get()) {
391     ALOGE("Fail to new jbyteArray bd addr for play_item command");
392     return;
393   }
394 
395   sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(bt_bdaddr_t),
396                                    (jbyte*)bd_addr);
397   sCallbackEnv->SetByteArrayRegion(
398       attrs.get(), 0, sizeof(uint8_t) * BTRC_UID_SIZE, (jbyte*)uid);
399   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_playItemCallback,
400                                addr.get(), (jbyte)scope, (jint)uid_counter,
401                                attrs.get());
402 }
403 
btavrcp_get_total_num_items_callback(uint8_t scope,bt_bdaddr_t * bd_addr)404 static void btavrcp_get_total_num_items_callback(uint8_t scope,
405                                                  bt_bdaddr_t* bd_addr) {
406   CallbackEnv sCallbackEnv(__func__);
407   if (!sCallbackEnv.valid()) return;
408   if (!mCallbacksObj) {
409     ALOGE("%s: mCallbacksObj is null", __func__);
410     return;
411   }
412 
413   ScopedLocalRef<jbyteArray> addr(
414       sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t)));
415   if (!addr.get()) {
416     ALOGE("Fail to new jbyteArray bd addr for get_total_num_items command");
417     return;
418   }
419 
420   sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(bt_bdaddr_t),
421                                    (jbyte*)bd_addr);
422   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_getTotalNumOfItemsCallback,
423                                addr.get(), (jbyte)scope);
424 }
425 
btavrcp_search_callback(uint16_t charset_id,uint16_t str_len,uint8_t * p_str,bt_bdaddr_t * bd_addr)426 static void btavrcp_search_callback(uint16_t charset_id, uint16_t str_len,
427                                     uint8_t* p_str, bt_bdaddr_t* bd_addr) {
428   CallbackEnv sCallbackEnv(__func__);
429   if (!sCallbackEnv.valid()) return;
430   if (!mCallbacksObj) {
431     ALOGE("%s: mCallbacksObj is null", __func__);
432     return;
433   }
434 
435   ScopedLocalRef<jbyteArray> attrs(sCallbackEnv.get(),
436                                    sCallbackEnv->NewByteArray(str_len));
437   if (!attrs.get()) {
438     ALOGE("Fail to new jintArray for attrs");
439     return;
440   }
441 
442   ScopedLocalRef<jbyteArray> addr(
443       sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t)));
444   if (!addr.get()) {
445     ALOGE("Fail to new jbyteArray bd addr for search command");
446     return;
447   }
448 
449   sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(bt_bdaddr_t),
450                                    (jbyte*)bd_addr);
451   sCallbackEnv->SetByteArrayRegion(attrs.get(), 0, str_len * sizeof(uint8_t),
452                                    (jbyte*)p_str);
453   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_searchCallback, addr.get(),
454                                (jint)charset_id, attrs.get());
455 }
456 
btavrcp_add_to_play_list_callback(uint8_t scope,uint8_t * uid,uint16_t uid_counter,bt_bdaddr_t * bd_addr)457 static void btavrcp_add_to_play_list_callback(uint8_t scope, uint8_t* uid,
458                                               uint16_t uid_counter,
459                                               bt_bdaddr_t* bd_addr) {
460   CallbackEnv sCallbackEnv(__func__);
461   if (!sCallbackEnv.valid()) return;
462   if (!mCallbacksObj) {
463     ALOGE("%s: mCallbacksObj is null", __func__);
464     return;
465   }
466 
467   ScopedLocalRef<jbyteArray> addr(
468       sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t)));
469   if (!addr.get()) {
470     ALOGE("Fail to new jbyteArray bd addr for add_to_play_list command");
471     return;
472   }
473 
474   ScopedLocalRef<jbyteArray> attrs(sCallbackEnv.get(),
475                                    sCallbackEnv->NewByteArray(BTRC_UID_SIZE));
476   if (!attrs.get()) {
477     ALOGE("Fail to new jByteArray for attrs");
478     return;
479   }
480 
481   sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(bt_bdaddr_t),
482                                    (jbyte*)bd_addr);
483   sCallbackEnv->SetByteArrayRegion(
484       attrs.get(), 0, sizeof(uint8_t) * BTRC_UID_SIZE, (jbyte*)uid);
485   sCallbackEnv->CallVoidMethod(mCallbacksObj, method_addToPlayListCallback,
486                                addr.get(), (jbyte)scope, attrs.get(),
487                                (jint)uid_counter);
488 }
489 
490 static btrc_callbacks_t sBluetoothAvrcpCallbacks = {
491     sizeof(sBluetoothAvrcpCallbacks),
492     btavrcp_remote_features_callback,
493     btavrcp_get_play_status_callback,
494     NULL,
495     NULL,
496     NULL,
497     NULL,
498     NULL,
499     NULL,
500     btavrcp_get_element_attr_callback,
501     btavrcp_register_notification_callback,
502     btavrcp_volume_change_callback,
503     btavrcp_passthrough_command_callback,
504     btavrcp_set_addressed_player_callback,
505     btavrcp_set_browsed_player_callback,
506     btavrcp_get_folder_items_callback,
507     btavrcp_change_path_callback,
508     btavrcp_get_item_attr_callback,
509     btavrcp_play_item_callback,
510     btavrcp_get_total_num_items_callback,
511     btavrcp_search_callback,
512     btavrcp_add_to_play_list_callback,
513 };
514 
classInitNative(JNIEnv * env,jclass clazz)515 static void classInitNative(JNIEnv* env, jclass clazz) {
516   method_getRcFeatures =
517       env->GetMethodID(clazz, "getRcFeaturesRequestFromNative", "([BI)V");
518   method_getPlayStatus =
519       env->GetMethodID(clazz, "getPlayStatusRequestFromNative", "([B)V");
520 
521   method_getElementAttr =
522       env->GetMethodID(clazz, "getElementAttrRequestFromNative", "([BB[I)V");
523 
524   method_registerNotification = env->GetMethodID(
525       clazz, "registerNotificationRequestFromNative", "([BII)V");
526 
527   method_volumeChangeCallback =
528       env->GetMethodID(clazz, "volumeChangeRequestFromNative", "([BII)V");
529 
530   method_handlePassthroughCmd = env->GetMethodID(
531       clazz, "handlePassthroughCmdRequestFromNative", "([BII)V");
532 
533   method_setAddressedPlayerCallback =
534       env->GetMethodID(clazz, "setAddressedPlayerRequestFromNative", "([BI)V");
535 
536   method_setBrowsedPlayerCallback =
537       env->GetMethodID(clazz, "setBrowsedPlayerRequestFromNative", "([BI)V");
538 
539   method_getFolderItemsCallback =
540       env->GetMethodID(clazz, "getFolderItemsRequestFromNative", "([BBJJB[I)V");
541 
542   method_changePathCallback =
543       env->GetMethodID(clazz, "changePathRequestFromNative", "([BB[B)V");
544 
545   method_getItemAttrCallback =
546       env->GetMethodID(clazz, "getItemAttrRequestFromNative", "([BB[BIB[I)V");
547 
548   method_playItemCallback =
549       env->GetMethodID(clazz, "playItemRequestFromNative", "([BBI[B)V");
550 
551   method_getTotalNumOfItemsCallback =
552       env->GetMethodID(clazz, "getTotalNumOfItemsRequestFromNative", "([BB)V");
553 
554   method_searchCallback =
555       env->GetMethodID(clazz, "searchRequestFromNative", "([BI[B)V");
556 
557   method_addToPlayListCallback =
558       env->GetMethodID(clazz, "addToPlayListRequestFromNative", "([BB[BI)V");
559 
560   ALOGI("%s: succeeds", __func__);
561 }
562 
initNative(JNIEnv * env,jobject object)563 static void initNative(JNIEnv* env, jobject object) {
564   const bt_interface_t* btInf = getBluetoothInterface();
565   if (btInf == NULL) {
566     ALOGE("Bluetooth module is not loaded");
567     return;
568   }
569 
570   if (sBluetoothAvrcpInterface != NULL) {
571     ALOGW("Cleaning up Avrcp Interface before initializing...");
572     sBluetoothAvrcpInterface->cleanup();
573     sBluetoothAvrcpInterface = NULL;
574   }
575 
576   if (mCallbacksObj != NULL) {
577     ALOGW("Cleaning up Avrcp callback object");
578     env->DeleteGlobalRef(mCallbacksObj);
579     mCallbacksObj = NULL;
580   }
581 
582   sBluetoothAvrcpInterface =
583       (btrc_interface_t*)btInf->get_profile_interface(BT_PROFILE_AV_RC_ID);
584   if (sBluetoothAvrcpInterface == NULL) {
585     ALOGE("Failed to get Bluetooth Avrcp Interface");
586     return;
587   }
588 
589   bt_status_t status =
590       sBluetoothAvrcpInterface->init(&sBluetoothAvrcpCallbacks);
591   if (status != BT_STATUS_SUCCESS) {
592     ALOGE("Failed to initialize Bluetooth Avrcp, status: %d", status);
593     sBluetoothAvrcpInterface = NULL;
594     return;
595   }
596 
597   mCallbacksObj = env->NewGlobalRef(object);
598 }
599 
cleanupNative(JNIEnv * env,jobject object)600 static void cleanupNative(JNIEnv* env, jobject object) {
601   const bt_interface_t* btInf = getBluetoothInterface();
602   if (btInf == NULL) {
603     ALOGE("Bluetooth module is not loaded");
604     return;
605   }
606 
607   if (sBluetoothAvrcpInterface != NULL) {
608     sBluetoothAvrcpInterface->cleanup();
609     sBluetoothAvrcpInterface = NULL;
610   }
611 
612   if (mCallbacksObj != NULL) {
613     env->DeleteGlobalRef(mCallbacksObj);
614     mCallbacksObj = NULL;
615   }
616 }
617 
getPlayStatusRspNative(JNIEnv * env,jobject object,jbyteArray address,jint playStatus,jint songLen,jint songPos)618 static jboolean getPlayStatusRspNative(JNIEnv* env, jobject object,
619                                        jbyteArray address, jint playStatus,
620                                        jint songLen, jint songPos) {
621   if (!sBluetoothAvrcpInterface) {
622     ALOGE("%s: sBluetoothAvrcpInterface is null", __func__);
623     return JNI_FALSE;
624   }
625 
626   jbyte* addr = env->GetByteArrayElements(address, NULL);
627   if (!addr) {
628     jniThrowIOException(env, EINVAL);
629     return JNI_FALSE;
630   }
631 
632   bt_status_t status = sBluetoothAvrcpInterface->get_play_status_rsp(
633       (bt_bdaddr_t*)addr, (btrc_play_status_t)playStatus, songLen, songPos);
634   if (status != BT_STATUS_SUCCESS) {
635     ALOGE("Failed get_play_status_rsp, status: %d", status);
636   }
637   env->ReleaseByteArrayElements(address, addr, 0);
638   return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
639 }
640 
getElementAttrRspNative(JNIEnv * env,jobject object,jbyteArray address,jbyte numAttr,jintArray attrIds,jobjectArray textArray)641 static jboolean getElementAttrRspNative(JNIEnv* env, jobject object,
642                                         jbyteArray address, jbyte numAttr,
643                                         jintArray attrIds,
644                                         jobjectArray textArray) {
645   if (!sBluetoothAvrcpInterface) {
646     ALOGE("%s: sBluetoothAvrcpInterface is null", __func__);
647     return JNI_FALSE;
648   }
649 
650   if (numAttr > BTRC_MAX_ELEM_ATTR_SIZE) {
651     ALOGE("get_element_attr_rsp: number of attributes exceed maximum");
652     return JNI_FALSE;
653   }
654 
655   jbyte* addr = env->GetByteArrayElements(address, NULL);
656   if (!addr) {
657     jniThrowIOException(env, EINVAL);
658     return JNI_FALSE;
659   }
660 
661   btrc_element_attr_val_t* pAttrs = new btrc_element_attr_val_t[numAttr];
662   if (!pAttrs) {
663     ALOGE("get_element_attr_rsp: not have enough memeory");
664     env->ReleaseByteArrayElements(address, addr, 0);
665     return JNI_FALSE;
666   }
667 
668   jint* attr = env->GetIntArrayElements(attrIds, NULL);
669   if (!attr) {
670     delete[] pAttrs;
671     jniThrowIOException(env, EINVAL);
672     env->ReleaseByteArrayElements(address, addr, 0);
673     return JNI_FALSE;
674   }
675 
676   int attr_cnt;
677   for (attr_cnt = 0; attr_cnt < numAttr; ++attr_cnt) {
678     pAttrs[attr_cnt].attr_id = attr[attr_cnt];
679     ScopedLocalRef<jstring> text(
680         env, (jstring)env->GetObjectArrayElement(textArray, attr_cnt));
681 
682     if (!copy_jstring(pAttrs[attr_cnt].text, BTRC_MAX_ATTR_STR_LEN, text.get(),
683                       env)) {
684       break;
685     }
686   }
687 
688   if (attr_cnt < numAttr) {
689     delete[] pAttrs;
690     env->ReleaseIntArrayElements(attrIds, attr, 0);
691     ALOGE("%s: Failed to copy attributes", __func__);
692     return JNI_FALSE;
693   }
694 
695   bt_bdaddr_t* btAddr = (bt_bdaddr_t*)addr;
696   bt_status_t status =
697       sBluetoothAvrcpInterface->get_element_attr_rsp(btAddr, numAttr, pAttrs);
698   if (status != BT_STATUS_SUCCESS) {
699     ALOGE("Failed get_element_attr_rsp, status: %d", status);
700   }
701 
702   delete[] pAttrs;
703   env->ReleaseIntArrayElements(attrIds, attr, 0);
704   env->ReleaseByteArrayElements(address, addr, 0);
705   return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
706 }
707 
getItemAttrRspNative(JNIEnv * env,jobject object,jbyteArray address,jint rspStatus,jbyte numAttr,jintArray attrIds,jobjectArray textArray)708 static jboolean getItemAttrRspNative(JNIEnv* env, jobject object,
709                                      jbyteArray address, jint rspStatus,
710                                      jbyte numAttr, jintArray attrIds,
711                                      jobjectArray textArray) {
712   if (!sBluetoothAvrcpInterface) {
713     ALOGE("%s: sBluetoothAvrcpInterface is null", __func__);
714     return JNI_FALSE;
715   }
716 
717   jbyte* addr = env->GetByteArrayElements(address, NULL);
718   if (!addr) {
719     jniThrowIOException(env, EINVAL);
720     return JNI_FALSE;
721   }
722 
723   if (numAttr > BTRC_MAX_ELEM_ATTR_SIZE) {
724     ALOGE("get_element_attr_rsp: number of attributes exceed maximum");
725     return JNI_FALSE;
726   }
727 
728   btrc_element_attr_val_t* pAttrs = new btrc_element_attr_val_t[numAttr];
729   if (!pAttrs) {
730     ALOGE("%s: not have enough memory", __func__);
731     env->ReleaseByteArrayElements(address, addr, 0);
732     return JNI_FALSE;
733   }
734 
735   jint* attr = NULL;
736   if (attrIds != NULL) {
737     attr = env->GetIntArrayElements(attrIds, NULL);
738     if (!attr) {
739       delete[] pAttrs;
740       jniThrowIOException(env, EINVAL);
741       env->ReleaseByteArrayElements(address, addr, 0);
742       return JNI_FALSE;
743     }
744   }
745 
746   for (int attr_cnt = 0; attr_cnt < numAttr; ++attr_cnt) {
747     pAttrs[attr_cnt].attr_id = attr[attr_cnt];
748     ScopedLocalRef<jstring> text(
749         env, (jstring)env->GetObjectArrayElement(textArray, attr_cnt));
750 
751     if (!copy_jstring(pAttrs[attr_cnt].text, BTRC_MAX_ATTR_STR_LEN, text.get(),
752                       env)) {
753       rspStatus = BTRC_STS_INTERNAL_ERR;
754       ALOGE("%s: Failed to copy attributes", __func__);
755       break;
756     }
757   }
758 
759   bt_bdaddr_t* btAddr = (bt_bdaddr_t*)addr;
760   bt_status_t status = sBluetoothAvrcpInterface->get_item_attr_rsp(
761       btAddr, (btrc_status_t)rspStatus, numAttr, pAttrs);
762   if (status != BT_STATUS_SUCCESS)
763     ALOGE("Failed get_item_attr_rsp, status: %d", status);
764 
765   if (pAttrs) delete[] pAttrs;
766   if (attr) env->ReleaseIntArrayElements(attrIds, attr, 0);
767   env->ReleaseByteArrayElements(address, addr, 0);
768 
769   return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
770 }
771 
registerNotificationRspPlayStatusNative(JNIEnv * env,jobject object,jint type,jint playStatus)772 static jboolean registerNotificationRspPlayStatusNative(JNIEnv* env,
773                                                         jobject object,
774                                                         jint type,
775                                                         jint playStatus) {
776   if (!sBluetoothAvrcpInterface) {
777     ALOGE("%s: sBluetoothAvrcpInterface is null", __func__);
778     return JNI_FALSE;
779   }
780 
781   btrc_register_notification_t param;
782   param.play_status = (btrc_play_status_t)playStatus;
783 
784   bt_status_t status = sBluetoothAvrcpInterface->register_notification_rsp(
785       BTRC_EVT_PLAY_STATUS_CHANGED, (btrc_notification_type_t)type, &param);
786   if (status != BT_STATUS_SUCCESS) {
787     ALOGE("Failed register_notification_rsp play status, status: %d", status);
788   }
789 
790   return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
791 }
792 
registerNotificationRspTrackChangeNative(JNIEnv * env,jobject object,jint type,jbyteArray track)793 static jboolean registerNotificationRspTrackChangeNative(JNIEnv* env,
794                                                          jobject object,
795                                                          jint type,
796                                                          jbyteArray track) {
797   if (!sBluetoothAvrcpInterface) {
798     ALOGE("%s: sBluetoothAvrcpInterface is null", __func__);
799     return JNI_FALSE;
800   }
801 
802   jbyte* trk = env->GetByteArrayElements(track, NULL);
803   if (!trk) {
804     jniThrowIOException(env, EINVAL);
805     return JNI_FALSE;
806   }
807 
808   btrc_register_notification_t param;
809   uint64_t uid = 0;
810   for (int uid_idx = 0; uid_idx < BTRC_UID_SIZE; ++uid_idx) {
811     param.track[uid_idx] = trk[uid_idx];
812     uid = uid + (trk[uid_idx] << (BTRC_UID_SIZE - 1 - uid_idx));
813   }
814 
815   ALOGV("%s: Sending track change notification: %d -> %llu", __func__, type,
816         uid);
817 
818   bt_status_t status = sBluetoothAvrcpInterface->register_notification_rsp(
819       BTRC_EVT_TRACK_CHANGE, (btrc_notification_type_t)type, &param);
820   if (status != BT_STATUS_SUCCESS) {
821     ALOGE("Failed register_notification_rsp track change, status: %d", status);
822   }
823 
824   env->ReleaseByteArrayElements(track, trk, 0);
825   return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
826 }
827 
registerNotificationRspPlayPosNative(JNIEnv * env,jobject object,jint type,jint playPos)828 static jboolean registerNotificationRspPlayPosNative(JNIEnv* env,
829                                                      jobject object, jint type,
830                                                      jint playPos) {
831   if (!sBluetoothAvrcpInterface) {
832     ALOGE("%s: sBluetoothAvrcpInterface is null", __func__);
833     return JNI_FALSE;
834   }
835 
836   btrc_register_notification_t param;
837   param.song_pos = (uint32_t)playPos;
838 
839   bt_status_t status = sBluetoothAvrcpInterface->register_notification_rsp(
840       BTRC_EVT_PLAY_POS_CHANGED, (btrc_notification_type_t)type, &param);
841   if (status != BT_STATUS_SUCCESS) {
842     ALOGE("Failed register_notification_rsp play position, status: %d", status);
843   }
844 
845   return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
846 }
847 
registerNotificationRspNowPlayingChangedNative(JNIEnv * env,jobject object,jint type)848 static jboolean registerNotificationRspNowPlayingChangedNative(JNIEnv* env,
849                                                                jobject object,
850                                                                jint type) {
851   if (!sBluetoothAvrcpInterface) {
852     ALOGE("%s: sBluetoothAvrcpInterface is null", __func__);
853     return JNI_FALSE;
854   }
855 
856   btrc_register_notification_t param;
857   bt_status_t status = sBluetoothAvrcpInterface->register_notification_rsp(
858       BTRC_EVT_NOW_PLAYING_CONTENT_CHANGED, (btrc_notification_type_t)type,
859       &param);
860   if (status != BT_STATUS_SUCCESS) {
861     ALOGE("Failed register_notification_rsp, nowPlaying Content status: %d",
862           status);
863   }
864   return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
865 }
866 
registerNotificationRspUIDsChangedNative(JNIEnv * env,jobject object,jint type,jint uidCounter)867 static jboolean registerNotificationRspUIDsChangedNative(JNIEnv* env,
868                                                          jobject object,
869                                                          jint type,
870                                                          jint uidCounter) {
871   if (!sBluetoothAvrcpInterface) {
872     ALOGE("%s: sBluetoothAvrcpInterface is null", __func__);
873     return JNI_FALSE;
874   }
875 
876   btrc_register_notification_t param;
877   param.uids_changed.uid_counter = (uint16_t)uidCounter;
878 
879   bt_status_t status = sBluetoothAvrcpInterface->register_notification_rsp(
880       BTRC_EVT_UIDS_CHANGED, (btrc_notification_type_t)type, &param);
881   if (status != BT_STATUS_SUCCESS) {
882     ALOGE("Failed register_notification_rsp, uids changed status: %d", status);
883   }
884 
885   return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
886 }
887 
registerNotificationRspAddrPlayerChangedNative(JNIEnv * env,jobject object,jint type,jint playerId,jint uidCounter)888 static jboolean registerNotificationRspAddrPlayerChangedNative(
889     JNIEnv* env, jobject object, jint type, jint playerId, jint uidCounter) {
890   if (!sBluetoothAvrcpInterface) {
891     ALOGE("%s: sBluetoothAvrcpInterface is null", __func__);
892     return JNI_FALSE;
893   }
894 
895   btrc_register_notification_t param;
896   param.addr_player_changed.player_id = (uint16_t)playerId;
897   param.addr_player_changed.uid_counter = (uint16_t)uidCounter;
898 
899   bt_status_t status = sBluetoothAvrcpInterface->register_notification_rsp(
900       BTRC_EVT_ADDR_PLAYER_CHANGE, (btrc_notification_type_t)type, &param);
901   if (status != BT_STATUS_SUCCESS) {
902     ALOGE("Failed register_notification_rsp address player changed status: %d",
903           status);
904   }
905 
906   return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
907 }
908 
registerNotificationRspAvalPlayerChangedNative(JNIEnv * env,jobject object,jint type)909 static jboolean registerNotificationRspAvalPlayerChangedNative(JNIEnv* env,
910                                                                jobject object,
911                                                                jint type) {
912   if (!sBluetoothAvrcpInterface) {
913     ALOGE("%s: sBluetoothAvrcpInterface is null", __func__);
914     return JNI_FALSE;
915   }
916 
917   btrc_register_notification_t param;
918   bt_status_t status = sBluetoothAvrcpInterface->register_notification_rsp(
919       BTRC_EVT_AVAL_PLAYER_CHANGE, (btrc_notification_type_t)type, &param);
920   if (status != BT_STATUS_SUCCESS) {
921     ALOGE(
922         "Failed register_notification_rsp available player changed status, "
923         "status: %d",
924         status);
925   }
926 
927   return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
928 }
929 
setVolumeNative(JNIEnv * env,jobject object,jint volume)930 static jboolean setVolumeNative(JNIEnv* env, jobject object, jint volume) {
931   if (!sBluetoothAvrcpInterface) {
932     ALOGE("%s: sBluetoothAvrcpInterface is null", __func__);
933     return JNI_FALSE;
934   }
935 
936   bt_status_t status = sBluetoothAvrcpInterface->set_volume((uint8_t)volume);
937   if (status != BT_STATUS_SUCCESS) {
938     ALOGE("Failed set_volume, status: %d", status);
939   }
940 
941   return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
942 }
943 
944 /* native response for scope as Media player */
mediaPlayerListRspNative(JNIEnv * env,jobject object,jbyteArray address,jint rspStatus,jint uidCounter,jbyte itemType,jint numItems,jintArray playerIds,jbyteArray playerTypes,jintArray playerSubtypes,jbyteArray playStatusValues,jshortArray featureBitmask,jobjectArray textArray)945 static jboolean mediaPlayerListRspNative(
946     JNIEnv* env, jobject object, jbyteArray address, jint rspStatus,
947     jint uidCounter, jbyte itemType, jint numItems, jintArray playerIds,
948     jbyteArray playerTypes, jintArray playerSubtypes,
949     jbyteArray playStatusValues, jshortArray featureBitmask,
950     jobjectArray textArray) {
951   if (!sBluetoothAvrcpInterface) {
952     ALOGE("%s: sBluetoothAvrcpInterface is null", __func__);
953     return JNI_FALSE;
954   }
955 
956   jbyte* addr = env->GetByteArrayElements(address, NULL);
957   if (!addr) {
958     jniThrowIOException(env, EINVAL);
959     return JNI_FALSE;
960   }
961 
962   jbyte *p_playerTypes = NULL, *p_PlayStatusValues = NULL;
963   jshort* p_FeatBitMaskValues = NULL;
964   jint *p_playerIds = NULL, *p_playerSubTypes = NULL;
965   btrc_folder_items_t* p_items = NULL;
966   if (rspStatus == BTRC_STS_NO_ERROR) {
967     /* allocate memory */
968     p_playerIds = env->GetIntArrayElements(playerIds, NULL);
969     p_playerTypes = env->GetByteArrayElements(playerTypes, NULL);
970     p_playerSubTypes = env->GetIntArrayElements(playerSubtypes, NULL);
971     p_PlayStatusValues = env->GetByteArrayElements(playStatusValues, NULL);
972     p_FeatBitMaskValues = env->GetShortArrayElements(featureBitmask, NULL);
973     p_items = new btrc_folder_items_t[numItems];
974     /* deallocate memory and return if allocation failed */
975     if (!p_playerIds || !p_playerTypes || !p_playerSubTypes ||
976         !p_PlayStatusValues || !p_FeatBitMaskValues || !p_items) {
977       if (p_playerIds) env->ReleaseIntArrayElements(playerIds, p_playerIds, 0);
978       if (p_playerTypes)
979         env->ReleaseByteArrayElements(playerTypes, p_playerTypes, 0);
980       if (p_playerSubTypes)
981         env->ReleaseIntArrayElements(playerSubtypes, p_playerSubTypes, 0);
982       if (p_PlayStatusValues)
983         env->ReleaseByteArrayElements(playStatusValues, p_PlayStatusValues, 0);
984       if (p_FeatBitMaskValues)
985         env->ReleaseShortArrayElements(featureBitmask, p_FeatBitMaskValues, 0);
986       if (p_items) delete[] p_items;
987 
988       jniThrowIOException(env, EINVAL);
989       ALOGE("%s: not have enough memory", __func__);
990       return JNI_FALSE;
991     }
992 
993     p_items->item_type = (uint8_t)itemType;
994 
995     /* copy list of media players along with other parameters */
996     int itemIdx;
997     for (itemIdx = 0; itemIdx < numItems; ++itemIdx) {
998       p_items[itemIdx].player.player_id = p_playerIds[itemIdx];
999       p_items[itemIdx].player.major_type = p_playerTypes[itemIdx];
1000       p_items[itemIdx].player.sub_type = p_playerSubTypes[itemIdx];
1001       p_items[itemIdx].player.play_status = p_PlayStatusValues[itemIdx];
1002       p_items[itemIdx].player.charset_id = BTRC_CHARSET_ID_UTF8;
1003 
1004       ScopedLocalRef<jstring> text(
1005           env, (jstring)env->GetObjectArrayElement(textArray, itemIdx));
1006       /* copy player name */
1007       if (!copy_jstring(p_items[itemIdx].player.name, BTRC_MAX_ATTR_STR_LEN,
1008                         text.get(), env))
1009         break;
1010 
1011       /* Feature bit mask is 128-bit value each */
1012       for (int InnCnt = 0; InnCnt < 16; InnCnt++) {
1013         p_items[itemIdx].player.features[InnCnt] =
1014             (uint8_t)p_FeatBitMaskValues[(itemIdx * 16) + InnCnt];
1015       }
1016     }
1017 
1018     /* failed to copy list of media players */
1019     if (itemIdx < numItems) {
1020       rspStatus = BTRC_STS_INTERNAL_ERR;
1021       ALOGE("%s: Failed to copy Media player attributes", __func__);
1022     }
1023   }
1024 
1025   bt_bdaddr_t* btAddr = (bt_bdaddr_t*)addr;
1026   bt_status_t status = sBluetoothAvrcpInterface->get_folder_items_list_rsp(
1027       btAddr, (btrc_status_t)rspStatus, uidCounter, numItems, p_items);
1028   if (status != BT_STATUS_SUCCESS) {
1029     ALOGE("Failed get_folder_items_list_rsp, status: %d", status);
1030   }
1031 
1032   /* release allocated memory */
1033   if (p_items) delete[] p_items;
1034   if (p_playerTypes)
1035     env->ReleaseByteArrayElements(playerTypes, p_playerTypes, 0);
1036   if (p_playerSubTypes)
1037     env->ReleaseIntArrayElements(playerSubtypes, p_playerSubTypes, 0);
1038   if (p_PlayStatusValues)
1039     env->ReleaseByteArrayElements(playStatusValues, p_PlayStatusValues, 0);
1040   if (p_FeatBitMaskValues) {
1041     env->ReleaseShortArrayElements(featureBitmask, p_FeatBitMaskValues, 0);
1042   }
1043   env->ReleaseByteArrayElements(address, addr, 0);
1044 
1045   return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
1046 }
1047 
getFolderItemsRspNative(JNIEnv * env,jobject object,jbyteArray address,jint rspStatus,jshort uidCounter,jbyte scope,jint numItems,jbyteArray folderType,jbyteArray playable,jbyteArray itemType,jbyteArray itemUidArray,jobjectArray displayNameArray,jintArray numAttrs,jintArray attributesIds,jobjectArray attributesArray)1048 static jboolean getFolderItemsRspNative(
1049     JNIEnv* env, jobject object, jbyteArray address, jint rspStatus,
1050     jshort uidCounter, jbyte scope, jint numItems, jbyteArray folderType,
1051     jbyteArray playable, jbyteArray itemType, jbyteArray itemUidArray,
1052     jobjectArray displayNameArray, jintArray numAttrs, jintArray attributesIds,
1053     jobjectArray attributesArray) {
1054   if (!sBluetoothAvrcpInterface) {
1055     ALOGE("%s: sBluetoothAvrcpInterface is null", __func__);
1056     return JNI_FALSE;
1057   }
1058 
1059   jbyte* addr = env->GetByteArrayElements(address, NULL);
1060   if (!addr) {
1061     jniThrowIOException(env, EINVAL);
1062     return JNI_FALSE;
1063   }
1064 
1065   jbyte *p_playable = NULL, *p_item_uid = NULL;
1066   jbyte* p_item_types = NULL; /* Folder or Media Item */
1067   jint* p_attributesIds = NULL;
1068   jbyte* p_folder_types =
1069       NULL; /* Folder properties like Album/Genre/Artists etc */
1070   jint* p_num_attrs = NULL;
1071   btrc_folder_items_t* p_items = NULL;
1072   /* none of the parameters should be null when no error */
1073   if (rspStatus == BTRC_STS_NO_ERROR) {
1074     /* allocate memory to each rsp item */
1075     if (folderType != NULL)
1076       p_folder_types = env->GetByteArrayElements(folderType, NULL);
1077     if (playable != NULL)
1078       p_playable = env->GetByteArrayElements(playable, NULL);
1079     if (itemType != NULL)
1080       p_item_types = env->GetByteArrayElements(itemType, NULL);
1081     if (NULL != numAttrs)
1082       p_num_attrs = env->GetIntArrayElements(numAttrs, NULL);
1083     if (NULL != attributesIds)
1084       p_attributesIds = env->GetIntArrayElements(attributesIds, NULL);
1085     if (itemUidArray != NULL)
1086       p_item_uid = (jbyte*)env->GetByteArrayElements(itemUidArray, NULL);
1087 
1088     p_items = new btrc_folder_items_t[numItems];
1089 
1090     /* if memory alloc failed, release memory */
1091     if (p_items && p_folder_types && p_playable && p_item_types && p_item_uid &&
1092         /* attributes can be null if remote requests 0 attributes */
1093         ((numAttrs != NULL && p_num_attrs) || (!numAttrs && !p_num_attrs)) &&
1094         ((attributesIds != NULL && p_attributesIds) ||
1095          (!attributesIds && !p_attributesIds))) {
1096       memset(p_items, 0, sizeof(btrc_folder_items_t) * numItems);
1097       if (scope == BTRC_SCOPE_FILE_SYSTEM || scope == BTRC_SCOPE_SEARCH ||
1098           scope == BTRC_SCOPE_NOW_PLAYING) {
1099         int attribCopiedIndex = 0;
1100         for (int item_idx = 0; item_idx < numItems; item_idx++) {
1101           if (BTRC_ITEM_FOLDER == p_item_types[item_idx]) {
1102             btrc_folder_items_t* pitem = &p_items[item_idx];
1103 
1104             memcpy(pitem->folder.uid, p_item_uid + item_idx * BTRC_UID_SIZE,
1105                    BTRC_UID_SIZE);
1106             pitem->item_type = (uint8_t)BTRC_ITEM_FOLDER;
1107             pitem->folder.charset_id = BTRC_CHARSET_ID_UTF8;
1108             pitem->folder.type = p_folder_types[item_idx];
1109             pitem->folder.playable = p_playable[item_idx];
1110 
1111             ScopedLocalRef<jstring> text(
1112                 env, (jstring)env->GetObjectArrayElement(displayNameArray,
1113                                                          item_idx));
1114             if (!copy_jstring(pitem->folder.name, BTRC_MAX_ATTR_STR_LEN,
1115                               text.get(), env)) {
1116               rspStatus = BTRC_STS_INTERNAL_ERR;
1117               ALOGE("%s: failed to copy display name of folder item", __func__);
1118               break;
1119             }
1120           } else if (BTRC_ITEM_MEDIA == p_item_types[item_idx]) {
1121             btrc_folder_items_t* pitem = &p_items[item_idx];
1122             memcpy(pitem->media.uid, p_item_uid + item_idx * BTRC_UID_SIZE,
1123                    BTRC_UID_SIZE);
1124 
1125             pitem->item_type = (uint8_t)BTRC_ITEM_MEDIA;
1126             pitem->media.charset_id = BTRC_CHARSET_ID_UTF8;
1127             pitem->media.type = BTRC_MEDIA_TYPE_AUDIO;
1128             pitem->media.num_attrs =
1129                 (p_num_attrs != NULL) ? p_num_attrs[item_idx] : 0;
1130 
1131             ScopedLocalRef<jstring> text(
1132                 env, (jstring)env->GetObjectArrayElement(displayNameArray,
1133                                                          item_idx));
1134             if (!copy_jstring(pitem->media.name, BTRC_MAX_ATTR_STR_LEN,
1135                               text.get(), env)) {
1136               rspStatus = BTRC_STS_INTERNAL_ERR;
1137               ALOGE("%s: failed to copy display name of media item", __func__);
1138               break;
1139             }
1140 
1141             /* copy item attributes */
1142             if (!copy_item_attributes(env, object, pitem, p_attributesIds,
1143                                       attributesArray, item_idx,
1144                                       attribCopiedIndex)) {
1145               ALOGE("%s: error in copying attributes of item = %s", __func__,
1146                     pitem->media.name);
1147               rspStatus = BTRC_STS_INTERNAL_ERR;
1148               break;
1149             }
1150             attribCopiedIndex += pitem->media.num_attrs;
1151           }
1152         }
1153       }
1154     } else {
1155       rspStatus = BTRC_STS_INTERNAL_ERR;
1156       ALOGE("%s: unable to allocate memory", __func__);
1157     }
1158   }
1159 
1160   bt_bdaddr_t* btAddr = (bt_bdaddr_t*)addr;
1161   bt_status_t status = sBluetoothAvrcpInterface->get_folder_items_list_rsp(
1162       btAddr, (btrc_status_t)rspStatus, uidCounter, numItems, p_items);
1163   if (status != BT_STATUS_SUCCESS)
1164     ALOGE("Failed get_folder_items_list_rsp, status: %d", status);
1165 
1166   /* Release allocated memory for all attributes in each media item */
1167   if (p_items) cleanup_items(p_items, numItems);
1168 
1169   /* Release allocated memory  */
1170   if (p_folder_types)
1171     env->ReleaseByteArrayElements(folderType, p_folder_types, 0);
1172   if (p_playable) env->ReleaseByteArrayElements(playable, p_playable, 0);
1173   if (p_item_types) env->ReleaseByteArrayElements(itemType, p_item_types, 0);
1174   if (p_num_attrs) env->ReleaseIntArrayElements(numAttrs, p_num_attrs, 0);
1175   if (p_attributesIds)
1176     env->ReleaseIntArrayElements(attributesIds, p_attributesIds, 0);
1177   if (p_item_uid) env->ReleaseByteArrayElements(itemUidArray, p_item_uid, 0);
1178   if (p_items) delete[] p_items;
1179   env->ReleaseByteArrayElements(address, addr, 0);
1180 
1181   return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
1182 }
1183 
setAddressedPlayerRspNative(JNIEnv * env,jobject object,jbyteArray address,jint rspStatus)1184 static jboolean setAddressedPlayerRspNative(JNIEnv* env, jobject object,
1185                                             jbyteArray address,
1186                                             jint rspStatus) {
1187   if (!sBluetoothAvrcpInterface) {
1188     ALOGE("%s: sBluetoothAvrcpInterface is null", __func__);
1189     return JNI_FALSE;
1190   }
1191 
1192   jbyte* addr = env->GetByteArrayElements(address, NULL);
1193   if (!addr) {
1194     jniThrowIOException(env, EINVAL);
1195     return JNI_FALSE;
1196   }
1197 
1198   bt_bdaddr_t* btAddr = (bt_bdaddr_t*)addr;
1199   bt_status_t status = sBluetoothAvrcpInterface->set_addressed_player_rsp(
1200       btAddr, (btrc_status_t)rspStatus);
1201   if (status != BT_STATUS_SUCCESS) {
1202     ALOGE("Failed set_addressed_player_rsp, status: %d", status);
1203   }
1204   env->ReleaseByteArrayElements(address, addr, 0);
1205 
1206   return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
1207 }
1208 
setBrowsedPlayerRspNative(JNIEnv * env,jobject object,jbyteArray address,jint rspStatus,jbyte depth,jint numItems,jobjectArray textArray)1209 static jboolean setBrowsedPlayerRspNative(JNIEnv* env, jobject object,
1210                                           jbyteArray address, jint rspStatus,
1211                                           jbyte depth, jint numItems,
1212                                           jobjectArray textArray) {
1213   if (!sBluetoothAvrcpInterface) {
1214     ALOGE("%s: sBluetoothAvrcpInterface is null", __func__);
1215     return JNI_FALSE;
1216   }
1217 
1218   jbyte* addr = env->GetByteArrayElements(address, NULL);
1219   if (!addr) {
1220     jniThrowIOException(env, EINVAL);
1221     return JNI_FALSE;
1222   }
1223 
1224   btrc_br_folder_name_t* p_folders = NULL;
1225   if (rspStatus == BTRC_STS_NO_ERROR) {
1226     if (depth > 0) {
1227       p_folders = new btrc_br_folder_name_t[depth];
1228     }
1229 
1230     for (int folder_idx = 0; folder_idx < depth; folder_idx++) {
1231       /* copy folder names */
1232       ScopedLocalRef<jstring> text(
1233           env, (jstring)env->GetObjectArrayElement(textArray, folder_idx));
1234 
1235       if (!copy_jstring(p_folders[folder_idx].p_str, BTRC_MAX_ATTR_STR_LEN,
1236                         text.get(), env)) {
1237         rspStatus = BTRC_STS_INTERNAL_ERR;
1238         delete[] p_folders;
1239         env->ReleaseByteArrayElements(address, addr, 0);
1240         ALOGE("%s: Failed to copy folder name", __func__);
1241         return JNI_FALSE;
1242       }
1243 
1244       p_folders[folder_idx].str_len =
1245           strlen((char*)p_folders[folder_idx].p_str);
1246     }
1247   }
1248 
1249   uint8_t folder_depth =
1250       depth; /* folder_depth is 0 if current folder is root */
1251   uint16_t charset_id = BTRC_CHARSET_ID_UTF8;
1252   bt_bdaddr_t* btAddr = (bt_bdaddr_t*)addr;
1253   bt_status_t status = sBluetoothAvrcpInterface->set_browsed_player_rsp(
1254       btAddr, (btrc_status_t)rspStatus, numItems, charset_id, folder_depth,
1255       p_folders);
1256   if (status != BT_STATUS_SUCCESS) {
1257     ALOGE("%s: Failed set_browsed_player_rsp, status: %d", __func__, status);
1258   }
1259 
1260   if (depth > 0) {
1261     delete[] p_folders;
1262   }
1263 
1264   env->ReleaseByteArrayElements(address, addr, 0);
1265   return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
1266 }
1267 
changePathRspNative(JNIEnv * env,jobject object,jbyteArray address,jint rspStatus,jint numItems)1268 static jboolean changePathRspNative(JNIEnv* env, jobject object,
1269                                     jbyteArray address, jint rspStatus,
1270                                     jint numItems) {
1271   if (!sBluetoothAvrcpInterface) {
1272     ALOGE("%s: sBluetoothAvrcpInterface is null", __func__);
1273     return JNI_FALSE;
1274   }
1275 
1276   jbyte* addr = env->GetByteArrayElements(address, NULL);
1277   if (!addr) {
1278     jniThrowIOException(env, EINVAL);
1279     return JNI_FALSE;
1280   }
1281 
1282   uint32_t nItems = (uint32_t)numItems;
1283   bt_bdaddr_t* btAddr = (bt_bdaddr_t*)addr;
1284   bt_status_t status = sBluetoothAvrcpInterface->change_path_rsp(
1285       btAddr, (btrc_status_t)rspStatus, (uint32_t)nItems);
1286   if (status != BT_STATUS_SUCCESS) {
1287     ALOGE("Failed change_path_rsp, status: %d", status);
1288   }
1289   env->ReleaseByteArrayElements(address, addr, 0);
1290 
1291   return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
1292 }
1293 
searchRspNative(JNIEnv * env,jobject object,jbyteArray address,jint rspStatus,jint uidCounter,jint numItems)1294 static jboolean searchRspNative(JNIEnv* env, jobject object, jbyteArray address,
1295                                 jint rspStatus, jint uidCounter,
1296                                 jint numItems) {
1297   if (!sBluetoothAvrcpInterface) {
1298     ALOGE("%s: sBluetoothAvrcpInterface is null", __func__);
1299     return JNI_FALSE;
1300   }
1301 
1302   jbyte* addr = env->GetByteArrayElements(address, NULL);
1303   if (!addr) {
1304     jniThrowIOException(env, EINVAL);
1305     return JNI_FALSE;
1306   }
1307 
1308   uint32_t nItems = (uint32_t)numItems;
1309   bt_bdaddr_t* btAddr = (bt_bdaddr_t*)addr;
1310   bt_status_t status = sBluetoothAvrcpInterface->search_rsp(
1311       btAddr, (btrc_status_t)rspStatus, (uint32_t)uidCounter, (uint32_t)nItems);
1312   if (status != BT_STATUS_SUCCESS) {
1313     ALOGE("Failed search_rsp, status: %d", status);
1314   }
1315 
1316   env->ReleaseByteArrayElements(address, addr, 0);
1317 
1318   return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
1319 }
1320 
playItemRspNative(JNIEnv * env,jobject object,jbyteArray address,jint rspStatus)1321 static jboolean playItemRspNative(JNIEnv* env, jobject object,
1322                                   jbyteArray address, jint rspStatus) {
1323   if (!sBluetoothAvrcpInterface) {
1324     ALOGE("%s: sBluetoothAvrcpInterface is null", __func__);
1325     return JNI_FALSE;
1326   }
1327 
1328   jbyte* addr = env->GetByteArrayElements(address, NULL);
1329   if (!addr) {
1330     jniThrowIOException(env, EINVAL);
1331     return JNI_FALSE;
1332   }
1333 
1334   bt_bdaddr_t* btAddr = (bt_bdaddr_t*)addr;
1335   bt_status_t status =
1336       sBluetoothAvrcpInterface->play_item_rsp(btAddr, (btrc_status_t)rspStatus);
1337   if (status != BT_STATUS_SUCCESS) {
1338     ALOGE("Failed play_item_rsp, status: %d", status);
1339   }
1340   env->ReleaseByteArrayElements(address, addr, 0);
1341 
1342   return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
1343 }
1344 
getTotalNumOfItemsRspNative(JNIEnv * env,jobject object,jbyteArray address,jint rspStatus,jint uidCounter,jint numItems)1345 static jboolean getTotalNumOfItemsRspNative(JNIEnv* env, jobject object,
1346                                             jbyteArray address, jint rspStatus,
1347                                             jint uidCounter, jint numItems) {
1348   if (!sBluetoothAvrcpInterface) {
1349     ALOGE("%s: sBluetoothAvrcpInterface is null", __func__);
1350     return JNI_FALSE;
1351   }
1352 
1353   jbyte* addr = env->GetByteArrayElements(address, NULL);
1354   if (!addr) {
1355     jniThrowIOException(env, EINVAL);
1356     return JNI_FALSE;
1357   }
1358 
1359   uint32_t nItems = (uint32_t)numItems;
1360   bt_bdaddr_t* btAddr = (bt_bdaddr_t*)addr;
1361   bt_status_t status = sBluetoothAvrcpInterface->get_total_num_of_items_rsp(
1362       btAddr, (btrc_status_t)rspStatus, (uint32_t)uidCounter, (uint32_t)nItems);
1363   if (status != BT_STATUS_SUCCESS) {
1364     ALOGE("Failed get_total_num_of_items_rsp, status: %d", status);
1365   }
1366   env->ReleaseByteArrayElements(address, addr, 0);
1367 
1368   return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
1369 }
1370 
addToNowPlayingRspNative(JNIEnv * env,jobject object,jbyteArray address,jint rspStatus)1371 static jboolean addToNowPlayingRspNative(JNIEnv* env, jobject object,
1372                                          jbyteArray address, jint rspStatus) {
1373   if (!sBluetoothAvrcpInterface) {
1374     ALOGE("%s: sBluetoothAvrcpInterface is null", __func__);
1375     return JNI_FALSE;
1376   }
1377 
1378   jbyte* addr = env->GetByteArrayElements(address, NULL);
1379   if (!addr) {
1380     jniThrowIOException(env, EINVAL);
1381     return JNI_FALSE;
1382   }
1383 
1384   bt_bdaddr_t* btAddr = (bt_bdaddr_t*)addr;
1385   bt_status_t status = sBluetoothAvrcpInterface->add_to_now_playing_rsp(
1386       btAddr, (btrc_status_t)rspStatus);
1387   if (status != BT_STATUS_SUCCESS) {
1388     ALOGE("Failed add_to_now_playing_rsp, status: %d", status);
1389   }
1390   env->ReleaseByteArrayElements(address, addr, 0);
1391 
1392   return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
1393 }
1394 
1395 static JNINativeMethod sMethods[] = {
1396     {"classInitNative", "()V", (void*)classInitNative},
1397     {"initNative", "()V", (void*)initNative},
1398     {"cleanupNative", "()V", (void*)cleanupNative},
1399     {"getPlayStatusRspNative", "([BIII)Z", (void*)getPlayStatusRspNative},
1400     {"getElementAttrRspNative", "([BB[I[Ljava/lang/String;)Z",
1401      (void*)getElementAttrRspNative},
1402     {"registerNotificationRspPlayStatusNative", "(II)Z",
1403      (void*)registerNotificationRspPlayStatusNative},
1404     {"registerNotificationRspTrackChangeNative", "(I[B)Z",
1405      (void*)registerNotificationRspTrackChangeNative},
1406     {"registerNotificationRspPlayPosNative", "(II)Z",
1407      (void*)registerNotificationRspPlayPosNative},
1408     {"setVolumeNative", "(I)Z", (void*)setVolumeNative},
1409 
1410     {"setAddressedPlayerRspNative", "([BI)Z",
1411      (void*)setAddressedPlayerRspNative},
1412 
1413     {"setBrowsedPlayerRspNative", "([BIBI[Ljava/lang/String;)Z",
1414      (void*)setBrowsedPlayerRspNative},
1415 
1416     {"mediaPlayerListRspNative", "([BIIBI[I[B[I[B[S[Ljava/lang/String;)Z",
1417      (void*)mediaPlayerListRspNative},
1418 
1419     {"getFolderItemsRspNative",
1420      "([BISBI[B[B[B[B[Ljava/lang/String;[I[I[Ljava/lang/String;)Z",
1421      (void*)getFolderItemsRspNative},
1422 
1423     {"changePathRspNative", "([BII)Z", (void*)changePathRspNative},
1424 
1425     {"getItemAttrRspNative", "([BIB[I[Ljava/lang/String;)Z",
1426      (void*)getItemAttrRspNative},
1427 
1428     {"playItemRspNative", "([BI)Z", (void*)playItemRspNative},
1429 
1430     {"getTotalNumOfItemsRspNative", "([BIII)Z",
1431      (void*)getTotalNumOfItemsRspNative},
1432 
1433     {"searchRspNative", "([BIII)Z", (void*)searchRspNative},
1434 
1435     {"addToNowPlayingRspNative", "([BI)Z", (void*)addToNowPlayingRspNative},
1436 
1437     {"registerNotificationRspAddrPlayerChangedNative", "(III)Z",
1438      (void*)registerNotificationRspAddrPlayerChangedNative},
1439 
1440     {"registerNotificationRspAvalPlayerChangedNative", "(I)Z",
1441      (void*)registerNotificationRspAvalPlayerChangedNative},
1442 
1443     {"registerNotificationRspUIDsChangedNative", "(II)Z",
1444      (void*)registerNotificationRspUIDsChangedNative},
1445 
1446     {"registerNotificationRspNowPlayingChangedNative", "(I)Z",
1447      (void*)registerNotificationRspNowPlayingChangedNative}};
1448 
register_com_android_bluetooth_avrcp(JNIEnv * env)1449 int register_com_android_bluetooth_avrcp(JNIEnv* env) {
1450   return jniRegisterNativeMethods(env, "com/android/bluetooth/avrcp/Avrcp",
1451                                   sMethods, NELEM(sMethods));
1452 }
1453 
1454 /* Helper function to copy attributes of item.
1455  * Assumes that all items in response have same number of attributes
1456  *
1457  * returns true on succes, false otherwise.
1458 */
copy_item_attributes(JNIEnv * env,jobject object,btrc_folder_items_t * pitem,jint * p_attributesIds,jobjectArray attributesArray,int item_idx,int attribCopiedIndex)1459 static bool copy_item_attributes(JNIEnv* env, jobject object,
1460                                  btrc_folder_items_t* pitem,
1461                                  jint* p_attributesIds,
1462                                  jobjectArray attributesArray, int item_idx,
1463                                  int attribCopiedIndex) {
1464   bool success = true;
1465 
1466   /* copy attributes of the item */
1467   if (0 < pitem->media.num_attrs) {
1468     int num_attrs = pitem->media.num_attrs;
1469     ALOGI("%s num_attr = %d", __func__, num_attrs);
1470     pitem->media.p_attrs = new btrc_element_attr_val_t[num_attrs];
1471     if (!pitem->media.p_attrs) {
1472       return false;
1473     }
1474 
1475     for (int tempAtrCount = 0; tempAtrCount < pitem->media.num_attrs;
1476          ++tempAtrCount) {
1477       pitem->media.p_attrs[tempAtrCount].attr_id =
1478           p_attributesIds[attribCopiedIndex + tempAtrCount];
1479 
1480       ScopedLocalRef<jstring> text(
1481           env, (jstring)env->GetObjectArrayElement(
1482                    attributesArray, attribCopiedIndex + tempAtrCount));
1483 
1484       if (!copy_jstring(pitem->media.p_attrs[tempAtrCount].text,
1485                         BTRC_MAX_ATTR_STR_LEN, text.get(), env)) {
1486         success = false;
1487         ALOGE("%s: failed to copy attributes", __func__);
1488         break;
1489       }
1490     }
1491   }
1492   return success;
1493 }
1494 
1495 /* Helper function to copy String data from java to native
1496  *
1497  * returns true on succes, false otherwise
1498  */
copy_jstring(uint8_t * str,int maxBytes,jstring jstr,JNIEnv * env)1499 static bool copy_jstring(uint8_t* str, int maxBytes, jstring jstr,
1500                          JNIEnv* env) {
1501   if (str == NULL || jstr == NULL || env == NULL) return false;
1502 
1503   memset(str, 0, maxBytes);
1504   const char* p_str = env->GetStringUTFChars(jstr, NULL);
1505   size_t len = strnlen(p_str, maxBytes - 1);
1506   memcpy(str, p_str, len);
1507 
1508   env->ReleaseStringUTFChars(jstr, p_str);
1509   return true;
1510 }
1511 
1512 /* Helper function to cleanup items */
cleanup_items(btrc_folder_items_t * p_items,int numItems)1513 static void cleanup_items(btrc_folder_items_t* p_items, int numItems) {
1514   for (int item_idx = 0; item_idx < numItems; item_idx++) {
1515     /* release memory for attributes in case item is media item */
1516     if ((BTRC_ITEM_MEDIA == p_items[item_idx].item_type) &&
1517         p_items[item_idx].media.p_attrs != NULL)
1518       delete[] p_items[item_idx].media.p_attrs;
1519   }
1520 }
1521 }
1522