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