1#!/usr/bin/env python3 2# 3# Copyright (C) 2016 The Android Open Source Project 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); you may not 6# use this file except in compliance with the License. You may obtain a copy of 7# the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 13# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 14# License for the specific language governing permissions and limitations under 15# the License. 16""" 17Test the HFP profile for calling and connection management. 18""" 19 20from acts.test_decorators import test_tracker_info 21from acts_contrib.test_utils.bt.BluetoothBaseTest import BluetoothBaseTest 22from acts_contrib.test_utils.bt.BluetoothCarHfpBaseTest import BluetoothCarHfpBaseTest 23from acts_contrib.test_utils.bt import BtEnum 24from acts_contrib.test_utils.bt import bt_test_utils 25from acts_contrib.test_utils.car import car_bt_utils 26from acts_contrib.test_utils.car import car_telecom_utils 27from acts_contrib.test_utils.tel import tel_defines 28from acts_contrib.test_utils.tel.tel_voice_utils import hangup_call 29from acts_contrib.test_utils.tel.tel_voice_utils import initiate_call 30from acts_contrib.test_utils.tel.tel_voice_utils import wait_and_answer_call 31 32BLUETOOTH_PKG_NAME = "com.android.bluetooth" 33CALL_TYPE_OUTGOING = "CALL_TYPE_OUTGOING" 34CALL_TYPE_INCOMING = "CALL_TYPE_INCOMING" 35default_timeout = 20 36 37 38class BtCarHfpConnectionTest(BluetoothCarHfpBaseTest): 39 def setup_class(self): 40 if not super(BtCarHfpConnectionTest, self).setup_class(): 41 return False 42 43 # Disable all 44 car_bt_utils.set_car_profile_priorities_off(self.hf, self.ag) 45 46 # Enable A2DP 47 bt_test_utils.set_profile_priority( 48 self.hf, self.ag, [BtEnum.BluetoothProfile.HEADSET_CLIENT], 49 BtEnum.BluetoothPriorityLevel.PRIORITY_ON) 50 51 return True 52 53 def setup_test(self): 54 if not super(BtCarHfpConnectionTest, self).setup_test(): 55 return False 56 self.hf.droid.bluetoothDisconnectConnected( 57 self.ag.droid.bluetoothGetLocalAddress()) 58 59 @test_tracker_info(uuid='a6669f9b-fb49-4bd8-aa9c-9d6369e34442') 60 @BluetoothBaseTest.bt_test_wrap 61 def test_call_transfer_disconnect_connect(self): 62 """ 63 Tests that after we connect when an active call is in progress, 64 we show the call. 65 66 Precondition: 67 1. AG & HF are disconnected but paired. 68 69 Steps: 70 1. Make a call from AG role (since disconnected) 71 2. Accept from RE role and transition the call to Active 72 3. Connect AG & HF 73 4. HF should transition into Active call state. 74 75 Returns: 76 Pass if True 77 Fail if False 78 79 Priority: 1 80 """ 81 # make a call on AG 82 if not initiate_call(self.log, self.ag, self.re_phone_number): 83 self.ag.log.error("Failed to initiate call from ag.") 84 return False 85 if not wait_and_answer_call(self.log, self.re): 86 self.re.log.error("Failed to accept call on re.") 87 return False 88 89 # Wait for AG, RE to go into an Active state. 90 if not car_telecom_utils.wait_for_active(self.log, self.ag): 91 self.ag.log.error("AG not in Active state.") 92 return False 93 if not car_telecom_utils.wait_for_active(self.log, self.re): 94 self.re.log.error("RE not in Active state.") 95 return False 96 97 # Now connect the devices. 98 if not bt_test_utils.connect_pri_to_sec( 99 self.hf, self.ag, 100 set([BtEnum.BluetoothProfile.HEADSET_CLIENT.value])): 101 self.log.error("Could not connect HF and AG {} {}".format( 102 self.hf.serial, self.ag.serial)) 103 return False 104 105 # Check that HF is in active state 106 if not car_telecom_utils.wait_for_active(self.log, self.hf): 107 self.hf.log.error("HF not in Active state.") 108 return False 109 110 # Hangup the call and check all devices are clean 111 self.hf.droid.telecomEndCall() 112 ret = True 113 ret &= car_telecom_utils.wait_for_not_in_call(self.log, self.hf) 114 ret &= car_telecom_utils.wait_for_not_in_call(self.log, self.ag) 115 ret &= car_telecom_utils.wait_for_not_in_call(self.log, self.re) 116 117 return ret 118 119 @test_tracker_info(uuid='97727b64-a590-4d84-a257-1facd8aafd16') 120 @BluetoothBaseTest.bt_test_wrap 121 def test_call_transfer_off_on(self): 122 """ 123 Tests that after we turn adapter on when an active call is in 124 progress, we show the call. 125 126 Precondition: 127 1. AG & HF are disconnected but paired. 128 2. HF's adapter is OFF 129 130 Steps: 131 1. Make a call from AG role (since disconnected) 132 2. Accept from RE role and transition the call to Active 133 3. Turn HF's adapter ON 134 4. HF should transition into Active call state. 135 136 Returns: 137 Pass if True 138 Fail if False 139 140 Priority: 1 141 """ 142 # Connect HF & AG 143 if not bt_test_utils.connect_pri_to_sec( 144 self.hf, self.ag, 145 set([BtEnum.BluetoothProfile.HEADSET_CLIENT.value])): 146 self.log.error("Could not connect HF and AG {} {}".format( 147 self.hf.serial, self.ag.serial)) 148 return False 149 150 # make a call on AG 151 if not initiate_call(self.log, self.ag, self.re_phone_number): 152 self.ag.log.error("Failed to initiate call from ag.") 153 return False 154 155 # Wait for all HF 156 if not car_telecom_utils.wait_for_dialing(self.log, self.hf): 157 self.hf.log.error("HF not in ringing state.") 158 return False 159 160 # Accept the call on RE 161 if not wait_and_answer_call(self.log, self.re): 162 self.re.log.error("Failed to accept call on re.") 163 return False 164 # Wait for all HF, AG, RE to go into an Active state. 165 if not car_telecom_utils.wait_for_active(self.log, self.hf): 166 self.hf.log.error("HF not in Active state.") 167 return False 168 if not car_telecom_utils.wait_for_active(self.log, self.ag): 169 self.ag.log.error("AG not in Active state.") 170 return False 171 if not car_telecom_utils.wait_for_active(self.log, self.re): 172 self.re.log.error("RE not in Active state.") 173 return False 174 175 # Turn the adapter OFF on HF 176 if not bt_test_utils.disable_bluetooth(self.hf.droid): 177 self.hf.log.error("Failed to turn BT off on HF.") 178 return False 179 180 # Turn adapter ON on HF 181 if not bt_test_utils.enable_bluetooth(self.hf.droid, self.hf.ed): 182 self.hf.log.error("Failed to turn BT ON after call on HF.") 183 return False 184 185 # Check that HF is in active state 186 if not car_telecom_utils.wait_for_active(self.log, self.hf): 187 self.hf.log.error("HF not in Active state.") 188 return False 189 190 # Hangup the call and check all devices are clean 191 self.hf.droid.telecomEndCall() 192 ret = True 193 ret &= car_telecom_utils.wait_for_not_in_call(self.log, self.hf) 194 ret &= car_telecom_utils.wait_for_not_in_call(self.log, self.ag) 195 ret &= car_telecom_utils.wait_for_not_in_call(self.log, self.re) 196 197 return ret 198 199 @test_tracker_info(uuid='95f76e2c-1cdd-4a7c-8e26-863b4c4242be') 200 @BluetoothBaseTest.bt_test_wrap 201 def test_call_transfer_connect_disconnect_connect(self): 202 """ 203 Test that when we go from connect -> disconnect -> connect on an active 204 call then the call is restored on HF. 205 206 Precondition: 207 1. AG & HF are paired 208 209 Steps: 210 0. Connect AG & HF 211 1. Make a call from HF role 212 2. Accept from RE role and transition the call to Active 213 3. Disconnect AG & HF 214 4. Verify that we don't have any calls on HF 215 5. Connect AG & HF 216 6. Verify that HF gets the call back. 217 218 Returns: 219 Pass if True 220 Fail if False 221 222 Priority: 1 223 """ 224 # Now connect the devices. 225 if not bt_test_utils.connect_pri_to_sec( 226 self.hf, self.ag, 227 set([BtEnum.BluetoothProfile.HEADSET_CLIENT.value])): 228 self.log.error("Could not connect HF and AG {} {}".format( 229 self.hf.serial, self.ag.serial)) 230 return False 231 232 # make a call on HF 233 if not car_telecom_utils.dial_number(self.log, self.hf, 234 self.re_phone_number): 235 self.hf.log.error("HF not in dialing state.") 236 return False 237 238 # Wait for HF, AG to be dialing and RE to be ringing 239 ret = True 240 ret &= car_telecom_utils.wait_for_dialing(self.log, self.hf) 241 #uncomment once sl4a code has been merged. 242 ret &= car_telecom_utils.wait_for_dialing(self.log, self.ag) 243 ret &= car_telecom_utils.wait_for_ringing(self.log, self.re) 244 245 if not ret: 246 self.log.error("Outgoing call did not get established") 247 return False 248 249 # Accept call on RE. 250 if not wait_and_answer_call(self.log, self.re): 251 self.re.log.error("Failed to accept call on re.") 252 return False 253 254 ret &= car_telecom_utils.wait_for_active(self.log, self.hf) 255 ret &= car_telecom_utils.wait_for_active(self.log, self.ag) 256 ret &= car_telecom_utils.wait_for_active(self.log, self.re) 257 258 if not ret: 259 self.log.error("Outgoing call did not transition to active") 260 return False 261 262 # Disconnect HF & AG 263 self.hf.droid.bluetoothDisconnectConnected( 264 self.ag.droid.bluetoothGetLocalAddress()) 265 266 # We use the proxy of the Call going away as HF disconnected 267 if not car_telecom_utils.wait_for_not_in_call(self.log, self.hf): 268 self.hf.log.error("HF still in call after disconnection.") 269 return False 270 271 # Now connect the devices. 272 if not bt_test_utils.connect_pri_to_sec( 273 self.hf, self.ag, 274 set([BtEnum.BluetoothProfile.HEADSET_CLIENT.value])): 275 self.log.error("Could not connect HF and AG {} {}".format( 276 self.hf.serial, self.ag.serial)) 277 # Additional profile connection check for b/ 278 if not bt_test_utils.is_hfp_client_device_connected( 279 self.hf, self.ag.droid.bluetoothGetLocalAddress()): 280 self.hf.log.info( 281 "HFP Client connected even though connection state changed " 282 + " event not found") 283 return False 284 285 # Check that HF is in active state 286 if not car_telecom_utils.wait_for_active(self.log, self.hf): 287 self.hf.log.error("HF not in Active state.") 288 return False 289 290 # Hangup the call and check all devices are clean 291 self.hf.droid.telecomEndCall() 292 ret &= car_telecom_utils.wait_for_not_in_call(self.log, self.hf) 293 ret &= car_telecom_utils.wait_for_not_in_call(self.log, self.ag) 294 ret &= car_telecom_utils.wait_for_not_in_call(self.log, self.re) 295 296 return ret 297