1 /*
2  * Copyright (C) 2018 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 "AvrcpTargetJni"
18 
19 #include <base/functional/bind.h>
20 #include <base/functional/callback.h>
21 
22 #include <map>
23 #include <mutex>
24 #include <shared_mutex>
25 #include <vector>
26 
27 #include "avrcp.h"
28 #include "com_android_bluetooth.h"
29 
30 using namespace bluetooth::avrcp;
31 
32 namespace android {
33 
34 // Static Variables
35 static MediaCallbacks* mServiceCallbacks;
36 static ServiceInterface* sServiceInterface;
37 static jobject mJavaInterface;
38 static std::shared_timed_mutex interface_mutex;
39 static std::shared_timed_mutex callbacks_mutex;
40 
41 // Forward Declarations
42 static void sendMediaKeyEvent(int, KeyState);
43 static std::string getCurrentMediaId();
44 static SongInfo getSongInfo();
45 static PlayStatus getCurrentPlayStatus();
46 static std::vector<SongInfo> getNowPlayingList();
47 static uint16_t getCurrentPlayerId();
48 static std::vector<MediaPlayerInfo> getMediaPlayerList();
49 using SetBrowsedPlayerCb = MediaInterface::SetBrowsedPlayerCallback;
50 static void setBrowsedPlayer(uint16_t player_id, SetBrowsedPlayerCb);
51 using GetFolderItemsCb = MediaInterface::FolderItemsCallback;
52 static void getFolderItems(uint16_t player_id, std::string media_id,
53                            GetFolderItemsCb cb);
54 static void playItem(uint16_t player_id, bool now_playing,
55                      std::string media_id);
56 static void setActiveDevice(const RawAddress& address);
57 
58 static void volumeDeviceConnected(const RawAddress& address);
59 static void volumeDeviceConnected(
60     const RawAddress& address,
61     ::bluetooth::avrcp::VolumeInterface::VolumeChangedCb cb);
62 static void volumeDeviceDisconnected(const RawAddress& address);
63 static void setVolume(int8_t volume);
64 
65 using ListPlayerSettingsCb =
66     PlayerSettingsInterface::ListPlayerSettingsCallback;
67 static void listPlayerSettings(ListPlayerSettingsCb cb);
68 ListPlayerSettingsCb list_player_settings_cb;
69 using ListPlayerSettingValuesCb =
70     PlayerSettingsInterface::ListPlayerSettingValuesCallback;
71 static void listPlayerSettingValues(PlayerAttribute setting,
72                                     ListPlayerSettingValuesCb cb);
73 ListPlayerSettingValuesCb list_player_setting_values_cb;
74 using GetCurrentPlayerSettingValueCb =
75     PlayerSettingsInterface::GetCurrentPlayerSettingValueCallback;
76 static void getPlayerSettings(std::vector<PlayerAttribute> attributes,
77                               GetCurrentPlayerSettingValueCb cb);
78 GetCurrentPlayerSettingValueCb get_current_player_setting_value_cb;
79 using SetPlayerSettingValueCb =
80     PlayerSettingsInterface::SetPlayerSettingValueCallback;
81 static void setPlayerSettings(std::vector<PlayerAttribute> attributes,
82                               std::vector<uint8_t> values,
83                               SetPlayerSettingValueCb cb);
84 SetPlayerSettingValueCb set_player_setting_value_cb;
85 
86 // Local Variables
87 // TODO (apanicke): Use a map here to store the callback in order to
88 // support multi-browsing
89 SetBrowsedPlayerCb set_browsed_player_cb;
90 using map_entry = std::pair<std::string, GetFolderItemsCb>;
91 std::map<std::string, GetFolderItemsCb> get_folder_items_cb_map;
92 std::map<RawAddress, ::bluetooth::avrcp::VolumeInterface::VolumeChangedCb>
93     volumeCallbackMap;
94 
95 template <typename T>
copyJavaArraytoCppVector(JNIEnv * env,const jbyteArray & jArray,std::vector<T> & cVec)96 void copyJavaArraytoCppVector(JNIEnv* env, const jbyteArray& jArray,
97                               std::vector<T>& cVec) {
98   size_t len = (size_t)env->GetArrayLength(jArray);
99   if (len == 0) return;
100   jbyte* elements = env->GetByteArrayElements(jArray, nullptr);
101   T* array = reinterpret_cast<T*>(elements);
102   cVec.reserve(len);
103   std::copy(array, array + len, std::back_inserter(cVec));
104   env->ReleaseByteArrayElements(jArray, elements, 0);
105 }
106 
107 // TODO (apanicke): In the future, this interface should guarantee that
108 // all calls happen on the JNI Thread. Right now this is very difficult
109 // as it is hard to get a handle on the JNI thread from here.
110 class AvrcpMediaInterfaceImpl : public MediaInterface {
111  public:
SendKeyEvent(uint8_t key,KeyState state)112   void SendKeyEvent(uint8_t key, KeyState state) {
113     sendMediaKeyEvent(key, state);
114   }
115 
GetSongInfo(SongInfoCallback cb)116   void GetSongInfo(SongInfoCallback cb) override {
117     auto info = getSongInfo();
118     cb.Run(info);
119   }
120 
GetPlayStatus(PlayStatusCallback cb)121   void GetPlayStatus(PlayStatusCallback cb) override {
122     auto status = getCurrentPlayStatus();
123     cb.Run(status);
124   }
125 
GetNowPlayingList(NowPlayingCallback cb)126   void GetNowPlayingList(NowPlayingCallback cb) override {
127     auto curr_song_id = getCurrentMediaId();
128     auto now_playing_list = getNowPlayingList();
129     cb.Run(curr_song_id, std::move(now_playing_list));
130   }
131 
GetMediaPlayerList(MediaListCallback cb)132   void GetMediaPlayerList(MediaListCallback cb) override {
133     uint16_t current_player = getCurrentPlayerId();
134     auto player_list = getMediaPlayerList();
135     cb.Run(current_player, std::move(player_list));
136   }
137 
GetFolderItems(uint16_t player_id,std::string media_id,FolderItemsCallback folder_cb)138   void GetFolderItems(uint16_t player_id, std::string media_id,
139                       FolderItemsCallback folder_cb) override {
140     getFolderItems(player_id, media_id, folder_cb);
141   }
142 
SetBrowsedPlayer(uint16_t player_id,SetBrowsedPlayerCallback browse_cb)143   void SetBrowsedPlayer(uint16_t player_id,
144                         SetBrowsedPlayerCallback browse_cb) override {
145     setBrowsedPlayer(player_id, browse_cb);
146   }
147 
RegisterUpdateCallback(MediaCallbacks * callback)148   void RegisterUpdateCallback(MediaCallbacks* callback) override {
149     // TODO (apanicke): Allow multiple registrations in the future
150     mServiceCallbacks = callback;
151   }
152 
UnregisterUpdateCallback(MediaCallbacks *)153   void UnregisterUpdateCallback(MediaCallbacks* /* callback */) override {
154     mServiceCallbacks = nullptr;
155   }
156 
PlayItem(uint16_t player_id,bool now_playing,std::string media_id)157   void PlayItem(uint16_t player_id, bool now_playing,
158                 std::string media_id) override {
159     playItem(player_id, now_playing, media_id);
160   }
161 
SetActiveDevice(const RawAddress & address)162   void SetActiveDevice(const RawAddress& address) override {
163     setActiveDevice(address);
164   }
165 };
166 static AvrcpMediaInterfaceImpl mAvrcpInterface;
167 
168 class VolumeInterfaceImpl : public VolumeInterface {
169  public:
DeviceConnected(const RawAddress & bdaddr)170   void DeviceConnected(const RawAddress& bdaddr) override {
171     volumeDeviceConnected(bdaddr);
172   }
173 
DeviceConnected(const RawAddress & bdaddr,VolumeChangedCb cb)174   void DeviceConnected(const RawAddress& bdaddr, VolumeChangedCb cb) override {
175     volumeDeviceConnected(bdaddr, cb);
176   }
177 
DeviceDisconnected(const RawAddress & bdaddr)178   void DeviceDisconnected(const RawAddress& bdaddr) override {
179     volumeDeviceDisconnected(bdaddr);
180   }
181 
SetVolume(int8_t volume)182   void SetVolume(int8_t volume) override { setVolume(volume); }
183 };
184 static VolumeInterfaceImpl mVolumeInterface;
185 
186 class PlayerSettingsInterfaceImpl : public PlayerSettingsInterface {
187  public:
ListPlayerSettings(ListPlayerSettingsCallback cb)188   void ListPlayerSettings(ListPlayerSettingsCallback cb) {
189     listPlayerSettings(cb);
190   }
191 
ListPlayerSettingValues(PlayerAttribute setting,ListPlayerSettingValuesCallback cb)192   void ListPlayerSettingValues(PlayerAttribute setting,
193                                ListPlayerSettingValuesCallback cb) {
194     listPlayerSettingValues(setting, cb);
195   }
196 
GetCurrentPlayerSettingValue(std::vector<PlayerAttribute> attributes,GetCurrentPlayerSettingValueCallback cb)197   void GetCurrentPlayerSettingValue(std::vector<PlayerAttribute> attributes,
198                                     GetCurrentPlayerSettingValueCallback cb) {
199     getPlayerSettings(attributes, cb);
200   }
201 
SetPlayerSettings(std::vector<PlayerAttribute> attributes,std::vector<uint8_t> values,SetPlayerSettingValueCallback cb)202   void SetPlayerSettings(std::vector<PlayerAttribute> attributes,
203                          std::vector<uint8_t> values,
204                          SetPlayerSettingValueCallback cb) {
205     setPlayerSettings(attributes, values, cb);
206   }
207 };
208 static PlayerSettingsInterfaceImpl mPlayerSettingsInterface;
209 
210 static jmethodID method_getCurrentSongInfo;
211 static jmethodID method_getPlaybackStatus;
212 static jmethodID method_sendMediaKeyEvent;
213 
214 static jmethodID method_getCurrentMediaId;
215 static jmethodID method_getNowPlayingList;
216 
217 static jmethodID method_setBrowsedPlayer;
218 static jmethodID method_getCurrentPlayerId;
219 static jmethodID method_getMediaPlayerList;
220 static jmethodID method_getFolderItemsRequest;
221 static jmethodID method_playItem;
222 
223 static jmethodID method_setActiveDevice;
224 
225 static jmethodID method_volumeDeviceConnected;
226 static jmethodID method_volumeDeviceDisconnected;
227 
228 static jmethodID method_setVolume;
229 
230 static jmethodID method_listPlayerSettings;
231 static jmethodID method_listPlayerSettingValues;
232 static jmethodID method_getPlayerSettings;
233 static jmethodID method_setPlayerSettings;
234 
initNative(JNIEnv * env,jobject object)235 static void initNative(JNIEnv* env, jobject object) {
236   log::debug("");
237   std::unique_lock<std::shared_timed_mutex> interface_lock(interface_mutex);
238   std::unique_lock<std::shared_timed_mutex> callbacks_lock(callbacks_mutex);
239   mJavaInterface = env->NewGlobalRef(object);
240 
241   sServiceInterface = getBluetoothInterface()->get_avrcp_service();
242   sServiceInterface->Init(&mAvrcpInterface, &mVolumeInterface,
243                           &mPlayerSettingsInterface);
244 }
245 
registerBipServerNative(JNIEnv *,jobject,jint l2cap_psm)246 static void registerBipServerNative(JNIEnv* /* env */, jobject /* object */,
247                                     jint l2cap_psm) {
248   log::debug("l2cap_psm={}", (int)l2cap_psm);
249   std::unique_lock<std::shared_timed_mutex> interface_lock(interface_mutex);
250   if (sServiceInterface == nullptr) {
251     log::warn("Service not loaded.");
252     return;
253   }
254   sServiceInterface->RegisterBipServer((int)l2cap_psm);
255 }
256 
unregisterBipServerNative(JNIEnv *,jobject)257 static void unregisterBipServerNative(JNIEnv* /* env */, jobject /* object */) {
258   log::debug("");
259   std::unique_lock<std::shared_timed_mutex> interface_lock(interface_mutex);
260   if (sServiceInterface == nullptr) {
261     log::warn("Service not loaded.");
262     return;
263   }
264   sServiceInterface->UnregisterBipServer();
265 }
266 
sendMediaUpdateNative(JNIEnv *,jobject,jboolean metadata,jboolean state,jboolean queue)267 static void sendMediaUpdateNative(JNIEnv* /* env */, jobject /* object */,
268                                   jboolean metadata, jboolean state,
269                                   jboolean queue) {
270   log::debug("");
271   std::unique_lock<std::shared_timed_mutex> interface_lock(interface_mutex);
272   if (mServiceCallbacks == nullptr) {
273     log::warn("Service not loaded.");
274     return;
275   }
276 
277   mServiceCallbacks->SendMediaUpdate(metadata == JNI_TRUE, state == JNI_TRUE,
278                                      queue == JNI_TRUE);
279 }
280 
sendFolderUpdateNative(JNIEnv *,jobject,jboolean available_players,jboolean addressed_player,jboolean uids)281 static void sendFolderUpdateNative(JNIEnv* /* env */, jobject /* object */,
282                                    jboolean available_players,
283                                    jboolean addressed_player, jboolean uids) {
284   log::debug("");
285   std::unique_lock<std::shared_timed_mutex> interface_lock(interface_mutex);
286   if (mServiceCallbacks == nullptr) {
287     log::warn("Service not loaded.");
288     return;
289   }
290 
291   mServiceCallbacks->SendFolderUpdate(available_players == JNI_TRUE,
292                                       addressed_player == JNI_TRUE,
293                                       uids == JNI_TRUE);
294 }
295 
cleanupNative(JNIEnv * env,jobject)296 static void cleanupNative(JNIEnv* env, jobject /* object */) {
297   std::unique_lock<std::shared_timed_mutex> interface_lock(interface_mutex);
298   std::unique_lock<std::shared_timed_mutex> callbacks_lock(callbacks_mutex);
299 
300   get_folder_items_cb_map.clear();
301   volumeCallbackMap.clear();
302 
303   sServiceInterface->Cleanup();
304   env->DeleteGlobalRef(mJavaInterface);
305   mJavaInterface = nullptr;
306   mServiceCallbacks = nullptr;
307   sServiceInterface = nullptr;
308 }
309 
connectDeviceNative(JNIEnv * env,jobject,jstring address)310 jboolean connectDeviceNative(JNIEnv* env, jobject /* object */,
311                              jstring address) {
312   log::debug("");
313   std::unique_lock<std::shared_timed_mutex> interface_lock(interface_mutex);
314   if (mServiceCallbacks == nullptr) {
315     log::warn("Service not loaded.");
316     return JNI_FALSE;
317   }
318 
319   const char* tmp_addr = env->GetStringUTFChars(address, 0);
320   RawAddress bdaddr;
321   bool success = RawAddress::FromString(tmp_addr, bdaddr);
322   env->ReleaseStringUTFChars(address, tmp_addr);
323 
324   if (!success) return JNI_FALSE;
325 
326   return sServiceInterface->ConnectDevice(bdaddr) == true ? JNI_TRUE
327                                                           : JNI_FALSE;
328 }
329 
disconnectDeviceNative(JNIEnv * env,jobject,jstring address)330 jboolean disconnectDeviceNative(JNIEnv* env, jobject /* object */,
331                                 jstring address) {
332   log::debug("");
333   std::unique_lock<std::shared_timed_mutex> interface_lock(interface_mutex);
334   if (mServiceCallbacks == nullptr) {
335     log::warn("Service not loaded.");
336     return JNI_FALSE;
337   }
338 
339   const char* tmp_addr = env->GetStringUTFChars(address, 0);
340   RawAddress bdaddr;
341   bool success = RawAddress::FromString(tmp_addr, bdaddr);
342   env->ReleaseStringUTFChars(address, tmp_addr);
343 
344   if (!success) return JNI_FALSE;
345 
346   return sServiceInterface->DisconnectDevice(bdaddr) == true ? JNI_TRUE
347                                                              : JNI_FALSE;
348 }
349 
sendMediaKeyEvent(int key,KeyState state)350 static void sendMediaKeyEvent(int key, KeyState state) {
351   log::debug("");
352   std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
353   CallbackEnv sCallbackEnv(__func__);
354   if (!sCallbackEnv.valid() || !mJavaInterface) return;
355   sCallbackEnv->CallVoidMethod(
356       mJavaInterface, method_sendMediaKeyEvent, key,
357       state == KeyState::PUSHED ? JNI_TRUE : JNI_FALSE);
358 }
359 
getImageHandleFromJavaObj(JNIEnv * env,jobject image)360 static std::string getImageHandleFromJavaObj(JNIEnv* env, jobject image) {
361   std::string handle;
362 
363   if (image == nullptr) return handle;
364 
365   jclass class_image = env->GetObjectClass(image);
366   jmethodID method_getImageHandle =
367       env->GetMethodID(class_image, "getImageHandle", "()Ljava/lang/String;");
368   jstring imageHandle = (jstring) env->CallObjectMethod(
369       image, method_getImageHandle);
370   if (imageHandle == nullptr) {
371     return handle;
372   }
373 
374   const char* value = env->GetStringUTFChars(imageHandle, nullptr);
375   handle = std::string(value);
376   env->ReleaseStringUTFChars(imageHandle, value);
377   env->DeleteLocalRef(imageHandle);
378   return handle;
379 }
380 
getSongInfoFromJavaObj(JNIEnv * env,jobject metadata)381 static SongInfo getSongInfoFromJavaObj(JNIEnv* env, jobject metadata) {
382   SongInfo info;
383 
384   if (metadata == nullptr) return info;
385 
386   jclass class_metadata = env->GetObjectClass(metadata);
387   jfieldID field_mediaId =
388       env->GetFieldID(class_metadata, "mediaId", "Ljava/lang/String;");
389   jfieldID field_title =
390       env->GetFieldID(class_metadata, "title", "Ljava/lang/String;");
391   jfieldID field_artist =
392       env->GetFieldID(class_metadata, "artist", "Ljava/lang/String;");
393   jfieldID field_album =
394       env->GetFieldID(class_metadata, "album", "Ljava/lang/String;");
395   jfieldID field_trackNum =
396       env->GetFieldID(class_metadata, "trackNum", "Ljava/lang/String;");
397   jfieldID field_numTracks =
398       env->GetFieldID(class_metadata, "numTracks", "Ljava/lang/String;");
399   jfieldID field_genre =
400       env->GetFieldID(class_metadata, "genre", "Ljava/lang/String;");
401   jfieldID field_playingTime =
402       env->GetFieldID(class_metadata, "duration", "Ljava/lang/String;");
403   jfieldID field_image =
404       env->GetFieldID(class_metadata, "image", "Lcom/android/bluetooth/audio_util/Image;");
405 
406   jstring jstr = (jstring)env->GetObjectField(metadata, field_mediaId);
407   if (jstr != nullptr) {
408     const char* value = env->GetStringUTFChars(jstr, nullptr);
409     info.media_id = std::string(value);
410     env->ReleaseStringUTFChars(jstr, value);
411     env->DeleteLocalRef(jstr);
412   }
413 
414   jstr = (jstring)env->GetObjectField(metadata, field_title);
415   if (jstr != nullptr) {
416     const char* value = env->GetStringUTFChars(jstr, nullptr);
417     info.attributes.insert(
418         AttributeEntry(Attribute::TITLE, std::string(value)));
419     env->ReleaseStringUTFChars(jstr, value);
420     env->DeleteLocalRef(jstr);
421   }
422 
423   jstr = (jstring)env->GetObjectField(metadata, field_artist);
424   if (jstr != nullptr) {
425     const char* value = env->GetStringUTFChars(jstr, nullptr);
426     info.attributes.insert(
427         AttributeEntry(Attribute::ARTIST_NAME, std::string(value)));
428     env->ReleaseStringUTFChars(jstr, value);
429     env->DeleteLocalRef(jstr);
430   }
431 
432   jstr = (jstring)env->GetObjectField(metadata, field_album);
433   if (jstr != nullptr) {
434     const char* value = env->GetStringUTFChars(jstr, nullptr);
435     info.attributes.insert(
436         AttributeEntry(Attribute::ALBUM_NAME, std::string(value)));
437     env->ReleaseStringUTFChars(jstr, value);
438     env->DeleteLocalRef(jstr);
439   }
440 
441   jstr = (jstring)env->GetObjectField(metadata, field_trackNum);
442   if (jstr != nullptr) {
443     const char* value = env->GetStringUTFChars(jstr, nullptr);
444     info.attributes.insert(
445         AttributeEntry(Attribute::TRACK_NUMBER, std::string(value)));
446     env->ReleaseStringUTFChars(jstr, value);
447     env->DeleteLocalRef(jstr);
448   }
449 
450   jstr = (jstring)env->GetObjectField(metadata, field_numTracks);
451   if (jstr != nullptr) {
452     const char* value = env->GetStringUTFChars(jstr, nullptr);
453     info.attributes.insert(
454         AttributeEntry(Attribute::TOTAL_NUMBER_OF_TRACKS, std::string(value)));
455     env->ReleaseStringUTFChars(jstr, value);
456     env->DeleteLocalRef(jstr);
457   }
458 
459   jstr = (jstring)env->GetObjectField(metadata, field_genre);
460   if (jstr != nullptr) {
461     const char* value = env->GetStringUTFChars(jstr, nullptr);
462     info.attributes.insert(
463         AttributeEntry(Attribute::GENRE, std::string(value)));
464     env->ReleaseStringUTFChars(jstr, value);
465     env->DeleteLocalRef(jstr);
466   }
467 
468   jstr = (jstring)env->GetObjectField(metadata, field_playingTime);
469   if (jstr != nullptr) {
470     const char* value = env->GetStringUTFChars(jstr, nullptr);
471     info.attributes.insert(
472         AttributeEntry(Attribute::PLAYING_TIME, std::string(value)));
473     env->ReleaseStringUTFChars(jstr, value);
474     env->DeleteLocalRef(jstr);
475   }
476 
477   jobject object_image = env->GetObjectField(metadata, field_image);
478   if (object_image != nullptr) {
479     std::string imageHandle = getImageHandleFromJavaObj(env, object_image);
480     if (!imageHandle.empty()) {
481       info.attributes.insert(
482           AttributeEntry(Attribute::DEFAULT_COVER_ART, imageHandle));
483     }
484     env->DeleteLocalRef(object_image);
485   }
486 
487   return info;
488 }
489 
getFolderInfoFromJavaObj(JNIEnv * env,jobject folder)490 static FolderInfo getFolderInfoFromJavaObj(JNIEnv* env, jobject folder) {
491   FolderInfo info;
492 
493   jclass class_folder = env->GetObjectClass(folder);
494   jfieldID field_mediaId =
495       env->GetFieldID(class_folder, "mediaId", "Ljava/lang/String;");
496   jfieldID field_isPlayable = env->GetFieldID(class_folder, "isPlayable", "Z");
497   jfieldID field_name =
498       env->GetFieldID(class_folder, "title", "Ljava/lang/String;");
499 
500   jstring jstr = (jstring)env->GetObjectField(folder, field_mediaId);
501   if (jstr != nullptr) {
502     const char* value = env->GetStringUTFChars(jstr, nullptr);
503     info.media_id = std::string(value);
504     env->ReleaseStringUTFChars(jstr, value);
505     env->DeleteLocalRef(jstr);
506   }
507 
508   info.is_playable = env->GetBooleanField(folder, field_isPlayable) == JNI_TRUE;
509 
510   jstr = (jstring)env->GetObjectField(folder, field_name);
511   if (jstr != nullptr) {
512     const char* value = env->GetStringUTFChars(jstr, nullptr);
513     info.name = std::string(value);
514     env->ReleaseStringUTFChars(jstr, value);
515     env->DeleteLocalRef(jstr);
516   }
517 
518   return info;
519 }
520 
getSongInfo()521 static SongInfo getSongInfo() {
522   log::debug("");
523   std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
524   CallbackEnv sCallbackEnv(__func__);
525   if (!sCallbackEnv.valid() || !mJavaInterface) return SongInfo();
526 
527   jobject metadata =
528       sCallbackEnv->CallObjectMethod(mJavaInterface, method_getCurrentSongInfo);
529   SongInfo info = getSongInfoFromJavaObj(sCallbackEnv.get(), metadata);
530   sCallbackEnv->DeleteLocalRef(metadata);
531   return info;
532 }
533 
getCurrentPlayStatus()534 static PlayStatus getCurrentPlayStatus() {
535   log::debug("");
536   std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
537   CallbackEnv sCallbackEnv(__func__);
538   if (!sCallbackEnv.valid() || !mJavaInterface) return PlayStatus();
539 
540   PlayStatus status;
541   jobject playStatus =
542       sCallbackEnv->CallObjectMethod(mJavaInterface, method_getPlaybackStatus);
543 
544   if (playStatus == nullptr) {
545     log::error("Got a null play status");
546     return status;
547   }
548 
549   jclass class_playStatus = sCallbackEnv->GetObjectClass(playStatus);
550   jfieldID field_position =
551       sCallbackEnv->GetFieldID(class_playStatus, "position", "J");
552   jfieldID field_duration =
553       sCallbackEnv->GetFieldID(class_playStatus, "duration", "J");
554   jfieldID field_state =
555       sCallbackEnv->GetFieldID(class_playStatus, "state", "B");
556 
557   status.position = sCallbackEnv->GetLongField(playStatus, field_position);
558   status.duration = sCallbackEnv->GetLongField(playStatus, field_duration);
559   status.state = (PlayState)sCallbackEnv->GetByteField(playStatus, field_state);
560 
561   sCallbackEnv->DeleteLocalRef(playStatus);
562 
563   return status;
564 }
565 
getCurrentMediaId()566 static std::string getCurrentMediaId() {
567   log::debug("");
568   std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
569   CallbackEnv sCallbackEnv(__func__);
570   if (!sCallbackEnv.valid() || !mJavaInterface) return "";
571 
572   jstring media_id = (jstring)sCallbackEnv->CallObjectMethod(
573       mJavaInterface, method_getCurrentMediaId);
574   if (media_id == nullptr) {
575     log::error("Got a null media ID");
576     return "";
577   }
578 
579   const char* value = sCallbackEnv->GetStringUTFChars(media_id, nullptr);
580   std::string ret(value);
581   sCallbackEnv->ReleaseStringUTFChars(media_id, value);
582   sCallbackEnv->DeleteLocalRef(media_id);
583   return ret;
584 }
585 
getNowPlayingList()586 static std::vector<SongInfo> getNowPlayingList() {
587   log::debug("");
588   std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
589   CallbackEnv sCallbackEnv(__func__);
590   if (!sCallbackEnv.valid() || !mJavaInterface) return std::vector<SongInfo>();
591 
592   jobject song_list =
593       sCallbackEnv->CallObjectMethod(mJavaInterface, method_getNowPlayingList);
594   if (song_list == nullptr) {
595     log::error("Got a null now playing list");
596     return std::vector<SongInfo>();
597   }
598 
599   jclass class_list = sCallbackEnv->GetObjectClass(song_list);
600   jmethodID method_get =
601       sCallbackEnv->GetMethodID(class_list, "get", "(I)Ljava/lang/Object;");
602   jmethodID method_size = sCallbackEnv->GetMethodID(class_list, "size", "()I");
603 
604   auto size = sCallbackEnv->CallIntMethod(song_list, method_size);
605   if (size == 0) {
606     sCallbackEnv->DeleteLocalRef(song_list);
607     return std::vector<SongInfo>();
608   }
609   std::vector<SongInfo> ret;
610   for (int i = 0; i < size; i++) {
611     jobject song = sCallbackEnv->CallObjectMethod(song_list, method_get, i);
612     ret.push_back(getSongInfoFromJavaObj(sCallbackEnv.get(), song));
613     sCallbackEnv->DeleteLocalRef(song);
614   }
615 
616   sCallbackEnv->DeleteLocalRef(song_list);
617 
618   return ret;
619 }
620 
getCurrentPlayerId()621 static uint16_t getCurrentPlayerId() {
622   log::debug("");
623   std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
624   CallbackEnv sCallbackEnv(__func__);
625   if (!sCallbackEnv.valid() || !mJavaInterface) return 0u;
626 
627   jint id =
628       sCallbackEnv->CallIntMethod(mJavaInterface, method_getCurrentPlayerId);
629 
630   return (static_cast<int>(id) & 0xFFFF);
631 }
632 
getMediaPlayerList()633 static std::vector<MediaPlayerInfo> getMediaPlayerList() {
634   log::debug("");
635   std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
636   CallbackEnv sCallbackEnv(__func__);
637   if (!sCallbackEnv.valid() || !mJavaInterface)
638     return std::vector<MediaPlayerInfo>();
639 
640   jobject player_list = (jobject)sCallbackEnv->CallObjectMethod(
641       mJavaInterface, method_getMediaPlayerList);
642 
643   if (player_list == nullptr) {
644     log::error("Got a null media player list");
645     return std::vector<MediaPlayerInfo>();
646   }
647 
648   jclass class_list = sCallbackEnv->GetObjectClass(player_list);
649   jmethodID method_get =
650       sCallbackEnv->GetMethodID(class_list, "get", "(I)Ljava/lang/Object;");
651   jmethodID method_size = sCallbackEnv->GetMethodID(class_list, "size", "()I");
652 
653   jint list_size = sCallbackEnv->CallIntMethod(player_list, method_size);
654   if (list_size == 0) {
655     sCallbackEnv->DeleteLocalRef(player_list);
656     return std::vector<MediaPlayerInfo>();
657   }
658 
659   jobject player_info =
660       sCallbackEnv->CallObjectMethod(player_list, method_get, 0);
661   jclass class_playerInfo = sCallbackEnv->GetObjectClass(player_info);
662   jfieldID field_playerId =
663       sCallbackEnv->GetFieldID(class_playerInfo, "id", "I");
664   jfieldID field_name =
665       sCallbackEnv->GetFieldID(class_playerInfo, "name", "Ljava/lang/String;");
666   jfieldID field_browsable =
667       sCallbackEnv->GetFieldID(class_playerInfo, "browsable", "Z");
668 
669   std::vector<MediaPlayerInfo> ret_list;
670   for (jsize i = 0; i < list_size; i++) {
671     jobject player = sCallbackEnv->CallObjectMethod(player_list, method_get, i);
672 
673     MediaPlayerInfo temp;
674     temp.id = sCallbackEnv->GetIntField(player, field_playerId);
675 
676     jstring jstr = (jstring)sCallbackEnv->GetObjectField(player, field_name);
677     if (jstr != nullptr) {
678       const char* value = sCallbackEnv->GetStringUTFChars(jstr, nullptr);
679       temp.name = std::string(value);
680       sCallbackEnv->ReleaseStringUTFChars(jstr, value);
681       sCallbackEnv->DeleteLocalRef(jstr);
682     }
683 
684     temp.browsing_supported =
685         sCallbackEnv->GetBooleanField(player, field_browsable) == JNI_TRUE
686             ? true
687             : false;
688 
689     ret_list.push_back(std::move(temp));
690     sCallbackEnv->DeleteLocalRef(player);
691   }
692 
693   sCallbackEnv->DeleteLocalRef(player_info);
694   sCallbackEnv->DeleteLocalRef(player_list);
695 
696   return ret_list;
697 }
698 
setBrowsedPlayer(uint16_t player_id,SetBrowsedPlayerCb cb)699 static void setBrowsedPlayer(uint16_t player_id, SetBrowsedPlayerCb cb) {
700   log::debug("");
701   std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
702   CallbackEnv sCallbackEnv(__func__);
703   if (!sCallbackEnv.valid() || !mJavaInterface) return;
704 
705   set_browsed_player_cb = cb;
706   sCallbackEnv->CallVoidMethod(mJavaInterface, method_setBrowsedPlayer,
707                                player_id);
708 }
709 
setBrowsedPlayerResponseNative(JNIEnv * env,jobject,jint,jboolean success,jstring root_id,jint num_items)710 static void setBrowsedPlayerResponseNative(JNIEnv* env, jobject /* object */,
711                                            jint /* player_id */,
712                                            jboolean success, jstring root_id,
713                                            jint num_items) {
714   log::debug("");
715 
716   std::string root;
717   if (root_id != nullptr) {
718     const char* value = env->GetStringUTFChars(root_id, nullptr);
719     root = std::string(value);
720     env->ReleaseStringUTFChars(root_id, value);
721   }
722 
723   set_browsed_player_cb.Run(success == JNI_TRUE, root, num_items);
724 }
725 
getFolderItemsResponseNative(JNIEnv * env,jobject,jstring parent_id,jobject list)726 static void getFolderItemsResponseNative(JNIEnv* env, jobject /* object */,
727                                          jstring parent_id, jobject list) {
728   log::debug("");
729 
730   std::string id;
731   if (parent_id != nullptr) {
732     const char* value = env->GetStringUTFChars(parent_id, nullptr);
733     id = std::string(value);
734     env->ReleaseStringUTFChars(parent_id, value);
735   }
736 
737   // TODO (apanicke): Right now browsing will fail on a second device if two
738   // devices browse the same folder. Use a MultiMap to fix this behavior so
739   // that both callbacks can be handled with one lookup if a request comes
740   // for a folder that is already trying to be looked at.
741   if (get_folder_items_cb_map.find(id) == get_folder_items_cb_map.end()) {
742     log::error("Could not find response callback for the request of \"{}\"",
743                id);
744     return;
745   }
746 
747   auto callback = get_folder_items_cb_map.find(id)->second;
748   get_folder_items_cb_map.erase(id);
749 
750   if (list == nullptr) {
751     log::error("Got a null get folder items response list");
752     callback.Run(std::vector<ListItem>());
753     return;
754   }
755 
756   jclass class_list = env->GetObjectClass(list);
757   jmethodID method_get =
758       env->GetMethodID(class_list, "get", "(I)Ljava/lang/Object;");
759   jmethodID method_size = env->GetMethodID(class_list, "size", "()I");
760 
761   jint list_size = env->CallIntMethod(list, method_size);
762   if (list_size == 0) {
763     callback.Run(std::vector<ListItem>());
764     return;
765   }
766 
767   jobject list_item = env->CallObjectMethod(list, method_get, 0);
768   jclass class_listItem = env->GetObjectClass(list_item);
769   jfieldID field_isFolder = env->GetFieldID(class_listItem, "isFolder", "Z");
770   jfieldID field_folder = env->GetFieldID(
771       class_listItem, "folder", "Lcom/android/bluetooth/audio_util/Folder;");
772   jfieldID field_song = env->GetFieldID(
773       class_listItem, "song", "Lcom/android/bluetooth/audio_util/Metadata;");
774 
775   std::vector<ListItem> ret_list;
776   for (jsize i = 0; i < list_size; i++) {
777     jobject item = env->CallObjectMethod(list, method_get, i);
778 
779     bool is_folder = env->GetBooleanField(item, field_isFolder) == JNI_TRUE;
780 
781     if (is_folder) {
782       jobject folder = env->GetObjectField(item, field_folder);
783       ListItem temp = {ListItem::FOLDER,
784                        getFolderInfoFromJavaObj(env, folder),
785                        SongInfo()};
786       ret_list.push_back(temp);
787       env->DeleteLocalRef(folder);
788     } else {
789       jobject song = env->GetObjectField(item, field_song);
790       ListItem temp = {ListItem::SONG, FolderInfo(),
791                        getSongInfoFromJavaObj(env, song)};
792       ret_list.push_back(temp);
793       env->DeleteLocalRef(song);
794     }
795     env->DeleteLocalRef(item);
796   }
797 
798   env->DeleteLocalRef(list_item);
799 
800   callback.Run(std::move(ret_list));
801 }
802 
getFolderItems(uint16_t player_id,std::string media_id,GetFolderItemsCb cb)803 static void getFolderItems(uint16_t player_id, std::string media_id,
804                            GetFolderItemsCb cb) {
805   log::debug("");
806   std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
807   CallbackEnv sCallbackEnv(__func__);
808   if (!sCallbackEnv.valid() || !mJavaInterface) return;
809 
810   // TODO (apanicke): Fix a potential media_id collision if two media players
811   // use the same media_id scheme or two devices browse the same content.
812   get_folder_items_cb_map.insert(map_entry(media_id, cb));
813 
814   jstring j_media_id = sCallbackEnv->NewStringUTF(media_id.c_str());
815   sCallbackEnv->CallVoidMethod(mJavaInterface, method_getFolderItemsRequest,
816                                player_id, j_media_id);
817 }
818 
playItem(uint16_t player_id,bool now_playing,std::string media_id)819 static void playItem(uint16_t player_id, bool now_playing,
820                      std::string media_id) {
821   log::debug("");
822   std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
823   CallbackEnv sCallbackEnv(__func__);
824   if (!sCallbackEnv.valid() || !mJavaInterface) return;
825 
826   jstring j_media_id = sCallbackEnv->NewStringUTF(media_id.c_str());
827   sCallbackEnv->CallVoidMethod(mJavaInterface, method_playItem, player_id,
828                                now_playing ? JNI_TRUE : JNI_FALSE, j_media_id);
829 }
830 
setActiveDevice(const RawAddress & address)831 static void setActiveDevice(const RawAddress& address) {
832   log::debug("");
833   std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
834   CallbackEnv sCallbackEnv(__func__);
835   if (!sCallbackEnv.valid() || !mJavaInterface) return;
836 
837   jstring j_bdaddr = sCallbackEnv->NewStringUTF(address.ToString().c_str());
838   sCallbackEnv->CallVoidMethod(mJavaInterface, method_setActiveDevice,
839                                j_bdaddr);
840 }
841 
volumeDeviceConnected(const RawAddress & address)842 static void volumeDeviceConnected(const RawAddress& address) {
843   log::debug("");
844   std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
845   CallbackEnv sCallbackEnv(__func__);
846   if (!sCallbackEnv.valid() || !mJavaInterface) return;
847 
848   jstring j_bdaddr = sCallbackEnv->NewStringUTF(address.ToString().c_str());
849   sCallbackEnv->CallVoidMethod(mJavaInterface, method_volumeDeviceConnected,
850                                j_bdaddr, JNI_FALSE);
851 }
852 
volumeDeviceConnected(const RawAddress & address,::bluetooth::avrcp::VolumeInterface::VolumeChangedCb cb)853 static void volumeDeviceConnected(
854     const RawAddress& address,
855     ::bluetooth::avrcp::VolumeInterface::VolumeChangedCb cb) {
856   log::debug("");
857   std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
858   CallbackEnv sCallbackEnv(__func__);
859   if (!sCallbackEnv.valid() || !mJavaInterface) return;
860 
861   volumeCallbackMap.emplace(address, cb);
862 
863   jstring j_bdaddr = sCallbackEnv->NewStringUTF(address.ToString().c_str());
864   sCallbackEnv->CallVoidMethod(mJavaInterface, method_volumeDeviceConnected,
865                                j_bdaddr, JNI_TRUE);
866 }
867 
volumeDeviceDisconnected(const RawAddress & address)868 static void volumeDeviceDisconnected(const RawAddress& address) {
869   log::debug("");
870   std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
871   CallbackEnv sCallbackEnv(__func__);
872   if (!sCallbackEnv.valid() || !mJavaInterface) return;
873 
874   volumeCallbackMap.erase(address);
875 
876   jstring j_bdaddr = sCallbackEnv->NewStringUTF(address.ToString().c_str());
877   sCallbackEnv->CallVoidMethod(mJavaInterface, method_volumeDeviceDisconnected,
878                                j_bdaddr);
879 }
880 
sendVolumeChangedNative(JNIEnv * env,jobject,jstring address,jint volume)881 static void sendVolumeChangedNative(JNIEnv* env, jobject /* object */,
882                                     jstring address, jint volume) {
883   const char* tmp_addr = env->GetStringUTFChars(address, 0);
884   RawAddress bdaddr;
885   bool success = RawAddress::FromString(tmp_addr, bdaddr);
886   env->ReleaseStringUTFChars(address, tmp_addr);
887 
888   if (!success) return;
889 
890   log::debug("");
891   if (volumeCallbackMap.find(bdaddr) != volumeCallbackMap.end()) {
892     volumeCallbackMap.find(bdaddr)->second.Run(volume & 0x7F);
893   }
894 }
895 
setVolume(int8_t volume)896 static void setVolume(int8_t volume) {
897   log::debug("");
898   std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
899   CallbackEnv sCallbackEnv(__func__);
900   if (!sCallbackEnv.valid() || !mJavaInterface) return;
901 
902   sCallbackEnv->CallVoidMethod(mJavaInterface, method_setVolume, volume);
903 }
904 
setBipClientStatusNative(JNIEnv * env,jobject,jstring address,jboolean connected)905 static void setBipClientStatusNative(JNIEnv* env, jobject /* object */,
906                                      jstring address, jboolean connected) {
907   std::unique_lock<std::shared_timed_mutex> interface_lock(interface_mutex);
908   if (mServiceCallbacks == nullptr) {
909     log::warn("Service not loaded.");
910     return;
911   }
912 
913   const char* tmp_addr = env->GetStringUTFChars(address, 0);
914   RawAddress bdaddr;
915   bool success = RawAddress::FromString(tmp_addr, bdaddr);
916   env->ReleaseStringUTFChars(address, tmp_addr);
917 
918   if (!success) return;
919 
920   bool status = (connected == JNI_TRUE);
921   sServiceInterface->SetBipClientStatus(bdaddr, status);
922 }
923 
924 // Called from native to list available player settings
listPlayerSettings(ListPlayerSettingsCb cb)925 static void listPlayerSettings(ListPlayerSettingsCb cb) {
926   log::debug("");
927   std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
928   CallbackEnv sCallbackEnv(__func__);
929   if (!sCallbackEnv.valid() || !mJavaInterface) return;
930 
931   list_player_settings_cb = std::move(cb);
932   sCallbackEnv->CallVoidMethod(mJavaInterface, method_listPlayerSettings);
933 }
934 
listPlayerSettingsResponseNative(JNIEnv * env,jobject,jbyteArray attributes)935 static void listPlayerSettingsResponseNative(JNIEnv* env, jobject /* object */,
936                                              jbyteArray attributes) {
937   log::debug("");
938 
939   std::vector<PlayerAttribute> attributes_vector;
940   copyJavaArraytoCppVector(env, attributes, attributes_vector);
941 
942   list_player_settings_cb.Run(std::move(attributes_vector));
943 }
944 
945 // Called from native to list available values for player setting
listPlayerSettingValues(PlayerAttribute attribute,ListPlayerSettingValuesCb cb)946 static void listPlayerSettingValues(PlayerAttribute attribute,
947                                     ListPlayerSettingValuesCb cb) {
948   log::debug("");
949   std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
950   CallbackEnv sCallbackEnv(__func__);
951   if (!sCallbackEnv.valid() || !mJavaInterface) return;
952 
953   list_player_setting_values_cb = std::move(cb);
954   sCallbackEnv->CallVoidMethod(mJavaInterface, method_listPlayerSettingValues,
955                                (jbyte)attribute);
956 }
957 
listPlayerSettingValuesResponseNative(JNIEnv * env,jobject,jbyte attribute,jbyteArray values)958 static void listPlayerSettingValuesResponseNative(JNIEnv* env,
959                                                   jobject /* object */,
960                                                   jbyte attribute,
961                                                   jbyteArray values) {
962   log::debug("");
963   PlayerAttribute player_attribute = static_cast<PlayerAttribute>(attribute);
964   std::vector<uint8_t> values_vector;
965   copyJavaArraytoCppVector(env, values, values_vector);
966   list_player_setting_values_cb.Run(player_attribute, std::move(values_vector));
967 }
968 
969 // Called from native to get current player settings
getPlayerSettings(std::vector<PlayerAttribute> attributes,GetCurrentPlayerSettingValueCb cb)970 static void getPlayerSettings(std::vector<PlayerAttribute> attributes,
971                               GetCurrentPlayerSettingValueCb cb) {
972   log::debug("");
973   std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
974   CallbackEnv sCallbackEnv(__func__);
975   if (!sCallbackEnv.valid() || !mJavaInterface) return;
976 
977   jbyteArray attributes_array = sCallbackEnv->NewByteArray(attributes.size());
978   sCallbackEnv->SetByteArrayRegion(
979       attributes_array, 0, attributes.size(),
980       reinterpret_cast<const jbyte*>(attributes.data()));
981 
982   get_current_player_setting_value_cb = std::move(cb);
983   sCallbackEnv->CallVoidMethod(mJavaInterface, method_getPlayerSettings,
984                                attributes_array);
985 }
986 
getPlayerSettingsResponseNative(JNIEnv * env,jobject,jbyteArray attributes,jbyteArray values)987 static void getPlayerSettingsResponseNative(JNIEnv* env, jobject /* object */,
988                                             jbyteArray attributes,
989                                             jbyteArray values) {
990   log::debug("");
991   std::vector<PlayerAttribute> attributes_vector;
992   std::vector<uint8_t> values_vector;
993   copyJavaArraytoCppVector(env, attributes, attributes_vector);
994   copyJavaArraytoCppVector(env, values, values_vector);
995   get_current_player_setting_value_cb.Run(std::move(attributes_vector),
996                                           std::move(values_vector));
997 }
998 
999 // Called from native to set current player settings
setPlayerSettings(std::vector<PlayerAttribute> attributes,std::vector<uint8_t> values,SetPlayerSettingValueCb cb)1000 static void setPlayerSettings(std::vector<PlayerAttribute> attributes,
1001                               std::vector<uint8_t> values,
1002                               SetPlayerSettingValueCb cb) {
1003   log::debug("");
1004   std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
1005   CallbackEnv sCallbackEnv(__func__);
1006   if (!sCallbackEnv.valid() || !mJavaInterface) return;
1007 
1008   jbyteArray attributes_array = sCallbackEnv->NewByteArray(attributes.size());
1009   sCallbackEnv->SetByteArrayRegion(
1010       attributes_array, 0, attributes.size(),
1011       reinterpret_cast<const jbyte*>(attributes.data()));
1012 
1013   jbyteArray values_array = sCallbackEnv->NewByteArray(values.size());
1014   sCallbackEnv->SetByteArrayRegion(
1015       values_array, 0, values.size(),
1016       reinterpret_cast<const jbyte*>(values.data()));
1017 
1018   set_player_setting_value_cb = std::move(cb);
1019 
1020   sCallbackEnv->CallVoidMethod(mJavaInterface, method_setPlayerSettings,
1021                                attributes_array, values_array);
1022 }
1023 
setPlayerSettingsResponseNative(JNIEnv *,jobject,jboolean success)1024 static void setPlayerSettingsResponseNative(JNIEnv* /* env */,
1025                                             jobject /* object */,
1026                                             jboolean success) {
1027   log::debug("");
1028   set_player_setting_value_cb.Run(success);
1029 }
1030 
sendPlayerSettingsNative(JNIEnv * env,jobject,jbyteArray attributes,jbyteArray values)1031 static void sendPlayerSettingsNative(JNIEnv* env, jobject /* object */,
1032                                      jbyteArray attributes, jbyteArray values) {
1033   log::debug("");
1034   std::unique_lock<std::shared_timed_mutex> interface_lock(interface_mutex);
1035   if (mServiceCallbacks == nullptr) {
1036     log::warn("Service not loaded.");
1037     return;
1038   }
1039   std::vector<PlayerAttribute> attributes_vector;
1040   std::vector<uint8_t> values_vector;
1041   copyJavaArraytoCppVector(env, attributes, attributes_vector);
1042   copyJavaArraytoCppVector(env, values, values_vector);
1043   mServiceCallbacks->SendPlayerSettingsChanged(attributes_vector,
1044                                                values_vector);
1045 }
1046 
register_com_android_bluetooth_avrcp_target(JNIEnv * env)1047 int register_com_android_bluetooth_avrcp_target(JNIEnv* env) {
1048   const JNINativeMethod methods[] = {
1049       {"initNative", "()V", (void*)initNative},
1050       {"registerBipServerNative", "(I)V", (void*)registerBipServerNative},
1051       {"unregisterBipServerNative", "()V", (void*)unregisterBipServerNative},
1052       {"sendMediaUpdateNative", "(ZZZ)V", (void*)sendMediaUpdateNative},
1053       {"sendFolderUpdateNative", "(ZZZ)V", (void*)sendFolderUpdateNative},
1054       {"setBrowsedPlayerResponseNative", "(IZLjava/lang/String;I)V",
1055        (void*)setBrowsedPlayerResponseNative},
1056       {"getFolderItemsResponseNative", "(Ljava/lang/String;Ljava/util/List;)V",
1057        (void*)getFolderItemsResponseNative},
1058       {"cleanupNative", "()V", (void*)cleanupNative},
1059       {"connectDeviceNative", "(Ljava/lang/String;)Z",
1060        (void*)connectDeviceNative},
1061       {"disconnectDeviceNative", "(Ljava/lang/String;)Z",
1062        (void*)disconnectDeviceNative},
1063       {"sendVolumeChangedNative", "(Ljava/lang/String;I)V",
1064        (void*)sendVolumeChangedNative},
1065       {"setBipClientStatusNative", "(Ljava/lang/String;Z)V",
1066        (void*)setBipClientStatusNative},
1067       {"listPlayerSettingsResponseNative", "([B)V",
1068        (void*)listPlayerSettingsResponseNative},
1069       {"listPlayerSettingValuesResponseNative", "(B[B)V",
1070        (void*)listPlayerSettingValuesResponseNative},
1071       {"getPlayerSettingsResponseNative", "([B[B)V",
1072        (void*)getPlayerSettingsResponseNative},
1073       {"setPlayerSettingsResponseNative", "(Z)V",
1074        (void*)setPlayerSettingsResponseNative},
1075       {"sendPlayerSettingsNative", "([B[B)V", (void*)sendPlayerSettingsNative},
1076   };
1077   const int result = REGISTER_NATIVE_METHODS(
1078       env, "com/android/bluetooth/avrcp/AvrcpNativeInterface", methods);
1079   if (result != 0) {
1080     return result;
1081   }
1082 
1083   const JNIJavaMethod javaMethods[] = {
1084       {"getCurrentSongInfo", "()Lcom/android/bluetooth/audio_util/Metadata;",
1085        &method_getCurrentSongInfo},
1086       {"getPlayStatus", "()Lcom/android/bluetooth/audio_util/PlayStatus;",
1087        &method_getPlaybackStatus},
1088       {"sendMediaKeyEvent", "(IZ)V", &method_sendMediaKeyEvent},
1089       {"getCurrentMediaId", "()Ljava/lang/String;", &method_getCurrentMediaId},
1090       {"getNowPlayingList", "()Ljava/util/List;", &method_getNowPlayingList},
1091       {"getCurrentPlayerId", "()I", &method_getCurrentPlayerId},
1092       {"getMediaPlayerList", "()Ljava/util/List;", &method_getMediaPlayerList},
1093       {"setBrowsedPlayer", "(I)V", &method_setBrowsedPlayer},
1094       {"getFolderItemsRequest", "(ILjava/lang/String;)V",
1095        &method_getFolderItemsRequest},
1096       {"playItem", "(IZLjava/lang/String;)V", &method_playItem},
1097       {"setActiveDevice", "(Ljava/lang/String;)V", &method_setActiveDevice},
1098       {"deviceConnected", "(Ljava/lang/String;Z)V",
1099        &method_volumeDeviceConnected},
1100       {"deviceDisconnected", "(Ljava/lang/String;)V",
1101        &method_volumeDeviceDisconnected},
1102       {"setVolume", "(I)V", &method_setVolume},
1103       {"listPlayerSettingsRequest", "()V", &method_listPlayerSettings},
1104       {"listPlayerSettingValuesRequest", "(B)V",
1105        &method_listPlayerSettingValues},
1106       {"getCurrentPlayerSettingValuesRequest", "([B)V",
1107        &method_getPlayerSettings},
1108       {"setPlayerSettingsRequest", "([B[B)V", &method_setPlayerSettings},
1109   };
1110   GET_JAVA_METHODS(env, "com/android/bluetooth/avrcp/AvrcpNativeInterface",
1111                    javaMethods);
1112 
1113   return 0;
1114 }
1115 
1116 }  // namespace android
1117