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 setup_class(self): TelephonyBaseTest.setup_class(self) self.dut = self.android_devices[0] self.number_of_devices = 1 self.skip_reset_between_cases = False subid = get_outgoing_voice_sub_id(self.dut) self.carrier_configs = dumpsys_carrier_config(self.dut)[subid] self.dut_capabilities = self.dut.telephony["subscription"][ subid].get("capabilities", []) self.dut.log.info("DUT capabilities: %s", self.dut_capabilities) if CAPABILITY_VOLTE not in self.dut_capabilities: raise signals.TestAbortClass("VoLTE is not supported") if CAPABILITY_WFC not in self.dut_capabilities: raise signals.TestAbortClass("WFC is not supported") self.default_volte = (CAPABILITY_VOLTE in self.dut_capabilities) and ( self.carrier_configs[CarrierConfigs. ENHANCED_4G_LTE_ON_BY_DEFAULT_BOOL]) self.default_wfc_enabled = ( CAPABILITY_WFC in self.dut_capabilities ) and ( self.carrier_configs[CarrierConfigs.DEFAULT_WFC_IMS_ENABLED_BOOL]) self.default_wfc_mode = self.carrier_configs.get( CarrierConfigs.DEFAULT_WFC_IMS_MODE_INT, None) self.dut_wfc_modes = self.dut.telephony[ "subscription"][subid].get("wfc_modes", [])
def phone_setup_iwlan(log, ad, is_airplane_mode, wfc_mode, wifi_ssid=None, wifi_pwd=None): """Phone setup function for epdg call test. Set WFC mode according to wfc_mode. Set airplane mode according to is_airplane_mode. Make sure phone connect to WiFi. (If wifi_ssid is not None.) Wait for phone to be in iwlan data network type. Wait for phone to report wfc enabled flag to be true. Args: log: Log object. ad: Android device object. is_airplane_mode: True to turn on airplane mode. False to turn off airplane mode. wfc_mode: WFC mode to set to. wifi_ssid: WiFi network SSID. This is optional. If wifi_ssid is None, then phone_setup_iwlan will not attempt to connect to wifi. wifi_pwd: WiFi network password. This is optional. Returns: True if success. False if fail. """ #TODO: get per sub_id carrier_config for multi-sim purpose if CAPABILITY_WFC not in ad.telephony.get("capabilities", []): ad.log.error("WFC is not supported, abort test.") raise signals.TestSkip("WFC is not supported, abort test.") return phone_setup_iwlan_for_subscription(log, ad, get_outgoing_voice_sub_id(ad), is_airplane_mode, wfc_mode, wifi_ssid, wifi_pwd)
def phone_setup_iwlan(log, ad, is_airplane_mode, wfc_mode, wifi_ssid=None, wifi_pwd=None): """Phone setup function for epdg call test. Set WFC mode according to wfc_mode. Set airplane mode according to is_airplane_mode. Make sure phone connect to WiFi. (If wifi_ssid is not None.) Wait for phone to be in iwlan data network type. Wait for phone to report wfc enabled flag to be true. Args: log: Log object. ad: Android device object. is_airplane_mode: True to turn on airplane mode. False to turn off airplane mode. wfc_mode: WFC mode to set to. wifi_ssid: WiFi network SSID. This is optional. If wifi_ssid is None, then phone_setup_iwlan will not attempt to connect to wifi. wifi_pwd: WiFi network password. This is optional. Returns: True if success. False if fail. """ return phone_setup_iwlan_for_subscription(log, ad, get_outgoing_voice_sub_id(ad), is_airplane_mode, wfc_mode, wifi_ssid, wifi_pwd)
def wait_and_answer_video_call(log, ad, incoming_number=None, video_state=VT_STATE_BIDIRECTIONAL, incall_ui_display=INCALL_UI_DISPLAY_FOREGROUND): """Wait for an incoming call on default voice subscription and accepts the call. Args: ad: android device object. incoming_number: Expected incoming number. Optional. Default is None 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 incoming call is received and answered successfully. False: for errors """ return wait_and_answer_video_call_for_subscription( log, ad, get_outgoing_voice_sub_id(ad), incoming_number, video_state, incall_ui_display)
def get_current_voice_rat(log, ad): """Return current Voice RAT Args: ad: Android device object. """ return get_current_voice_rat_for_subscription( log, ad, get_outgoing_voice_sub_id(ad))
def is_phone_in_call_3g(log, ad): """Return if phone is in 3G call. Args: ad: Android device object. """ return is_phone_in_call_3g_for_subscription(log, ad, get_outgoing_voice_sub_id(ad))
def phone_idle_2g(log, ad): """Return if phone is idle for 2G call test. Args: ad: Android device object. """ return phone_idle_2g_for_subscription(log, ad, get_outgoing_voice_sub_id(ad))
def phone_idle_not_iwlan(log, ad): """Return if phone is idle for non WiFi calling call test. Args: ad: Android device object. """ return phone_idle_not_iwlan_for_subscription(log, ad, get_outgoing_voice_sub_id(ad))
def phone_idle_video(log, ad): """Return if phone (default sub_id) is idle for video call. Args: log: log object. ad: android device object Returns: True if ad is idle for video call. """ return phone_idle_video_for_subscription(log, ad, get_outgoing_voice_sub_id(ad))
def is_phone_in_call_video_bidirectional(log, ad): """Return if phone in bi-directional video call. Args: log: log object. ad: android device object Returns: True if phone in bi-directional video call. """ return is_phone_in_call_video_bidirectional_for_subscription( log, ad, get_outgoing_voice_sub_id(ad))
def is_phone_in_call_voice_hd(log, ad): """Return if phone in hd voice call. Args: log: log object. ad: android device object Returns: True if phone in hd voice call. """ return is_phone_in_call_voice_hd_for_subscription( log, ad, get_outgoing_voice_sub_id(ad))
def phone_setup_voice_2g(log, ad): """Setup phone voice to 2G. Args: log: log object ad: Android device object. Returns: True if setup successfully. False for errors. """ return phone_setup_voice_2g_for_subscription(log, ad, get_outgoing_voice_sub_id(ad))
def phone_setup_volte(log, ad): """Setup VoLTE enable. Args: log: log object ad: android device object. Returns: True: if VoLTE is enabled successfully. False: for errors """ return phone_setup_volte_for_subscription(log, ad, get_outgoing_voice_sub_id(ad))
def phone_setup_video(log, ad, wfc_mode=WFC_MODE_DISABLED): """Setup phone default sub_id to make video call Args: log: log object. ad: android device object wfc_mode: WFC mode to set to. Valid mode includes: WFC_MODE_WIFI_ONLY, WFC_MODE_CELLULAR_PREFERRED, WFC_MODE_WIFI_PREFERRED, WFC_MODE_DISABLED. Returns: True if ad (default sub_id) is setup correctly and idle for video call. """ return phone_setup_video_for_subscription(log, ad, get_outgoing_voice_sub_id(ad), wfc_mode)
def phone_setup_voice_general(log, ad): """Setup phone for voice general call test. Make sure phone attached to voice. Make necessary delay. Args: ad: Android device object. Returns: True if setup successfully. False for errors. """ return phone_setup_voice_general_for_subscription( log, ad, get_outgoing_voice_sub_id(ad))
def phone_setup_csfb(log, ad): """Setup phone for CSFB call test. Setup Phone to be in 4G mode. Disabled VoLTE. Args: log: log object ad: Android device object. Returns: True if setup successfully. False for errors. """ return phone_setup_csfb_for_subscription(log, ad, get_outgoing_voice_sub_id(ad))
def is_phone_in_call_video(log, ad): """Return if ad is in a video call (in expected video state). Args: log: log object. ad: android device object video_state: Expected Video call state. This is optional, if it's None, then TX_ENABLED/RX_ENABLED/BIDIRECTIONAL video call state will return True. Returns: True if ad (for sub_id) is in a video call (in expected video state). """ return is_phone_in_call_video_for_subscription( log, ad, get_outgoing_voice_sub_id(ad))
def phone_setup_volte(log, ad): """Setup VoLTE enable. Args: log: log object ad: android device object. Returns: True: if VoLTE is enabled successfully. False: for errors """ #TODO: get per sub_id carrier_config for multi-sim purpose if CAPABILITY_VOLTE not in ad.telephony.get("capabilities", []): ad.log.error("VoLTE is not supported, abort test.") raise signals.TestSkip("VoLTE is not supported, abort test.") return phone_setup_volte_for_subscription(log, ad, get_outgoing_voice_sub_id(ad))
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