1#/usr/bin/env python3.4 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 17""" 18Test the HFP profile for basic calling functionality. 19""" 20 21import time 22 23from acts.test_utils.bt.BluetoothBaseTest import BluetoothBaseTest 24from acts.test_utils.bt import BtEnum 25from acts.test_utils.bt import bt_test_utils 26from acts.test_utils.car import car_telecom_utils 27from acts.test_utils.tel import tel_defines 28 29BLUETOOTH_PKG_NAME = "com.android.bluetooth" 30CALL_TYPE_OUTGOING = "CALL_TYPE_OUTGOING" 31CALL_TYPE_INCOMING = "CALL_TYPE_INCOMING" 32default_timeout = 20 33 34class BtCarHfpTest(BluetoothBaseTest): 35 def setup_class(self): 36 self.hf = self.android_devices[0] 37 self.ag = self.android_devices[1] 38 self.re = self.android_devices[2] 39 self.ag_phone_number = "tel:{}".format( 40 self.ag.droid.telephonyGetLine1Number()) 41 self.re_phone_number = "tel:{}".format( 42 self.re.droid.telephonyGetLine1Number()) 43 self.log.info("ag tel: {} re tel: {}".format( 44 self.ag_phone_number, self.re_phone_number)) 45 46 # Setup includes pairing and connecting the devices. 47 bt_test_utils.setup_multiple_devices_for_bt_test([self.hf, self.ag]) 48 bt_test_utils.reset_bluetooth([self.hf, self.ag]) 49 50 # Pair and connect the devices. 51 if not bt_test_utils.pair_pri_to_sec(self.hf.droid, self.ag.droid): 52 self.log.error("Failed to pair") 53 return False 54 55 # Connect the devices now, try twice. 56 attempts = 2 57 connected = False 58 while attempts > 0 and not connected: 59 connected = bt_test_utils.connect_pri_to_sec( 60 self.log, self.hf, self.ag.droid, 61 set([BtEnum.BluetoothProfile.HEADSET_CLIENT.value])) 62 self.log.info("Connected {}".format(connected)) 63 attempts -= 1 64 return connected 65 66 def setup_test(self): 67 # Reset the devices. 68 for d in self.android_devices: 69 d.ed.clear_all_events() 70 71 def on_fail(self, test_name, begin_time): 72 self.log.debug("Test {} failed.".format(test_name)) 73 74 @BluetoothBaseTest.bt_test_wrap 75 def test_default_calling_account(self): 76 """ 77 Tests if the default calling account is coming from the 78 bluetooth pacakge. 79 80 Precondition: 81 1. Devices are connected. 82 83 Steps: 84 1. Check if the default calling account is via Bluetooth package. 85 86 Returns: 87 Pass if True 88 Fail if False 89 90 Priority: 0 91 """ 92 selected_acc = \ 93 self.hf.droid.telecomGetUserSelectedOutgoingPhoneAccount() 94 if not selected_acc: 95 self.log.info("No default account found.") 96 return False 97 98 # Check if the default account is from the Bluetooth package. This is a 99 # light weight check. 100 try: 101 acc_component_id = selected_acc['ComponentName'] 102 except KeyError: 103 self.log.info( 104 "No component name for account {}".format(selected_acc)) 105 return False 106 if not acc_component_id.startswith(BLUETOOTH_PKG_NAME): 107 self.log.info( 108 "Component name does not start with pkg name {}".format( 109 selected_acc)) 110 return False 111 112 @BluetoothBaseTest.bt_test_wrap 113 def test_outgoing_call_hf(self): 114 """ 115 Tests if we can make a phone call from HF role and disconnect from HF 116 role. 117 118 Precondition: 119 1. Devices are connected. 120 121 Steps: 122 1. Make a call from HF role. 123 2. Wait for the HF, AG to be dialing and RE to see the call ringing. 124 3. Hangup the call on HF role. 125 4. Wait for all devices to hangup the call. 126 127 Returns: 128 Pass if True 129 Fail if False 130 131 Priority: 0 132 """ 133 return self.dial_a_hangup_b(self.hf, self.hf) 134 135 136 @BluetoothBaseTest.bt_test_wrap 137 def test_outgoing_call_ag(self): 138 """ 139 Tests if we can make a phone call from AG role and disconnect from AG 140 role. 141 142 Precondition: 143 1. Devices are connected. 144 145 Steps: 146 1. Make a call from AG role. 147 2. Wait for the HF, AG to be in dialing and RE to see the call ringing. 148 3. Hangup the call on AG role. 149 4. Wait for all devices to hangup the call. 150 151 Returns: 152 Pass if True 153 Fail if False 154 155 Priority: 0 156 """ 157 return self.dial_a_hangup_b(self.ag, self.ag) 158 159 @BluetoothBaseTest.bt_test_wrap 160 def test_outgoing_dial_ag_hangup_hf(self): 161 """ 162 Tests if we can make a phone call from AG role and disconnect from HF 163 role. 164 165 Precondition: 166 1. Devices are connected. 167 168 Steps: 169 1. Make a call from AG role. 170 2. Wait for the HF, AG to show dialing and RE to see the call ringing. 171 3. Hangup the call on HF role. 172 4. Wait for all devices to hangup the call. 173 174 Returns: 175 Pass if True 176 Fail if False 177 178 Priority: 0 179 """ 180 return self.dial_a_hangup_b(self.ag, self.hf) 181 182 @BluetoothBaseTest.bt_test_wrap 183 def test_outgoing_dial_hf_hangup_ag(self): 184 """ 185 Tests if we can make a phone call from HF role and disconnect from AG 186 role. 187 188 Precondition: 189 1. Devices are connected. 190 191 Steps: 192 1. Make a call from HF role. 193 2. Wait for the HF, AG to show dialing and RE to see the call ringing. 194 3. Hangup the call on AG role. 195 4. Wait for all devices to hangup the call. 196 197 Returns: 198 Pass if True 199 Fail if False 200 201 Priority: 0 202 """ 203 return self.dial_a_hangup_b(self.hf, self.ag) 204 205 @BluetoothBaseTest.bt_test_wrap 206 def test_incoming_dial_re_hangup_re(self): 207 """ 208 Tests if we can make a phone call from remote and disconnect from 209 remote. 210 211 Precondition: 212 1. Devices are connected. 213 214 Steps: 215 1. Make a call from RE role. 216 2. Wait for the HF, AG to show ringing and RE to see the call dialing. 217 3. Hangup the call on RE role. 218 4. Wait for all devices to hangup the call. 219 220 Returns: 221 Pass if True 222 Fail if False 223 224 Priority: 0 225 """ 226 return self.dial_a_hangup_b(self.re, self.re, self.ag_phone_number) 227 228 def dial_a_hangup_b(self, a, b, ph=""): 229 """ 230 a, b and c can be either of AG, HF or Remote. 231 1. Make a call from 'a' on a fixed number. 232 2. Wait for the call to get connected (check on both 'a' and 'b') 233 Check that 'c' is in ringing state. 234 3. Hangup the call on 'b'. 235 4. Wait for call to get completely disconnected 236 (check on both 'a' and 'b') 237 It is assumed that scenarios will not go into voice mail. 238 """ 239 if ph == "": ph = self.re_phone_number 240 241 # Determine if this is outgoing or incoming call. 242 call_type = None 243 if a == self.ag or a == self.hf: 244 call_type = CALL_TYPE_OUTGOING 245 if b != self.ag and b != self.hf: 246 self.log.info("outgoing call should terminate at AG or HF") 247 return False 248 elif a == self.re: 249 call_type = CALL_TYPE_INCOMING 250 if b != self.re: 251 self.log.info("Incoming call should terminate at Re") 252 return False 253 254 self.log.info("Call type is {}".format(call_type)) 255 256 # make a call on 'a' 257 if not car_telecom_utils.dial_number(self.log, a, ph): 258 return False 259 260 # Check that everyone is in dialing/ringing state. 261 ret = True 262 if call_type == CALL_TYPE_OUTGOING: 263 ret &= car_telecom_utils.wait_for_dialing(self.log, self.hf) 264 ret &= car_telecom_utils.wait_for_dialing(self.log, self.ag) 265 ret &= car_telecom_utils.wait_for_ringing(self.log, self.re) 266 else: 267 ret &= car_telecom_utils.wait_for_ringing(self.log, self.hf) 268 ret &= car_telecom_utils.wait_for_ringing(self.log, self.ag) 269 ret &= car_telecom_utils.wait_for_dialing(self.log, self.re) 270 if not ret: 271 return False 272 273 # Check if we have any calls with dialing or active state on 'b'. 274 # We assume we never disconnect from 'ringing' state since it will lead 275 # to voicemail. 276 call_state_dialing_or_active = \ 277 [tel_defines.CALL_STATE_CONNECTING, 278 tel_defines.CALL_STATE_DIALING, 279 tel_defines.CALL_STATE_ACTIVE] 280 281 calls_in_dialing_or_active = car_telecom_utils.get_calls_in_states( 282 self.log, b, call_state_dialing_or_active) 283 284 # Make sure there is only one! 285 if len(calls_in_dialing_or_active) != 1: 286 self.log.info("Call State in dialing or active failed {}".format( 287 calls_in_dialing_or_active)) 288 return False 289 290 # Hangup the *only* call on 'b' 291 if not car_telecom_utils.hangup_call( 292 self.log, b, calls_in_dialing_or_active[0]): 293 return False 294 295 # Make sure everyone got out of in call state. 296 for d in self.android_devices: 297 ret &= car_telecom_utils.wait_for_not_in_call(self.log, d) 298 return ret 299