1 /* 2 * Copyright 2023 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 package com.android.bluetooth.avrcpcontroller; 18 19 import android.bluetooth.BluetoothAdapter; 20 import android.bluetooth.BluetoothDevice; 21 import android.support.v4.media.session.PlaybackStateCompat; 22 import android.util.Log; 23 24 import com.android.internal.annotations.GuardedBy; 25 import com.android.internal.annotations.VisibleForTesting; 26 27 import java.util.Arrays; 28 import java.util.UUID; 29 30 /** Provides Bluetooth AVRCP Controller native interface for the AVRCP Controller service */ 31 public class AvrcpControllerNativeInterface { 32 static final String TAG = AvrcpControllerNativeInterface.class.getSimpleName(); 33 34 private AvrcpControllerService mAvrcpController; 35 36 @GuardedBy("INSTANCE_LOCK") 37 private static AvrcpControllerNativeInterface sInstance; 38 39 private static final Object INSTANCE_LOCK = new Object(); 40 getInstance()41 static AvrcpControllerNativeInterface getInstance() { 42 synchronized (INSTANCE_LOCK) { 43 if (sInstance == null) { 44 sInstance = new AvrcpControllerNativeInterface(); 45 } 46 return sInstance; 47 } 48 } 49 50 /** Set singleton instance. */ 51 @VisibleForTesting setInstance(AvrcpControllerNativeInterface instance)52 public static void setInstance(AvrcpControllerNativeInterface instance) { 53 synchronized (INSTANCE_LOCK) { 54 sInstance = instance; 55 } 56 } 57 init(AvrcpControllerService controller)58 void init(AvrcpControllerService controller) { 59 mAvrcpController = controller; 60 initNative(); 61 } 62 cleanup()63 void cleanup() { 64 cleanupNative(); 65 } 66 sendPassThroughCommand(byte[] address, int keyCode, int keyState)67 boolean sendPassThroughCommand(byte[] address, int keyCode, int keyState) { 68 return sendPassThroughCommandNative(address, keyCode, keyState); 69 } 70 setPlayerApplicationSettingValues( byte[] address, byte numAttrib, byte[] attribIds, byte[] attribVal)71 void setPlayerApplicationSettingValues( 72 byte[] address, byte numAttrib, byte[] attribIds, byte[] attribVal) { 73 setPlayerApplicationSettingValuesNative(address, numAttrib, attribIds, attribVal); 74 } 75 sendAbsVolRsp(byte[] address, int absVol, int label)76 void sendAbsVolRsp(byte[] address, int absVol, int label) { 77 sendAbsVolRspNative(address, absVol, label); 78 } 79 sendRegisterAbsVolRsp(byte[] address, byte rspType, int absVol, int label)80 void sendRegisterAbsVolRsp(byte[] address, byte rspType, int absVol, int label) { 81 sendRegisterAbsVolRspNative(address, rspType, absVol, label); 82 } 83 getCurrentMetadata(byte[] address)84 void getCurrentMetadata(byte[] address) { 85 getCurrentMetadataNative(address); 86 } 87 getPlaybackState(byte[] address)88 void getPlaybackState(byte[] address) { 89 getPlaybackStateNative(address); 90 } 91 getNowPlayingList(byte[] address, int start, int end)92 void getNowPlayingList(byte[] address, int start, int end) { 93 getNowPlayingListNative(address, start, end); 94 } 95 getFolderList(byte[] address, int start, int end)96 void getFolderList(byte[] address, int start, int end) { 97 getFolderListNative(address, start, end); 98 } 99 getPlayerList(byte[] address, int start, int end)100 void getPlayerList(byte[] address, int start, int end) { 101 getPlayerListNative(address, start, end); 102 } 103 changeFolderPath(byte[] address, byte direction, long uid)104 void changeFolderPath(byte[] address, byte direction, long uid) { 105 changeFolderPathNative(address, direction, uid); 106 } 107 playItem(byte[] address, byte scope, long uid, int uidCounter)108 void playItem(byte[] address, byte scope, long uid, int uidCounter) { 109 playItemNative(address, scope, uid, uidCounter); 110 } 111 setBrowsedPlayer(byte[] address, int playerId)112 void setBrowsedPlayer(byte[] address, int playerId) { 113 setBrowsedPlayerNative(address, playerId); 114 } 115 116 /**********************************************************************************************/ 117 /*********************************** callbacks from native ************************************/ 118 /**********************************************************************************************/ 119 120 // Called by JNI when a device has connected or disconnected. onConnectionStateChanged( boolean remoteControlConnected, boolean browsingConnected, byte[] address)121 void onConnectionStateChanged( 122 boolean remoteControlConnected, boolean browsingConnected, byte[] address) { 123 BluetoothDevice device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(address); 124 Log.d( 125 TAG, 126 "onConnectionStateChanged: " 127 + (" remoteControlConnected=" + remoteControlConnected) 128 + (" browsingConnected=" + browsingConnected) 129 + (" device=" + device)); 130 131 mAvrcpController.onConnectionStateChanged( 132 remoteControlConnected, browsingConnected, device); 133 } 134 135 // Called by JNI to notify Avrcp of a remote device's Cover Art PSM 136 @VisibleForTesting getRcPsm(byte[] address, int psm)137 void getRcPsm(byte[] address, int psm) { 138 BluetoothDevice device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(address); 139 Log.d(TAG, "getRcPsm: device=" + device + " psm=" + psm); 140 141 mAvrcpController.getRcPsm(device, psm); 142 } 143 144 // Called by JNI to report remote Player's capabilities handlePlayerAppSetting(byte[] address, byte[] playerAttribRsp, int rspLen)145 void handlePlayerAppSetting(byte[] address, byte[] playerAttribRsp, int rspLen) { 146 BluetoothDevice device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(address); 147 Log.d(TAG, "handlePlayerAppSetting: device=" + device + " rspLen=" + rspLen); 148 149 mAvrcpController.handlePlayerAppSetting(device, playerAttribRsp, rspLen); 150 } 151 152 @VisibleForTesting onPlayerAppSettingChanged(byte[] address, byte[] playerAttribRsp, int rspLen)153 void onPlayerAppSettingChanged(byte[] address, byte[] playerAttribRsp, int rspLen) { 154 BluetoothDevice device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(address); 155 Log.d(TAG, "onPlayerAppSettingChanged: device=" + device); 156 157 mAvrcpController.onPlayerAppSettingChanged(device, playerAttribRsp, rspLen); 158 } 159 160 // Called by JNI when remote wants to set absolute volume. handleSetAbsVolume(byte[] address, byte absVol, byte label)161 void handleSetAbsVolume(byte[] address, byte absVol, byte label) { 162 BluetoothDevice device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(address); 163 Log.d(TAG, "handleSetAbsVolume: device=" + device); 164 165 mAvrcpController.handleSetAbsVolume(device, absVol, label); 166 } 167 168 // Called by JNI when remote wants to receive absolute volume notifications. handleRegisterNotificationAbsVol(byte[] address, byte label)169 void handleRegisterNotificationAbsVol(byte[] address, byte label) { 170 BluetoothDevice device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(address); 171 Log.d(TAG, "handleRegisterNotificationAbsVol: device=" + device); 172 173 mAvrcpController.handleRegisterNotificationAbsVol(device, label); 174 } 175 176 // Called by JNI when a track changes and local AvrcpController is registered for updates. onTrackChanged(byte[] address, byte numAttributes, int[] attributes, String[] attribVals)177 void onTrackChanged(byte[] address, byte numAttributes, int[] attributes, String[] attribVals) { 178 BluetoothDevice device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(address); 179 Log.d(TAG, "onTrackChanged: device=" + device); 180 181 mAvrcpController.onTrackChanged(device, numAttributes, attributes, attribVals); 182 } 183 184 // Called by JNI periodically based upon timer to update play position onPlayPositionChanged(byte[] address, int songLen, int currSongPosition)185 void onPlayPositionChanged(byte[] address, int songLen, int currSongPosition) { 186 BluetoothDevice device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(address); 187 Log.d(TAG, "onPlayPositionChanged: device=" + device + " pos=" + currSongPosition); 188 189 mAvrcpController.onPlayPositionChanged(device, songLen, currSongPosition); 190 } 191 192 // Called by JNI on changes of play status onPlayStatusChanged(byte[] address, byte playStatus)193 void onPlayStatusChanged(byte[] address, byte playStatus) { 194 BluetoothDevice device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(address); 195 Log.d(TAG, "onPlayStatusChanged: device=" + device + " playStatus=" + playStatus); 196 197 mAvrcpController.onPlayStatusChanged(device, toPlaybackStateFromJni(playStatus)); 198 } 199 200 // Browsing related JNI callbacks. handleGetFolderItemsRsp(byte[] address, int status, AvrcpItem[] items)201 void handleGetFolderItemsRsp(byte[] address, int status, AvrcpItem[] items) { 202 BluetoothDevice device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(address); 203 Log.d( 204 TAG, 205 "handleGetFolderItemsRsp:" 206 + (" device=" + device) 207 + (" status=" + status) 208 + (" NumberOfItems=" + items.length)); 209 210 mAvrcpController.handleGetFolderItemsRsp(device, status, items); 211 } 212 handleGetPlayerItemsRsp(byte[] address, AvrcpPlayer[] items)213 void handleGetPlayerItemsRsp(byte[] address, AvrcpPlayer[] items) { 214 BluetoothDevice device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(address); 215 Log.d( 216 TAG, 217 "handleGetFolderItemsRsp:" 218 + (" device=" + device) 219 + (" NumberOfItems=" + items.length)); 220 221 mAvrcpController.handleGetPlayerItemsRsp(device, Arrays.asList(items)); 222 } 223 224 // JNI Helper functions to convert native objects to java. createFromNativeMediaItem( byte[] address, long uid, int type, String name, int[] attrIds, String[] attrVals)225 static AvrcpItem createFromNativeMediaItem( 226 byte[] address, long uid, int type, String name, int[] attrIds, String[] attrVals) { 227 BluetoothDevice device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(address); 228 Log.d( 229 TAG, 230 "createFromNativeMediaItem:" 231 + (" device=" + device) 232 + (" uid=" + uid) 233 + (" type=" + type) 234 + (" name=" + name) 235 + (" attrids=" + Arrays.toString(attrIds)) 236 + (" attrVals=" + Arrays.toString(attrVals))); 237 238 return new AvrcpItem.Builder() 239 .fromAvrcpAttributeArray(attrIds, attrVals) 240 .setDevice(device) 241 .setItemType(AvrcpItem.TYPE_MEDIA) 242 .setType(type) 243 .setUid(uid) 244 .setUuid(UUID.randomUUID().toString()) 245 .setPlayable(true) 246 .build(); 247 } 248 createFromNativeFolderItem( byte[] address, long uid, int type, String name, int playable)249 static AvrcpItem createFromNativeFolderItem( 250 byte[] address, long uid, int type, String name, int playable) { 251 BluetoothDevice device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(address); 252 Log.d( 253 TAG, 254 "createFromNativeFolderItem:" 255 + (" device=" + device) 256 + (" uid=" + uid) 257 + (" type=" + type) 258 + (" name=" + name) 259 + (" playable=" + playable)); 260 261 return new AvrcpItem.Builder() 262 .setDevice(device) 263 .setItemType(AvrcpItem.TYPE_FOLDER) 264 .setType(type) 265 .setUid(uid) 266 .setUuid(UUID.randomUUID().toString()) 267 .setDisplayableName(name) 268 .setPlayable(playable == 0x01) 269 .setBrowsable(true) 270 .build(); 271 } 272 createFromNativePlayerItem( byte[] address, int id, String name, byte[] transportFlags, int playStatus, int playerType)273 static AvrcpPlayer createFromNativePlayerItem( 274 byte[] address, 275 int id, 276 String name, 277 byte[] transportFlags, 278 int playStatus, 279 int playerType) { 280 BluetoothDevice device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(address); 281 Log.d( 282 TAG, 283 "createFromNativePlayerItem:" 284 + (" device=" + device) 285 + (" name=" + name) 286 + (" transportFlags=" + Arrays.toString(transportFlags)) 287 + (" playStatus=" + playStatus) 288 + (" playerType=" + playerType)); 289 290 return new AvrcpPlayer.Builder() 291 .setDevice(device) 292 .setPlayerId(id) 293 .setSupportedFeatures(transportFlags) 294 .setName(name) 295 .setPlayStatus(toPlaybackStateFromJni(playStatus)) 296 .build(); 297 } 298 handleChangeFolderRsp(byte[] address, int count)299 void handleChangeFolderRsp(byte[] address, int count) { 300 BluetoothDevice device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(address); 301 Log.d(TAG, "handleChangeFolderRsp: device=" + device + " count=" + count); 302 303 mAvrcpController.handleChangeFolderRsp(device, count); 304 } 305 handleSetBrowsedPlayerRsp(byte[] address, int items, int depth)306 void handleSetBrowsedPlayerRsp(byte[] address, int items, int depth) { 307 BluetoothDevice device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(address); 308 Log.d(TAG, "handleSetBrowsedPlayerRsp: device=" + device + " depth=" + depth); 309 310 mAvrcpController.handleSetBrowsedPlayerRsp(device, items, depth); 311 } 312 handleSetAddressedPlayerRsp(byte[] address, int status)313 void handleSetAddressedPlayerRsp(byte[] address, int status) { 314 BluetoothDevice device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(address); 315 Log.d(TAG, "handleSetAddressedPlayerRsp device=" + device + " status=" + status); 316 317 mAvrcpController.handleSetAddressedPlayerRsp(device, status); 318 } 319 handleAddressedPlayerChanged(byte[] address, int id)320 void handleAddressedPlayerChanged(byte[] address, int id) { 321 BluetoothDevice device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(address); 322 Log.d(TAG, "handleAddressedPlayerChanged: device=" + device + " id=" + id); 323 324 mAvrcpController.handleAddressedPlayerChanged(device, id); 325 } 326 handleNowPlayingContentChanged(byte[] address)327 void handleNowPlayingContentChanged(byte[] address) { 328 BluetoothDevice device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(address); 329 Log.d(TAG, "handleNowPlayingContentChanged: device=" + device); 330 mAvrcpController.handleNowPlayingContentChanged(device); 331 } 332 onAvailablePlayerChanged(byte[] address)333 void onAvailablePlayerChanged(byte[] address) { 334 BluetoothDevice device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(address); 335 Log.d(TAG, "onAvailablePlayerChanged: device=" + device); 336 mAvrcpController.onAvailablePlayerChanged(device); 337 } 338 339 /* 340 * Play State Values from JNI 341 */ 342 private static final byte JNI_PLAY_STATUS_STOPPED = 0x00; 343 private static final byte JNI_PLAY_STATUS_PLAYING = 0x01; 344 private static final byte JNI_PLAY_STATUS_PAUSED = 0x02; 345 private static final byte JNI_PLAY_STATUS_FWD_SEEK = 0x03; 346 private static final byte JNI_PLAY_STATUS_REV_SEEK = 0x04; 347 toPlaybackStateFromJni(int fromJni)348 private static int toPlaybackStateFromJni(int fromJni) { 349 switch (fromJni) { 350 case JNI_PLAY_STATUS_STOPPED: 351 return PlaybackStateCompat.STATE_STOPPED; 352 case JNI_PLAY_STATUS_PLAYING: 353 return PlaybackStateCompat.STATE_PLAYING; 354 case JNI_PLAY_STATUS_PAUSED: 355 return PlaybackStateCompat.STATE_PAUSED; 356 case JNI_PLAY_STATUS_FWD_SEEK: 357 return PlaybackStateCompat.STATE_FAST_FORWARDING; 358 case JNI_PLAY_STATUS_REV_SEEK: 359 return PlaybackStateCompat.STATE_REWINDING; 360 default: 361 return PlaybackStateCompat.STATE_NONE; 362 } 363 } 364 365 /**********************************************************************************************/ 366 /******************************************* native *******************************************/ 367 /**********************************************************************************************/ 368 initNative()369 private native void initNative(); 370 cleanupNative()371 private native void cleanupNative(); 372 373 /** 374 * Send button press commands to addressed device 375 * 376 * @param keyCode key code as defined in AVRCP specification 377 * @param keyState 0 = key pressed, 1 = key released 378 * @return command was sent 379 */ sendPassThroughCommandNative(byte[] address, int keyCode, int keyState)380 private native boolean sendPassThroughCommandNative(byte[] address, int keyCode, int keyState); 381 382 /** 383 * TODO DELETE: This method is not used Send group navigation commands 384 * 385 * @param keyCode next/previous 386 * @param keyState state 387 * @return command was sent 388 */ sendGroupNavigationCommandNative( byte[] address, int keyCode, int keyState)389 private native boolean sendGroupNavigationCommandNative( 390 byte[] address, int keyCode, int keyState); 391 392 /** 393 * Change player specific settings such as shuffle 394 * 395 * @param numAttrib number of settings being sent 396 * @param attribIds list of settings to be changed 397 * @param attribVal list of settings values 398 */ setPlayerApplicationSettingValuesNative( byte[] address, byte numAttrib, byte[] attribIds, byte[] attribVal)399 private native void setPlayerApplicationSettingValuesNative( 400 byte[] address, byte numAttrib, byte[] attribIds, byte[] attribVal); 401 402 /** 403 * Send response to set absolute volume 404 * 405 * @param absVol new volume 406 * @param label label 407 */ sendAbsVolRspNative(byte[] address, int absVol, int label)408 private native void sendAbsVolRspNative(byte[] address, int absVol, int label); 409 410 /** 411 * Register for any volume level changes 412 * 413 * @param rspType type of response 414 * @param absVol current volume 415 * @param label label 416 */ sendRegisterAbsVolRspNative( byte[] address, byte rspType, int absVol, int label)417 private native void sendRegisterAbsVolRspNative( 418 byte[] address, byte rspType, int absVol, int label); 419 420 /** 421 * Fetch the current track's metadata 422 * 423 * <p>This method is specifically meant to allow us to fetch image handles that may not have 424 * been sent to us yet, prior to having a BIP client connection. See the AVRCP 1.6+ 425 * specification, section 4.1.7, for more details. 426 */ getCurrentMetadataNative(byte[] address)427 private native void getCurrentMetadataNative(byte[] address); 428 429 /** Fetch the playback state */ getPlaybackStateNative(byte[] address)430 private native void getPlaybackStateNative(byte[] address); 431 432 /** 433 * Fetch the current now playing list 434 * 435 * @param start first index to retrieve 436 * @param end last index to retrieve 437 */ getNowPlayingListNative(byte[] address, int start, int end)438 private native void getNowPlayingListNative(byte[] address, int start, int end); 439 440 /** 441 * Fetch the current folder's listing 442 * 443 * @param start first index to retrieve 444 * @param end last index to retrieve 445 */ getFolderListNative(byte[] address, int start, int end)446 private native void getFolderListNative(byte[] address, int start, int end); 447 448 /** 449 * Fetch the listing of players 450 * 451 * @param start first index to retrieve 452 * @param end last index to retrieve 453 */ getPlayerListNative(byte[] address, int start, int end)454 private native void getPlayerListNative(byte[] address, int start, int end); 455 456 /** 457 * Change the current browsed folder 458 * 459 * @param direction up/down 460 * @param uid folder unique id 461 */ changeFolderPathNative(byte[] address, byte direction, long uid)462 private native void changeFolderPathNative(byte[] address, byte direction, long uid); 463 464 /** 465 * Play item with provided uid 466 * 467 * @param scope scope of item to played 468 * @param uid song unique id 469 * @param uidCounter counter 470 */ playItemNative(byte[] address, byte scope, long uid, int uidCounter)471 private native void playItemNative(byte[] address, byte scope, long uid, int uidCounter); 472 473 /** 474 * Set a specific player for browsing 475 * 476 * @param playerId player number 477 */ setBrowsedPlayerNative(byte[] address, int playerId)478 private native void setBrowsedPlayerNative(byte[] address, int playerId); 479 480 /** 481 * TODO DELETE: This method is not used Set a specific player for handling playback commands 482 * 483 * @param playerId player number 484 */ setAddressedPlayerNative(byte[] address, int playerId)485 private native void setAddressedPlayerNative(byte[] address, int playerId); 486 } 487