1 /* 2 * Copyright 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 package com.android.bluetooth.avrcp; 18 19 import android.annotation.RequiresPermission; 20 import android.bluetooth.BluetoothAdapter; 21 import android.bluetooth.BluetoothDevice; 22 import android.util.Log; 23 24 import com.android.bluetooth.audio_util.ListItem; 25 import com.android.bluetooth.audio_util.Metadata; 26 import com.android.bluetooth.audio_util.PlayStatus; 27 import com.android.bluetooth.audio_util.PlayerInfo; 28 29 import java.util.List; 30 31 /** 32 * Native Interface to communicate with the JNI layer. This class should never be passed null 33 * data. 34 */ 35 public class AvrcpNativeInterface { 36 private static final String TAG = "AvrcpNativeInterface"; 37 private static final boolean DEBUG = true; 38 39 private static AvrcpNativeInterface sInstance; 40 private AvrcpTargetService mAvrcpService; 41 42 static { classInitNative()43 classInitNative(); 44 } 45 getInterface()46 static AvrcpNativeInterface getInterface() { 47 if (sInstance == null) { 48 sInstance = new AvrcpNativeInterface(); 49 } 50 51 return sInstance; 52 } 53 init(AvrcpTargetService service)54 void init(AvrcpTargetService service) { 55 d("Init AvrcpNativeInterface"); 56 mAvrcpService = service; 57 initNative(); 58 } 59 cleanup()60 void cleanup() { 61 d("Cleanup AvrcpNativeInterface"); 62 mAvrcpService = null; 63 cleanupNative(); 64 } 65 registerBipServer(int l2capPsm)66 void registerBipServer(int l2capPsm) { 67 d("Register our BIP server at psm=" + l2capPsm); 68 registerBipServerNative(l2capPsm); 69 } 70 unregisterBipServer()71 void unregisterBipServer() { 72 d("Unregister any BIP server"); 73 unregisterBipServerNative(); 74 } 75 setBipClientStatus(String bdaddr, boolean connected)76 void setBipClientStatus(String bdaddr, boolean connected) { 77 setBipClientStatusNative(bdaddr, connected); 78 } 79 getCurrentSongInfo()80 Metadata getCurrentSongInfo() { 81 d("getCurrentSongInfo"); 82 if (mAvrcpService == null) { 83 Log.w(TAG, "getCurrentSongInfo(): AvrcpTargetService is null"); 84 return null; 85 } 86 87 return mAvrcpService.getCurrentSongInfo(); 88 } 89 getPlayStatus()90 PlayStatus getPlayStatus() { 91 d("getPlayStatus"); 92 if (mAvrcpService == null) { 93 Log.w(TAG, "getPlayStatus(): AvrcpTargetService is null"); 94 return null; 95 } 96 97 return mAvrcpService.getPlayState(); 98 } 99 sendMediaKeyEvent(int keyEvent, boolean pushed)100 void sendMediaKeyEvent(int keyEvent, boolean pushed) { 101 d("sendMediaKeyEvent: keyEvent=" + keyEvent + " pushed=" + pushed); 102 if (mAvrcpService == null) { 103 Log.w(TAG, "sendMediaKeyEvent(): AvrcpTargetService is null"); 104 return; 105 } 106 107 mAvrcpService.sendMediaKeyEvent(keyEvent, pushed); 108 } 109 getCurrentMediaId()110 String getCurrentMediaId() { 111 d("getCurrentMediaId"); 112 if (mAvrcpService == null) { 113 Log.w(TAG, "getMediaPlayerList(): AvrcpTargetService is null"); 114 return ""; 115 } 116 117 return mAvrcpService.getCurrentMediaId(); 118 } 119 getNowPlayingList()120 List<Metadata> getNowPlayingList() { 121 d("getNowPlayingList"); 122 if (mAvrcpService == null) { 123 Log.w(TAG, "getMediaPlayerList(): AvrcpTargetService is null"); 124 return null; 125 } 126 127 return mAvrcpService.getNowPlayingList(); 128 } 129 getCurrentPlayerId()130 int getCurrentPlayerId() { 131 d("getCurrentPlayerId"); 132 if (mAvrcpService == null) { 133 Log.w(TAG, "getMediaPlayerList(): AvrcpTargetService is null"); 134 return -1; 135 } 136 137 return mAvrcpService.getCurrentPlayerId(); 138 } 139 getMediaPlayerList()140 List<PlayerInfo> getMediaPlayerList() { 141 d("getMediaPlayerList"); 142 if (mAvrcpService == null) { 143 Log.w(TAG, "getMediaPlayerList(): AvrcpTargetService is null"); 144 return null; 145 } 146 147 return mAvrcpService.getMediaPlayerList(); 148 } 149 150 // TODO(apanicke): This shouldn't be named setBrowsedPlayer as it doesn't actually connect 151 // anything internally. It just returns the number of items in the root folder. setBrowsedPlayer(int playerId)152 void setBrowsedPlayer(int playerId) { 153 d("setBrowsedPlayer: playerId=" + playerId); 154 mAvrcpService.getPlayerRoot(playerId, (a, b, c, d) -> 155 setBrowsedPlayerResponse(a, b, c, d)); 156 } 157 setBrowsedPlayerResponse(int playerId, boolean success, String rootId, int numItems)158 void setBrowsedPlayerResponse(int playerId, boolean success, String rootId, int numItems) { 159 d("setBrowsedPlayerResponse: playerId=" + playerId 160 + " success=" + success 161 + " rootId=" + rootId 162 + " numItems=" + numItems); 163 setBrowsedPlayerResponseNative(playerId, success, rootId, numItems); 164 } 165 getFolderItemsRequest(int playerId, String mediaId)166 void getFolderItemsRequest(int playerId, String mediaId) { 167 d("getFolderItemsRequest: playerId=" + playerId + " mediaId=" + mediaId); 168 mAvrcpService.getFolderItems(playerId, mediaId, (a, b) -> getFolderItemsResponse(a, b)); 169 } 170 getFolderItemsResponse(String parentId, List<ListItem> items)171 void getFolderItemsResponse(String parentId, List<ListItem> items) { 172 d("getFolderItemsResponse: parentId=" + parentId + " items.size=" + items.size()); 173 getFolderItemsResponseNative(parentId, items); 174 } 175 sendMediaUpdate(boolean metadata, boolean playStatus, boolean queue)176 void sendMediaUpdate(boolean metadata, boolean playStatus, boolean queue) { 177 d("sendMediaUpdate: metadata=" + metadata 178 + " playStatus=" + playStatus 179 + " queue=" + queue); 180 sendMediaUpdateNative(metadata, playStatus, queue); 181 } 182 sendFolderUpdate(boolean availablePlayers, boolean addressedPlayers, boolean uids)183 void sendFolderUpdate(boolean availablePlayers, boolean addressedPlayers, boolean uids) { 184 d("sendFolderUpdate: availablePlayers=" + availablePlayers 185 + " addressedPlayers=" + addressedPlayers 186 + " uids=" + uids); 187 sendFolderUpdateNative(availablePlayers, addressedPlayers, uids); 188 } 189 playItem(int playerId, boolean nowPlaying, String mediaId)190 void playItem(int playerId, boolean nowPlaying, String mediaId) { 191 d("playItem: playerId=" + playerId + " nowPlaying=" + nowPlaying + " mediaId" + mediaId); 192 if (mAvrcpService == null) { 193 Log.d(TAG, "playItem: AvrcpTargetService is null"); 194 return; 195 } 196 197 mAvrcpService.playItem(playerId, nowPlaying, mediaId); 198 } 199 connectDevice(String bdaddr)200 boolean connectDevice(String bdaddr) { 201 d("connectDevice: bdaddr=" + bdaddr); 202 return connectDeviceNative(bdaddr); 203 } 204 disconnectDevice(String bdaddr)205 boolean disconnectDevice(String bdaddr) { 206 d("disconnectDevice: bdaddr=" + bdaddr); 207 return disconnectDeviceNative(bdaddr); 208 } 209 setActiveDevice(String bdaddr)210 void setActiveDevice(String bdaddr) { 211 BluetoothDevice device = 212 BluetoothAdapter.getDefaultAdapter().getRemoteDevice(bdaddr.toUpperCase()); 213 d("setActiveDevice: device=" + device); 214 mAvrcpService.setActiveDevice(device); 215 } 216 deviceConnected(String bdaddr, boolean absoluteVolume)217 void deviceConnected(String bdaddr, boolean absoluteVolume) { 218 BluetoothDevice device = 219 BluetoothAdapter.getDefaultAdapter().getRemoteDevice(bdaddr.toUpperCase()); 220 d("deviceConnected: device=" + device + " absoluteVolume=" + absoluteVolume); 221 if (mAvrcpService == null) { 222 Log.w(TAG, "deviceConnected: AvrcpTargetService is null"); 223 return; 224 } 225 226 mAvrcpService.deviceConnected(device, absoluteVolume); 227 } 228 deviceDisconnected(String bdaddr)229 void deviceDisconnected(String bdaddr) { 230 BluetoothDevice device = 231 BluetoothAdapter.getDefaultAdapter().getRemoteDevice(bdaddr.toUpperCase()); 232 d("deviceDisconnected: device=" + device); 233 if (mAvrcpService == null) { 234 Log.w(TAG, "deviceDisconnected: AvrcpTargetService is null"); 235 return; 236 } 237 238 mAvrcpService.deviceDisconnected(device); 239 } 240 sendVolumeChanged(String bdaddr, int volume)241 void sendVolumeChanged(String bdaddr, int volume) { 242 d("sendVolumeChanged: volume=" + volume); 243 sendVolumeChangedNative(bdaddr, volume); 244 } 245 setVolume(int volume)246 void setVolume(int volume) { 247 d("setVolume: volume=" + volume); 248 if (mAvrcpService == null) { 249 Log.w(TAG, "setVolume: AvrcpTargetService is null"); 250 return; 251 } 252 253 mAvrcpService.setVolume(volume); 254 } 255 classInitNative()256 private static native void classInitNative(); initNative()257 private native void initNative(); registerBipServerNative(int l2capPsm)258 private native void registerBipServerNative(int l2capPsm); unregisterBipServerNative()259 private native void unregisterBipServerNative(); sendMediaUpdateNative( boolean trackChanged, boolean playState, boolean playPos)260 private native void sendMediaUpdateNative( 261 boolean trackChanged, boolean playState, boolean playPos); sendFolderUpdateNative( boolean availablePlayers, boolean addressedPlayers, boolean uids)262 private native void sendFolderUpdateNative( 263 boolean availablePlayers, boolean addressedPlayers, boolean uids); setBrowsedPlayerResponseNative( int playerId, boolean success, String rootId, int numItems)264 private native void setBrowsedPlayerResponseNative( 265 int playerId, boolean success, String rootId, int numItems); getFolderItemsResponseNative(String parentId, List<ListItem> list)266 private native void getFolderItemsResponseNative(String parentId, List<ListItem> list); cleanupNative()267 private native void cleanupNative(); connectDeviceNative(String bdaddr)268 private native boolean connectDeviceNative(String bdaddr); disconnectDeviceNative(String bdaddr)269 private native boolean disconnectDeviceNative(String bdaddr); sendVolumeChangedNative(String bdaddr, int volume)270 private native void sendVolumeChangedNative(String bdaddr, int volume); setBipClientStatusNative(String bdaddr, boolean connected)271 private native void setBipClientStatusNative(String bdaddr, boolean connected); 272 d(String msg)273 private static void d(String msg) { 274 if (DEBUG) { 275 Log.d(TAG, msg); 276 } 277 } 278 } 279