1 /* 2 * Copyright (C) 2017 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.googlecode.android_scripting.facade.bluetooth; 18 19 import android.app.Service; 20 import android.bluetooth.BluetoothAdapter; 21 import android.bluetooth.BluetoothDevice; 22 import android.bluetooth.BluetoothHeadsetClient; 23 import android.bluetooth.BluetoothProfile; 24 import android.bluetooth.BluetoothUuid; 25 import android.os.ParcelUuid; 26 27 import com.googlecode.android_scripting.Log; 28 import com.googlecode.android_scripting.facade.FacadeManager; 29 import com.googlecode.android_scripting.jsonrpc.RpcReceiver; 30 import com.googlecode.android_scripting.rpc.Rpc; 31 import com.googlecode.android_scripting.rpc.RpcDefault; 32 import com.googlecode.android_scripting.rpc.RpcParameter; 33 34 import java.util.ArrayList; 35 import java.util.List; 36 37 public class BluetoothHfpClientFacade extends RpcReceiver { 38 static final ParcelUuid[] UUIDS = { 39 BluetoothUuid.HFP_AG, 40 }; 41 42 private final Service mService; 43 private final BluetoothAdapter mBluetoothAdapter; 44 45 private static boolean sIsHfpClientReady = false; 46 private static BluetoothHeadsetClient sHfpClientProfile = null; 47 BluetoothHfpClientFacade(FacadeManager manager)48 public BluetoothHfpClientFacade(FacadeManager manager) { 49 super(manager); 50 mService = manager.getService(); 51 mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); 52 mBluetoothAdapter.getProfileProxy(mService, 53 new HfpClientServiceListener(), 54 BluetoothProfile.HEADSET_CLIENT); 55 } 56 57 class HfpClientServiceListener implements BluetoothProfile.ServiceListener { 58 @Override onServiceConnected(int profile, BluetoothProfile proxy)59 public void onServiceConnected(int profile, BluetoothProfile proxy) { 60 sHfpClientProfile = (BluetoothHeadsetClient) proxy; 61 sIsHfpClientReady = true; 62 } 63 64 @Override onServiceDisconnected(int profile)65 public void onServiceDisconnected(int profile) { 66 sIsHfpClientReady = false; 67 } 68 } 69 70 /** 71 * Connect to HfpClient. 72 * @param device - the BluetoothDevice object to connect Hfp client. 73 * @return if the connection was successfull or not. 74 */ hfpClientConnect(BluetoothDevice device)75 public Boolean hfpClientConnect(BluetoothDevice device) { 76 if (sHfpClientProfile == null) return false; 77 return sHfpClientProfile.connect(device); 78 } 79 80 /** 81 * Disconnect from HfpClient. 82 * @param device - the BluetoothDevice object to disconnect from Hfp client. 83 * @return if the disconnection was successfull or not. 84 */ hfpClientDisconnect(BluetoothDevice device)85 public Boolean hfpClientDisconnect(BluetoothDevice device) { 86 if (sHfpClientProfile == null) return false; 87 return sHfpClientProfile.disconnect(device); 88 } 89 90 /** 91 * Is Hfp Client profile ready. 92 * @return Hfp Client profile is ready or not. 93 */ 94 @Rpc(description = "Is HfpClient profile ready.") bluetoothHfpClientIsReady()95 public Boolean bluetoothHfpClientIsReady() { 96 return sIsHfpClientReady; 97 } 98 99 /** 100 * Set priority of the profile. 101 * @param deviceStr - Mac address of a BT device. 102 * @param priority - Priority that needs to be set. 103 */ 104 @Rpc(description = "Set priority of the profile") bluetoothHfpClientSetPriority( @pcParametername = "device", description = "Mac address of a BT device.") String deviceStr, @RpcParameter(name = "priority", description = "Priority that needs to be set.") Integer priority)105 public void bluetoothHfpClientSetPriority( 106 @RpcParameter(name = "device", 107 description = "Mac address of a BT device.") String deviceStr, 108 @RpcParameter(name = "priority", 109 description = "Priority that needs to be set.") 110 Integer priority) throws Exception { 111 if (sHfpClientProfile == null) return; 112 BluetoothDevice device = 113 BluetoothFacade.getDevice(mBluetoothAdapter.getBondedDevices(), 114 deviceStr); 115 Log.d("Changing priority of device " + device.getAlias() 116 + " p: " + priority); 117 sHfpClientProfile.setPriority(device, priority); 118 } 119 120 /** 121 * Get priority of the profile. 122 * @param deviceStr - Mac address of a BT device. 123 * @return Priority of the device. 124 */ 125 @Rpc(description = "Get priority of the profile") bluetoothHfpClientGetPriority( @pcParametername = "device", description = "Mac address of a BT device.") String deviceStr)126 public Integer bluetoothHfpClientGetPriority( 127 @RpcParameter(name = "device", description = 128 "Mac address of a BT device.") String deviceStr) 129 throws Exception { 130 if (sHfpClientProfile == null) return BluetoothProfile.PRIORITY_UNDEFINED; 131 BluetoothDevice device = BluetoothFacade.getDevice( 132 mBluetoothAdapter.getBondedDevices(), deviceStr); 133 return sHfpClientProfile.getPriority(device); 134 } 135 136 /** 137 * Connect to an HFP Client device. 138 * @param deviceStr - Name or MAC address of a bluetooth device. 139 * @return Hfp Client was connected or not. 140 */ 141 @Rpc(description = "Connect to an HFP Client device.") bluetoothHfpClientConnect( @pcParametername = "device", description = "Name or MAC address of a bluetooth device.") String deviceStr)142 public Boolean bluetoothHfpClientConnect( 143 @RpcParameter(name = "device", 144 description = "Name or MAC address of a bluetooth device.") 145 String deviceStr) 146 throws Exception { 147 if (sHfpClientProfile == null) return false; 148 try { 149 BluetoothDevice device = BluetoothFacade.getDevice( 150 BluetoothFacade.DiscoveredDevices, deviceStr); 151 Log.d("Connecting to device " + device.getAlias()); 152 return hfpClientConnect(device); 153 } catch (Exception e) { 154 Log.e("bluetoothHfpClientConnect failed on getDevice " 155 + deviceStr + " with " + e); 156 return false; 157 } 158 } 159 160 /** 161 * Disconnect an HFP Client device. 162 * @param deviceStr - Name or MAC address of a bluetooth device. 163 * @return Hfp Client was disconnected or not. 164 */ 165 @Rpc(description = "Disconnect an HFP Client device.") bluetoothHfpClientDisconnect( @pcParametername = "device", description = "Name or MAC address of a device.") String deviceStr)166 public Boolean bluetoothHfpClientDisconnect( 167 @RpcParameter(name = "device", 168 description = "Name or MAC address of a device.") 169 String deviceStr) { 170 if (sHfpClientProfile == null) return false; 171 Log.d("Connected devices: " + sHfpClientProfile.getConnectedDevices()); 172 try { 173 BluetoothDevice device = BluetoothFacade.getDevice( 174 sHfpClientProfile.getConnectedDevices(), deviceStr); 175 return hfpClientDisconnect(device); 176 } catch (Exception e) { 177 // Do nothing since it is disconnect and this 178 // function should force disconnect. 179 Log.e("bluetoothHfpClientConnect getDevice failed " + e); 180 } 181 return false; 182 } 183 184 /** 185 * Get all the devices connected through HFP Client. 186 * @return List of all the devices connected through HFP Client. 187 */ 188 @Rpc(description = "Get all the devices connected through HFP Client.") bluetoothHfpClientGetConnectedDevices()189 public List<BluetoothDevice> bluetoothHfpClientGetConnectedDevices() { 190 if (sHfpClientProfile == null) return new ArrayList<BluetoothDevice>(); 191 return sHfpClientProfile.getConnectedDevices(); 192 } 193 194 /** 195 * Get the connection status of a device. 196 * @param deviceID - Name or MAC address of a bluetooth device. 197 * @return connection status of the device. 198 */ 199 @Rpc(description = "Get the connection status of a device.") bluetoothHfpClientGetConnectionStatus( @pcParametername = "deviceID", description = "Name or MAC address of a bluetooth device.") String deviceID)200 public Integer bluetoothHfpClientGetConnectionStatus( 201 @RpcParameter(name = "deviceID", 202 description = "Name or MAC address of a bluetooth device.") 203 String deviceID) { 204 if (sHfpClientProfile == null) { 205 return BluetoothProfile.STATE_DISCONNECTED; 206 } 207 List<BluetoothDevice> deviceList = 208 sHfpClientProfile.getConnectedDevices(); 209 BluetoothDevice device; 210 try { 211 device = BluetoothFacade.getDevice(deviceList, deviceID); 212 } catch (Exception e) { 213 Log.e(e); 214 return BluetoothProfile.STATE_DISCONNECTED; 215 } 216 return sHfpClientProfile.getConnectionState(device); 217 } 218 219 /** 220 * Get the audio routing state of specified device. 221 * @param deviceStr the Bluetooth MAC address of remote device 222 * @return Audio State of the device. 223 */ 224 @Rpc(description = "Get all the devices connected through HFP Client.") bluetoothHfpClientGetAudioState( @pcParametername = "device", description = "MAC address of a bluetooth device.") String deviceStr)225 public Integer bluetoothHfpClientGetAudioState( 226 @RpcParameter(name = "device", 227 description = "MAC address of a bluetooth device.") 228 String deviceStr) { 229 if (sHfpClientProfile == null) return -1; 230 BluetoothDevice device; 231 try { 232 device = BluetoothFacade.getDevice(sHfpClientProfile.getConnectedDevices(), deviceStr); 233 } catch (Exception e) { 234 // Do nothing since it is disconnect and this function should force disconnect. 235 Log.e("bluetoothHfpClientConnect getDevice failed " + e); 236 return -1; 237 } 238 return sHfpClientProfile.getAudioState(device); 239 } 240 getDevice(String deviceStr)241 private BluetoothDevice getDevice(String deviceStr) { 242 if (sHfpClientProfile == null) return null; 243 BluetoothDevice device; 244 try { 245 device = BluetoothFacade.getDevice(sHfpClientProfile.getConnectedDevices(), deviceStr); 246 } catch (Exception e) { 247 // Do nothing since it is disconnect and this function should force disconnect. 248 Log.e("bluetoothHfpClientConnect getDevice failed " + e); 249 return null; 250 } 251 return device; 252 } 253 254 /** 255 * Starts Voice Recognition on remote device 256 * 257 * @param deviceStr the Bluetooth MAC address of remote device 258 * @return True if command has been issued successfully 259 */ 260 @Rpc(description = "Start Remote device Voice Recognition through HFP Client.") bluetoothHfpClientStartVoiceRecognition( @pcParametername = "device", description = "MAC address of a bluetooth device.") String deviceStr)261 public boolean bluetoothHfpClientStartVoiceRecognition( 262 @RpcParameter(name = "device", 263 description = "MAC address of a bluetooth device.") 264 String deviceStr) { 265 BluetoothDevice device = getDevice(deviceStr); 266 if (device == null) return false; 267 return sHfpClientProfile.startVoiceRecognition(device); 268 } 269 270 /** 271 * Stops Voice Recognition in the remote device through Bluetooth HFP client 272 * 273 * @param deviceStr the Bluetooth MAC address of remote device 274 * @return True if command has been issued successfully 275 */ 276 @Rpc(description = "Stops Remote device Voice Recognition through HFP Client.") bluetoothHfpClientStopVoiceRecognition( @pcParametername = "device", description = "MAC address of a bluetooth device.") String deviceStr)277 public boolean bluetoothHfpClientStopVoiceRecognition( 278 @RpcParameter(name = "device", 279 description = "MAC address of a bluetooth device.") 280 String deviceStr) { 281 BluetoothDevice device = getDevice(deviceStr); 282 if (device == null) return false; 283 return sHfpClientProfile.stopVoiceRecognition(device); 284 } 285 286 /** 287 * Initiates a connection of audio channel. 288 * 289 * It setup SCO channel with remote connected Handsfree Audio Gateway device. 290 * 291 * @param deviceStr the Bluetooth MAC address of remote device 292 * @return True if command has been issued successfully 293 */ 294 @Rpc(description = "Initiates a connection of audio channel.") bluetoothHfpClientConnectAudio( @pcParametername = "device", description = "MAC address of a bluetooth device.") String deviceStr)295 public boolean bluetoothHfpClientConnectAudio( 296 @RpcParameter(name = "device", 297 description = "MAC address of a bluetooth device.") 298 String deviceStr) { 299 BluetoothDevice device = getDevice(deviceStr); 300 if (device == null) return false; 301 return sHfpClientProfile.connectAudio(device); 302 } 303 304 /** 305 * Dials a call in the remote device through Bluetooth HFP Client 306 * 307 * The last number dial will be placed if the number is an empty string 308 * 309 * @param deviceStr the Bluetooth MAC address of remote device 310 * @param number phone number to dial, the value of null or empty string for last number redial 311 * @return The string of <code>{@link BluetoothHeadsetClientCall} call</code> or null if no 312 * device was not found. 313 */ 314 @Rpc(description = "Dials a call in the remote device through HFP Client.") bluetoothHfpClientDial( @pcParametername = "device", description = "MAC address of a bluetooth device.") String deviceStr, @RpcParameter(name = "phone_number", description = "phone number to dial, default for last number redial") @RpcDefault("") String number)315 public String bluetoothHfpClientDial( 316 @RpcParameter(name = "device", 317 description = "MAC address of a bluetooth device.") String deviceStr, 318 @RpcParameter(name = "phone_number", description = 319 "phone number to dial, default for last number redial") 320 @RpcDefault("") String number) { 321 BluetoothDevice device = getDevice(deviceStr); 322 if (device == null) return null; 323 return sHfpClientProfile.dial(device, number).toString(true); 324 } 325 326 /** 327 * Disconnects audio channel. 328 * 329 * It tears down the SCO channel from remote AuG device. 330 * 331 * @param deviceStr the Bluetooth MAC address of remote device 332 * @return True if command has been issued successfully 333 */ 334 @Rpc(description = "Disconnects audio channel.") bluetoothHfpClientDisconnectAudio( @pcParametername = "device", description = "MAC address of a bluetooth device.") String deviceStr)335 public boolean bluetoothHfpClientDisconnectAudio( 336 @RpcParameter(name = "device", 337 description = "MAC address of a bluetooth device.") 338 String deviceStr) { 339 BluetoothDevice device = getDevice(deviceStr); 340 if (device == null) return false; 341 return sHfpClientProfile.disconnectAudio(device); 342 } 343 344 /** 345 * Accepts a call in the remote device through Bluetooth HFP Client 346 * 347 * @param deviceStr the Bluetooth MAC address of remote device 348 * @return True if command has been issued successfully 349 */ 350 @Rpc(description = "Accepts a call in the remote device through HFP Client.") bluetoothHfpClientAcceptCall( @pcParametername = "device", description = "MAC address of a bluetooth device.") String deviceStr)351 public boolean bluetoothHfpClientAcceptCall( 352 @RpcParameter(name = "device", 353 description = "MAC address of a bluetooth device.") 354 String deviceStr) { 355 BluetoothDevice device = getDevice(deviceStr); 356 if (device == null) return false; 357 return sHfpClientProfile.acceptCall(device, BluetoothHeadsetClient.CALL_ACCEPT_NONE); 358 } 359 360 /** 361 * Terminates all calls in the remote device through Bluetooth HFP Client 362 * 363 * @param deviceStr the Bluetooth MAC address of remote device 364 * @return True if command has been issued successfully 365 */ 366 @Rpc(description = "Terminates all calls in the remote device through HFP Client.") bluetoothHfpClientTerminateAllCalls( @pcParametername = "device", description = "MAC address of a bluetooth device.") String deviceStr)367 public boolean bluetoothHfpClientTerminateAllCalls( 368 @RpcParameter(name = "device", 369 description = "MAC address of a bluetooth device.") 370 String deviceStr) { 371 BluetoothDevice device = getDevice(deviceStr); 372 if (device == null) return false; 373 return sHfpClientProfile.terminateCall(device, null); 374 } 375 376 /** 377 * Rejects a call in the remote device through Bluetooth HFP Client 378 * 379 * @param deviceStr the Bluetooth MAC address of remote device 380 * @return True if command has been issued successfully 381 */ 382 @Rpc(description = "Rejects a call in the remote device through HFP Client.") bluetoothHfpClientRejectCall( @pcParametername = "device", description = "MAC address of a bluetooth device.") String deviceStr)383 public boolean bluetoothHfpClientRejectCall( 384 @RpcParameter(name = "device", 385 description = "MAC address of a bluetooth device.") 386 String deviceStr) { 387 BluetoothDevice device = getDevice(deviceStr); 388 if (device == null) return false; 389 return sHfpClientProfile.rejectCall(device); 390 } 391 392 @Override shutdown()393 public void shutdown() { 394 } 395 }