Home | History | Annotate | Download | only in car_bt
      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 Test the HFP profile for basic calling functionality.
     18 """
     19 
     20 import time
     21 from acts.test_decorators import test_tracker_info
     22 from acts.test_utils.bt.BluetoothBaseTest import BluetoothBaseTest
     23 from acts.test_utils.bt.BluetoothCarHfpBaseTest import BluetoothCarHfpBaseTest
     24 from acts.test_utils.bt import BtEnum
     25 from acts.test_utils.bt import bt_test_utils
     26 from acts.test_utils.car import car_telecom_utils
     27 from acts.test_utils.car import tel_telecom_utils
     28 from acts.test_utils.tel import tel_defines
     29 
     30 BLUETOOTH_PKG_NAME = "com.android.bluetooth"
     31 CALL_TYPE_OUTGOING = "CALL_TYPE_OUTGOING"
     32 CALL_TYPE_INCOMING = "CALL_TYPE_INCOMING"
     33 AUDIO_STATE_DISCONNECTED = 0
     34 AUDIO_STATE_ROUTED = 2
     35 SHORT_TIMEOUT = 5
     36 
     37 
     38 class BtCarHfpTest(BluetoothCarHfpBaseTest):
     39     def setup_class(self):
     40         if not super(BtCarHfpTest, self).setup_class():
     41             return False
     42         # Disable the A2DP profile.
     43         bt_test_utils.set_profile_priority(self.hf, self.ag, [
     44             BtEnum.BluetoothProfile.PBAP_CLIENT.value,
     45             BtEnum.BluetoothProfile.A2DP_SINK.value
     46         ], BtEnum.BluetoothPriorityLevel.PRIORITY_OFF)
     47         bt_test_utils.set_profile_priority(
     48             self.hf, self.ag, [BtEnum.BluetoothProfile.HEADSET_CLIENT.value],
     49             BtEnum.BluetoothPriorityLevel.PRIORITY_ON)
     50 
     51         if not bt_test_utils.connect_pri_to_sec(
     52                 self.hf, self.ag,
     53                 set([BtEnum.BluetoothProfile.HEADSET_CLIENT.value])):
     54             self.log.error("Failed to connect.")
     55             return False
     56         return True
     57 
     58     @test_tracker_info(uuid='4ce2195a-b70a-4584-912e-cbd20d20e19d')
     59     @BluetoothBaseTest.bt_test_wrap
     60     def test_default_calling_account(self):
     61         """
     62         Tests if the default calling account is coming from the
     63         bluetooth pacakge.
     64 
     65         Precondition:
     66         1. Devices are connected.
     67 
     68         Steps:
     69         1. Check if the default calling account is via Bluetooth package.
     70 
     71         Returns:
     72           Pass if True
     73           Fail if False
     74 
     75         Priority: 0
     76         """
     77         selected_acc = \
     78             self.hf.droid.telecomGetUserSelectedOutgoingPhoneAccount()
     79         if not selected_acc:
     80             self.hf.log.error("No default account found.")
     81             return False
     82 
     83         # Check if the default account is from the Bluetooth package. This is a
     84         # light weight check.
     85         try:
     86             acc_component_id = selected_acc['ComponentName']
     87         except KeyError:
     88             self.hf.log.error("No component name for account {}".format(
     89                 selected_acc))
     90             return False
     91         if not acc_component_id.startswith(BLUETOOTH_PKG_NAME):
     92             self.hf.log.error("Component name does not start with pkg name {}".
     93                               format(selected_acc))
     94             return False
     95         return True
     96 
     97     @test_tracker_info(uuid='e579009d-05f3-4236-a698-5de8c11d73a9')
     98     @BluetoothBaseTest.bt_test_wrap
     99     def test_outgoing_call_hf(self):
    100         """
    101         Tests if we can make a phone call from HF role and disconnect from HF
    102         role.
    103 
    104         Precondition:
    105         1. Devices are connected.
    106 
    107         Steps:
    108         1. Make a call from HF role.
    109         2. Wait for the HF, AG to be dialing and RE to see the call ringing.
    110         3. Hangup the call on HF role.
    111         4. Wait for all devices to hangup the call.
    112 
    113         Returns:
    114           Pass if True
    115           Fail if False
    116 
    117         Priority: 0
    118         """
    119         return self.dial_a_hangup_b(self.hf, self.hf)
    120 
    121     @test_tracker_info(uuid='c9d5f9cd-f275-4adf-b212-c2e9a70d4cac')
    122     @BluetoothBaseTest.bt_test_wrap
    123     def test_outgoing_call_ag(self):
    124         """
    125         Tests if we can make a phone call from AG role and disconnect from AG
    126         role.
    127 
    128         Precondition:
    129         1. Devices are connected.
    130 
    131         Steps:
    132         1. Make a call from AG role.
    133         2. Wait for the HF, AG to be in dialing and RE to see the call ringing.
    134         3. Hangup the call on AG role.
    135         4. Wait for all devices to hangup the call.
    136 
    137         Returns:
    138           Pass if True
    139           Fail if False
    140 
    141         Priority: 0
    142         """
    143         return self.dial_a_hangup_b(self.ag, self.ag)
    144 
    145     @test_tracker_info(uuid='908c199b-ca65-4694-821d-1b864ee3fe69')
    146     @BluetoothBaseTest.bt_test_wrap
    147     def test_outgoing_dial_ag_hangup_hf(self):
    148         """
    149         Tests if we can make a phone call from AG role and disconnect from HF
    150         role.
    151 
    152         Precondition:
    153         1. Devices are connected.
    154 
    155         Steps:
    156         1. Make a call from AG role.
    157         2. Wait for the HF, AG to show dialing and RE to see the call ringing.
    158         3. Hangup the call on HF role.
    159         4. Wait for all devices to hangup the call.
    160 
    161         Returns:
    162           Pass if True
    163           Fail if False
    164 
    165         Priority: 0
    166         """
    167         return self.dial_a_hangup_b(self.ag, self.hf)
    168 
    169     @test_tracker_info(uuid='5d1d52c7-51d8-4c82-b437-2e91a6220db3')
    170     @BluetoothBaseTest.bt_test_wrap
    171     def test_outgoing_dial_hf_hangup_ag(self):
    172         """
    173         Tests if we can make a phone call from HF role and disconnect from AG
    174         role.
    175 
    176         Precondition:
    177         1. Devices are connected.
    178 
    179         Steps:
    180         1. Make a call from HF role.
    181         2. Wait for the HF, AG to show dialing and RE to see the call ringing.
    182         3. Hangup the call on AG role.
    183         4. Wait for all devices to hangup the call.
    184 
    185         Returns:
    186           Pass if True
    187           Fail if False
    188 
    189         Priority: 0
    190         """
    191         return self.dial_a_hangup_b(self.hf, self.ag)
    192 
    193     @test_tracker_info(uuid='a718e238-7e31-40c9-a45b-72081210cc73')
    194     @BluetoothBaseTest.bt_test_wrap
    195     def test_incoming_dial_re_hangup_re(self):
    196         """
    197         Tests if we can make a phone call from remote and disconnect from
    198         remote.
    199 
    200         Precondition:
    201         1. Devices are connected.
    202 
    203         Steps:
    204         1. Make a call from RE role.
    205         2. Wait for the HF, AG to show ringing and RE to see the call dialing.
    206         3. Hangup the call on RE role.
    207         4. Wait for all devices to hangup the call.
    208 
    209         Returns:
    210           Pass if True
    211           Fail if False
    212 
    213         Priority: 0
    214         """
    215         return self.dial_a_hangup_b(self.re, self.re, self.ag_phone_number)
    216 
    217     def test_bluetooth_voice_recognition_assistant(self):
    218         """
    219         Tests if we can initate a remote Voice Recognition session.
    220 
    221         Precondition:
    222         1. Devices are connected.
    223 
    224         Steps:
    225         1. Verify that audio isn't routed between the HF and AG.
    226         2. From the HF send a BVRA command.
    227         3. Verify that audio is routed from the HF to AG.
    228         4. From the HF send a BVRA command to stop the session.
    229         5. Verify that audio is no longer routed from the HF to AG.
    230 
    231         Returns:
    232           Pass if True
    233           Fail if False
    234 
    235         Priority: 0
    236         """
    237         audio_state = self.hf.droid.bluetoothHfpClientGetAudioState(
    238             self.ag.droid.bluetoothGetLocalAddress())
    239         if (audio_state != AUDIO_STATE_DISCONNECTED):
    240             self.log.info(
    241                 "Audio connected before test started, current state {}.".
    242                 format(str(audio_state)))
    243             return False
    244         bvra_started = self.hf.droid.bluetoothHfpClientStartVoiceRecognition(
    245             self.ag.droid.bluetoothGetLocalAddress())
    246         if (bvra_started != True):
    247             self.log.info("BVRA Failed to start.")
    248             return False
    249         time.sleep(SHORT_TIMEOUT)
    250         audio_state = self.hf.droid.bluetoothHfpClientGetAudioState(
    251             self.ag.droid.bluetoothGetLocalAddress())
    252         if (audio_state != AUDIO_STATE_ROUTED):
    253             self.log.info("Audio didn't route, current state {}.".format(
    254                 str(audio_state)))
    255             return False
    256         bvra_stopped = self.hf.droid.bluetoothHfpClientStopVoiceRecognition(
    257             self.ag.droid.bluetoothGetLocalAddress())
    258         if (bvra_stopped != True):
    259             self.log.info("BVRA Failed to stop.")
    260             return False
    261         time.sleep(SHORT_TIMEOUT)
    262         audio_state = self.hf.droid.bluetoothHfpClientGetAudioState(
    263             self.ag.droid.bluetoothGetLocalAddress())
    264         if (audio_state != AUDIO_STATE_DISCONNECTED):
    265             self.log.info("Audio didn't cleanup, current state {}.".format(
    266                 str(audio_state)))
    267             return False
    268         return True
    269 
    270     def dial_a_hangup_b(self, caller, callee, ph=""):
    271         """
    272         a, b and c can be either of AG, HF or Remote.
    273         1. Make a call from 'a' on a fixed number.
    274         2. Wait for the call to get connected (check on both 'a' and 'b')
    275            Check that 'c' is in ringing state.
    276         3. Hangup the call on 'b'.
    277         4. Wait for call to get completely disconnected
    278         (check on both 'a' and 'b')
    279         It is assumed that scenarios will not go into voice mail.
    280         """
    281         if ph == "": ph = self.re_phone_number
    282 
    283         # Determine if this is outgoing or incoming call.
    284         call_type = None
    285         if caller == self.ag or caller == self.hf:
    286             call_type = CALL_TYPE_OUTGOING
    287             if callee != self.ag and callee != self.hf:
    288                 self.log.info("outgoing call should terminate at AG or HF")
    289                 return False
    290         elif caller == self.re:
    291             call_type = CALL_TYPE_INCOMING
    292             if callee != self.re:
    293                 self.log.info("Incoming call should terminate at Re")
    294                 return False
    295 
    296         self.log.info("Call type is {}".format(call_type))
    297 
    298         # make a call on 'caller'
    299         if not tel_telecom_utils.dial_number(self.log, caller, ph):
    300             return False
    301 
    302         # Give time for state to update due to carrier limitations
    303         time.sleep(SHORT_TIMEOUT)
    304         # Check that everyone is in dialing/ringing state.
    305         ret = True
    306         if call_type == CALL_TYPE_OUTGOING:
    307             ret &= tel_telecom_utils.wait_for_dialing(self.log, self.hf)
    308             ret &= tel_telecom_utils.wait_for_dialing(self.log, self.ag)
    309             ret &= tel_telecom_utils.wait_for_ringing(self.log, self.re)
    310         else:
    311             ret &= tel_telecom_utils.wait_for_ringing(self.log, self.hf)
    312             ret &= tel_telecom_utils.wait_for_ringing(self.log, self.ag)
    313             ret &= tel_telecom_utils.wait_for_dialing(self.log, self.re)
    314         if not ret:
    315             return False
    316 
    317         # Give time for state to update due to carrier limitations
    318         time.sleep(SHORT_TIMEOUT)
    319         # Check if we have any calls with dialing or active state on 'b'.
    320         # We assume we never disconnect from 'ringing' state since it will lead
    321         # to voicemail.
    322         call_state_dialing_or_active = \
    323             [tel_defines.CALL_STATE_CONNECTING,
    324              tel_defines.CALL_STATE_DIALING,
    325              tel_defines.CALL_STATE_ACTIVE]
    326 
    327         calls_in_dialing_or_active = tel_telecom_utils.get_calls_in_states(
    328             self.log, callee, call_state_dialing_or_active)
    329 
    330         # Make sure there is only one!
    331         if len(calls_in_dialing_or_active) != 1:
    332             self.log.info("Call State in dialing or active failed {}".format(
    333                 calls_in_dialing_or_active))
    334             return False
    335 
    336         # Hangup the *only* call on 'callee'
    337         if not car_telecom_utils.hangup_call(self.log, callee,
    338                                              calls_in_dialing_or_active[0]):
    339             return False
    340 
    341         time.sleep(SHORT_TIMEOUT)
    342         # Make sure everyone got out of in call state.
    343         for d in self.android_devices:
    344             ret &= tel_telecom_utils.wait_for_not_in_call(self.log, d)
    345         return ret
    346