def video_call_setup(log,
                     ad_caller,
                     ad_callee,
                     video_state=VT_STATE_BIDIRECTIONAL,
                     incall_ui_display=INCALL_UI_DISPLAY_FOREGROUND):
    """ Call process, including make a phone call from caller,
    accept from callee, and hang up. The call is on default subscription

    In call process, call from <droid_caller> to <droid_callee>,
    accept the call, (optional)then hang up from <droid_hangup>.

    Args:
        ad_caller: Caller Android Device Object.
        ad_callee: Callee Android Device Object.
        incall_ui_display: after answer the call, bring in-call UI to foreground or
            background. Optional, default value is INCALL_UI_DISPLAY_FOREGROUND.
            if = INCALL_UI_DISPLAY_FOREGROUND, bring in-call UI to foreground.
            if = INCALL_UI_DISPLAY_BACKGROUND, bring in-call UI to background.
            else, do nothing.

    Returns:
        True if call process without any error.
        False if error happened.

    """
    return video_call_setup_for_subscription(
        log, ad_caller, ad_callee, get_outgoing_voice_sub_id(ad_caller),
        get_incoming_voice_sub_id(ad_callee), video_state, incall_ui_display)
def video_call_setup_teardown(log,
                              ad_caller,
                              ad_callee,
                              ad_hangup=None,
                              video_state=VT_STATE_BIDIRECTIONAL,
                              verify_caller_func=None,
                              verify_callee_func=None,
                              wait_time_in_call=WAIT_TIME_IN_CALL,
                              incall_ui_display=INCALL_UI_DISPLAY_FOREGROUND):
    """ Call process, including make a phone call from caller,
    accept from callee, and hang up. The call is on default subscription

    In call process, call from <droid_caller> to <droid_callee>,
    accept the call, (optional)then hang up from <droid_hangup>.

    Args:
        ad_caller: Caller Android Device Object.
        ad_callee: Callee Android Device Object.
        ad_hangup: Android Device Object end the phone call.
            Optional. Default value is None, and phone call will continue.
        video_state: video state for VT call.
            Optional. Default value is VT_STATE_BIDIRECTIONAL
        verify_caller_func: func_ptr to verify caller in correct mode
            Optional. Default is None
        verify_callee_func: func_ptr to verify callee in correct mode
            Optional. Default is None
        wait_time_in_call: wait time during call.
            Optional. Default is WAIT_TIME_IN_CALL.
        incall_ui_display: after answer the call, bring in-call UI to foreground or
            background. Optional, default value is INCALL_UI_DISPLAY_FOREGROUND.
            if = INCALL_UI_DISPLAY_FOREGROUND, bring in-call UI to foreground.
            if = INCALL_UI_DISPLAY_BACKGROUND, bring in-call UI to background.
            else, do nothing.

    Returns:
        True if call process without any error.
        False if error happened.

    """
    return video_call_setup_teardown_for_subscription(
        log, ad_caller, ad_callee, get_outgoing_voice_sub_id(ad_caller),
        get_incoming_voice_sub_id(ad_callee), ad_hangup, video_state,
        verify_caller_func, verify_callee_func, wait_time_in_call,
        incall_ui_display)
    def _test_msim_call_voice(self,
                              mo_slot,
                              mt_slot,
                              dds_slot,
                              mo_rat=["", ""],
                              mt_rat=["", ""],
                              call_direction="mo"):
        """Make MO/MT voice call at specific slot in specific RAT with DDS at
        specific slot.

        Test step:
        1. Get sub IDs of specific slots of both MO and MT devices.
        2. Switch DDS to specific slot.
        3. Check HTTP connection after DDS switch.
        4. Set up phones in desired RAT.
        5. Make voice call.

        Args:
            mo_slot: Slot making MO call (0 or 1)
            mt_slot: Slot receiving MT call (0 or 1)
            dds_slot: Preferred data slot
            mo_rat: RAT for both slots of MO device
            mt_rat: RAT for both slots of MT device
            call_direction: "mo" or "mt"

        Returns:
            TestFailure if failed.
        """
        ads = self.android_devices

        if call_direction == "mo":
            ad_mo = ads[0]
            ad_mt = ads[1]
        else:
            ad_mo = ads[1]
            ad_mt = ads[0]

        if mo_slot is not None:
            mo_sub_id = get_subid_from_slot_index(self.log, ad_mo, mo_slot)
            if mo_sub_id == INVALID_SUB_ID:
                ad_mo.log.warning("Failed to get sub ID ar slot %s.", mo_slot)
                return False
            mo_other_sub_id = get_subid_from_slot_index(
                self.log, ad_mo, 1 - mo_slot)
            set_incoming_voice_sub_id(ad_mo, mo_sub_id)
        else:
            _, mo_sub_id, _ = get_subid_on_same_network_of_host_ad(ads)
            if mo_sub_id == INVALID_SUB_ID:
                ad_mo.log.warning("Failed to get sub ID ar slot %s.", mo_slot)
                return False
            mo_slot = "auto"
            set_incoming_voice_sub_id(ad_mo, mo_sub_id)
        ad_mo.log.info("Sub ID for outgoing call at slot %s: %s", mo_slot,
                       get_outgoing_voice_sub_id(ad_mo))

        if mt_slot is not None:
            mt_sub_id = get_subid_from_slot_index(self.log, ad_mt, mt_slot)
            if mt_sub_id == INVALID_SUB_ID:
                ad_mt.log.warning("Failed to get sub ID at slot %s.", mt_slot)
                return False
            mt_other_sub_id = get_subid_from_slot_index(
                self.log, ad_mt, 1 - mt_slot)
            set_incoming_voice_sub_id(ad_mt, mt_sub_id)
        else:
            _, mt_sub_id, _ = get_subid_on_same_network_of_host_ad(ads)
            if mt_sub_id == INVALID_SUB_ID:
                ad_mt.log.warning("Failed to get sub ID at slot %s.", mt_slot)
                return False
            mt_slot = "auto"
            set_incoming_voice_sub_id(ad_mt, mt_sub_id)
        ad_mt.log.info("Sub ID for incoming call at slot %s: %s", mt_slot,
                       get_incoming_voice_sub_id(ad_mt))

        self.log.info("Step 1: Switch DDS.")
        if dds_slot:
            if not set_dds_on_slot_1(ads[0]):
                ads[0].log.warning("Failed to set DDS at eSIM.")
                return False
        else:
            if not set_dds_on_slot_0(ads[0]):
                ads[0].log.warning("Failed to set DDS at pSIM.")
                return False

        self.log.info("Step 2: Check HTTP connection after DDS switch.")
        if not verify_http_connection(self.log,
                                      ads[0],
                                      url="https://www.google.com",
                                      retry=5,
                                      retry_interval=15,
                                      expected_state=True):

            self.log.error("Failed to verify http connection.")
            return False
        else:
            self.log.info("Verify http connection successfully.")

        if mo_rat[0] == "volte":
            mo_slot0_phone_setup_func = phone_setup_volte
            is_mo_slot0_in_call = is_phone_in_call_volte
        elif mo_rat[0] == "csfb":
            mo_slot0_phone_setup_func = phone_setup_csfb
            is_mo_slot0_in_call = is_phone_in_call_csfb
        elif mo_rat[0] == "3g":
            mo_slot0_phone_setup_func = phone_setup_voice_3g
            is_mo_slot0_in_call = is_phone_in_call_3g
        elif not mo_rat[0] or mo_rat[0] == "general":
            mo_slot0_phone_setup_func = phone_setup_voice_general
            is_mo_slot0_in_call = None

        if mo_rat[1] == "volte":
            mo_slot1_phone_setup_func = phone_setup_volte
            is_mo_slot1_in_call = is_phone_in_call_volte
        elif mo_rat[1] == "csfb":
            mo_slot1_phone_setup_func = phone_setup_csfb
            is_mo_slot1_in_call = is_phone_in_call_csfb
        elif mo_rat[1] == "3g":
            mo_slot1_phone_setup_func = phone_setup_voice_3g
            is_mo_slot1_in_call = is_phone_in_call_3g
        elif not mo_rat[1] or mo_rat[1] == "general":
            mo_slot1_phone_setup_func = phone_setup_voice_general
            is_mo_slot1_in_call = None

        if mt_rat[0] == "volte":
            mt_slot0_phone_setup_func = phone_setup_volte
            is_mt_slot0_in_call = is_phone_in_call_volte
        elif mt_rat[0] == "csfb":
            mt_slot0_phone_setup_func = phone_setup_csfb
            is_mt_slot0_in_call = is_phone_in_call_csfb
        elif mt_rat[0] == "3g":
            mt_slot0_phone_setup_func = phone_setup_voice_3g
            is_mt_slot0_in_call = is_phone_in_call_3g
        elif not mt_rat[0] or mt_rat[0] == "general":
            mt_slot0_phone_setup_func = phone_setup_voice_general
            is_mt_slot0_in_call = None

        if mt_rat[1] == "volte":
            mt_slot1_phone_setup_func = phone_setup_volte
            is_mt_slot1_in_call = is_phone_in_call_volte
        elif mt_rat[1] == "csfb":
            mt_slot1_phone_setup_func = phone_setup_csfb
            is_mt_slot1_in_call = is_phone_in_call_csfb
        elif mt_rat[1] == "3g":
            mt_slot1_phone_setup_func = phone_setup_voice_3g
            is_mt_slot1_in_call = is_phone_in_call_3g
        elif not mt_rat[1] or mt_rat[1] == "general":
            mt_slot1_phone_setup_func = phone_setup_voice_general
            is_mt_slot1_in_call = None

        if mo_slot == 1:
            mo_phone_setup_func = mo_slot1_phone_setup_func
            is_mo_in_call = is_mo_slot1_in_call
            if mo_rat[0] == "volte":
                phone_setup_volte_for_subscription(self.log, ad_mo,
                                                   mo_other_sub_id)
            elif mo_rat[0] == "csfb":
                phone_setup_csfb_for_subscription(self.log, ad_mo,
                                                  mo_other_sub_id)
            elif mo_rat[0] == "3g":
                phone_setup_voice_3g_for_subscription(self.log, ad_mo,
                                                      mo_other_sub_id)
            elif not mo_rat[0] or mo_rat[0] == "general":
                phone_setup_voice_general_for_subscription(
                    self.log, ad_mo, mo_other_sub_id)
        elif mo_slot == 0:
            mo_phone_setup_func = mo_slot0_phone_setup_func
            is_mo_in_call = is_mo_slot0_in_call
            if mo_rat[1] == "volte":
                phone_setup_volte_for_subscription(self.log, ad_mo,
                                                   mo_other_sub_id)
            elif mo_rat[1] == "csfb":
                phone_setup_csfb_for_subscription(self.log, ad_mo,
                                                  mo_other_sub_id)
            elif mo_rat[1] == "3g":
                phone_setup_voice_3g_for_subscription(self.log, ad_mo,
                                                      mo_other_sub_id)
            elif not mo_rat[1] or mo_rat[1] == "general":
                phone_setup_voice_general_for_subscription(
                    self.log, ad_mo, mo_other_sub_id)
        else:
            mo_phone_setup_func = phone_setup_voice_general
            is_mo_in_call = None

        if mt_slot == 1:
            mt_phone_setup_func = mt_slot1_phone_setup_func
            is_mt_in_call = is_mt_slot1_in_call
            if mt_rat[0] == "volte":
                phone_setup_volte_for_subscription(self.log, ad_mt,
                                                   mt_other_sub_id)
            elif mt_rat[0] == "csfb":
                phone_setup_csfb_for_subscription(self.log, ad_mt,
                                                  mt_other_sub_id)
            elif mt_rat[0] == "3g":
                phone_setup_voice_3g_for_subscription(self.log, ad_mt,
                                                      mt_other_sub_id)
            elif not mt_rat[0] or mt_rat[0] == "general":
                phone_setup_voice_general_for_subscription(
                    self.log, ad_mt, mt_other_sub_id)
        elif mt_slot == 0:
            mt_phone_setup_func = mt_slot0_phone_setup_func
            is_mt_in_call = is_mt_slot0_in_call
            if mt_rat[1] == "volte":
                phone_setup_volte_for_subscription(self.log, ad_mt,
                                                   mt_other_sub_id)
            elif mt_rat[1] == "csfb":
                phone_setup_csfb_for_subscription(self.log, ad_mt,
                                                  mt_other_sub_id)
            elif mt_rat[1] == "3g":
                phone_setup_voice_3g_for_subscription(self.log, ad_mt,
                                                      mt_other_sub_id)
            elif not mt_rat[1] or mt_rat[1] == "general":
                phone_setup_voice_general_for_subscription(
                    self.log, ad_mt, mt_other_sub_id)
        else:
            mt_phone_setup_func = phone_setup_voice_general
            is_mt_in_call = None

        self.log.info("Step 3: Set up phones in desired RAT.")
        tasks = [(mo_phone_setup_func, (self.log, ad_mo)),
                 (mt_phone_setup_func, (self.log, ad_mt))]
        if not multithread_func(self.log, tasks):
            self.log.error("Phone Failed to Set Up Properly.")
            self.tel_logger.set_result(CallResult("CALL_SETUP_FAILURE"))
            raise signals.TestFailure(
                "Failed",
                extras={"fail_reason": "Phone Failed to Set Up Properly."})

        self.log.info("Step 4: Make voice call.")
        result = two_phone_call_msim_for_slot(
            self.log, ad_mo,
            get_slot_index_from_subid(self.log, ad_mo,
                                      mo_sub_id), None, is_mo_in_call, ad_mt,
            get_slot_index_from_subid(self.log, ad_mt, mt_sub_id), None,
            is_mt_in_call)
        self.tel_logger.set_result(result.result_value)

        if not result:
            self.log.error(
                "Failed to make MO call from %s slot %s to %s slot %s",
                ad_mo.serial, mo_slot, ad_mt.serial, mt_slot)
            raise signals.TestFailure(
                "Failed", extras={"fail_reason": str(result.result_value)})
    def _telephony_monitor_test(self):
        """
        Steps -
        1. Reboot the phone
        2. Start Telephony Monitor using adb/developer options
        3. Verify if it is running
        4. Phone Call from A to B
        5. Answer on B
        6. Trigger ModemSSR on B
        7. There will be a call drop with Media Timeout/Server Unreachable
        8. Parse logcat to confirm that

        Expected Results:
            UI Notification is received by User

        Returns:
            True is pass, False if fail.
        """
        # Reboot
        ads = self.android_devices
        ads[0].adb.shell(
            "am start -n com.android.settings/.DevelopmentSettings",
            ignore_status=True)
        ads[0].log.info("reboot!")
        ads[0].reboot()
        ads[0].log.info("wait %d secs for radio up." % WAIT_TIME_AFTER_REBOOT)
        time.sleep(WAIT_TIME_AFTER_REBOOT)

        # Ensure apk is running
        if not ads[0].is_apk_running("com.google.telephonymonitor"):
            ads[0].log.info("TelephonyMonitor is not running, start it now")
            ads[0].adb.shell(
                'am broadcast -a '
                'com.google.gservices.intent.action.GSERVICES_OVERRIDE -e '
                '"ce.telephony_monitor_enable" "true"')

        # Setup Phone Call
        caller_number = ads[0].cfg['subscription'][get_outgoing_voice_sub_id(
            ads[0])]['phone_num']
        callee_number = ads[1].cfg['subscription'][get_incoming_voice_sub_id(
            ads[1])]['phone_num']
        tasks = [(phone_setup_voice_general, (self.log, ads[0])),
                 (phone_setup_voice_general, (self.log, ads[1]))]
        if not multithread_func(self.log, tasks):
            self.log.error("Phone Failed to Set Up Properly.")
            return False

        if not initiate_call(ads[0].log, ads[0], callee_number):
            ads[0].log.error("Phone was unable to initate a call")
            return False
        if not wait_and_answer_call(self.log, ads[1], caller_number):
            ads[0].log.error("wait_and_answer_call failed")
            return False

        # Modem SSR
        time.sleep(5)
        ads[1].log.info("Triggering ModemSSR")
        ads[1].adb.shell("echo restart > /sys/kernel/debug/msm_subsys/modem",
                         ignore_status=True)
        time.sleep(60)

        # Parse logcat for UI notification
        if ads[0].search_logcat("Bugreport notification title Call Drop:"):
            ads[0].log.info("User got the Call Drop Notification")
        else:
            ads[0].log.error("User didn't get Call Drop Notification in 1 min")
            return False
        return True