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 conference calling functionality. 18""" 19 20import time 21 22from acts.test_decorators import test_tracker_info 23from acts.test_utils.bt.BluetoothBaseTest import BluetoothBaseTest 24from acts.test_utils.bt.BluetoothCarHfpBaseTest import BluetoothCarHfpBaseTest 25from acts.test_utils.bt import BtEnum 26from acts.test_utils.bt import bt_test_utils 27from acts.test_utils.car import car_telecom_utils 28from acts.test_utils.tel import tel_defines 29from acts.test_utils.tel.tel_test_utils import hangup_call 30from acts.test_utils.tel.tel_test_utils import initiate_call 31from acts.test_utils.tel.tel_test_utils import wait_and_answer_call 32from acts.test_utils.tel.tel_test_utils import wait_for_ringing_call 33from acts.test_utils.tel.tel_voice_utils import get_audio_route 34from acts.test_utils.tel.tel_voice_utils import set_audio_route 35from acts.test_utils.tel.tel_voice_utils import swap_calls 36 37BLUETOOTH_PKG_NAME = "com.android.bluetooth" 38CALL_TYPE_OUTGOING = "CALL_TYPE_OUTGOING" 39CALL_TYPE_INCOMING = "CALL_TYPE_INCOMING" 40SHORT_TIMEOUT = 3 41 42 43class BtCarHfpConferenceTest(BluetoothCarHfpBaseTest): 44 def setup_class(self): 45 if not super(BtCarHfpConferenceTest, self).setup_class(): 46 return False 47 48 # Connect the devices now, try twice. 49 attempts = 2 50 connected = False 51 while attempts > 0 and not connected: 52 connected = bt_test_utils.connect_pri_to_sec( 53 self.hf, self.ag, 54 set([BtEnum.BluetoothProfile.HEADSET_CLIENT.value])) 55 self.log.info("Connected {}".format(connected)) 56 attempts -= 1 57 return connected 58 59 @test_tracker_info(uuid='a9657693-b534-4625-bf91-69a1d1b9a943') 60 @BluetoothBaseTest.bt_test_wrap 61 def test_multi_way_call_accept(self): 62 """ 63 Tests if we can have a 3-way calling between re, RE2 and AG/HF. 64 65 Precondition: 66 1. Devices are connected over HFP. 67 68 Steps: 69 1. Make a call from AG to RE 70 2. Wait for dialing on re and ringing on RE/HF. 71 3. Accept the call on RE 72 4. Make a call from AG to RE2 73 5. Wait for dialing on re and ringing on RE2/HF. 74 6. Accept the call on RE2. 75 7. See that HF/AG have one active and one held call. 76 8. Merge the call on HF. 77 9. Verify that we have a conference call on HF/AG. 78 10. Hangup the call on HF. 79 11. Wait for all devices to go back into stable state. 80 81 Returns: 82 Pass if True 83 Fail if False 84 85 Priority: 0 86 """ 87 88 # Dial RE from AG 89 if not initiate_call(self.log, self.ag, self.re_phone_number): 90 self.log.error("Failed to initiate call from re.") 91 return False 92 93 # Wait for dialing/ringing 94 ret = True 95 ret &= wait_for_ringing_call(self.log, self.re) 96 ret &= car_telecom_utils.wait_for_ringing(self.log, self.hf) 97 98 if not ret: 99 self.log.error("Failed to dial incoming number from") 100 return False 101 102 # Give time for state to update due to carrier limitations 103 time.sleep(SHORT_TIMEOUT) 104 # Extract the call. 105 call_1 = car_telecom_utils.get_calls_in_states( 106 self.log, self.hf, [tel_defines.CALL_STATE_DIALING]) 107 if len(call_1) != 1: 108 self.hf.log.error("Call State in ringing failed {}".format(call_1)) 109 return False 110 111 re_ringing_call_id = car_telecom_utils.get_calls_in_states( 112 self.log, self.re, [tel_defines.CALL_STATE_RINGING]) 113 114 # Accept the call on RE 115 if not car_telecom_utils.accept_call(self.log, self.re, re_ringing_call_id[0]): 116 self.hf.log.error("Accepting call failed {}".format( 117 self.hf.serial)) 118 return False 119 120 time.sleep(SHORT_TIMEOUT) 121 # Dial another call to RE2 122 if not initiate_call(self.log, self.ag, self.re2_phone_number): 123 self.re2.log.error("Failed to initiate call from re.") 124 return False 125 126 # Wait for dialing/ringing 127 ret &= wait_for_ringing_call(self.log, self.re2) 128 ret &= car_telecom_utils.wait_for_ringing(self.log, self.hf) 129 130 if not ret: 131 self.log.error("AG and HF not in ringing state.") 132 return False 133 134 # Give time for state to update due to carrier limitations 135 time.sleep(SHORT_TIMEOUT) 136 # Extract the call. 137 # input("Continue?") 138 call_2 = car_telecom_utils.get_calls_in_states( 139 self.log, self.hf, [tel_defines.CALL_STATE_DIALING]) 140 if len(call_2) != 1: 141 self.hf.log.info("Call State in ringing failed {}".format(call_2)) 142 return False 143 144 re2_ringing_call_id = car_telecom_utils.get_calls_in_states( 145 self.log, self.re2, [tel_defines.CALL_STATE_RINGING]) 146 147 # Accept the call on HF 148 if not car_telecom_utils.accept_call(self.log, self.re2, re2_ringing_call_id[0]): 149 self.hf.log.info("Accepting call failed {}".format(self.hf.serial)) 150 return False 151 152 # Give time before merge for state to update due to carrier limitations 153 time.sleep(SHORT_TIMEOUT) 154 155 # Merge the calls now. 156 self.hf.droid.telecomCallJoinCallsInConf(call_1[0], call_2[0]) 157 158 # Check if we are in conference with call_1 and call_2 159 conf_call_id = car_telecom_utils.wait_for_conference(self.log, self.hf, participants=2) 160 if conf_call_id is None: 161 self.hf.log.error("Did not get the conference setup correctly") 162 return False 163 164 # Now hangup the conference call. 165 if not car_telecom_utils.hangup_conf(self.log, self.hf, conf_call_id): 166 self.hf.log.error("Could not hangup conference call {}!".format(conf_call_id)) 167 return False 168 169 return True 170