#/usr/bin/env python3.4
#
# Copyright (C) 2016 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
"""
Test the HFP profile for basic calling functionality.
"""
import time
from acts.test_utils.bt.BluetoothBaseTest import BluetoothBaseTest
from acts.test_utils.bt.BluetoothCarHfpBaseTest import BluetoothCarHfpBaseTest
from acts.test_utils.bt import BtEnum
from acts.test_utils.bt import bt_test_utils
from acts.test_utils.car import car_telecom_utils
from acts.test_utils.car import tel_telecom_utils
from acts.test_utils.tel import tel_defines
BLUETOOTH_PKG_NAME = "com.android.bluetooth"
CALL_TYPE_OUTGOING = "CALL_TYPE_OUTGOING"
CALL_TYPE_INCOMING = "CALL_TYPE_INCOMING"
SHORT_TIMEOUT = 5
class BtCarHfpTest(BluetoothCarHfpBaseTest):
def setup_class(self):
if not super(BtCarHfpTest, self).setup_class():
return False
# Disable the A2DP profile.
bt_test_utils.set_profile_priority(
self.hf, self.ag, [BtEnum.BluetoothProfile.PBAP_CLIENT.value,
BtEnum.BluetoothProfile.A2DP_SINK.value],
BtEnum.BluetoothPriorityLevel.PRIORITY_OFF)
bt_test_utils.set_profile_priority(
self.hf, self.ag, [BtEnum.BluetoothProfile.HEADSET_CLIENT.value],
BtEnum.BluetoothPriorityLevel.PRIORITY_ON)
if not bt_test_utils.connect_pri_to_sec(self.hf, self.ag, set(
[BtEnum.BluetoothProfile.HEADSET_CLIENT.value])):
self.log.error("Failed to connect.")
return False
return True
#@BluetoothTest(UUID=4ce2195a-b70a-4584-912e-cbd20d20e19d)
@BluetoothBaseTest.bt_test_wrap
def test_default_calling_account(self):
"""
Tests if the default calling account is coming from the
bluetooth pacakge.
Precondition:
1. Devices are connected.
Steps:
1. Check if the default calling account is via Bluetooth package.
Returns:
Pass if True
Fail if False
Priority: 0
"""
selected_acc = \
self.hf.droid.telecomGetUserSelectedOutgoingPhoneAccount()
if not selected_acc:
self.hf.log.error("No default account found.")
return False
# Check if the default account is from the Bluetooth package. This is a
# light weight check.
try:
acc_component_id = selected_acc['ComponentName']
except KeyError:
self.hf.log.error("No component name for account {}".format(
selected_acc))
return False
if not acc_component_id.startswith(BLUETOOTH_PKG_NAME):
self.hf.log.error("Component name does not start with pkg name {}".
format(selected_acc))
return False
return True
#@BluetoothTest(UUID=e579009d-05f3-4236-a698-5de8c11d73a9)
@BluetoothBaseTest.bt_test_wrap
def test_outgoing_call_hf(self):
"""
Tests if we can make a phone call from HF role and disconnect from HF
role.
Precondition:
1. Devices are connected.
Steps:
1. Make a call from HF role.
2. Wait for the HF, AG to be dialing and RE to see the call ringing.
3. Hangup the call on HF role.
4. Wait for all devices to hangup the call.
Returns:
Pass if True
Fail if False
Priority: 0
"""
return self.dial_a_hangup_b(self.hf, self.hf)
#@BluetoothTest(UUID=c9d5f9cd-f275-4adf-b212-c2e9a70d4cac)
@BluetoothBaseTest.bt_test_wrap
def test_outgoing_call_ag(self):
"""
Tests if we can make a phone call from AG role and disconnect from AG
role.
Precondition:
1. Devices are connected.
Steps:
1. Make a call from AG role.
2. Wait for the HF, AG to be in dialing and RE to see the call ringing.
3. Hangup the call on AG role.
4. Wait for all devices to hangup the call.
Returns:
Pass if True
Fail if False
Priority: 0
"""
return self.dial_a_hangup_b(self.ag, self.ag)
#@BluetoothTest(UUID=908c199b-ca65-4694-821d-1b864ee3fe69)
@BluetoothBaseTest.bt_test_wrap
def test_outgoing_dial_ag_hangup_hf(self):
"""
Tests if we can make a phone call from AG role and disconnect from HF
role.
Precondition:
1. Devices are connected.
Steps:
1. Make a call from AG role.
2. Wait for the HF, AG to show dialing and RE to see the call ringing.
3. Hangup the call on HF role.
4. Wait for all devices to hangup the call.
Returns:
Pass if True
Fail if False
Priority: 0
"""
return self.dial_a_hangup_b(self.ag, self.hf)
#@BluetoothTest(UUID=5d1d52c7-51d8-4c82-b437-2e91a6220db3)
@BluetoothBaseTest.bt_test_wrap
def test_outgoing_dial_hf_hangup_ag(self):
"""
Tests if we can make a phone call from HF role and disconnect from AG
role.
Precondition:
1. Devices are connected.
Steps:
1. Make a call from HF role.
2. Wait for the HF, AG to show dialing and RE to see the call ringing.
3. Hangup the call on AG role.
4. Wait for all devices to hangup the call.
Returns:
Pass if True
Fail if False
Priority: 0
"""
return self.dial_a_hangup_b(self.hf, self.ag)
#@BluetoothTest(UUID=a718e238-7e31-40c9-a45b-72081210cc73)
@BluetoothBaseTest.bt_test_wrap
def test_incoming_dial_re_hangup_re(self):
"""
Tests if we can make a phone call from remote and disconnect from
remote.
Precondition:
1. Devices are connected.
Steps:
1. Make a call from RE role.
2. Wait for the HF, AG to show ringing and RE to see the call dialing.
3. Hangup the call on RE role.
4. Wait for all devices to hangup the call.
Returns:
Pass if True
Fail if False
Priority: 0
"""
return self.dial_a_hangup_b(self.re, self.re, self.ag_phone_number)
def dial_a_hangup_b(self, caller, callee, ph=""):
"""
a, b and c can be either of AG, HF or Remote.
1. Make a call from 'a' on a fixed number.
2. Wait for the call to get connected (check on both 'a' and 'b')
Check that 'c' is in ringing state.
3. Hangup the call on 'b'.
4. Wait for call to get completely disconnected
(check on both 'a' and 'b')
It is assumed that scenarios will not go into voice mail.
"""
if ph == "": ph = self.re_phone_number
# Determine if this is outgoing or incoming call.
call_type = None
if caller == self.ag or caller == self.hf:
call_type = CALL_TYPE_OUTGOING
if callee != self.ag and callee != self.hf:
self.log.info("outgoing call should terminate at AG or HF")
return False
elif caller == self.re:
call_type = CALL_TYPE_INCOMING
if callee != self.re:
self.log.info("Incoming call should terminate at Re")
return False
self.log.info("Call type is {}".format(call_type))
# make a call on 'caller'
if not tel_telecom_utils.dial_number(self.log, caller, ph):
return False
# Give time for state to update due to carrier limitations
time.sleep(SHORT_TIMEOUT)
# Check that everyone is in dialing/ringing state.
ret = True
if call_type == CALL_TYPE_OUTGOING:
ret &= tel_telecom_utils.wait_for_dialing(self.log, self.hf)
ret &= tel_telecom_utils.wait_for_dialing(self.log, self.ag)
ret &= tel_telecom_utils.wait_for_ringing(self.log, self.re)
else:
ret &= tel_telecom_utils.wait_for_ringing(self.log, self.hf)
ret &= tel_telecom_utils.wait_for_ringing(self.log, self.ag)
ret &= tel_telecom_utils.wait_for_dialing(self.log, self.re)
if not ret:
return False
# Give time for state to update due to carrier limitations
time.sleep(SHORT_TIMEOUT)
# Check if we have any calls with dialing or active state on 'b'.
# We assume we never disconnect from 'ringing' state since it will lead
# to voicemail.
call_state_dialing_or_active = \
[tel_defines.CALL_STATE_CONNECTING,
tel_defines.CALL_STATE_DIALING,
tel_defines.CALL_STATE_ACTIVE]
calls_in_dialing_or_active = tel_telecom_utils.get_calls_in_states(
self.log, callee, call_state_dialing_or_active)
# Make sure there is only one!
if len(calls_in_dialing_or_active) != 1:
self.log.info("Call State in dialing or active failed {}".format(
calls_in_dialing_or_active))
return False
# Hangup the *only* call on 'callee'
if not car_telecom_utils.hangup_call(self.log, callee,
calls_in_dialing_or_active[0]):
return False
time.sleep(SHORT_TIMEOUT)
# Make sure everyone got out of in call state.
for d in self.android_devices:
ret &= tel_telecom_utils.wait_for_not_in_call(self.log, d)
return ret