Home | History | Annotate | Download | only in bt
      1 #/usr/bin/env python3.4
      2 #
      3 # Copyright (C) 2018 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 import time
     18 import os
     19 
     20 from acts.keys import Config
     21 from acts.utils import rand_ascii_str
     22 from acts.test_utils.bt.BluetoothBaseTest import BluetoothBaseTest
     23 from acts.test_utils.bt.bt_constants import logcat_strings
     24 from acts.test_utils.tel.TelephonyBaseTest import TelephonyBaseTest
     25 from acts.test_utils.tel.tel_defines import AUDIO_ROUTE_BLUETOOTH
     26 from acts.test_utils.tel.tel_defines import AUDIO_ROUTE_EARPIECE
     27 from acts.test_utils.tel.tel_defines import AUDIO_ROUTE_SPEAKER
     28 from acts.test_utils.tel.tel_defines import WAIT_TIME_IN_CALL
     29 from acts.test_utils.tel.tel_test_utils import get_phone_number
     30 from acts.test_utils.tel.tel_test_utils import hangup_call
     31 from acts.test_utils.tel.tel_test_utils import initiate_call
     32 from acts.test_utils.tel.tel_test_utils import num_active_calls
     33 from acts.test_utils.tel.tel_test_utils import sms_send_receive_verify
     34 from acts.test_utils.tel.tel_test_utils import wait_and_answer_call
     35 from acts.test_utils.tel.tel_voice_utils import get_audio_route
     36 from acts.test_utils.tel.tel_voice_utils import set_audio_route
     37 from acts.test_utils.tel.tel_voice_utils import swap_calls
     38 from acts.test_utils.tel.tel_test_utils import toggle_airplane_mode
     39 from acts.test_utils.tel.tel_test_utils import call_setup_teardown
     40 from acts.utils import exe_cmd
     41 from acts.utils import get_current_epoch_time
     42 
     43 KEYCODE_VOLUME_UP = "input keyevent 24"
     44 KEYCODE_VOLUME_DOWN = "input keyevent 25"
     45 KEYCODE_EVENT_PLAY_PAUSE = "input keyevent 85"
     46 KEYCODE_MEDIA_STOP = "input keyevent 86"
     47 KEYCODE_EVENT_NEXT = "input keyevent 87"
     48 KEYCODE_EVENT_PREVIOUS = "input keyevent 88"
     49 KEYCODE_MEDIA_REWIND = "input keyevent 89"
     50 KEYCODE_MEDIA_FAST_FORWARD = "input keyevent 90"
     51 KEYCODE_MUTE = "input keyevent 91"
     52 
     53 default_timeout = 10
     54 
     55 
     56 class E2eBtCarkitLib():
     57 
     58     android_devices = []
     59     short_timeout = 3
     60     active_call_id = None
     61     hold_call_id = None
     62     log = None
     63     mac_address = None
     64 
     65     def __init__(self, log, target_mac_address=None):
     66         self.log = log
     67         self.target_mac_address = target_mac_address
     68 
     69     def connect_hsp_helper(self, ad):
     70         end_time = time.time() + default_timeout + 10
     71         connected_hsp_devices = len(ad.droid.bluetoothHspGetConnectedDevices())
     72         while connected_hsp_devices != 1 and time.time() < end_time:
     73             try:
     74                 ad.droid.bluetoothHspConnect(self.target_mac_address)
     75                 time.sleep(3)
     76                 if len(ad.droid.bluetoothHspGetConnectedDevices() == 1):
     77                     break
     78             except Exception:
     79                 self.log.debug("Failed to connect hsp trying again...")
     80             try:
     81                 ad.droid.bluetoothConnectBonded(self.target_mac_address)
     82             except Exception:
     83                 self.log.info("Failed to connect to bonded device...")
     84             connected_hsp_devices = len(
     85                 ad.droid.bluetoothHspGetConnectedDevices())
     86         if connected_hsp_devices != 1:
     87             self.log.error("Failed to reconnect to HSP service...")
     88             return False
     89         self.log.info("Connected to HSP service...")
     90         return True
     91 
     92     def setup_multi_call(self, caller0, caller1, callee):
     93         outgoing_num = get_phone_number(self.log, callee)
     94         if not initiate_call(self.log, caller0, outgoing_num):
     95             self.log.error("Failed to initiate call")
     96             return False
     97         if not wait_and_answer_call(self.log, callee):
     98             self.log.error("Failed to answer call.")
     99             return False
    100         time.sleep(self.short_timeout)
    101         if not initiate_call(self.log, caller1, outgoing_num):
    102             self.log.error("Failed to initiate call")
    103             return False
    104         if not wait_and_answer_call(self.log, callee):
    105             self.log.error("Failed to answer call.")
    106             return False
    107         return True
    108 
    109     def process_tests(self, tests):
    110         for test in tests:
    111             try:
    112                 test()
    113             except Exception as err:
    114                 self.log.error(err)
    115 
    116     def run_suite_hfp_tests(self):
    117         tests = [
    118             self.outgoing_call_private_number,
    119             self.outgoing_call_unknown_contact,
    120             self.incomming_call_private_number,
    121             self.incomming_call_unknown_contact,
    122             self.outgoing_call_multiple_iterations,
    123             self.outgoing_call_hsp_disabled_then_enabled_during_call,
    124             self.call_audio_routes,
    125             self.sms_during_incomming_call,
    126             self.multi_incomming_call,
    127             self.multi_call_audio_routing,
    128             self.multi_call_swap_multiple_times,
    129             self.outgoing_call_a2dp_play_before_and_after,
    130         ]
    131         _process_tests(tests)
    132 
    133     def run_suite_hfp_conf_tests(self):
    134         tests = [
    135             self.multi_call_join_conference_call,
    136             self.multi_call_join_conference_call_hangup_conf_call,
    137             self.outgoing_multi_call_join_conference_call,
    138             self.multi_call_join_conference_call_audio_routes,
    139         ]
    140         _process_tests(tests)
    141 
    142     def run_suite_map_tests(self):
    143         tests = [
    144             self.sms_receive_different_sizes,
    145             self.sms_receive_multiple,
    146             self.sms_send_outgoing_texts,
    147         ]
    148         _process_tests(tests)
    149 
    150     def run_suite_avrcp_tests(self):
    151         tests = [
    152             self.avrcp_play_pause,
    153             self.avrcp_next_previous_song,
    154             self.avrcp_next_previous,
    155             self.avrcp_next_repetative,
    156         ]
    157         _process_tests(tests)
    158 
    159     def disconnect_reconnect_multiple_iterations(self, pri_dut):
    160         iteration_count = 5
    161         self.log.info(
    162             "Test disconnect-reconnect scenario from phone {} times.".format(
    163                 iteration_count))
    164         self.log.info(
    165             "This test will prompt for user interaction after each reconnect.")
    166         input("Press enter to execute this testcase...")
    167         #Assumes only one devices connected
    168         grace_timeout = 4  #disconnect and reconnect timeout
    169         for n in range(iteration_count):
    170             self.log.info("Test iteration {}.".format(n + 1))
    171             self.log.info("Disconnecting device {}...".format(
    172                 self.target_mac_address))
    173             pri_dut.droid.bluetoothDisconnectConnected(self.target_mac_address)
    174             # May have to do a longer sleep for carkits.... need to test
    175             time.sleep(grace_timeout)
    176             self.log.info("Connecting device {}...".format(
    177                 self.target_mac_address))
    178             pri_dut.droid.bluetoothConnectBonded(self.target_mac_address)
    179             if not self.connect_hsp_helper(pri_dut):
    180                 return False
    181             start_time = time.time()
    182             connected_devices = pri_dut.droid.bluetoothGetConnectedDevices()
    183             self.log.info(
    184                 "Waiting up to 10 seconds for device to reconnect...")
    185             while time.time() < start_time + 10 and len(connected_devices) != 1:
    186                 connected_devices = pri_dut.droid.bluetoothGetConnectedDevices(
    187                 )
    188                 time.sleep(1)
    189             if len(connected_devices) != 1:
    190                 self.log.error(
    191                     "Failed to reconnect at iteration {}... continuing".format(
    192                         n))
    193                 return False
    194             input("Continue to next iteration?")
    195         return True
    196 
    197     def disconnect_a2dp_only_then_reconnect(self, pri_dut):
    198         self.log.info(
    199             "Test disconnect-reconnect a2dp only scenario from phone.")
    200         input("Press enter to execute this testcase...")
    201         if not pri_dut.droid.bluetoothA2dpDisconnect(self.target_mac_address):
    202             self.log.error("Failed to disconnect A2DP service...")
    203             return False
    204         time.sleep(self.short_timeout)
    205         result = input("Confirm A2DP disconnected? (Y/n) ")
    206         if result == "n":
    207             self.log.error(
    208                 "Tester confirmed that A2DP did not disconnect. Failing test.")
    209             return False
    210         if len(pri_dut.droid.bluetoothA2dpGetConnectedDevices()) != 0:
    211             self.log.error("Failed to disconnect from A2DP service")
    212             return False
    213         pri_dut.droid.bluetoothA2dpConnect(self.target_mac_address)
    214         time.sleep(self.short_timeout)
    215         if len(pri_dut.droid.bluetoothA2dpGetConnectedDevices()) != 1:
    216             self.log.error("Failed to reconnect to A2DP service...")
    217             return False
    218         return True
    219 
    220     def disconnect_hsp_only_then_reconnect(self, pri_dut):
    221         self.log.info(
    222             "Test disconnect-reconnect hsp only scenario from phone.")
    223         input("Press enter to execute this testcase...")
    224         if not pri_dut.droid.bluetoothHspDisconnect(self.target_mac_address):
    225             self.log.error("Failed to disconnect HSP service...")
    226             return False
    227         time.sleep(self.short_timeout)
    228         result = input("Confirm HFP disconnected? (Y/n) ")
    229         pri_dut.droid.bluetoothHspConnect(self.target_mac_address)
    230         time.sleep(self.short_timeout)
    231         if len(pri_dut.droid.bluetoothHspGetConnectedDevices()) != 1:
    232             self.log.error("Failed to connect from HSP service")
    233             return False
    234         return True
    235 
    236     def disconnect_both_hsp_and_a2dp_then_reconnect(self, pri_dut):
    237         self.log.info(
    238             "Test disconnect-reconnect hsp and a2dp scenario from phone.")
    239         input("Press enter to execute this testcase...")
    240         if not pri_dut.droid.bluetoothA2dpDisconnect(self.target_mac_address):
    241             self.log.error("Failed to disconnect A2DP service...")
    242             return False
    243         if not pri_dut.droid.bluetoothHspDisconnect(self.target_mac_address):
    244             self.log.error("Failed to disconnect HSP service...")
    245             return False
    246         time.sleep(self.short_timeout)
    247         if len(pri_dut.droid.bluetoothA2dpGetConnectedDevices()) != 0:
    248             self.log.error("Failed to disconnect from A2DP service")
    249             return False
    250         if len(pri_dut.droid.bluetoothHspGetConnectedDevices()) != 0:
    251             self.log.error("Failed to disconnect from HSP service")
    252             return False
    253         result = input("Confirm HFP and A2DP disconnected? (Y/n) ")
    254         pri_dut.droid.bluetoothConnectBonded(self.target_mac_address)
    255         time.sleep(self.short_timeout)
    256         if len(pri_dut.droid.bluetoothA2dpGetConnectedDevices()) != 1:
    257             self.log.error("Failed to reconnect to A2DP service...")
    258             return False
    259         if not self.connect_hsp_helper(pri_dut):
    260             return False
    261         return True
    262 
    263     def outgoing_call_private_number(self, pri_dut, ter_dut):
    264         self.log.info(
    265             "Test outgoing call scenario from phone to private number")
    266         input("Press enter to execute this testcase...")
    267         outgoing_num = "*67" + get_phone_number(self.log, ter_dut)
    268         if not initiate_call(self.log, pri_dut, outgoing_num):
    269             self.log.error("Failed to initiate call")
    270             return False
    271         if not wait_and_answer_call(self.log, ter_dut):
    272             self.log.error("Failed to answer call.")
    273             return False
    274         time.sleep(self.short_timeout)
    275         input("Press enter to hangup call...")
    276         if not hangup_call(self.log, pri_dut):
    277             self.log.error("Failed to hangup call")
    278             return False
    279         return True
    280 
    281     def outgoing_call_a2dp_play_before_and_after(self, pri_dut, sec_dut):
    282         self.log.info(
    283             "Test outgoing call scenario while playing music. Music should resume after call."
    284         )
    285         pri_dut.adb.shell(KEYCODE_EVENT_PREVIOUS)
    286         input(
    287             "Press enter to execute this testcase when music is in a play state..."
    288         )
    289         outgoing_num = get_phone_number(self.log, sec_dut)
    290         if not initiate_call(self.log, pri_dut, outgoing_num):
    291             self.log.error("Failed to initiate call")
    292             return False
    293         if not wait_and_answer_call(self.log, sec_dut):
    294             self.log.error("Failed to answer call.")
    295             return False
    296         time.sleep(self.short_timeout)
    297         input("Press enter to hangup call...")
    298         if not hangup_call(self.log, pri_dut):
    299             self.log.error("Failed to hangup call")
    300             return False
    301         input("Press enter when music continues to play.")
    302         self.log.info("Pausing Music...")
    303         pri_dut.adb.shell(KEYCODE_EVENT_PLAY_PAUSE)
    304         return True
    305 
    306     def outgoing_call_unknown_contact(self, pri_dut, ter_dut):
    307         self.log.info(
    308             "Test outgoing call scenario from phone to unknow contact")
    309         input("Press enter to execute this testcase...")
    310         outgoing_num = get_phone_number(self.log, ter_dut)
    311         if not initiate_call(self.log, pri_dut, outgoing_num):
    312             self.log.error("Failed to initiate call")
    313             return False
    314         if not wait_and_answer_call(self.log, ter_dut):
    315             self.log.error("Failed to answer call.")
    316             return False
    317         time.sleep(self.short_timeout)
    318         input("Press enter to hangup call...")
    319         if not hangup_call(self.log, pri_dut):
    320             self.log.error("Failed to hangup call")
    321             return False
    322         return True
    323 
    324     def incomming_call_private_number(self, pri_dut, ter_dut):
    325         self.log.info(
    326             "Test incomming call scenario to phone from private number")
    327         input("Press enter to execute this testcase...")
    328         outgoing_num = "*67" + get_phone_number(self.log, pri_dut)
    329         if not initiate_call(self.log, ter_dut, outgoing_num):
    330             self.log.error("Failed to initiate call")
    331             return False
    332         if not wait_and_answer_call(self.log, pri_dut):
    333             self.log.error("Failed to answer call.")
    334             return False
    335         time.sleep(self.short_timeout)
    336         input("Press enter to hangup call...")
    337         if not hangup_call(self.log, ter_dut):
    338             self.log.error("Failed to hangup call")
    339             return False
    340 
    341         return True
    342 
    343     def incomming_call_unknown_contact(self, pri_dut, ter_dut):
    344         self.log.info(
    345             "Test incomming call scenario to phone from unknown contact")
    346         input("Press enter to execute this testcase...")
    347         outgoing_num = get_phone_number(self.log, pri_dut)
    348         if not initiate_call(self.log, ter_dut, outgoing_num):
    349             self.log.error("Failed to initiate call")
    350             return False
    351         if not wait_and_answer_call(self.log, pri_dut):
    352             self.log.error("Failed to answer call.")
    353             return False
    354         time.sleep(self.short_timeout)
    355         input("Press enter to hangup call...")
    356         if not hangup_call(self.log, ter_dut):
    357             self.log.error("Failed to hangup call")
    358             return False
    359         return True
    360 
    361     def outgoing_call_multiple_iterations(self, pri_dut, sec_dut):
    362         iteration_count = 3
    363         self.log.info(
    364             "Test outgoing call scenario from phone {} times from known contact".
    365             format(iteration_count))
    366         input("Press enter to execute this testcase...")
    367         outgoing_num = get_phone_number(self.log, sec_dut)
    368         for _ in range(iteration_count):
    369             if not initiate_call(self.log, pri_dut, outgoing_num):
    370                 self.log.error("Failed to initiate call")
    371                 return False
    372             if not wait_and_answer_call(self.log, sec_dut):
    373                 self.log.error("Failed to answer call.")
    374                 return False
    375             time.sleep(self.short_timeout)
    376             if not hangup_call(self.log, pri_dut):
    377                 self.log.error("Failed to hangup call")
    378                 return False
    379         return True
    380 
    381     def outgoing_call_hsp_disabled_then_enabled_during_call(
    382             self, pri_dut, sec_dut):
    383         self.log.info(
    384             "Test outgoing call hsp disabled then enable during call.")
    385         input("Press enter to execute this testcase...")
    386         outgoing_num = get_phone_number(self.log, sec_dut)
    387         if not pri_dut.droid.bluetoothHspDisconnect(self.target_mac_address):
    388             self.log.error("Failed to disconnect HSP service...")
    389             return False
    390         time.sleep(self.short_timeout)
    391         if len(pri_dut.droid.bluetoothHspGetConnectedDevices()) != 0:
    392             self.log.error("Failed to disconnect from HSP service")
    393             return False
    394         if not initiate_call(self.log, pri_dut, outgoing_num):
    395             self.log.error("Failed to initiate call")
    396             return False
    397         time.sleep(default_timeout)
    398         pri_dut.droid.bluetoothConnectBonded(self.target_mac_address)
    399         time.sleep(self.short_timeout)
    400         test_result = True
    401         if len(pri_dut.droid.bluetoothHspGetConnectedDevices()) != 1:
    402             self.log.error("Failed to reconnect to HSP service...")
    403             return
    404         if not hangup_call(self.log, pri_dut):
    405             self.log.error("Failed to hangup call")
    406             return False
    407         return test_result
    408 
    409     def call_audio_routes(self, pri_dut, sec_dut):
    410         self.log.info("Test various audio routes scenario from phone.")
    411         input("Press enter to execute this testcase...")
    412         outgoing_num = get_phone_number(self.log, sec_dut)
    413         if not initiate_call(self.log, pri_dut, outgoing_num):
    414             self.log.error("Failed to initiate call")
    415             return False
    416         if not wait_and_answer_call(self.log, sec_dut):
    417             self.log.error("Failed to answer call.")
    418             return False
    419         time.sleep(self.short_timeout)
    420         call_id = pri_dut.droid.telecomCallGetCallIds()[0]
    421         pri_dut.droid.telecomCallPlayDtmfTone(call_id, "9")
    422         input("Press enter to switch to speaker...")
    423         self.log.info("Switching to speaker.")
    424         set_audio_route(self.log, pri_dut, AUDIO_ROUTE_SPEAKER)
    425         time.sleep(self.short_timeout)
    426         if get_audio_route(self.log, pri_dut) != AUDIO_ROUTE_SPEAKER:
    427             self.log.error(
    428                 "Audio Route not set to {}".format(AUDIO_ROUTE_SPEAKER))
    429             return False
    430         input("Press enter to switch to earpiece...")
    431         self.log.info("Switching to earpiece.")
    432         set_audio_route(self.log, pri_dut, AUDIO_ROUTE_EARPIECE)
    433         time.sleep(self.short_timeout)
    434         if get_audio_route(self.log, pri_dut) != AUDIO_ROUTE_EARPIECE:
    435             self.log.error(
    436                 "Audio Route not set to {}".format(AUDIO_ROUTE_EARPIECE))
    437             return False
    438         input("Press enter to switch to Bluetooth...")
    439         self.log.info("Switching to Bluetooth...")
    440         set_audio_route(self.log, pri_dut, AUDIO_ROUTE_BLUETOOTH)
    441         time.sleep(self.short_timeout)
    442         if get_audio_route(self.log, pri_dut) != AUDIO_ROUTE_BLUETOOTH:
    443             self.log.error(
    444                 "Audio Route not set to {}".format(AUDIO_ROUTE_BLUETOOTH))
    445             return False
    446         input("Press enter to hangup call...")
    447         self.log.info("Hanging up call...")
    448         pri_dut.droid.telecomCallStopDtmfTone(call_id)
    449         if not hangup_call(self.log, pri_dut):
    450             self.log.error("Failed to hangup call")
    451             return False
    452         return True
    453 
    454     def sms_receive_different_sizes(self, pri_dut, sec_dut):
    455         self.log.info("Test recieve sms.")
    456         input("Press enter to execute this testcase...")
    457         msg = [rand_ascii_str(50), rand_ascii_str(1), rand_ascii_str(500)]
    458         if not sms_send_receive_verify(self.log, sec_dut, pri_dut, msg):
    459             return False
    460         else:
    461             self.log.info("Successfully sent sms. Please verify on carkit.")
    462         return True
    463 
    464     def sms_receive_multiple(self, pri_dut, sec_dut):
    465         text_count = 10
    466         self.log.info(
    467             "Test sending {} sms messages to phone.".format(text_count))
    468         input("Press enter to execute this testcase...")
    469         for _ in range(text_count):
    470             msg = [rand_ascii_str(50)]
    471             if not sms_send_receive_verify(self.log, sec_dut, pri_dut, msg):
    472                 return False
    473             else:
    474                 self.log.info(
    475                     "Successfully sent sms. Please verify on carkit.")
    476         return True
    477 
    478     def sms_send_outgoing_texts(self, pri_dut, sec_dut):
    479         self.log.info("Test send sms of different sizes.")
    480         input("Press enter to execute this testcase...")
    481         msg = [rand_ascii_str(50), rand_ascii_str(1), rand_ascii_str(500)]
    482         if not sms_send_receive_verify(self.log, pri_dut, sec_dut, msg):
    483             return False
    484         else:
    485             self.log.info("Successfully sent sms. Please verify on carkit.")
    486         return True
    487 
    488     def sms_during_incomming_call(self, pri_dut, sec_dut):
    489         self.log.info(
    490             "Test incomming call scenario to phone from unknown contact")
    491         input("Press enter to execute this testcase...")
    492         outgoing_num = get_phone_number(self.log, pri_dut)
    493         if not initiate_call(self.log, sec_dut, outgoing_num):
    494             self.log.error("Failed to initiate call")
    495             return False
    496         if not wait_and_answer_call(self.log, pri_dut):
    497             self.log.error("Failed to answer call.")
    498             return False
    499         time.sleep(self.short_timeout)
    500         msg = [rand_ascii_str(10)]
    501         if not sms_send_receive_verify(self.log, sec_dut, pri_dut, msg):
    502             return False
    503         else:
    504             self.log.info("Successfully sent sms. Please verify on carkit.")
    505         input("Press enter to hangup call...")
    506         if not hangup_call(self.log, sec_dut):
    507             self.log.error("Failed to hangup call")
    508             return False
    509         return True
    510 
    511     def multi_incomming_call(self, pri_dut, sec_dut, ter_dut):
    512         self.log.info("Test 2 incomming calls scenario to phone.")
    513         input("Press enter to execute this testcase...")
    514         if not self.setup_multi_call(sec_dut, ter_dut, pri_dut):
    515             return False
    516         input("Press enter to hangup call 1...")
    517         if not hangup_call(self.log, sec_dut):
    518             self.log.error("Failed to hangup call")
    519             return False
    520         input("Press enter to hangup call 2...")
    521         if not hangup_call(self.log, ter_dut):
    522             self.log.error("Failed to hangup call")
    523             return False
    524         return True
    525 
    526     def multi_call_audio_routing(self, pri_dut, sec_dut, ter_dut):
    527         self.log.info(
    528             "Test 2 incomming calls scenario to phone, then test audio routing."
    529         )
    530         input("Press enter to execute this testcase...")
    531         if not self.setup_multi_call(sec_dut, ter_dut, pri_dut):
    532             return False
    533         input("Press enter to switch to earpiece...")
    534         self.log.info("Switching to earpiece.")
    535         set_audio_route(self.log, pri_dut, AUDIO_ROUTE_EARPIECE)
    536         time.sleep(self.short_timeout)
    537         if get_audio_route(self.log, pri_dut) != AUDIO_ROUTE_EARPIECE:
    538             self.log.error(
    539                 "Audio Route not set to {}".format(AUDIO_ROUTE_EARPIECE))
    540             return False
    541         input("Press enter to switch to Bluetooth...")
    542         self.log.info("Switching to Bluetooth...")
    543         set_audio_route(self.log, pri_dut, AUDIO_ROUTE_BLUETOOTH)
    544         time.sleep(self.short_timeout)
    545         if get_audio_route(self.log, pri_dut) != AUDIO_ROUTE_BLUETOOTH:
    546             self.log.error(
    547                 "Audio Route not set to {}".format(AUDIO_ROUTE_BLUETOOTH))
    548             return False
    549         input("Press enter to hangup call 1...")
    550         if not hangup_call(self.log, sec_dut):
    551             self.log.error("Failed to hangup call")
    552             return False
    553         input("Press enter to hangup call 2...")
    554         if not hangup_call(self.log, ter_dut):
    555             self.log.error("Failed to hangup call")
    556             return False
    557         return True
    558 
    559     def multi_call_swap_multiple_times(self, pri_dut, sec_dut, ter_dut):
    560         self.log.info(
    561             "Test 2 incomming calls scenario to phone, then test audio routing."
    562         )
    563         input("Press enter to execute this testcase...")
    564         if not self.setup_multi_call(sec_dut, ter_dut, pri_dut):
    565             return False
    566         input("Press enter to swap active calls...")
    567         calls = pri_dut.droid.telecomCallGetCallIds()
    568         if not swap_calls(self.log, [pri_dut, sec_dut, ter_dut], calls[0],
    569                           calls[1], 5):
    570             return False
    571         input("Press enter to hangup call 1...")
    572         if not hangup_call(self.log, sec_dut):
    573             self.log.error("Failed to hangup call")
    574             return False
    575         input("Press enter to hangup call 2...")
    576         if not hangup_call(self.log, ter_dut):
    577             self.log.error("Failed to hangup call")
    578             return False
    579         return True
    580 
    581     def multi_call_join_conference_call(self, pri_dut, sec_dut, ter_dut):
    582         self.log.info(
    583             "Test 2 incomming calls scenario to phone then join the calls.")
    584         input("Press enter to execute this testcase...")
    585         if not self.setup_multi_call(sec_dut, ter_dut, pri_dut):
    586             return False
    587         input("Press enter to join active calls...")
    588         calls = pri_dut.droid.telecomCallGetCallIds()
    589         pri_dut.droid.telecomCallJoinCallsInConf(calls[0], calls[1])
    590         time.sleep(WAIT_TIME_IN_CALL)
    591         if num_active_calls(self.log, pri_dut) != 4:
    592             self.log.error("Total number of call ids in {} is not 4.".format(
    593                 pri_dut.serial))
    594             return False
    595         input("Press enter to hangup call 1...")
    596         if not hangup_call(self.log, sec_dut):
    597             self.log.error("Failed to hangup call")
    598             return False
    599         input("Press enter to hangup call 2...")
    600         if not hangup_call(self.log, ter_dut):
    601             self.log.error("Failed to hangup call")
    602             return False
    603         return True
    604 
    605     def multi_call_join_conference_call_hangup_conf_call(
    606             self, pri_dut, sec_dut, ter_dut):
    607         self.log.info(
    608             "Test 2 incomming calls scenario to phone then join the calls, then terminate the call from the primary dut."
    609         )
    610         input("Press enter to execute this testcase...")
    611         if not self.setup_multi_call(sec_dut, ter_dut, pri_dut):
    612             return False
    613         input("Press enter to join active calls...")
    614         calls = pri_dut.droid.telecomCallGetCallIds()
    615         pri_dut.droid.telecomCallJoinCallsInConf(calls[0], calls[1])
    616         time.sleep(WAIT_TIME_IN_CALL)
    617         if num_active_calls(self.log, pri_dut) != 4:
    618             self.log.error("Total number of call ids in {} is not 4.".format(
    619                 pri_dut.serial))
    620             return False
    621         input("Press enter to hangup conf call...")
    622         if not hangup_call(self.log, pri_dut):
    623             self.log.error("Failed to hangup call")
    624             return False
    625         return True
    626 
    627     def outgoing_multi_call_join_conference_call(self, pri_dut, sec_dut,
    628                                                  ter_dut):
    629         self.log.info(
    630             "Test 2 outgoing calls scenario from phone then join the calls.")
    631         input("Press enter to execute this testcase...")
    632         outgoing_num = get_phone_number(self.log, sec_dut)
    633         if not initiate_call(self.log, pri_dut, outgoing_num):
    634             self.log.error("Failed to initiate call")
    635             return False
    636         if not wait_and_answer_call(self.log, sec_dut):
    637             self.log.error("Failed to answer call.")
    638             return False
    639         time.sleep(self.short_timeout)
    640         outgoing_num = get_phone_number(self.log, ter_dut)
    641         if not initiate_call(self.log, pri_dut, outgoing_num):
    642             self.log.error("Failed to initiate call")
    643             return False
    644         if not wait_and_answer_call(self.log, ter_dut):
    645             self.log.error("Failed to answer call.")
    646             return False
    647         input("Press enter to join active calls...")
    648         calls = pri_dut.droid.telecomCallGetCallIds()
    649         pri_dut.droid.telecomCallJoinCallsInConf(calls[0], calls[1])
    650         time.sleep(WAIT_TIME_IN_CALL)
    651         if num_active_calls(self.log, pri_dut) != 4:
    652             self.log.error("Total number of call ids in {} is not 4.".format(
    653                 pri_dut.serial))
    654             return False
    655         input("Press enter to hangup call 1...")
    656         if not hangup_call(self.log, sec_dut):
    657             self.log.error("Failed to hangup call")
    658             return False
    659         input("Press enter to hangup call 2...")
    660         if not hangup_call(self.log, ter_dut):
    661             self.log.error("Failed to hangup call")
    662             return False
    663         return True
    664 
    665     def multi_call_join_conference_call_audio_routes(self, pri_dut, sec_dut,
    666                                                      ter_dut):
    667         self.log.info(
    668             "Test 2 incomming calls scenario to phone then join the calls, then test different audio routes."
    669         )
    670         input("Press enter to execute this testcase...")
    671         if not self.setup_multi_call(sec_dut, ter_dut, pri_dut):
    672             return False
    673         input("Press enter to join active calls...")
    674         calls = pri_dut.droid.telecomCallGetCallIds()
    675         pri_dut.droid.telecomCallJoinCallsInConf(calls[0], calls[1])
    676         time.sleep(WAIT_TIME_IN_CALL)
    677         if num_active_calls(self.log, pri_dut) != 4:
    678             self.log.error("Total number of call ids in {} is not 4.".format(
    679                 pri_dut.serial))
    680             return False
    681         input("Press enter to switch to phone speaker...")
    682         self.log.info("Switching to earpiece.")
    683         set_audio_route(self.log, pri_dut, AUDIO_ROUTE_EARPIECE)
    684         time.sleep(self.short_timeout)
    685         if get_audio_route(self.log, pri_dut) != AUDIO_ROUTE_EARPIECE:
    686             self.log.error(
    687                 "Audio Route not set to {}".format(AUDIO_ROUTE_EARPIECE))
    688             return False
    689         input("Press enter to switch to Bluetooth...")
    690         self.log.info("Switching to Bluetooth...")
    691         set_audio_route(self.log, pri_dut, AUDIO_ROUTE_BLUETOOTH)
    692         time.sleep(self.short_timeout)
    693         if get_audio_route(self.log, pri_dut) != AUDIO_ROUTE_BLUETOOTH:
    694             self.log.error(
    695                 "Audio Route not set to {}".format(AUDIO_ROUTE_BLUETOOTH))
    696             return False
    697         input("Press enter to hangup conf call...")
    698         if not hangup_call(self.log, pri_dut):
    699             self.log.error("Failed to hangup call")
    700             return False
    701         return True
    702 
    703     def avrcp_play_pause(self, pri_dut):
    704         play_pause_count = 5
    705         self.log.info(
    706             "Test AVRCP play/pause {} times.".format(play_pause_count))
    707         pri_dut.adb.shell(KEYCODE_EVENT_PREVIOUS)
    708         input(
    709             "Press enter to execute this testcase when music is in the play state..."
    710         )
    711         for i in range(play_pause_count):
    712             input("Execute iteration {}?".format(i + 1))
    713             pri_dut.adb.shell(KEYCODE_EVENT_PLAY_PAUSE)
    714         self.log.info("Test should end in a paused state.")
    715         return True
    716 
    717     def avrcp_next_previous_song(self, pri_dut):
    718         self.log.info("Test AVRCP go to the next song then the previous song.")
    719         pri_dut.adb.shell(KEYCODE_EVENT_PREVIOUS)
    720         input(
    721             "Press enter to execute this testcase when music is in the play state..."
    722         )
    723         self.log.info("Hitting Next input event...")
    724         pri_dut.adb.shell(KEYCODE_EVENT_NEXT)
    725         input("Press enter to go to the previous song")
    726         pri_dut.adb.shell(KEYCODE_EVENT_PREVIOUS)
    727         pri_dut.adb.shell(KEYCODE_EVENT_PREVIOUS)
    728         self.log.info("Test should end on original song.")
    729         return True
    730 
    731     def avrcp_next_previous(self, pri_dut):
    732         self.log.info(
    733             "Test AVRCP go to the next song then the press previous after a few seconds."
    734         )
    735         pri_dut.adb.shell(KEYCODE_EVENT_PREVIOUS)
    736         input(
    737             "Press enter to execute this testcase when music is in the play state..."
    738         )
    739         self.log.info("Hitting Next input event...")
    740         pri_dut.adb.shell(KEYCODE_EVENT_NEXT)
    741         time.sleep(5)
    742         self.log.info("Hitting Previous input event...")
    743         pri_dut.adb.shell(KEYCODE_EVENT_PREVIOUS)
    744         self.log.info("Test should end on \"next\" song.")
    745         return True
    746 
    747     def avrcp_next_repetative(self, pri_dut):
    748         iterations = 10
    749         self.log.info("Test AVRCP go to the next {} times".format(iterations))
    750         pri_dut.adb.shell(KEYCODE_EVENT_PREVIOUS)
    751         input(
    752             "Press enter to execute this testcase when music is in the play state..."
    753         )
    754         for i in range(iterations):
    755             self.log.info(
    756                 "Hitting Next input event, iteration {}...".format(i + 1))
    757             pri_dut.adb.shell(KEYCODE_EVENT_NEXT)
    758             # Allow time for the carkit to update.
    759             time.sleep(1)
    760         return True
    761 
    762     def _cycle_aboslute_volume_control_helper(self, volume_step,
    763                                               android_volume_steps, pri_dut):
    764         begin_time = get_current_epoch_time()
    765         pri_dut.droid.setMediaVolume(volume_step)
    766         percentage_to_set = int((volume_step / android_volume_steps) * 100)
    767         self.log.info("Setting phone volume to {}%".format(percentage_to_set))
    768         volume_info_logcat = pri_dut.search_logcat(
    769             logcat_strings['media_playback_vol_changed'], begin_time)
    770         if len(volume_info_logcat) > 1:
    771             self.log.info("Instant response detected.")
    772             carkit_response = volume_info_logcat[-1]['log_message'].split(',')
    773             for item in carkit_response:
    774                 if " volume=" in item:
    775                     carkit_vol_response = int((
    776                         int(item.split("=")[-1]) / android_volume_steps) * 100)
    777                     self.log.info(
    778                         "Carkit set volume to {}%".format(carkit_vol_response))
    779         result = input(
    780             "Did volume change reflect properly on carkit and phone? (Y/n) "
    781         ).lower()
    782 
    783     def cycle_absolute_volume_control(self, pri_dut):
    784         result = input(
    785             "Does carkit support Absolute Volume Control? (Y/n) ").lower()
    786         if result is "n":
    787             return True
    788         android_volume_steps = 25
    789         for i in range(android_volume_steps):
    790             self._cycle_aboslute_volume_control_helper(i, android_volume_steps,
    791                                                        pri_dut)
    792         for i in reversed(range(android_volume_steps)):
    793             self._cycle_aboslute_volume_control_helper(i, android_volume_steps,
    794                                                        pri_dut)
    795         return True
    796 
    797     def cycle_battery_level(self, pri_dut):
    798         for i in range(11):
    799             level = i * 10
    800             pri_dut.shell.set_battery_level(level)
    801             question = "Phone battery level {}. Has the carkit indicator " \
    802                 "changed? (Y/n) "
    803             result = input(question.format(level)).lower()
    804 
    805     def test_voice_recognition_from_phone(self, pri_dut):
    806         result = input(
    807             "Does carkit support voice recognition (BVRA)? (Y/n) ").lower()
    808         if result is "n":
    809             return True
    810         input("Press enter to start voice recognition from phone.")
    811         self.pri_dut.droid.bluetoothHspStartVoiceRecognition(
    812             self.target_mac_address)
    813         input("Press enter to stop voice recognition from phone.")
    814         self.pri_dut.droid.bluetoothHspStopVoiceRecognition(
    815             self.target_mac_address)
    816 
    817     def test_audio_and_voice_recognition_from_phone(self, pri_dut):
    818         result = input(
    819             "Does carkit support voice recognition (BVRA)? (Y/n) ").lower()
    820         if result is "n":
    821             return True
    822         # Start playing music here
    823         input("Press enter to start voice recognition from phone.")
    824         self.pri_dut.droid.bluetoothHspStartVoiceRecognition(
    825             self.target_mac_address)
    826         input("Press enter to stop voice recognition from phone.")
    827         self.pri_dut.droid.bluetoothHspStopVoiceRecognition(
    828             self.target_mac_address)
    829         time.sleep(2)
    830         result = input("Did carkit continue music playback after? (Y/n) ")
    831