1#!/usr/bin/env python3
2#
3#   Copyright 2022 - Google
4#
5#   Licensed under the Apache License, Version 2.0 (the "License");
6#   you may not use this file except in compliance with the License.
7#   You may obtain a copy of 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,
13#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14#   See the License for the specific language governing permissions and
15#   limitations under the License.
16
17from datetime import datetime, timedelta
18import re
19import time
20from typing import Optional, Sequence
21
22from acts import signals
23from acts import tracelogger
24from acts.controllers.android_device import AndroidDevice
25from acts.utils import rand_ascii_str
26from acts.libs.proc.job import TimeoutError
27from acts.libs.utils.multithread import multithread_func
28from acts_contrib.test_utils.tel.loggers.protos.telephony_metric_pb2 import TelephonyVoiceTestResult
29from acts_contrib.test_utils.tel.loggers.telephony_metric_logger import TelephonyMetricLogger
30from acts_contrib.test_utils.tel.tel_defines import INVALID_SUB_ID
31from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_SMS_RECEIVE
32from acts_contrib.test_utils.tel.tel_defines import SimSlotInfo
33from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_ANDROID_STATE_SETTLING
34from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_IN_CALL
35from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_CELLULAR_PREFERRED
36from acts_contrib.test_utils.tel.tel_defines import YOUTUBE_PACKAGE_NAME
37from acts_contrib.test_utils.tel.tel_data_utils import active_file_download_test
38from acts_contrib.test_utils.tel.tel_data_utils import start_youtube_video
39from acts_contrib.test_utils.tel.tel_message_utils import log_messaging_screen_shot
40from acts_contrib.test_utils.tel.tel_message_utils import mms_send_receive_verify
41from acts_contrib.test_utils.tel.tel_message_utils import sms_send_receive_verify_for_subscription
42from acts_contrib.test_utils.tel.tel_ss_utils import erase_call_forwarding_by_mmi
43from acts_contrib.test_utils.tel.tel_ss_utils import set_call_forwarding_by_mmi
44from acts_contrib.test_utils.tel.tel_ss_utils import set_call_waiting
45from acts_contrib.test_utils.tel.tel_ims_utils import toggle_wfc_for_subscription
46from acts_contrib.test_utils.tel.tel_ims_utils import set_wfc_mode_for_subscription
47from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_voice_general
48from acts_contrib.test_utils.tel.tel_phone_setup_utils import phone_setup_on_rat
49from acts_contrib.test_utils.tel.tel_phone_setup_utils import wait_for_network_idle
50from acts_contrib.test_utils.tel.tel_ss_utils import three_phone_call_forwarding_short_seq
51from acts_contrib.test_utils.tel.tel_ss_utils import three_phone_call_waiting_short_seq
52from acts_contrib.test_utils.tel.tel_subscription_utils import get_default_data_sub_id
53from acts_contrib.test_utils.tel.tel_subscription_utils import get_incoming_voice_sub_id
54from acts_contrib.test_utils.tel.tel_subscription_utils import get_outgoing_message_sub_id
55from acts_contrib.test_utils.tel.tel_subscription_utils import get_outgoing_voice_sub_id
56from acts_contrib.test_utils.tel.tel_subscription_utils import get_slot_index_from_subid
57from acts_contrib.test_utils.tel.tel_subscription_utils import get_subid_from_slot_index
58from acts_contrib.test_utils.tel.tel_subscription_utils import get_subid_on_same_network_of_host_ad
59from acts_contrib.test_utils.tel.tel_subscription_utils import set_dds_on_slot
60from acts_contrib.test_utils.tel.tel_subscription_utils import set_message_subid
61from acts_contrib.test_utils.tel.tel_subscription_utils import set_subid_for_data
62from acts_contrib.test_utils.tel.tel_subscription_utils import set_voice_sub_id
63from acts_contrib.test_utils.tel.tel_test_utils import change_slot
64from acts_contrib.test_utils.tel.tel_test_utils import get_operator_name
65from acts_contrib.test_utils.tel.tel_test_utils import num_active_calls
66from acts_contrib.test_utils.tel.tel_test_utils import power_off_sim
67from acts_contrib.test_utils.tel.tel_test_utils import power_on_sim
68from acts_contrib.test_utils.tel.tel_test_utils import toggle_airplane_mode
69from acts_contrib.test_utils.tel.tel_test_utils import verify_incall_state
70from acts_contrib.test_utils.tel.tel_test_utils import verify_http_connection
71from acts_contrib.test_utils.tel.tel_voice_conf_utils import _test_ims_conference_merge_drop_second_call_from_participant
72from acts_contrib.test_utils.tel.tel_voice_conf_utils import _test_wcdma_conference_merge_drop
73from acts_contrib.test_utils.tel.tel_voice_conf_utils import _three_phone_call_mo_add_mt
74from acts_contrib.test_utils.tel.tel_voice_utils import call_setup_teardown
75from acts_contrib.test_utils.tel.tel_voice_utils import hangup_call
76from acts_contrib.test_utils.tel.tel_voice_utils import initiate_call
77from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call_on_rat
78from acts_contrib.test_utils.tel.tel_voice_utils import swap_calls
79from acts_contrib.test_utils.tel.tel_voice_utils import two_phone_call_msim_for_slot
80from acts_contrib.test_utils.tel.tel_voice_utils import wait_and_reject_call_for_subscription
81from acts_contrib.test_utils.tel.tel_wifi_utils import ensure_wifi_connected
82from acts_contrib.test_utils.tel.tel_wifi_utils import wifi_toggle_state
83
84CallResult = TelephonyVoiceTestResult.CallResult.Value
85
86
87def dsds_dds_swap_message_streaming_test(
88    log: tracelogger.TraceLogger,
89    ads: Sequence[AndroidDevice],
90    sim_slot: Sequence[SimSlotInfo],
91    test_rat: Sequence[str],
92    test_slot: Sequence[SimSlotInfo] = [
93        SimSlotInfo.SLOT_0,
94        SimSlotInfo.SLOT_1,
95        SimSlotInfo.SLOT_0],
96    init_dds: int = 0,
97    msg_type: str = "SMS",
98    direction: str = "mt",
99    streaming: bool = True,
100    expected_result: bool = True) -> bool:
101    """Make MO/MT message at specific slot in specific RAT with DDS at
102    specific slot and do the same steps after dds swap.
103
104    Args:
105        log: Logger object.
106        ads: A list of Android device objects.
107        sim_slot: a list which contains 2 slots for logical slot 0 and 1.
108            e.g. [SimSlotInfo.SLOT_0, SimSlotInfo.SLOT_1]
109        test_rat: RAT for both slots of primary device.
110        test_slot: The slot which make/receive MO/MT SMS/MMS of primary device.
111            e.g. [SimSlotInfo.SLOT_0, SimSlotInfo.SLOT_1, SimSlotInfo.SLOT_0]
112        dds_slot: Preferred data slot of primary device.
113        msg_type: SMS or MMS to send.
114        direction: The direction of message("mo" or "mt") at first.
115        streaming: True for playing Youtube before send/receive SMS/MMS and
116            False on the contrary.
117        expected_result: True or False
118
119    Returns:
120        TestFailure if failed.
121    """
122    result = True
123    to_change_slot = True
124    dds_slot = [sim.value[0] for sim in sim_slot]
125    if init_dds != dds_slot[0]:
126        dds_slot = dds_slot[::-1]
127        dds_slot.append(dds_slot[0])
128    else:
129        dds_slot.append(init_dds)
130
131    for test_slot, dds_slot in zip(test_slot, dds_slot):
132        ads[0].log.info("test_slot: %d, dds_slot: %d", test_slot, dds_slot)
133        result = result and dsds_message_streaming_test(
134            log=log,
135            ads=ads,
136            sim_slot=sim_slot,
137            test_rat=test_rat,
138            test_slot=test_slot,
139            dds_slot=dds_slot,
140            msg_type=msg_type,
141            direction=direction,
142            to_change_slot=to_change_slot,
143            streaming=streaming,
144            expected_result=expected_result
145        )
146        to_change_slot = False
147        if not result:
148            return result
149
150    return result
151
152
153def dsds_dds_swap_call_streaming_test(
154    log: tracelogger.TraceLogger,
155    tel_logger: TelephonyMetricLogger.for_test_case,
156    ads: Sequence[AndroidDevice],
157    sim_slot: Sequence[SimSlotInfo],
158    test_rat: Sequence[str],
159    init_dds: int = 0,
160    test_slot: Sequence[SimSlotInfo] = [
161        SimSlotInfo.SLOT_0,
162        SimSlotInfo.SLOT_1,
163        SimSlotInfo.SLOT_0],
164    direction: Optional[str] = None,
165    duration: int = WAIT_TIME_IN_CALL,
166    streaming: bool = True,
167    is_airplane_mode: bool = False,
168    wfc_mode: Sequence[str] = [
169        WFC_MODE_CELLULAR_PREFERRED,
170        WFC_MODE_CELLULAR_PREFERRED],
171    wifi_network_ssid: Optional[str] = None,
172    wifi_network_pass: Optional[str] = None,
173    turn_off_wifi_in_the_end: bool = False,
174    turn_off_airplane_mode_in_the_end: bool = False) -> bool:
175    """Make MO/MT call at specific slot in specific RAT with DDS at specific
176    slot and do the same steps after dds swap.
177
178    Args:
179        log: Logger object.
180        tel_logger: Logger object for telephony proto.
181        ads: A list of Android device objects.
182        sim_slot: a list which contains 2 slots for logical slot 0 and 1.
183            e.g. [SimSlotInfo.SLOT_0, SimSlotInfo.SLOT_1]
184        test_rat: RAT for both slots of primary device.
185        init_dds: Initial preferred data slot of primary device.
186        test_slot: The slot which make/receive MO/MT call of primary device.
187            e.g. [SimSlotInfo.SLOT_0, SimSlotInfo.SLOT_1, SimSlotInfo.SLOT_0]
188        direction: The direction of call("mo" or "mt").
189        duration: In call time of voice call.
190        streaming: True for playing Youtube and False on the contrary.
191        is_airplane_mode: True or False for WFC setup
192        wfc_mode: Cellular preferred or Wi-Fi preferred.
193        wifi_network_ssid: SSID of Wi-Fi AP.
194        wifi_network_pass: Password of Wi-Fi AP SSID.
195        turn_off_wifi_in_the_end: True to turn off Wi-Fi and False not to turn
196            off Wi-Fi in the end of the function.
197        turn_off_airplane_mode_in_the_end: True to turn off airplane mode and
198            False not to turn off airplane mode in the end of the function.
199
200    Returns:
201        TestFailure if failed.
202    """
203    result = True
204    to_change_slot = True
205    dds_slot = [sim.value[0] for sim in sim_slot]
206    if init_dds != dds_slot[0]:
207        dds_slot = dds_slot[::-1]
208        dds_slot.append(dds_slot[0])
209    else:
210        dds_slot.append(init_dds)
211
212    for test_slot, dds_slot in zip(test_slot, dds_slot):
213        ads[0].log.info("test_slot: %d, dds_slot: %d", test_slot, dds_slot)
214        result = result and dsds_call_streaming_test(
215            log=log,
216            tel_logger=tel_logger,
217            ads=ads,
218            sim_slot=sim_slot,
219            test_rat=test_rat,
220            dds_slot=dds_slot,
221            test_slot=test_slot,
222            direction=direction,
223            duration=duration,
224            to_change_slot=to_change_slot,
225            streaming=streaming,
226            is_airplane_mode=is_airplane_mode,
227            wfc_mode=wfc_mode,
228            wifi_network_ssid=wifi_network_ssid,
229            wifi_network_pass=wifi_network_pass,
230            turn_off_wifi_in_the_end=turn_off_wifi_in_the_end,
231            turn_off_airplane_mode_in_the_end=turn_off_airplane_mode_in_the_end
232        )
233        to_change_slot = False
234        if not result:
235            return result
236
237    return result
238
239
240def dsds_call_streaming_test(
241    log: tracelogger.TraceLogger,
242    tel_logger: TelephonyMetricLogger.for_test_case,
243    ads: Sequence[AndroidDevice],
244    sim_slot: Sequence[SimSlotInfo],
245    test_rat: Sequence[str],
246    dds_slot: int,
247    test_slot: Optional[SimSlotInfo] = None,
248    direction: Optional[str] = None,
249    duration: int = WAIT_TIME_IN_CALL,
250    to_change_slot: bool = True,
251    streaming: bool = True,
252    is_airplane_mode: bool = False,
253    wfc_mode: Sequence[str] = [
254        WFC_MODE_CELLULAR_PREFERRED,
255        WFC_MODE_CELLULAR_PREFERRED],
256    wifi_network_ssid: Optional[str] = None,
257    wifi_network_pass: Optional[str] = None,
258    turn_off_wifi_in_the_end: bool = False,
259    turn_off_airplane_mode_in_the_end: bool = False) -> bool:
260    """Make MO/MT call at specific slot in specific RAT with DDS at specific
261    slot for the given time.
262
263    Args:
264        log: Logger object.
265        tel_logger: Logger object for telephony proto.
266        ads: A list of Android device objects.
267        sim_slot: a list which contains 2 slots for logical slot 0 and 1.
268            e.g. [SimSlotInfo.SLOT_0, SimSlotInfo.SLOT_1]
269        test_rat: RAT for both slots of primary device.
270            e.g. ["5g_volte", "5g_volte"]
271        dds_slot: Preferred data slot of primary device.
272                  0 for pSIM,
273                  1 for eSIM port 0,
274                  2 for eSIM port 1.
275        test_slot: The slot which make/receive MO/MT call of primary device.
276            e.g. SimSlotInfo.SLOT_0 for pSIM
277                 SimSlotInfo.SLOT_1 for eSIM port 0
278                 SimSlotInfo.SLOT_2 for eSIM port 1
279        direction: The direction of call("mo" or "mt").
280        duration: In call time of voice call.
281        to_change_slot: True to change slot, False otherwise.
282        streaming: True for playing Youtube and False on the contrary.
283        is_airplane_mode: True or False for WFC setup
284        wfc_mode: Cellular preferred or Wi-Fi preferred.
285        wifi_network_ssid: SSID of Wi-Fi AP.
286        wifi_network_pass: Password of Wi-Fi AP SSID.
287        turn_off_wifi_in_the_end: True to turn off Wi-Fi and False not to turn
288            off Wi-Fi in the end of the function.
289        turn_off_airplane_mode_in_the_end: True to turn off airplane mode and
290            False not to turn off airplane mode in the end of the function.
291
292    Returns:
293        TestFailure if failed.
294    """
295    rat_dict = dict((x, y) for x, y in list(zip(sim_slot, test_rat)))
296    wfc_mode_dict = dict((x, y) for x, y in list(zip(sim_slot, wfc_mode)))
297
298    if to_change_slot:
299        log.info("Step 0: Switch to specific SIM slot combination.")
300        try:
301            change_slot(ads[0], sim_slot)
302        except TimeoutError:
303            ads[0].log.warning("Device not support MEP.")
304
305    log.info("Step 1: Switch DDS.")
306    if not set_dds_on_slot(ads[0], dds_slot):
307        ads[0].log.error(
308            "Failed to set DDS at slot %s on %s",(dds_slot, ads[0].serial))
309        return False
310
311    log.info("Step 2: Check HTTP connection after DDS switch.")
312    if not verify_http_connection(log, ads[0]):
313        ads[0].log.error("Failed to verify http connection.")
314        return False
315    else:
316        ads[0].log.info("Verify http connection successfully.")
317
318    log.info("Step 3: Set up phones in desired RAT.")
319    if test_slot:
320        non_test_slot = list(set(sim_slot) - set([test_slot]))[0]
321    if direction == "mo":
322        # setup voice subid on primary device.
323        ad_mo = ads[0]
324        mo_sub_id = get_subid_from_slot_index(log, ad_mo, test_slot.value[0])
325        if mo_sub_id == INVALID_SUB_ID:
326            ad_mo.log.warning("Failed to get sub ID at slot %s.", test_slot.value[0])
327            return False
328        mo_other_sub_id = get_subid_from_slot_index(
329            log, ad_mo, non_test_slot.value[0])
330        sub_id_list = [mo_sub_id, mo_other_sub_id]
331        set_voice_sub_id(ad_mo, mo_sub_id)
332        ad_mo.log.info("Sub ID for outgoing call at slot %s: %s", test_slot.value[0],
333        get_outgoing_voice_sub_id(ad_mo))
334
335        # setup voice subid on secondary device.
336        ad_mt = ads[1]
337        _, mt_sub_id, _ = get_subid_on_same_network_of_host_ad(ads)
338        if mt_sub_id == INVALID_SUB_ID:
339            ad_mt.log.warning("Failed to get sub ID at default voice slot.")
340            return False
341        mo_slot = test_slot.value[0]
342        mt_slot = get_slot_index_from_subid(ad_mt, mt_sub_id)
343        set_voice_sub_id(ad_mt, mt_sub_id)
344        ad_mt.log.info("Sub ID for incoming call at slot %s: %s", mt_slot,
345        get_outgoing_voice_sub_id(ad_mt))
346
347        # setup the rat on non-test slot(primary device).
348        phone_setup_on_rat(
349            log,
350            ad_mo,
351            rat_dict[non_test_slot],
352            mo_other_sub_id,
353            is_airplane_mode,
354            wfc_mode_dict[non_test_slot],
355            wifi_network_ssid,
356            wifi_network_pass)
357        # assign phone setup argv for test slot.
358        mo_phone_setup_func_argv = (
359            log,
360            ad_mo,
361            rat_dict[test_slot],
362            mo_sub_id,
363            is_airplane_mode,
364            wfc_mode_dict[test_slot],
365            wifi_network_ssid,
366            wifi_network_pass)
367        verify_caller_func = is_phone_in_call_on_rat(
368            log, ad_mo, rat_dict[test_slot], only_return_fn=True)
369        mt_phone_setup_func_argv = (log, ad_mt, 'general')
370        verify_callee_func = is_phone_in_call_on_rat(
371            log, ad_mt, 'general', only_return_fn=True)
372    elif direction == "mt":
373        # setup voice subid on primary device.
374        ad_mt = ads[0]
375        mt_sub_id = get_subid_from_slot_index(log, ad_mt, test_slot.value[0])
376        if mt_sub_id == INVALID_SUB_ID:
377            ad_mt.log.warning("Failed to get sub ID at slot %s.", test_slot.value[0])
378            return False
379        mt_other_sub_id = get_subid_from_slot_index(
380            log, ad_mt, non_test_slot.value[0])
381        sub_id_list = [mt_sub_id, mt_other_sub_id]
382        set_voice_sub_id(ad_mt, mt_sub_id)
383        ad_mt.log.info("Sub ID for incoming call at slot %s: %s", test_slot.value[0],
384        get_outgoing_voice_sub_id(ad_mt))
385
386        # setup voice subid on secondary device.
387        ad_mo = ads[1]
388        _, mo_sub_id, _ = get_subid_on_same_network_of_host_ad(ads)
389        if mo_sub_id == INVALID_SUB_ID:
390            ad_mo.log.warning("Failed to get sub ID at default voice slot.")
391            return False
392        mo_slot = get_slot_index_from_subid(ad_mo, mo_sub_id)
393        mt_slot = test_slot.value[0]
394        set_voice_sub_id(ad_mo, mo_sub_id)
395        ad_mo.log.info("Sub ID for outgoing call at slot %s: %s", mo_slot,
396        get_outgoing_voice_sub_id(ad_mo))
397
398        # setup the rat on non-test slot(primary device).
399        phone_setup_on_rat(
400            log,
401            ad_mt,
402            rat_dict[non_test_slot],
403            mt_other_sub_id,
404            is_airplane_mode,
405            wfc_mode_dict[non_test_slot],
406            wifi_network_ssid,
407            wifi_network_pass)
408        # assign phone setup argv for test slot.
409        mt_phone_setup_func_argv = (
410            log,
411            ad_mt,
412            rat_dict[test_slot],
413            mt_sub_id,
414            is_airplane_mode,
415            wfc_mode_dict[test_slot],
416            wifi_network_ssid,
417            wifi_network_pass)
418        verify_callee_func = is_phone_in_call_on_rat(
419            log, ad_mt, rat_dict[test_slot], only_return_fn=True)
420        mo_phone_setup_func_argv = (log, ad_mo, 'general')
421        verify_caller_func = is_phone_in_call_on_rat(
422            log, ad_mo, 'general', only_return_fn=True)
423    else:
424        return True
425
426    tasks = [(phone_setup_on_rat, mo_phone_setup_func_argv),
427             (phone_setup_on_rat, mt_phone_setup_func_argv)]
428    if not multithread_func(log, tasks):
429        log.error("Phone Failed to Set Up Properly.")
430        tel_logger.set_result(CallResult("CALL_SETUP_FAILURE"))
431        raise signals.TestFailure("Failed",
432            extras={"fail_reason": "Phone Failed to Set Up Properly."})
433    if streaming:
434        log.info("Step 4-0: Start Youtube streaming.")
435        if not start_youtube_video(ads[0]):
436            raise signals.TestFailure("Failed",
437                extras={"fail_reason": "Fail to bring up youtube video."})
438        time.sleep(10)
439
440    log.info("Step 4: Make voice call.")
441    result = call_setup_teardown(log,
442                                 ad_mo,
443                                 ad_mt,
444                                 ad_hangup=ad_mo,
445                                 verify_caller_func=verify_caller_func,
446                                 verify_callee_func=verify_callee_func,
447                                 wait_time_in_call=duration)
448    tel_logger.set_result(result.result_value)
449
450    if not result:
451        log.error(
452            "Failed to make %s call from %s slot %s to %s slot %s",
453                direction, ad_mo.serial, mo_slot, ad_mt.serial, mt_slot)
454        raise signals.TestFailure("Failed",
455            extras={"fail_reason": str(result.result_value)})
456
457    log.info("Step 5: Verify RAT and HTTP connection.")
458    # For the tese cases related to WFC in which airplane mode will be turned
459    # off in the end.
460    if turn_off_airplane_mode_in_the_end:
461        log.info("Step 5-1: Turning off airplane mode......")
462        if not toggle_airplane_mode(log, ads[0], False):
463            ads[0].log.error('Failed to toggle off airplane mode.')
464
465    # For the tese cases related to WFC in which Wi-Fi will be turned off in the
466    # end.
467    rat_list = [rat_dict[test_slot], rat_dict[non_test_slot]]
468
469    if turn_off_wifi_in_the_end:
470        log.info("Step 5-2: Turning off Wi-Fi......")
471        if not wifi_toggle_state(log, ads[0], False):
472            ads[0].log.error('Failed to toggle off Wi-Fi.')
473            return False
474
475        for index, value in enumerate(rat_list):
476            if value == '5g_wfc':
477                rat_list[index] = '5g'
478            elif value == 'wfc':
479                rat_list[index] = '4g'
480
481    for rat, sub_id in zip(rat_list, sub_id_list):
482        if not wait_for_network_idle(log, ads[0], rat, sub_id):
483            raise signals.TestFailure(
484                "Failed",
485                extras={
486                    "fail_reason": "Idle state of sub ID %s does not match the "
487                    "given RAT %s." % (sub_id, rat)})
488
489    if not verify_http_connection(log, ads[0]):
490        ads[0].log.error("Failed to verify http connection.")
491        return False
492    else:
493        ads[0].log.info("Verify http connection successfully.")
494
495    if streaming:
496        ads[0].force_stop_apk(YOUTUBE_PACKAGE_NAME)
497
498    return True
499
500
501def dsds_voice_call_test(
502        log,
503        tel_logger,
504        ads,
505        mo_slot,
506        mt_slot,
507        dds,
508        mo_rat=["", ""],
509        mt_rat=["", ""],
510        call_direction="mo",
511        is_airplane_mode=False,
512        wfc_mode=[
513            WFC_MODE_CELLULAR_PREFERRED,
514            WFC_MODE_CELLULAR_PREFERRED],
515        wifi_network_ssid=None,
516        wifi_network_pass=None,
517        turn_off_wifi_in_the_end=False,
518        turn_off_airplane_mode_in_the_end=False):
519    """Make MO/MT voice call at specific slot in specific RAT with DDS at
520    specific slot.
521
522    Test step:
523    1. Get sub IDs of specific slots of both MO and MT devices.
524    2. Switch DDS to specific slot.
525    3. Check HTTP connection after DDS switch.
526    4. Set up phones in desired RAT.
527    5. Make voice call.
528    6. Turn off airplane mode if necessary.
529    7. Turn off Wi-Fi if necessary.
530    8. Verify RAT and HTTP connection.
531
532    Args:
533        log: logger object
534        tel_logger: logger object for telephony proto
535        ads: list of android devices
536        mo_slot: Slot making MO call (0 or 1)
537        mt_slot: Slot receiving MT call (0 or 1)
538        dds: Preferred data slot
539        mo_rat: RAT for both slots of MO device
540        mt_rat: RAT for both slots of MT device
541        call_direction: "mo" or "mt"
542        is_airplane_mode: True or False for WFC setup
543        wfc_mode: Cellular preferred or Wi-Fi preferred.
544        wifi_network_ssid: SSID of Wi-Fi AP
545        wifi_network_pass: Password of Wi-Fi AP SSID
546        turn_off_wifi_in_the_end: True to turn off Wi-Fi and False not to turn
547            off Wi-Fi in the end of the function.
548        turn_off_airplane_mode_in_the_end: True to turn off airplane mode and
549            False not to turn off airplane mode in the end of the function.
550
551    Returns:
552        TestFailure if failed.
553    """
554    if not toggle_airplane_mode(log, ads[0], False):
555        ads[0].log.error("Failed to disable airplane mode.")
556        return False
557
558    if call_direction == "mo":
559        ad_mo = ads[0]
560        ad_mt = ads[1]
561    else:
562        ad_mo = ads[1]
563        ad_mt = ads[0]
564
565    if mo_slot is not None:
566        mo_sub_id = get_subid_from_slot_index(log, ad_mo, mo_slot)
567        if mo_sub_id == INVALID_SUB_ID:
568            ad_mo.log.warning("Failed to get sub ID ar slot %s.", mo_slot)
569            return False
570        mo_other_sub_id = get_subid_from_slot_index(
571            log, ad_mo, 1-mo_slot)
572        set_voice_sub_id(ad_mo, mo_sub_id)
573    else:
574        _, mo_sub_id, _ = get_subid_on_same_network_of_host_ad(ads)
575        if mo_sub_id == INVALID_SUB_ID:
576            ad_mo.log.warning("Failed to get sub ID ar slot %s.", mo_slot)
577            return False
578        mo_slot = "auto"
579        set_voice_sub_id(ad_mo, mo_sub_id)
580    ad_mo.log.info("Sub ID for outgoing call at slot %s: %s",
581        mo_slot, get_outgoing_voice_sub_id(ad_mo))
582
583    if mt_slot is not None:
584        mt_sub_id = get_subid_from_slot_index(log, ad_mt, mt_slot)
585        if mt_sub_id == INVALID_SUB_ID:
586            ad_mt.log.warning("Failed to get sub ID at slot %s.", mt_slot)
587            return False
588        mt_other_sub_id = get_subid_from_slot_index(
589            log, ad_mt, 1-mt_slot)
590        set_voice_sub_id(ad_mt, mt_sub_id)
591    else:
592        _, mt_sub_id, _ = get_subid_on_same_network_of_host_ad(ads)
593        if mt_sub_id == INVALID_SUB_ID:
594            ad_mt.log.warning("Failed to get sub ID at slot %s.", mt_slot)
595            return False
596        mt_slot = "auto"
597        set_voice_sub_id(ad_mt, mt_sub_id)
598    ad_mt.log.info("Sub ID for incoming call at slot %s: %s", mt_slot,
599        get_incoming_voice_sub_id(ad_mt))
600
601    log.info("Step 1: Switch DDS.")
602    if not set_dds_on_slot(ads[0], dds):
603        log.error(
604            "Failed to set DDS at slot %s on %s",(dds, ads[0].serial))
605        return False
606
607    log.info("Step 2: Check HTTP connection after DDS switch.")
608    if not verify_http_connection(log, ads[0]):
609        log.error("Failed to verify http connection.")
610        return False
611    else:
612        log.info("Verify http connection successfully.")
613
614    log.info("Step 3: Set up phones in desired RAT.")
615    if mo_slot == 0 or mo_slot == 1:
616        phone_setup_on_rat(
617            log,
618            ad_mo,
619            mo_rat[1-mo_slot],
620            mo_other_sub_id,
621            is_airplane_mode,
622            wfc_mode[1-mo_slot],
623            wifi_network_ssid,
624            wifi_network_pass)
625
626        mo_phone_setup_func_argv = (
627            log,
628            ad_mo,
629            mo_rat[mo_slot],
630            mo_sub_id,
631            is_airplane_mode,
632            wfc_mode[mo_slot],
633            wifi_network_ssid,
634            wifi_network_pass)
635
636        is_mo_in_call = is_phone_in_call_on_rat(
637            log, ad_mo, mo_rat[mo_slot], only_return_fn=True)
638    else:
639        mo_phone_setup_func_argv = (log, ad_mo, 'general')
640        is_mo_in_call = is_phone_in_call_on_rat(
641            log, ad_mo, 'general', only_return_fn=True)
642
643    if mt_slot == 0 or mt_slot == 1:
644        phone_setup_on_rat(
645            log,
646            ad_mt,
647            mt_rat[1-mt_slot],
648            mt_other_sub_id,
649            is_airplane_mode,
650            wfc_mode[1-mt_slot],
651            wifi_network_ssid,
652            wifi_network_pass)
653
654        mt_phone_setup_func_argv = (
655            log,
656            ad_mt,
657            mt_rat[mt_slot],
658            mt_sub_id,
659            is_airplane_mode,
660            wfc_mode[mt_slot],
661            wifi_network_ssid,
662            wifi_network_pass)
663
664        is_mt_in_call = is_phone_in_call_on_rat(
665            log, ad_mt, mt_rat[mt_slot], only_return_fn=True)
666    else:
667        mt_phone_setup_func_argv = (log, ad_mt, 'general')
668        is_mt_in_call = is_phone_in_call_on_rat(
669            log, ad_mt, 'general', only_return_fn=True)
670
671    tasks = [(phone_setup_on_rat, mo_phone_setup_func_argv),
672                (phone_setup_on_rat, mt_phone_setup_func_argv)]
673    if not multithread_func(log, tasks):
674        log.error("Phone Failed to Set Up Properly.")
675        tel_logger.set_result(CallResult("CALL_SETUP_FAILURE"))
676        raise signals.TestFailure("Failed",
677            extras={"fail_reason": "Phone Failed to Set Up Properly."})
678
679    log.info("Step 4: Make voice call.")
680    result = two_phone_call_msim_for_slot(
681        log,
682        ad_mo,
683        get_slot_index_from_subid(ad_mo, mo_sub_id),
684        None,
685        is_mo_in_call,
686        ad_mt,
687        get_slot_index_from_subid(ad_mt, mt_sub_id),
688        None,
689        is_mt_in_call)
690
691    tel_logger.set_result(result.result_value)
692
693    if not result:
694        log.error(
695            "Failed to make MO call from %s slot %s to %s slot %s",
696                ad_mo.serial, mo_slot, ad_mt.serial, mt_slot)
697        raise signals.TestFailure("Failed",
698            extras={"fail_reason": str(result.result_value)})
699
700    log.info("Step 5: Verify RAT and HTTP connection.")
701    if call_direction == "mo":
702        rat_list = [mo_rat[mo_slot], mo_rat[1-mo_slot]]
703        sub_id_list = [mo_sub_id, mo_other_sub_id]
704    else:
705        rat_list = [mt_rat[mt_slot], mt_rat[1-mt_slot]]
706        sub_id_list = [mt_sub_id, mt_other_sub_id]
707
708    # For the tese cases related to WFC in which airplane mode will be turned
709    # off in the end.
710    if turn_off_airplane_mode_in_the_end:
711        log.info("Step 5-1: Turning off airplane mode......")
712        if not toggle_airplane_mode(log, ads[0], False):
713            ads[0].log.error('Failed to toggle off airplane mode.')
714
715    # For the tese cases related to WFC in which Wi-Fi will be turned off in the
716    # end.
717    if turn_off_wifi_in_the_end:
718        log.info("Step 5-2: Turning off Wi-Fi......")
719        if not wifi_toggle_state(log, ads[0], False):
720            ads[0].log.error('Failed to toggle off Wi-Fi.')
721            return False
722
723        for index, value in enumerate(rat_list):
724            if value == '5g_wfc':
725                rat_list[index] = '5g'
726            elif value == 'wfc':
727                rat_list[index] = '4g'
728
729    for rat, sub_id in zip(rat_list, sub_id_list):
730        if not wait_for_network_idle(log, ads[0], rat, sub_id):
731            raise signals.TestFailure(
732                "Failed",
733                extras={
734                    "fail_reason": "Idle state of sub ID %s does not match the "
735                    "given RAT %s." % (sub_id, rat)})
736
737
738def dsds_message_streaming_test(
739    log: tracelogger.TraceLogger,
740    ads: Sequence[AndroidDevice],
741    sim_slot: Sequence[SimSlotInfo],
742    test_rat: Sequence[str],
743    test_slot: SimSlotInfo,
744    dds_slot: int,
745    msg_type: str = "SMS",
746    direction: str = "mt",
747    to_change_slot: bool = True,
748    streaming: bool = True,
749    expected_result: bool = True) -> bool:
750    """Make MO or MT SMS/MMS at specific slot in specific RAT with DDS at
751    specific slot.
752
753    Test step:
754    1. Get sub IDs of specific slots of both MO and MT devices.
755    2. Switch DDS to specific slot.
756    3. Check HTTP connection after DDS switch.
757    4. Set up phones in desired RAT.
758    5. Receive and Send SMS/MMS.
759
760    Args:
761        log: Logger object.
762        ads: A list of Android device objects.
763        sim_slot: a list which contains 2 slots for logical slot 0 and 1.
764            e.g. [SimSlotInfo.SLOT_0, SimSlotInfo.SLOT_1]
765        test_rat: RAT for both slots of primary device.
766            e.g. ["5g_volte", "5g_volte"]
767        test_slot: The slot which make/receive MO/MT call of primary device.
768            e.g. SimSlotInfo.SLOT_0 for pSIM
769                 SimSlotInfo.SLOT_1 for eSIM port 0
770                 SimSlotInfo.SLOT_2 for eSIM port 1
771        dds_slot: Preferred data slot of primary device.
772                  0 for pSIM,
773                  1 for eSIM port 0,
774                  2 for eSIM port 1.
775        msg_type: SMS or MMS to send.
776        direction: The direction of message("mo" or "mt") at first.
777        to_change_slot: True to change slot, False otherwise.
778        streaming: True for playing Youtube before send/receive SMS/MMS and
779            False on the contrary.
780        expected_result: True or False
781
782    Returns:
783        TestFailure if failed.
784    """
785    rat_dict = dict((x, y) for x, y in list(zip(sim_slot, test_rat)))
786
787    if to_change_slot:
788        log.info("Step 0: Switch to specific SIM slot combination.")
789        try:
790            change_slot(ads[0], sim_slot)
791        except TimeoutError:
792            ads[0].log.warning("Device not support MEP.")
793
794    log.info("Step 1: Switch DDS.")
795    if not set_dds_on_slot(ads[0], dds_slot):
796        ads[0].log.error(
797            "Failed to set DDS at slot %s on %s",(dds_slot, ads[0].serial))
798        return False
799
800    log.info("Step 2: Check HTTP connection after DDS switch.")
801    if not verify_http_connection(log, ads[0]):
802        ads[0].log.error("Failed to verify http connection.")
803        return False
804    else:
805        ads[0].log.info("Verify http connection successfully.")
806
807    log.info("Step 3: Set up phones in desired RAT.")
808    non_test_slot = list(set(sim_slot) - set([test_slot]))[0]
809    if direction == "mo":
810        # setup message subid on primary device.
811        ad_mo = ads[0]
812        mo_sub_id = get_subid_from_slot_index(log, ad_mo, test_slot.value[0])
813        if mo_sub_id == INVALID_SUB_ID:
814            ad_mo.log.warning("Failed to get sub ID at slot %s.", test_slot.value[0])
815            return False
816        mo_other_sub_id = get_subid_from_slot_index(
817            log, ad_mo, non_test_slot.value[0])
818        sub_id_list = [mo_sub_id, mo_other_sub_id]
819        set_message_subid(ad_mo, mo_sub_id)
820        ad_mo.log.info("Sub ID for outgoing call at slot %s: %s", test_slot.value[0],
821            get_outgoing_message_sub_id(ad_mo))
822
823        # setup message subid on secondary device.
824        ad_mt = ads[1]
825        _, mt_sub_id, _ = get_subid_on_same_network_of_host_ad(ads, type="sms")
826        if mt_sub_id == INVALID_SUB_ID:
827            ad_mt.log.warning("Failed to get sub ID at default voice slot.")
828            return False
829        mt_slot = get_slot_index_from_subid(ad_mt, mt_sub_id)
830        set_message_subid(ad_mt, mt_sub_id)
831        ad_mt.log.info("Sub ID for incoming call at slot %s: %s", mt_slot,
832            get_outgoing_message_sub_id(ad_mt))
833
834        # setup the rat on non-test slot(primary device).
835        phone_setup_on_rat(
836            log,
837            ad_mo,
838            rat_dict[non_test_slot],
839            mo_other_sub_id)
840        # assign phone setup argv for test slot.
841        mo_phone_setup_func_argv = (
842            log,
843            ad_mo,
844            rat_dict[test_slot],
845            mo_sub_id)
846        mt_phone_setup_func_argv = (log, ad_mt, 'general')
847    else:
848        # setup message subid on primary device.
849        ad_mt = ads[0]
850        mt_sub_id = get_subid_from_slot_index(log, ad_mt, test_slot.value[0])
851        if mt_sub_id == INVALID_SUB_ID:
852            ad_mt.log.warning("Failed to get sub ID at slot %s.", test_slot.value[0])
853            return False
854        mt_other_sub_id = get_subid_from_slot_index(
855            log, ad_mt, non_test_slot.value[0])
856        sub_id_list = [mt_sub_id, mt_other_sub_id]
857        set_message_subid(ad_mt, mt_sub_id)
858        ad_mt.log.info("Sub ID for incoming call at slot %s: %s", test_slot.value[0],
859            get_outgoing_message_sub_id(ad_mt))
860
861        # setup message subid on secondary device.
862        ad_mo = ads[1]
863        _, mo_sub_id, _ = get_subid_on_same_network_of_host_ad(ads, type="sms")
864        if mo_sub_id == INVALID_SUB_ID:
865            ad_mo.log.warning("Failed to get sub ID at default voice slot.")
866            return False
867        mo_slot = get_slot_index_from_subid(ad_mo, mo_sub_id)
868        set_message_subid(ad_mo, mo_sub_id)
869        ad_mo.log.info("Sub ID for outgoing call at slot %s: %s", mo_slot,
870            get_outgoing_message_sub_id(ad_mo))
871
872        # setup the rat on non-test slot(primary device).
873        phone_setup_on_rat(
874            log,
875            ad_mt,
876            rat_dict[non_test_slot],
877            mt_other_sub_id)
878        # assign phone setup argv for test slot.
879        mt_phone_setup_func_argv = (
880            log,
881            ad_mt,
882            rat_dict[test_slot],
883            mt_sub_id)
884        mo_phone_setup_func_argv = (log, ad_mo, 'general')
885
886    tasks = [(phone_setup_on_rat, mo_phone_setup_func_argv),
887             (phone_setup_on_rat, mt_phone_setup_func_argv)]
888    if not multithread_func(log, tasks):
889        log.error("Phone Failed to Set Up Properly.")
890        raise signals.TestFailure("Failed",
891            extras={"fail_reason": "Phone Failed to Set Up Properly."})
892    time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
893
894    if streaming:
895        log.info("Step 4-0: Start Youtube streaming.")
896        if not start_youtube_video(ads[0]):
897            raise signals.TestFailure("Failed",
898                extras={"fail_reason": "Fail to bring up youtube video."})
899        time.sleep(10)
900
901    log.info("Step 4: Send %s.", msg_type)
902    if msg_type == "MMS":
903        for ad, current_data_sub_id, current_msg_sub_id in [
904            [ ads[0],
905                get_default_data_sub_id(ads[0]),
906                get_outgoing_message_sub_id(ads[0]) ],
907            [ ads[1],
908                get_default_data_sub_id(ads[1]),
909                get_outgoing_message_sub_id(ads[1]) ]]:
910            if current_data_sub_id != current_msg_sub_id:
911                ad.log.warning(
912                    "Current data sub ID (%s) does not match message"
913                    " sub ID (%s). MMS should NOT be sent.",
914                    current_data_sub_id,
915                    current_msg_sub_id)
916                expected_result = False
917
918    result = msim_message_test(log, ad_mo, ad_mt, mo_sub_id, mt_sub_id,
919        msg=msg_type, expected_result=expected_result)
920
921    if not result:
922        log_messaging_screen_shot(ad_mo, test_name="%s_tx" % msg_type)
923        log_messaging_screen_shot(ad_mt, test_name="%s_rx" % msg_type)
924
925    log.info("Step 5: Verify RAT and HTTP connection.")
926    rat_list = [rat_dict[test_slot], rat_dict[non_test_slot]]
927    for rat, sub_id in zip(rat_list, sub_id_list):
928        if not wait_for_network_idle(log, ads[0], rat, sub_id):
929            raise signals.TestFailure(
930                "Failed",
931                extras={
932                    "fail_reason": "Idle state of sub ID %s does not match the "
933                    "given RAT %s." % (sub_id, rat)})
934
935    if streaming:
936        ads[0].force_stop_apk(YOUTUBE_PACKAGE_NAME)
937
938    return result
939
940
941def dsds_message_test(
942        log,
943        ads,
944        mo_slot,
945        mt_slot,
946        dds_slot,
947        msg="SMS",
948        mo_rat=["", ""],
949        mt_rat=["", ""],
950        direction="mo",
951        streaming=False,
952        expected_result=True):
953    """Make MO/MT SMS/MMS at specific slot in specific RAT with DDS at
954    specific slot.
955
956    Test step:
957    1. Get sub IDs of specific slots of both MO and MT devices.
958    2. Switch DDS to specific slot.
959    3. Check HTTP connection after DDS switch.
960    4. Set up phones in desired RAT.
961    5. Send SMS/MMS.
962
963    Args:
964        mo_slot: Slot sending MO SMS (0 or 1)
965        mt_slot: Slot receiving MT SMS (0 or 1)
966        dds_slot: Preferred data slot
967        mo_rat: RAT for both slots of MO device
968        mt_rat: RAT for both slots of MT device
969        direction: "mo" or "mt"
970        streaming: True for playing Youtube before send/receive SMS/MMS and
971            False on the contrary.
972        expected_result: True or False
973
974    Returns:
975        TestFailure if failed.
976    """
977    if direction == "mo":
978        ad_mo = ads[0]
979        ad_mt = ads[1]
980    else:
981        ad_mo = ads[1]
982        ad_mt = ads[0]
983
984    if mo_slot is not None:
985        mo_sub_id = get_subid_from_slot_index(log, ad_mo, mo_slot)
986        if mo_sub_id == INVALID_SUB_ID:
987            ad_mo.log.warning("Failed to get sub ID at slot %s.", mo_slot)
988            return False
989        mo_other_sub_id = get_subid_from_slot_index(
990            log, ad_mo, 1-mo_slot)
991        set_message_subid(ad_mo, mo_sub_id)
992    else:
993        _, mo_sub_id, _ = get_subid_on_same_network_of_host_ad(
994            ads, type="sms")
995        if mo_sub_id == INVALID_SUB_ID:
996            ad_mo.log.warning("Failed to get sub ID at slot %s.", mo_slot)
997            return False
998        mo_slot = "auto"
999        set_message_subid(ad_mo, mo_sub_id)
1000        if msg == "MMS":
1001            set_subid_for_data(ad_mo, mo_sub_id)
1002            ad_mo.droid.telephonyToggleDataConnection(True)
1003    ad_mo.log.info("Sub ID for outgoing %s at slot %s: %s", msg, mo_slot,
1004        get_outgoing_message_sub_id(ad_mo))
1005
1006    if mt_slot is not None:
1007        mt_sub_id = get_subid_from_slot_index(log, ad_mt, mt_slot)
1008        if mt_sub_id == INVALID_SUB_ID:
1009            ad_mt.log.warning("Failed to get sub ID at slot %s.", mt_slot)
1010            return False
1011        mt_other_sub_id = get_subid_from_slot_index(log, ad_mt, 1-mt_slot)
1012        set_message_subid(ad_mt, mt_sub_id)
1013    else:
1014        _, mt_sub_id, _ = get_subid_on_same_network_of_host_ad(
1015            ads, type="sms")
1016        if mt_sub_id == INVALID_SUB_ID:
1017            ad_mt.log.warning("Failed to get sub ID at slot %s.", mt_slot)
1018            return False
1019        mt_slot = "auto"
1020        set_message_subid(ad_mt, mt_sub_id)
1021        if msg == "MMS":
1022            set_subid_for_data(ad_mt, mt_sub_id)
1023            ad_mt.droid.telephonyToggleDataConnection(True)
1024    ad_mt.log.info("Sub ID for incoming %s at slot %s: %s", msg, mt_slot,
1025        get_outgoing_message_sub_id(ad_mt))
1026
1027    log.info("Step 1: Switch DDS.")
1028    if not set_dds_on_slot(ads[0], dds_slot):
1029        log.error(
1030            "Failed to set DDS at slot %s on %s",(dds_slot, ads[0].serial))
1031        return False
1032
1033    log.info("Step 2: Check HTTP connection after DDS switch.")
1034    if not verify_http_connection(log, ads[0]):
1035        log.error("Failed to verify http connection.")
1036        return False
1037    else:
1038        log.info("Verify http connection successfully.")
1039
1040    if mo_slot == 0 or mo_slot == 1:
1041        phone_setup_on_rat(log, ad_mo, mo_rat[1-mo_slot], mo_other_sub_id)
1042        mo_phone_setup_func_argv = (log, ad_mo, mo_rat[mo_slot], mo_sub_id)
1043    else:
1044        mo_phone_setup_func_argv = (log, ad_mo, 'general', mo_sub_id)
1045
1046    if mt_slot == 0 or mt_slot == 1:
1047        phone_setup_on_rat(log, ad_mt, mt_rat[1-mt_slot], mt_other_sub_id)
1048        mt_phone_setup_func_argv = (log, ad_mt, mt_rat[mt_slot], mt_sub_id)
1049    else:
1050        mt_phone_setup_func_argv = (log, ad_mt, 'general', mt_sub_id)
1051
1052    log.info("Step 3: Set up phones in desired RAT.")
1053    tasks = [(phone_setup_on_rat, mo_phone_setup_func_argv),
1054                (phone_setup_on_rat, mt_phone_setup_func_argv)]
1055    if not multithread_func(log, tasks):
1056        log.error("Phone Failed to Set Up Properly.")
1057        return False
1058    time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
1059
1060    if streaming:
1061        log.info("Step 4: Start Youtube streaming.")
1062        if not start_youtube_video(ads[0]):
1063            log.warning("Fail to bring up youtube video")
1064        time.sleep(10)
1065    else:
1066        log.info("Step 4: Skip Youtube streaming.")
1067
1068    log.info("Step 5: Send %s.", msg)
1069    if msg == "MMS":
1070        for ad, current_data_sub_id, current_msg_sub_id in [
1071            [ ads[0],
1072                get_default_data_sub_id(ads[0]),
1073                get_outgoing_message_sub_id(ads[0]) ],
1074            [ ads[1],
1075                get_default_data_sub_id(ads[1]),
1076                get_outgoing_message_sub_id(ads[1]) ]]:
1077            if current_data_sub_id != current_msg_sub_id:
1078                ad.log.warning(
1079                    "Current data sub ID (%s) does not match message"
1080                    " sub ID (%s). MMS should NOT be sent.",
1081                    current_data_sub_id,
1082                    current_msg_sub_id)
1083                expected_result = False
1084
1085    result = msim_message_test(log, ad_mo, ad_mt, mo_sub_id, mt_sub_id,
1086        msg=msg, expected_result=expected_result)
1087
1088    if not result:
1089        log_messaging_screen_shot(ad_mo, test_name="%s_tx" % msg)
1090        log_messaging_screen_shot(ad_mt, test_name="%s_rx" % msg)
1091
1092    if streaming:
1093        ads[0].force_stop_apk(YOUTUBE_PACKAGE_NAME)
1094    return result
1095
1096
1097def dds_switch_during_data_transfer_test(
1098        log,
1099        tel_logger,
1100        ads,
1101        nw_rat=["volte", "volte"],
1102        call_slot=0,
1103        call_direction=None,
1104        call_or_sms_or_mms="call",
1105        streaming=True,
1106        is_airplane_mode=False,
1107        wfc_mode=[WFC_MODE_CELLULAR_PREFERRED, WFC_MODE_CELLULAR_PREFERRED],
1108        wifi_network_ssid=None,
1109        wifi_network_pass=None):
1110    """Switch DDS and make voice call(VoLTE/WFC/CS call)/SMS/MMS together with
1111    Youtube playing after each DDS switch at specific slot in specific RAT.
1112
1113    Test step:
1114        1. Get sub ID of each slot of the primary device.
1115        2. Set up phones in desired RAT.
1116        3. Switch DDS to slot 0.
1117        4. Check HTTP connection after DDS switch.
1118        5. Play Youtube.
1119        6. Make voice call (VoLTE/WFC/CS call)/SMS/MMS
1120        7. Switch DDS to slot 1 and repeat step 4-6.
1121        8. Switch DDS to slot 0 again and repeat step 4-6.
1122
1123    Args:
1124        log: logger object
1125        tel_logger: logger object for telephony proto
1126        ads: list of android devices
1127        sim_slot: a list which contains 2 slots for logical slot 0 and 1.
1128            e.g. [SimSlotInfo.SLOT_0, SimSlotInfo.SLOT_1]
1129        nw_rat: RAT for both slots of the primary device
1130        call_slot: Slot for making voice call
1131        call_direction: "mo" or "mt" or None to stoping making call.
1132        call_or_sms_or_mms: Voice call or SMS or MMS
1133        streaming: True for playing Youtube after DDS switch and False on the contrary.
1134        is_airplane_mode: True or False for WFC setup
1135        wfc_mode: Cellular preferred or Wi-Fi preferred.
1136        wifi_network_ssid: SSID of Wi-Fi AP
1137        wifi_network_pass: Password of Wi-Fi AP SSID
1138
1139    Returns:
1140        TestFailure if failed.
1141    """
1142    ad = ads[0]
1143    slot_0_subid = get_subid_from_slot_index(log, ad, 0)
1144    slot_1_subid = get_subid_from_slot_index(log, ad, 1)
1145
1146    if slot_0_subid == INVALID_SUB_ID or slot_1_subid == INVALID_SUB_ID:
1147        ad.log.error("Not all slots have valid sub ID.")
1148        raise signals.TestFailure("Failed",
1149            extras={"fail_reason": "Not all slots have valid sub ID"})
1150
1151    ad.log.info(
1152        "Step 0: Set up phone in desired RAT (slot 0: %s, slot 1: %s)",
1153        nw_rat[0], nw_rat[1])
1154
1155    if not phone_setup_on_rat(
1156        log,
1157        ad,
1158        nw_rat[0],
1159        slot_0_subid,
1160        is_airplane_mode,
1161        wfc_mode[0],
1162        wifi_network_ssid,
1163        wifi_network_pass):
1164        log.error("Phone Failed to Set Up Properly.")
1165        tel_logger.set_result(CallResult("CALL_SETUP_FAILURE"))
1166        raise signals.TestFailure("Failed",
1167            extras={"fail_reason": "Phone Failed to Set Up Properly."})
1168
1169    if not phone_setup_on_rat(
1170        log,
1171        ad,
1172        nw_rat[1],
1173        slot_1_subid,
1174        is_airplane_mode,
1175        wfc_mode[1],
1176        wifi_network_ssid,
1177        wifi_network_pass):
1178        log.error("Phone Failed to Set Up Properly.")
1179        tel_logger.set_result(CallResult("CALL_SETUP_FAILURE"))
1180        raise signals.TestFailure("Failed",
1181            extras={"fail_reason": "Phone Failed to Set Up Properly."})
1182
1183    is_slot0_in_call = is_phone_in_call_on_rat(
1184        log, ad, nw_rat[0], True)
1185    is_slot1_in_call = is_phone_in_call_on_rat(
1186        log, ad, nw_rat[1], True)
1187
1188    for attempt in range(3):
1189        if attempt != 0:
1190            ad.log.info("Repeat step 1 to 4.")
1191
1192        ad.log.info("Step 1: Switch DDS.")
1193        if attempt % 2 == 0:
1194            set_dds_on_slot(ad, 0)
1195        else:
1196            set_dds_on_slot(ad, 1)
1197
1198        ad.log.info("Step 2: Check HTTP connection after DDS switch.")
1199        if not verify_http_connection(log, ad):
1200            ad.log.error("Failed to verify http connection.")
1201            return False
1202        else:
1203            ad.log.info("Verify http connection successfully.")
1204
1205        if streaming:
1206            ad.log.info("Step 3: Start Youtube streaming.")
1207            if not start_youtube_video(ad):
1208                ad.log.warning("Fail to bring up youtube video")
1209            time.sleep(10)
1210        else:
1211            ad.log.info("Step 3: Skip Youtube streaming.")
1212
1213        if not call_direction:
1214            return True
1215        else:
1216            expected_result = True
1217            if call_direction == "mo":
1218                ad_mo = ads[0]
1219                ad_mt = ads[1]
1220                phone_setup_on_rat(log, ad_mt, 'general')
1221                mo_sub_id = get_subid_from_slot_index(log, ad, call_slot)
1222                if call_or_sms_or_mms == "call":
1223                    set_voice_sub_id(ad_mo, mo_sub_id)
1224                    _, mt_sub_id, _ = get_subid_on_same_network_of_host_ad(
1225                        ads)
1226
1227                    if call_slot == 0:
1228                        is_mo_in_call = is_slot0_in_call
1229                    elif call_slot == 1:
1230                        is_mo_in_call = is_slot1_in_call
1231                    is_mt_in_call = None
1232
1233                elif call_or_sms_or_mms == "sms":
1234                    set_message_subid(ad_mo, mo_sub_id)
1235                    _, mt_sub_id, _ = get_subid_on_same_network_of_host_ad(
1236                        ads, type="sms")
1237                    set_message_subid(ad_mt, mt_sub_id)
1238
1239                elif call_or_sms_or_mms == "mms":
1240                    current_data_sub_id = get_default_data_sub_id(ad_mo)
1241                    if mo_sub_id != current_data_sub_id:
1242                        ad_mo.log.warning(
1243                            "Current data sub ID (%s) does not match"
1244                            " message sub ID (%s). MMS should NOT be sent.",
1245                            current_data_sub_id, mo_sub_id)
1246                        expected_result = False
1247                    set_message_subid(ad_mo, mo_sub_id)
1248                    _, mt_sub_id, _ = get_subid_on_same_network_of_host_ad(
1249                        ads, type="sms")
1250                    set_message_subid(ad_mt, mt_sub_id)
1251                    set_subid_for_data(ad_mt, mt_sub_id)
1252                    ad_mt.droid.telephonyToggleDataConnection(True)
1253
1254            elif call_direction == "mt":
1255                ad_mo = ads[1]
1256                ad_mt = ads[0]
1257                phone_setup_on_rat(log, ad_mo, 'general')
1258                mt_sub_id = get_subid_from_slot_index(log, ad, call_slot)
1259                if call_or_sms_or_mms == "call":
1260                    set_voice_sub_id(ad_mt, mt_sub_id)
1261                    _, mo_sub_id, _ = get_subid_on_same_network_of_host_ad(
1262                        ads)
1263
1264                    if call_slot == 0:
1265                        is_mt_in_call = is_slot0_in_call
1266                    elif call_slot == 1:
1267                        is_mt_in_call = is_slot1_in_call
1268                    is_mo_in_call = None
1269
1270                elif call_or_sms_or_mms == "sms":
1271                    set_message_subid(ad_mt, mt_sub_id)
1272                    _, mo_sub_id, _ = get_subid_on_same_network_of_host_ad(
1273                        ads, type="sms")
1274                    set_message_subid(ad_mo, mo_sub_id)
1275
1276                elif call_or_sms_or_mms == "mms":
1277                    current_data_sub_id = get_default_data_sub_id(ad_mt)
1278                    if mt_sub_id != current_data_sub_id:
1279                        ad_mt.log.warning(
1280                            "Current data sub ID (%s) does not match"
1281                            " message sub ID (%s). MMS should NOT be"
1282                            " received.", current_data_sub_id, mt_sub_id)
1283                        expected_result = False
1284                    set_message_subid(ad_mt, mt_sub_id)
1285                    _, mo_sub_id, _ = get_subid_on_same_network_of_host_ad(
1286                        ads, type="sms")
1287                    set_message_subid(ad_mo, mo_sub_id)
1288                    set_subid_for_data(ad_mo, mo_sub_id)
1289                    ad_mo.droid.telephonyToggleDataConnection(True)
1290
1291            if call_or_sms_or_mms == "call":
1292                log.info("Step 4: Make voice call.")
1293                mo_slot = get_slot_index_from_subid(ad_mo, mo_sub_id)
1294                mt_slot = get_slot_index_from_subid(ad_mt, mt_sub_id)
1295                result = two_phone_call_msim_for_slot(
1296                    log,
1297                    ad_mo,
1298                    mo_slot,
1299                    None,
1300                    is_mo_in_call,
1301                    ad_mt,
1302                    mt_slot,
1303                    None,
1304                    is_mt_in_call)
1305                tel_logger.set_result(result.result_value)
1306
1307                if not result:
1308                    log.error(
1309                        "Failed to make MO call from %s slot %s to %s"
1310                        " slot %s", ad_mo.serial, mo_slot, ad_mt.serial,
1311                        mt_slot)
1312                    raise signals.TestFailure("Failed",
1313                        extras={"fail_reason": str(result.result_value)})
1314            else:
1315                log.info("Step 4: Send %s.", call_or_sms_or_mms)
1316                if call_or_sms_or_mms == "sms":
1317                    result = msim_message_test(
1318                        ad_mo,
1319                        ad_mt,
1320                        mo_sub_id,
1321                        mt_sub_id,
1322                        msg=call_or_sms_or_mms.upper())
1323                elif call_or_sms_or_mms == "mms":
1324                    result = msim_message_test(
1325                        ad_mo,
1326                        ad_mt,
1327                        mo_sub_id,
1328                        mt_sub_id,
1329                        msg=call_or_sms_or_mms.upper(),
1330                        expected_result=expected_result)
1331                if not result:
1332                    log_messaging_screen_shot(
1333                        ad_mo, test_name="%s_tx" % call_or_sms_or_mms)
1334                    log_messaging_screen_shot(
1335                        ad_mt, test_name="%s_rx" % call_or_sms_or_mms)
1336                    return False
1337        if streaming:
1338            ad.force_stop_apk(YOUTUBE_PACKAGE_NAME)
1339    return True
1340
1341
1342def enable_slot_after_voice_call_test(
1343        log,
1344        tel_logger,
1345        ads,
1346        mo_slot,
1347        mt_slot,
1348        disabled_slot,
1349        mo_rat=["", ""],
1350        mt_rat=["", ""],
1351        call_direction="mo"):
1352    """Disable/enable pSIM or eSIM with voice call
1353
1354    Test step:
1355    1. Get sub IDs of specific slots of both MO and MT devices.
1356    2. Set up phones in desired RAT.
1357    3. Disable assigned slot.
1358    4. Switch DDS to the other slot.
1359    5. Verify RAT and HTTP connection after DDS switch.
1360    6. Make voice call.
1361    7. Enable assigned slot.
1362    8. Switch DDS to the assigned slot.
1363    9. Verify RAT and HTTP connection after DDS switch.
1364
1365    Args:
1366        log: logger object
1367        tel_logger: logger object for telephony proto
1368        ads: list of android devices
1369        mo_slot: Slot making MO call (0 or 1)
1370        mt_slot: Slot receiving MT call (0 or 1)
1371        disabled_slot: slot to be disabled/enabled
1372        mo_rat: RAT for both slots of MO device
1373        mt_rat: RAT for both slots of MT device
1374        call_direction: "mo" or "mt"
1375
1376    Returns:
1377        TestFailure if failed.
1378    """
1379    if call_direction == "mo":
1380        ad_mo = ads[0]
1381        ad_mt = ads[1]
1382    else:
1383        ad_mo = ads[1]
1384        ad_mt = ads[0]
1385
1386    if mo_slot is not None:
1387        mo_sub_id = get_subid_from_slot_index(log, ad_mo, mo_slot)
1388        if mo_sub_id == INVALID_SUB_ID:
1389            ad_mo.log.warning("Failed to get sub ID at slot %s.", mo_slot)
1390            raise signals.TestFailure(
1391                "Failed",
1392                extras={
1393                    "fail_reason": "Failed to get sub ID at slot %s." % mo_slot})
1394        mo_other_sub_id = get_subid_from_slot_index(
1395            log, ad_mo, 1-mo_slot)
1396        set_voice_sub_id(ad_mo, mo_sub_id)
1397    else:
1398        _, mo_sub_id, _ = get_subid_on_same_network_of_host_ad(ads)
1399        if mo_sub_id == INVALID_SUB_ID:
1400            ad_mo.log.warning("Failed to get sub ID at slot %s.", mo_slot)
1401            raise signals.TestFailure(
1402                "Failed",
1403                extras={
1404                    "fail_reason": "Failed to get sub ID at slot %s." % mo_slot})
1405        mo_slot = "auto"
1406        set_voice_sub_id(ad_mo, mo_sub_id)
1407    ad_mo.log.info("Sub ID for outgoing call at slot %s: %s",
1408        mo_slot, get_outgoing_voice_sub_id(ad_mo))
1409
1410    if mt_slot is not None:
1411        mt_sub_id = get_subid_from_slot_index(log, ad_mt, mt_slot)
1412        if mt_sub_id == INVALID_SUB_ID:
1413            ad_mt.log.warning("Failed to get sub ID at slot %s.", mt_slot)
1414            raise signals.TestFailure(
1415                "Failed",
1416                extras={
1417                    "fail_reason": "Failed to get sub ID at slot %s." % mt_slot})
1418        mt_other_sub_id = get_subid_from_slot_index(
1419            log, ad_mt, 1-mt_slot)
1420        set_voice_sub_id(ad_mt, mt_sub_id)
1421    else:
1422        _, mt_sub_id, _ = get_subid_on_same_network_of_host_ad(ads)
1423        if mt_sub_id == INVALID_SUB_ID:
1424            ad_mt.log.warning("Failed to get sub ID at slot %s.", mt_slot)
1425            raise signals.TestFailure(
1426                "Failed",
1427                extras={
1428                    "fail_reason": "Failed to get sub ID at slot %s." % mt_slot})
1429        mt_slot = "auto"
1430        set_voice_sub_id(ad_mt, mt_sub_id)
1431    ad_mt.log.info("Sub ID for incoming call at slot %s: %s", mt_slot,
1432        get_incoming_voice_sub_id(ad_mt))
1433
1434    if mo_slot == 0 or mo_slot == 1:
1435        phone_setup_on_rat(log, ad_mo, mo_rat[1-mo_slot], mo_other_sub_id)
1436        mo_phone_setup_func_argv = (log, ad_mo, mo_rat[mo_slot], mo_sub_id)
1437        is_mo_in_call = is_phone_in_call_on_rat(
1438            log, ad_mo, mo_rat[mo_slot], only_return_fn=True)
1439    else:
1440        mo_phone_setup_func_argv = (log, ad_mo, 'general')
1441        is_mo_in_call = is_phone_in_call_on_rat(
1442            log, ad_mo, 'general', only_return_fn=True)
1443
1444    if mt_slot == 0 or mt_slot == 1:
1445        phone_setup_on_rat(log, ad_mt, mt_rat[1-mt_slot], mt_other_sub_id)
1446        mt_phone_setup_func_argv = (log, ad_mt, mt_rat[mt_slot], mt_sub_id)
1447        is_mt_in_call = is_phone_in_call_on_rat(
1448            log, ad_mt, mt_rat[mt_slot], only_return_fn=True)
1449    else:
1450        mt_phone_setup_func_argv = (log, ad_mt, 'general')
1451        is_mt_in_call = is_phone_in_call_on_rat(
1452            log, ad_mt, 'general', only_return_fn=True)
1453
1454    log.info("Step 1: Set up phones in desired RAT.")
1455    tasks = [(phone_setup_on_rat, mo_phone_setup_func_argv),
1456                (phone_setup_on_rat, mt_phone_setup_func_argv)]
1457    if not multithread_func(log, tasks):
1458        log.error("Phone Failed to Set Up Properly.")
1459        tel_logger.set_result(CallResult("CALL_SETUP_FAILURE"))
1460        raise signals.TestFailure(
1461            "Failed",
1462            extras={"fail_reason": "Phone Failed to Set Up Properly."})
1463
1464    log.info("Step 2: Disable slot %s.", disabled_slot)
1465    if not power_off_sim(ads[0], disabled_slot):
1466        raise signals.TestFailure(
1467            "Failed",
1468            extras={
1469                "fail_reason": "Failed to disable slot %s." % disabled_slot})
1470
1471    log.info("Step 3: Switch DDS.")
1472    if not set_dds_on_slot(ads[0], 1-disabled_slot):
1473        log.error(
1474            "Failed to set DDS at slot %s on %s.",
1475            (1-disabled_slot, ads[0].serial))
1476        raise signals.TestFailure(
1477            "Failed",
1478            extras={"fail_reason": "Failed to set DDS at slot %s on %s." % (
1479                1-disabled_slot, ads[0].serial)})
1480
1481    log.info("Step 4: Verify RAT and HTTP connection after DDS switch.")
1482    if mo_slot == 0 or mo_slot == 1:
1483        if not wait_for_network_idle(
1484            log, ad_mo, mo_rat[1-disabled_slot], mo_sub_id):
1485            raise signals.TestFailure(
1486                "Failed",
1487                extras={
1488                    "fail_reason": "Idle state does not match the given "
1489                    "RAT %s." % mo_rat[1-disabled_slot]})
1490
1491    if mt_slot == 0 or mt_slot == 1:
1492        if not wait_for_network_idle(
1493            log, ad_mt, mt_rat[1-disabled_slot], mt_sub_id):
1494            raise signals.TestFailure(
1495                "Failed",
1496                extras={
1497                    "fail_reason": "Idle state does not match the given "
1498                    "RAT %s." % mt_rat[1-disabled_slot]})
1499
1500    if not verify_http_connection(log, ads[0]):
1501        log.error("Failed to verify http connection.")
1502        raise signals.TestFailure(
1503            "Failed",
1504            extras={"fail_reason": "Failed to verify http connection."})
1505    else:
1506        log.info("Verify http connection successfully.")
1507
1508    log.info("Step 5: Make voice call.")
1509    result = two_phone_call_msim_for_slot(
1510        log,
1511        ad_mo,
1512        get_slot_index_from_subid(ad_mo, mo_sub_id),
1513        None,
1514        is_mo_in_call,
1515        ad_mt,
1516        get_slot_index_from_subid(ad_mt, mt_sub_id),
1517        None,
1518        is_mt_in_call)
1519
1520    tel_logger.set_result(result.result_value)
1521
1522    if not result:
1523        log.error(
1524            "Failed to make MO call from %s slot %s to %s slot %s",
1525                ad_mo.serial, mo_slot, ad_mt.serial, mt_slot)
1526        raise signals.TestFailure("Failed",
1527            extras={"fail_reason": str(result.result_value)})
1528
1529    log.info("Step 6: Enable slot %s.", disabled_slot)
1530    if not power_on_sim(ads[0], disabled_slot):
1531        raise signals.TestFailure(
1532            "Failed",
1533            extras={"fail_reason": "Failed to enable slot %s." % disabled_slot})
1534
1535    log.info("Step 7: Switch DDS to slot %s.", disabled_slot)
1536    if not set_dds_on_slot(ads[0], disabled_slot):
1537        log.error(
1538            "Failed to set DDS at slot %s on %s.",(disabled_slot, ads[0].serial))
1539        raise signals.TestFailure(
1540            "Failed",
1541            extras={"fail_reason": "Failed to set DDS at slot %s on %s." % (
1542                disabled_slot, ads[0].serial)})
1543
1544    log.info("Step 8: Verify RAT and HTTP connection after DDS switch.")
1545    if mo_slot == 0 or mo_slot == 1:
1546        if not wait_for_network_idle(
1547            log, ad_mo, mo_rat[disabled_slot], mo_other_sub_id):
1548            raise signals.TestFailure(
1549                "Failed",
1550                extras={
1551                    "fail_reason": "Idle state does not match the given "
1552                    "RAT %s." % mo_rat[mo_slot]})
1553
1554    if mt_slot == 0 or mt_slot == 1:
1555        if not wait_for_network_idle(
1556            log, ad_mt, mt_rat[disabled_slot], mt_other_sub_id):
1557            raise signals.TestFailure(
1558                "Failed",
1559                extras={"fail_reason": "Idle state does not match the given "
1560                "RAT %s." % mt_rat[mt_slot]})
1561
1562    if not verify_http_connection(log, ads[0]):
1563        log.error("Failed to verify http connection.")
1564        raise signals.TestFailure(
1565            "Failed",
1566            extras={"fail_reason": "Failed to verify http connection."})
1567    else:
1568        log.info("Verify http connection successfully.")
1569
1570
1571def enable_slot_after_data_call_test(
1572        log,
1573        ad,
1574        disabled_slot,
1575        rat=["", ""]):
1576    """Disable/enable pSIM or eSIM with data call
1577
1578    Test step:
1579    1. Get sub IDs of specific slots of both MO and MT devices.
1580    2. Set up phones in desired RAT.
1581    3. Disable assigned slot.
1582    4. Switch DDS to the other slot.
1583    5. Verify RAT and HTTP connection after DDS switch.
1584    6. Make a data call by http download.
1585    7. Enable assigned slot.
1586    8. Switch DDS to the assigned slot.
1587    9. Verify RAT and HTTP connection after DDS switch.
1588
1589    Args:
1590        log: logger object
1591        ads: list of android devices
1592        disabled_slot: slot to be disabled/enabled
1593        mo_rat: RAT for both slots of MO device
1594        mt_rat: RAT for both slots of MT device
1595
1596    Returns:
1597        TestFailure if failed.
1598    """
1599    data_sub_id = get_subid_from_slot_index(log, ad, 1-disabled_slot)
1600    if data_sub_id == INVALID_SUB_ID:
1601        ad.log.warning("Failed to get sub ID at slot %s.", 1-disabled_slot)
1602        raise signals.TestFailure(
1603            "Failed",
1604            extras={
1605                "fail_reason": "Failed to get sub ID at slot %s." % (
1606                    1-disabled_slot)})
1607    other_sub_id = get_subid_from_slot_index(log, ad, disabled_slot)
1608
1609    log.info("Step 1: Set up phones in desired RAT.")
1610    if not phone_setup_on_rat(log, ad, rat[1-disabled_slot], data_sub_id):
1611        raise signals.TestFailure(
1612            "Failed",
1613            extras={"fail_reason": "Phone Failed to Set Up Properly."})
1614
1615    if not phone_setup_on_rat(log, ad, rat[disabled_slot], other_sub_id):
1616        raise signals.TestFailure(
1617            "Failed",
1618            extras={"fail_reason": "Phone Failed to Set Up Properly."})
1619
1620    log.info("Step 2: Disable slot %s.", disabled_slot)
1621    if not power_off_sim(ad, disabled_slot):
1622        raise signals.TestFailure(
1623            "Failed",
1624            extras={"fail_reason": "Failed to disable slot %s." % disabled_slot})
1625
1626    log.info("Step 3: Switch DDS.")
1627    if not set_dds_on_slot(ad, 1-disabled_slot):
1628        log.error(
1629            "Failed to set DDS at slot %s on %s.",(1-disabled_slot, ad.serial))
1630        raise signals.TestFailure(
1631            "Failed",
1632            extras={"fail_reason": "Failed to set DDS at slot %s on %s." % (
1633                1-disabled_slot, ad.serial)})
1634
1635    log.info("Step 4: Verify RAT and HTTP connection after DDS switch.")
1636    if not wait_for_network_idle(log, ad, rat[1-disabled_slot], data_sub_id):
1637        raise signals.TestFailure(
1638            "Failed",
1639            extras={
1640                "fail_reason": "Idle state does not match the given "
1641                "RAT %s." % rat[1-disabled_slot]})
1642
1643    if not verify_http_connection(log, ad):
1644        log.error("Failed to verify http connection.")
1645        raise signals.TestFailure("Failed",
1646            extras={"fail_reason": "Failed to verify http connection."})
1647    else:
1648        log.info("Verify http connection successfully.")
1649
1650    duration = 30
1651    start_time = datetime.now()
1652    while datetime.now() - start_time <= timedelta(seconds=duration):
1653        if not active_file_download_test(
1654            log, ad, file_name='20MB', method='sl4a'):
1655            raise signals.TestFailure(
1656                "Failed",
1657                extras={"fail_reason": "Failed to download by sl4a."})
1658
1659    log.info("Step 6: Enable slot %s.", disabled_slot)
1660    if not power_on_sim(ad, disabled_slot):
1661        raise signals.TestFailure(
1662            "Failed",
1663            extras={"fail_reason": "Failed to enable slot %s." % disabled_slot})
1664
1665    log.info("Step 7: Switch DDS to slot %s.", disabled_slot)
1666    if not set_dds_on_slot(ad, disabled_slot):
1667        log.error(
1668            "Failed to set DDS at slot %s on %s.",(disabled_slot, ad.serial))
1669        raise signals.TestFailure(
1670            "Failed",
1671            extras={"fail_reason": "Failed to set DDS at slot %s on %s." % (
1672                disabled_slot, ad.serial)})
1673
1674    log.info("Step 8: Verify RAT and HTTP connection after DDS switch.")
1675    if not wait_for_network_idle(log, ad, rat[disabled_slot], other_sub_id):
1676        raise signals.TestFailure(
1677            "Failed",
1678            extras={
1679                "fail_reason": "Idle state does not match the given "
1680                "RAT %s." % rat[disabled_slot]})
1681
1682    if not verify_http_connection(log, ad):
1683        log.error("Failed to verify http connection.")
1684        raise signals.TestFailure(
1685            "Failed",
1686            extras={"fail_reason": "Failed to verify http connection."})
1687    else:
1688        log.info("Verify http connection successfully.")
1689
1690
1691def erase_call_forwarding(log, ad):
1692    slot0_sub_id = get_subid_from_slot_index(log, ad, 0)
1693    slot1_sub_id = get_subid_from_slot_index(log, ad, 1)
1694    current_voice_sub_id = get_incoming_voice_sub_id(ad)
1695    for sub_id in (slot0_sub_id, slot1_sub_id):
1696        set_voice_sub_id(ad, sub_id)
1697        get_operator_name(log, ad, sub_id)
1698        erase_call_forwarding_by_mmi(log, ad)
1699    set_voice_sub_id(ad, current_voice_sub_id)
1700
1701
1702def three_way_calling_mo_and_mt_with_hangup_once(
1703    log,
1704    ads,
1705    phone_setups,
1706    verify_funcs,
1707    reject_once=False):
1708    """Use 3 phones to make MO call and MT call.
1709
1710    Call from PhoneA to PhoneB, accept on PhoneB.
1711    Call from PhoneC to PhoneA, accept on PhoneA.
1712
1713    Args:
1714        ads: list of ad object.
1715            The list should have three objects.
1716        phone_setups: list of phone setup functions.
1717            The list should have three objects.
1718        verify_funcs: list of phone call verify functions.
1719            The list should have three objects.
1720
1721    Returns:
1722        If success, return 'call_AB' id in PhoneA.
1723        if fail, return None.
1724    """
1725
1726    class _CallException(Exception):
1727        pass
1728
1729    try:
1730        verify_func_a, verify_func_b, verify_func_c = verify_funcs
1731        tasks = []
1732        for ad, setup_func in zip(ads, phone_setups):
1733            if setup_func is not None:
1734                tasks.append((setup_func, (log, ad, get_incoming_voice_sub_id(ad))))
1735        if tasks != [] and not multithread_func(log, tasks):
1736            log.error("Phone Failed to Set Up Properly.")
1737            raise _CallException("Setup failed.")
1738        for ad in ads:
1739            ad.droid.telecomCallClearCallList()
1740            if num_active_calls(log, ad) != 0:
1741                ad.log.error("Phone Call List is not empty.")
1742                raise _CallException("Clear call list failed.")
1743
1744        log.info("Step1: Call From PhoneA to PhoneB.")
1745        if not call_setup_teardown(
1746                log,
1747                ads[0],
1748                ads[1],
1749                ad_hangup=None,
1750                verify_caller_func=verify_func_a,
1751                verify_callee_func=verify_func_b):
1752            raise _CallException("PhoneA call PhoneB failed.")
1753
1754        calls = ads[0].droid.telecomCallGetCallIds()
1755        ads[0].log.info("Calls in PhoneA %s", calls)
1756        if num_active_calls(log, ads[0]) != 1:
1757            raise _CallException("Call list verify failed.")
1758        call_ab_id = calls[0]
1759
1760        log.info("Step2: Call From PhoneC to PhoneA.")
1761        if reject_once:
1762            log.info("Step2-1: Reject incoming call once.")
1763            if not initiate_call(
1764                log,
1765                ads[2],
1766                ads[0].telephony['subscription'][get_incoming_voice_sub_id(
1767                    ads[0])]['phone_num']):
1768                ads[2].log.error("Initiate call failed.")
1769                raise _CallException("Failed to initiate call.")
1770
1771            if not wait_and_reject_call_for_subscription(
1772                    log,
1773                    ads[0],
1774                    get_incoming_voice_sub_id(ads[0]),
1775                    incoming_number= \
1776                        ads[2].telephony['subscription'][
1777                            get_incoming_voice_sub_id(
1778                                ads[2])]['phone_num']):
1779                ads[0].log.error("Reject call fail.")
1780                raise _CallException("Failed to reject call.")
1781
1782            hangup_call(log, ads[2])
1783            time.sleep(15)
1784
1785        if not call_setup_teardown(
1786                log,
1787                ads[2],
1788                ads[0],
1789                ad_hangup=None,
1790                verify_caller_func=verify_func_c,
1791                verify_callee_func=verify_func_a):
1792            raise _CallException("PhoneA call PhoneC failed.")
1793        if not verify_incall_state(log, [ads[0], ads[1], ads[2]],
1794                                    True):
1795            raise _CallException("Not All phones are in-call.")
1796
1797    except Exception as e:
1798        setattr(ads[0], "exception", e)
1799        return None
1800
1801    return call_ab_id
1802
1803
1804def msim_message_test(
1805    log,
1806    ad_mo,
1807    ad_mt,
1808    mo_sub_id,
1809    mt_sub_id, msg="SMS",
1810    max_wait_time=MAX_WAIT_TIME_SMS_RECEIVE,
1811    expected_result=True):
1812    """Make MO/MT SMS/MMS at specific slot.
1813
1814    Args:
1815        ad_mo: Android object of the device sending SMS/MMS
1816        ad_mt: Android object of the device receiving SMS/MMS
1817        mo_sub_id: Sub ID of MO device
1818        mt_sub_id: Sub ID of MT device
1819        max_wait_time: Max wait time before SMS/MMS is received.
1820        expected_result: True for successful sending/receiving and False on
1821                            the contrary
1822
1823    Returns:
1824        True if the result matches expected_result and False on the
1825        contrary.
1826    """
1827    message_lengths = (50, 160, 180)
1828    if msg == "SMS":
1829        for length in message_lengths:
1830            message_array = [rand_ascii_str(length)]
1831            if not sms_send_receive_verify_for_subscription(
1832                log,
1833                ad_mo,
1834                ad_mt,
1835                mo_sub_id,
1836                mt_sub_id,
1837                message_array,
1838                max_wait_time):
1839                ad_mo.log.warning(
1840                    "%s of length %s test failed", msg, length)
1841                return False
1842            else:
1843                ad_mo.log.info(
1844                    "%s of length %s test succeeded", msg, length)
1845        log.info("%s test of length %s characters succeeded.",
1846            msg, message_lengths)
1847
1848    elif msg == "MMS":
1849        for length in message_lengths:
1850            message_array = [("Test Message", rand_ascii_str(length), None)]
1851
1852            if not mms_send_receive_verify(
1853                log,
1854                ad_mo,
1855                ad_mt,
1856                message_array,
1857                max_wait_time,
1858                expected_result):
1859                log.warning("%s of body length %s test failed",
1860                    msg, length)
1861                return False
1862            else:
1863                log.info(
1864                    "%s of body length %s test succeeded", msg, length)
1865        log.info("%s test of body lengths %s succeeded",
1866                        msg, message_lengths)
1867    return True
1868
1869
1870def msim_call_forwarding(
1871        log,
1872        tel_logger,
1873        ads,
1874        caller_slot,
1875        callee_slot,
1876        forwarded_callee_slot,
1877        dds_slot,
1878        sim_slot=[SimSlotInfo.SLOT_0, SimSlotInfo.SLOT_1],
1879        caller_rat=["", ""],
1880        callee_rat=["", ""],
1881        forwarded_callee_rat=["", ""],
1882        call_forwarding_type="unconditional"):
1883    """Make MO voice call to the primary device at specific slot in specific
1884    RAT with DDS at specific slot, and then forwarded to 3rd device with
1885    specific call forwarding type.
1886
1887    Test step:
1888    1. Get sub IDs of specific slots of both MO and MT devices.
1889    2. Switch DDS to specific slot.
1890    3. Check HTTP connection after DDS switch.
1891    4. Set up phones in desired RAT.
1892    5. Register and enable call forwarding with specifc type.
1893    5. Make voice call to the primary device and wait for being forwarded
1894        to 3rd device.
1895
1896    Args:
1897        log: logger object
1898        tel_logger: logger object for telephony proto
1899        ads: list of android devices
1900        caller_slot: Slot of 2nd device making MO call (0 or 1)
1901        callee_slot: Slot of primary device receiving and forwarding MT call
1902                        (0 or 1)
1903        forwarded_callee_slot: Slot of 3rd device receiving forwarded call.
1904        dds_slot: Preferred data slot
1905        sim_slot: a list which contains 2 slots for logical slot 0 and 1.
1906            e.g. [SimSlotInfo.SLOT_0, SimSlotInfo.SLOT_1]
1907        caller_rat: RAT for both slots of the 2nd device
1908        callee_rat: RAT for both slots of the primary device
1909        forwarded_callee_rat: RAT for both slots of the 3rd device
1910        call_forwarding_type:
1911            "unconditional"
1912            "busy"
1913            "not_answered"
1914            "not_reachable"
1915
1916    Returns:
1917        True or False
1918    """
1919    ad_caller = ads[1]
1920    ad_callee = ads[0]
1921    ad_forwarded_callee = ads[2]
1922
1923    log.info("Step 0: Switch to specific SIM slot combination.")
1924    try:
1925        change_slot(ad_callee, sim_slot)
1926    except TimeoutError:
1927        ad_callee.log.warning("Device not support MEP.")
1928
1929    if callee_slot is not None:
1930        callee_sub_id = get_subid_from_slot_index(
1931            log, ad_callee, callee_slot)
1932        if callee_sub_id == INVALID_SUB_ID:
1933            ad_callee.log.warning(
1934                "Failed to get sub ID at slot %s.", callee_slot)
1935            return False
1936        callee_other_sub_id = get_subid_from_slot_index(
1937            log, ad_callee, 1-callee_slot)
1938        set_voice_sub_id(ad_callee, callee_sub_id)
1939    else:
1940        callee_sub_id, _, _ = get_subid_on_same_network_of_host_ad(ads)
1941        if callee_sub_id == INVALID_SUB_ID:
1942            ad_callee.log.warning(
1943                "Failed to get sub ID at slot %s.", callee_slot)
1944            return False
1945        callee_slot = "auto"
1946        set_voice_sub_id(ad_callee, callee_sub_id)
1947    ad_callee.log.info(
1948        "Sub ID for incoming call at slot %s: %s",
1949        callee_slot, get_incoming_voice_sub_id(ad_callee))
1950
1951    if caller_slot is not None:
1952        caller_sub_id = get_subid_from_slot_index(
1953            log, ad_caller, caller_slot)
1954        if caller_sub_id == INVALID_SUB_ID:
1955            ad_caller.log.warning(
1956                "Failed to get sub ID at slot %s.", caller_slot)
1957            return False
1958        caller_other_sub_id = get_subid_from_slot_index(
1959            log, ad_caller, 1-caller_slot)
1960        set_voice_sub_id(ad_caller, caller_sub_id)
1961    else:
1962        _, caller_sub_id, _ = get_subid_on_same_network_of_host_ad(ads)
1963        if caller_sub_id == INVALID_SUB_ID:
1964            ad_caller.log.warning(
1965                "Failed to get sub ID at slot %s.", caller_slot)
1966            return False
1967        caller_slot = "auto"
1968        set_voice_sub_id(ad_caller, caller_sub_id)
1969    ad_caller.log.info(
1970        "Sub ID for outgoing call at slot %s: %s",
1971        caller_slot, get_outgoing_voice_sub_id(ad_caller))
1972
1973    if forwarded_callee_slot is not None:
1974        forwarded_callee_sub_id = get_subid_from_slot_index(
1975            log, ad_forwarded_callee, forwarded_callee_slot)
1976        if forwarded_callee_sub_id == INVALID_SUB_ID:
1977            ad_forwarded_callee.log.warning(
1978                "Failed to get sub ID at slot %s.", forwarded_callee_slot)
1979            return False
1980        forwarded_callee_other_sub_id = get_subid_from_slot_index(
1981            log, ad_forwarded_callee, 1-forwarded_callee_slot)
1982        set_voice_sub_id(
1983            ad_forwarded_callee, forwarded_callee_sub_id)
1984    else:
1985        _, _, forwarded_callee_sub_id = \
1986            get_subid_on_same_network_of_host_ad(ads)
1987        if forwarded_callee_sub_id == INVALID_SUB_ID:
1988            ad_forwarded_callee.log.warning(
1989                "Failed to get sub ID at slot %s.", forwarded_callee_slot)
1990            return False
1991        forwarded_callee_slot = "auto"
1992        set_voice_sub_id(
1993            ad_forwarded_callee, forwarded_callee_sub_id)
1994    ad_forwarded_callee.log.info(
1995        "Sub ID for incoming call at slot %s: %s",
1996        forwarded_callee_slot,
1997        get_incoming_voice_sub_id(ad_forwarded_callee))
1998
1999    log.info("Step 1: Switch DDS.")
2000    if not set_dds_on_slot(ads[0], dds_slot):
2001        log.error(
2002            "Failed to set DDS at slot %s on %s",(dds_slot, ads[0].serial))
2003        return False
2004
2005    log.info("Step 2: Check HTTP connection after DDS switch.")
2006    if not verify_http_connection(log, ads[0]):
2007        log.error("Failed to verify http connection.")
2008        return False
2009    else:
2010        log.info("Verify http connection successfully.")
2011
2012    if caller_slot == 1:
2013        phone_setup_on_rat(
2014            log,
2015            ad_caller,
2016            caller_rat[0],
2017            caller_other_sub_id)
2018
2019    elif caller_slot == 0:
2020        phone_setup_on_rat(
2021            log,
2022            ad_caller,
2023            caller_rat[1],
2024            caller_other_sub_id)
2025    else:
2026        phone_setup_on_rat(
2027            log,
2028            ad_caller,
2029            'general')
2030
2031    if callee_slot == 1:
2032        phone_setup_on_rat(
2033            log,
2034            ad_callee,
2035            callee_rat[0],
2036            callee_other_sub_id)
2037
2038    elif callee_slot == 0:
2039        phone_setup_on_rat(
2040            log,
2041            ad_callee,
2042            callee_rat[1],
2043            callee_other_sub_id)
2044    else:
2045        phone_setup_on_rat(
2046            log,
2047            ad_callee,
2048            'general')
2049
2050    if forwarded_callee_slot == 1:
2051        phone_setup_on_rat(
2052            log,
2053            ad_forwarded_callee,
2054            forwarded_callee_rat[0],
2055            forwarded_callee_other_sub_id)
2056
2057    elif forwarded_callee_slot == 0:
2058        phone_setup_on_rat(
2059            log,
2060            ad_forwarded_callee,
2061            forwarded_callee_rat[1],
2062            forwarded_callee_other_sub_id)
2063    else:
2064        phone_setup_on_rat(
2065            log,
2066            ad_forwarded_callee,
2067            'general')
2068
2069    if caller_slot == 0 or caller_slot == 1:
2070        caller_phone_setup_func_argv = (log, ad_caller, caller_rat[caller_slot], caller_sub_id)
2071    else:
2072        caller_phone_setup_func_argv = (log, ad_caller, 'general')
2073
2074    callee_phone_setup_func_argv = (log, ad_callee, callee_rat[callee_slot], callee_sub_id)
2075
2076    if forwarded_callee_slot == 0 or forwarded_callee_slot == 1:
2077        forwarded_callee_phone_setup_func_argv = (
2078            log,
2079            ad_forwarded_callee,
2080            forwarded_callee_rat[forwarded_callee_slot],
2081            forwarded_callee_sub_id)
2082    else:
2083        forwarded_callee_phone_setup_func_argv = (
2084            log,
2085            ad_forwarded_callee,
2086            'general')
2087
2088    log.info("Step 3: Set up phones in desired RAT.")
2089    tasks = [(phone_setup_on_rat, caller_phone_setup_func_argv),
2090                (phone_setup_on_rat, callee_phone_setup_func_argv),
2091                (phone_setup_on_rat,
2092                forwarded_callee_phone_setup_func_argv)]
2093    if not multithread_func(log, tasks):
2094        log.error("Phone Failed to Set Up Properly.")
2095        tel_logger.set_result(CallResult("CALL_SETUP_FAILURE"))
2096        raise signals.TestFailure("Failed",
2097            extras={"fail_reason": "Phone Failed to Set Up Properly."})
2098
2099    is_callee_in_call = is_phone_in_call_on_rat(
2100        log, ad_callee, callee_rat[callee_slot], only_return_fn=True)
2101
2102    is_call_waiting = re.search(
2103        "call_waiting (True (\d)|False)", call_forwarding_type, re.I)
2104    if is_call_waiting:
2105        if is_call_waiting.group(1) == "False":
2106            call_waiting = False
2107            scenario = None
2108        else:
2109            call_waiting = True
2110            scenario = int(is_call_waiting.group(2))
2111
2112        log.info(
2113            "Step 4: Make voice call with call waiting enabled = %s.",
2114            call_waiting)
2115        result = three_phone_call_waiting_short_seq(
2116            log,
2117            ads[0],
2118            None,
2119            is_callee_in_call,
2120            ads[1],
2121            ads[2],
2122            call_waiting=call_waiting, scenario=scenario)
2123    else:
2124        log.info(
2125            "Step 4: Make voice call with call forwarding %s.",
2126            call_forwarding_type)
2127        result = three_phone_call_forwarding_short_seq(
2128            log,
2129            ads[0],
2130            None,
2131            is_callee_in_call,
2132            ads[1],
2133            ads[2],
2134            call_forwarding_type=call_forwarding_type)
2135
2136    if not result:
2137        if is_call_waiting:
2138            pass
2139        else:
2140            log.error(
2141                "Failed to make MO call from %s slot %s to %s slot %s"
2142                " and forward to %s slot %s",
2143                ad_caller.serial,
2144                caller_slot,
2145                ad_callee.serial,
2146                callee_slot,
2147                ad_forwarded_callee.serial,
2148                forwarded_callee_slot)
2149
2150    return result
2151
2152
2153def msim_call_voice_conf(
2154        log,
2155        tel_logger,
2156        ads,
2157        host_slot,
2158        p1_slot,
2159        p2_slot,
2160        dds_slot,
2161        sim_slot=[SimSlotInfo.SLOT_0, SimSlotInfo.SLOT_1],
2162        host_rat=["volte", "volte"],
2163        p1_rat="",
2164        p2_rat="",
2165        merge=True,
2166        disable_cw=False):
2167    """Make a voice conference call at specific slot in specific RAT with
2168    DDS at specific slot.
2169
2170    Test step:
2171    1. Get sub IDs of specific slots of both MO and MT devices.
2172    2. Switch DDS to specific slot.
2173    3. Check HTTP connection after DDS switch.
2174    4. Set up phones in desired RAT and make 3-way voice call.
2175    5. Swap calls.
2176    6. Merge calls.
2177
2178    Args:
2179        log: logger object
2180        tel_logger: logger object for telephony proto
2181        ads: list of android devices
2182        host_slot: Slot on the primary device to host the comference call.
2183        0 or 1 (0 for pSIM or 1 for eSIM)
2184        p1_slot: Slot on the participant device for the call
2185        p2_slot: Slot on another participant device for the call
2186        dds_slot: Preferred data slot
2187        sim_slot: a list which contains 2 slots for logical slot 0 and 1.
2188            e.g. [SimSlotInfo.SLOT_0, SimSlotInfo.SLOT_1]
2189        host_rat: RAT for both slots of the primary device
2190        p1_rat: RAT for both slots of the participant device
2191        p2_rat: RAT for both slots of another participant device
2192        merge: True for merging 2 calls into the conference call. False for
2193        not merging 2 separated call.
2194        disable_cw: True for disabling call waiting and False on the
2195        contrary.
2196
2197    Returns:
2198        True or False
2199    """
2200    ad_host = ads[0]
2201    ad_p1 = ads[1]
2202    ad_p2 = ads[2]
2203
2204    log.info("Step 0: Switch to specific SIM slot combination.")
2205    try:
2206        change_slot(ad_host, sim_slot)
2207    except TimeoutError:
2208        ad_host.log.warning("Device not support MEP.")
2209
2210    if host_slot is not None:
2211        host_sub_id = get_subid_from_slot_index(
2212            log, ad_host, host_slot)
2213        if host_sub_id == INVALID_SUB_ID:
2214            ad_host.log.warning("Failed to get sub ID at slot.", host_slot)
2215            return False
2216        host_other_sub_id = get_subid_from_slot_index(
2217            log, ad_host, 1-host_slot)
2218        set_voice_sub_id(ad_host, host_sub_id)
2219    else:
2220        host_sub_id, _, _ = get_subid_on_same_network_of_host_ad(ads)
2221        if host_sub_id == INVALID_SUB_ID:
2222            ad_host.log.warning("Failed to get sub ID at slot.", host_slot)
2223            return False
2224        host_slot = "auto"
2225        set_voice_sub_id(ad_host, host_sub_id)
2226
2227    ad_host.log.info("Sub ID for outgoing call at slot %s: %s",
2228        host_slot, get_outgoing_voice_sub_id(ad_host))
2229
2230    if p1_slot is not None:
2231        p1_sub_id = get_subid_from_slot_index(log, ad_p1, p1_slot)
2232        if p1_sub_id == INVALID_SUB_ID:
2233            ad_p1.log.warning("Failed to get sub ID at slot %s.", p1_slot)
2234            return False
2235        set_voice_sub_id(ad_p1, p1_sub_id)
2236    else:
2237        _, p1_sub_id, _ = get_subid_on_same_network_of_host_ad(ads)
2238        if p1_sub_id == INVALID_SUB_ID:
2239            ad_p1.log.warning("Failed to get sub ID at slot %s.", p1_slot)
2240            return False
2241        p1_slot = "auto"
2242        set_voice_sub_id(ad_p1, p1_sub_id)
2243    ad_p1.log.info("Sub ID for incoming call at slot %s: %s",
2244        p1_slot, get_incoming_voice_sub_id(ad_p1))
2245
2246    if p2_slot is not None:
2247        p2_sub_id = get_subid_from_slot_index(log, ad_p2, p2_slot)
2248        if p2_sub_id == INVALID_SUB_ID:
2249            ad_p2.log.warning("Failed to get sub ID at slot %s.", p2_slot)
2250            return False
2251        set_voice_sub_id(ad_p2, p2_sub_id)
2252    else:
2253        _, _, p2_sub_id = get_subid_on_same_network_of_host_ad(ads)
2254        if p2_sub_id == INVALID_SUB_ID:
2255            ad_p2.log.warning("Failed to get sub ID at slot %s.", p2_slot)
2256            return False
2257        p2_slot = "auto"
2258        set_voice_sub_id(ad_p2, p2_sub_id)
2259    ad_p2.log.info("Sub ID for incoming call at slot %s: %s",
2260        p2_slot, get_incoming_voice_sub_id(ad_p2))
2261
2262    log.info("Step 1: Switch DDS.")
2263    if not set_dds_on_slot(ads[0], dds_slot):
2264        log.error(
2265            "Failed to set DDS at slot %s on %s",(dds_slot, ads[0].serial))
2266        return False
2267
2268    log.info("Step 2: Check HTTP connection after DDS switch.")
2269    if not verify_http_connection(log, ads[0]):
2270        log.error("Failed to verify http connection.")
2271        return False
2272    else:
2273        log.info("Verify http connection successfully.")
2274
2275    if disable_cw:
2276        if not set_call_waiting(log, ad_host, enable=0):
2277            return False
2278    else:
2279        if not set_call_waiting(log, ad_host, enable=1):
2280            return False
2281
2282    if host_slot == 1:
2283        phone_setup_on_rat(
2284            log,
2285            ad_host,
2286            host_rat[0],
2287            host_other_sub_id)
2288
2289    elif host_slot == 0:
2290        phone_setup_on_rat(
2291            log,
2292            ad_host,
2293            host_rat[1],
2294            host_other_sub_id)
2295
2296    if host_slot == 0 or host_slot == 1:
2297        host_phone_setup_func_argv = (log, ad_host, host_rat[host_slot], host_sub_id)
2298        is_host_in_call = is_phone_in_call_on_rat(
2299            log, ad_host, host_rat[host_slot], only_return_fn=True)
2300    else:
2301        host_phone_setup_func_argv = (log, ad_host, 'general')
2302        is_host_in_call = is_phone_in_call_on_rat(
2303            log, ad_host, 'general', only_return_fn=True)
2304
2305    if p1_rat:
2306        p1_phone_setup_func_argv = (log, ad_p1, p1_rat, p1_sub_id)
2307        is_p1_in_call = is_phone_in_call_on_rat(
2308            log, ad_p1, p1_rat, only_return_fn=True)
2309    else:
2310        p1_phone_setup_func_argv = (log, ad_p1, 'general')
2311        is_p1_in_call = is_phone_in_call_on_rat(
2312            log, ad_p1, 'general', only_return_fn=True)
2313
2314    if p2_rat:
2315        p2_phone_setup_func_argv = (log, ad_p2, p2_rat, p2_sub_id)
2316        is_p2_in_call = is_phone_in_call_on_rat(
2317            log, ad_p2, p2_rat, only_return_fn=True)
2318    else:
2319        p2_phone_setup_func_argv = (log, ad_p2, 'general')
2320        is_p2_in_call = is_phone_in_call_on_rat(
2321            log, ad_p2, 'general', only_return_fn=True)
2322
2323    log.info("Step 3: Set up phone in desired RAT and make 3-way"
2324        " voice call.")
2325
2326    tasks = [(phone_setup_on_rat, host_phone_setup_func_argv),
2327                (phone_setup_on_rat, p1_phone_setup_func_argv),
2328                (phone_setup_on_rat, p2_phone_setup_func_argv)]
2329    if not multithread_func(log, tasks):
2330        log.error("Phone Failed to Set Up Properly.")
2331        tel_logger.set_result(CallResult("CALL_SETUP_FAILURE"))
2332        raise signals.TestFailure("Failed",
2333            extras={"fail_reason": "Phone Failed to Set Up Properly."})
2334
2335    call_ab_id = three_way_calling_mo_and_mt_with_hangup_once(
2336        log,
2337        [ad_host, ad_p1, ad_p2],
2338        [None, None, None], [
2339            is_host_in_call, is_p1_in_call,
2340            is_p2_in_call
2341        ])
2342
2343    if call_ab_id is None:
2344        if disable_cw:
2345            set_call_waiting(log, ad_host, enable=1)
2346            if str(getattr(ad_host, "exception", None)) == \
2347                "PhoneA call PhoneC failed.":
2348                ads[0].log.info("PhoneA failed to call PhoneC due to call"
2349                    " waiting being disabled.")
2350                delattr(ad_host, "exception")
2351                return True
2352        log.error("Failed to get call_ab_id")
2353        return False
2354    else:
2355        if disable_cw:
2356            return False
2357
2358    calls = ads[0].droid.telecomCallGetCallIds()
2359    ads[0].log.info("Calls in PhoneA %s", calls)
2360    if num_active_calls(log, ads[0]) != 2:
2361        return False
2362    if calls[0] == call_ab_id:
2363        call_ac_id = calls[1]
2364    else:
2365        call_ac_id = calls[0]
2366
2367    if call_ac_id is None:
2368        log.error("Failed to get call_ac_id")
2369        return False
2370
2371    num_swaps = 2
2372    log.info("Step 4: Begin Swap x%s test.", num_swaps)
2373    if not swap_calls(log, ads, call_ab_id, call_ac_id,
2374                        num_swaps):
2375        log.error("Swap test failed.")
2376        return False
2377
2378    if not merge:
2379        result = True
2380        if not hangup_call(log, ads[1]):
2381            result =  False
2382        if not hangup_call(log, ads[2]):
2383            result =  False
2384        return result
2385    else:
2386        log.info("Step 5: Merge calls.")
2387        if host_rat[host_slot] == "volte":
2388            return _test_ims_conference_merge_drop_second_call_from_participant(
2389                log, ads, call_ab_id, call_ac_id)
2390        else:
2391            return _test_wcdma_conference_merge_drop(
2392                log, ads, call_ab_id, call_ac_id)
2393
2394
2395def msim_volte_wfc_call_forwarding(
2396        log,
2397        tel_logger,
2398        ads,
2399        callee_slot,
2400        dds_slot,
2401        callee_rat=["5g_wfc", "5g_wfc"],
2402        call_forwarding_type="unconditional",
2403        is_airplane_mode=False,
2404        is_wifi_connected=False,
2405        wfc_mode=[
2406            WFC_MODE_CELLULAR_PREFERRED,
2407            WFC_MODE_CELLULAR_PREFERRED],
2408        wifi_network_ssid=None,
2409        wifi_network_pass=None):
2410    """Make VoLTE/WFC call to the primary device at specific slot with DDS
2411    at specific slot, and then forwarded to 3rd device with specific call
2412    forwarding type.
2413
2414    Test step:
2415    1. Get sub IDs of specific slots of both MO and MT devices.
2416    2. Switch DDS to specific slot.
2417    3. Check HTTP connection after DDS switch.
2418    4. Set up phones in desired RAT.
2419    5. Register and enable call forwarding with specifc type.
2420    6. Make VoLTE/WFC call to the primary device and wait for being
2421        forwarded to 3rd device.
2422
2423    Args:
2424        log: logger object
2425        tel_logger: logger object for telephony proto
2426        ads: list of android devices
2427        callee_slot: Slot of primary device receiving and forwarding MT call
2428                        (0 or 1)
2429        dds_slot: Preferred data slot
2430        callee_rat: RAT for both slots of the primary device
2431        call_forwarding_type:
2432            "unconditional"
2433            "busy"
2434            "not_answered"
2435            "not_reachable"
2436        is_airplane_mode: True or False for WFC setup
2437        wfc_mode: Cellular preferred or Wi-Fi preferred.
2438        wifi_network_ssid: SSID of Wi-Fi AP
2439        wifi_network_pass: Password of Wi-Fi AP SSID
2440
2441    Returns:
2442        True or False
2443    """
2444    ad_caller = ads[1]
2445    ad_callee = ads[0]
2446    ad_forwarded_callee = ads[2]
2447
2448    if not toggle_airplane_mode(log, ad_callee, False):
2449        ad_callee.log.error("Failed to disable airplane mode.")
2450        return False
2451
2452    # Set up callee (primary device)
2453    callee_sub_id = get_subid_from_slot_index(
2454        log, ad_callee, callee_slot)
2455    if callee_sub_id == INVALID_SUB_ID:
2456        log.warning(
2457            "Failed to get sub ID at slot %s.", callee_slot)
2458        return
2459    callee_other_sub_id = get_subid_from_slot_index(
2460        log, ad_callee, 1-callee_slot)
2461    set_voice_sub_id(ad_callee, callee_sub_id)
2462    ad_callee.log.info(
2463        "Sub ID for incoming call at slot %s: %s",
2464        callee_slot, get_incoming_voice_sub_id(ad_callee))
2465
2466    # Set up caller
2467    _, caller_sub_id, _ = get_subid_on_same_network_of_host_ad(ads)
2468    if caller_sub_id == INVALID_SUB_ID:
2469        ad_caller.log.warning("Failed to get proper sub ID of the caller")
2470        return
2471    set_voice_sub_id(ad_caller, caller_sub_id)
2472    ad_caller.log.info(
2473        "Sub ID for outgoing call of the caller: %s",
2474        get_outgoing_voice_sub_id(ad_caller))
2475
2476    # Set up forwarded callee
2477    _, _, forwarded_callee_sub_id = get_subid_on_same_network_of_host_ad(
2478        ads)
2479    if forwarded_callee_sub_id == INVALID_SUB_ID:
2480        ad_forwarded_callee.log.warning(
2481            "Failed to get proper sub ID of the forwarded callee.")
2482        return
2483    set_voice_sub_id(ad_forwarded_callee, forwarded_callee_sub_id)
2484    ad_forwarded_callee.log.info(
2485        "Sub ID for incoming call of the forwarded callee: %s",
2486        get_incoming_voice_sub_id(ad_forwarded_callee))
2487
2488    log.info("Step 1: Switch DDS.")
2489    if not set_dds_on_slot(ads[0], dds_slot):
2490        log.error(
2491            "Failed to set DDS at slot %s on %s",(dds_slot, ads[0].serial))
2492        return False
2493
2494    log.info("Step 2: Check HTTP connection after DDS switch.")
2495    if not verify_http_connection(log, ad_callee):
2496        ad_callee.log.error("Failed to verify http connection.")
2497        return False
2498    else:
2499        ad_callee.log.info("Verify http connection successfully.")
2500
2501    is_callee_in_call = is_phone_in_call_on_rat(
2502        log, ad_callee, callee_rat[callee_slot], only_return_fn=True)
2503
2504    if is_airplane_mode:
2505        set_call_forwarding_by_mmi(log, ad_callee, ad_forwarded_callee)
2506
2507    log.info("Step 3: Set up phones in desired RAT.")
2508    if callee_slot == 1:
2509        phone_setup_on_rat(
2510            log,
2511            ad_callee,
2512            callee_rat[0],
2513            callee_other_sub_id,
2514            is_airplane_mode,
2515            wfc_mode[0],
2516            wifi_network_ssid,
2517            wifi_network_pass)
2518
2519    elif callee_slot == 0:
2520        phone_setup_on_rat(
2521            log,
2522            ad_callee,
2523            callee_rat[1],
2524            callee_other_sub_id,
2525            is_airplane_mode,
2526            wfc_mode[1],
2527            wifi_network_ssid,
2528            wifi_network_pass)
2529
2530    argv = (
2531        log,
2532        ad_callee,
2533        callee_rat[callee_slot],
2534        callee_sub_id,
2535        is_airplane_mode,
2536        wfc_mode[callee_slot],
2537        wifi_network_ssid,
2538        wifi_network_pass)
2539
2540    tasks = [(phone_setup_voice_general, (log, ad_caller)),
2541            (phone_setup_on_rat, argv),
2542            (phone_setup_voice_general, (log, ad_forwarded_callee))]
2543
2544    if not multithread_func(log, tasks):
2545        log.error("Phone Failed to Set Up Properly.")
2546        tel_logger.set_result(CallResult("CALL_SETUP_FAILURE"))
2547        raise signals.TestFailure("Failed",
2548            extras={"fail_reason": "Phone Failed to Set Up Properly."})
2549
2550    if is_wifi_connected:
2551        if not ensure_wifi_connected(
2552            log,
2553            ad_callee,
2554            wifi_network_ssid,
2555            wifi_network_pass,
2556            apm=is_airplane_mode):
2557            return False
2558        time.sleep(5)
2559
2560    if "wfc" not in callee_rat[callee_slot]:
2561        if not toggle_wfc_for_subscription(
2562            log,
2563            ad_callee,
2564            new_state=True,
2565            sub_id=callee_sub_id):
2566            return False
2567        if not set_wfc_mode_for_subscription(
2568            ad_callee, wfc_mode[callee_slot], sub_id=callee_sub_id):
2569            return False
2570
2571    log.info(
2572        "Step 4: Make voice call with call forwarding %s.",
2573        call_forwarding_type)
2574    result = three_phone_call_forwarding_short_seq(
2575        log,
2576        ad_callee,
2577        None,
2578        is_callee_in_call,
2579        ad_caller,
2580        ad_forwarded_callee,
2581        call_forwarding_type=call_forwarding_type)
2582
2583    if not result:
2584        log.error(
2585            "Failed to make MO call from %s to %s slot %s and forward"
2586            " to %s.",
2587            ad_caller.serial,
2588            ad_callee.serial,
2589            callee_slot,
2590            ad_forwarded_callee.serial)
2591    return result
2592
2593
2594def msim_volte_wfc_call_voice_conf(
2595        log,
2596        tel_logger,
2597        ads,
2598        host_slot,
2599        dds_slot,
2600        sim_slot=[SimSlotInfo.SLOT_0, SimSlotInfo.SLOT_1],
2601        host_rat=["5g_wfc", "5g_wfc"],
2602        merge=True,
2603        disable_cw=False,
2604        is_airplane_mode=False,
2605        is_wifi_connected=False,
2606        wfc_mode=[WFC_MODE_CELLULAR_PREFERRED, WFC_MODE_CELLULAR_PREFERRED],
2607        reject_once=False,
2608        wifi_network_ssid=None,
2609        wifi_network_pass=None):
2610    """Make a VoLTE/WFC conference call at specific slot with DDS at
2611        specific slot.
2612
2613    Test step:
2614    1. Get sub IDs of specific slots of both MO and MT devices.
2615    2. Set up phones in desired RAT
2616    3. Enable VoLTE/WFC.
2617    4. Switch DDS to specific slot.
2618    5. Check HTTP connection after DDS switch.
2619    6. Make 3-way VoLTE/WFC call.
2620    7. Swap calls.
2621    8. Merge calls.
2622
2623    Args:
2624        log: logger object
2625        tel_logger: logger object for telephony proto
2626        ads: list of android devices
2627        host_slot: Slot on the primary device to host the comference call.
2628                    0 or 1 (0 for pSIM or 1 for eSIM)call
2629        dds_slot: Preferred data slot
2630        sim_slot: a list which contains 2 slots for logical slot 0 and 1.
2631            e.g. [SimSlotInfo.SLOT_0, SimSlotInfo.SLOT_1]
2632        host_rat: RAT for both slots of the primary devicevice
2633        merge: True for merging 2 calls into the conference call. False for
2634                not merging 2 separated call.
2635        disable_cw: True for disabling call waiting and False on the
2636                    contrary.
2637        enable_volte: True for enabling and False for disabling VoLTE for
2638                        each slot on the primary device
2639        enable_wfc: True for enabling and False for disabling WFC for
2640                    each slot on the primary device
2641        is_airplane_mode: True or False for WFC setup
2642        wfc_mode: Cellular preferred or Wi-Fi preferred.
2643        reject_once: True for rejecting the 2nd call once from the 3rd
2644                        device (Phone C) to the primary device (Phone A).
2645        wifi_network_ssid: SSID of Wi-Fi AP
2646        wifi_network_pass: Password of Wi-Fi AP SSID
2647
2648    Returns:
2649        True or False
2650    """
2651    ad_host = ads[0]
2652    ad_p1 = ads[1]
2653    ad_p2 = ads[2]
2654
2655    log.info("Step 0: Switch to specific SIM slot combination.")
2656    try:
2657        change_slot(ad_host, sim_slot)
2658    except TimeoutError:
2659        ad_host.log.warning("Device not support MEP.")
2660
2661    host_sub_id = get_subid_from_slot_index(log, ad_host, host_slot)
2662    if host_sub_id == INVALID_SUB_ID:
2663        ad_host.log.warning("Failed to get sub ID at slot.", host_slot)
2664        return
2665    host_other_sub_id = get_subid_from_slot_index(
2666        log, ad_host, 1-host_slot)
2667    set_voice_sub_id(ad_host, host_sub_id)
2668    ad_host.log.info(
2669        "Sub ID for outgoing call at slot %s: %s",
2670        host_slot, get_outgoing_voice_sub_id(ad_host))
2671
2672    _, p1_sub_id, p2_sub_id = get_subid_on_same_network_of_host_ad(ads)
2673
2674    if p1_sub_id == INVALID_SUB_ID:
2675        ad_p1.log.warning("Failed to get proper sub ID.")
2676        return
2677    set_voice_sub_id(ad_p1, p1_sub_id)
2678    ad_p1.log.info(
2679        "Sub ID for incoming call: %s",
2680        get_incoming_voice_sub_id(ad_p1))
2681
2682    if p2_sub_id == INVALID_SUB_ID:
2683        ad_p2.log.warning("Failed to get proper sub ID.")
2684        return
2685    set_voice_sub_id(ad_p2, p2_sub_id)
2686    ad_p2.log.info(
2687        "Sub ID for incoming call: %s", get_incoming_voice_sub_id(ad_p2))
2688
2689    log.info("Step 1: Switch DDS.")
2690    if not set_dds_on_slot(ads[0], dds_slot):
2691        log.error(
2692            "Failed to set DDS at slot %s on %s",(dds_slot, ads[0].serial))
2693        return False
2694
2695    log.info("Step 2: Check HTTP connection after DDS switch.")
2696    if not verify_http_connection(log, ads[0]):
2697        ad_host.log.error("Failed to verify http connection.")
2698        return False
2699    else:
2700        ad_host.log.info("Verify http connection successfully.")
2701
2702    if disable_cw:
2703        if not set_call_waiting(log, ad_host, enable=0):
2704            return False
2705
2706    log.info("Step 3: Set up phones in desired RAT.")
2707    if host_slot == 1:
2708        phone_setup_on_rat(
2709            log,
2710            ad_host,
2711            host_rat[0],
2712            host_other_sub_id,
2713            is_airplane_mode,
2714            wfc_mode[0],
2715            wifi_network_ssid,
2716            wifi_network_pass)
2717
2718    elif host_slot == 0:
2719        phone_setup_on_rat(
2720            log,
2721            ad_host,
2722            host_rat[1],
2723            host_other_sub_id,
2724            is_airplane_mode,
2725            wfc_mode[1],
2726            wifi_network_ssid,
2727            wifi_network_pass)
2728
2729    argv = (
2730        log,
2731        ad_host,
2732        host_rat[host_slot],
2733        host_sub_id,
2734        is_airplane_mode,
2735        wfc_mode[host_slot],
2736        wifi_network_ssid,
2737        wifi_network_pass)
2738
2739    tasks = [(phone_setup_voice_general, (log, ad_p1)),
2740            (phone_setup_on_rat, argv),
2741            (phone_setup_voice_general, (log, ad_p2))]
2742
2743    if not multithread_func(log, tasks):
2744        log.error("Phone Failed to Set Up Properly.")
2745        tel_logger.set_result(CallResult("CALL_SETUP_FAILURE"))
2746        raise signals.TestFailure("Failed",
2747            extras={"fail_reason": "Phone Failed to Set Up Properly."})
2748
2749    if is_wifi_connected:
2750        if not ensure_wifi_connected(
2751            log,
2752            ad_host,
2753            wifi_network_ssid,
2754            wifi_network_pass,
2755            apm=is_airplane_mode):
2756            return False
2757        time.sleep(5)
2758
2759    if "wfc" not in host_rat[host_slot]:
2760        if not toggle_wfc_for_subscription(
2761            log,
2762            ad_host,
2763            new_state=True,
2764            sub_id=host_sub_id):
2765            return False
2766        if not set_wfc_mode_for_subscription(
2767            ad_host, wfc_mode[host_slot], sub_id=host_sub_id):
2768            return False
2769
2770    log.info("Step 4: Make 3-way voice call.")
2771    is_host_in_call = is_phone_in_call_on_rat(
2772        log, ad_host, host_rat[host_slot], only_return_fn=True)
2773    call_ab_id = _three_phone_call_mo_add_mt(
2774        log,
2775        [ad_host, ad_p1, ad_p2],
2776        [None, None, None],
2777        [is_host_in_call, None, None],
2778        reject_once=reject_once)
2779
2780    if call_ab_id is None:
2781        if disable_cw:
2782            set_call_waiting(log, ad_host, enable=1)
2783            if str(getattr(ad_host, "exception", None)) == \
2784                "PhoneA call PhoneC failed.":
2785                ads[0].log.info("PhoneA failed to call PhoneC due to call"
2786                " waiting being disabled.")
2787                delattr(ad_host, "exception")
2788                return True
2789        log.error("Failed to get call_ab_id")
2790        return False
2791    else:
2792        if disable_cw:
2793            set_call_waiting(log, ad_host, enable=0)
2794            return False
2795
2796    calls = ads[0].droid.telecomCallGetCallIds()
2797    ads[0].log.info("Calls in PhoneA %s", calls)
2798    if num_active_calls(log, ads[0]) != 2:
2799        return False
2800    if calls[0] == call_ab_id:
2801        call_ac_id = calls[1]
2802    else:
2803        call_ac_id = calls[0]
2804
2805    if call_ac_id is None:
2806        log.error("Failed to get call_ac_id")
2807        return False
2808
2809    num_swaps = 2
2810    log.info("Step 5: Begin Swap x%s test.", num_swaps)
2811    if not swap_calls(log, ads, call_ab_id, call_ac_id,
2812                        num_swaps):
2813        ad_host.log.error("Swap test failed.")
2814        return False
2815
2816    if not merge:
2817        result = True
2818        if not hangup_call(log, ads[1]):
2819            result =  False
2820        if not hangup_call(log, ads[2]):
2821            result =  False
2822        return result
2823    else:
2824        log.info("Step 6: Merge calls.")
2825
2826        if re.search('csfb|2g|3g', host_rat[host_slot].lower(), re.I):
2827            return _test_wcdma_conference_merge_drop(
2828                log, ads, call_ab_id, call_ac_id)
2829        else:
2830            return _test_ims_conference_merge_drop_second_call_from_participant(
2831                log, ads, call_ab_id, call_ac_id)