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.BluetoothHeadset; 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.RpcParameter; 32 33 import java.util.List; 34 35 public class BluetoothHspFacade extends RpcReceiver { 36 static final ParcelUuid[] UUIDS = { 37 BluetoothUuid.HSP, BluetoothUuid.Handsfree 38 }; 39 40 private final Service mService; 41 private final BluetoothAdapter mBluetoothAdapter; 42 43 private static boolean sIsHspReady = false; 44 private static BluetoothHeadset sHspProfile = null; 45 BluetoothHspFacade(FacadeManager manager)46 public BluetoothHspFacade(FacadeManager manager) { 47 super(manager); 48 mService = manager.getService(); 49 mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); 50 mBluetoothAdapter.getProfileProxy(mService, new HspServiceListener(), 51 BluetoothProfile.HEADSET); 52 } 53 54 class HspServiceListener implements BluetoothProfile.ServiceListener { 55 @Override onServiceConnected(int profile, BluetoothProfile proxy)56 public void onServiceConnected(int profile, BluetoothProfile proxy) { 57 sHspProfile = (BluetoothHeadset) proxy; 58 sIsHspReady = true; 59 } 60 61 @Override onServiceDisconnected(int profile)62 public void onServiceDisconnected(int profile) { 63 sIsHspReady = false; 64 } 65 } 66 hspConnect(BluetoothDevice device)67 public Boolean hspConnect(BluetoothDevice device) { 68 if (sHspProfile == null) return false; 69 return sHspProfile.connect(device); 70 } 71 hspDisconnect(BluetoothDevice device)72 public Boolean hspDisconnect(BluetoothDevice device) { 73 if (sHspProfile == null) return false; 74 return sHspProfile.disconnect(device); 75 } 76 77 @Rpc(description = "Is Hsp profile ready.") bluetoothHspIsReady()78 public Boolean bluetoothHspIsReady() { 79 return sIsHspReady; 80 } 81 82 @Rpc(description = "Set priority of the profile") bluetoothHspSetPriority( @pcParametername = "device", description = "Mac address of a BT device.") String deviceStr, @RpcParameter(name = "priority", description = "Priority that needs to be set.") Integer priority)83 public void bluetoothHspSetPriority( 84 @RpcParameter(name = "device", description = "Mac address of a BT device.") 85 String deviceStr, 86 @RpcParameter(name = "priority", description = "Priority that needs to be set.") 87 Integer priority) 88 throws Exception { 89 if (sHspProfile == null) return; 90 BluetoothDevice device = 91 BluetoothFacade.getDevice(mBluetoothAdapter.getBondedDevices(), deviceStr); 92 Log.d("Changing priority of device " + device.getAliasName() + " p: " + priority); 93 sHspProfile.setPriority(device, priority); 94 } 95 96 @Rpc(description = "Connect to an HSP device.") bluetoothHspConnect( @pcParametername = "device", description = "Name or MAC address of a bluetooth device.") String device)97 public Boolean bluetoothHspConnect( 98 @RpcParameter(name = "device", description = "Name or MAC address of a bluetooth device.") 99 String device) 100 throws Exception { 101 if (sHspProfile == null) 102 return false; 103 BluetoothDevice mDevice = BluetoothFacade.getDevice(BluetoothFacade.DiscoveredDevices, device); 104 Log.d("Connecting to device " + mDevice.getAliasName()); 105 return hspConnect(mDevice); 106 } 107 108 @Rpc(description = "Disconnect an HSP device.") bluetoothHspDisconnect( @pcParametername = "device", description = "Name or MAC address of a device.") String device)109 public Boolean bluetoothHspDisconnect( 110 @RpcParameter(name = "device", description = "Name or MAC address of a device.") 111 String device) 112 throws Exception { 113 if (sHspProfile == null) 114 return false; 115 Log.d("Connected devices: " + sHspProfile.getConnectedDevices()); 116 BluetoothDevice mDevice = BluetoothFacade.getDevice(sHspProfile.getConnectedDevices(), 117 device); 118 return hspDisconnect(mDevice); 119 } 120 121 @Rpc(description = "Get all the devices connected through HSP.") bluetoothHspGetConnectedDevices()122 public List<BluetoothDevice> bluetoothHspGetConnectedDevices() { 123 while (!sIsHspReady); 124 return sHspProfile.getConnectedDevices(); 125 } 126 127 @Rpc(description = "Get the connection status of a device.") bluetoothHspGetConnectionStatus( @pcParametername = "deviceID", description = "Name or MAC address of a bluetooth device.") String deviceID)128 public Integer bluetoothHspGetConnectionStatus( 129 @RpcParameter(name = "deviceID", 130 description = "Name or MAC address of a bluetooth device.") 131 String deviceID) { 132 if (sHspProfile == null) { 133 return BluetoothProfile.STATE_DISCONNECTED; 134 } 135 List<BluetoothDevice> deviceList = sHspProfile.getConnectedDevices(); 136 BluetoothDevice device; 137 try { 138 device = BluetoothFacade.getDevice(deviceList, deviceID); 139 } catch (Exception e) { 140 return BluetoothProfile.STATE_DISCONNECTED; 141 } 142 return sHspProfile.getConnectionState(device); 143 } 144 145 /** 146 * Force SCO audio on DUT, ignore all other restrictions 147 * 148 * @param force True to force SCO audio, False to resume normal 149 * @return True if the setup is successful 150 */ 151 @Rpc(description = "Force SCO audio connection on DUT") bluetoothHspForceScoAudio( @pcParametername = "force", description = "whether to force SCO audio") Boolean force)152 public Boolean bluetoothHspForceScoAudio( 153 @RpcParameter(name = "force", description = "whether to force SCO audio") 154 Boolean force) { 155 if (sHspProfile == null) { 156 return false; 157 } 158 sHspProfile.setForceScoAudio(force); 159 return true; 160 } 161 162 /** 163 * Connect SCO audio to a remote device 164 * 165 * @param deviceAddress the Bluetooth MAC address of remote device 166 * @return True if connection is successful, False otherwise 167 */ 168 @Rpc(description = "Connect SCO audio for a remote device") bluetoothHspConnectAudio( @pcParametername = "deviceAddress", description = "MAC address of a bluetooth device.") String deviceAddress)169 public Boolean bluetoothHspConnectAudio( 170 @RpcParameter(name = "deviceAddress", description = "MAC address of a bluetooth device.") 171 String deviceAddress) { 172 if (sHspProfile == null) { 173 return false; 174 } 175 Log.d("Connected devices: " + sHspProfile.getConnectedDevices()); 176 BluetoothDevice device = null; 177 if (sHspProfile.getConnectedDevices().size() > 1) { 178 Log.d("More than one device available"); 179 } 180 try { 181 device = BluetoothFacade.getDevice(sHspProfile.getConnectedDevices(), deviceAddress); 182 } catch (Exception e) { 183 Log.d("Cannot find device " + deviceAddress); 184 return false; 185 } 186 return sHspProfile.connectAudio(); 187 } 188 189 /** 190 * Disconnect SCO audio for a remote device 191 * 192 * @param deviceAddress the Bluetooth MAC address of remote device 193 * @return True if disconnection is successful, False otherwise 194 */ 195 @Rpc(description = "Disconnect SCO audio for a remote device") bluetoothHspDisconnectAudio( @pcParametername = "deviceAddress", description = "MAC address of a bluetooth device.") String deviceAddress)196 public Boolean bluetoothHspDisconnectAudio( 197 @RpcParameter(name = "deviceAddress", description = "MAC address of a bluetooth device.") 198 String deviceAddress) { 199 if (sHspProfile == null) { 200 return false; 201 } 202 Log.d("Connected devices: " + sHspProfile.getConnectedDevices()); 203 BluetoothDevice device = null; 204 if (sHspProfile.getConnectedDevices().size() > 1) { 205 Log.d("More than one device available"); 206 } 207 try { 208 device = BluetoothFacade.getDevice(sHspProfile.getConnectedDevices(), deviceAddress); 209 } catch (Exception e) { 210 Log.d("Cannot find device " + deviceAddress); 211 return false; 212 } 213 if (!sHspProfile.isAudioConnected(device)) { 214 Log.d("SCO audio is not connected for device " + deviceAddress); 215 return false; 216 } 217 return sHspProfile.disconnectAudio(); 218 } 219 220 /** 221 * Check if SCO audio is connected for a remote device 222 * 223 * @param deviceAddress the Bluetooth MAC address of remote device 224 * @return True if device is connected to us via SCO audio, False otherwise 225 */ 226 @Rpc(description = "Check if SCO audio is connected for a remote device") bluetoothHspIsAudioConnected( @pcParametername = "deviceAddress", description = "MAC address of a bluetooth device.") String deviceAddress)227 public Boolean bluetoothHspIsAudioConnected( 228 @RpcParameter(name = "deviceAddress", description = "MAC address of a bluetooth device.") 229 String deviceAddress) { 230 if (sHspProfile == null) { 231 return false; 232 } 233 Log.d("Connected devices: " + sHspProfile.getConnectedDevices()); 234 BluetoothDevice device = null; 235 if (sHspProfile.getConnectedDevices().size() > 1) { 236 Log.d("More than one device available"); 237 } 238 try { 239 device = BluetoothFacade.getDevice(sHspProfile.getConnectedDevices(), deviceAddress); 240 } catch (Exception e) { 241 Log.d("Cannot find device " + deviceAddress); 242 return false; 243 } 244 return sHspProfile.isAudioConnected(device); 245 } 246 247 @Override shutdown()248 public void shutdown() { 249 } 250 } 251