• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python3
2#
3#   Copyright 2016 - 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
18from future import standard_library
19standard_library.install_aliases()
20
21import concurrent.futures
22import json
23import logging
24import re
25import os
26import urllib.parse
27import time
28import acts.controllers.iperf_server as ipf
29import shutil
30import struct
31
32from acts import signals
33from acts import utils
34from queue import Empty
35from acts.asserts import abort_all
36from acts.asserts import fail
37from acts.controllers.adb_lib.error import AdbError
38from acts.controllers.android_device import list_adb_devices
39from acts.controllers.android_device import list_fastboot_devices
40from acts.controllers.android_device import DEFAULT_QXDM_LOG_PATH
41from acts.controllers.android_device import DEFAULT_SDM_LOG_PATH
42from acts.controllers.android_device import SL4A_APK_NAME
43from acts.libs.proc import job
44from acts_contrib.test_utils.tel.loggers.protos.telephony_metric_pb2 import TelephonyVoiceTestResult
45from acts_contrib.test_utils.tel.tel_defines import CarrierConfigs, CARRIER_NTT_DOCOMO, CARRIER_KDDI, CARRIER_RAKUTEN, \
46    CARRIER_SBM
47from acts_contrib.test_utils.tel.tel_defines import AOSP_PREFIX
48from acts_contrib.test_utils.tel.tel_defines import CARD_POWER_DOWN
49from acts_contrib.test_utils.tel.tel_defines import CARD_POWER_UP
50from acts_contrib.test_utils.tel.tel_defines import CAPABILITY_CONFERENCE
51from acts_contrib.test_utils.tel.tel_defines import CAPABILITY_VOLTE
52from acts_contrib.test_utils.tel.tel_defines import CAPABILITY_VOLTE_PROVISIONING
53from acts_contrib.test_utils.tel.tel_defines import CAPABILITY_VOLTE_OVERRIDE_WFC_PROVISIONING
54from acts_contrib.test_utils.tel.tel_defines import CAPABILITY_HIDE_ENHANCED_4G_LTE_BOOL
55from acts_contrib.test_utils.tel.tel_defines import CAPABILITY_VT
56from acts_contrib.test_utils.tel.tel_defines import CAPABILITY_WFC
57from acts_contrib.test_utils.tel.tel_defines import CAPABILITY_WFC_MODE_CHANGE
58from acts_contrib.test_utils.tel.tel_defines import CARRIER_UNKNOWN
59from acts_contrib.test_utils.tel.tel_defines import CARRIER_FRE
60from acts_contrib.test_utils.tel.tel_defines import COUNTRY_CODE_LIST
61from acts_contrib.test_utils.tel.tel_defines import NOT_CHECK_MCALLFORWARDING_OPERATOR_LIST
62from acts_contrib.test_utils.tel.tel_defines import DATA_STATE_CONNECTED
63from acts_contrib.test_utils.tel.tel_defines import DATA_STATE_DISCONNECTED
64from acts_contrib.test_utils.tel.tel_defines import DATA_ROAMING_ENABLE
65from acts_contrib.test_utils.tel.tel_defines import DATA_ROAMING_DISABLE
66from acts_contrib.test_utils.tel.tel_defines import GEN_4G
67from acts_contrib.test_utils.tel.tel_defines import GEN_5G
68from acts_contrib.test_utils.tel.tel_defines import GEN_UNKNOWN
69from acts_contrib.test_utils.tel.tel_defines import INCALL_UI_DISPLAY_BACKGROUND
70from acts_contrib.test_utils.tel.tel_defines import INCALL_UI_DISPLAY_FOREGROUND
71from acts_contrib.test_utils.tel.tel_defines import INVALID_SIM_SLOT_INDEX
72from acts_contrib.test_utils.tel.tel_defines import INVALID_SUB_ID
73from acts_contrib.test_utils.tel.tel_defines import MAX_SAVED_VOICE_MAIL
74from acts_contrib.test_utils.tel.tel_defines import MAX_SCREEN_ON_TIME
75from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_ACCEPT_CALL_TO_OFFHOOK_EVENT
76from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_AIRPLANEMODE_EVENT
77from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_CALL_DROP
78from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_CALL_INITIATION
79from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_CALLEE_RINGING
80from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_CONNECTION_STATE_UPDATE
81from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_DATA_SUB_CHANGE
82from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_CALL_IDLE_EVENT
83from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_NW_SELECTION
84from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_SMS_RECEIVE
85from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_SMS_RECEIVE_IN_COLLISION
86from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_SMS_SENT_SUCCESS
87from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_SMS_SENT_SUCCESS_IN_COLLISION
88from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_TELECOM_RINGING
89from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_VOICE_MAIL_COUNT
90from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_VOLTE_ENABLED
91from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_WFC_DISABLED
92from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_WFC_ENABLED
93from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_FOR_DATA_STALL
94from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_FOR_NW_VALID_FAIL
95from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_FOR_DATA_STALL_RECOVERY
96from acts_contrib.test_utils.tel.tel_defines import NETWORK_MODE_LTE_ONLY
97from acts_contrib.test_utils.tel.tel_defines import NETWORK_CONNECTION_TYPE_CELL
98from acts_contrib.test_utils.tel.tel_defines import NETWORK_CONNECTION_TYPE_WIFI
99from acts_contrib.test_utils.tel.tel_defines import NETWORK_SERVICE_DATA
100from acts_contrib.test_utils.tel.tel_defines import NETWORK_SERVICE_VOICE
101from acts_contrib.test_utils.tel.tel_defines import PHONE_NUMBER_STRING_FORMAT_7_DIGIT
102from acts_contrib.test_utils.tel.tel_defines import PHONE_NUMBER_STRING_FORMAT_10_DIGIT
103from acts_contrib.test_utils.tel.tel_defines import PHONE_NUMBER_STRING_FORMAT_11_DIGIT
104from acts_contrib.test_utils.tel.tel_defines import PHONE_NUMBER_STRING_FORMAT_12_DIGIT
105from acts_contrib.test_utils.tel.tel_defines import RAT_FAMILY_GSM
106from acts_contrib.test_utils.tel.tel_defines import RAT_FAMILY_LTE
107from acts_contrib.test_utils.tel.tel_defines import RAT_FAMILY_WLAN
108from acts_contrib.test_utils.tel.tel_defines import RAT_FAMILY_WCDMA
109from acts_contrib.test_utils.tel.tel_defines import RAT_1XRTT
110from acts_contrib.test_utils.tel.tel_defines import RAT_UNKNOWN
111from acts_contrib.test_utils.tel.tel_defines import SERVICE_STATE_EMERGENCY_ONLY
112from acts_contrib.test_utils.tel.tel_defines import SERVICE_STATE_IN_SERVICE
113from acts_contrib.test_utils.tel.tel_defines import SERVICE_STATE_MAPPING
114from acts_contrib.test_utils.tel.tel_defines import SERVICE_STATE_OUT_OF_SERVICE
115from acts_contrib.test_utils.tel.tel_defines import SERVICE_STATE_POWER_OFF
116from acts_contrib.test_utils.tel.tel_defines import SIM_STATE_ABSENT
117from acts_contrib.test_utils.tel.tel_defines import SIM_STATE_LOADED
118from acts_contrib.test_utils.tel.tel_defines import SIM_STATE_NOT_READY
119from acts_contrib.test_utils.tel.tel_defines import SIM_STATE_PIN_REQUIRED
120from acts_contrib.test_utils.tel.tel_defines import SIM_STATE_READY
121from acts_contrib.test_utils.tel.tel_defines import SIM_STATE_UNKNOWN
122from acts_contrib.test_utils.tel.tel_defines import TELEPHONY_STATE_IDLE
123from acts_contrib.test_utils.tel.tel_defines import TELEPHONY_STATE_OFFHOOK
124from acts_contrib.test_utils.tel.tel_defines import TELEPHONY_STATE_RINGING
125from acts_contrib.test_utils.tel.tel_defines import VOICEMAIL_DELETE_DIGIT
126from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_1XRTT_VOICE_ATTACH
127from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_ANDROID_STATE_SETTLING
128from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_BETWEEN_STATE_CHECK
129from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_FOR_STATE_CHANGE
130from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_CHANGE_DATA_SUB_ID
131from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_IN_CALL
132from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_LEAVE_VOICE_MAIL
133from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_REJECT_CALL
134from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_SYNC_DATE_TIME_FROM_NETWORK
135from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_VOICE_MAIL_SERVER_RESPONSE
136from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_DISABLED
137from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_CELLULAR_PREFERRED
138from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_WIFI_ONLY
139from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_WIFI_PREFERRED
140from acts_contrib.test_utils.tel.tel_defines import TYPE_MOBILE
141from acts_contrib.test_utils.tel.tel_defines import TYPE_WIFI
142from acts_contrib.test_utils.tel.tel_defines import EventCallStateChanged
143from acts_contrib.test_utils.tel.tel_defines import EventActiveDataSubIdChanged
144from acts_contrib.test_utils.tel.tel_defines import EventDisplayInfoChanged
145from acts_contrib.test_utils.tel.tel_defines import EventConnectivityChanged
146from acts_contrib.test_utils.tel.tel_defines import EventDataConnectionStateChanged
147from acts_contrib.test_utils.tel.tel_defines import EventDataSmsReceived
148from acts_contrib.test_utils.tel.tel_defines import EventMessageWaitingIndicatorChanged
149from acts_contrib.test_utils.tel.tel_defines import EventServiceStateChanged
150from acts_contrib.test_utils.tel.tel_defines import EventMmsSentFailure
151from acts_contrib.test_utils.tel.tel_defines import EventMmsSentSuccess
152from acts_contrib.test_utils.tel.tel_defines import EventMmsDownloaded
153from acts_contrib.test_utils.tel.tel_defines import EventSmsReceived
154from acts_contrib.test_utils.tel.tel_defines import EventSmsDeliverFailure
155from acts_contrib.test_utils.tel.tel_defines import EventSmsDeliverSuccess
156from acts_contrib.test_utils.tel.tel_defines import EventSmsSentFailure
157from acts_contrib.test_utils.tel.tel_defines import EventSmsSentSuccess
158from acts_contrib.test_utils.tel.tel_defines import CallStateContainer
159from acts_contrib.test_utils.tel.tel_defines import DataConnectionStateContainer
160from acts_contrib.test_utils.tel.tel_defines import MessageWaitingIndicatorContainer
161from acts_contrib.test_utils.tel.tel_defines import NetworkCallbackContainer
162from acts_contrib.test_utils.tel.tel_defines import ServiceStateContainer
163from acts_contrib.test_utils.tel.tel_defines import DisplayInfoContainer
164from acts_contrib.test_utils.tel.tel_defines import OverrideNetworkContainer
165from acts_contrib.test_utils.tel.tel_defines import NETWORK_MODE_NR_LTE_GSM_WCDMA
166from acts_contrib.test_utils.tel.tel_defines import CARRIER_VZW, CARRIER_ATT, \
167    CARRIER_BELL, CARRIER_ROGERS, CARRIER_KOODO, CARRIER_VIDEOTRON, CARRIER_TELUS
168from acts_contrib.test_utils.tel.tel_lookup_tables import connection_type_from_type_string
169from acts_contrib.test_utils.tel.tel_lookup_tables import is_valid_rat
170from acts_contrib.test_utils.tel.tel_lookup_tables import get_allowable_network_preference
171from acts_contrib.test_utils.tel.tel_lookup_tables import get_voice_mail_count_check_function
172from acts_contrib.test_utils.tel.tel_lookup_tables import get_voice_mail_check_number
173from acts_contrib.test_utils.tel.tel_lookup_tables import get_voice_mail_delete_digit
174from acts_contrib.test_utils.tel.tel_lookup_tables import network_preference_for_generation
175from acts_contrib.test_utils.tel.tel_lookup_tables import operator_name_from_network_name
176from acts_contrib.test_utils.tel.tel_lookup_tables import operator_name_from_plmn_id
177from acts_contrib.test_utils.tel.tel_lookup_tables import rat_families_for_network_preference
178from acts_contrib.test_utils.tel.tel_lookup_tables import rat_family_for_generation
179from acts_contrib.test_utils.tel.tel_lookup_tables import rat_family_from_rat
180from acts_contrib.test_utils.tel.tel_lookup_tables import rat_generation_from_rat
181from acts_contrib.test_utils.tel.tel_subscription_utils import get_default_data_sub_id, get_subid_from_slot_index
182from acts_contrib.test_utils.tel.tel_subscription_utils import get_outgoing_message_sub_id
183from acts_contrib.test_utils.tel.tel_subscription_utils import get_outgoing_voice_sub_id
184from acts_contrib.test_utils.tel.tel_subscription_utils import get_incoming_voice_sub_id
185from acts_contrib.test_utils.tel.tel_subscription_utils import get_incoming_message_sub_id
186from acts_contrib.test_utils.tel.tel_subscription_utils import set_subid_for_outgoing_call
187from acts_contrib.test_utils.tel.tel_subscription_utils import set_incoming_voice_sub_id
188from acts_contrib.test_utils.tel.tel_subscription_utils import set_subid_for_message
189from acts_contrib.test_utils.tel.tel_subscription_utils import get_subid_on_same_network_of_host_ad
190from acts_contrib.test_utils.tel.tel_5g_utils import is_current_network_5g_nsa_for_subscription
191from acts_contrib.test_utils.tel.tel_5g_utils import is_current_network_5g_nsa
192from acts_contrib.test_utils.wifi import wifi_test_utils
193from acts_contrib.test_utils.wifi import wifi_constants
194from acts_contrib.test_utils.gnss import gnss_test_utils as gutils
195from acts.utils import adb_shell_ping
196from acts.utils import load_config
197from acts.utils import start_standing_subprocess
198from acts.utils import stop_standing_subprocess
199from acts.logger import epoch_to_log_line_timestamp
200from acts.logger import normalize_log_line_timestamp
201from acts.utils import get_current_epoch_time
202from acts.utils import exe_cmd
203from acts.utils import rand_ascii_str
204
205
206WIFI_SSID_KEY = wifi_test_utils.WifiEnums.SSID_KEY
207WIFI_PWD_KEY = wifi_test_utils.WifiEnums.PWD_KEY
208WIFI_CONFIG_APBAND_2G = 1
209WIFI_CONFIG_APBAND_5G = 2
210WIFI_CONFIG_APBAND_AUTO = wifi_test_utils.WifiEnums.WIFI_CONFIG_APBAND_AUTO
211log = logging
212STORY_LINE = "+19523521350"
213CallResult = TelephonyVoiceTestResult.CallResult.Value
214voice_call_type = {}
215result_dict ={}
216
217class TelTestUtilsError(Exception):
218    pass
219
220
221class TelResultWrapper(object):
222    """Test results wrapper for Telephony test utils.
223
224    In order to enable metrics reporting without refactoring
225    all of the test utils this class is used to keep the
226    current return boolean scheme in tact.
227    """
228
229    def __init__(self, result_value):
230        self._result_value = result_value
231
232    @property
233    def result_value(self):
234        return self._result_value
235
236    @result_value.setter
237    def result_value(self, result_value):
238        self._result_value = result_value
239
240    def __bool__(self):
241        return self._result_value == CallResult('SUCCESS')
242
243
244def abort_all_tests(log, msg):
245    log.error("Aborting all ongoing tests due to: %s.", msg)
246    abort_all(msg)
247
248
249def get_phone_number_by_adb(ad):
250    return phone_number_formatter(
251        ad.adb.shell("service call iphonesubinfo 13"))
252
253
254def get_iccid_by_adb(ad):
255    return ad.adb.shell("service call iphonesubinfo 11")
256
257
258def get_operator_by_adb(ad):
259    operator = ad.adb.getprop("gsm.sim.operator.alpha")
260    if "," in operator:
261        operator = operator.strip()[0]
262    return operator
263
264
265def get_plmn_by_adb(ad):
266    plmn_id = ad.adb.getprop("gsm.sim.operator.numeric")
267    if "," in plmn_id:
268        plmn_id = plmn_id.strip()[0]
269    return plmn_id
270
271
272def get_sub_id_by_adb(ad):
273    return ad.adb.shell("service call iphonesubinfo 5")
274
275
276def setup_droid_properties_by_adb(log, ad, sim_filename=None):
277
278    sim_data = None
279    if sim_filename:
280        try:
281            sim_data = load_config(sim_filename)
282        except Exception:
283            log.warning("Failed to load %s!", sim_filename)
284
285    sub_id = get_sub_id_by_adb(ad)
286    iccid = get_iccid_by_adb(ad)
287    ad.log.info("iccid = %s", iccid)
288    if sim_data.get(iccid) and sim_data[iccid].get("phone_num"):
289        phone_number = phone_number_formatter(sim_data[iccid]["phone_num"])
290    else:
291        phone_number = get_phone_number_by_adb(ad)
292        if not phone_number and hasattr(ad, phone_number):
293            phone_number = ad.phone_number
294    if not phone_number:
295        ad.log.error("Failed to find valid phone number for %s", iccid)
296        abort_all_tests(ad.log, "Failed to find valid phone number for %s")
297    sub_record = {
298        'phone_num': phone_number,
299        'iccid': get_iccid_by_adb(ad),
300        'sim_operator_name': get_operator_by_adb(ad),
301        'operator': operator_name_from_plmn_id(get_plmn_by_adb(ad))
302    }
303    device_props = {'subscription': {sub_id: sub_record}}
304    ad.log.info("subId %s SIM record: %s", sub_id, sub_record)
305    setattr(ad, 'telephony', device_props)
306
307
308def setup_droid_properties(log, ad, sim_filename=None):
309
310    if ad.skip_sl4a:
311        return setup_droid_properties_by_adb(
312            log, ad, sim_filename=sim_filename)
313    refresh_droid_config(log, ad)
314    device_props = {}
315    device_props['subscription'] = {}
316
317    sim_data = {}
318    if sim_filename:
319        try:
320            sim_data = load_config(sim_filename)
321        except Exception:
322            log.warning("Failed to load %s!", sim_filename)
323    if not ad.telephony["subscription"]:
324        abort_all_tests(ad.log, "No valid subscription")
325    ad.log.debug("Subscription DB %s", ad.telephony["subscription"])
326    result = True
327    active_sub_id = get_outgoing_voice_sub_id(ad)
328    for sub_id, sub_info in ad.telephony["subscription"].items():
329        ad.log.debug("Loop for Subid %s", sub_id)
330        sub_info["operator"] = get_operator_name(log, ad, sub_id)
331        iccid = sub_info["iccid"]
332        if not iccid:
333            ad.log.warning("Unable to find ICC-ID for subscriber %s", sub_id)
334            continue
335        if sub_info.get("phone_num"):
336            if iccid in sim_data and sim_data[iccid].get("phone_num"):
337                if not check_phone_number_match(sim_data[iccid]["phone_num"],
338                                                sub_info["phone_num"]):
339                    ad.log.warning(
340                        "phone_num %s in sim card data file for iccid %s"
341                        "  do not match phone_num %s from subscription",
342                        sim_data[iccid]["phone_num"], iccid,
343                        sub_info["phone_num"])
344                sub_info["phone_num"] = sim_data[iccid]["phone_num"]
345        else:
346            if iccid in sim_data and sim_data[iccid].get("phone_num"):
347                sub_info["phone_num"] = sim_data[iccid]["phone_num"]
348            elif sub_id == active_sub_id:
349                phone_number = get_phone_number_by_secret_code(
350                    ad, sub_info["sim_operator_name"])
351                if phone_number:
352                    sub_info["phone_num"] = phone_number
353                elif getattr(ad, "phone_num", None):
354                    sub_info["phone_num"] = ad.phone_number
355        if (not sub_info.get("phone_num")) and sub_id == active_sub_id:
356            ad.log.info("sub_id %s sub_info = %s", sub_id, sub_info)
357            ad.log.error(
358                "Unable to retrieve phone number for sub %s with iccid"
359                " %s from device or testbed config or sim card file %s",
360                sub_id, iccid, sim_filename)
361            result = False
362        if not hasattr(
363                ad, 'roaming'
364        ) and sub_info["sim_plmn"] != sub_info["network_plmn"] and sub_info["sim_operator_name"].strip(
365        ) not in sub_info["network_operator_name"].strip():
366            ad.log.info("roaming is not enabled, enable it")
367            setattr(ad, 'roaming', True)
368        ad.log.info("SubId %s info: %s", sub_id, sorted(sub_info.items()))
369    get_phone_capability(ad)
370    data_roaming = getattr(ad, 'roaming', False)
371    if get_cell_data_roaming_state_by_adb(ad) != data_roaming:
372        set_cell_data_roaming_state_by_adb(ad, data_roaming)
373        # Setup VoWiFi MDN for Verizon. b/33187374
374    if not result:
375        abort_all_tests(ad.log, "Failed to find valid phone number")
376
377    ad.log.debug("telephony = %s", ad.telephony)
378
379
380def refresh_droid_config(log, ad):
381    """ Update Android Device telephony records for each sub_id.
382
383    Args:
384        log: log object
385        ad: android device object
386
387    Returns:
388        None
389    """
390    if not getattr(ad, 'telephony', {}):
391        setattr(ad, 'telephony', {"subscription": {}})
392    droid = ad.droid
393    sub_info_list = droid.subscriptionGetAllSubInfoList()
394    ad.log.info("SubInfoList is %s", sub_info_list)
395    active_sub_id = get_outgoing_voice_sub_id(ad)
396    for sub_info in sub_info_list:
397        sub_id = sub_info["subscriptionId"]
398        sim_slot = sub_info["simSlotIndex"]
399        if sub_info.get("carrierId"):
400            carrier_id = sub_info["carrierId"]
401        else:
402            carrier_id = -1
403        if sub_info.get("isOpportunistic"):
404            isopportunistic = sub_info["isOpportunistic"]
405        else:
406            isopportunistic = -1
407
408        if sim_slot != INVALID_SIM_SLOT_INDEX:
409            if sub_id not in ad.telephony["subscription"]:
410                ad.telephony["subscription"][sub_id] = {}
411            sub_record = ad.telephony["subscription"][sub_id]
412            if sub_info.get("iccId"):
413                sub_record["iccid"] = sub_info["iccId"]
414            else:
415                sub_record[
416                    "iccid"] = droid.telephonyGetSimSerialNumberForSubscription(
417                        sub_id)
418            sub_record["sim_slot"] = sim_slot
419            if sub_info.get("mcc"):
420                sub_record["mcc"] = sub_info["mcc"]
421            if sub_info.get("mnc"):
422                sub_record["mnc"] = sub_info["mnc"]
423            if sub_info.get("displayName"):
424                sub_record["display_name"] = sub_info["displayName"]
425            try:
426                sub_record[
427                    "phone_type"] = droid.telephonyGetPhoneTypeForSubscription(
428                        sub_id)
429            except:
430                if not sub_record.get("phone_type"):
431                    sub_record["phone_type"] = droid.telephonyGetPhoneType()
432            sub_record[
433                "sim_plmn"] = droid.telephonyGetSimOperatorForSubscription(
434                    sub_id)
435            sub_record[
436                "sim_operator_name"] = droid.telephonyGetSimOperatorNameForSubscription(
437                    sub_id)
438            sub_record[
439                "network_plmn"] = droid.telephonyGetNetworkOperatorForSubscription(
440                    sub_id)
441            sub_record[
442                "network_operator_name"] = droid.telephonyGetNetworkOperatorNameForSubscription(
443                    sub_id)
444            sub_record[
445                "sim_country"] = droid.telephonyGetSimCountryIsoForSubscription(
446                    sub_id)
447            if active_sub_id == sub_id:
448                try:
449                    sub_record[
450                        "carrier_id"] = ad.droid.telephonyGetSimCarrierId()
451                    sub_record[
452                        "carrier_id_name"] = ad.droid.telephonyGetSimCarrierIdName(
453                        )
454                except:
455                    ad.log.info("Carrier ID is not supported")
456            if carrier_id == 2340:
457                ad.log.info("SubId %s info: %s", sub_id, sorted(
458                    sub_record.items()))
459                continue
460            if carrier_id == 1989 and isopportunistic == "true":
461                ad.log.info("SubId %s info: %s", sub_id, sorted(
462                    sub_record.items()))
463                continue
464            if not sub_info.get("number"):
465                sub_info[
466                    "number"] = droid.telephonyGetLine1NumberForSubscription(
467                        sub_id)
468            if sub_info.get("number"):
469                if sub_record.get("phone_num"):
470                    # Use the phone number provided in sim info file by default
471                    # as the sub_info["number"] may not be formatted in a
472                    # dialable number
473                    if not check_phone_number_match(sub_info["number"],
474                                                    sub_record["phone_num"]):
475                        ad.log.info(
476                            "Subscriber phone number changed from %s to %s",
477                            sub_record["phone_num"], sub_info["number"])
478                        sub_record["phone_num"] = sub_info["number"]
479                else:
480                    sub_record["phone_num"] = phone_number_formatter(
481                        sub_info["number"])
482            #ad.telephony['subscription'][sub_id] = sub_record
483            ad.log.info("SubId %s info: %s", sub_id, sorted(
484                sub_record.items()))
485
486
487def get_phone_number_by_secret_code(ad, operator):
488    if "T-Mobile" in operator:
489        ad.droid.telecomDialNumber("#686#")
490        ad.send_keycode("ENTER")
491        for _ in range(12):
492            output = ad.search_logcat("mobile number")
493            if output:
494                result = re.findall(r"mobile number is (\S+)",
495                                    output[-1]["log_message"])
496                ad.send_keycode("BACK")
497                return result[0]
498            else:
499                time.sleep(5)
500    return ""
501
502
503def get_user_config_profile(ad):
504    return {
505        "Airplane Mode":
506        ad.droid.connectivityCheckAirplaneMode(),
507        "IMS Registered":
508        ad.droid.telephonyIsImsRegistered(),
509        "Preferred Network Type":
510        ad.droid.telephonyGetPreferredNetworkTypes(),
511        "VoLTE Platform Enabled":
512        ad.droid.imsIsEnhanced4gLteModeSettingEnabledByPlatform(),
513        "VoLTE Enabled":
514        ad.droid.imsIsEnhanced4gLteModeSettingEnabledByUser(),
515        "VoLTE Available":
516        ad.droid.telephonyIsVolteAvailable(),
517        "VT Available":
518        ad.droid.telephonyIsVideoCallingAvailable(),
519        "VT Enabled":
520        ad.droid.imsIsVtEnabledByUser(),
521        "VT Platform Enabled":
522        ad.droid.imsIsVtEnabledByPlatform(),
523        "WiFi State":
524        ad.droid.wifiCheckState(),
525        "WFC Available":
526        ad.droid.telephonyIsWifiCallingAvailable(),
527        "WFC Enabled":
528        ad.droid.imsIsWfcEnabledByUser(),
529        "WFC Platform Enabled":
530        ad.droid.imsIsWfcEnabledByPlatform(),
531        "WFC Mode":
532        ad.droid.imsGetWfcMode()
533    }
534
535
536def get_slot_index_from_subid(log, ad, sub_id):
537    try:
538        info = ad.droid.subscriptionGetSubInfoForSubscriber(sub_id)
539        return info['simSlotIndex']
540    except KeyError:
541        return INVALID_SIM_SLOT_INDEX
542
543
544def get_num_active_sims(log, ad):
545    """ Get the number of active SIM cards by counting slots
546
547    Args:
548        ad: android_device object.
549
550    Returns:
551        result: The number of loaded (physical) SIM cards
552    """
553    # using a dictionary as a cheap way to prevent double counting
554    # in the situation where multiple subscriptions are on the same SIM.
555    # yes, this is a corner corner case.
556    valid_sims = {}
557    subInfo = ad.droid.subscriptionGetAllSubInfoList()
558    for info in subInfo:
559        ssidx = info['simSlotIndex']
560        if ssidx == INVALID_SIM_SLOT_INDEX:
561            continue
562        valid_sims[ssidx] = True
563    return len(valid_sims.keys())
564
565
566def toggle_airplane_mode_by_adb(log, ad, new_state=None):
567    """ Toggle the state of airplane mode.
568
569    Args:
570        log: log handler.
571        ad: android_device object.
572        new_state: Airplane mode state to set to.
573            If None, opposite of the current state.
574        strict_checking: Whether to turn on strict checking that checks all features.
575
576    Returns:
577        result: True if operation succeed. False if error happens.
578    """
579    cur_state = bool(int(ad.adb.shell("settings get global airplane_mode_on")))
580    if new_state == cur_state:
581        ad.log.info("Airplane mode already in %s", new_state)
582        return True
583    elif new_state is None:
584        new_state = not cur_state
585    ad.log.info("Change airplane mode from %s to %s", cur_state, new_state)
586    try:
587        ad.adb.shell("settings put global airplane_mode_on %s" % int(new_state))
588        ad.adb.shell("am broadcast -a android.intent.action.AIRPLANE_MODE")
589    except Exception as e:
590        ad.log.error(e)
591        return False
592    changed_state = bool(int(ad.adb.shell("settings get global airplane_mode_on")))
593    return changed_state == new_state
594
595
596def toggle_airplane_mode(log, ad, new_state=None, strict_checking=True):
597    """ Toggle the state of airplane mode.
598
599    Args:
600        log: log handler.
601        ad: android_device object.
602        new_state: Airplane mode state to set to.
603            If None, opposite of the current state.
604        strict_checking: Whether to turn on strict checking that checks all features.
605
606    Returns:
607        result: True if operation succeed. False if error happens.
608    """
609    if ad.skip_sl4a:
610        return toggle_airplane_mode_by_adb(log, ad, new_state)
611    else:
612        return toggle_airplane_mode_msim(
613            log, ad, new_state, strict_checking=strict_checking)
614
615
616def get_telephony_signal_strength(ad):
617    #{'evdoEcio': -1, 'asuLevel': 28, 'lteSignalStrength': 14, 'gsmLevel': 0,
618    # 'cdmaAsuLevel': 99, 'evdoDbm': -120, 'gsmDbm': -1, 'cdmaEcio': -160,
619    # 'level': 2, 'lteLevel': 2, 'cdmaDbm': -120, 'dbm': -112, 'cdmaLevel': 0,
620    # 'lteAsuLevel': 28, 'gsmAsuLevel': 99, 'gsmBitErrorRate': 0,
621    # 'lteDbm': -112, 'gsmSignalStrength': 99}
622    try:
623        signal_strength = ad.droid.telephonyGetSignalStrength()
624        if not signal_strength:
625            signal_strength = {}
626    except Exception as e:
627        ad.log.error(e)
628        signal_strength = {}
629    return signal_strength
630
631
632def get_wifi_signal_strength(ad):
633    signal_strength = ad.droid.wifiGetConnectionInfo()['rssi']
634    ad.log.info("WiFi Signal Strength is %s" % signal_strength)
635    return signal_strength
636
637
638def get_lte_rsrp(ad):
639    try:
640        if ad.adb.getprop("ro.build.version.release")[0] in ("9", "P"):
641            out = ad.adb.shell(
642                "dumpsys telephony.registry | grep -i signalstrength")
643            if out:
644                lte_rsrp = out.split()[9]
645                if lte_rsrp:
646                    ad.log.info("lte_rsrp: %s ", lte_rsrp)
647                    return lte_rsrp
648        else:
649            out = ad.adb.shell(
650            "dumpsys telephony.registry |grep -i primary=CellSignalStrengthLte")
651            if out:
652                lte_cell_info = out.split('mLte=')[1]
653                lte_rsrp = re.match(r'.*rsrp=(\S+).*', lte_cell_info).group(1)
654                if lte_rsrp:
655                    ad.log.info("lte_rsrp: %s ", lte_rsrp)
656                    return lte_rsrp
657    except Exception as e:
658        ad.log.error(e)
659    return None
660
661
662def check_data_stall_detection(ad, wait_time=WAIT_TIME_FOR_DATA_STALL):
663    data_stall_detected = False
664    time_var = 1
665    try:
666        while (time_var < wait_time):
667            out = ad.adb.shell("dumpsys network_stack " \
668                              "| grep \"Suspecting data stall\"",
669                            ignore_status=True)
670            ad.log.debug("Output is %s", out)
671            if out:
672                ad.log.info("NetworkMonitor detected - %s", out)
673                data_stall_detected = True
674                break
675            time.sleep(30)
676            time_var += 30
677    except Exception as e:
678        ad.log.error(e)
679    return data_stall_detected
680
681
682def check_network_validation_fail(ad, begin_time=None,
683                                  wait_time=WAIT_TIME_FOR_NW_VALID_FAIL):
684    network_validation_fail = False
685    time_var = 1
686    try:
687        while (time_var < wait_time):
688            time_var += 30
689            nw_valid = ad.search_logcat("validation failed",
690                                         begin_time)
691            if nw_valid:
692                ad.log.info("Validation Failed received here - %s",
693                            nw_valid[0]["log_message"])
694                network_validation_fail = True
695                break
696            time.sleep(30)
697    except Exception as e:
698        ad.log.error(e)
699    return network_validation_fail
700
701
702def check_data_stall_recovery(ad, begin_time=None,
703                              wait_time=WAIT_TIME_FOR_DATA_STALL_RECOVERY):
704    data_stall_recovery = False
705    time_var = 1
706    try:
707        while (time_var < wait_time):
708            time_var += 30
709            recovery = ad.search_logcat("doRecovery() cleanup all connections",
710                                         begin_time)
711            if recovery:
712                ad.log.info("Recovery Performed here - %s",
713                            recovery[-1]["log_message"])
714                data_stall_recovery = True
715                break
716            time.sleep(30)
717    except Exception as e:
718        ad.log.error(e)
719    return data_stall_recovery
720
721
722def break_internet_except_sl4a_port(ad, sl4a_port):
723    ad.log.info("Breaking internet using iptables rules")
724    ad.adb.shell("iptables -I INPUT 1 -p tcp --dport %s -j ACCEPT" % sl4a_port,
725                 ignore_status=True)
726    ad.adb.shell("iptables -I INPUT 2 -p tcp --sport %s -j ACCEPT" % sl4a_port,
727                 ignore_status=True)
728    ad.adb.shell("iptables -I INPUT 3 -j DROP", ignore_status=True)
729    ad.adb.shell("ip6tables -I INPUT -j DROP", ignore_status=True)
730    return True
731
732
733def resume_internet_with_sl4a_port(ad, sl4a_port):
734    ad.log.info("Bring internet back using iptables rules")
735    ad.adb.shell("iptables -D INPUT -p tcp --dport %s -j ACCEPT" % sl4a_port,
736                 ignore_status=True)
737    ad.adb.shell("iptables -D INPUT -p tcp --sport %s -j ACCEPT" % sl4a_port,
738                 ignore_status=True)
739    ad.adb.shell("iptables -D INPUT -j DROP", ignore_status=True)
740    ad.adb.shell("ip6tables -D INPUT -j DROP", ignore_status=True)
741    return True
742
743
744def test_data_browsing_success_using_sl4a(log, ad):
745    result = True
746    web_page_list = ['https://www.google.com', 'https://www.yahoo.com',
747                     'https://www.amazon.com', 'https://www.nike.com',
748                     'https://www.facebook.com']
749    for website in web_page_list:
750        if not verify_http_connection(log, ad, website, retry=0):
751            ad.log.error("Failed to browse %s successfully!", website)
752            result = False
753    return result
754
755
756def test_data_browsing_failure_using_sl4a(log, ad):
757    result = True
758    web_page_list = ['https://www.youtube.com', 'https://www.cnn.com',
759                     'https://www.att.com', 'https://www.nbc.com',
760                     'https://www.verizonwireless.com']
761    for website in web_page_list:
762        if not verify_http_connection(log, ad, website, retry=0,
763                                      expected_state=False):
764            ad.log.error("Browsing to %s worked!", website)
765            result = False
766    return result
767
768
769def is_expected_event(event_to_check, events_list):
770    """ check whether event is present in the event list
771
772    Args:
773        event_to_check: event to be checked.
774        events_list: list of events
775    Returns:
776        result: True if event present in the list. False if not.
777    """
778    for event in events_list:
779        if event in event_to_check['name']:
780            return True
781    return False
782
783
784def is_sim_ready(log, ad, sim_slot_id=None):
785    """ check whether SIM is ready.
786
787    Args:
788        ad: android_device object.
789        sim_slot_id: check the SIM status for sim_slot_id
790            This is optional. If this is None, check default SIM.
791
792    Returns:
793        result: True if all SIMs are ready. False if not.
794    """
795    if sim_slot_id is None:
796        status = ad.droid.telephonyGetSimState()
797    else:
798        status = ad.droid.telephonyGetSimStateForSlotId(sim_slot_id)
799    if status != SIM_STATE_READY:
800        ad.log.info("Sim state is %s, not ready", status)
801        return False
802    return True
803
804
805def is_sim_ready_by_adb(log, ad):
806    state = ad.adb.getprop("gsm.sim.state")
807    ad.log.info("gsm.sim.state = %s", state)
808    return state == SIM_STATE_READY or state == SIM_STATE_LOADED
809
810
811def wait_for_sim_ready_by_adb(log, ad, wait_time=90):
812    return _wait_for_droid_in_state(log, ad, wait_time, is_sim_ready_by_adb)
813
814
815def is_sims_ready_by_adb(log, ad):
816    states = list(ad.adb.getprop("gsm.sim.state").split(","))
817    ad.log.info("gsm.sim.state = %s", states)
818    for state in states:
819        if state != SIM_STATE_READY and state != SIM_STATE_LOADED:
820            return False
821    return True
822
823
824def wait_for_sims_ready_by_adb(log, ad, wait_time=90):
825    return _wait_for_droid_in_state(log, ad, wait_time, is_sims_ready_by_adb)
826
827
828def get_service_state_by_adb(log, ad):
829    output = ad.adb.shell("dumpsys telephony.registry | grep mServiceState")
830    if "mVoiceRegState" in output:
831        result = re.findall(r"mVoiceRegState=(\S+)\((\S+)\)", output)
832        if result:
833            if getattr(ad, 'dsds', False):
834                default_slot = getattr(ad, 'default_slot', 0)
835                ad.log.info("mVoiceRegState is %s %s", result[default_slot][0],
836                            result[default_slot][1])
837                return result[default_slot][1]
838            else:
839                ad.log.info("mVoiceRegState is %s %s", result[0][0],
840                            result[0][1])
841                return result[0][1]
842    else:
843        result = re.search(r"mServiceState=(\S+)", output)
844        if result:
845            ad.log.info("mServiceState=%s %s", result.group(1),
846                        SERVICE_STATE_MAPPING[result.group(1)])
847            return SERVICE_STATE_MAPPING[result.group(1)]
848
849
850def _is_expecting_event(event_recv_list):
851    """ check for more event is expected in event list
852
853    Args:
854        event_recv_list: list of events
855    Returns:
856        result: True if more events are expected. False if not.
857    """
858    for state in event_recv_list:
859        if state is False:
860            return True
861    return False
862
863
864def _set_event_list(event_recv_list, sub_id_list, sub_id, value):
865    """ set received event in expected event list
866
867    Args:
868        event_recv_list: list of received events
869        sub_id_list: subscription ID list
870        sub_id: subscription id of current event
871        value: True or False
872    Returns:
873        None.
874    """
875    for i in range(len(sub_id_list)):
876        if sub_id_list[i] == sub_id:
877            event_recv_list[i] = value
878
879
880def _wait_for_bluetooth_in_state(log, ad, state, max_wait):
881    # FIXME: These event names should be defined in a common location
882    _BLUETOOTH_STATE_ON_EVENT = 'BluetoothStateChangedOn'
883    _BLUETOOTH_STATE_OFF_EVENT = 'BluetoothStateChangedOff'
884    ad.ed.clear_events(_BLUETOOTH_STATE_ON_EVENT)
885    ad.ed.clear_events(_BLUETOOTH_STATE_OFF_EVENT)
886
887    ad.droid.bluetoothStartListeningForAdapterStateChange()
888    try:
889        bt_state = ad.droid.bluetoothCheckState()
890        if bt_state == state:
891            return True
892        if max_wait <= 0:
893            ad.log.error("Time out: bluetooth state still %s, expecting %s",
894                         bt_state, state)
895            return False
896
897        event = {
898            False: _BLUETOOTH_STATE_OFF_EVENT,
899            True: _BLUETOOTH_STATE_ON_EVENT
900        }[state]
901        event = ad.ed.pop_event(event, max_wait)
902        ad.log.info("Got event %s", event['name'])
903        return True
904    except Empty:
905        ad.log.error("Time out: bluetooth state still in %s, expecting %s",
906                     bt_state, state)
907        return False
908    finally:
909        ad.droid.bluetoothStopListeningForAdapterStateChange()
910
911
912# TODO: replace this with an event-based function
913def _wait_for_wifi_in_state(log, ad, state, max_wait):
914    return _wait_for_droid_in_state(log, ad, max_wait,
915        lambda log, ad, state: \
916                (True if ad.droid.wifiCheckState() == state else False),
917                state)
918
919
920def toggle_airplane_mode_msim(log, ad, new_state=None, strict_checking=True):
921    """ Toggle the state of airplane mode.
922
923    Args:
924        log: log handler.
925        ad: android_device object.
926        new_state: Airplane mode state to set to.
927            If None, opposite of the current state.
928        strict_checking: Whether to turn on strict checking that checks all features.
929
930    Returns:
931        result: True if operation succeed. False if error happens.
932    """
933
934    cur_state = ad.droid.connectivityCheckAirplaneMode()
935    if cur_state == new_state:
936        ad.log.info("Airplane mode already in %s", new_state)
937        return True
938    elif new_state is None:
939        new_state = not cur_state
940        ad.log.info("Toggle APM mode, from current tate %s to %s", cur_state,
941                    new_state)
942    sub_id_list = []
943    active_sub_info = ad.droid.subscriptionGetAllSubInfoList()
944    if active_sub_info:
945        for info in active_sub_info:
946            sub_id_list.append(info['subscriptionId'])
947
948    ad.ed.clear_all_events()
949    time.sleep(0.1)
950    service_state_list = []
951    if new_state:
952        service_state_list.append(SERVICE_STATE_POWER_OFF)
953        ad.log.info("Turn on airplane mode")
954
955    else:
956        # If either one of these 3 events show up, it should be OK.
957        # Normal SIM, phone in service
958        service_state_list.append(SERVICE_STATE_IN_SERVICE)
959        # NO SIM, or Dead SIM, or no Roaming coverage.
960        service_state_list.append(SERVICE_STATE_OUT_OF_SERVICE)
961        service_state_list.append(SERVICE_STATE_EMERGENCY_ONLY)
962        ad.log.info("Turn off airplane mode")
963
964    for sub_id in sub_id_list:
965        ad.droid.telephonyStartTrackingServiceStateChangeForSubscription(
966            sub_id)
967
968    timeout_time = time.time() + MAX_WAIT_TIME_AIRPLANEMODE_EVENT
969    ad.droid.connectivityToggleAirplaneMode(new_state)
970
971    try:
972        try:
973            event = ad.ed.wait_for_event(
974                EventServiceStateChanged,
975                is_event_match_for_list,
976                timeout=MAX_WAIT_TIME_AIRPLANEMODE_EVENT,
977                field=ServiceStateContainer.SERVICE_STATE,
978                value_list=service_state_list)
979            ad.log.info("Got event %s", event)
980        except Empty:
981            ad.log.warning("Did not get expected service state change to %s",
982                           service_state_list)
983        finally:
984            for sub_id in sub_id_list:
985                ad.droid.telephonyStopTrackingServiceStateChangeForSubscription(
986                    sub_id)
987    except Exception as e:
988        ad.log.error(e)
989
990    # APM on (new_state=True) will turn off bluetooth but may not turn it on
991    try:
992        if new_state and not _wait_for_bluetooth_in_state(
993                log, ad, False, timeout_time - time.time()):
994            ad.log.error(
995                "Failed waiting for bluetooth during airplane mode toggle")
996            if strict_checking: return False
997    except Exception as e:
998        ad.log.error("Failed to check bluetooth state due to %s", e)
999        if strict_checking:
1000            raise
1001
1002    # APM on (new_state=True) will turn off wifi but may not turn it on
1003    if new_state and not _wait_for_wifi_in_state(log, ad, False,
1004                                                 timeout_time - time.time()):
1005        ad.log.error("Failed waiting for wifi during airplane mode toggle on")
1006        if strict_checking: return False
1007
1008    if ad.droid.connectivityCheckAirplaneMode() != new_state:
1009        ad.log.error("Set airplane mode to %s failed", new_state)
1010        return False
1011    return True
1012
1013
1014def wait_and_answer_call(log,
1015                         ad,
1016                         incoming_number=None,
1017                         incall_ui_display=INCALL_UI_DISPLAY_FOREGROUND,
1018                         caller=None,
1019                         video_state=None):
1020    """Wait for an incoming call on default voice subscription and
1021       accepts the call.
1022
1023    Args:
1024        ad: android device object.
1025        incoming_number: Expected incoming number.
1026            Optional. Default is None
1027        incall_ui_display: after answer the call, bring in-call UI to foreground or
1028            background. Optional, default value is INCALL_UI_DISPLAY_FOREGROUND.
1029            if = INCALL_UI_DISPLAY_FOREGROUND, bring in-call UI to foreground.
1030            if = INCALL_UI_DISPLAY_BACKGROUND, bring in-call UI to background.
1031            else, do nothing.
1032
1033    Returns:
1034        True: if incoming call is received and answered successfully.
1035        False: for errors
1036        """
1037    return wait_and_answer_call_for_subscription(
1038        log,
1039        ad,
1040        get_incoming_voice_sub_id(ad),
1041        incoming_number,
1042        incall_ui_display=incall_ui_display,
1043        caller=caller,
1044        video_state=video_state)
1045
1046
1047def _wait_for_ringing_event(log, ad, wait_time):
1048    """Wait for ringing event.
1049
1050    Args:
1051        log: log object.
1052        ad: android device object.
1053        wait_time: max time to wait for ringing event.
1054
1055    Returns:
1056        event_ringing if received ringing event.
1057        otherwise return None.
1058    """
1059    event_ringing = None
1060
1061    try:
1062        event_ringing = ad.ed.wait_for_event(
1063            EventCallStateChanged,
1064            is_event_match,
1065            timeout=wait_time,
1066            field=CallStateContainer.CALL_STATE,
1067            value=TELEPHONY_STATE_RINGING)
1068        ad.log.info("Receive ringing event")
1069    except Empty:
1070        ad.log.info("No Ringing Event")
1071    finally:
1072        return event_ringing
1073
1074
1075def wait_for_ringing_call(log, ad, incoming_number=None):
1076    """Wait for an incoming call on default voice subscription and
1077       accepts the call.
1078
1079    Args:
1080        log: log object.
1081        ad: android device object.
1082        incoming_number: Expected incoming number.
1083            Optional. Default is None
1084
1085    Returns:
1086        True: if incoming call is received and answered successfully.
1087        False: for errors
1088        """
1089    return wait_for_ringing_call_for_subscription(
1090        log, ad, get_incoming_voice_sub_id(ad), incoming_number)
1091
1092
1093def wait_for_ringing_call_for_subscription(
1094        log,
1095        ad,
1096        sub_id,
1097        incoming_number=None,
1098        caller=None,
1099        event_tracking_started=False,
1100        timeout=MAX_WAIT_TIME_CALLEE_RINGING,
1101        interval=WAIT_TIME_BETWEEN_STATE_CHECK):
1102    """Wait for an incoming call on specified subscription.
1103
1104    Args:
1105        log: log object.
1106        ad: android device object.
1107        sub_id: subscription ID
1108        incoming_number: Expected incoming number. Default is None
1109        event_tracking_started: True if event tracking already state outside
1110        timeout: time to wait for ring
1111        interval: checking interval
1112
1113    Returns:
1114        True: if incoming call is received and answered successfully.
1115        False: for errors
1116    """
1117    if not event_tracking_started:
1118        ad.ed.clear_events(EventCallStateChanged)
1119        ad.droid.telephonyStartTrackingCallStateForSubscription(sub_id)
1120    ring_event_received = False
1121    end_time = time.time() + timeout
1122    try:
1123        while time.time() < end_time:
1124            if not ring_event_received:
1125                event_ringing = _wait_for_ringing_event(log, ad, interval)
1126                if event_ringing:
1127                    if incoming_number and not check_phone_number_match(
1128                            event_ringing['data']
1129                        [CallStateContainer.INCOMING_NUMBER], incoming_number):
1130                        ad.log.error(
1131                            "Incoming Number not match. Expected number:%s, actual number:%s",
1132                            incoming_number, event_ringing['data'][
1133                                CallStateContainer.INCOMING_NUMBER])
1134                        return False
1135                    ring_event_received = True
1136            telephony_state = ad.droid.telephonyGetCallStateForSubscription(
1137                sub_id)
1138            telecom_state = ad.droid.telecomGetCallState()
1139            if telephony_state == TELEPHONY_STATE_RINGING and (
1140                    telecom_state == TELEPHONY_STATE_RINGING):
1141                ad.log.info("callee is in telephony and telecom RINGING state")
1142                if caller:
1143                    if caller.droid.telecomIsInCall():
1144                        caller.log.info("Caller telecom is in call state")
1145                        return True
1146                    else:
1147                        caller.log.info("Caller telecom is NOT in call state")
1148                else:
1149                    return True
1150            else:
1151                ad.log.info(
1152                    "telephony in %s, telecom in %s, expecting RINGING state",
1153                    telephony_state, telecom_state)
1154            time.sleep(interval)
1155    finally:
1156        if not event_tracking_started:
1157            ad.droid.telephonyStopTrackingCallStateChangeForSubscription(
1158                sub_id)
1159
1160
1161def wait_for_call_offhook_for_subscription(
1162        log,
1163        ad,
1164        sub_id,
1165        event_tracking_started=False,
1166        timeout=MAX_WAIT_TIME_ACCEPT_CALL_TO_OFFHOOK_EVENT,
1167        interval=WAIT_TIME_BETWEEN_STATE_CHECK):
1168    """Wait for an incoming call on specified subscription.
1169
1170    Args:
1171        log: log object.
1172        ad: android device object.
1173        sub_id: subscription ID
1174        timeout: time to wait for ring
1175        interval: checking interval
1176
1177    Returns:
1178        True: if incoming call is received and answered successfully.
1179        False: for errors
1180    """
1181    if not event_tracking_started:
1182        ad.ed.clear_events(EventCallStateChanged)
1183        ad.droid.telephonyStartTrackingCallStateForSubscription(sub_id)
1184    offhook_event_received = False
1185    end_time = time.time() + timeout
1186    try:
1187        while time.time() < end_time:
1188            if not offhook_event_received:
1189                if wait_for_call_offhook_event(log, ad, sub_id, True,
1190                                               interval):
1191                    offhook_event_received = True
1192            telephony_state = ad.droid.telephonyGetCallStateForSubscription(
1193                sub_id)
1194            telecom_state = ad.droid.telecomGetCallState()
1195            if telephony_state == TELEPHONY_STATE_OFFHOOK and (
1196                    telecom_state == TELEPHONY_STATE_OFFHOOK):
1197                ad.log.info("telephony and telecom are in OFFHOOK state")
1198                return True
1199            else:
1200                ad.log.info(
1201                    "telephony in %s, telecom in %s, expecting OFFHOOK state",
1202                    telephony_state, telecom_state)
1203            if offhook_event_received:
1204                time.sleep(interval)
1205    finally:
1206        if not event_tracking_started:
1207            ad.droid.telephonyStopTrackingCallStateChangeForSubscription(
1208                sub_id)
1209
1210
1211def wait_for_call_offhook_event(
1212        log,
1213        ad,
1214        sub_id,
1215        event_tracking_started=False,
1216        timeout=MAX_WAIT_TIME_ACCEPT_CALL_TO_OFFHOOK_EVENT):
1217    """Wait for an incoming call on specified subscription.
1218
1219    Args:
1220        log: log object.
1221        ad: android device object.
1222        event_tracking_started: True if event tracking already state outside
1223        timeout: time to wait for event
1224
1225    Returns:
1226        True: if call offhook event is received.
1227        False: if call offhook event is not received.
1228    """
1229    if not event_tracking_started:
1230        ad.ed.clear_events(EventCallStateChanged)
1231        ad.droid.telephonyStartTrackingCallStateForSubscription(sub_id)
1232    try:
1233        ad.ed.wait_for_event(
1234            EventCallStateChanged,
1235            is_event_match,
1236            timeout=timeout,
1237            field=CallStateContainer.CALL_STATE,
1238            value=TELEPHONY_STATE_OFFHOOK)
1239        ad.log.info("Got event %s", TELEPHONY_STATE_OFFHOOK)
1240    except Empty:
1241        ad.log.info("No event for call state change to OFFHOOK")
1242        return False
1243    finally:
1244        if not event_tracking_started:
1245            ad.droid.telephonyStopTrackingCallStateChangeForSubscription(
1246                sub_id)
1247    return True
1248
1249
1250def wait_and_answer_call_for_subscription(
1251        log,
1252        ad,
1253        sub_id,
1254        incoming_number=None,
1255        incall_ui_display=INCALL_UI_DISPLAY_FOREGROUND,
1256        timeout=MAX_WAIT_TIME_CALLEE_RINGING,
1257        caller=None,
1258        video_state=None):
1259    """Wait for an incoming call on specified subscription and
1260       accepts the call.
1261
1262    Args:
1263        log: log object.
1264        ad: android device object.
1265        sub_id: subscription ID
1266        incoming_number: Expected incoming number.
1267            Optional. Default is None
1268        incall_ui_display: after answer the call, bring in-call UI to foreground or
1269            background. Optional, default value is INCALL_UI_DISPLAY_FOREGROUND.
1270            if = INCALL_UI_DISPLAY_FOREGROUND, bring in-call UI to foreground.
1271            if = INCALL_UI_DISPLAY_BACKGROUND, bring in-call UI to background.
1272            else, do nothing.
1273
1274    Returns:
1275        True: if incoming call is received and answered successfully.
1276        False: for errors
1277    """
1278    ad.ed.clear_events(EventCallStateChanged)
1279    ad.droid.telephonyStartTrackingCallStateForSubscription(sub_id)
1280    try:
1281        if not wait_for_ringing_call_for_subscription(
1282                log,
1283                ad,
1284                sub_id,
1285                incoming_number=incoming_number,
1286                caller=caller,
1287                event_tracking_started=True,
1288                timeout=timeout):
1289            ad.log.info("Incoming call ringing check failed.")
1290            return False
1291        ad.log.info("Accept the ring call")
1292        ad.droid.telecomAcceptRingingCall(video_state)
1293
1294        if wait_for_call_offhook_for_subscription(
1295                log, ad, sub_id, event_tracking_started=True):
1296            return True
1297        else:
1298            ad.log.error("Could not answer the call.")
1299            return False
1300    except Exception as e:
1301        log.error(e)
1302        return False
1303    finally:
1304        ad.droid.telephonyStopTrackingCallStateChangeForSubscription(sub_id)
1305        if incall_ui_display == INCALL_UI_DISPLAY_FOREGROUND:
1306            ad.droid.telecomShowInCallScreen()
1307        elif incall_ui_display == INCALL_UI_DISPLAY_BACKGROUND:
1308            ad.droid.showHomeScreen()
1309
1310
1311def wait_and_reject_call(log,
1312                         ad,
1313                         incoming_number=None,
1314                         delay_reject=WAIT_TIME_REJECT_CALL,
1315                         reject=True):
1316    """Wait for an incoming call on default voice subscription and
1317       reject the call.
1318
1319    Args:
1320        log: log object.
1321        ad: android device object.
1322        incoming_number: Expected incoming number.
1323            Optional. Default is None
1324        delay_reject: time to wait before rejecting the call
1325            Optional. Default is WAIT_TIME_REJECT_CALL
1326
1327    Returns:
1328        True: if incoming call is received and reject successfully.
1329        False: for errors
1330    """
1331    return wait_and_reject_call_for_subscription(log, ad,
1332                                                 get_incoming_voice_sub_id(ad),
1333                                                 incoming_number, delay_reject,
1334                                                 reject)
1335
1336
1337def wait_and_reject_call_for_subscription(log,
1338                                          ad,
1339                                          sub_id,
1340                                          incoming_number=None,
1341                                          delay_reject=WAIT_TIME_REJECT_CALL,
1342                                          reject=True):
1343    """Wait for an incoming call on specific subscription and
1344       reject the call.
1345
1346    Args:
1347        log: log object.
1348        ad: android device object.
1349        sub_id: subscription ID
1350        incoming_number: Expected incoming number.
1351            Optional. Default is None
1352        delay_reject: time to wait before rejecting the call
1353            Optional. Default is WAIT_TIME_REJECT_CALL
1354
1355    Returns:
1356        True: if incoming call is received and reject successfully.
1357        False: for errors
1358    """
1359
1360    if not wait_for_ringing_call_for_subscription(log, ad, sub_id,
1361                                                  incoming_number):
1362        ad.log.error(
1363            "Could not reject a call: incoming call in ringing check failed.")
1364        return False
1365
1366    ad.ed.clear_events(EventCallStateChanged)
1367    ad.droid.telephonyStartTrackingCallStateForSubscription(sub_id)
1368    if reject is True:
1369        # Delay between ringing and reject.
1370        time.sleep(delay_reject)
1371        is_find = False
1372        # Loop the call list and find the matched one to disconnect.
1373        for call in ad.droid.telecomCallGetCallIds():
1374            if check_phone_number_match(
1375                    get_number_from_tel_uri(get_call_uri(ad, call)),
1376                    incoming_number):
1377                ad.droid.telecomCallDisconnect(call)
1378                ad.log.info("Callee reject the call")
1379                is_find = True
1380        if is_find is False:
1381            ad.log.error("Callee did not find matching call to reject.")
1382            return False
1383    else:
1384        # don't reject on callee. Just ignore the incoming call.
1385        ad.log.info("Callee received incoming call. Ignore it.")
1386    try:
1387        ad.ed.wait_for_event(
1388            EventCallStateChanged,
1389            is_event_match_for_list,
1390            timeout=MAX_WAIT_TIME_CALL_IDLE_EVENT,
1391            field=CallStateContainer.CALL_STATE,
1392            value_list=[TELEPHONY_STATE_IDLE, TELEPHONY_STATE_OFFHOOK])
1393    except Empty:
1394        ad.log.error("No onCallStateChangedIdle event received.")
1395        return False
1396    finally:
1397        ad.droid.telephonyStopTrackingCallStateChangeForSubscription(sub_id)
1398    return True
1399
1400
1401def hangup_call(log, ad, is_emergency=False):
1402    """Hang up ongoing active call.
1403
1404    Args:
1405        log: log object.
1406        ad: android device object.
1407
1408    Returns:
1409        True: if all calls are cleared
1410        False: for errors
1411    """
1412    # short circuit in case no calls are active
1413    if not ad.droid.telecomIsInCall():
1414        ad.log.warning("No active call exists.")
1415        return True
1416    ad.ed.clear_events(EventCallStateChanged)
1417    ad.droid.telephonyStartTrackingCallState()
1418    ad.log.info("Hangup call.")
1419    if is_emergency:
1420        for call in ad.droid.telecomCallGetCallIds():
1421            ad.droid.telecomCallDisconnect(call)
1422    else:
1423        ad.droid.telecomEndCall()
1424
1425    try:
1426        ad.ed.wait_for_event(
1427            EventCallStateChanged,
1428            is_event_match,
1429            timeout=MAX_WAIT_TIME_CALL_IDLE_EVENT,
1430            field=CallStateContainer.CALL_STATE,
1431            value=TELEPHONY_STATE_IDLE)
1432    except Empty:
1433        ad.log.warning("Call state IDLE event is not received after hang up.")
1434    finally:
1435        ad.droid.telephonyStopTrackingCallStateChange()
1436    if not wait_for_state(ad.droid.telecomIsInCall, False, 15, 1):
1437        ad.log.error("Telecom is in call, hangup call failed.")
1438        return False
1439    return True
1440
1441
1442def wait_for_cbrs_data_active_sub_change_event(
1443        ad,
1444        event_tracking_started=False,
1445        timeout=120):
1446    """Wait for an data change event on specified subscription.
1447
1448    Args:
1449        ad: android device object.
1450        event_tracking_started: True if event tracking already state outside
1451        timeout: time to wait for event
1452
1453    Returns:
1454        True: if data change event is received.
1455        False: if data change event is not received.
1456    """
1457    if not event_tracking_started:
1458        ad.ed.clear_events(EventActiveDataSubIdChanged)
1459        ad.droid.telephonyStartTrackingActiveDataChange()
1460    try:
1461        ad.ed.wait_for_event(
1462            EventActiveDataSubIdChanged,
1463            is_event_match,
1464            timeout=timeout)
1465        ad.log.info("Got event activedatasubidchanged")
1466    except Empty:
1467        ad.log.info("No event for data subid change")
1468        return False
1469    finally:
1470        if not event_tracking_started:
1471            ad.droid.telephonyStopTrackingActiveDataChange()
1472    return True
1473
1474
1475def is_current_data_on_cbrs(ad, cbrs_subid):
1476    """Verifies if current data sub is on CBRS
1477
1478    Args:
1479        ad: android device object.
1480        cbrs_subid: sub_id against which we need to check
1481
1482    Returns:
1483        True: if data is on cbrs
1484        False: if data is not on cbrs
1485    """
1486    if cbrs_subid is None:
1487        return False
1488    current_data = ad.droid.subscriptionGetActiveDataSubscriptionId()
1489    ad.log.info("Current Data subid %s cbrs_subid %s", current_data, cbrs_subid)
1490    if current_data == cbrs_subid:
1491        return True
1492    else:
1493        return False
1494
1495
1496def get_current_override_network_type(ad, timeout=30):
1497    """Returns current override network type
1498
1499    Args:
1500        ad: android device object.
1501        timeout: max time to wait for event
1502
1503    Returns:
1504        value: current override type
1505        -1: if no event received
1506    """
1507    override_value_list = [OverrideNetworkContainer.OVERRIDE_NETWORK_TYPE_NR_NSA,
1508                           OverrideNetworkContainer.OVERRIDE_NETWORK_TYPE_NONE,
1509                           OverrideNetworkContainer.OVERRIDE_NETWORK_TYPE_NR_MMWAVE,
1510                           OverrideNetworkContainer.OVERRIDE_NETWORK_TYPE_LTE_CA,
1511                           OverrideNetworkContainer.OVERRIDE_NETWORK_TYPE_LTE_ADVANCED_PRO]
1512    ad.ed.clear_events(EventDisplayInfoChanged)
1513    ad.droid.telephonyStartTrackingDisplayInfoChange()
1514    try:
1515        event = ad.ed.wait_for_event(
1516                    EventDisplayInfoChanged,
1517                    is_event_match_for_list,
1518                    timeout=timeout,
1519                    field=DisplayInfoContainer.OVERRIDE,
1520                    value_list=override_value_list)
1521        override_type = event['data']['override']
1522        ad.log.info("Current Override Type is %s", override_type)
1523        return override_type
1524    except Empty:
1525        ad.log.info("No event for display info change")
1526        return -1
1527    finally:
1528        ad.droid.telephonyStopTrackingDisplayInfoChange()
1529    return -1
1530
1531def disconnect_call_by_id(log, ad, call_id):
1532    """Disconnect call by call id.
1533    """
1534    ad.droid.telecomCallDisconnect(call_id)
1535    return True
1536
1537
1538def _phone_number_remove_prefix(number):
1539    """Remove the country code and other prefix from the input phone number.
1540    Currently only handle phone number with the following formats:
1541        (US phone number format)
1542        +1abcxxxyyyy
1543        1abcxxxyyyy
1544        abcxxxyyyy
1545        abc xxx yyyy
1546        abc.xxx.yyyy
1547        abc-xxx-yyyy
1548        (EEUK phone number format)
1549        +44abcxxxyyyy
1550        0abcxxxyyyy
1551
1552    Args:
1553        number: input phone number
1554
1555    Returns:
1556        Phone number without country code or prefix
1557    """
1558    if number is None:
1559        return None, None
1560    for country_code in COUNTRY_CODE_LIST:
1561        if number.startswith(country_code):
1562            return number[len(country_code):], country_code
1563    if number[0] == "1" or number[0] == "0":
1564        return number[1:], None
1565    return number, None
1566
1567
1568def check_phone_number_match(number1, number2):
1569    """Check whether two input phone numbers match or not.
1570
1571    Compare the two input phone numbers.
1572    If they match, return True; otherwise, return False.
1573    Currently only handle phone number with the following formats:
1574        (US phone number format)
1575        +1abcxxxyyyy
1576        1abcxxxyyyy
1577        abcxxxyyyy
1578        abc xxx yyyy
1579        abc.xxx.yyyy
1580        abc-xxx-yyyy
1581        (EEUK phone number format)
1582        +44abcxxxyyyy
1583        0abcxxxyyyy
1584
1585        There are some scenarios we can not verify, one example is:
1586            number1 = +15555555555, number2 = 5555555555
1587            (number2 have no country code)
1588
1589    Args:
1590        number1: 1st phone number to be compared.
1591        number2: 2nd phone number to be compared.
1592
1593    Returns:
1594        True if two phone numbers match. Otherwise False.
1595    """
1596    number1 = phone_number_formatter(number1)
1597    number2 = phone_number_formatter(number2)
1598    # Handle extra country code attachment when matching phone number
1599    if number1[-7:] in number2 or number2[-7:] in number1:
1600        return True
1601    else:
1602        logging.info("phone number1 %s and number2 %s does not match" %
1603                     (number1, number2))
1604        return False
1605
1606
1607def initiate_call(log,
1608                  ad,
1609                  callee_number,
1610                  emergency=False,
1611                  timeout=MAX_WAIT_TIME_CALL_INITIATION,
1612                  checking_interval=5,
1613                  incall_ui_display=INCALL_UI_DISPLAY_FOREGROUND,
1614                  video=False,
1615                  voice_type_init=None,
1616                  call_stats_check=False,
1617                  result_info=result_dict,
1618                  nsa_5g_for_stress=False):
1619    """Make phone call from caller to callee.
1620
1621    Args:
1622        ad_caller: Caller android device object.
1623        callee_number: Callee phone number.
1624        emergency : specify the call is emergency.
1625            Optional. Default value is False.
1626        incall_ui_display: show the dialer UI foreground or backgroud
1627        video: whether to initiate as video call
1628
1629    Returns:
1630        result: if phone call is placed successfully.
1631    """
1632    ad.ed.clear_events(EventCallStateChanged)
1633    sub_id = get_outgoing_voice_sub_id(ad)
1634    begin_time = get_device_epoch_time(ad)
1635    ad.droid.telephonyStartTrackingCallStateForSubscription(sub_id)
1636    try:
1637        # Make a Call
1638        ad.log.info("Make a phone call to %s", callee_number)
1639        if emergency:
1640            ad.droid.telecomCallEmergencyNumber(callee_number)
1641        else:
1642            ad.droid.telecomCallNumber(callee_number, video)
1643
1644        # Verify OFFHOOK state
1645        if not wait_for_call_offhook_for_subscription(
1646                log, ad, sub_id, event_tracking_started=True):
1647            ad.log.info("sub_id %s not in call offhook state", sub_id)
1648            last_call_drop_reason(ad, begin_time=begin_time)
1649            return False
1650        else:
1651            return True
1652
1653        if call_stats_check:
1654            voice_type_in_call = ad.droid.telephonyGetCurrentVoiceNetworkType()
1655            phone_call_type = check_call_status(ad,
1656                                                voice_type_init,
1657                                                voice_type_in_call)
1658            result_info["Call Stats"] = phone_call_type
1659            ad.log.debug("Voice Call Type: %s", phone_call_type)
1660
1661    finally:
1662        if hasattr(ad, "sdm_log") and getattr(ad, "sdm_log"):
1663            ad.adb.shell("i2cset -fy 3 64 6 1 b", ignore_status=True)
1664            ad.adb.shell("i2cset -fy 3 65 6 1 b", ignore_status=True)
1665        ad.droid.telephonyStopTrackingCallStateChangeForSubscription(sub_id)
1666
1667        if nsa_5g_for_stress:
1668            if not is_current_network_5g_nsa(ad):
1669                ad.log.error("Phone is not attached on 5G NSA")
1670
1671        if incall_ui_display == INCALL_UI_DISPLAY_FOREGROUND:
1672            ad.droid.telecomShowInCallScreen()
1673        elif incall_ui_display == INCALL_UI_DISPLAY_BACKGROUND:
1674            ad.droid.showHomeScreen()
1675
1676
1677def dial_phone_number(ad, callee_number):
1678    for number in str(callee_number):
1679        if number == "#":
1680            ad.send_keycode("POUND")
1681        elif number == "*":
1682            ad.send_keycode("STAR")
1683        elif number in ["1", "2", "3", "4", "5", "6", "7", "8", "9", "0"]:
1684            ad.send_keycode("%s" % number)
1685
1686
1687def get_call_state_by_adb(ad):
1688    slot_index_of_default_voice_subid = get_slot_index_from_subid(ad.log, ad,
1689        get_incoming_voice_sub_id(ad))
1690    output = ad.adb.shell("dumpsys telephony.registry | grep mCallState")
1691    if "mCallState" in output:
1692        call_state_list = re.findall("mCallState=(\d)", output)
1693        if call_state_list:
1694            return call_state_list[slot_index_of_default_voice_subid]
1695
1696
1697def check_call_state_connected_by_adb(ad):
1698    return "2" in get_call_state_by_adb(ad)
1699
1700
1701def check_call_state_idle_by_adb(ad):
1702    return "0" in get_call_state_by_adb(ad)
1703
1704
1705def check_call_state_ring_by_adb(ad):
1706    return "1" in get_call_state_by_adb(ad)
1707
1708
1709def get_incoming_call_number_by_adb(ad):
1710    output = ad.adb.shell(
1711        "dumpsys telephony.registry | grep mCallIncomingNumber")
1712    return re.search(r"mCallIncomingNumber=(.*)", output).group(1)
1713
1714
1715def emergency_dialer_call_by_keyevent(ad, callee_number):
1716    for i in range(3):
1717        if "EmergencyDialer" in ad.get_my_current_focus_window():
1718            ad.log.info("EmergencyDialer is the current focus window")
1719            break
1720        elif i <= 2:
1721            ad.adb.shell("am start -a com.android.phone.EmergencyDialer.DIAL")
1722            time.sleep(1)
1723        else:
1724            ad.log.error("Unable to bring up EmergencyDialer")
1725            return False
1726    ad.log.info("Make a phone call to %s", callee_number)
1727    dial_phone_number(ad, callee_number)
1728    ad.send_keycode("CALL")
1729
1730
1731def initiate_emergency_dialer_call_by_adb(
1732        log,
1733        ad,
1734        callee_number,
1735        timeout=MAX_WAIT_TIME_CALL_INITIATION,
1736        checking_interval=5):
1737    """Make emergency call by EmergencyDialer.
1738
1739    Args:
1740        ad: Caller android device object.
1741        callee_number: Callee phone number.
1742        emergency : specify the call is emergency.
1743        Optional. Default value is False.
1744
1745    Returns:
1746        result: if phone call is placed successfully.
1747    """
1748    try:
1749        # Make a Call
1750        ad.wakeup_screen()
1751        ad.send_keycode("MENU")
1752        ad.log.info("Call %s", callee_number)
1753        ad.adb.shell("am start -a com.android.phone.EmergencyDialer.DIAL")
1754        ad.adb.shell(
1755            "am start -a android.intent.action.CALL_EMERGENCY -d tel:%s" %
1756            callee_number)
1757        if not timeout: return True
1758        ad.log.info("Check call state")
1759        # Verify Call State
1760        elapsed_time = 0
1761        while elapsed_time < timeout:
1762            time.sleep(checking_interval)
1763            elapsed_time += checking_interval
1764            if check_call_state_connected_by_adb(ad):
1765                ad.log.info("Call to %s is connected", callee_number)
1766                return True
1767            if check_call_state_idle_by_adb(ad):
1768                ad.log.info("Call to %s failed", callee_number)
1769                return False
1770        ad.log.info("Make call to %s failed", callee_number)
1771        return False
1772    except Exception as e:
1773        ad.log.error("initiate emergency call failed with error %s", e)
1774
1775
1776def hangup_call_by_adb(ad):
1777    """Make emergency call by EmergencyDialer.
1778
1779    Args:
1780        ad: Caller android device object.
1781        callee_number: Callee phone number.
1782    """
1783    ad.log.info("End call by adb")
1784    ad.send_keycode("ENDCALL")
1785
1786
1787def dumpsys_all_call_info(ad):
1788    """ Get call information by dumpsys telecom. """
1789    output = ad.adb.shell("dumpsys telecom")
1790    calls = re.findall("Call TC@\d+: {(.*?)}", output, re.DOTALL)
1791    calls_info = []
1792    for call in calls:
1793        call_info = {}
1794        for attr in ("startTime", "endTime", "direction", "isInterrupted",
1795                     "callTechnologies", "callTerminationsReason",
1796                     "connectionService", "isVideoCall", "callProperties"):
1797            match = re.search(r"%s: (.*)" % attr, call)
1798            if match:
1799                if attr in ("startTime", "endTime"):
1800                    call_info[attr] = epoch_to_log_line_timestamp(
1801                        int(match.group(1)))
1802                else:
1803                    call_info[attr] = match.group(1)
1804        call_info["inCallServices"] = re.findall(r"name: (.*)", call)
1805        calls_info.append(call_info)
1806    ad.log.debug("calls_info = %s", calls_info)
1807    return calls_info
1808
1809
1810def dumpsys_last_call_info(ad):
1811    """ Get call information by dumpsys telecom. """
1812    num = dumpsys_last_call_number(ad)
1813    output = ad.adb.shell("dumpsys telecom")
1814    result = re.search(r"Call TC@%s: {(.*?)}" % num, output, re.DOTALL)
1815    call_info = {"TC": num}
1816    if result:
1817        result = result.group(1)
1818        for attr in ("startTime", "endTime", "direction", "isInterrupted",
1819                     "callTechnologies", "callTerminationsReason",
1820                     "isVideoCall", "callProperties"):
1821            match = re.search(r"%s: (.*)" % attr, result)
1822            if match:
1823                if attr in ("startTime", "endTime"):
1824                    call_info[attr] = epoch_to_log_line_timestamp(
1825                        int(match.group(1)))
1826                else:
1827                    call_info[attr] = match.group(1)
1828    ad.log.debug("call_info = %s", call_info)
1829    return call_info
1830
1831
1832def dumpsys_last_call_number(ad):
1833    output = ad.adb.shell("dumpsys telecom")
1834    call_nums = re.findall("Call TC@(\d+):", output)
1835    if not call_nums:
1836        return 0
1837    else:
1838        return int(call_nums[-1])
1839
1840
1841def dumpsys_new_call_info(ad, last_tc_number, retries=3, interval=5):
1842    for i in range(retries):
1843        if dumpsys_last_call_number(ad) > last_tc_number:
1844            call_info = dumpsys_last_call_info(ad)
1845            ad.log.info("New call info = %s", sorted(call_info.items()))
1846            return call_info
1847        else:
1848            time.sleep(interval)
1849    ad.log.error("New call is not in sysdump telecom")
1850    return {}
1851
1852
1853def dumpsys_carrier_config(ad):
1854    output = ad.adb.shell("dumpsys carrier_config").split("\n")
1855    output_phone_id_0 = []
1856    output_phone_id_1 = []
1857    current_output = []
1858    for line in output:
1859        if "Phone Id = 0" in line:
1860            current_output = output_phone_id_0
1861        elif "Phone Id = 1" in line:
1862            current_output = output_phone_id_1
1863        current_output.append(line.strip())
1864
1865    configs = {}
1866    if ad.adb.getprop("ro.build.version.release")[0] in ("9", "P"):
1867        phone_count = 1
1868        if "," in ad.adb.getprop("gsm.network.type"):
1869            phone_count = 2
1870    else:
1871        phone_count = ad.droid.telephonyGetPhoneCount()
1872
1873    slot_0_subid = get_subid_from_slot_index(ad.log, ad, 0)
1874    if slot_0_subid != INVALID_SUB_ID:
1875        configs[slot_0_subid] = {}
1876
1877    if phone_count == 2:
1878        slot_1_subid = get_subid_from_slot_index(ad.log, ad, 1)
1879        if slot_1_subid != INVALID_SUB_ID:
1880            configs[slot_1_subid] = {}
1881
1882    attrs = [attr for attr in dir(CarrierConfigs) if not attr.startswith("__")]
1883    for attr in attrs:
1884        attr_string = getattr(CarrierConfigs, attr)
1885        values = re.findall(
1886            r"%s = (\S+)" % attr_string, "\n".join(output_phone_id_0))
1887
1888        if slot_0_subid != INVALID_SUB_ID:
1889            if values:
1890                value = values[-1]
1891                if value == "true":
1892                    configs[slot_0_subid][attr_string] = True
1893                elif value == "false":
1894                    configs[slot_0_subid][attr_string] = False
1895                elif attr_string == CarrierConfigs.DEFAULT_WFC_IMS_MODE_INT:
1896                    if value == "0":
1897                        configs[slot_0_subid][attr_string] = WFC_MODE_WIFI_ONLY
1898                    elif value == "1":
1899                        configs[slot_0_subid][attr_string] = \
1900                            WFC_MODE_CELLULAR_PREFERRED
1901                    elif value == "2":
1902                        configs[slot_0_subid][attr_string] = \
1903                            WFC_MODE_WIFI_PREFERRED
1904                else:
1905                    try:
1906                        configs[slot_0_subid][attr_string] = int(value)
1907                    except Exception:
1908                        configs[slot_0_subid][attr_string] = value
1909            else:
1910                configs[slot_0_subid][attr_string] = None
1911
1912        if phone_count == 2:
1913            if slot_1_subid != INVALID_SUB_ID:
1914                values = re.findall(
1915                    r"%s = (\S+)" % attr_string, "\n".join(output_phone_id_1))
1916                if values:
1917                    value = values[-1]
1918                    if value == "true":
1919                        configs[slot_1_subid][attr_string] = True
1920                    elif value == "false":
1921                        configs[slot_1_subid][attr_string] = False
1922                    elif attr_string == CarrierConfigs.DEFAULT_WFC_IMS_MODE_INT:
1923                        if value == "0":
1924                            configs[slot_1_subid][attr_string] = \
1925                                WFC_MODE_WIFI_ONLY
1926                        elif value == "1":
1927                            configs[slot_1_subid][attr_string] = \
1928                                WFC_MODE_CELLULAR_PREFERRED
1929                        elif value == "2":
1930                            configs[slot_1_subid][attr_string] = \
1931                                WFC_MODE_WIFI_PREFERRED
1932                    else:
1933                        try:
1934                            configs[slot_1_subid][attr_string] = int(value)
1935                        except Exception:
1936                            configs[slot_1_subid][attr_string] = value
1937                else:
1938                    configs[slot_1_subid][attr_string] = None
1939    return configs
1940
1941
1942def get_phone_capability(ad):
1943    carrier_configs = dumpsys_carrier_config(ad)
1944    for sub_id in carrier_configs:
1945        capabilities = []
1946        if carrier_configs[sub_id][CarrierConfigs.VOLTE_AVAILABLE_BOOL]:
1947            capabilities.append(CAPABILITY_VOLTE)
1948        if carrier_configs[sub_id][CarrierConfigs.WFC_IMS_AVAILABLE_BOOL]:
1949            capabilities.append(CAPABILITY_WFC)
1950        if carrier_configs[sub_id][CarrierConfigs.EDITABLE_WFC_MODE_BOOL]:
1951            capabilities.append(CAPABILITY_WFC_MODE_CHANGE)
1952        if carrier_configs[sub_id][CarrierConfigs.SUPPORT_CONFERENCE_CALL_BOOL]:
1953            capabilities.append(CAPABILITY_CONFERENCE)
1954        if carrier_configs[sub_id][CarrierConfigs.VT_AVAILABLE_BOOL]:
1955            capabilities.append(CAPABILITY_VT)
1956        if carrier_configs[sub_id][CarrierConfigs.VOLTE_PROVISIONED_BOOL]:
1957            capabilities.append(CAPABILITY_VOLTE_PROVISIONING)
1958        if carrier_configs[sub_id][CarrierConfigs.VOLTE_OVERRIDE_WFC_BOOL]:
1959            capabilities.append(CAPABILITY_VOLTE_OVERRIDE_WFC_PROVISIONING)
1960        if carrier_configs[sub_id][CarrierConfigs.HIDE_ENHANCED_4G_LTE_BOOL]:
1961            capabilities.append(CAPABILITY_HIDE_ENHANCED_4G_LTE_BOOL)
1962
1963        ad.log.info("Capabilities of sub ID %s: %s", sub_id, capabilities)
1964        if not getattr(ad, 'telephony', {}):
1965            ad.telephony["subscription"] = {}
1966            ad.telephony["subscription"][sub_id] = {}
1967            setattr(
1968                ad.telephony["subscription"][sub_id],
1969                'capabilities', capabilities)
1970
1971        else:
1972            ad.telephony["subscription"][sub_id]["capabilities"] = capabilities
1973        if CAPABILITY_WFC not in capabilities:
1974            wfc_modes = []
1975        else:
1976            if carrier_configs[sub_id].get(
1977                CarrierConfigs.EDITABLE_WFC_MODE_BOOL, False):
1978                wfc_modes = [
1979                    WFC_MODE_CELLULAR_PREFERRED,
1980                    WFC_MODE_WIFI_PREFERRED]
1981            else:
1982                wfc_modes = [
1983                    carrier_configs[sub_id].get(
1984                        CarrierConfigs.DEFAULT_WFC_IMS_MODE_INT,
1985                        WFC_MODE_CELLULAR_PREFERRED)
1986                ]
1987        if carrier_configs[sub_id].get(
1988            CarrierConfigs.WFC_SUPPORTS_WIFI_ONLY_BOOL,
1989            False) and WFC_MODE_WIFI_ONLY not in wfc_modes:
1990            wfc_modes.append(WFC_MODE_WIFI_ONLY)
1991        ad.telephony["subscription"][sub_id]["wfc_modes"] = wfc_modes
1992        if wfc_modes:
1993            ad.log.info("Supported WFC modes for sub ID %s: %s", sub_id,
1994                wfc_modes)
1995
1996
1997def get_capability_for_subscription(ad, capability, subid):
1998    if capability in ad.telephony["subscription"][subid].get(
1999        "capabilities", []):
2000        ad.log.info('Capability "%s" is available for sub ID %s.',
2001            capability, subid)
2002        return True
2003    else:
2004        ad.log.info('Capability "%s" is NOT available for sub ID %s.',
2005            capability, subid)
2006        return False
2007
2008
2009def call_reject(log, ad_caller, ad_callee, reject=True):
2010    """Caller call Callee, then reject on callee.
2011
2012
2013    """
2014    subid_caller = ad_caller.droid.subscriptionGetDefaultVoiceSubId()
2015    subid_callee = ad_callee.incoming_voice_sub_id
2016    ad_caller.log.info("Sub-ID Caller %s, Sub-ID Callee %s", subid_caller,
2017                       subid_callee)
2018    return call_reject_for_subscription(log, ad_caller, ad_callee,
2019                                        subid_caller, subid_callee, reject)
2020
2021
2022def call_reject_for_subscription(log,
2023                                 ad_caller,
2024                                 ad_callee,
2025                                 subid_caller,
2026                                 subid_callee,
2027                                 reject=True):
2028    """
2029    """
2030
2031    caller_number = ad_caller.telephony['subscription'][subid_caller][
2032        'phone_num']
2033    callee_number = ad_callee.telephony['subscription'][subid_callee][
2034        'phone_num']
2035
2036    ad_caller.log.info("Call from %s to %s", caller_number, callee_number)
2037    if not initiate_call(log, ad_caller, callee_number):
2038        ad_caller.log.error("Initiate call failed")
2039        return False
2040
2041    if not wait_and_reject_call_for_subscription(
2042            log, ad_callee, subid_callee, caller_number, WAIT_TIME_REJECT_CALL,
2043            reject):
2044        ad_callee.log.error("Reject call fail.")
2045        return False
2046    # Check if incoming call is cleared on callee or not.
2047    if ad_callee.droid.telephonyGetCallStateForSubscription(
2048            subid_callee) == TELEPHONY_STATE_RINGING:
2049        ad_callee.log.error("Incoming call is not cleared")
2050        return False
2051    # Hangup on caller
2052    hangup_call(log, ad_caller)
2053    return True
2054
2055
2056def call_reject_leave_message(log,
2057                              ad_caller,
2058                              ad_callee,
2059                              verify_caller_func=None,
2060                              wait_time_in_call=WAIT_TIME_LEAVE_VOICE_MAIL):
2061    """On default voice subscription, Call from caller to callee,
2062    reject on callee, caller leave a voice mail.
2063
2064    1. Caller call Callee.
2065    2. Callee reject incoming call.
2066    3. Caller leave a voice mail.
2067    4. Verify callee received the voice mail notification.
2068
2069    Args:
2070        ad_caller: caller android device object.
2071        ad_callee: callee android device object.
2072        verify_caller_func: function to verify caller is in correct state while in-call.
2073            This is optional, default is None.
2074        wait_time_in_call: time to wait when leaving a voice mail.
2075            This is optional, default is WAIT_TIME_LEAVE_VOICE_MAIL
2076
2077    Returns:
2078        True: if voice message is received on callee successfully.
2079        False: for errors
2080    """
2081    subid_caller = get_outgoing_voice_sub_id(ad_caller)
2082    subid_callee = get_incoming_voice_sub_id(ad_callee)
2083    return call_reject_leave_message_for_subscription(
2084        log, ad_caller, ad_callee, subid_caller, subid_callee,
2085        verify_caller_func, wait_time_in_call)
2086
2087
2088def check_reject_needed_for_voice_mail(log, ad_callee):
2089    """Check if the carrier requires reject call to receive voice mail or just keep ringing
2090    Requested in b//155935290
2091    Four Japan carriers do not need to reject
2092    SBM, KDDI, Ntt Docomo, Rakuten
2093    Args:
2094        log: log object
2095        ad_callee: android device object
2096    Returns:
2097        True if callee's carrier is not one of the four Japan carriers
2098        False if callee's carrier is one of the four Japan carriers
2099    """
2100
2101    operators_no_reject = [CARRIER_NTT_DOCOMO,
2102                           CARRIER_KDDI,
2103                           CARRIER_RAKUTEN,
2104                           CARRIER_SBM]
2105    operator_name = get_operator_name(log, ad_callee)
2106
2107    return operator_name not in operators_no_reject
2108
2109
2110def call_reject_leave_message_for_subscription(
2111        log,
2112        ad_caller,
2113        ad_callee,
2114        subid_caller,
2115        subid_callee,
2116        verify_caller_func=None,
2117        wait_time_in_call=WAIT_TIME_LEAVE_VOICE_MAIL):
2118    """On specific voice subscription, Call from caller to callee,
2119    reject on callee, caller leave a voice mail.
2120
2121    1. Caller call Callee.
2122    2. Callee reject incoming call.
2123    3. Caller leave a voice mail.
2124    4. Verify callee received the voice mail notification.
2125
2126    Args:
2127        ad_caller: caller android device object.
2128        ad_callee: callee android device object.
2129        subid_caller: caller's subscription id.
2130        subid_callee: callee's subscription id.
2131        verify_caller_func: function to verify caller is in correct state while in-call.
2132            This is optional, default is None.
2133        wait_time_in_call: time to wait when leaving a voice mail.
2134            This is optional, default is WAIT_TIME_LEAVE_VOICE_MAIL
2135
2136    Returns:
2137        True: if voice message is received on callee successfully.
2138        False: for errors
2139    """
2140
2141    # Currently this test utility only works for TMO and ATT and SPT.
2142    # It does not work for VZW (see b/21559800)
2143    # "with VVM TelephonyManager APIs won't work for vm"
2144
2145    caller_number = ad_caller.telephony['subscription'][subid_caller][
2146        'phone_num']
2147    callee_number = ad_callee.telephony['subscription'][subid_callee][
2148        'phone_num']
2149
2150    ad_caller.log.info("Call from %s to %s", caller_number, callee_number)
2151
2152    try:
2153        voice_mail_count_before = ad_callee.droid.telephonyGetVoiceMailCountForSubscription(
2154            subid_callee)
2155        ad_callee.log.info("voice mail count is %s", voice_mail_count_before)
2156        # -1 means there are unread voice mail, but the count is unknown
2157        # 0 means either this API not working (VZW) or no unread voice mail.
2158        if voice_mail_count_before != 0:
2159            log.warning("--Pending new Voice Mail, please clear on phone.--")
2160
2161        if not initiate_call(log, ad_caller, callee_number):
2162            ad_caller.log.error("Initiate call failed.")
2163            return False
2164        if check_reject_needed_for_voice_mail(log, ad_callee):
2165            carrier_specific_delay_reject = 30
2166        else:
2167            carrier_specific_delay_reject = 2
2168        carrier_reject_call = not check_reject_needed_for_voice_mail(log, ad_callee)
2169
2170        if not wait_and_reject_call_for_subscription(
2171                log, ad_callee, subid_callee, incoming_number=caller_number, delay_reject=carrier_specific_delay_reject,
2172                reject=carrier_reject_call):
2173            ad_callee.log.error("Reject call fail.")
2174            return False
2175
2176        ad_callee.droid.telephonyStartTrackingVoiceMailStateChangeForSubscription(
2177            subid_callee)
2178
2179        # ensure that all internal states are updated in telecom
2180        time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
2181        ad_callee.ed.clear_events(EventCallStateChanged)
2182
2183        if verify_caller_func and not verify_caller_func(log, ad_caller):
2184            ad_caller.log.error("Caller not in correct state!")
2185            return False
2186
2187        # TODO: b/26293512 Need to play some sound to leave message.
2188        # Otherwise carrier voice mail server may drop this voice mail.
2189        time.sleep(wait_time_in_call)
2190
2191        if not verify_caller_func:
2192            caller_state_result = ad_caller.droid.telecomIsInCall()
2193        else:
2194            caller_state_result = verify_caller_func(log, ad_caller)
2195        if not caller_state_result:
2196            ad_caller.log.error("Caller not in correct state after %s seconds",
2197                                wait_time_in_call)
2198
2199        if not hangup_call(log, ad_caller):
2200            ad_caller.log.error("Error in Hanging-Up Call")
2201            return False
2202
2203        ad_callee.log.info("Wait for voice mail indicator on callee.")
2204        try:
2205            event = ad_callee.ed.wait_for_event(
2206                EventMessageWaitingIndicatorChanged,
2207                _is_on_message_waiting_event_true)
2208            ad_callee.log.info("Got event %s", event)
2209        except Empty:
2210            ad_callee.log.warning("No expected event %s",
2211                                  EventMessageWaitingIndicatorChanged)
2212            return False
2213        voice_mail_count_after = ad_callee.droid.telephonyGetVoiceMailCountForSubscription(
2214            subid_callee)
2215        ad_callee.log.info(
2216            "telephonyGetVoiceMailCount output - before: %s, after: %s",
2217            voice_mail_count_before, voice_mail_count_after)
2218
2219        # voice_mail_count_after should:
2220        # either equals to (voice_mail_count_before + 1) [For ATT and SPT]
2221        # or equals to -1 [For TMO]
2222        # -1 means there are unread voice mail, but the count is unknown
2223        if not check_voice_mail_count(log, ad_callee, voice_mail_count_before,
2224                                      voice_mail_count_after):
2225            log.error("before and after voice mail count is not incorrect.")
2226            return False
2227    finally:
2228        ad_callee.droid.telephonyStopTrackingVoiceMailStateChangeForSubscription(
2229            subid_callee)
2230    return True
2231
2232
2233def call_voicemail_erase_all_pending_voicemail(log, ad):
2234    """Script for phone to erase all pending voice mail.
2235    This script only works for TMO and ATT and SPT currently.
2236    This script only works if phone have already set up voice mail options,
2237    and phone should disable password protection for voice mail.
2238
2239    1. If phone don't have pending voice message, return True.
2240    2. Dial voice mail number.
2241        For TMO, the number is '123'
2242        For ATT, the number is phone's number
2243        For SPT, the number is phone's number
2244    3. Wait for voice mail connection setup.
2245    4. Wait for voice mail play pending voice message.
2246    5. Send DTMF to delete one message.
2247        The digit is '7'.
2248    6. Repeat steps 4 and 5 until voice mail server drop this call.
2249        (No pending message)
2250    6. Check telephonyGetVoiceMailCount result. it should be 0.
2251
2252    Args:
2253        log: log object
2254        ad: android device object
2255    Returns:
2256        False if error happens. True is succeed.
2257    """
2258    log.info("Erase all pending voice mail.")
2259    count = ad.droid.telephonyGetVoiceMailCount()
2260    if count == 0:
2261        ad.log.info("No Pending voice mail.")
2262        return True
2263    if count == -1:
2264        ad.log.info("There is pending voice mail, but the count is unknown")
2265        count = MAX_SAVED_VOICE_MAIL
2266    else:
2267        ad.log.info("There are %s voicemails", count)
2268
2269    voice_mail_number = get_voice_mail_number(log, ad)
2270    delete_digit = get_voice_mail_delete_digit(get_operator_name(log, ad))
2271    if not initiate_call(log, ad, voice_mail_number):
2272        log.error("Initiate call to voice mail failed.")
2273        return False
2274    time.sleep(WAIT_TIME_VOICE_MAIL_SERVER_RESPONSE)
2275    callId = ad.droid.telecomCallGetCallIds()[0]
2276    time.sleep(WAIT_TIME_VOICE_MAIL_SERVER_RESPONSE)
2277    while (is_phone_in_call(log, ad) and (count > 0)):
2278        ad.log.info("Press %s to delete voice mail.", delete_digit)
2279        ad.droid.telecomCallPlayDtmfTone(callId, delete_digit)
2280        ad.droid.telecomCallStopDtmfTone(callId)
2281        time.sleep(WAIT_TIME_VOICE_MAIL_SERVER_RESPONSE)
2282        count -= 1
2283    if is_phone_in_call(log, ad):
2284        hangup_call(log, ad)
2285
2286    # wait for telephonyGetVoiceMailCount to update correct result
2287    remaining_time = MAX_WAIT_TIME_VOICE_MAIL_COUNT
2288    while ((remaining_time > 0)
2289           and (ad.droid.telephonyGetVoiceMailCount() != 0)):
2290        time.sleep(1)
2291        remaining_time -= 1
2292    current_voice_mail_count = ad.droid.telephonyGetVoiceMailCount()
2293    ad.log.info("telephonyGetVoiceMailCount: %s", current_voice_mail_count)
2294    return (current_voice_mail_count == 0)
2295
2296
2297def _is_on_message_waiting_event_true(event):
2298    """Private function to return if the received EventMessageWaitingIndicatorChanged
2299    event MessageWaitingIndicatorContainer.IS_MESSAGE_WAITING field is True.
2300    """
2301    return event['data'][MessageWaitingIndicatorContainer.IS_MESSAGE_WAITING]
2302
2303
2304def call_setup_teardown(log,
2305                        ad_caller,
2306                        ad_callee,
2307                        ad_hangup=None,
2308                        verify_caller_func=None,
2309                        verify_callee_func=None,
2310                        wait_time_in_call=WAIT_TIME_IN_CALL,
2311                        incall_ui_display=INCALL_UI_DISPLAY_FOREGROUND,
2312                        dialing_number_length=None,
2313                        video_state=None,
2314                        slot_id_callee=None,
2315                        voice_type_init=None,
2316                        call_stats_check=False,
2317                        result_info=result_dict,
2318                        nsa_5g_for_stress=False):
2319    """ Call process, including make a phone call from caller,
2320    accept from callee, and hang up. The call is on default voice subscription
2321
2322    In call process, call from <droid_caller> to <droid_callee>,
2323    accept the call, (optional)then hang up from <droid_hangup>.
2324
2325    Args:
2326        ad_caller: Caller Android Device Object.
2327        ad_callee: Callee Android Device Object.
2328        ad_hangup: Android Device Object end the phone call.
2329            Optional. Default value is None, and phone call will continue.
2330        verify_call_mode_caller: func_ptr to verify caller in correct mode
2331            Optional. Default is None
2332        verify_call_mode_caller: func_ptr to verify caller in correct mode
2333            Optional. Default is None
2334        incall_ui_display: after answer the call, bring in-call UI to foreground or
2335            background. Optional, default value is INCALL_UI_DISPLAY_FOREGROUND.
2336            if = INCALL_UI_DISPLAY_FOREGROUND, bring in-call UI to foreground.
2337            if = INCALL_UI_DISPLAY_BACKGROUND, bring in-call UI to background.
2338            else, do nothing.
2339        dialing_number_length: the number of digits used for dialing
2340        slot_id_callee : the slot if of the callee to call to
2341
2342    Returns:
2343        True if call process without any error.
2344        False if error happened.
2345
2346    """
2347    subid_caller = get_outgoing_voice_sub_id(ad_caller)
2348    if slot_id_callee is None:
2349        subid_callee = get_incoming_voice_sub_id(ad_callee)
2350    else:
2351        subid_callee = get_subid_from_slot_index(log, ad_callee, slot_id_callee)
2352
2353    return call_setup_teardown_for_subscription(
2354        log, ad_caller, ad_callee, subid_caller, subid_callee, ad_hangup,
2355        verify_caller_func, verify_callee_func, wait_time_in_call,
2356        incall_ui_display, dialing_number_length, video_state,
2357        voice_type_init, call_stats_check, result_info, nsa_5g_for_stress)
2358
2359
2360
2361def call_setup_teardown_for_subscription(
2362        log,
2363        ad_caller,
2364        ad_callee,
2365        subid_caller,
2366        subid_callee,
2367        ad_hangup=None,
2368        verify_caller_func=None,
2369        verify_callee_func=None,
2370        wait_time_in_call=WAIT_TIME_IN_CALL,
2371        incall_ui_display=INCALL_UI_DISPLAY_FOREGROUND,
2372        dialing_number_length=None,
2373        video_state=None,
2374        voice_type_init=None,
2375        call_stats_check=False,
2376        result_info=result_dict,
2377        nsa_5g_for_stress=False):
2378    """ Call process, including make a phone call from caller,
2379    accept from callee, and hang up. The call is on specified subscription
2380
2381    In call process, call from <droid_caller> to <droid_callee>,
2382    accept the call, (optional)then hang up from <droid_hangup>.
2383
2384    Args:
2385        ad_caller: Caller Android Device Object.
2386        ad_callee: Callee Android Device Object.
2387        subid_caller: Caller subscription ID
2388        subid_callee: Callee subscription ID
2389        ad_hangup: Android Device Object end the phone call.
2390            Optional. Default value is None, and phone call will continue.
2391        verify_call_mode_caller: func_ptr to verify caller in correct mode
2392            Optional. Default is None
2393        verify_call_mode_caller: func_ptr to verify caller in correct mode
2394            Optional. Default is None
2395        incall_ui_display: after answer the call, bring in-call UI to foreground or
2396            background. Optional, default value is INCALL_UI_DISPLAY_FOREGROUND.
2397            if = INCALL_UI_DISPLAY_FOREGROUND, bring in-call UI to foreground.
2398            if = INCALL_UI_DISPLAY_BACKGROUND, bring in-call UI to background.
2399            else, do nothing.
2400
2401    Returns:
2402        TelResultWrapper which will evaluate as False if error.
2403
2404    """
2405    CHECK_INTERVAL = 5
2406    begin_time = get_current_epoch_time()
2407    if not verify_caller_func:
2408        verify_caller_func = is_phone_in_call
2409    if not verify_callee_func:
2410        verify_callee_func = is_phone_in_call
2411
2412    caller_number = ad_caller.telephony['subscription'][subid_caller][
2413        'phone_num']
2414    callee_number = ad_callee.telephony['subscription'][subid_callee][
2415        'phone_num']
2416    if dialing_number_length:
2417        skip_test = False
2418        trunc_position = 0 - int(dialing_number_length)
2419        try:
2420            caller_area_code = caller_number[:trunc_position]
2421            callee_area_code = callee_number[:trunc_position]
2422            callee_dial_number = callee_number[trunc_position:]
2423        except:
2424            skip_test = True
2425        if caller_area_code != callee_area_code:
2426            skip_test = True
2427        if skip_test:
2428            msg = "Cannot make call from %s to %s by %s digits" % (
2429                caller_number, callee_number, dialing_number_length)
2430            ad_caller.log.info(msg)
2431            raise signals.TestSkip(msg)
2432        else:
2433            callee_number = callee_dial_number
2434
2435    tel_result_wrapper = TelResultWrapper(CallResult('SUCCESS'))
2436    msg = "Call from %s to %s" % (caller_number, callee_number)
2437    if video_state:
2438        msg = "Video %s" % msg
2439        video = True
2440    else:
2441        video = False
2442    if ad_hangup:
2443        msg = "%s for duration of %s seconds" % (msg, wait_time_in_call)
2444    ad_caller.log.info(msg)
2445
2446    for ad in (ad_caller, ad_callee):
2447        call_ids = ad.droid.telecomCallGetCallIds()
2448        setattr(ad, "call_ids", call_ids)
2449        if call_ids:
2450            ad.log.info("Pre-exist CallId %s before making call", call_ids)
2451    try:
2452        if not initiate_call(
2453                log,
2454                ad_caller,
2455                callee_number,
2456                incall_ui_display=incall_ui_display,
2457                video=video):
2458            ad_caller.log.error("Initiate call failed.")
2459            tel_result_wrapper.result_value = CallResult('INITIATE_FAILED')
2460            return tel_result_wrapper
2461        else:
2462            ad_caller.log.info("Caller initate call successfully")
2463        if not wait_and_answer_call_for_subscription(
2464                log,
2465                ad_callee,
2466                subid_callee,
2467                incoming_number=caller_number,
2468                caller=ad_caller,
2469                incall_ui_display=incall_ui_display,
2470                video_state=video_state):
2471            ad_callee.log.error("Answer call fail.")
2472            tel_result_wrapper.result_value = CallResult(
2473                'NO_RING_EVENT_OR_ANSWER_FAILED')
2474            return tel_result_wrapper
2475        else:
2476            ad_callee.log.info("Callee answered the call successfully")
2477
2478        for ad, call_func in zip([ad_caller, ad_callee],
2479                                 [verify_caller_func, verify_callee_func]):
2480            call_ids = ad.droid.telecomCallGetCallIds()
2481            new_call_ids = set(call_ids) - set(ad.call_ids)
2482            if not new_call_ids:
2483                ad.log.error(
2484                    "No new call ids are found after call establishment")
2485                ad.log.error("telecomCallGetCallIds returns %s",
2486                             ad.droid.telecomCallGetCallIds())
2487                tel_result_wrapper.result_value = CallResult('NO_CALL_ID_FOUND')
2488            for new_call_id in new_call_ids:
2489                if not wait_for_in_call_active(ad, call_id=new_call_id):
2490                    tel_result_wrapper.result_value = CallResult(
2491                        'CALL_STATE_NOT_ACTIVE_DURING_ESTABLISHMENT')
2492                else:
2493                    ad.log.info("callProperties = %s",
2494                                ad.droid.telecomCallGetProperties(new_call_id))
2495
2496            if not ad.droid.telecomCallGetAudioState():
2497                ad.log.error("Audio is not in call state")
2498                tel_result_wrapper.result_value = CallResult(
2499                    'AUDIO_STATE_NOT_INCALL_DURING_ESTABLISHMENT')
2500
2501            if call_func(log, ad):
2502                ad.log.info("Call is in %s state", call_func.__name__)
2503            else:
2504                ad.log.error("Call is not in %s state, voice in RAT %s",
2505                             call_func.__name__,
2506                             ad.droid.telephonyGetCurrentVoiceNetworkType())
2507                tel_result_wrapper.result_value = CallResult(
2508                    'CALL_DROP_OR_WRONG_STATE_DURING_ESTABLISHMENT')
2509        if not tel_result_wrapper:
2510            return tel_result_wrapper
2511
2512        if call_stats_check:
2513            voice_type_in_call = check_voice_network_type([ad_caller, ad_callee], voice_init=False)
2514            phone_a_call_type = check_call_status(ad_caller,
2515                                                  voice_type_init[0],
2516                                                  voice_type_in_call[0])
2517            result_info["Call Stats"] = phone_a_call_type
2518            ad_caller.log.debug("Voice Call Type: %s", phone_a_call_type)
2519            phone_b_call_type = check_call_status(ad_callee,
2520                                                  voice_type_init[1],
2521                                                  voice_type_in_call[1])
2522            result_info["Call Stats"] = phone_b_call_type
2523            ad_callee.log.debug("Voice Call Type: %s", phone_b_call_type)
2524
2525        elapsed_time = 0
2526        while (elapsed_time < wait_time_in_call):
2527            CHECK_INTERVAL = min(CHECK_INTERVAL,
2528                                 wait_time_in_call - elapsed_time)
2529            time.sleep(CHECK_INTERVAL)
2530            elapsed_time += CHECK_INTERVAL
2531            time_message = "at <%s>/<%s> second." % (elapsed_time,
2532                                                     wait_time_in_call)
2533            for ad, call_func in [(ad_caller, verify_caller_func),
2534                                  (ad_callee, verify_callee_func)]:
2535                if not call_func(log, ad):
2536                    ad.log.error(
2537                        "NOT in correct %s state at %s, voice in RAT %s",
2538                        call_func.__name__, time_message,
2539                        ad.droid.telephonyGetCurrentVoiceNetworkType())
2540                    tel_result_wrapper.result_value = CallResult(
2541                        'CALL_DROP_OR_WRONG_STATE_AFTER_CONNECTED')
2542                else:
2543                    ad.log.info("In correct %s state at %s",
2544                                call_func.__name__, time_message)
2545                if not ad.droid.telecomCallGetAudioState():
2546                    ad.log.error("Audio is not in call state at %s",
2547                                 time_message)
2548                    tel_result_wrapper.result_value = CallResult(
2549                        'AUDIO_STATE_NOT_INCALL_AFTER_CONNECTED')
2550            if not tel_result_wrapper:
2551                return tel_result_wrapper
2552
2553        if ad_hangup:
2554            if not hangup_call(log, ad_hangup):
2555                ad_hangup.log.info("Failed to hang up the call")
2556                tel_result_wrapper.result_value = CallResult('CALL_HANGUP_FAIL')
2557                return tel_result_wrapper
2558    finally:
2559        if not tel_result_wrapper:
2560            for ad in (ad_caller, ad_callee):
2561                last_call_drop_reason(ad, begin_time)
2562                try:
2563                    if ad.droid.telecomIsInCall():
2564                        ad.log.info("In call. End now.")
2565                        ad.droid.telecomEndCall()
2566                except Exception as e:
2567                    log.error(str(e))
2568
2569        if nsa_5g_for_stress:
2570            for ad in (ad_caller, ad_callee):
2571                if not is_current_network_5g_nsa(ad):
2572                    ad.log.error("Phone not attached on 5G NSA")
2573
2574        if ad_hangup or not tel_result_wrapper:
2575            for ad in (ad_caller, ad_callee):
2576                if not wait_for_call_id_clearing(
2577                        ad, getattr(ad, "caller_ids", [])):
2578                    tel_result_wrapper.result_value = CallResult(
2579                        'CALL_ID_CLEANUP_FAIL')
2580    return tel_result_wrapper
2581
2582
2583def call_setup_teardown_for_call_forwarding(
2584    log,
2585    ad_caller,
2586    ad_callee,
2587    forwarded_callee,
2588    ad_hangup=None,
2589    verify_callee_func=None,
2590    verify_after_cf_disabled=None,
2591    wait_time_in_call=WAIT_TIME_IN_CALL,
2592    incall_ui_display=INCALL_UI_DISPLAY_FOREGROUND,
2593    dialing_number_length=None,
2594    video_state=None,
2595    call_forwarding_type="unconditional"):
2596    """ Call process for call forwarding, including make a phone call from
2597    caller, forward from callee, accept from the forwarded callee and hang up.
2598    The call is on default voice subscription
2599
2600    In call process, call from <ad_caller> to <ad_callee>, forwarded to
2601    <forwarded_callee>, accept the call, (optional) and then hang up from
2602    <ad_hangup>.
2603
2604    Args:
2605        ad_caller: Caller Android Device Object.
2606        ad_callee: Callee Android Device Object which forwards the call.
2607        forwarded_callee: Callee Android Device Object which answers the call.
2608        ad_hangup: Android Device Object end the phone call.
2609            Optional. Default value is None, and phone call will continue.
2610        verify_callee_func: func_ptr to verify callee in correct mode
2611            Optional. Default is None
2612        verify_after_cf_disabled: If True the test of disabling call forwarding
2613        will be appended.
2614        wait_time_in_call: the call duration of a connected call
2615        incall_ui_display: after answer the call, bring in-call UI to foreground
2616        or background.
2617            Optional, default value is INCALL_UI_DISPLAY_FOREGROUND.
2618            if = INCALL_UI_DISPLAY_FOREGROUND, bring in-call UI to foreground.
2619            if = INCALL_UI_DISPLAY_BACKGROUND, bring in-call UI to background.
2620            else, do nothing.
2621        dialing_number_length: the number of digits used for dialing
2622        video_state: video call or voice call. Default is voice call.
2623        call_forwarding_type: type of call forwarding listed below:
2624            - unconditional
2625            - busy
2626            - not_answered
2627            - not_reachable
2628
2629    Returns:
2630        True if call process without any error.
2631        False if error happened.
2632
2633    """
2634    subid_caller = get_outgoing_voice_sub_id(ad_caller)
2635    subid_callee = get_incoming_voice_sub_id(ad_callee)
2636    subid_forwarded_callee = get_incoming_voice_sub_id(forwarded_callee)
2637    return call_setup_teardown_for_call_forwarding_for_subscription(
2638        log,
2639        ad_caller,
2640        ad_callee,
2641        forwarded_callee,
2642        subid_caller,
2643        subid_callee,
2644        subid_forwarded_callee,
2645        ad_hangup,
2646        verify_callee_func,
2647        wait_time_in_call,
2648        incall_ui_display,
2649        dialing_number_length,
2650        video_state,
2651        call_forwarding_type,
2652        verify_after_cf_disabled)
2653
2654
2655def call_setup_teardown_for_call_forwarding_for_subscription(
2656        log,
2657        ad_caller,
2658        ad_callee,
2659        forwarded_callee,
2660        subid_caller,
2661        subid_callee,
2662        subid_forwarded_callee,
2663        ad_hangup=None,
2664        verify_callee_func=None,
2665        wait_time_in_call=WAIT_TIME_IN_CALL,
2666        incall_ui_display=INCALL_UI_DISPLAY_FOREGROUND,
2667        dialing_number_length=None,
2668        video_state=None,
2669        call_forwarding_type="unconditional",
2670        verify_after_cf_disabled=None):
2671    """ Call process for call forwarding, including make a phone call from caller,
2672    forward from callee, accept from the forwarded callee and hang up.
2673    The call is on specified subscription
2674
2675    In call process, call from <ad_caller> to <ad_callee>, forwarded to
2676    <forwarded_callee>, accept the call, (optional) and then hang up from
2677    <ad_hangup>.
2678
2679    Args:
2680        ad_caller: Caller Android Device Object.
2681        ad_callee: Callee Android Device Object which forwards the call.
2682        forwarded_callee: Callee Android Device Object which answers the call.
2683        subid_caller: Caller subscription ID
2684        subid_callee: Callee subscription ID
2685        subid_forwarded_callee: Forwarded callee subscription ID
2686        ad_hangup: Android Device Object end the phone call.
2687            Optional. Default value is None, and phone call will continue.
2688        verify_callee_func: func_ptr to verify callee in correct mode
2689            Optional. Default is None
2690        wait_time_in_call: the call duration of a connected call
2691        incall_ui_display: after answer the call, bring in-call UI to foreground
2692        or background. Optional, default value is INCALL_UI_DISPLAY_FOREGROUND.
2693            if = INCALL_UI_DISPLAY_FOREGROUND, bring in-call UI to foreground.
2694            if = INCALL_UI_DISPLAY_BACKGROUND, bring in-call UI to background.
2695            else, do nothing.
2696        dialing_number_length: the number of digits used for dialing
2697        video_state: video call or voice call. Default is voice call.
2698        call_forwarding_type: type of call forwarding listed below:
2699            - unconditional
2700            - busy
2701            - not_answered
2702            - not_reachable
2703        verify_after_cf_disabled: If True the call forwarding will not be
2704        enabled. This argument is used to verify if the call can be received
2705        successfully after call forwarding was disabled.
2706
2707    Returns:
2708        True if call process without any error.
2709        False if error happened.
2710
2711    """
2712    CHECK_INTERVAL = 5
2713    begin_time = get_current_epoch_time()
2714    verify_caller_func = is_phone_in_call
2715    if not verify_callee_func:
2716        verify_callee_func = is_phone_in_call
2717    verify_forwarded_callee_func = is_phone_in_call
2718
2719    caller_number = ad_caller.telephony['subscription'][subid_caller][
2720        'phone_num']
2721    callee_number = ad_callee.telephony['subscription'][subid_callee][
2722        'phone_num']
2723    forwarded_callee_number = forwarded_callee.telephony['subscription'][
2724        subid_forwarded_callee]['phone_num']
2725
2726    if dialing_number_length:
2727        skip_test = False
2728        trunc_position = 0 - int(dialing_number_length)
2729        try:
2730            caller_area_code = caller_number[:trunc_position]
2731            callee_area_code = callee_number[:trunc_position]
2732            callee_dial_number = callee_number[trunc_position:]
2733        except:
2734            skip_test = True
2735        if caller_area_code != callee_area_code:
2736            skip_test = True
2737        if skip_test:
2738            msg = "Cannot make call from %s to %s by %s digits" % (
2739                caller_number, callee_number, dialing_number_length)
2740            ad_caller.log.info(msg)
2741            raise signals.TestSkip(msg)
2742        else:
2743            callee_number = callee_dial_number
2744
2745    result = True
2746    msg = "Call from %s to %s (forwarded to %s)" % (
2747        caller_number, callee_number, forwarded_callee_number)
2748    if video_state:
2749        msg = "Video %s" % msg
2750        video = True
2751    else:
2752        video = False
2753    if ad_hangup:
2754        msg = "%s for duration of %s seconds" % (msg, wait_time_in_call)
2755    ad_caller.log.info(msg)
2756
2757    for ad in (ad_caller, forwarded_callee):
2758        call_ids = ad.droid.telecomCallGetCallIds()
2759        setattr(ad, "call_ids", call_ids)
2760        if call_ids:
2761            ad.log.info("Pre-exist CallId %s before making call", call_ids)
2762
2763    if not verify_after_cf_disabled:
2764        if not set_call_forwarding_by_mmi(
2765            log,
2766            ad_callee,
2767            forwarded_callee,
2768            call_forwarding_type=call_forwarding_type):
2769            raise signals.TestFailure(
2770                    "Failed to register or activate call forwarding.",
2771                    extras={"fail_reason": "Failed to register or activate call"
2772                    " forwarding."})
2773
2774    if call_forwarding_type == "not_reachable":
2775        if not toggle_airplane_mode_msim(
2776            log,
2777            ad_callee,
2778            new_state=True,
2779            strict_checking=True):
2780            return False
2781
2782    if call_forwarding_type == "busy":
2783        ad_callee.log.info("Callee is making a phone call to 0000000000 to make"
2784            " itself busy.")
2785        ad_callee.droid.telecomCallNumber("0000000000", False)
2786        time.sleep(2)
2787
2788        if check_call_state_idle_by_adb(ad_callee):
2789            ad_callee.log.error("Call state of the callee is idle.")
2790            if not verify_after_cf_disabled:
2791                erase_call_forwarding_by_mmi(
2792                    log,
2793                    ad_callee,
2794                    call_forwarding_type=call_forwarding_type)
2795            return False
2796
2797    try:
2798        if not initiate_call(
2799                log,
2800                ad_caller,
2801                callee_number,
2802                incall_ui_display=incall_ui_display,
2803                video=video):
2804
2805            ad_caller.log.error("Caller failed to initiate the call.")
2806            result = False
2807
2808            if call_forwarding_type == "not_reachable":
2809                if toggle_airplane_mode_msim(
2810                    log,
2811                    ad_callee,
2812                    new_state=False,
2813                    strict_checking=True):
2814                    time.sleep(10)
2815            elif call_forwarding_type == "busy":
2816                hangup_call(log, ad_callee)
2817
2818            if not verify_after_cf_disabled:
2819                erase_call_forwarding_by_mmi(
2820                    log,
2821                    ad_callee,
2822                    call_forwarding_type=call_forwarding_type)
2823            return False
2824        else:
2825            ad_caller.log.info("Caller initated the call successfully.")
2826
2827        if call_forwarding_type == "not_answered":
2828            if not wait_for_ringing_call_for_subscription(
2829                    log,
2830                    ad_callee,
2831                    subid_callee,
2832                    incoming_number=caller_number,
2833                    caller=ad_caller,
2834                    event_tracking_started=True):
2835                ad.log.info("Incoming call ringing check failed.")
2836                return False
2837
2838            _timeout = 30
2839            while check_call_state_ring_by_adb(ad_callee) == 1 and _timeout >= 0:
2840                time.sleep(1)
2841                _timeout = _timeout - 1
2842
2843        if not wait_and_answer_call_for_subscription(
2844                log,
2845                forwarded_callee,
2846                subid_forwarded_callee,
2847                incoming_number=caller_number,
2848                caller=ad_caller,
2849                incall_ui_display=incall_ui_display,
2850                video_state=video_state):
2851
2852            if not verify_after_cf_disabled:
2853                forwarded_callee.log.error("Forwarded callee failed to receive"
2854                    "or answer the call.")
2855                result = False
2856            else:
2857                forwarded_callee.log.info("Forwarded callee did not receive or"
2858                    " answer the call.")
2859
2860            if call_forwarding_type == "not_reachable":
2861                if toggle_airplane_mode_msim(
2862                    log,
2863                    ad_callee,
2864                    new_state=False,
2865                    strict_checking=True):
2866                    time.sleep(10)
2867            elif call_forwarding_type == "busy":
2868                hangup_call(log, ad_callee)
2869
2870            if not verify_after_cf_disabled:
2871                erase_call_forwarding_by_mmi(
2872                    log,
2873                    ad_callee,
2874                    call_forwarding_type=call_forwarding_type)
2875                return False
2876
2877        else:
2878            if not verify_after_cf_disabled:
2879                forwarded_callee.log.info("Forwarded callee answered the call"
2880                    " successfully.")
2881            else:
2882                forwarded_callee.log.error("Forwarded callee should not be able"
2883                    " to answer the call.")
2884                hangup_call(log, ad_caller)
2885                result = False
2886
2887        for ad, subid, call_func in zip(
2888                [ad_caller, forwarded_callee],
2889                [subid_caller, subid_forwarded_callee],
2890                [verify_caller_func, verify_forwarded_callee_func]):
2891            call_ids = ad.droid.telecomCallGetCallIds()
2892            new_call_ids = set(call_ids) - set(ad.call_ids)
2893            if not new_call_ids:
2894                if not verify_after_cf_disabled:
2895                    ad.log.error(
2896                        "No new call ids are found after call establishment")
2897                    ad.log.error("telecomCallGetCallIds returns %s",
2898                                 ad.droid.telecomCallGetCallIds())
2899                result = False
2900            for new_call_id in new_call_ids:
2901                if not verify_after_cf_disabled:
2902                    if not wait_for_in_call_active(ad, call_id=new_call_id):
2903                        result = False
2904                    else:
2905                        ad.log.info("callProperties = %s",
2906                            ad.droid.telecomCallGetProperties(new_call_id))
2907                else:
2908                    ad.log.error("No new call id should be found.")
2909
2910            if not ad.droid.telecomCallGetAudioState():
2911                if not verify_after_cf_disabled:
2912                    ad.log.error("Audio is not in call state")
2913                    result = False
2914
2915            if call_func(log, ad):
2916                if not verify_after_cf_disabled:
2917                    ad.log.info("Call is in %s state", call_func.__name__)
2918                else:
2919                    ad.log.error("Call is in %s state", call_func.__name__)
2920            else:
2921                if not verify_after_cf_disabled:
2922                    ad.log.error(
2923                        "Call is not in %s state, voice in RAT %s",
2924                        call_func.__name__,
2925                        ad.droid.telephonyGetCurrentVoiceNetworkTypeForSubscription(subid))
2926                    result = False
2927
2928        if not result:
2929            if call_forwarding_type == "not_reachable":
2930                if toggle_airplane_mode_msim(
2931                    log,
2932                    ad_callee,
2933                    new_state=False,
2934                    strict_checking=True):
2935                    time.sleep(10)
2936            elif call_forwarding_type == "busy":
2937                hangup_call(log, ad_callee)
2938
2939            if not verify_after_cf_disabled:
2940                erase_call_forwarding_by_mmi(
2941                    log,
2942                    ad_callee,
2943                    call_forwarding_type=call_forwarding_type)
2944                return False
2945
2946        elapsed_time = 0
2947        while (elapsed_time < wait_time_in_call):
2948            CHECK_INTERVAL = min(CHECK_INTERVAL,
2949                                 wait_time_in_call - elapsed_time)
2950            time.sleep(CHECK_INTERVAL)
2951            elapsed_time += CHECK_INTERVAL
2952            time_message = "at <%s>/<%s> second." % (elapsed_time,
2953                                                     wait_time_in_call)
2954            for ad, subid, call_func in [
2955                (ad_caller, subid_caller, verify_caller_func),
2956                (forwarded_callee, subid_forwarded_callee,
2957                    verify_forwarded_callee_func)]:
2958                if not call_func(log, ad):
2959                    if not verify_after_cf_disabled:
2960                        ad.log.error(
2961                            "NOT in correct %s state at %s, voice in RAT %s",
2962                            call_func.__name__, time_message,
2963                            ad.droid.telephonyGetCurrentVoiceNetworkTypeForSubscription(subid))
2964                    result = False
2965                else:
2966                    if not verify_after_cf_disabled:
2967                        ad.log.info("In correct %s state at %s",
2968                                    call_func.__name__, time_message)
2969                    else:
2970                        ad.log.error("In correct %s state at %s",
2971                                    call_func.__name__, time_message)
2972
2973                if not ad.droid.telecomCallGetAudioState():
2974                    if not verify_after_cf_disabled:
2975                        ad.log.error("Audio is not in call state at %s",
2976                                     time_message)
2977                    result = False
2978
2979            if not result:
2980                if call_forwarding_type == "not_reachable":
2981                    if toggle_airplane_mode_msim(
2982                        log,
2983                        ad_callee,
2984                        new_state=False,
2985                        strict_checking=True):
2986                        time.sleep(10)
2987                elif call_forwarding_type == "busy":
2988                    hangup_call(log, ad_callee)
2989
2990                if not verify_after_cf_disabled:
2991                    erase_call_forwarding_by_mmi(
2992                        log,
2993                        ad_callee,
2994                        call_forwarding_type=call_forwarding_type)
2995                    return False
2996
2997        if ad_hangup:
2998            if not hangup_call(log, ad_hangup):
2999                ad_hangup.log.info("Failed to hang up the call")
3000                result = False
3001                if call_forwarding_type == "not_reachable":
3002                    if toggle_airplane_mode_msim(
3003                        log,
3004                        ad_callee,
3005                        new_state=False,
3006                        strict_checking=True):
3007                        time.sleep(10)
3008                elif call_forwarding_type == "busy":
3009                    hangup_call(log, ad_callee)
3010
3011                if not verify_after_cf_disabled:
3012                    erase_call_forwarding_by_mmi(
3013                        log,
3014                        ad_callee,
3015                        call_forwarding_type=call_forwarding_type)
3016                return False
3017    finally:
3018        if not result:
3019            if verify_after_cf_disabled:
3020                result = True
3021            else:
3022                for ad in (ad_caller, forwarded_callee):
3023                    last_call_drop_reason(ad, begin_time)
3024                    try:
3025                        if ad.droid.telecomIsInCall():
3026                            ad.log.info("In call. End now.")
3027                            ad.droid.telecomEndCall()
3028                    except Exception as e:
3029                        log.error(str(e))
3030
3031        if ad_hangup or not result:
3032            for ad in (ad_caller, forwarded_callee):
3033                if not wait_for_call_id_clearing(
3034                        ad, getattr(ad, "caller_ids", [])):
3035                    result = False
3036
3037    if call_forwarding_type == "not_reachable":
3038        if toggle_airplane_mode_msim(
3039            log,
3040            ad_callee,
3041            new_state=False,
3042            strict_checking=True):
3043            time.sleep(10)
3044    elif call_forwarding_type == "busy":
3045        hangup_call(log, ad_callee)
3046
3047    if not verify_after_cf_disabled:
3048        erase_call_forwarding_by_mmi(
3049            log,
3050            ad_callee,
3051            call_forwarding_type=call_forwarding_type)
3052
3053    if not result:
3054        return result
3055
3056    ad_caller.log.info(
3057        "Make a normal call to callee to ensure the call can be connected after"
3058        " call forwarding was disabled")
3059    return call_setup_teardown_for_subscription(
3060        log, ad_caller, ad_callee, subid_caller, subid_callee, ad_caller,
3061        verify_caller_func, verify_callee_func, wait_time_in_call,
3062        incall_ui_display, dialing_number_length, video_state)
3063
3064
3065def call_setup_teardown_for_call_waiting(log,
3066                        ad_caller,
3067                        ad_callee,
3068                        ad_caller2,
3069                        ad_hangup=None,
3070                        ad_hangup2=None,
3071                        verify_callee_func=None,
3072                        end_first_call_before_answering_second_call=True,
3073                        wait_time_in_call=WAIT_TIME_IN_CALL,
3074                        incall_ui_display=INCALL_UI_DISPLAY_FOREGROUND,
3075                        dialing_number_length=None,
3076                        video_state=None,
3077                        call_waiting=True):
3078    """ Call process for call waiting, including make the 1st phone call from
3079    caller, answer the call by the callee, and receive the 2nd call from the
3080    caller2. The call is on default voice subscription
3081
3082    In call process, 1st call from <ad_caller> to <ad_callee>, 2nd call from
3083    <ad_caller2> to <ad_callee>, hang up the existing call or reject the
3084    incoming call according to the test scenario.
3085
3086    Args:
3087        ad_caller: Caller Android Device Object.
3088        ad_callee: Callee Android Device Object.
3089        ad_caller2: Caller2 Android Device Object.
3090        ad_hangup: Android Device Object end the 1st phone call.
3091            Optional. Default value is None, and phone call will continue.
3092        ad_hangup2: Android Device Object end the 2nd phone call.
3093            Optional. Default value is None, and phone call will continue.
3094        verify_callee_func: func_ptr to verify callee in correct mode
3095            Optional. Default is None
3096        end_first_call_before_answering_second_call: If True the 2nd call will
3097            be rejected on the ringing stage.
3098        wait_time_in_call: the call duration of a connected call
3099        incall_ui_display: after answer the call, bring in-call UI to foreground
3100        or background.
3101            Optional, default value is INCALL_UI_DISPLAY_FOREGROUND.
3102            if = INCALL_UI_DISPLAY_FOREGROUND, bring in-call UI to foreground.
3103            if = INCALL_UI_DISPLAY_BACKGROUND, bring in-call UI to background.
3104            else, do nothing.
3105        dialing_number_length: the number of digits used for dialing
3106        video_state: video call or voice call. Default is voice call.
3107        call_waiting: True to enable call waiting and False to disable.
3108
3109    Returns:
3110        True if call process without any error.
3111        False if error happened.
3112
3113    """
3114    subid_caller = get_outgoing_voice_sub_id(ad_caller)
3115    subid_callee = get_incoming_voice_sub_id(ad_callee)
3116    subid_caller2 = get_incoming_voice_sub_id(ad_caller2)
3117    return call_setup_teardown_for_call_waiting_for_subscription(
3118        log,
3119        ad_caller,
3120        ad_callee,
3121        ad_caller2,
3122        subid_caller,
3123        subid_callee,
3124        subid_caller2,
3125        ad_hangup, ad_hangup2,
3126        verify_callee_func,
3127        end_first_call_before_answering_second_call,
3128        wait_time_in_call,
3129        incall_ui_display,
3130        dialing_number_length,
3131        video_state,
3132        call_waiting)
3133
3134
3135def call_setup_teardown_for_call_waiting_for_subscription(
3136        log,
3137        ad_caller,
3138        ad_callee,
3139        ad_caller2,
3140        subid_caller,
3141        subid_callee,
3142        subid_caller2,
3143        ad_hangup=None,
3144        ad_hangup2=None,
3145        verify_callee_func=None,
3146        end_first_call_before_answering_second_call=True,
3147        wait_time_in_call=WAIT_TIME_IN_CALL,
3148        incall_ui_display=INCALL_UI_DISPLAY_FOREGROUND,
3149        dialing_number_length=None,
3150        video_state=None,
3151        call_waiting=True):
3152    """ Call process for call waiting, including make the 1st phone call from
3153    caller, answer the call by the callee, and receive the 2nd call from the
3154    caller2. The call is on specified subscription.
3155
3156    In call process, 1st call from <ad_caller> to <ad_callee>, 2nd call from
3157    <ad_caller2> to <ad_callee>, hang up the existing call or reject the
3158    incoming call according to the test scenario.
3159
3160    Args:
3161        ad_caller: Caller Android Device Object.
3162        ad_callee: Callee Android Device Object.
3163        ad_caller2: Caller2 Android Device Object.
3164        subid_caller: Caller subscription ID.
3165        subid_callee: Callee subscription ID.
3166        subid_caller2: Caller2 subscription ID.
3167        ad_hangup: Android Device Object end the 1st phone call.
3168            Optional. Default value is None, and phone call will continue.
3169        ad_hangup2: Android Device Object end the 2nd phone call.
3170            Optional. Default value is None, and phone call will continue.
3171        verify_callee_func: func_ptr to verify callee in correct mode
3172            Optional. Default is None
3173        end_first_call_before_answering_second_call: If True the 2nd call will
3174            be rejected on the ringing stage.
3175        wait_time_in_call: the call duration of a connected call
3176        incall_ui_display: after answer the call, bring in-call UI to foreground
3177        or background. Optional, default value is INCALL_UI_DISPLAY_FOREGROUND.
3178            if = INCALL_UI_DISPLAY_FOREGROUND, bring in-call UI to foreground.
3179            if = INCALL_UI_DISPLAY_BACKGROUND, bring in-call UI to background.
3180            else, do nothing.
3181        dialing_number_length: the number of digits used for dialing
3182        video_state: video call or voice call. Default is voice call.
3183        call_waiting: True to enable call waiting and False to disable.
3184
3185    Returns:
3186        True if call process without any error.
3187        False if error happened.
3188
3189    """
3190
3191    CHECK_INTERVAL = 5
3192    begin_time = get_current_epoch_time()
3193    verify_caller_func = is_phone_in_call
3194    if not verify_callee_func:
3195        verify_callee_func = is_phone_in_call
3196    verify_caller2_func = is_phone_in_call
3197
3198    caller_number = ad_caller.telephony['subscription'][subid_caller][
3199        'phone_num']
3200    callee_number = ad_callee.telephony['subscription'][subid_callee][
3201        'phone_num']
3202    caller2_number = ad_caller2.telephony['subscription'][subid_caller2][
3203        'phone_num']
3204    if dialing_number_length:
3205        skip_test = False
3206        trunc_position = 0 - int(dialing_number_length)
3207        try:
3208            caller_area_code = caller_number[:trunc_position]
3209            callee_area_code = callee_number[:trunc_position]
3210            callee_dial_number = callee_number[trunc_position:]
3211        except:
3212            skip_test = True
3213        if caller_area_code != callee_area_code:
3214            skip_test = True
3215        if skip_test:
3216            msg = "Cannot make call from %s to %s by %s digits" % (
3217                caller_number, callee_number, dialing_number_length)
3218            ad_caller.log.info(msg)
3219            raise signals.TestSkip(msg)
3220        else:
3221            callee_number = callee_dial_number
3222
3223    result = True
3224    msg = "Call from %s to %s" % (caller_number, callee_number)
3225    if video_state:
3226        msg = "Video %s" % msg
3227        video = True
3228    else:
3229        video = False
3230    if ad_hangup:
3231        msg = "%s for duration of %s seconds" % (msg, wait_time_in_call)
3232    ad_caller.log.info(msg)
3233
3234    for ad in (ad_caller, ad_callee, ad_caller2):
3235        call_ids = ad.droid.telecomCallGetCallIds()
3236        setattr(ad, "call_ids", call_ids)
3237        if call_ids:
3238            ad.log.info("Pre-exist CallId %s before making call", call_ids)
3239
3240    if not call_waiting:
3241        set_call_waiting(log, ad_callee, enable=0)
3242    else:
3243        set_call_waiting(log, ad_callee, enable=1)
3244
3245    first_call_ids = []
3246    try:
3247        if not initiate_call(
3248                log,
3249                ad_caller,
3250                callee_number,
3251                incall_ui_display=incall_ui_display,
3252                video=video):
3253            ad_caller.log.error("Initiate call failed.")
3254            if not call_waiting:
3255                set_call_waiting(log, ad_callee, enable=1)
3256            result = False
3257            return False
3258        else:
3259            ad_caller.log.info("Caller initate call successfully")
3260        if not wait_and_answer_call_for_subscription(
3261                log,
3262                ad_callee,
3263                subid_callee,
3264                incoming_number=caller_number,
3265                caller=ad_caller,
3266                incall_ui_display=incall_ui_display,
3267                video_state=video_state):
3268            ad_callee.log.error("Answer call fail.")
3269            if not call_waiting:
3270                set_call_waiting(log, ad_callee, enable=1)
3271            result = False
3272            return False
3273        else:
3274            ad_callee.log.info("Callee answered the call successfully")
3275
3276        for ad, subid, call_func in zip(
3277            [ad_caller, ad_callee],
3278            [subid_caller, subid_callee],
3279            [verify_caller_func, verify_callee_func]):
3280            call_ids = ad.droid.telecomCallGetCallIds()
3281            new_call_ids = set(call_ids) - set(ad.call_ids)
3282            if not new_call_ids:
3283                ad.log.error(
3284                    "No new call ids are found after call establishment")
3285                ad.log.error("telecomCallGetCallIds returns %s",
3286                             ad.droid.telecomCallGetCallIds())
3287                result = False
3288            for new_call_id in new_call_ids:
3289                first_call_ids.append(new_call_id)
3290                if not wait_for_in_call_active(ad, call_id=new_call_id):
3291                    result = False
3292                else:
3293                    ad.log.info("callProperties = %s",
3294                                ad.droid.telecomCallGetProperties(new_call_id))
3295
3296            if not ad.droid.telecomCallGetAudioState():
3297                ad.log.error("Audio is not in call state")
3298                result = False
3299
3300            if call_func(log, ad):
3301                ad.log.info("Call is in %s state", call_func.__name__)
3302            else:
3303                ad.log.error("Call is not in %s state, voice in RAT %s",
3304                             call_func.__name__,
3305                             ad.droid.telephonyGetCurrentVoiceNetworkTypeForSubscription(subid))
3306                result = False
3307        if not result:
3308            if not call_waiting:
3309                set_call_waiting(log, ad_callee, enable=1)
3310            return False
3311
3312        time.sleep(3)
3313        if not call_waiting:
3314            if not initiate_call(
3315                    log,
3316                    ad_caller2,
3317                    callee_number,
3318                    incall_ui_display=incall_ui_display,
3319                    video=video):
3320                ad_caller2.log.info("Initiate call failed.")
3321                if not call_waiting:
3322                    set_call_waiting(log, ad_callee, enable=1)
3323                result = False
3324                return False
3325            else:
3326                ad_caller2.log.info("Caller 2 initate 2nd call successfully")
3327
3328            if not wait_and_answer_call_for_subscription(
3329                    log,
3330                    ad_callee,
3331                    subid_callee,
3332                    incoming_number=caller2_number,
3333                    caller=ad_caller2,
3334                    incall_ui_display=incall_ui_display,
3335                    video_state=video_state):
3336                ad_callee.log.info(
3337                    "Answering 2nd call fail due to call waiting deactivate.")
3338            else:
3339                ad_callee.log.error("Callee should not be able to answer the"
3340                    " 2nd call due to call waiting deactivated.")
3341                if not call_waiting:
3342                    set_call_waiting(log, ad_callee, enable=1)
3343                result = False
3344                return False
3345
3346            time.sleep(3)
3347            if not hangup_call(log, ad_caller2):
3348                ad_caller2.log.info("Failed to hang up the 2nd call")
3349                if not call_waiting:
3350                    set_call_waiting(log, ad_callee, enable=1)
3351                result = False
3352                return False
3353
3354        else:
3355
3356            for ad in (ad_callee, ad_caller2):
3357                call_ids = ad.droid.telecomCallGetCallIds()
3358                setattr(ad, "call_ids", call_ids)
3359                if call_ids:
3360                    ad.log.info("Current existing CallId %s before making the"
3361                        " second call.", call_ids)
3362
3363            if not initiate_call(
3364                    log,
3365                    ad_caller2,
3366                    callee_number,
3367                    incall_ui_display=incall_ui_display,
3368                    video=video):
3369                ad_caller2.log.info("Initiate 2nd call failed.")
3370                if not call_waiting:
3371                    set_call_waiting(log, ad_callee, enable=1)
3372                result = False
3373                return False
3374            else:
3375                ad_caller2.log.info("Caller 2 initate 2nd call successfully")
3376
3377            if end_first_call_before_answering_second_call:
3378                try:
3379                    if not wait_for_ringing_call_for_subscription(
3380                            log,
3381                            ad_callee,
3382                            subid_callee,
3383                            incoming_number=caller2_number,
3384                            caller=ad_caller2,
3385                            event_tracking_started=True):
3386                        ad_callee.log.info(
3387                            "2nd incoming call ringing check failed.")
3388                        if not call_waiting:
3389                            set_call_waiting(log, ad_callee, enable=1)
3390                        return False
3391
3392                    time.sleep(3)
3393
3394                    ad_hangup.log.info("Disconnecting first call...")
3395                    for call_id in first_call_ids:
3396                        disconnect_call_by_id(log, ad_hangup, call_id)
3397                    time.sleep(3)
3398
3399                    ad_callee.log.info("Answering the 2nd ring call...")
3400                    ad_callee.droid.telecomAcceptRingingCall(video_state)
3401
3402                    if wait_for_call_offhook_for_subscription(
3403                            log,
3404                            ad_callee,
3405                            subid_callee,
3406                            event_tracking_started=True):
3407                        ad_callee.log.info(
3408                            "Callee answered the 2nd call successfully.")
3409                    else:
3410                        ad_callee.log.error("Could not answer the 2nd call.")
3411                        if not call_waiting:
3412                            set_call_waiting(log, ad_callee, enable=1)
3413                        return False
3414                except Exception as e:
3415                    log.error(e)
3416                    if not call_waiting:
3417                        set_call_waiting(log, ad_callee, enable=1)
3418                    return False
3419
3420            else:
3421                if not wait_and_answer_call_for_subscription(
3422                        log,
3423                        ad_callee,
3424                        subid_callee,
3425                        incoming_number=caller2_number,
3426                        caller=ad_caller2,
3427                        incall_ui_display=incall_ui_display,
3428                        video_state=video_state):
3429                    ad_callee.log.error("Failed to answer 2nd call.")
3430                    if not call_waiting:
3431                        set_call_waiting(log, ad_callee, enable=1)
3432                    result = False
3433                    return False
3434                else:
3435                    ad_callee.log.info(
3436                        "Callee answered the 2nd call successfully.")
3437
3438            for ad, subid, call_func in zip(
3439                [ad_callee, ad_caller2],
3440                [subid_callee, subid_caller2],
3441                [verify_callee_func, verify_caller2_func]):
3442                call_ids = ad.droid.telecomCallGetCallIds()
3443                new_call_ids = set(call_ids) - set(ad.call_ids)
3444                if not new_call_ids:
3445                    ad.log.error(
3446                        "No new call ids are found after 2nd call establishment")
3447                    ad.log.error("telecomCallGetCallIds returns %s",
3448                                 ad.droid.telecomCallGetCallIds())
3449                    result = False
3450                for new_call_id in new_call_ids:
3451                    if not wait_for_in_call_active(ad, call_id=new_call_id):
3452                        result = False
3453                    else:
3454                        ad.log.info("callProperties = %s",
3455                            ad.droid.telecomCallGetProperties(new_call_id))
3456
3457                if not ad.droid.telecomCallGetAudioState():
3458                    ad.log.error("Audio is not in 2nd call state")
3459                    result = False
3460
3461                if call_func(log, ad):
3462                    ad.log.info("2nd call is in %s state", call_func.__name__)
3463                else:
3464                    ad.log.error("2nd call is not in %s state, voice in RAT %s",
3465                                 call_func.__name__,
3466                                 ad.droid.telephonyGetCurrentVoiceNetworkTypeForSubscription(subid))
3467                    result = False
3468            if not result:
3469                if not call_waiting:
3470                    set_call_waiting(log, ad_callee, enable=1)
3471                return False
3472
3473        elapsed_time = 0
3474        while (elapsed_time < wait_time_in_call):
3475            CHECK_INTERVAL = min(CHECK_INTERVAL,
3476                                 wait_time_in_call - elapsed_time)
3477            time.sleep(CHECK_INTERVAL)
3478            elapsed_time += CHECK_INTERVAL
3479            time_message = "at <%s>/<%s> second." % (elapsed_time,
3480                                                     wait_time_in_call)
3481
3482            if not end_first_call_before_answering_second_call or \
3483                not call_waiting:
3484                for ad, subid, call_func in [
3485                    (ad_caller, subid_caller, verify_caller_func),
3486                    (ad_callee, subid_callee, verify_callee_func)]:
3487                    if not call_func(log, ad):
3488                        ad.log.error(
3489                            "The first call NOT in correct %s state at %s,"
3490                            " voice in RAT %s",
3491                            call_func.__name__, time_message,
3492                            ad.droid.telephonyGetCurrentVoiceNetworkTypeForSubscription(subid))
3493                        result = False
3494                    else:
3495                        ad.log.info("The first call in correct %s state at %s",
3496                                    call_func.__name__, time_message)
3497                    if not ad.droid.telecomCallGetAudioState():
3498                        ad.log.error(
3499                            "The first call audio is not in call state at %s",
3500                            time_message)
3501                        result = False
3502                if not result:
3503                    if not call_waiting:
3504                        set_call_waiting(log, ad_callee, enable=1)
3505                    return False
3506
3507            if call_waiting:
3508                for ad, call_func in [(ad_caller2, verify_caller2_func),
3509                                      (ad_callee, verify_callee_func)]:
3510                    if not call_func(log, ad):
3511                        ad.log.error(
3512                            "The 2nd call NOT in correct %s state at %s,"
3513                            " voice in RAT %s",
3514                            call_func.__name__, time_message,
3515                            ad.droid.telephonyGetCurrentVoiceNetworkTypeForSubscription(subid))
3516                        result = False
3517                    else:
3518                        ad.log.info("The 2nd call in correct %s state at %s",
3519                                    call_func.__name__, time_message)
3520                    if not ad.droid.telecomCallGetAudioState():
3521                        ad.log.error(
3522                            "The 2nd call audio is not in call state at %s",
3523                            time_message)
3524                        result = False
3525            if not result:
3526                if not call_waiting:
3527                    set_call_waiting(log, ad_callee, enable=1)
3528                return False
3529
3530        if not end_first_call_before_answering_second_call or not call_waiting:
3531            ad_hangup.log.info("Hanging up the first call...")
3532            for call_id in first_call_ids:
3533                disconnect_call_by_id(log, ad_hangup, call_id)
3534            time.sleep(5)
3535
3536        if ad_hangup2 and call_waiting:
3537            if not hangup_call(log, ad_hangup2):
3538                ad_hangup2.log.info("Failed to hang up the 2nd call")
3539                if not call_waiting:
3540                    set_call_waiting(log, ad_callee, enable=1)
3541                result = False
3542                return False
3543    finally:
3544        if not result:
3545            for ad in (ad_caller, ad_callee, ad_caller2):
3546                last_call_drop_reason(ad, begin_time)
3547                try:
3548                    if ad.droid.telecomIsInCall():
3549                        ad.log.info("In call. End now.")
3550                        ad.droid.telecomEndCall()
3551                except Exception as e:
3552                    log.error(str(e))
3553
3554        if ad_hangup or not result:
3555            for ad in (ad_caller, ad_callee):
3556                if not wait_for_call_id_clearing(
3557                        ad, getattr(ad, "caller_ids", [])):
3558                    result = False
3559
3560        if call_waiting:
3561            if ad_hangup2 or not result:
3562                for ad in (ad_caller2, ad_callee):
3563                    if not wait_for_call_id_clearing(
3564                            ad, getattr(ad, "caller_ids", [])):
3565                        result = False
3566    if not call_waiting:
3567        set_call_waiting(log, ad_callee, enable=1)
3568    return result
3569
3570
3571def wait_for_call_id_clearing(ad,
3572                              previous_ids,
3573                              timeout=MAX_WAIT_TIME_CALL_DROP):
3574    while timeout > 0:
3575        new_call_ids = ad.droid.telecomCallGetCallIds()
3576        if len(new_call_ids) <= len(previous_ids):
3577            return True
3578        time.sleep(5)
3579        timeout = timeout - 5
3580    ad.log.error("Call id clearing failed. Before: %s; After: %s",
3581                 previous_ids, new_call_ids)
3582    return False
3583
3584
3585def last_call_drop_reason(ad, begin_time=None):
3586    reasons = ad.search_logcat(
3587        "qcril_qmi_voice_map_qmi_to_ril_last_call_failure_cause", begin_time)
3588    reason_string = ""
3589    if reasons:
3590        log_msg = "Logcat call drop reasons:"
3591        for reason in reasons:
3592            log_msg = "%s\n\t%s" % (log_msg, reason["log_message"])
3593            if "ril reason str" in reason["log_message"]:
3594                reason_string = reason["log_message"].split(":")[-1].strip()
3595        ad.log.info(log_msg)
3596    reasons = ad.search_logcat("ACTION_FORBIDDEN_NO_SERVICE_AUTHORIZATION",
3597                               begin_time)
3598    if reasons:
3599        ad.log.warning("ACTION_FORBIDDEN_NO_SERVICE_AUTHORIZATION is seen")
3600    ad.log.info("last call dumpsys: %s",
3601                sorted(dumpsys_last_call_info(ad).items()))
3602    return reason_string
3603
3604
3605def phone_number_formatter(input_string, formatter=None):
3606    """Get expected format of input phone number string.
3607
3608    Args:
3609        input_string: (string) input phone number.
3610            The input could be 10/11/12 digital, with or without " "/"-"/"."
3611        formatter: (int) expected format, this could be 7/10/11/12
3612            if formatter is 7: output string would be 7 digital number.
3613            if formatter is 10: output string would be 10 digital (standard) number.
3614            if formatter is 11: output string would be "1" + 10 digital number.
3615            if formatter is 12: output string would be "+1" + 10 digital number.
3616
3617    Returns:
3618        If no error happen, return phone number in expected format.
3619        Else, return None.
3620    """
3621    if not input_string:
3622        return ""
3623    # make sure input_string is 10 digital
3624    # Remove white spaces, dashes, dots
3625    input_string = input_string.replace(" ", "").replace("-", "").replace(
3626        ".", "").lstrip("0")
3627    if not formatter:
3628        return input_string
3629    # Remove +81 and add 0 for Japan Carriers only.
3630    if (len(input_string) == 13 and input_string[0:3] == "+81"):
3631        input_string = "0" + input_string[3:]
3632        return input_string
3633    # Remove "1"  or "+1"from front
3634    if (len(input_string) == PHONE_NUMBER_STRING_FORMAT_11_DIGIT
3635            and input_string[0] == "1"):
3636        input_string = input_string[1:]
3637    elif (len(input_string) == PHONE_NUMBER_STRING_FORMAT_12_DIGIT
3638          and input_string[0:2] == "+1"):
3639        input_string = input_string[2:]
3640    elif (len(input_string) == PHONE_NUMBER_STRING_FORMAT_7_DIGIT
3641          and formatter == PHONE_NUMBER_STRING_FORMAT_7_DIGIT):
3642        return input_string
3643    elif len(input_string) != PHONE_NUMBER_STRING_FORMAT_10_DIGIT:
3644        return None
3645    # change input_string according to format
3646    if formatter == PHONE_NUMBER_STRING_FORMAT_12_DIGIT:
3647        input_string = "+1" + input_string
3648    elif formatter == PHONE_NUMBER_STRING_FORMAT_11_DIGIT:
3649        input_string = "1" + input_string
3650    elif formatter == PHONE_NUMBER_STRING_FORMAT_10_DIGIT:
3651        input_string = input_string
3652    elif formatter == PHONE_NUMBER_STRING_FORMAT_7_DIGIT:
3653        input_string = input_string[3:]
3654    else:
3655        return None
3656    return input_string
3657
3658
3659def get_internet_connection_type(log, ad):
3660    """Get current active connection type name.
3661
3662    Args:
3663        log: Log object.
3664        ad: Android Device Object.
3665    Returns:
3666        current active connection type name.
3667    """
3668    if not ad.droid.connectivityNetworkIsConnected():
3669        return 'none'
3670    return connection_type_from_type_string(
3671        ad.droid.connectivityNetworkGetActiveConnectionTypeName())
3672
3673
3674def verify_http_connection(log,
3675                           ad,
3676                           url="https://www.google.com",
3677                           retry=5,
3678                           retry_interval=15,
3679                           expected_state=True):
3680    """Make ping request and return status.
3681
3682    Args:
3683        log: log object
3684        ad: Android Device Object.
3685        url: Optional. The ping request will be made to this URL.
3686            Default Value is "http://www.google.com/".
3687
3688    """
3689    if not getattr(ad, "data_droid", None):
3690        ad.data_droid, ad.data_ed = ad.get_droid()
3691        ad.data_ed.start()
3692    else:
3693        try:
3694            if not ad.data_droid.is_live:
3695                ad.data_droid, ad.data_ed = ad.get_droid()
3696                ad.data_ed.start()
3697        except Exception:
3698            ad.log.info("Start new sl4a session for file download")
3699            ad.data_droid, ad.data_ed = ad.get_droid()
3700            ad.data_ed.start()
3701    for i in range(0, retry + 1):
3702        try:
3703            http_response = ad.data_droid.httpPing(url)
3704        except Exception as e:
3705            ad.log.info("httpPing with %s", e)
3706            http_response = None
3707        if (expected_state and http_response) or (not expected_state
3708                                                  and not http_response):
3709            ad.log.info("Http ping response for %s meet expected %s", url,
3710                        expected_state)
3711            return True
3712        if i < retry:
3713            time.sleep(retry_interval)
3714    ad.log.error("Http ping to %s is %s after %s second, expecting %s", url,
3715                 http_response, i * retry_interval, expected_state)
3716    return False
3717
3718
3719def _generate_file_directory_and_file_name(url, out_path):
3720    file_name = url.split("/")[-1]
3721    if not out_path:
3722        file_directory = "/sdcard/Download/"
3723    elif not out_path.endswith("/"):
3724        file_directory, file_name = os.path.split(out_path)
3725    else:
3726        file_directory = out_path
3727    return file_directory, file_name
3728
3729
3730def _check_file_existance(ad, file_path, expected_file_size=None):
3731    """Check file existance by file_path. If expected_file_size
3732       is provided, then also check if the file meet the file size requirement.
3733    """
3734    out = None
3735    try:
3736        out = ad.adb.shell('stat -c "%%s" %s' % file_path)
3737    except AdbError:
3738        pass
3739    # Handle some old version adb returns error message "No such" into std_out
3740    if out and "No such" not in out:
3741        if expected_file_size:
3742            file_size = int(out)
3743            if file_size >= expected_file_size:
3744                ad.log.info("File %s of size %s exists", file_path, file_size)
3745                return True
3746            else:
3747                ad.log.info("File %s is of size %s, does not meet expected %s",
3748                            file_path, file_size, expected_file_size)
3749                return False
3750        else:
3751            ad.log.info("File %s exists", file_path)
3752            return True
3753    else:
3754        ad.log.info("File %s does not exist.", file_path)
3755        return False
3756
3757
3758def check_curl_availability(ad):
3759    if not hasattr(ad, "curl_capable"):
3760        try:
3761            out = ad.adb.shell("/data/curl --version")
3762            if not out or "not found" in out:
3763                setattr(ad, "curl_capable", False)
3764                ad.log.info("curl is unavailable, use chrome to download file")
3765            else:
3766                setattr(ad, "curl_capable", True)
3767        except Exception:
3768            setattr(ad, "curl_capable", False)
3769            ad.log.info("curl is unavailable, use chrome to download file")
3770    return ad.curl_capable
3771
3772
3773def start_youtube_video(ad, url="vnd.youtube:watch?v=pSJoP0LR8CQ"):
3774    ad.log.info("Open an youtube video")
3775    for _ in range(3):
3776        ad.ensure_screen_on()
3777        ad.adb.shell('am start -a android.intent.action.VIEW -d "%s"' % url)
3778        if wait_for_state(ad.droid.audioIsMusicActive, True, 15, 1):
3779            ad.log.info("Started a video in youtube, audio is in MUSIC state")
3780            return True
3781        ad.log.info("Audio is not in MUSIC state. Quit Youtube.")
3782        for _ in range(3):
3783            ad.send_keycode("BACK")
3784            time.sleep(1)
3785        time.sleep(3)
3786    return False
3787
3788
3789def active_file_download_task(log, ad, file_name="5MB", method="curl"):
3790    # files available for download on the same website:
3791    # 1GB.zip, 512MB.zip, 200MB.zip, 50MB.zip, 20MB.zip, 10MB.zip, 5MB.zip
3792    # download file by adb command, as phone call will use sl4a
3793    file_size_map = {
3794        '1MB': 1000000,
3795        '5MB': 5000000,
3796        '10MB': 10000000,
3797        '20MB': 20000000,
3798        '50MB': 50000000,
3799        '100MB': 100000000,
3800        '200MB': 200000000,
3801        '512MB': 512000000
3802    }
3803    url_map = {
3804        "1MB": [
3805            "http://146.148.91.8/download/1MB.zip",
3806            "http://ipv4.download.thinkbroadband.com/1MB.zip"
3807        ],
3808        "5MB": [
3809            "http://146.148.91.8/download/5MB.zip",
3810            "http://212.183.159.230/5MB.zip",
3811            "http://ipv4.download.thinkbroadband.com/5MB.zip"
3812        ],
3813        "10MB": [
3814            "http://146.148.91.8/download/10MB.zip",
3815            "http://212.183.159.230/10MB.zip",
3816            "http://ipv4.download.thinkbroadband.com/10MB.zip",
3817            "http://lax.futurehosting.com/test.zip",
3818            "http://ovh.net/files/10Mio.dat"
3819        ],
3820        "20MB": [
3821            "http://146.148.91.8/download/20MB.zip",
3822            "http://212.183.159.230/20MB.zip",
3823            "http://ipv4.download.thinkbroadband.com/20MB.zip"
3824        ],
3825        "50MB": [
3826            "http://146.148.91.8/download/50MB.zip",
3827            "http://212.183.159.230/50MB.zip",
3828            "http://ipv4.download.thinkbroadband.com/50MB.zip"
3829        ],
3830        "100MB": [
3831            "http://146.148.91.8/download/100MB.zip",
3832            "http://212.183.159.230/100MB.zip",
3833            "http://ipv4.download.thinkbroadband.com/100MB.zip",
3834            "http://speedtest-ca.turnkeyinternet.net/100mb.bin",
3835            "http://ovh.net/files/100Mio.dat",
3836            "http://lax.futurehosting.com/test100.zip"
3837        ],
3838        "200MB": [
3839            "http://146.148.91.8/download/200MB.zip",
3840            "http://212.183.159.230/200MB.zip",
3841            "http://ipv4.download.thinkbroadband.com/200MB.zip"
3842        ],
3843        "512MB": [
3844            "http://146.148.91.8/download/512MB.zip",
3845            "http://212.183.159.230/512MB.zip",
3846            "http://ipv4.download.thinkbroadband.com/512MB.zip"
3847        ]
3848    }
3849
3850    file_size = file_size_map.get(file_name)
3851    file_urls = url_map.get(file_name)
3852    file_url = None
3853    for url in file_urls:
3854        url_splits = url.split("/")
3855        if verify_http_connection(log, ad, url=url, retry=1):
3856            output_path = "/sdcard/Download/%s" % url_splits[-1]
3857            file_url = url
3858            break
3859    if not file_url:
3860        ad.log.error("No url is available to download %s", file_name)
3861        return False
3862    timeout = min(max(file_size / 100000, 600), 3600)
3863    if method == "sl4a":
3864        return (http_file_download_by_sl4a, (ad, file_url, output_path,
3865                                             file_size, True, timeout))
3866    if method == "curl" and check_curl_availability(ad):
3867        return (http_file_download_by_curl, (ad, file_url, output_path,
3868                                             file_size, True, timeout))
3869    elif method == "sl4a" or method == "curl":
3870        return (http_file_download_by_sl4a, (ad, file_url, output_path,
3871                                             file_size, True, timeout))
3872    else:
3873        return (http_file_download_by_chrome, (ad, file_url, file_size, True,
3874                                               timeout))
3875
3876
3877def active_file_download_test(log, ad, file_name="5MB", method="sl4a"):
3878    task = active_file_download_task(log, ad, file_name, method=method)
3879    if not task:
3880        return False
3881    return task[0](*task[1])
3882
3883
3884def verify_internet_connection_by_ping(log,
3885                                       ad,
3886                                       retries=1,
3887                                       expected_state=True,
3888                                       timeout=60):
3889    """Verify internet connection by ping test.
3890
3891    Args:
3892        log: log object
3893        ad: Android Device Object.
3894
3895    """
3896    begin_time = get_current_epoch_time()
3897    ip_addr = "54.230.144.105"
3898    for dest in ("www.google.com", "www.amazon.com", ip_addr):
3899        for i in range(retries):
3900            ad.log.info("Ping %s - attempt %d", dest, i + 1)
3901            result = adb_shell_ping(
3902                ad, count=5, timeout=timeout, loss_tolerance=40, dest_ip=dest)
3903            if result == expected_state:
3904                ad.log.info(
3905                    "Internet connection by pinging to %s is %s as expected",
3906                    dest, expected_state)
3907                if dest == ip_addr:
3908                    ad.log.warning("Suspect dns failure")
3909                    ad.log.info("DNS config: %s",
3910                                ad.adb.shell("getprop | grep dns").replace(
3911                                    "\n", " "))
3912                    return False
3913                return True
3914            else:
3915                ad.log.warning(
3916                    "Internet connection test by pinging %s is %s, expecting %s",
3917                    dest, result, expected_state)
3918                if get_current_epoch_time() - begin_time < timeout * 1000:
3919                    time.sleep(5)
3920    ad.log.error("Ping test doesn't meet expected %s", expected_state)
3921    return False
3922
3923
3924def verify_internet_connection(log, ad, retries=3, expected_state=True):
3925    """Verify internet connection by ping test and http connection.
3926
3927    Args:
3928        log: log object
3929        ad: Android Device Object.
3930
3931    """
3932    if ad.droid.connectivityNetworkIsConnected() != expected_state:
3933        ad.log.info("NetworkIsConnected = %s, expecting %s",
3934                    not expected_state, expected_state)
3935    if verify_internet_connection_by_ping(
3936            log, ad, retries=retries, expected_state=expected_state):
3937        return True
3938    for url in ("https://www.google.com", "https://www.amazon.com"):
3939        if verify_http_connection(
3940                log, ad, url=url, retry=retries,
3941                expected_state=expected_state):
3942            return True
3943    ad.log.info("DNS config: %s", " ".join(
3944        ad.adb.shell("getprop | grep dns").split()))
3945    ad.log.info("Interface info:\n%s", ad.adb.shell("ifconfig"))
3946    ad.log.info("NetworkAgentInfo: %s",
3947                ad.adb.shell("dumpsys connectivity | grep NetworkAgentInfo"))
3948    return False
3949
3950
3951def iperf_test_with_options(log,
3952                            ad,
3953                            iperf_server,
3954                            iperf_option,
3955                            timeout=180,
3956                            rate_dict=None,
3957                            blocking=True,
3958                            log_file_path=None):
3959    """iperf adb run helper.
3960
3961    Args:
3962        log: log object
3963        ad: Android Device Object.
3964        iperf_server: The iperf host url".
3965        iperf_option: The options to pass to iperf client
3966        timeout: timeout for file download to complete.
3967        rate_dict: dictionary that can be passed in to save data
3968        blocking: run iperf in blocking mode if True
3969        log_file_path: location to save logs
3970    Returns:
3971        True if iperf runs without throwing an exception
3972    """
3973    try:
3974        if log_file_path:
3975            ad.adb.shell("rm %s" % log_file_path, ignore_status=True)
3976        ad.log.info("Running adb iperf test with server %s", iperf_server)
3977        ad.log.info("iperf options are %s", iperf_option)
3978        if not blocking:
3979            ad.run_iperf_client_nb(
3980                iperf_server,
3981                iperf_option,
3982                timeout=timeout + 60,
3983                log_file_path=log_file_path)
3984            return True
3985        result, data = ad.run_iperf_client(
3986            iperf_server, iperf_option, timeout=timeout + 60)
3987        ad.log.info("iperf test result with server %s is %s", iperf_server,
3988                    result)
3989        if result:
3990            iperf_str = ''.join(data)
3991            iperf_result = ipf.IPerfResult(iperf_str, 'None')
3992            if "-u" in iperf_option:
3993                udp_rate = iperf_result.avg_rate
3994                if udp_rate is None:
3995                    ad.log.warning(
3996                        "UDP rate is none, IPerf server returned error: %s",
3997                        iperf_result.error)
3998                ad.log.info("iperf3 UDP DL speed is %.6s Mbps", (udp_rate/1000000))
3999            else:
4000                tx_rate = iperf_result.avg_send_rate
4001                rx_rate = iperf_result.avg_receive_rate
4002                if (tx_rate or rx_rate) is None:
4003                    ad.log.warning(
4004                        "A TCP rate is none, iperf server returned error: %s",
4005                        iperf_result.error)
4006                ad.log.info(
4007                    "iperf3 TCP - UL speed is %.6s Mbps, DL speed is %.6s Mbps",
4008                    (tx_rate/1000000), (rx_rate/1000000))
4009            if rate_dict is not None:
4010                rate_dict["Uplink"] = tx_rate
4011                rate_dict["Downlink"] = rx_rate
4012        return result
4013    except AdbError as e:
4014        ad.log.warning("Fail to run iperf test with exception %s", e)
4015        raise
4016
4017
4018def iperf_udp_test_by_adb(log,
4019                          ad,
4020                          iperf_server,
4021                          port_num=None,
4022                          reverse=False,
4023                          timeout=180,
4024                          limit_rate=None,
4025                          pacing_timer=None,
4026                          omit=10,
4027                          ipv6=False,
4028                          rate_dict=None,
4029                          blocking=True,
4030                          log_file_path=None):
4031    """Iperf test by adb using UDP.
4032
4033    Args:
4034        log: log object
4035        ad: Android Device Object.
4036        iperf_Server: The iperf host url".
4037        port_num: TCP/UDP server port
4038        reverse: whether to test download instead of upload
4039        timeout: timeout for file download to complete.
4040        limit_rate: iperf bandwidth option. None by default
4041        omit: the omit option provided in iperf command.
4042        ipv6: whether to run the test as ipv6
4043        rate_dict: dictionary that can be passed in to save data
4044        blocking: run iperf in blocking mode if True
4045        log_file_path: location to save logs
4046    """
4047    iperf_option = "-u -i 1 -t %s -O %s -J" % (timeout, omit)
4048    if limit_rate:
4049        iperf_option += " -b %s" % limit_rate
4050    if pacing_timer:
4051        iperf_option += " --pacing-timer %s" % pacing_timer
4052    if port_num:
4053        iperf_option += " -p %s" % port_num
4054    if ipv6:
4055        iperf_option += " -6"
4056    if reverse:
4057        iperf_option += " -R"
4058    try:
4059        return iperf_test_with_options(log,
4060                                        ad,
4061                                        iperf_server,
4062                                        iperf_option,
4063                                        timeout,
4064                                        rate_dict,
4065                                        blocking,
4066                                        log_file_path)
4067    except AdbError:
4068        return False
4069
4070
4071def iperf_test_by_adb(log,
4072                      ad,
4073                      iperf_server,
4074                      port_num=None,
4075                      reverse=False,
4076                      timeout=180,
4077                      limit_rate=None,
4078                      omit=10,
4079                      ipv6=False,
4080                      rate_dict=None,
4081                      blocking=True,
4082                      log_file_path=None):
4083    """Iperf test by adb using TCP.
4084
4085    Args:
4086        log: log object
4087        ad: Android Device Object.
4088        iperf_server: The iperf host url".
4089        port_num: TCP/UDP server port
4090        reverse: whether to test download instead of upload
4091        timeout: timeout for file download to complete.
4092        limit_rate: iperf bandwidth option. None by default
4093        omit: the omit option provided in iperf command.
4094        ipv6: whether to run the test as ipv6
4095        rate_dict: dictionary that can be passed in to save data
4096        blocking: run iperf in blocking mode if True
4097        log_file_path: location to save logs
4098    """
4099    iperf_option = "-t %s -O %s -J" % (timeout, omit)
4100    if limit_rate:
4101        iperf_option += " -b %s" % limit_rate
4102    if port_num:
4103        iperf_option += " -p %s" % port_num
4104    if ipv6:
4105        iperf_option += " -6"
4106    if reverse:
4107        iperf_option += " -R"
4108    try:
4109        return iperf_test_with_options(log,
4110                                        ad,
4111                                        iperf_server,
4112                                        iperf_option,
4113                                        timeout,
4114                                        rate_dict,
4115                                        blocking,
4116                                        log_file_path)
4117    except AdbError:
4118        return False
4119
4120
4121def http_file_download_by_curl(ad,
4122                               url,
4123                               out_path=None,
4124                               expected_file_size=None,
4125                               remove_file_after_check=True,
4126                               timeout=3600,
4127                               limit_rate=None,
4128                               retry=3):
4129    """Download http file by adb curl.
4130
4131    Args:
4132        ad: Android Device Object.
4133        url: The url that file to be downloaded from".
4134        out_path: Optional. Where to download file to.
4135                  out_path is /sdcard/Download/ by default.
4136        expected_file_size: Optional. Provided if checking the download file meet
4137                            expected file size in unit of byte.
4138        remove_file_after_check: Whether to remove the downloaded file after
4139                                 check.
4140        timeout: timeout for file download to complete.
4141        limit_rate: download rate in bps. None, if do not apply rate limit.
4142        retry: the retry request times provided in curl command.
4143    """
4144    file_directory, file_name = _generate_file_directory_and_file_name(
4145        url, out_path)
4146    file_path = os.path.join(file_directory, file_name)
4147    curl_cmd = "/data/curl"
4148    if limit_rate:
4149        curl_cmd += " --limit-rate %s" % limit_rate
4150    if retry:
4151        curl_cmd += " --retry %s" % retry
4152    curl_cmd += " --url %s > %s" % (url, file_path)
4153    try:
4154        ad.log.info("Download %s to %s by adb shell command %s", url,
4155                    file_path, curl_cmd)
4156
4157        ad.adb.shell(curl_cmd, timeout=timeout)
4158        if _check_file_existance(ad, file_path, expected_file_size):
4159            ad.log.info("%s is downloaded to %s successfully", url, file_path)
4160            return True
4161        else:
4162            ad.log.warning("Fail to download %s", url)
4163            return False
4164    except Exception as e:
4165        ad.log.warning("Download %s failed with exception %s", url, e)
4166        return False
4167    finally:
4168        if remove_file_after_check:
4169            ad.log.info("Remove the downloaded file %s", file_path)
4170            ad.adb.shell("rm %s" % file_path, ignore_status=True)
4171
4172
4173def open_url_by_adb(ad, url):
4174    ad.adb.shell('am start -a android.intent.action.VIEW -d "%s"' % url)
4175
4176
4177def http_file_download_by_chrome(ad,
4178                                 url,
4179                                 expected_file_size=None,
4180                                 remove_file_after_check=True,
4181                                 timeout=3600):
4182    """Download http file by chrome.
4183
4184    Args:
4185        ad: Android Device Object.
4186        url: The url that file to be downloaded from".
4187        expected_file_size: Optional. Provided if checking the download file meet
4188                            expected file size in unit of byte.
4189        remove_file_after_check: Whether to remove the downloaded file after
4190                                 check.
4191        timeout: timeout for file download to complete.
4192    """
4193    chrome_apk = "com.android.chrome"
4194    file_directory, file_name = _generate_file_directory_and_file_name(
4195        url, "/sdcard/Download/")
4196    file_path = os.path.join(file_directory, file_name)
4197    # Remove pre-existing file
4198    ad.force_stop_apk(chrome_apk)
4199    file_to_be_delete = os.path.join(file_directory, "*%s*" % file_name)
4200    ad.adb.shell("rm -f %s" % file_to_be_delete)
4201    ad.adb.shell("rm -rf /sdcard/Download/.*")
4202    ad.adb.shell("rm -f /sdcard/Download/.*")
4203    data_accounting = {
4204        "total_rx_bytes": ad.droid.getTotalRxBytes(),
4205        "mobile_rx_bytes": ad.droid.getMobileRxBytes(),
4206        "subscriber_mobile_data_usage": get_mobile_data_usage(ad, None, None),
4207        "chrome_mobile_data_usage": get_mobile_data_usage(
4208            ad, None, chrome_apk)
4209    }
4210    ad.log.debug("Before downloading: %s", data_accounting)
4211    ad.log.info("Download %s with timeout %s", url, timeout)
4212    ad.ensure_screen_on()
4213    open_url_by_adb(ad, url)
4214    elapse_time = 0
4215    result = True
4216    while elapse_time < timeout:
4217        time.sleep(30)
4218        if _check_file_existance(ad, file_path, expected_file_size):
4219            ad.log.info("%s is downloaded successfully", url)
4220            if remove_file_after_check:
4221                ad.log.info("Remove the downloaded file %s", file_path)
4222                ad.adb.shell("rm -f %s" % file_to_be_delete)
4223                ad.adb.shell("rm -rf /sdcard/Download/.*")
4224                ad.adb.shell("rm -f /sdcard/Download/.*")
4225            #time.sleep(30)
4226            new_data_accounting = {
4227                "mobile_rx_bytes":
4228                ad.droid.getMobileRxBytes(),
4229                "subscriber_mobile_data_usage":
4230                get_mobile_data_usage(ad, None, None),
4231                "chrome_mobile_data_usage":
4232                get_mobile_data_usage(ad, None, chrome_apk)
4233            }
4234            ad.log.info("After downloading: %s", new_data_accounting)
4235            accounting_diff = {
4236                key: value - data_accounting[key]
4237                for key, value in new_data_accounting.items()
4238            }
4239            ad.log.debug("Data accounting difference: %s", accounting_diff)
4240            if getattr(ad, "on_mobile_data", False):
4241                for key, value in accounting_diff.items():
4242                    if value < expected_file_size:
4243                        ad.log.warning("%s diff is %s less than %s", key,
4244                                       value, expected_file_size)
4245                        ad.data_accounting["%s_failure" % key] += 1
4246            else:
4247                for key, value in accounting_diff.items():
4248                    if value >= expected_file_size:
4249                        ad.log.error("%s diff is %s. File download is "
4250                                     "consuming mobile data", key, value)
4251                        result = False
4252            return result
4253        elif _check_file_existance(ad, "%s.crdownload" % file_path):
4254            ad.log.info("Chrome is downloading %s", url)
4255        elif elapse_time < 60:
4256            # download not started, retry download wit chrome again
4257            open_url_by_adb(ad, url)
4258        else:
4259            ad.log.error("Unable to download file from %s", url)
4260            break
4261        elapse_time += 30
4262    ad.log.warning("Fail to download file from %s", url)
4263    ad.force_stop_apk("com.android.chrome")
4264    ad.adb.shell("rm -f %s" % file_to_be_delete)
4265    ad.adb.shell("rm -rf /sdcard/Download/.*")
4266    ad.adb.shell("rm -f /sdcard/Download/.*")
4267    return False
4268
4269
4270def http_file_download_by_sl4a(ad,
4271                               url,
4272                               out_path=None,
4273                               expected_file_size=None,
4274                               remove_file_after_check=True,
4275                               timeout=300):
4276    """Download http file by sl4a RPC call.
4277
4278    Args:
4279        ad: Android Device Object.
4280        url: The url that file to be downloaded from".
4281        out_path: Optional. Where to download file to.
4282                  out_path is /sdcard/Download/ by default.
4283        expected_file_size: Optional. Provided if checking the download file meet
4284                            expected file size in unit of byte.
4285        remove_file_after_check: Whether to remove the downloaded file after
4286                                 check.
4287        timeout: timeout for file download to complete.
4288    """
4289    file_folder, file_name = _generate_file_directory_and_file_name(
4290        url, out_path)
4291    file_path = os.path.join(file_folder, file_name)
4292    ad.adb.shell("rm -f %s" % file_path)
4293    accounting_apk = SL4A_APK_NAME
4294    result = True
4295    try:
4296        if not getattr(ad, "data_droid", None):
4297            ad.data_droid, ad.data_ed = ad.get_droid()
4298            ad.data_ed.start()
4299        else:
4300            try:
4301                if not ad.data_droid.is_live:
4302                    ad.data_droid, ad.data_ed = ad.get_droid()
4303                    ad.data_ed.start()
4304            except Exception:
4305                ad.log.info("Start new sl4a session for file download")
4306                ad.data_droid, ad.data_ed = ad.get_droid()
4307                ad.data_ed.start()
4308        data_accounting = {
4309            "mobile_rx_bytes":
4310            ad.droid.getMobileRxBytes(),
4311            "subscriber_mobile_data_usage":
4312            get_mobile_data_usage(ad, None, None),
4313            "sl4a_mobile_data_usage":
4314            get_mobile_data_usage(ad, None, accounting_apk)
4315        }
4316        ad.log.debug("Before downloading: %s", data_accounting)
4317        ad.log.info("Download file from %s to %s by sl4a RPC call", url,
4318                    file_path)
4319        try:
4320            ad.data_droid.httpDownloadFile(url, file_path, timeout=timeout)
4321        except Exception as e:
4322            ad.log.warning("SL4A file download error: %s", e)
4323            ad.data_droid.terminate()
4324            return False
4325        if _check_file_existance(ad, file_path, expected_file_size):
4326            ad.log.info("%s is downloaded successfully", url)
4327            new_data_accounting = {
4328                "mobile_rx_bytes":
4329                ad.droid.getMobileRxBytes(),
4330                "subscriber_mobile_data_usage":
4331                get_mobile_data_usage(ad, None, None),
4332                "sl4a_mobile_data_usage":
4333                get_mobile_data_usage(ad, None, accounting_apk)
4334            }
4335            ad.log.debug("After downloading: %s", new_data_accounting)
4336            accounting_diff = {
4337                key: value - data_accounting[key]
4338                for key, value in new_data_accounting.items()
4339            }
4340            ad.log.debug("Data accounting difference: %s", accounting_diff)
4341            if getattr(ad, "on_mobile_data", False):
4342                for key, value in accounting_diff.items():
4343                    if value < expected_file_size:
4344                        ad.log.debug("%s diff is %s less than %s", key,
4345                                       value, expected_file_size)
4346                        ad.data_accounting["%s_failure"] += 1
4347            else:
4348                for key, value in accounting_diff.items():
4349                    if value >= expected_file_size:
4350                        ad.log.error("%s diff is %s. File download is "
4351                                     "consuming mobile data", key, value)
4352                        result = False
4353            return result
4354        else:
4355            ad.log.warning("Fail to download %s", url)
4356            return False
4357    except Exception as e:
4358        ad.log.error("Download %s failed with exception %s", url, e)
4359        raise
4360    finally:
4361        if remove_file_after_check:
4362            ad.log.info("Remove the downloaded file %s", file_path)
4363            ad.adb.shell("rm %s" % file_path, ignore_status=True)
4364
4365
4366def get_wifi_usage(ad, sid=None, apk=None):
4367    if not sid:
4368        sid = ad.droid.subscriptionGetDefaultDataSubId()
4369    current_time = int(time.time() * 1000)
4370    begin_time = current_time - 10 * 24 * 60 * 60 * 1000
4371    end_time = current_time + 10 * 24 * 60 * 60 * 1000
4372
4373    if apk:
4374        uid = ad.get_apk_uid(apk)
4375        ad.log.debug("apk %s uid = %s", apk, uid)
4376        try:
4377            return ad.droid.connectivityQueryDetailsForUid(
4378                TYPE_WIFI,
4379                ad.droid.telephonyGetSubscriberIdForSubscription(sid),
4380                begin_time, end_time, uid)
4381        except:
4382            return ad.droid.connectivityQueryDetailsForUid(
4383                ad.droid.telephonyGetSubscriberIdForSubscription(sid),
4384                begin_time, end_time, uid)
4385    else:
4386        try:
4387            return ad.droid.connectivityQuerySummaryForDevice(
4388                TYPE_WIFI,
4389                ad.droid.telephonyGetSubscriberIdForSubscription(sid),
4390                begin_time, end_time)
4391        except:
4392            return ad.droid.connectivityQuerySummaryForDevice(
4393                ad.droid.telephonyGetSubscriberIdForSubscription(sid),
4394                begin_time, end_time)
4395
4396
4397def get_mobile_data_usage(ad, sid=None, apk=None):
4398    if not sid:
4399        sid = ad.droid.subscriptionGetDefaultDataSubId()
4400    current_time = int(time.time() * 1000)
4401    begin_time = current_time - 10 * 24 * 60 * 60 * 1000
4402    end_time = current_time + 10 * 24 * 60 * 60 * 1000
4403
4404    if apk:
4405        uid = ad.get_apk_uid(apk)
4406        ad.log.debug("apk %s uid = %s", apk, uid)
4407        try:
4408            usage_info = ad.droid.getMobileDataUsageInfoForUid(uid, sid)
4409            ad.log.debug("Mobile data usage info for uid %s = %s", uid,
4410                        usage_info)
4411            return usage_info["UsageLevel"]
4412        except:
4413            try:
4414                return ad.droid.connectivityQueryDetailsForUid(
4415                    TYPE_MOBILE,
4416                    ad.droid.telephonyGetSubscriberIdForSubscription(sid),
4417                    begin_time, end_time, uid)
4418            except:
4419                return ad.droid.connectivityQueryDetailsForUid(
4420                    ad.droid.telephonyGetSubscriberIdForSubscription(sid),
4421                    begin_time, end_time, uid)
4422    else:
4423        try:
4424            usage_info = ad.droid.getMobileDataUsageInfo(sid)
4425            ad.log.debug("Mobile data usage info = %s", usage_info)
4426            return usage_info["UsageLevel"]
4427        except:
4428            try:
4429                return ad.droid.connectivityQuerySummaryForDevice(
4430                    TYPE_MOBILE,
4431                    ad.droid.telephonyGetSubscriberIdForSubscription(sid),
4432                    begin_time, end_time)
4433            except:
4434                return ad.droid.connectivityQuerySummaryForDevice(
4435                    ad.droid.telephonyGetSubscriberIdForSubscription(sid),
4436                    begin_time, end_time)
4437
4438
4439def set_mobile_data_usage_limit(ad, limit, subscriber_id=None):
4440    if not subscriber_id:
4441        subscriber_id = ad.droid.telephonyGetSubscriberId()
4442    ad.log.debug("Set subscriber mobile data usage limit to %s", limit)
4443    ad.droid.logV("Setting subscriber mobile data usage limit to %s" % limit)
4444    try:
4445        ad.droid.connectivitySetDataUsageLimit(subscriber_id, str(limit))
4446    except:
4447        ad.droid.connectivitySetDataUsageLimit(subscriber_id, limit)
4448
4449
4450def remove_mobile_data_usage_limit(ad, subscriber_id=None):
4451    if not subscriber_id:
4452        subscriber_id = ad.droid.telephonyGetSubscriberId()
4453    ad.log.debug("Remove subscriber mobile data usage limit")
4454    ad.droid.logV(
4455        "Setting subscriber mobile data usage limit to -1, unlimited")
4456    try:
4457        ad.droid.connectivitySetDataUsageLimit(subscriber_id, "-1")
4458    except:
4459        ad.droid.connectivitySetDataUsageLimit(subscriber_id, -1)
4460
4461
4462def trigger_modem_crash(ad, timeout=120):
4463    cmd = "echo restart > /sys/kernel/debug/msm_subsys/modem"
4464    ad.log.info("Triggering Modem Crash from kernel using adb command %s", cmd)
4465    ad.adb.shell(cmd)
4466    time.sleep(timeout)
4467    return True
4468
4469
4470def trigger_modem_crash_by_modem(ad, timeout=120):
4471    begin_time = get_device_epoch_time(ad)
4472    ad.adb.shell(
4473        "setprop persist.vendor.sys.modem.diag.mdlog false",
4474        ignore_status=True)
4475    # Legacy pixels use persist.sys.modem.diag.mdlog.
4476    ad.adb.shell(
4477        "setprop persist.sys.modem.diag.mdlog false", ignore_status=True)
4478    disable_qxdm_logger(ad)
4479    cmd = ('am instrument -w -e request "4b 25 03 00" '
4480           '"com.google.mdstest/com.google.mdstest.instrument.'
4481           'ModemCommandInstrumentation"')
4482    ad.log.info("Crash modem by %s", cmd)
4483    ad.adb.shell(cmd, ignore_status=True)
4484    time.sleep(timeout)  # sleep time for sl4a stability
4485    reasons = ad.search_logcat("modem subsystem failure reason", begin_time)
4486    if reasons:
4487        ad.log.info("Modem crash is triggered successfully")
4488        ad.log.info(reasons[-1]["log_message"])
4489        return True
4490    else:
4491        ad.log.warning("There is no modem subsystem failure reason logcat")
4492        return False
4493
4494
4495def phone_switch_to_msim_mode(ad, retries=3, timeout=60):
4496    result = False
4497    if not ad.is_apk_installed("com.google.mdstest"):
4498        raise signals.TestAbortClass("mdstest is not installed")
4499    mode = ad.droid.telephonyGetPhoneCount()
4500    if mode == 2:
4501        ad.log.info("Device already in MSIM mode")
4502        return True
4503    for i in range(retries):
4504        ad.adb.shell(
4505        "setprop persist.vendor.sys.modem.diag.mdlog false", ignore_status=True)
4506        ad.adb.shell(
4507        "setprop persist.sys.modem.diag.mdlog false", ignore_status=True)
4508        disable_qxdm_logger(ad)
4509        cmd = ('am instrument -w -e request "WriteEFS" -e item '
4510               '"/google/pixel_multisim_config" -e data  "02 00 00 00" '
4511               '"com.google.mdstest/com.google.mdstest.instrument.'
4512               'ModemConfigInstrumentation"')
4513        ad.log.info("Switch to MSIM mode by using %s", cmd)
4514        ad.adb.shell(cmd, ignore_status=True)
4515        time.sleep(timeout)
4516        ad.adb.shell("setprop persist.radio.multisim.config dsds")
4517        reboot_device(ad)
4518        # Verify if device is really in msim mode
4519        mode = ad.droid.telephonyGetPhoneCount()
4520        if mode == 2:
4521            ad.log.info("Device correctly switched to MSIM mode")
4522            result = True
4523            if "Sprint" in ad.adb.getprop("gsm.sim.operator.alpha"):
4524                cmd = ('am instrument -w -e request "WriteEFS" -e item '
4525                       '"/google/pixel_dsds_imei_mapping_slot_record" -e data "03"'
4526                       ' "com.google.mdstest/com.google.mdstest.instrument.'
4527                       'ModemConfigInstrumentation"')
4528                ad.log.info("Switch Sprint to IMEI1 slot using %s", cmd)
4529                ad.adb.shell(cmd, ignore_status=True)
4530                time.sleep(timeout)
4531                reboot_device(ad)
4532            break
4533        else:
4534            ad.log.warning("Attempt %d - failed to switch to MSIM", (i + 1))
4535    return result
4536
4537
4538def phone_switch_to_ssim_mode(ad, retries=3, timeout=30):
4539    result = False
4540    if not ad.is_apk_installed("com.google.mdstest"):
4541        raise signals.TestAbortClass("mdstest is not installed")
4542    mode = ad.droid.telephonyGetPhoneCount()
4543    if mode == 1:
4544        ad.log.info("Device already in SSIM mode")
4545        return True
4546    for i in range(retries):
4547        ad.adb.shell(
4548        "setprop persist.vendor.sys.modem.diag.mdlog false", ignore_status=True)
4549        ad.adb.shell(
4550        "setprop persist.sys.modem.diag.mdlog false", ignore_status=True)
4551        disable_qxdm_logger(ad)
4552        cmds = ('am instrument -w -e request "WriteEFS" -e item '
4553                '"/google/pixel_multisim_config" -e data  "01 00 00 00" '
4554                '"com.google.mdstest/com.google.mdstest.instrument.'
4555                'ModemConfigInstrumentation"',
4556                'am instrument -w -e request "WriteEFS" -e item "/nv/item_files'
4557                '/modem/uim/uimdrv/uim_extended_slot_mapping_config" -e data '
4558                '"00 01 02 01" "com.google.mdstest/com.google.mdstest.'
4559                'instrument.ModemConfigInstrumentation"')
4560        for cmd in cmds:
4561            ad.log.info("Switch to SSIM mode by using %s", cmd)
4562            ad.adb.shell(cmd, ignore_status=True)
4563            time.sleep(timeout)
4564        ad.adb.shell("setprop persist.radio.multisim.config ssss")
4565        reboot_device(ad)
4566        # Verify if device is really in ssim mode
4567        mode = ad.droid.telephonyGetPhoneCount()
4568        if mode == 1:
4569            ad.log.info("Device correctly switched to SSIM mode")
4570            result = True
4571            break
4572        else:
4573            ad.log.warning("Attempt %d - failed to switch to SSIM", (i + 1))
4574    return result
4575
4576
4577def lock_lte_band_by_mds(ad, band):
4578    disable_qxdm_logger(ad)
4579    ad.log.info("Write band %s locking to efs file", band)
4580    if band == "4":
4581        item_string = (
4582            "4B 13 26 00 08 00 00 00 40 00 08 00 0B 00 08 00 00 00 00 00 00 00 "
4583            "2F 6E 76 2F 69 74 65 6D 5F 66 69 6C 65 73 2F 6D 6F 64 65 6D 2F 6D "
4584            "6D 6F 64 65 2F 6C 74 65 5F 62 61 6E 64 70 72 65 66 00")
4585    elif band == "13":
4586        item_string = (
4587            "4B 13 26 00 08 00 00 00 40 00 08 00 0A 00 00 10 00 00 00 00 00 00 "
4588            "2F 6E 76 2F 69 74 65 6D 5F 66 69 6C 65 73 2F 6D 6F 64 65 6D 2F 6D "
4589            "6D 6F 64 65 2F 6C 74 65 5F 62 61 6E 64 70 72 65 66 00")
4590    else:
4591        ad.log.error("Band %s is not supported", band)
4592        return False
4593    cmd = ('am instrument -w -e request "%s" com.google.mdstest/com.google.'
4594           'mdstest.instrument.ModemCommandInstrumentation')
4595    for _ in range(3):
4596        if "SUCCESS" in ad.adb.shell(cmd % item_string, ignore_status=True):
4597            break
4598    else:
4599        ad.log.error("Fail to write band by %s" % (cmd % item_string))
4600        return False
4601
4602    # EFS Sync
4603    item_string = "4B 13 30 00 2A 00 2F 00"
4604
4605    for _ in range(3):
4606        if "SUCCESS" in ad.adb.shell(cmd % item_string, ignore_status=True):
4607            break
4608    else:
4609        ad.log.error("Fail to sync efs by %s" % (cmd % item_string))
4610        return False
4611    time.sleep(5)
4612    reboot_device(ad)
4613
4614
4615def _connection_state_change(_event, target_state, connection_type):
4616    if connection_type:
4617        if 'TypeName' not in _event['data']:
4618            return False
4619        connection_type_string_in_event = _event['data']['TypeName']
4620        cur_type = connection_type_from_type_string(
4621            connection_type_string_in_event)
4622        if cur_type != connection_type:
4623            log.info(
4624                "_connection_state_change expect: %s, received: %s <type %s>",
4625                connection_type, connection_type_string_in_event, cur_type)
4626            return False
4627
4628    if 'isConnected' in _event['data'] and _event['data']['isConnected'] == target_state:
4629        return True
4630    return False
4631
4632
4633def wait_for_cell_data_connection(
4634        log, ad, state, timeout_value=MAX_WAIT_TIME_CONNECTION_STATE_UPDATE):
4635    """Wait for data connection status to be expected value for default
4636       data subscription.
4637
4638    Wait for the data connection status to be DATA_STATE_CONNECTED
4639        or DATA_STATE_DISCONNECTED.
4640
4641    Args:
4642        log: Log object.
4643        ad: Android Device Object.
4644        state: Expected status: True or False.
4645            If True, it will wait for status to be DATA_STATE_CONNECTED.
4646            If False, it will wait for status ti be DATA_STATE_DISCONNECTED.
4647        timeout_value: wait for cell data timeout value.
4648            This is optional, default value is MAX_WAIT_TIME_CONNECTION_STATE_UPDATE
4649
4650    Returns:
4651        True if success.
4652        False if failed.
4653    """
4654    sub_id = get_default_data_sub_id(ad)
4655    return wait_for_cell_data_connection_for_subscription(
4656        log, ad, sub_id, state, timeout_value)
4657
4658
4659def _is_data_connection_state_match(log, ad, expected_data_connection_state):
4660    return (expected_data_connection_state ==
4661            ad.droid.telephonyGetDataConnectionState())
4662
4663
4664def _is_network_connected_state_match(log, ad,
4665                                      expected_network_connected_state):
4666    return (expected_network_connected_state ==
4667            ad.droid.connectivityNetworkIsConnected())
4668
4669
4670def wait_for_cell_data_connection_for_subscription(
4671        log,
4672        ad,
4673        sub_id,
4674        state,
4675        timeout_value=MAX_WAIT_TIME_CONNECTION_STATE_UPDATE):
4676    """Wait for data connection status to be expected value for specified
4677       subscrption id.
4678
4679    Wait for the data connection status to be DATA_STATE_CONNECTED
4680        or DATA_STATE_DISCONNECTED.
4681
4682    Args:
4683        log: Log object.
4684        ad: Android Device Object.
4685        sub_id: subscription Id
4686        state: Expected status: True or False.
4687            If True, it will wait for status to be DATA_STATE_CONNECTED.
4688            If False, it will wait for status ti be DATA_STATE_DISCONNECTED.
4689        timeout_value: wait for cell data timeout value.
4690            This is optional, default value is MAX_WAIT_TIME_CONNECTION_STATE_UPDATE
4691
4692    Returns:
4693        True if success.
4694        False if failed.
4695    """
4696    state_str = {
4697        True: DATA_STATE_CONNECTED,
4698        False: DATA_STATE_DISCONNECTED
4699    }[state]
4700
4701    data_state = ad.droid.telephonyGetDataConnectionState()
4702    if not state and ad.droid.telephonyGetDataConnectionState() == state_str:
4703        return True
4704
4705    ad.ed.clear_events(EventDataConnectionStateChanged)
4706    ad.droid.telephonyStartTrackingDataConnectionStateChangeForSubscription(
4707        sub_id)
4708    ad.droid.connectivityStartTrackingConnectivityStateChange()
4709    try:
4710        ad.log.info("User data enabled for sub_id %s: %s", sub_id,
4711                    ad.droid.telephonyIsDataEnabledForSubscription(sub_id))
4712        data_state = ad.droid.telephonyGetDataConnectionState()
4713        ad.log.info("Data connection state is %s", data_state)
4714        ad.log.info("Network is connected: %s",
4715                    ad.droid.connectivityNetworkIsConnected())
4716        if data_state == state_str:
4717            return _wait_for_nw_data_connection(
4718                log, ad, state, NETWORK_CONNECTION_TYPE_CELL, timeout_value)
4719
4720        try:
4721            ad.ed.wait_for_event(
4722                EventDataConnectionStateChanged,
4723                is_event_match,
4724                timeout=timeout_value,
4725                field=DataConnectionStateContainer.DATA_CONNECTION_STATE,
4726                value=state_str)
4727        except Empty:
4728            ad.log.info("No expected event EventDataConnectionStateChanged %s",
4729                        state_str)
4730
4731        # TODO: Wait for <MAX_WAIT_TIME_CONNECTION_STATE_UPDATE> seconds for
4732        # data connection state.
4733        # Otherwise, the network state will not be correct.
4734        # The bug is tracked here: b/20921915
4735
4736        # Previously we use _is_data_connection_state_match,
4737        # but telephonyGetDataConnectionState sometimes return wrong value.
4738        # The bug is tracked here: b/22612607
4739        # So we use _is_network_connected_state_match.
4740
4741        if _wait_for_droid_in_state(log, ad, timeout_value,
4742                                    _is_network_connected_state_match, state):
4743            return _wait_for_nw_data_connection(
4744                log, ad, state, NETWORK_CONNECTION_TYPE_CELL, timeout_value)
4745        else:
4746            return False
4747
4748    finally:
4749        ad.droid.telephonyStopTrackingDataConnectionStateChangeForSubscription(
4750            sub_id)
4751
4752
4753def wait_for_wifi_data_connection(
4754        log, ad, state, timeout_value=MAX_WAIT_TIME_CONNECTION_STATE_UPDATE):
4755    """Wait for data connection status to be expected value and connection is by WiFi.
4756
4757    Args:
4758        log: Log object.
4759        ad: Android Device Object.
4760        state: Expected status: True or False.
4761            If True, it will wait for status to be DATA_STATE_CONNECTED.
4762            If False, it will wait for status ti be DATA_STATE_DISCONNECTED.
4763        timeout_value: wait for network data timeout value.
4764            This is optional, default value is MAX_WAIT_TIME_NW_SELECTION
4765
4766    Returns:
4767        True if success.
4768        False if failed.
4769    """
4770    ad.log.info("wait_for_wifi_data_connection")
4771    return _wait_for_nw_data_connection(
4772        log, ad, state, NETWORK_CONNECTION_TYPE_WIFI, timeout_value)
4773
4774
4775def wait_for_data_connection(
4776        log, ad, state, timeout_value=MAX_WAIT_TIME_CONNECTION_STATE_UPDATE):
4777    """Wait for data connection status to be expected value.
4778
4779    Wait for the data connection status to be DATA_STATE_CONNECTED
4780        or DATA_STATE_DISCONNECTED.
4781
4782    Args:
4783        log: Log object.
4784        ad: Android Device Object.
4785        state: Expected status: True or False.
4786            If True, it will wait for status to be DATA_STATE_CONNECTED.
4787            If False, it will wait for status ti be DATA_STATE_DISCONNECTED.
4788        timeout_value: wait for network data timeout value.
4789            This is optional, default value is MAX_WAIT_TIME_CONNECTION_STATE_UPDATE
4790
4791    Returns:
4792        True if success.
4793        False if failed.
4794    """
4795    return _wait_for_nw_data_connection(log, ad, state, None, timeout_value)
4796
4797
4798def _wait_for_nw_data_connection(
4799        log,
4800        ad,
4801        is_connected,
4802        connection_type=None,
4803        timeout_value=MAX_WAIT_TIME_CONNECTION_STATE_UPDATE):
4804    """Wait for data connection status to be expected value.
4805
4806    Wait for the data connection status to be DATA_STATE_CONNECTED
4807        or DATA_STATE_DISCONNECTED.
4808
4809    Args:
4810        log: Log object.
4811        ad: Android Device Object.
4812        is_connected: Expected connection status: True or False.
4813            If True, it will wait for status to be DATA_STATE_CONNECTED.
4814            If False, it will wait for status ti be DATA_STATE_DISCONNECTED.
4815        connection_type: expected connection type.
4816            This is optional, if it is None, then any connection type will return True.
4817        timeout_value: wait for network data timeout value.
4818            This is optional, default value is MAX_WAIT_TIME_CONNECTION_STATE_UPDATE
4819
4820    Returns:
4821        True if success.
4822        False if failed.
4823    """
4824    ad.ed.clear_events(EventConnectivityChanged)
4825    ad.droid.connectivityStartTrackingConnectivityStateChange()
4826    try:
4827        cur_data_connection_state = ad.droid.connectivityNetworkIsConnected()
4828        if is_connected == cur_data_connection_state:
4829            current_type = get_internet_connection_type(log, ad)
4830            ad.log.info("current data connection type: %s", current_type)
4831            if not connection_type:
4832                return True
4833            else:
4834                if not is_connected and current_type != connection_type:
4835                    ad.log.info("data connection not on %s!", connection_type)
4836                    return True
4837                elif is_connected and current_type == connection_type:
4838                    ad.log.info("data connection on %s as expected",
4839                                connection_type)
4840                    return True
4841        else:
4842            ad.log.info("current data connection state: %s target: %s",
4843                        cur_data_connection_state, is_connected)
4844
4845        try:
4846            event = ad.ed.wait_for_event(
4847                EventConnectivityChanged, _connection_state_change,
4848                timeout_value, is_connected, connection_type)
4849            ad.log.info("Got event: %s", event)
4850        except Empty:
4851            pass
4852
4853        log.info(
4854            "_wait_for_nw_data_connection: check connection after wait event.")
4855        # TODO: Wait for <MAX_WAIT_TIME_CONNECTION_STATE_UPDATE> seconds for
4856        # data connection state.
4857        # Otherwise, the network state will not be correct.
4858        # The bug is tracked here: b/20921915
4859        if _wait_for_droid_in_state(log, ad, timeout_value,
4860                                    _is_network_connected_state_match,
4861                                    is_connected):
4862            current_type = get_internet_connection_type(log, ad)
4863            ad.log.info("current data connection type: %s", current_type)
4864            if not connection_type:
4865                return True
4866            else:
4867                if not is_connected and current_type != connection_type:
4868                    ad.log.info("data connection not on %s", connection_type)
4869                    return True
4870                elif is_connected and current_type == connection_type:
4871                    ad.log.info("after event wait, data connection on %s",
4872                                connection_type)
4873                    return True
4874                else:
4875                    return False
4876        else:
4877            return False
4878    except Exception as e:
4879        ad.log.error("Exception error %s", str(e))
4880        return False
4881    finally:
4882        ad.droid.connectivityStopTrackingConnectivityStateChange()
4883
4884
4885def get_cell_data_roaming_state_by_adb(ad):
4886    """Get Cell Data Roaming state. True for enabled, False for disabled"""
4887    state_mapping = {"1": True, "0": False}
4888    return state_mapping[ad.adb.shell("settings get global data_roaming")]
4889
4890
4891def set_cell_data_roaming_state_by_adb(ad, state):
4892    """Set Cell Data Roaming state."""
4893    state_mapping = {True: "1", False: "0"}
4894    ad.log.info("Set data roaming to %s", state)
4895    ad.adb.shell("settings put global data_roaming %s" % state_mapping[state])
4896
4897
4898def toggle_cell_data_roaming(ad, state):
4899    """Enable cell data roaming for default data subscription.
4900
4901    Wait for the data roaming status to be DATA_STATE_CONNECTED
4902        or DATA_STATE_DISCONNECTED.
4903
4904    Args:
4905        log: Log object.
4906        ad: Android Device Object.
4907        state: True or False for enable or disable cell data roaming.
4908
4909    Returns:
4910        True if success.
4911        False if failed.
4912    """
4913    state_int = {True: DATA_ROAMING_ENABLE, False: DATA_ROAMING_DISABLE}[state]
4914    action_str = {True: "Enable", False: "Disable"}[state]
4915    if ad.droid.connectivityCheckDataRoamingMode() == state:
4916        ad.log.info("Data roaming is already in state %s", state)
4917        return True
4918    if not ad.droid.connectivitySetDataRoaming(state_int):
4919        ad.error.info("Fail to config data roaming into state %s", state)
4920        return False
4921    if ad.droid.connectivityCheckDataRoamingMode() == state:
4922        ad.log.info("Data roaming is configured into state %s", state)
4923        return True
4924    else:
4925        ad.log.error("Data roaming is not configured into state %s", state)
4926        return False
4927
4928
4929def verify_incall_state(log, ads, expected_status):
4930    """Verify phones in incall state or not.
4931
4932    Verify if all phones in the array <ads> are in <expected_status>.
4933
4934    Args:
4935        log: Log object.
4936        ads: Array of Android Device Object. All droid in this array will be tested.
4937        expected_status: If True, verify all Phones in incall state.
4938            If False, verify all Phones not in incall state.
4939
4940    """
4941    result = True
4942    for ad in ads:
4943        if ad.droid.telecomIsInCall() is not expected_status:
4944            ad.log.error("InCall status:%s, expected:%s",
4945                         ad.droid.telecomIsInCall(), expected_status)
4946            result = False
4947    return result
4948
4949
4950def verify_active_call_number(log, ad, expected_number):
4951    """Verify the number of current active call.
4952
4953    Verify if the number of current active call in <ad> is
4954        equal to <expected_number>.
4955
4956    Args:
4957        ad: Android Device Object.
4958        expected_number: Expected active call number.
4959    """
4960    calls = ad.droid.telecomCallGetCallIds()
4961    if calls is None:
4962        actual_number = 0
4963    else:
4964        actual_number = len(calls)
4965    if actual_number != expected_number:
4966        ad.log.error("Active Call number is %s, expecting", actual_number,
4967                     expected_number)
4968        return False
4969    return True
4970
4971
4972def num_active_calls(log, ad):
4973    """Get the count of current active calls.
4974
4975    Args:
4976        log: Log object.
4977        ad: Android Device Object.
4978
4979    Returns:
4980        Count of current active calls.
4981    """
4982    calls = ad.droid.telecomCallGetCallIds()
4983    return len(calls) if calls else 0
4984
4985
4986def show_enhanced_4g_lte(ad, sub_id):
4987    result = True
4988    capabilities = ad.telephony["subscription"][sub_id].get("capabilities", [])
4989    if capabilities:
4990        if "hide_enhanced_4g_lte" in capabilities:
4991            result = False
4992            ad.log.info(
4993                '"Enhanced 4G LTE MODE" is hidden for sub ID %s.', sub_id)
4994            show_enhanced_4g_lte_mode = getattr(
4995                ad, "show_enhanced_4g_lte_mode", False)
4996            if show_enhanced_4g_lte_mode in ["true", "True"]:
4997                current_voice_sub_id = get_outgoing_voice_sub_id(ad)
4998                if sub_id != current_voice_sub_id:
4999                    set_incoming_voice_sub_id(ad, sub_id)
5000
5001                ad.log.info(
5002                    'Show "Enhanced 4G LTE MODE" forcibly for sub ID %s.',
5003                    sub_id)
5004                ad.adb.shell(
5005                    "am broadcast \
5006                        -a com.google.android.carrier.action.LOCAL_OVERRIDE \
5007                        -n com.google.android.carrier/.ConfigOverridingReceiver \
5008                        --ez hide_enhanced_4g_lte_bool false")
5009                ad.telephony["subscription"][sub_id]["capabilities"].remove(
5010                    "hide_enhanced_4g_lte")
5011
5012                if sub_id != current_voice_sub_id:
5013                    set_incoming_voice_sub_id(ad, current_voice_sub_id)
5014
5015                result = True
5016    return result
5017
5018
5019def toggle_volte(log, ad, new_state=None):
5020    """Toggle enable/disable VoLTE for default voice subscription.
5021
5022    Args:
5023        ad: Android device object.
5024        new_state: VoLTE mode state to set to.
5025            True for enable, False for disable.
5026            If None, opposite of the current state.
5027
5028    Raises:
5029        TelTestUtilsError if platform does not support VoLTE.
5030    """
5031    return toggle_volte_for_subscription(
5032        log, ad, get_outgoing_voice_sub_id(ad), new_state)
5033
5034
5035def toggle_volte_for_subscription(log, ad, sub_id, new_state=None):
5036    """Toggle enable/disable VoLTE for specified voice subscription.
5037
5038    Args:
5039        ad: Android device object.
5040        sub_id: Optional. If not assigned the default sub ID for voice call will
5041            be used.
5042        new_state: VoLTE mode state to set to.
5043            True for enable, False for disable.
5044            If None, opposite of the current state.
5045
5046    """
5047    if not show_enhanced_4g_lte(ad, sub_id):
5048        return False
5049
5050    current_state = None
5051    result = True
5052
5053    if sub_id is None:
5054        sub_id = ad.droid.subscriptionGetDefaultVoiceSubId()
5055
5056    try:
5057        current_state = ad.droid.imsMmTelIsAdvancedCallingEnabled(sub_id)
5058    except Exception as e:
5059        ad.log.warning(e)
5060
5061    if current_state is not None:
5062        if new_state is None:
5063            new_state = not current_state
5064        if new_state != current_state:
5065            ad.log.info(
5066                "Toggle Enhanced 4G LTE Mode from %s to %s on sub_id %s",
5067                current_state, new_state, sub_id)
5068            ad.droid.imsMmTelSetAdvancedCallingEnabled(sub_id, new_state)
5069        check_state = ad.droid.imsMmTelIsAdvancedCallingEnabled(sub_id)
5070        if check_state != new_state:
5071            ad.log.error("Failed to toggle Enhanced 4G LTE Mode to %s, still \
5072                set to %s on sub_id %s", new_state, check_state, sub_id)
5073            result = False
5074        return result
5075    else:
5076        # TODO: b/26293960 No framework API available to set IMS by SubId.
5077        voice_sub_id_changed = False
5078        current_sub_id = get_incoming_voice_sub_id(ad)
5079        if current_sub_id != sub_id:
5080            set_incoming_voice_sub_id(ad, sub_id)
5081            voice_sub_id_changed = True
5082
5083        # b/139641554
5084        ad.terminate_all_sessions()
5085        bring_up_sl4a(ad)
5086
5087        if not ad.droid.imsIsEnhanced4gLteModeSettingEnabledByPlatform():
5088            ad.log.info(
5089                "Enhanced 4G Lte Mode Setting is not enabled by platform for \
5090                    sub ID %s.", sub_id)
5091            return False
5092
5093        current_state = ad.droid.imsIsEnhanced4gLteModeSettingEnabledByUser()
5094        ad.log.info("Current state of Enhanced 4G Lte Mode Setting for sub \
5095            ID %s: %s", sub_id, current_state)
5096        ad.log.info("New desired state of Enhanced 4G Lte Mode Setting for sub \
5097            ID %s: %s", sub_id, new_state)
5098
5099        if new_state is None:
5100            new_state = not current_state
5101        if new_state != current_state:
5102            ad.log.info(
5103                "Toggle Enhanced 4G LTE Mode from %s to %s for sub ID %s.",
5104                current_state, new_state, sub_id)
5105            ad.droid.imsSetEnhanced4gMode(new_state)
5106            time.sleep(5)
5107
5108        check_state = ad.droid.imsIsEnhanced4gLteModeSettingEnabledByUser()
5109        if check_state != new_state:
5110            ad.log.error("Failed to toggle Enhanced 4G LTE Mode to %s, \
5111                still set to %s on sub_id %s", new_state, check_state, sub_id)
5112            result = False
5113
5114        if voice_sub_id_changed:
5115            set_incoming_voice_sub_id(ad, current_sub_id)
5116
5117        return result
5118
5119
5120def toggle_wfc(log, ad, new_state=None):
5121    """ Toggle WFC enable/disable
5122
5123    Args:
5124        log: Log object
5125        ad: Android device object.
5126        new_state: WFC state to set to.
5127            True for enable, False for disable.
5128            If None, opposite of the current state.
5129    """
5130    return toggle_wfc_for_subscription(
5131        log, ad, new_state, get_outgoing_voice_sub_id(ad))
5132
5133
5134def toggle_wfc_for_subscription(log, ad, new_state=None, sub_id=None):
5135    """ Toggle WFC enable/disable for specified voice subscription.
5136
5137    Args:
5138        ad: Android device object.
5139        sub_id: Optional. If not assigned the default sub ID for voice call will
5140            be used.
5141        new_state: WFC state to set to.
5142            True for enable, False for disable.
5143            If None, opposite of the current state.
5144    """
5145    current_state = None
5146    result = True
5147
5148    if sub_id is None:
5149        sub_id = ad.droid.subscriptionGetDefaultVoiceSubId()
5150
5151    try:
5152        current_state = ad.droid.imsMmTelIsVoWiFiSettingEnabled(sub_id)
5153    except Exception as e:
5154        ad.log.warning(e)
5155
5156    if current_state is not None:
5157        if new_state is None:
5158            new_state = not current_state
5159        if new_state != current_state:
5160            ad.log.info(
5161                "Toggle Wi-Fi calling from %s to %s on sub_id %s",
5162                current_state, new_state, sub_id)
5163            ad.droid.imsMmTelSetVoWiFiSettingEnabled(sub_id, new_state)
5164        check_state = ad.droid.imsMmTelIsVoWiFiSettingEnabled(sub_id)
5165        if check_state != new_state:
5166            ad.log.error("Failed to toggle Wi-Fi calling to %s, \
5167                still set to %s on sub_id %s", new_state, check_state, sub_id)
5168            result = False
5169        return result
5170    else:
5171        voice_sub_id_changed = False
5172        if not sub_id:
5173            sub_id = get_outgoing_voice_sub_id(ad)
5174        else:
5175            current_sub_id = get_incoming_voice_sub_id(ad)
5176            if current_sub_id != sub_id:
5177                set_incoming_voice_sub_id(ad, sub_id)
5178                voice_sub_id_changed = True
5179
5180        # b/139641554
5181        ad.terminate_all_sessions()
5182        bring_up_sl4a(ad)
5183
5184        if not ad.droid.imsIsWfcEnabledByPlatform():
5185            ad.log.info("WFC is not enabled by platform for sub ID %s.", sub_id)
5186            return False
5187
5188        current_state = ad.droid.imsIsWfcEnabledByUser()
5189        ad.log.info("Current state of WFC Setting for sub ID %s: %s",
5190            sub_id, current_state)
5191        ad.log.info("New desired state of WFC Setting for sub ID %s: %s",
5192            sub_id, new_state)
5193
5194        if new_state is None:
5195            new_state = not current_state
5196        if new_state != current_state:
5197            ad.log.info("Toggle WFC user enabled from %s to %s for sub ID %s",
5198                current_state, new_state, sub_id)
5199            ad.droid.imsSetWfcSetting(new_state)
5200
5201        if voice_sub_id_changed:
5202            set_incoming_voice_sub_id(ad, current_sub_id)
5203
5204        return True
5205
5206
5207def is_enhanced_4g_lte_mode_setting_enabled(ad, sub_id, enabled_by="platform"):
5208    voice_sub_id_changed = False
5209    current_sub_id = get_incoming_voice_sub_id(ad)
5210    if current_sub_id != sub_id:
5211        set_incoming_voice_sub_id(ad, sub_id)
5212        voice_sub_id_changed = True
5213    if enabled_by == "platform":
5214        res = ad.droid.imsIsEnhanced4gLteModeSettingEnabledByPlatform()
5215    else:
5216        res = ad.droid.imsIsEnhanced4gLteModeSettingEnabledByUser()
5217    if not res:
5218        ad.log.info("Enhanced 4G Lte Mode Setting is NOT enabled by %s for sub \
5219            ID %s.", enabled_by, sub_id)
5220        if voice_sub_id_changed:
5221            set_incoming_voice_sub_id(ad, current_sub_id)
5222        return False
5223    if voice_sub_id_changed:
5224        set_incoming_voice_sub_id(ad, current_sub_id)
5225    ad.log.info("Enhanced 4G Lte Mode Setting is enabled by %s for sub ID %s.",
5226        enabled_by, sub_id)
5227    return True
5228
5229def set_enhanced_4g_mode(ad, sub_id, state):
5230    voice_sub_id_changed = False
5231    current_sub_id = get_incoming_voice_sub_id(ad)
5232    if current_sub_id != sub_id:
5233        set_incoming_voice_sub_id(ad, sub_id)
5234        voice_sub_id_changed = True
5235
5236    ad.droid.imsSetEnhanced4gMode(state)
5237    time.sleep(5)
5238
5239    if voice_sub_id_changed:
5240        set_incoming_voice_sub_id(ad, current_sub_id)
5241
5242
5243def wait_for_enhanced_4g_lte_setting(log,
5244                                     ad,
5245                                     sub_id,
5246                                     max_time=MAX_WAIT_TIME_FOR_STATE_CHANGE):
5247    """Wait for android device to enable enhance 4G LTE setting.
5248
5249    Args:
5250        log: log object.
5251        ad:  android device.
5252        max_time: maximal wait time.
5253
5254    Returns:
5255        Return True if device report VoLTE enabled bit true within max_time.
5256        Return False if timeout.
5257    """
5258    return wait_for_state(
5259        is_enhanced_4g_lte_mode_setting_enabled,
5260        True,
5261        max_time,
5262        WAIT_TIME_BETWEEN_STATE_CHECK,
5263        ad,
5264        sub_id,
5265        enabled_by="platform")
5266
5267
5268def set_wfc_mode(log, ad, wfc_mode):
5269    """Set WFC enable/disable and mode.
5270
5271    Args:
5272        log: Log object
5273        ad: Android device object.
5274        wfc_mode: WFC mode to set to.
5275            Valid mode includes: WFC_MODE_WIFI_ONLY, WFC_MODE_CELLULAR_PREFERRED,
5276            WFC_MODE_WIFI_PREFERRED, WFC_MODE_DISABLED.
5277
5278    Returns:
5279        True if success. False if ad does not support WFC or error happened.
5280    """
5281    return set_wfc_mode_for_subscription(
5282        ad, wfc_mode, get_outgoing_voice_sub_id(ad))
5283
5284
5285def set_wfc_mode_for_subscription(ad, wfc_mode, sub_id=None):
5286    """Set WFC enable/disable and mode subscription based
5287
5288    Args:
5289        ad: Android device object.
5290        wfc_mode: WFC mode to set to.
5291            Valid mode includes: WFC_MODE_WIFI_ONLY, WFC_MODE_CELLULAR_PREFERRED,
5292            WFC_MODE_WIFI_PREFERRED.
5293        sub_id: subscription Id
5294
5295    Returns:
5296        True if success. False if ad does not support WFC or error happened.
5297    """
5298    if wfc_mode not in [
5299        WFC_MODE_WIFI_ONLY,
5300        WFC_MODE_CELLULAR_PREFERRED,
5301        WFC_MODE_WIFI_PREFERRED,
5302        WFC_MODE_DISABLED]:
5303
5304        ad.log.error("Given WFC mode (%s) is not correct.", wfc_mode)
5305        return False
5306
5307    current_mode = None
5308    result = True
5309
5310    if sub_id is None:
5311        sub_id = ad.droid.subscriptionGetDefaultVoiceSubId()
5312
5313    try:
5314        current_mode = ad.droid.imsMmTelGetVoWiFiModeSetting(sub_id)
5315        ad.log.info("Current WFC mode of sub ID %s: %s", sub_id, current_mode)
5316    except Exception as e:
5317        ad.log.warning(e)
5318
5319    if current_mode is not None:
5320        try:
5321            if not ad.droid.imsMmTelIsVoWiFiSettingEnabled(sub_id):
5322                if wfc_mode is WFC_MODE_DISABLED:
5323                    ad.log.info("WFC is already disabled.")
5324                    return True
5325                ad.log.info(
5326                    "WFC is disabled for sub ID %s. Enabling WFC...", sub_id)
5327                ad.droid.imsMmTelSetVoWiFiSettingEnabled(sub_id, True)
5328
5329            if wfc_mode is WFC_MODE_DISABLED:
5330                ad.log.info(
5331                    "WFC is enabled for sub ID %s. Disabling WFC...", sub_id)
5332                ad.droid.imsMmTelSetVoWiFiSettingEnabled(sub_id, False)
5333                return True
5334
5335            ad.log.info("Set wfc mode to %s for sub ID %s.", wfc_mode, sub_id)
5336            ad.droid.imsMmTelSetVoWiFiModeSetting(sub_id, wfc_mode)
5337            mode = ad.droid.imsMmTelGetVoWiFiModeSetting(sub_id)
5338            if mode != wfc_mode:
5339                ad.log.error("WFC mode for sub ID %s is %s, not in %s",
5340                    sub_id, mode, wfc_mode)
5341                return False
5342        except Exception as e:
5343            ad.log.error(e)
5344            return False
5345        return True
5346    else:
5347        voice_sub_id_changed = False
5348        if not sub_id:
5349            sub_id = get_outgoing_voice_sub_id(ad)
5350        else:
5351            current_sub_id = get_incoming_voice_sub_id(ad)
5352            if current_sub_id != sub_id:
5353                set_incoming_voice_sub_id(ad, sub_id)
5354                voice_sub_id_changed = True
5355
5356        # b/139641554
5357        ad.terminate_all_sessions()
5358        bring_up_sl4a(ad)
5359
5360        if wfc_mode != WFC_MODE_DISABLED and wfc_mode not in ad.telephony[
5361            "subscription"][get_outgoing_voice_sub_id(ad)].get("wfc_modes", []):
5362            ad.log.error("WFC mode %s is not supported", wfc_mode)
5363            raise signals.TestSkip("WFC mode %s is not supported" % wfc_mode)
5364        try:
5365            ad.log.info("Set wfc mode to %s", wfc_mode)
5366            if wfc_mode != WFC_MODE_DISABLED:
5367                start_adb_tcpdump(ad, interface="wlan0", mask="all")
5368            if not ad.droid.imsIsWfcEnabledByPlatform():
5369                if wfc_mode == WFC_MODE_DISABLED:
5370                    if voice_sub_id_changed:
5371                        set_incoming_voice_sub_id(ad, current_sub_id)
5372                    return True
5373                else:
5374                    ad.log.error("WFC not supported by platform.")
5375                    if voice_sub_id_changed:
5376                        set_incoming_voice_sub_id(ad, current_sub_id)
5377                    return False
5378            ad.droid.imsSetWfcMode(wfc_mode)
5379            mode = ad.droid.imsGetWfcMode()
5380            if voice_sub_id_changed:
5381                set_incoming_voice_sub_id(ad, current_sub_id)
5382            if mode != wfc_mode:
5383                ad.log.error("WFC mode is %s, not in %s", mode, wfc_mode)
5384                return False
5385        except Exception as e:
5386            log.error(e)
5387            if voice_sub_id_changed:
5388                set_incoming_voice_sub_id(ad, current_sub_id)
5389            return False
5390        return True
5391
5392
5393def set_ims_provisioning_for_subscription(ad, feature_flag, value, sub_id=None):
5394    """ Sets Provisioning Values for Subscription Id
5395
5396    Args:
5397        ad: Android device object.
5398        sub_id: Subscription Id
5399        feature_flag: voice or video
5400        value: enable or disable
5401
5402    """
5403    try:
5404        if sub_id is None:
5405            sub_id = ad.droid.subscriptionGetDefaultVoiceSubId()
5406        ad.log.info("SubId %s - setprovisioning for %s to %s",
5407                    sub_id, feature_flag, value)
5408        result = ad.droid.provisioningSetProvisioningIntValue(sub_id,
5409                    feature_flag, value)
5410        if result == 0:
5411            return True
5412        return False
5413    except Exception as e:
5414        ad.log.error(e)
5415        return False
5416
5417
5418def get_ims_provisioning_for_subscription(ad, feature_flag, tech, sub_id=None):
5419    """ Gets Provisioning Values for Subscription Id
5420
5421    Args:
5422        ad: Android device object.
5423        sub_id: Subscription Id
5424        feature_flag: voice, video, ut, sms
5425        tech: lte, iwlan
5426
5427    """
5428    try:
5429        if sub_id is None:
5430            sub_id = ad.droid.subscriptionGetDefaultVoiceSubId()
5431        result = ad.droid.provisioningGetProvisioningStatusForCapability(
5432                    sub_id, feature_flag, tech)
5433        ad.log.info("SubId %s - getprovisioning for %s on %s - %s",
5434                    sub_id, feature_flag, tech, result)
5435        return result
5436    except Exception as e:
5437        ad.log.error(e)
5438        return False
5439
5440
5441def get_carrier_provisioning_for_subscription(ad, feature_flag,
5442                                              tech, sub_id=None):
5443    """ Gets Provisioning Values for Subscription Id
5444
5445    Args:
5446        ad: Android device object.
5447        sub_id: Subscription Id
5448        feature_flag: voice, video, ut, sms
5449        tech: wlan, wwan
5450
5451    """
5452    try:
5453        if sub_id is None:
5454            sub_id = ad.droid.subscriptionGetDefaultVoiceSubId()
5455        result = ad.droid.imsMmTelIsSupported(sub_id, feature_flag, tech)
5456        ad.log.info("SubId %s - imsMmTelIsSupported for %s on %s - %s",
5457                    sub_id, feature_flag, tech, result)
5458        return result
5459    except Exception as e:
5460        ad.log.error(e)
5461        return False
5462
5463
5464def activate_wfc_on_device(log, ad):
5465    """ Activates WiFi calling on device.
5466
5467        Required for certain network operators.
5468
5469    Args:
5470        log: Log object
5471        ad: Android device object
5472
5473    """
5474    activate_wfc_on_device_for_subscription(log, ad,
5475                                            ad.droid.subscriptionGetDefaultSubId())
5476
5477
5478def activate_wfc_on_device_for_subscription(log, ad, sub_id):
5479    """ Activates WiFi calling on device for a subscription.
5480
5481    Args:
5482        log: Log object
5483        ad: Android device object
5484        sub_id: Subscription id (integer)
5485
5486    """
5487    if not sub_id or INVALID_SUB_ID == sub_id:
5488        ad.log.error("Subscription id invalid")
5489        return
5490    operator_name = get_operator_name(log, ad, sub_id)
5491    if operator_name in (CARRIER_VZW, CARRIER_ATT, CARRIER_BELL, CARRIER_ROGERS,
5492                         CARRIER_TELUS, CARRIER_KOODO, CARRIER_VIDEOTRON, CARRIER_FRE):
5493        ad.log.info("Activating WFC on operator : %s", operator_name)
5494        if not ad.is_apk_installed("com.google.android.wfcactivation"):
5495            ad.log.error("WFC Activation Failed, wfc activation apk not installed")
5496            return
5497        wfc_activate_cmd ="am start --ei EXTRA_LAUNCH_CARRIER_APP 0 --ei " \
5498                    "android.telephony.extra.SUBSCRIPTION_INDEX {} -n ".format(sub_id)
5499        if CARRIER_ATT == operator_name:
5500            ad.adb.shell("setprop dbg.att.force_wfc_nv_enabled true")
5501            wfc_activate_cmd = wfc_activate_cmd+\
5502                               "\"com.google.android.wfcactivation/" \
5503                               ".WfcActivationActivity\""
5504        elif CARRIER_VZW == operator_name:
5505            ad.adb.shell("setprop dbg.vzw.force_wfc_nv_enabled true")
5506            wfc_activate_cmd = wfc_activate_cmd + \
5507                               "\"com.google.android.wfcactivation/" \
5508                               ".VzwEmergencyAddressActivity\""
5509        else:
5510            wfc_activate_cmd = wfc_activate_cmd+ \
5511                               "\"com.google.android.wfcactivation/" \
5512                               ".can.WfcActivationCanadaActivity\""
5513        ad.adb.shell(wfc_activate_cmd)
5514
5515
5516def toggle_video_calling(log, ad, new_state=None):
5517    """Toggle enable/disable Video calling for default voice subscription.
5518
5519    Args:
5520        ad: Android device object.
5521        new_state: Video mode state to set to.
5522            True for enable, False for disable.
5523            If None, opposite of the current state.
5524
5525    Raises:
5526        TelTestUtilsError if platform does not support Video calling.
5527    """
5528    if not ad.droid.imsIsVtEnabledByPlatform():
5529        if new_state is not False:
5530            raise TelTestUtilsError("VT not supported by platform.")
5531        # if the user sets VT false and it's unavailable we just let it go
5532        return False
5533
5534    current_state = ad.droid.imsIsVtEnabledByUser()
5535    if new_state is None:
5536        new_state = not current_state
5537    if new_state != current_state:
5538        ad.droid.imsSetVtSetting(new_state)
5539    return True
5540
5541
5542def toggle_video_calling_for_subscription(ad, new_state=None, sub_id=None):
5543    """Toggle enable/disable Video calling for subscription.
5544
5545    Args:
5546        ad: Android device object.
5547        new_state: Video mode state to set to.
5548            True for enable, False for disable.
5549            If None, opposite of the current state.
5550        sub_id: subscription Id
5551
5552    """
5553    try:
5554        if sub_id is None:
5555            sub_id = ad.droid.subscriptionGetDefaultVoiceSubId()
5556        current_state = ad.droid.imsMmTelIsVtSettingEnabled(sub_id)
5557        if new_state is None:
5558            new_state = not current_state
5559        if new_state != current_state:
5560            ad.log.info("SubId %s - Toggle VT from %s to %s", sub_id,
5561                        current_state, new_state)
5562            ad.droid.imsMmTelSetVtSettingEnabled(sub_id, new_state)
5563    except Exception as e:
5564        ad.log.error(e)
5565        return False
5566    return True
5567
5568
5569def _wait_for_droid_in_state(log, ad, max_time, state_check_func, *args,
5570                             **kwargs):
5571    while max_time >= 0:
5572        if state_check_func(log, ad, *args, **kwargs):
5573            return True
5574
5575        time.sleep(WAIT_TIME_BETWEEN_STATE_CHECK)
5576        max_time -= WAIT_TIME_BETWEEN_STATE_CHECK
5577
5578    return False
5579
5580
5581def _wait_for_droid_in_state_for_subscription(
5582        log, ad, sub_id, max_time, state_check_func, *args, **kwargs):
5583    while max_time >= 0:
5584        if state_check_func(log, ad, sub_id, *args, **kwargs):
5585            return True
5586
5587        time.sleep(WAIT_TIME_BETWEEN_STATE_CHECK)
5588        max_time -= WAIT_TIME_BETWEEN_STATE_CHECK
5589
5590    return False
5591
5592
5593def _wait_for_droids_in_state(log, ads, max_time, state_check_func, *args,
5594                              **kwargs):
5595    while max_time > 0:
5596        success = True
5597        for ad in ads:
5598            if not state_check_func(log, ad, *args, **kwargs):
5599                success = False
5600                break
5601        if success:
5602            return True
5603
5604        time.sleep(WAIT_TIME_BETWEEN_STATE_CHECK)
5605        max_time -= WAIT_TIME_BETWEEN_STATE_CHECK
5606
5607    return False
5608
5609
5610def is_phone_in_call(log, ad):
5611    """Return True if phone in call.
5612
5613    Args:
5614        log: log object.
5615        ad:  android device.
5616    """
5617    try:
5618        return ad.droid.telecomIsInCall()
5619    except:
5620        return "mCallState=2" in ad.adb.shell(
5621            "dumpsys telephony.registry | grep mCallState")
5622
5623
5624def is_phone_not_in_call(log, ad):
5625    """Return True if phone not in call.
5626
5627    Args:
5628        log: log object.
5629        ad:  android device.
5630    """
5631    in_call = ad.droid.telecomIsInCall()
5632    call_state = ad.droid.telephonyGetCallState()
5633    if in_call:
5634        ad.log.info("Device is In Call")
5635    if call_state != TELEPHONY_STATE_IDLE:
5636        ad.log.info("Call_state is %s, not %s", call_state,
5637                    TELEPHONY_STATE_IDLE)
5638    return ((not in_call) and (call_state == TELEPHONY_STATE_IDLE))
5639
5640
5641def wait_for_droid_in_call(log, ad, max_time):
5642    """Wait for android to be in call state.
5643
5644    Args:
5645        log: log object.
5646        ad:  android device.
5647        max_time: maximal wait time.
5648
5649    Returns:
5650        If phone become in call state within max_time, return True.
5651        Return False if timeout.
5652    """
5653    return _wait_for_droid_in_state(log, ad, max_time, is_phone_in_call)
5654
5655
5656def is_phone_in_call_active(ad, call_id=None):
5657    """Return True if phone in active call.
5658
5659    Args:
5660        log: log object.
5661        ad:  android device.
5662        call_id: the call id
5663    """
5664    if ad.droid.telecomIsInCall():
5665        if not call_id:
5666            call_id = ad.droid.telecomCallGetCallIds()[0]
5667        call_state = ad.droid.telecomCallGetCallState(call_id)
5668        ad.log.info("%s state is %s", call_id, call_state)
5669        return call_state == "ACTIVE"
5670    else:
5671        ad.log.info("Not in telecomIsInCall")
5672        return False
5673
5674
5675def wait_for_in_call_active(ad,
5676                            timeout=MAX_WAIT_TIME_ACCEPT_CALL_TO_OFFHOOK_EVENT,
5677                            interval=WAIT_TIME_BETWEEN_STATE_CHECK,
5678                            call_id=None):
5679    """Wait for call reach active state.
5680
5681    Args:
5682        log: log object.
5683        ad:  android device.
5684        call_id: the call id
5685    """
5686    if not call_id:
5687        call_id = ad.droid.telecomCallGetCallIds()[0]
5688    args = [ad, call_id]
5689    if not wait_for_state(is_phone_in_call_active, True, timeout, interval,
5690                          *args):
5691        ad.log.error("Call did not reach ACTIVE state")
5692        return False
5693    else:
5694        return True
5695
5696
5697def wait_for_telecom_ringing(log, ad, max_time=MAX_WAIT_TIME_TELECOM_RINGING):
5698    """Wait for android to be in telecom ringing state.
5699
5700    Args:
5701        log: log object.
5702        ad:  android device.
5703        max_time: maximal wait time. This is optional.
5704            Default Value is MAX_WAIT_TIME_TELECOM_RINGING.
5705
5706    Returns:
5707        If phone become in telecom ringing state within max_time, return True.
5708        Return False if timeout.
5709    """
5710    return _wait_for_droid_in_state(
5711        log, ad, max_time, lambda log, ad: ad.droid.telecomIsRinging())
5712
5713
5714def wait_for_droid_not_in_call(log, ad, max_time=MAX_WAIT_TIME_CALL_DROP):
5715    """Wait for android to be not in call state.
5716
5717    Args:
5718        log: log object.
5719        ad:  android device.
5720        max_time: maximal wait time.
5721
5722    Returns:
5723        If phone become not in call state within max_time, return True.
5724        Return False if timeout.
5725    """
5726    return _wait_for_droid_in_state(log, ad, max_time, is_phone_not_in_call)
5727
5728
5729def _is_attached(log, ad, voice_or_data):
5730    return _is_attached_for_subscription(
5731        log, ad, ad.droid.subscriptionGetDefaultSubId(), voice_or_data)
5732
5733
5734def _is_attached_for_subscription(log, ad, sub_id, voice_or_data):
5735    rat = get_network_rat_for_subscription(log, ad, sub_id, voice_or_data)
5736    ad.log.info("Sub_id %s network RAT is %s for %s", sub_id, rat,
5737                voice_or_data)
5738    return rat != RAT_UNKNOWN
5739
5740
5741def is_voice_attached(log, ad):
5742    return _is_attached_for_subscription(
5743        log, ad, ad.droid.subscriptionGetDefaultSubId(), NETWORK_SERVICE_VOICE)
5744
5745
5746def wait_for_voice_attach(log, ad, max_time=MAX_WAIT_TIME_NW_SELECTION):
5747    """Wait for android device to attach on voice.
5748
5749    Args:
5750        log: log object.
5751        ad:  android device.
5752        max_time: maximal wait time.
5753
5754    Returns:
5755        Return True if device attach voice within max_time.
5756        Return False if timeout.
5757    """
5758    return _wait_for_droid_in_state(log, ad, max_time, _is_attached,
5759                                    NETWORK_SERVICE_VOICE)
5760
5761
5762def wait_for_voice_attach_for_subscription(
5763        log, ad, sub_id, max_time=MAX_WAIT_TIME_NW_SELECTION):
5764    """Wait for android device to attach on voice in subscription id.
5765
5766    Args:
5767        log: log object.
5768        ad:  android device.
5769        sub_id: subscription id.
5770        max_time: maximal wait time.
5771
5772    Returns:
5773        Return True if device attach voice within max_time.
5774        Return False if timeout.
5775    """
5776    if not _wait_for_droid_in_state_for_subscription(
5777            log, ad, sub_id, max_time, _is_attached_for_subscription,
5778            NETWORK_SERVICE_VOICE):
5779        return False
5780
5781    # TODO: b/26295983 if pone attach to 1xrtt from unknown, phone may not
5782    # receive incoming call immediately.
5783    if ad.droid.telephonyGetCurrentVoiceNetworkType() == RAT_1XRTT:
5784        time.sleep(WAIT_TIME_1XRTT_VOICE_ATTACH)
5785    return True
5786
5787
5788def wait_for_data_attach(log, ad, max_time):
5789    """Wait for android device to attach on data.
5790
5791    Args:
5792        log: log object.
5793        ad:  android device.
5794        max_time: maximal wait time.
5795
5796    Returns:
5797        Return True if device attach data within max_time.
5798        Return False if timeout.
5799    """
5800    return _wait_for_droid_in_state(log, ad, max_time, _is_attached,
5801                                    NETWORK_SERVICE_DATA)
5802
5803
5804def wait_for_data_attach_for_subscription(log, ad, sub_id, max_time):
5805    """Wait for android device to attach on data in subscription id.
5806
5807    Args:
5808        log: log object.
5809        ad:  android device.
5810        sub_id: subscription id.
5811        max_time: maximal wait time.
5812
5813    Returns:
5814        Return True if device attach data within max_time.
5815        Return False if timeout.
5816    """
5817    return _wait_for_droid_in_state_for_subscription(
5818        log, ad, sub_id, max_time, _is_attached_for_subscription,
5819        NETWORK_SERVICE_DATA)
5820
5821
5822def is_ims_registered(log, ad, sub_id=None):
5823    """Return True if IMS registered.
5824
5825    Args:
5826        log: log object.
5827        ad: android device.
5828        sub_id: Optional. If not assigned the default sub ID of voice call will
5829            be used.
5830
5831    Returns:
5832        Return True if IMS registered.
5833        Return False if IMS not registered.
5834    """
5835    if not sub_id:
5836        return ad.droid.telephonyIsImsRegistered()
5837    else:
5838        return change_voice_subid_temporarily(
5839            ad, sub_id, ad.droid.telephonyIsImsRegistered)
5840
5841
5842def wait_for_ims_registered(log, ad, max_time=MAX_WAIT_TIME_WFC_ENABLED):
5843    """Wait for android device to register on ims.
5844
5845    Args:
5846        log: log object.
5847        ad:  android device.
5848        max_time: maximal wait time.
5849
5850    Returns:
5851        Return True if device register ims successfully within max_time.
5852        Return False if timeout.
5853    """
5854    return _wait_for_droid_in_state(log, ad, max_time, is_ims_registered)
5855
5856
5857def is_volte_available(log, ad, sub_id):
5858    """Return True if VoLTE is available.
5859
5860    Args:
5861        log: log object.
5862        ad: android device.
5863        sub_id: Optional. If not assigned the default sub ID of voice call will
5864            be used.
5865
5866    Returns:
5867        Return True if VoLTE is available.
5868        Return False if VoLTE is not available.
5869    """
5870    if not sub_id:
5871        return ad.droid.telephonyIsVolteAvailable()
5872    else:
5873        return change_voice_subid_temporarily(
5874            ad, sub_id, ad.droid.telephonyIsVolteAvailable)
5875
5876
5877def is_volte_enabled(log, ad, sub_id=None):
5878    """Return True if VoLTE feature bit is True.
5879
5880    Args:
5881        log: log object.
5882        ad: android device.
5883        sub_id: Optional. If not assigned the default sub ID of voice call will
5884            be used.
5885
5886    Returns:
5887        Return True if VoLTE feature bit is True and IMS registered.
5888        Return False if VoLTE feature bit is False or IMS not registered.
5889    """
5890    if not is_ims_registered(log, ad, sub_id):
5891        ad.log.info("IMS is not registered for sub ID %s.", sub_id)
5892        return False
5893    if not is_volte_available(log, ad, sub_id):
5894        ad.log.info("IMS is registered for sub ID %s, IsVolteCallingAvailable "
5895            "is False", sub_id)
5896        return False
5897    else:
5898        ad.log.info("IMS is registered for sub ID %s, IsVolteCallingAvailable "
5899            "is True", sub_id)
5900        return True
5901
5902
5903def is_video_enabled(log, ad):
5904    """Return True if Video Calling feature bit is True.
5905
5906    Args:
5907        log: log object.
5908        ad: android device.
5909
5910    Returns:
5911        Return True if Video Calling feature bit is True and IMS registered.
5912        Return False if Video Calling feature bit is False or IMS not registered.
5913    """
5914    video_status = ad.droid.telephonyIsVideoCallingAvailable()
5915    if video_status is True and is_ims_registered(log, ad) is False:
5916        ad.log.error(
5917            "Error! Video Call is Available, but IMS is not registered.")
5918        return False
5919    return video_status
5920
5921
5922def wait_for_volte_enabled(
5923    log, ad, max_time=MAX_WAIT_TIME_VOLTE_ENABLED,sub_id=None):
5924    """Wait for android device to report VoLTE enabled bit true.
5925
5926    Args:
5927        log: log object.
5928        ad:  android device.
5929        max_time: maximal wait time.
5930
5931    Returns:
5932        Return True if device report VoLTE enabled bit true within max_time.
5933        Return False if timeout.
5934    """
5935    if not sub_id:
5936        return _wait_for_droid_in_state(log, ad, max_time, is_volte_enabled)
5937    else:
5938        return _wait_for_droid_in_state_for_subscription(
5939            log, ad, sub_id, max_time, is_volte_enabled)
5940
5941
5942def wait_for_video_enabled(log, ad, max_time=MAX_WAIT_TIME_VOLTE_ENABLED):
5943    """Wait for android device to report Video Telephony enabled bit true.
5944
5945    Args:
5946        log: log object.
5947        ad:  android device.
5948        max_time: maximal wait time.
5949
5950    Returns:
5951        Return True if device report Video Telephony enabled bit true within max_time.
5952        Return False if timeout.
5953    """
5954    return _wait_for_droid_in_state(log, ad, max_time, is_video_enabled)
5955
5956
5957def is_wfc_enabled(log, ad):
5958    """Return True if WiFi Calling feature bit is True.
5959
5960    Args:
5961        log: log object.
5962        ad: android device.
5963
5964    Returns:
5965        Return True if WiFi Calling feature bit is True and IMS registered.
5966        Return False if WiFi Calling feature bit is False or IMS not registered.
5967    """
5968    if not is_ims_registered(log, ad):
5969        ad.log.info("IMS is not registered.")
5970        return False
5971    if not ad.droid.telephonyIsWifiCallingAvailable():
5972        ad.log.info("IMS is registered, IsWifiCallingAvailable is False")
5973        return False
5974    else:
5975        ad.log.info("IMS is registered, IsWifiCallingAvailable is True")
5976        return True
5977
5978
5979def wait_for_wfc_enabled(log, ad, max_time=MAX_WAIT_TIME_WFC_ENABLED):
5980    """Wait for android device to report WiFi Calling enabled bit true.
5981
5982    Args:
5983        log: log object.
5984        ad:  android device.
5985        max_time: maximal wait time.
5986            Default value is MAX_WAIT_TIME_WFC_ENABLED.
5987
5988    Returns:
5989        Return True if device report WiFi Calling enabled bit true within max_time.
5990        Return False if timeout.
5991    """
5992    return _wait_for_droid_in_state(log, ad, max_time, is_wfc_enabled)
5993
5994
5995def wait_for_wfc_disabled(log, ad, max_time=MAX_WAIT_TIME_WFC_DISABLED):
5996    """Wait for android device to report WiFi Calling enabled bit false.
5997
5998    Args:
5999        log: log object.
6000        ad:  android device.
6001        max_time: maximal wait time.
6002            Default value is MAX_WAIT_TIME_WFC_DISABLED.
6003
6004    Returns:
6005        Return True if device report WiFi Calling enabled bit false within max_time.
6006        Return False if timeout.
6007    """
6008    return _wait_for_droid_in_state(
6009        log, ad, max_time, lambda log, ad: not is_wfc_enabled(log, ad))
6010
6011
6012def get_phone_number(log, ad):
6013    """Get phone number for default subscription
6014
6015    Args:
6016        log: log object.
6017        ad: Android device object.
6018
6019    Returns:
6020        Phone number.
6021    """
6022    return get_phone_number_for_subscription(log, ad,
6023                                             get_outgoing_voice_sub_id(ad))
6024
6025
6026def get_phone_number_for_subscription(log, ad, subid):
6027    """Get phone number for subscription
6028
6029    Args:
6030        log: log object.
6031        ad: Android device object.
6032        subid: subscription id.
6033
6034    Returns:
6035        Phone number.
6036    """
6037    number = None
6038    try:
6039        number = ad.telephony['subscription'][subid]['phone_num']
6040    except KeyError:
6041        number = ad.droid.telephonyGetLine1NumberForSubscription(subid)
6042    return number
6043
6044
6045def set_phone_number(log, ad, phone_num):
6046    """Set phone number for default subscription
6047
6048    Args:
6049        log: log object.
6050        ad: Android device object.
6051        phone_num: phone number string.
6052
6053    Returns:
6054        True if success.
6055    """
6056    return set_phone_number_for_subscription(log, ad,
6057                                             get_outgoing_voice_sub_id(ad),
6058                                             phone_num)
6059
6060
6061def set_phone_number_for_subscription(log, ad, subid, phone_num):
6062    """Set phone number for subscription
6063
6064    Args:
6065        log: log object.
6066        ad: Android device object.
6067        subid: subscription id.
6068        phone_num: phone number string.
6069
6070    Returns:
6071        True if success.
6072    """
6073    try:
6074        ad.telephony['subscription'][subid]['phone_num'] = phone_num
6075    except Exception:
6076        return False
6077    return True
6078
6079
6080def get_operator_name(log, ad, subId=None):
6081    """Get operator name (e.g. vzw, tmo) of droid.
6082
6083    Args:
6084        ad: Android device object.
6085        sub_id: subscription ID
6086            Optional, default is None
6087
6088    Returns:
6089        Operator name.
6090    """
6091    try:
6092        if subId is not None:
6093            result = operator_name_from_plmn_id(
6094                ad.droid.telephonyGetNetworkOperatorForSubscription(subId))
6095        else:
6096            result = operator_name_from_plmn_id(
6097                ad.droid.telephonyGetNetworkOperator())
6098    except KeyError:
6099        try:
6100            if subId is not None:
6101                result = ad.droid.telephonyGetNetworkOperatorNameForSubscription(
6102                    subId)
6103            else:
6104                result = ad.droid.telephonyGetNetworkOperatorName()
6105            result = operator_name_from_network_name(result)
6106        except Exception:
6107            result = CARRIER_UNKNOWN
6108    ad.log.info("Operator Name is %s", result)
6109    return result
6110
6111
6112def get_model_name(ad):
6113    """Get android device model name
6114
6115    Args:
6116        ad: Android device object
6117
6118    Returns:
6119        model name string
6120    """
6121    # TODO: Create translate table.
6122    model = ad.model
6123    if (model.startswith(AOSP_PREFIX)):
6124        model = model[len(AOSP_PREFIX):]
6125    return model
6126
6127
6128def is_sms_match(event, phonenumber_tx, text):
6129    """Return True if 'text' equals to event['data']['Text']
6130        and phone number match.
6131
6132    Args:
6133        event: Event object to verify.
6134        phonenumber_tx: phone number for sender.
6135        text: text string to verify.
6136
6137    Returns:
6138        Return True if 'text' equals to event['data']['Text']
6139            and phone number match.
6140    """
6141    return (check_phone_number_match(event['data']['Sender'], phonenumber_tx)
6142            and event['data']['Text'].strip() == text)
6143
6144
6145def is_sms_partial_match(event, phonenumber_tx, text):
6146    """Return True if 'text' starts with event['data']['Text']
6147        and phone number match.
6148
6149    Args:
6150        event: Event object to verify.
6151        phonenumber_tx: phone number for sender.
6152        text: text string to verify.
6153
6154    Returns:
6155        Return True if 'text' starts with event['data']['Text']
6156            and phone number match.
6157    """
6158    event_text = event['data']['Text'].strip()
6159    if event_text.startswith("("):
6160        event_text = event_text.split(")")[-1]
6161    return (check_phone_number_match(event['data']['Sender'], phonenumber_tx)
6162            and text.startswith(event_text))
6163
6164
6165def sms_send_receive_verify(log,
6166                            ad_tx,
6167                            ad_rx,
6168                            array_message,
6169                            max_wait_time=MAX_WAIT_TIME_SMS_RECEIVE,
6170                            expected_result=True,
6171                            slot_id_rx=None):
6172    """Send SMS, receive SMS, and verify content and sender's number.
6173
6174        Send (several) SMS from droid_tx to droid_rx.
6175        Verify SMS is sent, delivered and received.
6176        Verify received content and sender's number are correct.
6177
6178    Args:
6179        log: Log object.
6180        ad_tx: Sender's Android Device Object
6181        ad_rx: Receiver's Android Device Object
6182        array_message: the array of message to send/receive
6183        slot_id_rx: the slot on the Receiver's android device (0/1)
6184    """
6185    subid_tx = get_outgoing_message_sub_id(ad_tx)
6186    if slot_id_rx is None:
6187        subid_rx = get_incoming_message_sub_id(ad_rx)
6188    else:
6189        subid_rx = get_subid_from_slot_index(log, ad_rx, slot_id_rx)
6190
6191    result = sms_send_receive_verify_for_subscription(
6192        log, ad_tx, ad_rx, subid_tx, subid_rx, array_message, max_wait_time)
6193    if result != expected_result:
6194        log_messaging_screen_shot(ad_tx, test_name="sms_tx")
6195        log_messaging_screen_shot(ad_rx, test_name="sms_rx")
6196    return result == expected_result
6197
6198
6199def wait_for_matching_sms(log,
6200                          ad_rx,
6201                          phonenumber_tx,
6202                          text,
6203                          max_wait_time=MAX_WAIT_TIME_SMS_RECEIVE,
6204                          allow_multi_part_long_sms=True):
6205    """Wait for matching incoming SMS.
6206
6207    Args:
6208        log: Log object.
6209        ad_rx: Receiver's Android Device Object
6210        phonenumber_tx: Sender's phone number.
6211        text: SMS content string.
6212        allow_multi_part_long_sms: is long SMS allowed to be received as
6213            multiple short SMS. This is optional, default value is True.
6214
6215    Returns:
6216        True if matching incoming SMS is received.
6217    """
6218    if not allow_multi_part_long_sms:
6219        try:
6220            ad_rx.messaging_ed.wait_for_event(EventSmsReceived, is_sms_match,
6221                                              max_wait_time, phonenumber_tx,
6222                                              text)
6223            ad_rx.log.info("Got event %s", EventSmsReceived)
6224            return True
6225        except Empty:
6226            ad_rx.log.error("No matched SMS received event.")
6227            return False
6228    else:
6229        try:
6230            received_sms = ''
6231            remaining_text = text
6232            while (remaining_text != ''):
6233                event = ad_rx.messaging_ed.wait_for_event(
6234                    EventSmsReceived, is_sms_partial_match, max_wait_time,
6235                    phonenumber_tx, remaining_text)
6236                event_text = event['data']['Text'].split(")")[-1].strip()
6237                event_text_length = len(event_text)
6238                ad_rx.log.info("Got event %s of text length %s from %s",
6239                               EventSmsReceived, event_text_length,
6240                               phonenumber_tx)
6241                remaining_text = remaining_text[event_text_length:]
6242                received_sms += event_text
6243            ad_rx.log.info("Received SMS of length %s", len(received_sms))
6244            return True
6245        except Empty:
6246            ad_rx.log.error(
6247                "Missing SMS received event of text length %s from %s",
6248                len(remaining_text), phonenumber_tx)
6249            if received_sms != '':
6250                ad_rx.log.error(
6251                    "Only received partial matched SMS of length %s",
6252                    len(received_sms))
6253            return False
6254
6255
6256def is_mms_match(event, phonenumber_tx, text):
6257    """Return True if 'text' equals to event['data']['Text']
6258        and phone number match.
6259
6260    Args:
6261        event: Event object to verify.
6262        phonenumber_tx: phone number for sender.
6263        text: text string to verify.
6264
6265    Returns:
6266        Return True if 'text' equals to event['data']['Text']
6267            and phone number match.
6268    """
6269    #TODO:  add mms matching after mms message parser is added in sl4a. b/34276948
6270    return True
6271
6272
6273def wait_for_matching_mms(log,
6274                          ad_rx,
6275                          phonenumber_tx,
6276                          text,
6277                          max_wait_time=MAX_WAIT_TIME_SMS_RECEIVE):
6278    """Wait for matching incoming SMS.
6279
6280    Args:
6281        log: Log object.
6282        ad_rx: Receiver's Android Device Object
6283        phonenumber_tx: Sender's phone number.
6284        text: SMS content string.
6285        allow_multi_part_long_sms: is long SMS allowed to be received as
6286            multiple short SMS. This is optional, default value is True.
6287
6288    Returns:
6289        True if matching incoming SMS is received.
6290    """
6291    try:
6292        #TODO: add mms matching after mms message parser is added in sl4a. b/34276948
6293        ad_rx.messaging_ed.wait_for_event(EventMmsDownloaded, is_mms_match,
6294                                          max_wait_time, phonenumber_tx, text)
6295        ad_rx.log.info("Got event %s", EventMmsDownloaded)
6296        return True
6297    except Empty:
6298        ad_rx.log.warning("No matched MMS downloaded event.")
6299        return False
6300
6301
6302def sms_send_receive_verify_for_subscription(
6303        log,
6304        ad_tx,
6305        ad_rx,
6306        subid_tx,
6307        subid_rx,
6308        array_message,
6309        max_wait_time=MAX_WAIT_TIME_SMS_RECEIVE):
6310    """Send SMS, receive SMS, and verify content and sender's number.
6311
6312        Send (several) SMS from droid_tx to droid_rx.
6313        Verify SMS is sent, delivered and received.
6314        Verify received content and sender's number are correct.
6315
6316    Args:
6317        log: Log object.
6318        ad_tx: Sender's Android Device Object..
6319        ad_rx: Receiver's Android Device Object.
6320        subid_tx: Sender's subsciption ID to be used for SMS
6321        subid_rx: Receiver's subsciption ID to be used for SMS
6322        array_message: the array of message to send/receive
6323    """
6324    phonenumber_tx = ad_tx.telephony['subscription'][subid_tx]['phone_num']
6325    phonenumber_rx = ad_rx.telephony['subscription'][subid_rx]['phone_num']
6326
6327    for ad in (ad_tx, ad_rx):
6328        ad.send_keycode("BACK")
6329        if not getattr(ad, "messaging_droid", None):
6330            ad.messaging_droid, ad.messaging_ed = ad.get_droid()
6331            ad.messaging_ed.start()
6332        else:
6333            try:
6334                if not ad.messaging_droid.is_live:
6335                    ad.messaging_droid, ad.messaging_ed = ad.get_droid()
6336                    ad.messaging_ed.start()
6337                else:
6338                    ad.messaging_ed.clear_all_events()
6339                ad.messaging_droid.logI(
6340                    "Start sms_send_receive_verify_for_subscription test")
6341            except Exception:
6342                ad.log.info("Create new sl4a session for messaging")
6343                ad.messaging_droid, ad.messaging_ed = ad.get_droid()
6344                ad.messaging_ed.start()
6345
6346    for text in array_message:
6347        length = len(text)
6348        ad_tx.log.info("Sending SMS from %s to %s, len: %s, content: %s.",
6349                       phonenumber_tx, phonenumber_rx, length, text)
6350        try:
6351            ad_rx.messaging_ed.clear_events(EventSmsReceived)
6352            ad_tx.messaging_ed.clear_events(EventSmsSentSuccess)
6353            ad_tx.messaging_ed.clear_events(EventSmsSentFailure)
6354            ad_rx.messaging_droid.smsStartTrackingIncomingSmsMessage()
6355            time.sleep(1)  #sleep 100ms after starting event tracking
6356            ad_tx.messaging_droid.logI("Sending SMS of length %s" % length)
6357            ad_rx.messaging_droid.logI("Expecting SMS of length %s" % length)
6358            ad_tx.messaging_droid.smsSendTextMessage(phonenumber_rx, text,
6359                                                     True)
6360            try:
6361                events = ad_tx.messaging_ed.pop_events(
6362                    "(%s|%s|%s|%s)" %
6363                    (EventSmsSentSuccess, EventSmsSentFailure,
6364                     EventSmsDeliverSuccess,
6365                     EventSmsDeliverFailure), max_wait_time)
6366                for event in events:
6367                    ad_tx.log.info("Got event %s", event["name"])
6368                    if event["name"] == EventSmsSentFailure or event["name"] == EventSmsDeliverFailure:
6369                        if event.get("data") and event["data"].get("Reason"):
6370                            ad_tx.log.error("%s with reason: %s",
6371                                            event["name"],
6372                                            event["data"]["Reason"])
6373                        return False
6374                    elif event["name"] == EventSmsSentSuccess or event["name"] == EventSmsDeliverSuccess:
6375                        break
6376            except Empty:
6377                ad_tx.log.error("No %s or %s event for SMS of length %s.",
6378                                EventSmsSentSuccess, EventSmsSentFailure,
6379                                length)
6380                return False
6381
6382            if not wait_for_matching_sms(
6383                    log,
6384                    ad_rx,
6385                    phonenumber_tx,
6386                    text,
6387                    max_wait_time,
6388                    allow_multi_part_long_sms=True):
6389                ad_rx.log.error("No matching received SMS of length %s.",
6390                                length)
6391                return False
6392        except Exception as e:
6393            log.error("Exception error %s", e)
6394            raise
6395        finally:
6396            ad_rx.messaging_droid.smsStopTrackingIncomingSmsMessage()
6397    return True
6398
6399
6400def mms_send_receive_verify(log,
6401                            ad_tx,
6402                            ad_rx,
6403                            array_message,
6404                            max_wait_time=MAX_WAIT_TIME_SMS_RECEIVE,
6405                            expected_result=True,
6406                            slot_id_rx=None):
6407    """Send MMS, receive MMS, and verify content and sender's number.
6408
6409        Send (several) MMS from droid_tx to droid_rx.
6410        Verify MMS is sent, delivered and received.
6411        Verify received content and sender's number are correct.
6412
6413    Args:
6414        log: Log object.
6415        ad_tx: Sender's Android Device Object
6416        ad_rx: Receiver's Android Device Object
6417        array_message: the array of message to send/receive
6418    """
6419    subid_tx = get_outgoing_message_sub_id(ad_tx)
6420    if slot_id_rx is None:
6421        subid_rx = get_incoming_message_sub_id(ad_rx)
6422    else:
6423        subid_rx = get_subid_from_slot_index(log, ad_rx, slot_id_rx)
6424
6425    result = mms_send_receive_verify_for_subscription(
6426        log, ad_tx, ad_rx, subid_tx, subid_rx, array_message, max_wait_time)
6427    if result != expected_result:
6428        log_messaging_screen_shot(ad_tx, test_name="mms_tx")
6429        log_messaging_screen_shot(ad_rx, test_name="mms_rx")
6430    return result == expected_result
6431
6432
6433def sms_mms_send_logcat_check(ad, type, begin_time):
6434    type = type.upper()
6435    log_results = ad.search_logcat(
6436        "%s Message sent successfully" % type, begin_time=begin_time)
6437    if log_results:
6438        ad.log.info("Found %s sent successful log message: %s", type,
6439                    log_results[-1]["log_message"])
6440        return True
6441    else:
6442        log_results = ad.search_logcat(
6443            "ProcessSentMessageAction: Done sending %s message" % type,
6444            begin_time=begin_time)
6445        if log_results:
6446            for log_result in log_results:
6447                if "status is SUCCEEDED" in log_result["log_message"]:
6448                    ad.log.info(
6449                        "Found BugleDataModel %s send succeed log message: %s",
6450                        type, log_result["log_message"])
6451                    return True
6452    return False
6453
6454
6455def sms_mms_receive_logcat_check(ad, type, begin_time):
6456    type = type.upper()
6457    smshandle_logs = ad.search_logcat(
6458        "InboundSmsHandler: No broadcast sent on processing EVENT_BROADCAST_SMS",
6459        begin_time=begin_time)
6460    if smshandle_logs:
6461        ad.log.warning("Found %s", smshandle_logs[-1]["log_message"])
6462    log_results = ad.search_logcat(
6463        "New %s Received" % type, begin_time=begin_time) or \
6464        ad.search_logcat("New %s Downloaded" % type, begin_time=begin_time)
6465    if log_results:
6466        ad.log.info("Found SL4A %s received log message: %s", type,
6467                    log_results[-1]["log_message"])
6468        return True
6469    else:
6470        log_results = ad.search_logcat(
6471            "Received %s message" % type, begin_time=begin_time)
6472        if log_results:
6473            ad.log.info("Found %s received log message: %s", type,
6474                        log_results[-1]["log_message"])
6475        log_results = ad.search_logcat(
6476            "ProcessDownloadedMmsAction", begin_time=begin_time)
6477        for log_result in log_results:
6478            ad.log.info("Found %s", log_result["log_message"])
6479            if "status is SUCCEEDED" in log_result["log_message"]:
6480                ad.log.info("Download succeed with ProcessDownloadedMmsAction")
6481                return True
6482    return False
6483
6484
6485#TODO: add mms matching after mms message parser is added in sl4a. b/34276948
6486def mms_send_receive_verify_for_subscription(
6487        log,
6488        ad_tx,
6489        ad_rx,
6490        subid_tx,
6491        subid_rx,
6492        array_payload,
6493        max_wait_time=MAX_WAIT_TIME_SMS_RECEIVE):
6494    """Send MMS, receive MMS, and verify content and sender's number.
6495
6496        Send (several) MMS from droid_tx to droid_rx.
6497        Verify MMS is sent, delivered and received.
6498        Verify received content and sender's number are correct.
6499
6500    Args:
6501        log: Log object.
6502        ad_tx: Sender's Android Device Object..
6503        ad_rx: Receiver's Android Device Object.
6504        subid_tx: Sender's subsciption ID to be used for SMS
6505        subid_rx: Receiver's subsciption ID to be used for SMS
6506        array_message: the array of message to send/receive
6507    """
6508
6509    phonenumber_tx = ad_tx.telephony['subscription'][subid_tx]['phone_num']
6510    phonenumber_rx = ad_rx.telephony['subscription'][subid_rx]['phone_num']
6511    toggle_enforce = False
6512
6513    for ad in (ad_tx, ad_rx):
6514        ad.send_keycode("BACK")
6515        if "Permissive" not in ad.adb.shell("su root getenforce"):
6516            ad.adb.shell("su root setenforce 0")
6517            toggle_enforce = True
6518        if not getattr(ad, "messaging_droid", None):
6519            ad.messaging_droid, ad.messaging_ed = ad.get_droid()
6520            ad.messaging_ed.start()
6521        else:
6522            try:
6523                if not ad.messaging_droid.is_live:
6524                    ad.messaging_droid, ad.messaging_ed = ad.get_droid()
6525                    ad.messaging_ed.start()
6526                else:
6527                    ad.messaging_ed.clear_all_events()
6528                ad.messaging_droid.logI(
6529                    "Start mms_send_receive_verify_for_subscription test")
6530            except Exception:
6531                ad.log.info("Create new sl4a session for messaging")
6532                ad.messaging_droid, ad.messaging_ed = ad.get_droid()
6533                ad.messaging_ed.start()
6534
6535    for subject, message, filename in array_payload:
6536        ad_tx.messaging_ed.clear_events(EventMmsSentSuccess)
6537        ad_tx.messaging_ed.clear_events(EventMmsSentFailure)
6538        ad_rx.messaging_ed.clear_events(EventMmsDownloaded)
6539        ad_rx.messaging_droid.smsStartTrackingIncomingMmsMessage()
6540        ad_tx.log.info(
6541            "Sending MMS from %s to %s, subject: %s, message: %s, file: %s.",
6542            phonenumber_tx, phonenumber_rx, subject, message, filename)
6543        try:
6544            ad_tx.messaging_droid.smsSendMultimediaMessage(
6545                phonenumber_rx, subject, message, phonenumber_tx, filename)
6546            try:
6547                events = ad_tx.messaging_ed.pop_events(
6548                    "(%s|%s)" % (EventMmsSentSuccess,
6549                                 EventMmsSentFailure), max_wait_time)
6550                for event in events:
6551                    ad_tx.log.info("Got event %s", event["name"])
6552                    if event["name"] == EventMmsSentFailure:
6553                        if event.get("data") and event["data"].get("Reason"):
6554                            ad_tx.log.error("%s with reason: %s",
6555                                            event["name"],
6556                                            event["data"]["Reason"])
6557                        return False
6558                    elif event["name"] == EventMmsSentSuccess:
6559                        break
6560            except Empty:
6561                ad_tx.log.warning("No %s or %s event.", EventMmsSentSuccess,
6562                                  EventMmsSentFailure)
6563                return False
6564
6565            if not wait_for_matching_mms(log, ad_rx, phonenumber_tx,
6566                                         message, max_wait_time):
6567                return False
6568        except Exception as e:
6569            log.error("Exception error %s", e)
6570            raise
6571        finally:
6572            ad_rx.messaging_droid.smsStopTrackingIncomingMmsMessage()
6573            for ad in (ad_tx, ad_rx):
6574                if toggle_enforce:
6575                    ad.send_keycode("BACK")
6576                    ad.adb.shell("su root setenforce 1")
6577    return True
6578
6579
6580def mms_receive_verify_after_call_hangup(
6581        log, ad_tx, ad_rx, array_message,
6582        max_wait_time=MAX_WAIT_TIME_SMS_RECEIVE):
6583    """Verify the suspanded MMS during call will send out after call release.
6584
6585        Hangup call from droid_tx to droid_rx.
6586        Verify MMS is sent, delivered and received.
6587        Verify received content and sender's number are correct.
6588
6589    Args:
6590        log: Log object.
6591        ad_tx: Sender's Android Device Object
6592        ad_rx: Receiver's Android Device Object
6593        array_message: the array of message to send/receive
6594    """
6595    return mms_receive_verify_after_call_hangup_for_subscription(
6596        log, ad_tx, ad_rx, get_outgoing_message_sub_id(ad_tx),
6597        get_incoming_message_sub_id(ad_rx), array_message, max_wait_time)
6598
6599
6600#TODO: add mms matching after mms message parser is added in sl4a. b/34276948
6601def mms_receive_verify_after_call_hangup_for_subscription(
6602        log,
6603        ad_tx,
6604        ad_rx,
6605        subid_tx,
6606        subid_rx,
6607        array_payload,
6608        max_wait_time=MAX_WAIT_TIME_SMS_RECEIVE):
6609    """Verify the suspanded MMS during call will send out after call release.
6610
6611        Hangup call from droid_tx to droid_rx.
6612        Verify MMS is sent, delivered and received.
6613        Verify received content and sender's number are correct.
6614
6615    Args:
6616        log: Log object.
6617        ad_tx: Sender's Android Device Object..
6618        ad_rx: Receiver's Android Device Object.
6619        subid_tx: Sender's subsciption ID to be used for SMS
6620        subid_rx: Receiver's subsciption ID to be used for SMS
6621        array_message: the array of message to send/receive
6622    """
6623
6624    phonenumber_tx = ad_tx.telephony['subscription'][subid_tx]['phone_num']
6625    phonenumber_rx = ad_rx.telephony['subscription'][subid_rx]['phone_num']
6626    for ad in (ad_tx, ad_rx):
6627        if not getattr(ad, "messaging_droid", None):
6628            ad.messaging_droid, ad.messaging_ed = ad.get_droid()
6629            ad.messaging_ed.start()
6630    for subject, message, filename in array_payload:
6631        ad_rx.log.info(
6632            "Waiting MMS from %s to %s, subject: %s, message: %s, file: %s.",
6633            phonenumber_tx, phonenumber_rx, subject, message, filename)
6634        ad_rx.messaging_droid.smsStartTrackingIncomingMmsMessage()
6635        time.sleep(5)
6636        try:
6637            hangup_call(log, ad_tx)
6638            hangup_call(log, ad_rx)
6639            try:
6640                ad_tx.messaging_ed.pop_event(EventMmsSentSuccess,
6641                                             max_wait_time)
6642                ad_tx.log.info("Got event %s", EventMmsSentSuccess)
6643            except Empty:
6644                log.warning("No sent_success event.")
6645            if not wait_for_matching_mms(log, ad_rx, phonenumber_tx, message):
6646                return False
6647        finally:
6648            ad_rx.messaging_droid.smsStopTrackingIncomingMmsMessage()
6649    return True
6650
6651
6652def ensure_preferred_network_type_for_subscription(
6653        ad,
6654        network_preference
6655        ):
6656    sub_id = ad.droid.subscriptionGetDefaultSubId()
6657    if not ad.droid.telephonySetPreferredNetworkTypesForSubscription(
6658            network_preference, sub_id):
6659        ad.log.error("Set sub_id %s Preferred Networks Type %s failed.",
6660                     sub_id, network_preference)
6661    return True
6662
6663
6664def ensure_network_rat(log,
6665                       ad,
6666                       network_preference,
6667                       rat_family,
6668                       voice_or_data=None,
6669                       max_wait_time=MAX_WAIT_TIME_NW_SELECTION,
6670                       toggle_apm_after_setting=False):
6671    """Ensure ad's current network is in expected rat_family.
6672    """
6673    return ensure_network_rat_for_subscription(
6674        log, ad, ad.droid.subscriptionGetDefaultSubId(), network_preference,
6675        rat_family, voice_or_data, max_wait_time, toggle_apm_after_setting)
6676
6677
6678def ensure_network_rat_for_subscription(
6679        log,
6680        ad,
6681        sub_id,
6682        network_preference,
6683        rat_family,
6684        voice_or_data=None,
6685        max_wait_time=MAX_WAIT_TIME_NW_SELECTION,
6686        toggle_apm_after_setting=False):
6687    """Ensure ad's current network is in expected rat_family.
6688    """
6689    if not ad.droid.telephonySetPreferredNetworkTypesForSubscription(
6690            network_preference, sub_id):
6691        ad.log.error("Set sub_id %s Preferred Networks Type %s failed.",
6692                     sub_id, network_preference)
6693        return False
6694    if is_droid_in_rat_family_for_subscription(log, ad, sub_id, rat_family,
6695                                               voice_or_data):
6696        ad.log.info("Sub_id %s in RAT %s for %s", sub_id, rat_family,
6697                    voice_or_data)
6698        return True
6699
6700    if toggle_apm_after_setting:
6701        toggle_airplane_mode(log, ad, new_state=True, strict_checking=False)
6702        time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
6703        toggle_airplane_mode(log, ad, new_state=None, strict_checking=False)
6704
6705    result = wait_for_network_rat_for_subscription(
6706        log, ad, sub_id, rat_family, max_wait_time, voice_or_data)
6707
6708    log.info(
6709        "End of ensure_network_rat_for_subscription for %s. "
6710        "Setting to %s, Expecting %s %s. Current: voice: %s(family: %s), "
6711        "data: %s(family: %s)", ad.serial, network_preference, rat_family,
6712        voice_or_data,
6713        ad.droid.telephonyGetCurrentVoiceNetworkTypeForSubscription(sub_id),
6714        rat_family_from_rat(
6715            ad.droid.telephonyGetCurrentVoiceNetworkTypeForSubscription(
6716                sub_id)),
6717        ad.droid.telephonyGetCurrentDataNetworkTypeForSubscription(sub_id),
6718        rat_family_from_rat(
6719            ad.droid.telephonyGetCurrentDataNetworkTypeForSubscription(
6720                sub_id)))
6721    return result
6722
6723
6724def ensure_network_preference(log,
6725                              ad,
6726                              network_preference,
6727                              voice_or_data=None,
6728                              max_wait_time=MAX_WAIT_TIME_NW_SELECTION,
6729                              toggle_apm_after_setting=False):
6730    """Ensure that current rat is within the device's preferred network rats.
6731    """
6732    return ensure_network_preference_for_subscription(
6733        log, ad, ad.droid.subscriptionGetDefaultSubId(), network_preference,
6734        voice_or_data, max_wait_time, toggle_apm_after_setting)
6735
6736
6737def ensure_network_preference_for_subscription(
6738        log,
6739        ad,
6740        sub_id,
6741        network_preference,
6742        voice_or_data=None,
6743        max_wait_time=MAX_WAIT_TIME_NW_SELECTION,
6744        toggle_apm_after_setting=False):
6745    """Ensure ad's network preference is <network_preference> for sub_id.
6746    """
6747    rat_family_list = rat_families_for_network_preference(network_preference)
6748    if not ad.droid.telephonySetPreferredNetworkTypesForSubscription(
6749            network_preference, sub_id):
6750        log.error("Set Preferred Networks failed.")
6751        return False
6752    if is_droid_in_rat_family_list_for_subscription(
6753            log, ad, sub_id, rat_family_list, voice_or_data):
6754        return True
6755
6756    if toggle_apm_after_setting:
6757        toggle_airplane_mode(log, ad, new_state=True, strict_checking=False)
6758        time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
6759        toggle_airplane_mode(log, ad, new_state=False, strict_checking=False)
6760
6761    result = wait_for_preferred_network_for_subscription(
6762        log, ad, sub_id, network_preference, max_wait_time, voice_or_data)
6763
6764    ad.log.info(
6765        "End of ensure_network_preference_for_subscription. "
6766        "Setting to %s, Expecting %s %s. Current: voice: %s(family: %s), "
6767        "data: %s(family: %s)", network_preference, rat_family_list,
6768        voice_or_data,
6769        ad.droid.telephonyGetCurrentVoiceNetworkTypeForSubscription(sub_id),
6770        rat_family_from_rat(
6771            ad.droid.telephonyGetCurrentVoiceNetworkTypeForSubscription(
6772                sub_id)),
6773        ad.droid.telephonyGetCurrentDataNetworkTypeForSubscription(sub_id),
6774        rat_family_from_rat(
6775            ad.droid.telephonyGetCurrentDataNetworkTypeForSubscription(
6776                sub_id)))
6777    return result
6778
6779
6780def ensure_network_generation(log,
6781                              ad,
6782                              generation,
6783                              max_wait_time=MAX_WAIT_TIME_NW_SELECTION,
6784                              voice_or_data=None,
6785                              toggle_apm_after_setting=False):
6786    """Ensure ad's network is <network generation> for default subscription ID.
6787
6788    Set preferred network generation to <generation>.
6789    Toggle ON/OFF airplane mode if necessary.
6790    Wait for ad in expected network type.
6791    """
6792    return ensure_network_generation_for_subscription(
6793        log, ad, ad.droid.subscriptionGetDefaultSubId(), generation,
6794        max_wait_time, voice_or_data, toggle_apm_after_setting)
6795
6796
6797def ensure_network_generation_for_subscription(
6798        log,
6799        ad,
6800        sub_id,
6801        generation,
6802        max_wait_time=MAX_WAIT_TIME_NW_SELECTION,
6803        voice_or_data=None,
6804        toggle_apm_after_setting=False):
6805    """Ensure ad's network is <network generation> for specified subscription ID.
6806
6807        Set preferred network generation to <generation>.
6808        Toggle ON/OFF airplane mode if necessary.
6809        Wait for ad in expected network type.
6810
6811    Args:
6812        log: log object.
6813        ad: android device object.
6814        sub_id: subscription id.
6815        generation: network generation, e.g. GEN_2G, GEN_3G, GEN_4G, GEN_5G.
6816        max_wait_time: the time to wait for NW selection.
6817        voice_or_data: check voice network generation or data network generation
6818            This parameter is optional. If voice_or_data is None, then if
6819            either voice or data in expected generation, function will return True.
6820        toggle_apm_after_setting: Cycle airplane mode if True, otherwise do nothing.
6821
6822    Returns:
6823        True if success, False if fail.
6824    """
6825    ad.log.info(
6826        "RAT network type voice: %s, data: %s",
6827        ad.droid.telephonyGetCurrentVoiceNetworkTypeForSubscription(sub_id),
6828        ad.droid.telephonyGetCurrentDataNetworkTypeForSubscription(sub_id))
6829
6830    try:
6831        ad.log.info("Finding the network preference for generation %s for "
6832                    "operator %s phone type %s", generation,
6833                    ad.telephony["subscription"][sub_id]["operator"],
6834                    ad.telephony["subscription"][sub_id]["phone_type"])
6835        network_preference = network_preference_for_generation(
6836            generation, ad.telephony["subscription"][sub_id]["operator"],
6837            ad.telephony["subscription"][sub_id]["phone_type"])
6838        if ad.telephony["subscription"][sub_id]["operator"] == CARRIER_FRE \
6839            and generation == GEN_4G:
6840            network_preference = NETWORK_MODE_LTE_ONLY
6841        ad.log.info("Network preference for %s is %s", generation,
6842                    network_preference)
6843        rat_family = rat_family_for_generation(
6844            generation, ad.telephony["subscription"][sub_id]["operator"],
6845            ad.telephony["subscription"][sub_id]["phone_type"])
6846    except KeyError as e:
6847        ad.log.error("Failed to find a rat_family entry for generation %s"
6848                     " for subscriber id %s with error %s", generation,
6849                     sub_id, e)
6850        return False
6851
6852    if not set_preferred_network_mode_pref(log, ad, sub_id,
6853                                           network_preference):
6854        return False
6855
6856    if hasattr(ad, "dsds") and voice_or_data == "data" and sub_id != get_default_data_sub_id(ad):
6857        ad.log.info("MSIM - Non DDS, ignore data RAT")
6858        return True
6859
6860    if generation == GEN_5G:
6861        if is_current_network_5g_nsa_for_subscription(ad, sub_id=sub_id):
6862            ad.log.info("Current network type is 5G NSA.")
6863            return True
6864        else:
6865            ad.log.error("Not in 5G NSA coverage for Sub %s.", sub_id)
6866            return False
6867
6868    if is_droid_in_network_generation_for_subscription(
6869            log, ad, sub_id, generation, voice_or_data):
6870        return True
6871
6872    if toggle_apm_after_setting:
6873        toggle_airplane_mode(log, ad, new_state=True, strict_checking=False)
6874        time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
6875        toggle_airplane_mode(log, ad, new_state=False, strict_checking=False)
6876
6877    result = wait_for_network_generation_for_subscription(
6878        log, ad, sub_id, generation, max_wait_time, voice_or_data)
6879
6880    ad.log.info(
6881        "Ensure network %s %s %s. With network preference %s, "
6882        "current: voice: %s(family: %s), data: %s(family: %s)", generation,
6883        voice_or_data, result, network_preference,
6884        ad.droid.telephonyGetCurrentVoiceNetworkTypeForSubscription(sub_id),
6885        rat_generation_from_rat(
6886            ad.droid.telephonyGetCurrentVoiceNetworkTypeForSubscription(
6887                sub_id)),
6888        ad.droid.telephonyGetCurrentDataNetworkTypeForSubscription(sub_id),
6889        rat_generation_from_rat(
6890            ad.droid.telephonyGetCurrentDataNetworkTypeForSubscription(
6891                sub_id)))
6892    if not result:
6893        get_telephony_signal_strength(ad)
6894    return result
6895
6896
6897def wait_for_network_rat(log,
6898                         ad,
6899                         rat_family,
6900                         max_wait_time=MAX_WAIT_TIME_NW_SELECTION,
6901                         voice_or_data=None):
6902    return wait_for_network_rat_for_subscription(
6903        log, ad, ad.droid.subscriptionGetDefaultSubId(), rat_family,
6904        max_wait_time, voice_or_data)
6905
6906
6907def wait_for_network_rat_for_subscription(
6908        log,
6909        ad,
6910        sub_id,
6911        rat_family,
6912        max_wait_time=MAX_WAIT_TIME_NW_SELECTION,
6913        voice_or_data=None):
6914    return _wait_for_droid_in_state_for_subscription(
6915        log, ad, sub_id, max_wait_time,
6916        is_droid_in_rat_family_for_subscription, rat_family, voice_or_data)
6917
6918
6919def wait_for_not_network_rat(log,
6920                             ad,
6921                             rat_family,
6922                             max_wait_time=MAX_WAIT_TIME_NW_SELECTION,
6923                             voice_or_data=None):
6924    return wait_for_not_network_rat_for_subscription(
6925        log, ad, ad.droid.subscriptionGetDefaultSubId(), rat_family,
6926        max_wait_time, voice_or_data)
6927
6928
6929def wait_for_not_network_rat_for_subscription(
6930        log,
6931        ad,
6932        sub_id,
6933        rat_family,
6934        max_wait_time=MAX_WAIT_TIME_NW_SELECTION,
6935        voice_or_data=None):
6936    return _wait_for_droid_in_state_for_subscription(
6937        log, ad, sub_id, max_wait_time,
6938        lambda log, ad, sub_id, *args, **kwargs: not is_droid_in_rat_family_for_subscription(log, ad, sub_id, rat_family, voice_or_data)
6939    )
6940
6941
6942def wait_for_preferred_network(log,
6943                               ad,
6944                               network_preference,
6945                               max_wait_time=MAX_WAIT_TIME_NW_SELECTION,
6946                               voice_or_data=None):
6947    return wait_for_preferred_network_for_subscription(
6948        log, ad, ad.droid.subscriptionGetDefaultSubId(), network_preference,
6949        max_wait_time, voice_or_data)
6950
6951
6952def wait_for_preferred_network_for_subscription(
6953        log,
6954        ad,
6955        sub_id,
6956        network_preference,
6957        max_wait_time=MAX_WAIT_TIME_NW_SELECTION,
6958        voice_or_data=None):
6959    rat_family_list = rat_families_for_network_preference(network_preference)
6960    return _wait_for_droid_in_state_for_subscription(
6961        log, ad, sub_id, max_wait_time,
6962        is_droid_in_rat_family_list_for_subscription, rat_family_list,
6963        voice_or_data)
6964
6965
6966def wait_for_network_generation(log,
6967                                ad,
6968                                generation,
6969                                max_wait_time=MAX_WAIT_TIME_NW_SELECTION,
6970                                voice_or_data=None):
6971    return wait_for_network_generation_for_subscription(
6972        log, ad, ad.droid.subscriptionGetDefaultSubId(), generation,
6973        max_wait_time, voice_or_data)
6974
6975
6976def wait_for_network_generation_for_subscription(
6977        log,
6978        ad,
6979        sub_id,
6980        generation,
6981        max_wait_time=MAX_WAIT_TIME_NW_SELECTION,
6982        voice_or_data=None):
6983    return _wait_for_droid_in_state_for_subscription(
6984        log, ad, sub_id, max_wait_time,
6985        is_droid_in_network_generation_for_subscription, generation,
6986        voice_or_data)
6987
6988
6989def is_droid_in_rat_family(log, ad, rat_family, voice_or_data=None):
6990    return is_droid_in_rat_family_for_subscription(
6991        log, ad, ad.droid.subscriptionGetDefaultSubId(), rat_family,
6992        voice_or_data)
6993
6994
6995def is_droid_in_rat_family_for_subscription(log,
6996                                            ad,
6997                                            sub_id,
6998                                            rat_family,
6999                                            voice_or_data=None):
7000    return is_droid_in_rat_family_list_for_subscription(
7001        log, ad, sub_id, [rat_family], voice_or_data)
7002
7003
7004def is_droid_in_rat_familiy_list(log, ad, rat_family_list, voice_or_data=None):
7005    return is_droid_in_rat_family_list_for_subscription(
7006        log, ad, ad.droid.subscriptionGetDefaultSubId(), rat_family_list,
7007        voice_or_data)
7008
7009
7010def is_droid_in_rat_family_list_for_subscription(log,
7011                                                 ad,
7012                                                 sub_id,
7013                                                 rat_family_list,
7014                                                 voice_or_data=None):
7015    service_list = [NETWORK_SERVICE_DATA, NETWORK_SERVICE_VOICE]
7016    if voice_or_data:
7017        service_list = [voice_or_data]
7018
7019    for service in service_list:
7020        nw_rat = get_network_rat_for_subscription(log, ad, sub_id, service)
7021        if nw_rat == RAT_UNKNOWN or not is_valid_rat(nw_rat):
7022            continue
7023        if rat_family_from_rat(nw_rat) in rat_family_list:
7024            return True
7025    return False
7026
7027
7028def is_droid_in_network_generation(log, ad, nw_gen, voice_or_data):
7029    """Checks if a droid in expected network generation ("2g", "3g" or "4g").
7030
7031    Args:
7032        log: log object.
7033        ad: android device.
7034        nw_gen: expected generation "4g", "3g", "2g".
7035        voice_or_data: check voice network generation or data network generation
7036            This parameter is optional. If voice_or_data is None, then if
7037            either voice or data in expected generation, function will return True.
7038
7039    Returns:
7040        True if droid in expected network generation. Otherwise False.
7041    """
7042    return is_droid_in_network_generation_for_subscription(
7043        log, ad, ad.droid.subscriptionGetDefaultSubId(), nw_gen, voice_or_data)
7044
7045
7046def is_droid_in_network_generation_for_subscription(log, ad, sub_id, nw_gen,
7047                                                    voice_or_data):
7048    """Checks if a droid in expected network generation ("2g", "3g" or "4g").
7049
7050    Args:
7051        log: log object.
7052        ad: android device.
7053        nw_gen: expected generation "4g", "3g", "2g".
7054        voice_or_data: check voice network generation or data network generation
7055            This parameter is optional. If voice_or_data is None, then if
7056            either voice or data in expected generation, function will return True.
7057
7058    Returns:
7059        True if droid in expected network generation. Otherwise False.
7060    """
7061    service_list = [NETWORK_SERVICE_DATA, NETWORK_SERVICE_VOICE]
7062
7063    if voice_or_data:
7064        service_list = [voice_or_data]
7065
7066    for service in service_list:
7067        nw_rat = get_network_rat_for_subscription(log, ad, sub_id, service)
7068        ad.log.info("%s network rat is %s", service, nw_rat)
7069        if nw_rat == RAT_UNKNOWN or not is_valid_rat(nw_rat):
7070            continue
7071
7072        if rat_generation_from_rat(nw_rat) == nw_gen:
7073            ad.log.info("%s network rat %s is expected %s", service, nw_rat,
7074                        nw_gen)
7075            return True
7076        else:
7077            ad.log.info("%s network rat %s is %s, does not meet expected %s",
7078                        service, nw_rat, rat_generation_from_rat(nw_rat),
7079                        nw_gen)
7080            return False
7081
7082    return False
7083
7084
7085def get_network_rat(log, ad, voice_or_data):
7086    """Get current network type (Voice network type, or data network type)
7087       for default subscription id
7088
7089    Args:
7090        ad: Android Device Object
7091        voice_or_data: Input parameter indicating to get voice network type or
7092            data network type.
7093
7094    Returns:
7095        Current voice/data network type.
7096    """
7097    return get_network_rat_for_subscription(
7098        log, ad, ad.droid.subscriptionGetDefaultSubId(), voice_or_data)
7099
7100
7101def get_network_rat_for_subscription(log, ad, sub_id, voice_or_data):
7102    """Get current network type (Voice network type, or data network type)
7103       for specified subscription id
7104
7105    Args:
7106        ad: Android Device Object
7107        sub_id: subscription ID
7108        voice_or_data: Input parameter indicating to get voice network type or
7109            data network type.
7110
7111    Returns:
7112        Current voice/data network type.
7113    """
7114    if voice_or_data == NETWORK_SERVICE_VOICE:
7115        ret_val = ad.droid.telephonyGetCurrentVoiceNetworkTypeForSubscription(
7116            sub_id)
7117    elif voice_or_data == NETWORK_SERVICE_DATA:
7118        ret_val = ad.droid.telephonyGetCurrentDataNetworkTypeForSubscription(
7119            sub_id)
7120    else:
7121        ret_val = ad.droid.telephonyGetNetworkTypeForSubscription(sub_id)
7122
7123    if ret_val is None:
7124        log.error("get_network_rat(): Unexpected null return value")
7125        return RAT_UNKNOWN
7126    else:
7127        return ret_val
7128
7129
7130def get_network_gen(log, ad, voice_or_data):
7131    """Get current network generation string (Voice network type, or data network type)
7132
7133    Args:
7134        ad: Android Device Object
7135        voice_or_data: Input parameter indicating to get voice network generation
7136            or data network generation.
7137
7138    Returns:
7139        Current voice/data network generation.
7140    """
7141    return get_network_gen_for_subscription(
7142        log, ad, ad.droid.subscriptionGetDefaultSubId(), voice_or_data)
7143
7144
7145def get_network_gen_for_subscription(log, ad, sub_id, voice_or_data):
7146    """Get current network generation string (Voice network type, or data network type)
7147
7148    Args:
7149        ad: Android Device Object
7150        voice_or_data: Input parameter indicating to get voice network generation
7151            or data network generation.
7152
7153    Returns:
7154        Current voice/data network generation.
7155    """
7156    try:
7157        return rat_generation_from_rat(
7158            get_network_rat_for_subscription(log, ad, sub_id, voice_or_data))
7159    except KeyError as e:
7160        ad.log.error("KeyError %s", e)
7161        return GEN_UNKNOWN
7162
7163
7164def check_voice_mail_count(log, ad, voice_mail_count_before,
7165                           voice_mail_count_after):
7166    """function to check if voice mail count is correct after leaving a new voice message.
7167    """
7168    return get_voice_mail_count_check_function(get_operator_name(log, ad))(
7169        voice_mail_count_before, voice_mail_count_after)
7170
7171
7172def get_voice_mail_number(log, ad):
7173    """function to get the voice mail number
7174    """
7175    voice_mail_number = get_voice_mail_check_number(get_operator_name(log, ad))
7176    if voice_mail_number is None:
7177        return get_phone_number(log, ad)
7178    return voice_mail_number
7179
7180
7181def ensure_phones_idle(log, ads, max_time=MAX_WAIT_TIME_CALL_DROP):
7182    """Ensure ads idle (not in call).
7183    """
7184    result = True
7185    for ad in ads:
7186        if not ensure_phone_idle(log, ad, max_time=max_time):
7187            result = False
7188    return result
7189
7190
7191def ensure_phone_idle(log, ad, max_time=MAX_WAIT_TIME_CALL_DROP, retry=2):
7192    """Ensure ad idle (not in call).
7193    """
7194    while ad.droid.telecomIsInCall() and retry > 0:
7195        ad.droid.telecomEndCall()
7196        time.sleep(3)
7197        retry -= 1
7198    if not wait_for_droid_not_in_call(log, ad, max_time=max_time):
7199        ad.log.error("Failed to end call")
7200        return False
7201    return True
7202
7203
7204def ensure_phone_subscription(log, ad):
7205    """Ensure Phone Subscription.
7206    """
7207    #check for sim and service
7208    duration = 0
7209    while duration < MAX_WAIT_TIME_NW_SELECTION:
7210        subInfo = ad.droid.subscriptionGetAllSubInfoList()
7211        if subInfo and len(subInfo) >= 1:
7212            ad.log.debug("Find valid subcription %s", subInfo)
7213            break
7214        else:
7215            ad.log.info("Did not find any subscription")
7216            time.sleep(5)
7217            duration += 5
7218    else:
7219        ad.log.error("Unable to find a valid subscription!")
7220        return False
7221    while duration < MAX_WAIT_TIME_NW_SELECTION:
7222        data_sub_id = ad.droid.subscriptionGetDefaultDataSubId()
7223        voice_sub_id = ad.droid.subscriptionGetDefaultVoiceSubId()
7224        if data_sub_id > INVALID_SUB_ID or voice_sub_id > INVALID_SUB_ID:
7225            ad.log.debug("Find valid voice or data sub id")
7226            break
7227        else:
7228            ad.log.info("Did not find valid data or voice sub id")
7229            time.sleep(5)
7230            duration += 5
7231    else:
7232        ad.log.error("Unable to find valid data or voice sub id")
7233        return False
7234    while duration < MAX_WAIT_TIME_NW_SELECTION:
7235        data_sub_id = ad.droid.subscriptionGetDefaultDataSubId()
7236        if data_sub_id > INVALID_SUB_ID:
7237            data_rat = get_network_rat_for_subscription(
7238                log, ad, data_sub_id, NETWORK_SERVICE_DATA)
7239        else:
7240            data_rat = RAT_UNKNOWN
7241        if voice_sub_id > INVALID_SUB_ID:
7242            voice_rat = get_network_rat_for_subscription(
7243                log, ad, voice_sub_id, NETWORK_SERVICE_VOICE)
7244        else:
7245            voice_rat = RAT_UNKNOWN
7246        if data_rat != RAT_UNKNOWN or voice_rat != RAT_UNKNOWN:
7247            ad.log.info("Data sub_id %s in %s, voice sub_id %s in %s",
7248                        data_sub_id, data_rat, voice_sub_id, voice_rat)
7249            return True
7250        else:
7251            ad.log.info("Did not attach for data or voice service")
7252            time.sleep(5)
7253            duration += 5
7254    else:
7255        ad.log.error("Did not attach for voice or data service")
7256        return False
7257
7258
7259def ensure_phone_default_state(log, ad, check_subscription=True, retry=2):
7260    """Ensure ad in default state.
7261    Phone not in call.
7262    Phone have no stored WiFi network and WiFi disconnected.
7263    Phone not in airplane mode.
7264    """
7265    result = True
7266    if not toggle_airplane_mode(log, ad, False, False):
7267        ad.log.error("Fail to turn off airplane mode")
7268        result = False
7269    try:
7270        set_wifi_to_default(log, ad)
7271        while ad.droid.telecomIsInCall() and retry > 0:
7272            ad.droid.telecomEndCall()
7273            time.sleep(3)
7274            retry -= 1
7275        if not wait_for_droid_not_in_call(log, ad):
7276            ad.log.error("Failed to end call")
7277        #ad.droid.telephonyFactoryReset()
7278        data_roaming = getattr(ad, 'roaming', False)
7279        if get_cell_data_roaming_state_by_adb(ad) != data_roaming:
7280            set_cell_data_roaming_state_by_adb(ad, data_roaming)
7281        #remove_mobile_data_usage_limit(ad)
7282        if not wait_for_not_network_rat(
7283                log, ad, RAT_FAMILY_WLAN, voice_or_data=NETWORK_SERVICE_DATA):
7284            ad.log.error("%s still in %s", NETWORK_SERVICE_DATA,
7285                         RAT_FAMILY_WLAN)
7286            result = False
7287
7288        if check_subscription and not ensure_phone_subscription(log, ad):
7289            ad.log.error("Unable to find a valid subscription!")
7290            result = False
7291    except Exception as e:
7292        ad.log.error("%s failure, toggle APM instead", e)
7293        toggle_airplane_mode_by_adb(log, ad, True)
7294        toggle_airplane_mode_by_adb(log, ad, False)
7295        ad.send_keycode("ENDCALL")
7296        ad.adb.shell("settings put global wfc_ims_enabled 0")
7297        ad.adb.shell("settings put global mobile_data 1")
7298
7299    return result
7300
7301
7302def ensure_phones_default_state(log, ads, check_subscription=True):
7303    """Ensure ads in default state.
7304    Phone not in call.
7305    Phone have no stored WiFi network and WiFi disconnected.
7306    Phone not in airplane mode.
7307
7308    Returns:
7309        True if all steps of restoring default state succeed.
7310        False if any of the steps to restore default state fails.
7311    """
7312    tasks = []
7313    for ad in ads:
7314        tasks.append((ensure_phone_default_state, (log, ad,
7315                                                   check_subscription)))
7316    if not multithread_func(log, tasks):
7317        log.error("Ensure_phones_default_state Fail.")
7318        return False
7319    return True
7320
7321
7322def check_is_wifi_connected(log, ad, wifi_ssid):
7323    """Check if ad is connected to wifi wifi_ssid.
7324
7325    Args:
7326        log: Log object.
7327        ad: Android device object.
7328        wifi_ssid: WiFi network SSID.
7329
7330    Returns:
7331        True if wifi is connected to wifi_ssid
7332        False if wifi is not connected to wifi_ssid
7333    """
7334    wifi_info = ad.droid.wifiGetConnectionInfo()
7335    if wifi_info["supplicant_state"] == "completed" and wifi_info["SSID"] == wifi_ssid:
7336        ad.log.info("Wifi is connected to %s", wifi_ssid)
7337        ad.on_mobile_data = False
7338        return True
7339    else:
7340        ad.log.info("Wifi is not connected to %s", wifi_ssid)
7341        ad.log.debug("Wifi connection_info=%s", wifi_info)
7342        ad.on_mobile_data = True
7343        return False
7344
7345
7346def ensure_wifi_connected(log, ad, wifi_ssid, wifi_pwd=None, retries=3, apm=False):
7347    """Ensure ad connected to wifi on network wifi_ssid.
7348
7349    Args:
7350        log: Log object.
7351        ad: Android device object.
7352        wifi_ssid: WiFi network SSID.
7353        wifi_pwd: optional secure network password.
7354        retries: the number of retries.
7355
7356    Returns:
7357        True if wifi is connected to wifi_ssid
7358        False if wifi is not connected to wifi_ssid
7359    """
7360    if not toggle_airplane_mode(log, ad, apm, strict_checking=False):
7361        return False
7362
7363    network = {WIFI_SSID_KEY: wifi_ssid}
7364    if wifi_pwd:
7365        network[WIFI_PWD_KEY] = wifi_pwd
7366    for i in range(retries):
7367        if not ad.droid.wifiCheckState():
7368            ad.log.info("Wifi state is down. Turn on Wifi")
7369            ad.droid.wifiToggleState(True)
7370        if check_is_wifi_connected(log, ad, wifi_ssid):
7371            ad.log.info("Wifi is connected to %s", wifi_ssid)
7372            return verify_internet_connection(log, ad, retries=3)
7373        else:
7374            ad.log.info("Connecting to wifi %s", wifi_ssid)
7375            try:
7376                ad.droid.wifiConnectByConfig(network)
7377            except Exception:
7378                ad.log.info("Connecting to wifi by wifiConnect instead")
7379                ad.droid.wifiConnect(network)
7380            time.sleep(20)
7381            if check_is_wifi_connected(log, ad, wifi_ssid):
7382                ad.log.info("Connected to Wifi %s", wifi_ssid)
7383                return verify_internet_connection(log, ad, retries=3)
7384    ad.log.info("Fail to connected to wifi %s", wifi_ssid)
7385    return False
7386
7387
7388def forget_all_wifi_networks(log, ad):
7389    """Forget all stored wifi network information
7390
7391    Args:
7392        log: log object
7393        ad: AndroidDevice object
7394
7395    Returns:
7396        boolean success (True) or failure (False)
7397    """
7398    if not ad.droid.wifiGetConfiguredNetworks():
7399        ad.on_mobile_data = True
7400        return True
7401    try:
7402        old_state = ad.droid.wifiCheckState()
7403        wifi_test_utils.reset_wifi(ad)
7404        wifi_toggle_state(log, ad, old_state)
7405    except Exception as e:
7406        log.error("forget_all_wifi_networks with exception: %s", e)
7407        return False
7408    ad.on_mobile_data = True
7409    return True
7410
7411
7412def wifi_reset(log, ad, disable_wifi=True):
7413    """Forget all stored wifi networks and (optionally) disable WiFi
7414
7415    Args:
7416        log: log object
7417        ad: AndroidDevice object
7418        disable_wifi: boolean to disable wifi, defaults to True
7419    Returns:
7420        boolean success (True) or failure (False)
7421    """
7422    if not forget_all_wifi_networks(log, ad):
7423        ad.log.error("Unable to forget all networks")
7424        return False
7425    if not wifi_toggle_state(log, ad, not disable_wifi):
7426        ad.log.error("Failed to toggle WiFi state to %s!", not disable_wifi)
7427        return False
7428    return True
7429
7430
7431def set_wifi_to_default(log, ad):
7432    """Set wifi to default state (Wifi disabled and no configured network)
7433
7434    Args:
7435        log: log object
7436        ad: AndroidDevice object
7437
7438    Returns:
7439        boolean success (True) or failure (False)
7440    """
7441    ad.droid.wifiFactoryReset()
7442    ad.droid.wifiToggleState(False)
7443    ad.on_mobile_data = True
7444
7445
7446def wifi_toggle_state(log, ad, state, retries=3):
7447    """Toggle the WiFi State
7448
7449    Args:
7450        log: log object
7451        ad: AndroidDevice object
7452        state: True, False, or None
7453
7454    Returns:
7455        boolean success (True) or failure (False)
7456    """
7457    for i in range(retries):
7458        if wifi_test_utils.wifi_toggle_state(ad, state, assert_on_fail=False):
7459            ad.on_mobile_data = not state
7460            return True
7461        time.sleep(WAIT_TIME_BETWEEN_STATE_CHECK)
7462    return False
7463
7464
7465def start_wifi_tethering(log, ad, ssid, password, ap_band=None):
7466    """Start a Tethering Session
7467
7468    Args:
7469        log: log object
7470        ad: AndroidDevice object
7471        ssid: the name of the WiFi network
7472        password: optional password, used for secure networks.
7473        ap_band=DEPRECATED specification of 2G or 5G tethering
7474    Returns:
7475        boolean success (True) or failure (False)
7476    """
7477    return wifi_test_utils._assert_on_fail_handler(
7478        wifi_test_utils.start_wifi_tethering,
7479        False,
7480        ad,
7481        ssid,
7482        password,
7483        band=ap_band)
7484
7485
7486def stop_wifi_tethering(log, ad):
7487    """Stop a Tethering Session
7488
7489    Args:
7490        log: log object
7491        ad: AndroidDevice object
7492    Returns:
7493        boolean success (True) or failure (False)
7494    """
7495    return wifi_test_utils._assert_on_fail_handler(
7496        wifi_test_utils.stop_wifi_tethering, False, ad)
7497
7498
7499def reset_preferred_network_type_to_allowable_range(log, ad):
7500    """If preferred network type is not in allowable range, reset to GEN_4G
7501    preferred network type.
7502
7503    Args:
7504        log: log object
7505        ad: android device object
7506
7507    Returns:
7508        None
7509    """
7510    for sub_id, sub_info in ad.telephony["subscription"].items():
7511        current_preference = \
7512            ad.droid.telephonyGetPreferredNetworkTypesForSubscription(sub_id)
7513        ad.log.debug("sub_id network preference is %s", current_preference)
7514        try:
7515            if current_preference not in get_allowable_network_preference(
7516                    sub_info["operator"], sub_info["phone_type"]):
7517                network_preference = network_preference_for_generation(
7518                    GEN_4G, sub_info["operator"], sub_info["phone_type"])
7519                ad.droid.telephonySetPreferredNetworkTypesForSubscription(
7520                    network_preference, sub_id)
7521        except KeyError:
7522            pass
7523
7524
7525def task_wrapper(task):
7526    """Task wrapper for multithread_func
7527
7528    Args:
7529        task[0]: function to be wrapped.
7530        task[1]: function args.
7531
7532    Returns:
7533        Return value of wrapped function call.
7534    """
7535    func = task[0]
7536    params = task[1]
7537    return func(*params)
7538
7539
7540def run_multithread_func_async(log, task):
7541    """Starts a multi-threaded function asynchronously.
7542
7543    Args:
7544        log: log object.
7545        task: a task to be executed in parallel.
7546
7547    Returns:
7548        Future object representing the execution of the task.
7549    """
7550    executor = concurrent.futures.ThreadPoolExecutor(max_workers=1)
7551    try:
7552        future_object = executor.submit(task_wrapper, task)
7553    except Exception as e:
7554        log.error("Exception error %s", e)
7555        raise
7556    return future_object
7557
7558
7559def run_multithread_func(log, tasks):
7560    """Run multi-thread functions and return results.
7561
7562    Args:
7563        log: log object.
7564        tasks: a list of tasks to be executed in parallel.
7565
7566    Returns:
7567        results for tasks.
7568    """
7569    MAX_NUMBER_OF_WORKERS = 10
7570    number_of_workers = min(MAX_NUMBER_OF_WORKERS, len(tasks))
7571    executor = concurrent.futures.ThreadPoolExecutor(
7572        max_workers=number_of_workers)
7573    if not log: log = logging
7574    try:
7575        results = list(executor.map(task_wrapper, tasks))
7576    except Exception as e:
7577        log.error("Exception error %s", e)
7578        raise
7579    executor.shutdown()
7580    if log:
7581        log.info("multithread_func %s result: %s",
7582                 [task[0].__name__ for task in tasks], results)
7583    return results
7584
7585
7586def multithread_func(log, tasks):
7587    """Multi-thread function wrapper.
7588
7589    Args:
7590        log: log object.
7591        tasks: tasks to be executed in parallel.
7592
7593    Returns:
7594        True if all tasks return True.
7595        False if any task return False.
7596    """
7597    results = run_multithread_func(log, tasks)
7598    for r in results:
7599        if not r:
7600            return False
7601    return True
7602
7603
7604def multithread_func_and_check_results(log, tasks, expected_results):
7605    """Multi-thread function wrapper.
7606
7607    Args:
7608        log: log object.
7609        tasks: tasks to be executed in parallel.
7610        expected_results: check if the results from tasks match expected_results.
7611
7612    Returns:
7613        True if expected_results are met.
7614        False if expected_results are not met.
7615    """
7616    return_value = True
7617    results = run_multithread_func(log, tasks)
7618    log.info("multithread_func result: %s, expecting %s", results,
7619             expected_results)
7620    for task, result, expected_result in zip(tasks, results, expected_results):
7621        if result != expected_result:
7622            logging.info("Result for task %s is %s, expecting %s", task[0],
7623                         result, expected_result)
7624            return_value = False
7625    return return_value
7626
7627
7628def set_phone_screen_on(log, ad, screen_on_time=MAX_SCREEN_ON_TIME):
7629    """Set phone screen on time.
7630
7631    Args:
7632        log: Log object.
7633        ad: Android device object.
7634        screen_on_time: screen on time.
7635            This is optional, default value is MAX_SCREEN_ON_TIME.
7636    Returns:
7637        True if set successfully.
7638    """
7639    ad.droid.setScreenTimeout(screen_on_time)
7640    return screen_on_time == ad.droid.getScreenTimeout()
7641
7642
7643def set_phone_silent_mode(log, ad, silent_mode=True):
7644    """Set phone silent mode.
7645
7646    Args:
7647        log: Log object.
7648        ad: Android device object.
7649        silent_mode: set phone silent or not.
7650            This is optional, default value is True (silent mode on).
7651    Returns:
7652        True if set successfully.
7653    """
7654    ad.droid.toggleRingerSilentMode(silent_mode)
7655    ad.droid.setMediaVolume(0)
7656    ad.droid.setVoiceCallVolume(0)
7657    ad.droid.setAlarmVolume(0)
7658    ad.adb.ensure_root()
7659    ad.adb.shell("setprop ro.audio.silent 1", ignore_status=True)
7660    ad.adb.shell("cmd notification set_dnd on", ignore_status=True)
7661    return silent_mode == ad.droid.checkRingerSilentMode()
7662
7663
7664def set_preferred_network_mode_pref(log,
7665                                    ad,
7666                                    sub_id,
7667                                    network_preference,
7668                                    timeout=WAIT_TIME_ANDROID_STATE_SETTLING):
7669    """Set Preferred Network Mode for Sub_id
7670    Args:
7671        log: Log object.
7672        ad: Android device object.
7673        sub_id: Subscription ID.
7674        network_preference: Network Mode Type
7675    """
7676    begin_time = get_device_epoch_time(ad)
7677    if ad.droid.telephonyGetPreferredNetworkTypesForSubscription(
7678            sub_id) == network_preference:
7679        ad.log.info("Current ModePref for Sub %s is in %s", sub_id,
7680                    network_preference)
7681        return True
7682    ad.log.info("Setting ModePref to %s for Sub %s", network_preference,
7683                sub_id)
7684    while timeout >= 0:
7685        if ad.droid.telephonySetPreferredNetworkTypesForSubscription(
7686                network_preference, sub_id):
7687            return True
7688        time.sleep(WAIT_TIME_BETWEEN_STATE_CHECK)
7689        timeout = timeout - WAIT_TIME_BETWEEN_STATE_CHECK
7690    error_msg = "Failed to set sub_id %s PreferredNetworkType to %s" % (
7691        sub_id, network_preference)
7692    search_results = ad.search_logcat(
7693        "REQUEST_SET_PREFERRED_NETWORK_TYPE error", begin_time=begin_time)
7694    if search_results:
7695        log_message = search_results[-1]["log_message"]
7696        if "DEVICE_IN_USE" in log_message:
7697            error_msg = "%s due to DEVICE_IN_USE" % error_msg
7698        else:
7699            error_msg = "%s due to %s" % (error_msg, log_message)
7700    ad.log.error(error_msg)
7701    return False
7702
7703
7704def set_preferred_subid_for_sms(log, ad, sub_id):
7705    """set subscription id for SMS
7706
7707    Args:
7708        log: Log object.
7709        ad: Android device object.
7710        sub_id :Subscription ID.
7711
7712    """
7713    ad.log.info("Setting subscription %s as preferred SMS SIM", sub_id)
7714    ad.droid.subscriptionSetDefaultSmsSubId(sub_id)
7715    # Wait to make sure settings take effect
7716    time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
7717    return sub_id == ad.droid.subscriptionGetDefaultSmsSubId()
7718
7719
7720def set_preferred_subid_for_data(log, ad, sub_id):
7721    """set subscription id for data
7722
7723    Args:
7724        log: Log object.
7725        ad: Android device object.
7726        sub_id :Subscription ID.
7727
7728    """
7729    ad.log.info("Setting subscription %s as preferred Data SIM", sub_id)
7730    ad.droid.subscriptionSetDefaultDataSubId(sub_id)
7731    time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
7732    # Wait to make sure settings take effect
7733    # Data SIM change takes around 1 min
7734    # Check whether data has changed to selected sim
7735    if not wait_for_data_connection(log, ad, True,
7736                                    MAX_WAIT_TIME_DATA_SUB_CHANGE):
7737        log.error("Data Connection failed - Not able to switch Data SIM")
7738        return False
7739    return True
7740
7741
7742def set_preferred_subid_for_voice(log, ad, sub_id):
7743    """set subscription id for voice
7744
7745    Args:
7746        log: Log object.
7747        ad: Android device object.
7748        sub_id :Subscription ID.
7749
7750    """
7751    ad.log.info("Setting subscription %s as Voice SIM", sub_id)
7752    ad.droid.subscriptionSetDefaultVoiceSubId(sub_id)
7753    ad.droid.telecomSetUserSelectedOutgoingPhoneAccountBySubId(sub_id)
7754    # Wait to make sure settings take effect
7755    time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
7756    return True
7757
7758
7759def set_call_state_listen_level(log, ad, value, sub_id):
7760    """Set call state listen level for subscription id.
7761
7762    Args:
7763        log: Log object.
7764        ad: Android device object.
7765        value: True or False
7766        sub_id :Subscription ID.
7767
7768    Returns:
7769        True or False
7770    """
7771    if sub_id == INVALID_SUB_ID:
7772        log.error("Invalid Subscription ID")
7773        return False
7774    ad.droid.telephonyAdjustPreciseCallStateListenLevelForSubscription(
7775        "Foreground", value, sub_id)
7776    ad.droid.telephonyAdjustPreciseCallStateListenLevelForSubscription(
7777        "Ringing", value, sub_id)
7778    ad.droid.telephonyAdjustPreciseCallStateListenLevelForSubscription(
7779        "Background", value, sub_id)
7780    return True
7781
7782
7783def setup_sim(log, ad, sub_id, voice=False, sms=False, data=False):
7784    """set subscription id for voice, sms and data
7785
7786    Args:
7787        log: Log object.
7788        ad: Android device object.
7789        sub_id :Subscription ID.
7790        voice: True if to set subscription as default voice subscription
7791        sms: True if to set subscription as default sms subscription
7792        data: True if to set subscription as default data subscription
7793
7794    """
7795    if sub_id == INVALID_SUB_ID:
7796        log.error("Invalid Subscription ID")
7797        return False
7798    else:
7799        if voice:
7800            if not set_preferred_subid_for_voice(log, ad, sub_id):
7801                return False
7802        if sms:
7803            if not set_preferred_subid_for_sms(log, ad, sub_id):
7804                return False
7805        if data:
7806            if not set_preferred_subid_for_data(log, ad, sub_id):
7807                return False
7808    return True
7809
7810
7811def is_event_match(event, field, value):
7812    """Return if <field> in "event" match <value> or not.
7813
7814    Args:
7815        event: event to test. This event need to have <field>.
7816        field: field to match.
7817        value: value to match.
7818
7819    Returns:
7820        True if <field> in "event" match <value>.
7821        False otherwise.
7822    """
7823    return is_event_match_for_list(event, field, [value])
7824
7825
7826def is_event_match_for_list(event, field, value_list):
7827    """Return if <field> in "event" match any one of the value
7828        in "value_list" or not.
7829
7830    Args:
7831        event: event to test. This event need to have <field>.
7832        field: field to match.
7833        value_list: a list of value to match.
7834
7835    Returns:
7836        True if <field> in "event" match one of the value in "value_list".
7837        False otherwise.
7838    """
7839    try:
7840        value_in_event = event['data'][field]
7841    except KeyError:
7842        return False
7843    for value in value_list:
7844        if value_in_event == value:
7845            return True
7846    return False
7847
7848
7849def is_network_call_back_event_match(event, network_callback_id,
7850                                     network_callback_event):
7851    try:
7852        return (
7853            (network_callback_id == event['data'][NetworkCallbackContainer.ID])
7854            and (network_callback_event == event['data']
7855                 [NetworkCallbackContainer.NETWORK_CALLBACK_EVENT]))
7856    except KeyError:
7857        return False
7858
7859
7860def is_build_id(log, ad, build_id):
7861    """Return if ad's build id is the same as input parameter build_id.
7862
7863    Args:
7864        log: log object.
7865        ad: android device object.
7866        build_id: android build id.
7867
7868    Returns:
7869        True if ad's build id is the same as input parameter build_id.
7870        False otherwise.
7871    """
7872    actual_bid = ad.droid.getBuildID()
7873
7874    ad.log.info("BUILD DISPLAY: %s", ad.droid.getBuildDisplay())
7875    #In case we want to log more stuff/more granularity...
7876    #log.info("{} BUILD ID:{} ".format(ad.serial, ad.droid.getBuildID()))
7877    #log.info("{} BUILD FINGERPRINT: {} "
7878    # .format(ad.serial), ad.droid.getBuildFingerprint())
7879    #log.info("{} BUILD TYPE: {} "
7880    # .format(ad.serial), ad.droid.getBuildType())
7881    #log.info("{} BUILD NUMBER: {} "
7882    # .format(ad.serial), ad.droid.getBuildNumber())
7883    if actual_bid.upper() != build_id.upper():
7884        ad.log.error("%s: Incorrect Build ID", ad.model)
7885        return False
7886    return True
7887
7888
7889def is_uri_equivalent(uri1, uri2):
7890    """Check whether two input uris match or not.
7891
7892    Compare Uris.
7893        If Uris are tel URI, it will only take the digit part
7894        and compare as phone number.
7895        Else, it will just do string compare.
7896
7897    Args:
7898        uri1: 1st uri to be compared.
7899        uri2: 2nd uri to be compared.
7900
7901    Returns:
7902        True if two uris match. Otherwise False.
7903    """
7904
7905    #If either is None/empty we return false
7906    if not uri1 or not uri2:
7907        return False
7908
7909    try:
7910        if uri1.startswith('tel:') and uri2.startswith('tel:'):
7911            uri1_number = get_number_from_tel_uri(uri1)
7912            uri2_number = get_number_from_tel_uri(uri2)
7913            return check_phone_number_match(uri1_number, uri2_number)
7914        else:
7915            return uri1 == uri2
7916    except AttributeError as e:
7917        return False
7918
7919
7920def get_call_uri(ad, call_id):
7921    """Get call's uri field.
7922
7923    Get Uri for call_id in ad.
7924
7925    Args:
7926        ad: android device object.
7927        call_id: the call id to get Uri from.
7928
7929    Returns:
7930        call's Uri if call is active and have uri field. None otherwise.
7931    """
7932    try:
7933        call_detail = ad.droid.telecomCallGetDetails(call_id)
7934        return call_detail["Handle"]["Uri"]
7935    except:
7936        return None
7937
7938
7939def get_number_from_tel_uri(uri):
7940    """Get Uri number from tel uri
7941
7942    Args:
7943        uri: input uri
7944
7945    Returns:
7946        If input uri is tel uri, return the number part.
7947        else return None.
7948    """
7949    if uri.startswith('tel:'):
7950        uri_number = ''.join(
7951            i for i in urllib.parse.unquote(uri) if i.isdigit())
7952        return uri_number
7953    else:
7954        return None
7955
7956
7957def find_qxdm_log_mask(ad, mask="default.cfg"):
7958    """Find QXDM logger mask."""
7959    if "/" not in mask:
7960        # Call nexuslogger to generate log mask
7961        start_nexuslogger(ad)
7962        # Find the log mask path
7963        for path in (DEFAULT_QXDM_LOG_PATH, "/data/diag_logs",
7964                     "/vendor/etc/mdlog/", "/vendor/etc/modem/"):
7965            out = ad.adb.shell(
7966                "find %s -type f -iname %s" % (path, mask), ignore_status=True)
7967            if out and "No such" not in out and "Permission denied" not in out:
7968                if path.startswith("/vendor/"):
7969                    setattr(ad, "qxdm_log_path", DEFAULT_QXDM_LOG_PATH)
7970                else:
7971                    setattr(ad, "qxdm_log_path", path)
7972                return out.split("\n")[0]
7973        for mask_file in ("/vendor/etc/mdlog/", "/vendor/etc/modem/"):
7974            if mask in ad.adb.shell("ls %s" % mask_file, ignore_status=True):
7975                setattr(ad, "qxdm_log_path", DEFAULT_QXDM_LOG_PATH)
7976                return "%s/%s" % (mask_file, mask)
7977    else:
7978        out = ad.adb.shell("ls %s" % mask, ignore_status=True)
7979        if out and "No such" not in out:
7980            qxdm_log_path, cfg_name = os.path.split(mask)
7981            setattr(ad, "qxdm_log_path", qxdm_log_path)
7982            return mask
7983    ad.log.warning("Could NOT find QXDM logger mask path for %s", mask)
7984
7985
7986def set_qxdm_logger_command(ad, mask=None):
7987    """Set QXDM logger always on.
7988
7989    Args:
7990        ad: android device object.
7991
7992    """
7993    ## Neet to check if log mask will be generated without starting nexus logger
7994    masks = []
7995    mask_path = None
7996    if mask:
7997        masks = [mask]
7998    masks.extend(["QC_Default.cfg", "default.cfg"])
7999    for mask in masks:
8000        mask_path = find_qxdm_log_mask(ad, mask)
8001        if mask_path: break
8002    if not mask_path:
8003        ad.log.error("Cannot find QXDM mask %s", mask)
8004        ad.qxdm_logger_command = None
8005        return False
8006    else:
8007        ad.log.info("Use QXDM log mask %s", mask_path)
8008        ad.log.debug("qxdm_log_path = %s", ad.qxdm_log_path)
8009        output_path = os.path.join(ad.qxdm_log_path, "logs")
8010        ad.qxdm_logger_command = ("diag_mdlog -f %s -o %s -s 90 -c" %
8011                                  (mask_path, output_path))
8012        return True
8013
8014
8015
8016def start_sdm_logger(ad):
8017    """Start SDM logger."""
8018    if not getattr(ad, "sdm_log", True): return
8019    # Delete existing SDM logs which were created 15 mins prior
8020    ad.sdm_log_path = DEFAULT_SDM_LOG_PATH
8021    file_count = ad.adb.shell(
8022        "find %s -type f -iname sbuff_[0-9]*.sdm* | wc -l" % ad.sdm_log_path)
8023    if int(file_count) > 3:
8024        seconds = 15 * 60
8025        # Remove sdm logs modified more than specified seconds ago
8026        ad.adb.shell(
8027            "find %s -type f -iname sbuff_[0-9]*.sdm* -not -mtime -%ss -delete" %
8028            (ad.sdm_log_path, seconds))
8029    # Disable any modem logging already running
8030    ad.adb.shell("setprop persist.vendor.sys.modem.logging.enable false")
8031    ad.adb.shell('echo "modem_logging_control START -n 10 -s 100 -i 1" > /data/vendor/radio/logs/always-on.conf')
8032    # start logging
8033    cmd = "setprop vendor.sys.modem.logging.enable true"
8034    ad.log.debug("start sdm logging")
8035    ad.adb.shell(cmd, ignore_status=True)
8036    time.sleep(5)
8037
8038
8039def stop_sdm_logger(ad):
8040    """Stop SDM logger."""
8041    cmd = "setprop vendor.sys.modem.logging.enable false"
8042    ad.log.debug("stop sdm logging")
8043    ad.adb.shell(cmd, ignore_status=True)
8044    time.sleep(5)
8045
8046
8047def stop_qxdm_logger(ad):
8048    """Stop QXDM logger."""
8049    for cmd in ("diag_mdlog -k", "killall diag_mdlog"):
8050        output = ad.adb.shell("ps -ef | grep mdlog") or ""
8051        if "diag_mdlog" not in output:
8052            break
8053        ad.log.debug("Kill the existing qxdm process")
8054        ad.adb.shell(cmd, ignore_status=True)
8055        time.sleep(5)
8056
8057
8058def start_qxdm_logger(ad, begin_time=None):
8059    """Start QXDM logger."""
8060    if not getattr(ad, "qxdm_log", True): return
8061    # Delete existing QXDM logs 5 minutes earlier than the begin_time
8062    current_time = get_current_epoch_time()
8063    if getattr(ad, "qxdm_log_path", None):
8064        seconds = None
8065        file_count = ad.adb.shell(
8066            "find %s -type f -iname *.qmdl | wc -l" % ad.qxdm_log_path)
8067        if int(file_count) > 50:
8068            if begin_time:
8069                # if begin_time specified, delete old qxdm logs modified
8070                # 10 minutes before begin time
8071                seconds = int((current_time - begin_time) / 1000.0) + 10 * 60
8072            else:
8073                # if begin_time is not specified, delete old qxdm logs modified
8074                # 15 minutes before current time
8075                seconds = 15 * 60
8076        if seconds:
8077            # Remove qxdm logs modified more than specified seconds ago
8078            ad.adb.shell(
8079                "find %s -type f -iname *.qmdl -not -mtime -%ss -delete" %
8080                (ad.qxdm_log_path, seconds))
8081            ad.adb.shell(
8082                "find %s -type f -iname *.xml -not -mtime -%ss -delete" %
8083                (ad.qxdm_log_path, seconds))
8084    if getattr(ad, "qxdm_logger_command", None):
8085        output = ad.adb.shell("ps -ef | grep mdlog") or ""
8086        if ad.qxdm_logger_command not in output:
8087            ad.log.debug("QXDM logging command %s is not running",
8088                         ad.qxdm_logger_command)
8089            if "diag_mdlog" in output:
8090                # Kill the existing non-matching diag_mdlog process
8091                # Only one diag_mdlog process can be run
8092                stop_qxdm_logger(ad)
8093            ad.log.info("Start QXDM logger")
8094            ad.adb.shell_nb(ad.qxdm_logger_command)
8095            time.sleep(10)
8096        else:
8097            run_time = check_qxdm_logger_run_time(ad)
8098            if run_time < 600:
8099                # the last diag_mdlog started within 10 minutes ago
8100                # no need to restart
8101                return True
8102            if ad.search_logcat(
8103                    "Diag_Lib: diag: In delete_log",
8104                    begin_time=current_time -
8105                    run_time) or not ad.get_file_names(
8106                        ad.qxdm_log_path,
8107                        begin_time=current_time - 600000,
8108                        match_string="*.qmdl"):
8109                # diag_mdlog starts deleting files or no qmdl logs were
8110                # modified in the past 10 minutes
8111                ad.log.debug("Quit existing diag_mdlog and start a new one")
8112                stop_qxdm_logger(ad)
8113                ad.adb.shell_nb(ad.qxdm_logger_command)
8114                time.sleep(10)
8115        return True
8116
8117
8118def disable_qxdm_logger(ad):
8119    for prop in ("persist.sys.modem.diag.mdlog",
8120                 "persist.vendor.sys.modem.diag.mdlog",
8121                 "vendor.sys.modem.diag.mdlog_on"):
8122        if ad.adb.getprop(prop):
8123            ad.adb.shell("setprop %s false" % prop, ignore_status=True)
8124    for apk in ("com.android.nexuslogger", "com.android.pixellogger"):
8125        if ad.is_apk_installed(apk) and ad.is_apk_running(apk):
8126            ad.force_stop_apk(apk)
8127    stop_qxdm_logger(ad)
8128    return True
8129
8130
8131def check_qxdm_logger_run_time(ad):
8132    output = ad.adb.shell("ps -eo etime,cmd | grep diag_mdlog")
8133    result = re.search(r"(\d+):(\d+):(\d+) diag_mdlog", output)
8134    if result:
8135        return int(result.group(1)) * 60 * 60 + int(
8136            result.group(2)) * 60 + int(result.group(3))
8137    else:
8138        result = re.search(r"(\d+):(\d+) diag_mdlog", output)
8139        if result:
8140            return int(result.group(1)) * 60 + int(result.group(2))
8141        else:
8142            return 0
8143
8144
8145def start_qxdm_loggers(log, ads, begin_time=None):
8146    tasks = [(start_qxdm_logger, [ad, begin_time]) for ad in ads
8147             if getattr(ad, "qxdm_log", True)]
8148    if tasks: run_multithread_func(log, tasks)
8149
8150
8151def stop_qxdm_loggers(log, ads):
8152    tasks = [(stop_qxdm_logger, [ad]) for ad in ads]
8153    run_multithread_func(log, tasks)
8154
8155
8156def start_sdm_loggers(log, ads):
8157    tasks = [(start_sdm_logger, [ad]) for ad in ads
8158             if getattr(ad, "sdm_log", True)]
8159    if tasks: run_multithread_func(log, tasks)
8160
8161
8162def stop_sdm_loggers(log, ads):
8163    tasks = [(stop_sdm_logger, [ad]) for ad in ads]
8164    run_multithread_func(log, tasks)
8165
8166
8167def start_nexuslogger(ad):
8168    """Start Nexus/Pixel Logger Apk."""
8169    qxdm_logger_apk = None
8170    for apk, activity in (("com.android.nexuslogger", ".MainActivity"),
8171                          ("com.android.pixellogger",
8172                           ".ui.main.MainActivity")):
8173        if ad.is_apk_installed(apk):
8174            qxdm_logger_apk = apk
8175            break
8176    if not qxdm_logger_apk: return
8177    if ad.is_apk_running(qxdm_logger_apk):
8178        if "granted=true" in ad.adb.shell(
8179                "dumpsys package %s | grep WRITE_EXTERN" % qxdm_logger_apk):
8180            return True
8181        else:
8182            ad.log.info("Kill %s" % qxdm_logger_apk)
8183            ad.force_stop_apk(qxdm_logger_apk)
8184            time.sleep(5)
8185    for perm in ("READ", "WRITE"):
8186        ad.adb.shell("pm grant %s android.permission.%s_EXTERNAL_STORAGE" %
8187                     (qxdm_logger_apk, perm))
8188    time.sleep(2)
8189    for i in range(3):
8190        ad.unlock_screen()
8191        ad.log.info("Start %s Attempt %d" % (qxdm_logger_apk, i + 1))
8192        ad.adb.shell("am start -n %s/%s" % (qxdm_logger_apk, activity))
8193        time.sleep(5)
8194        if ad.is_apk_running(qxdm_logger_apk):
8195            ad.send_keycode("HOME")
8196            return True
8197    return False
8198
8199
8200def check_qxdm_logger_mask(ad, mask_file="QC_Default.cfg"):
8201    """Check if QXDM logger always on is set.
8202
8203    Args:
8204        ad: android device object.
8205
8206    """
8207    output = ad.adb.shell(
8208        "ls /data/vendor/radio/diag_logs/", ignore_status=True)
8209    if not output or "No such" in output:
8210        return True
8211    if mask_file not in ad.adb.shell(
8212            "cat /data/vendor/radio/diag_logs/diag.conf", ignore_status=True):
8213        return False
8214    return True
8215
8216
8217def start_tcpdumps(ads,
8218                   test_name="",
8219                   begin_time=None,
8220                   interface="any",
8221                   mask="all"):
8222    for ad in ads:
8223        try:
8224            start_adb_tcpdump(
8225                ad,
8226                test_name=test_name,
8227                begin_time=begin_time,
8228                interface=interface,
8229                mask=mask)
8230        except Exception as e:
8231            ad.log.warning("Fail to start tcpdump due to %s", e)
8232
8233
8234def start_adb_tcpdump(ad,
8235                      test_name="",
8236                      begin_time=None,
8237                      interface="any",
8238                      mask="all"):
8239    """Start tcpdump on any iface
8240
8241    Args:
8242        ad: android device object.
8243        test_name: tcpdump file name will have this
8244
8245    """
8246    out = ad.adb.shell("ls -l /data/local/tmp/tcpdump/", ignore_status=True)
8247    if "No such file" in out or not out:
8248        ad.adb.shell("mkdir /data/local/tmp/tcpdump")
8249    else:
8250        ad.adb.shell(
8251            "find /data/local/tmp/tcpdump -type f -not -mtime -1800s -delete",
8252            ignore_status=True)
8253        ad.adb.shell(
8254            "find /data/local/tmp/tcpdump -type f -size +5G -delete",
8255            ignore_status=True)
8256
8257    if not begin_time:
8258        begin_time = get_current_epoch_time()
8259
8260    out = ad.adb.shell(
8261        'ifconfig | grep -v -E "r_|-rmnet" | grep -E "lan|data"',
8262        ignore_status=True,
8263        timeout=180)
8264    intfs = re.findall(r"(\S+).*", out)
8265    if interface and interface not in ("any", "all"):
8266        if interface not in intfs: return
8267        intfs = [interface]
8268
8269    out = ad.adb.shell("ps -ef | grep tcpdump")
8270    cmds = []
8271    for intf in intfs:
8272        if intf in out:
8273            ad.log.info("tcpdump on interface %s is already running", intf)
8274            continue
8275        else:
8276            log_file_name = "/data/local/tmp/tcpdump/tcpdump_%s_%s_%s_%s.pcap" \
8277                            % (ad.serial, intf, test_name, begin_time)
8278            if mask == "ims":
8279                cmds.append(
8280                    "adb -s %s shell tcpdump -i %s -s0 -n -p udp port 500 or "
8281                    "udp port 4500 -w %s" % (ad.serial, intf, log_file_name))
8282            else:
8283                cmds.append("adb -s %s shell tcpdump -i %s -s0 -w %s" %
8284                            (ad.serial, intf, log_file_name))
8285    if not gutils.check_chipset_vendor_by_qualcomm(ad):
8286        log_file_name = ("/data/local/tmp/tcpdump/tcpdump_%s_any_%s_%s.pcap"
8287                         % (ad.serial, test_name, begin_time))
8288        cmds.append("adb -s %s shell nohup tcpdump -i any -s0 -w %s" %
8289                    (ad.serial, log_file_name))
8290    for cmd in cmds:
8291        ad.log.info(cmd)
8292        try:
8293            start_standing_subprocess(cmd, 10)
8294        except Exception as e:
8295            ad.log.error(e)
8296    if cmds:
8297        time.sleep(5)
8298
8299
8300def stop_tcpdumps(ads):
8301    for ad in ads:
8302        stop_adb_tcpdump(ad)
8303
8304
8305def stop_adb_tcpdump(ad, interface="any"):
8306    """Stops tcpdump on any iface
8307       Pulls the tcpdump file in the tcpdump dir
8308
8309    Args:
8310        ad: android device object.
8311
8312    """
8313    if interface == "any":
8314        try:
8315            ad.adb.shell("killall -9 tcpdump", ignore_status=True)
8316        except Exception as e:
8317            ad.log.error("Killing tcpdump with exception %s", e)
8318    else:
8319        out = ad.adb.shell("ps -ef | grep tcpdump | grep %s" % interface)
8320        if "tcpdump -i" in out:
8321            pids = re.findall(r"\S+\s+(\d+).*tcpdump -i", out)
8322            for pid in pids:
8323                ad.adb.shell("kill -9 %s" % pid)
8324    ad.adb.shell(
8325        "find /data/local/tmp/tcpdump -type f -not -mtime -1800s -delete",
8326        ignore_status=True)
8327
8328
8329def get_tcpdump_log(ad, test_name="", begin_time=None):
8330    """Stops tcpdump on any iface
8331       Pulls the tcpdump file in the tcpdump dir
8332       Zips all tcpdump files
8333
8334    Args:
8335        ad: android device object.
8336        test_name: test case name
8337        begin_time: test begin time
8338    """
8339    logs = ad.get_file_names("/data/local/tmp/tcpdump", begin_time=begin_time)
8340    if logs:
8341        ad.log.info("Pulling tcpdumps %s", logs)
8342        log_path = os.path.join(
8343            ad.device_log_path, "TCPDUMP_%s_%s" % (ad.model, ad.serial))
8344        os.makedirs(log_path, exist_ok=True)
8345        ad.pull_files(logs, log_path)
8346        shutil.make_archive(log_path, "zip", log_path)
8347        shutil.rmtree(log_path)
8348    return True
8349
8350
8351def fastboot_wipe(ad, skip_setup_wizard=True):
8352    """Wipe the device in fastboot mode.
8353
8354    Pull sl4a apk from device. Terminate all sl4a sessions,
8355    Reboot the device to bootloader, wipe the device by fastboot.
8356    Reboot the device. wait for device to complete booting
8357    Re-intall and start an sl4a session.
8358    """
8359    status = True
8360    # Pull sl4a apk from device
8361    out = ad.adb.shell("pm path %s" % SL4A_APK_NAME)
8362    result = re.search(r"package:(.*)", out)
8363    if not result:
8364        ad.log.error("Couldn't find sl4a apk")
8365    else:
8366        sl4a_apk = result.group(1)
8367        ad.log.info("Get sl4a apk from %s", sl4a_apk)
8368        ad.pull_files([sl4a_apk], "/tmp/")
8369    ad.stop_services()
8370    attemps = 3
8371    for i in range(1, attemps + 1):
8372        try:
8373            if ad.serial in list_adb_devices():
8374                ad.log.info("Reboot to bootloader")
8375                ad.adb.reboot("bootloader", ignore_status=True)
8376                time.sleep(10)
8377            if ad.serial in list_fastboot_devices():
8378                ad.log.info("Wipe in fastboot")
8379                ad.fastboot._w(timeout=300, ignore_status=True)
8380                time.sleep(30)
8381                ad.log.info("Reboot in fastboot")
8382                ad.fastboot.reboot()
8383            ad.wait_for_boot_completion()
8384            ad.root_adb()
8385            if ad.skip_sl4a:
8386                break
8387            if ad.is_sl4a_installed():
8388                break
8389            ad.log.info("Re-install sl4a")
8390            ad.adb.shell("settings put global verifier_verify_adb_installs 0")
8391            ad.adb.install("-r /tmp/base.apk")
8392            time.sleep(10)
8393            break
8394        except Exception as e:
8395            ad.log.warning(e)
8396            if i == attemps:
8397                abort_all_tests(log, str(e))
8398            time.sleep(5)
8399    try:
8400        ad.start_adb_logcat()
8401    except:
8402        ad.log.error("Failed to start adb logcat!")
8403    if skip_setup_wizard:
8404        ad.exit_setup_wizard()
8405    if getattr(ad, "qxdm_log", True):
8406        set_qxdm_logger_command(ad, mask=getattr(ad, "qxdm_log_mask", None))
8407        start_qxdm_logger(ad)
8408    if ad.skip_sl4a: return status
8409    bring_up_sl4a(ad)
8410    synchronize_device_time(ad)
8411    set_phone_silent_mode(ad.log, ad)
8412    # Activate WFC on Verizon, AT&T and Canada operators as per # b/33187374 &
8413    # b/122327716
8414    activate_wfc_on_device(ad.log, ad)
8415    return status
8416
8417
8418def install_carriersettings_apk(ad, carriersettingsapk, skip_setup_wizard=True):
8419    """ Carrier Setting Installation Steps
8420
8421    Pull sl4a apk from device. Terminate all sl4a sessions,
8422    Reboot the device to bootloader, wipe the device by fastboot.
8423    Reboot the device. wait for device to complete booting
8424    """
8425    status = True
8426    if carriersettingsapk is None:
8427        ad.log.warning("CarrierSettingsApk is not provided, aborting")
8428        return False
8429    ad.log.info("Push carriersettings apk to the Android device.")
8430    android_apk_path = "/product/priv-app/CarrierSettings/CarrierSettings.apk"
8431    ad.adb.push("%s %s" % (carriersettingsapk, android_apk_path))
8432    ad.stop_services()
8433
8434    attempts = 3
8435    for i in range(1, attempts + 1):
8436        try:
8437            if ad.serial in list_adb_devices():
8438                ad.log.info("Reboot to bootloader")
8439                ad.adb.reboot("bootloader", ignore_status=True)
8440                time.sleep(30)
8441            if ad.serial in list_fastboot_devices():
8442                ad.log.info("Reboot in fastboot")
8443                ad.fastboot.reboot()
8444            ad.wait_for_boot_completion()
8445            ad.root_adb()
8446            if ad.is_sl4a_installed():
8447                break
8448            time.sleep(10)
8449            break
8450        except Exception as e:
8451            ad.log.warning(e)
8452            if i == attempts:
8453                abort_all_tests(log, str(e))
8454            time.sleep(5)
8455    try:
8456        ad.start_adb_logcat()
8457    except:
8458        ad.log.error("Failed to start adb logcat!")
8459    if skip_setup_wizard:
8460        ad.exit_setup_wizard()
8461    return status
8462
8463
8464def bring_up_sl4a(ad, attemps=3):
8465    for i in range(attemps):
8466        try:
8467            droid, ed = ad.get_droid()
8468            ed.start()
8469            ad.log.info("Brought up new sl4a session")
8470            break
8471        except Exception as e:
8472            if i < attemps - 1:
8473                ad.log.info(e)
8474                time.sleep(10)
8475            else:
8476                ad.log.error(e)
8477                raise
8478
8479
8480def reboot_device(ad, recover_sim_state=True):
8481    sim_state = is_sim_ready(ad.log, ad)
8482    ad.reboot()
8483    if ad.qxdm_log:
8484        start_qxdm_logger(ad)
8485    ad.unlock_screen()
8486    if recover_sim_state:
8487        if not unlock_sim(ad):
8488            ad.log.error("Unable to unlock SIM")
8489            return False
8490        if sim_state and not _wait_for_droid_in_state(
8491                log, ad, MAX_WAIT_TIME_FOR_STATE_CHANGE, is_sim_ready):
8492            ad.log.error("Sim state didn't reach pre-reboot ready state")
8493            return False
8494    return True
8495
8496
8497def unlocking_device(ad, device_password=None):
8498    """First unlock device attempt, required after reboot"""
8499    ad.unlock_screen(device_password)
8500    time.sleep(2)
8501    ad.adb.wait_for_device(timeout=180)
8502    if not ad.is_waiting_for_unlock_pin():
8503        return True
8504    else:
8505        ad.unlock_screen(device_password)
8506        time.sleep(2)
8507        ad.adb.wait_for_device(timeout=180)
8508        if ad.wait_for_window_ready():
8509            return True
8510    ad.log.error("Unable to unlock to user window")
8511    return False
8512
8513
8514def refresh_sl4a_session(ad):
8515    try:
8516        ad.droid.logI("Checking SL4A connection")
8517        ad.log.debug("Existing sl4a session is active")
8518        return True
8519    except Exception as e:
8520        ad.log.warning("Existing sl4a session is NOT active: %s", e)
8521    try:
8522        ad.terminate_all_sessions()
8523    except Exception as e:
8524        ad.log.info("terminate_all_sessions with error %s", e)
8525    ad.ensure_screen_on()
8526    ad.log.info("Open new sl4a connection")
8527    bring_up_sl4a(ad)
8528
8529
8530def reset_device_password(ad, device_password=None):
8531    # Enable or Disable Device Password per test bed config
8532    unlock_sim(ad)
8533    screen_lock = ad.is_screen_lock_enabled()
8534    if device_password:
8535        try:
8536            refresh_sl4a_session(ad)
8537            ad.droid.setDevicePassword(device_password)
8538        except Exception as e:
8539            ad.log.warning("setDevicePassword failed with %s", e)
8540            try:
8541                ad.droid.setDevicePassword(device_password, "1111")
8542            except Exception as e:
8543                ad.log.warning(
8544                    "setDevicePassword providing previous password error: %s",
8545                    e)
8546        time.sleep(2)
8547        if screen_lock:
8548            # existing password changed
8549            return
8550        else:
8551            # enable device password and log in for the first time
8552            ad.log.info("Enable device password")
8553            ad.adb.wait_for_device(timeout=180)
8554    else:
8555        if not screen_lock:
8556            # no existing password, do not set password
8557            return
8558        else:
8559            # password is enabled on the device
8560            # need to disable the password and log in on the first time
8561            # with unlocking with a swipe
8562            ad.log.info("Disable device password")
8563            ad.unlock_screen(password="1111")
8564            refresh_sl4a_session(ad)
8565            ad.ensure_screen_on()
8566            try:
8567                ad.droid.disableDevicePassword()
8568            except Exception as e:
8569                ad.log.warning("disableDevicePassword failed with %s", e)
8570                fastboot_wipe(ad)
8571            time.sleep(2)
8572            ad.adb.wait_for_device(timeout=180)
8573    refresh_sl4a_session(ad)
8574    if not ad.is_adb_logcat_on:
8575        ad.start_adb_logcat()
8576
8577
8578def get_sim_state(ad):
8579    try:
8580        state = ad.droid.telephonyGetSimState()
8581    except Exception as e:
8582        ad.log.error(e)
8583        state = ad.adb.getprop("gsm.sim.state")
8584    return state
8585
8586
8587def is_sim_locked(ad):
8588    return get_sim_state(ad) == SIM_STATE_PIN_REQUIRED
8589
8590
8591def is_sim_lock_enabled(ad):
8592    # TODO: add sl4a fascade to check if sim is locked
8593    return getattr(ad, "is_sim_locked", False)
8594
8595
8596def unlock_sim(ad):
8597    #The puk and pin can be provided in testbed config file.
8598    #"AndroidDevice": [{"serial": "84B5T15A29018214",
8599    #                   "adb_logcat_param": "-b all",
8600    #                   "puk": "12345678",
8601    #                   "puk_pin": "1234"}]
8602    if not is_sim_locked(ad):
8603        return True
8604    else:
8605        ad.is_sim_locked = True
8606    puk_pin = getattr(ad, "puk_pin", "1111")
8607    try:
8608        if not hasattr(ad, 'puk'):
8609            ad.log.info("Enter SIM pin code")
8610            ad.droid.telephonySupplyPin(puk_pin)
8611        else:
8612            ad.log.info("Enter PUK code and pin")
8613            ad.droid.telephonySupplyPuk(ad.puk, puk_pin)
8614    except:
8615        # if sl4a is not available, use adb command
8616        ad.unlock_screen(puk_pin)
8617        if is_sim_locked(ad):
8618            ad.unlock_screen(puk_pin)
8619    time.sleep(30)
8620    return not is_sim_locked(ad)
8621
8622
8623def send_dialer_secret_code(ad, secret_code):
8624    """Send dialer secret code.
8625
8626    ad: android device controller
8627    secret_code: the secret code to be sent to dialer. the string between
8628                 code prefix *#*# and code postfix #*#*. *#*#<xxx>#*#*
8629    """
8630    action = 'android.provider.Telephony.SECRET_CODE'
8631    uri = 'android_secret_code://%s' % secret_code
8632    intent = ad.droid.makeIntent(
8633        action,
8634        uri,
8635        None,  # type
8636        None,  # extras
8637        None,  # categories,
8638        None,  # packagename,
8639        None,  # classname,
8640        0x01000000)  # flags
8641    ad.log.info('Issuing dialer secret dialer code: %s', secret_code)
8642    ad.droid.sendBroadcastIntent(intent)
8643
8644
8645def enable_radio_log_on(ad):
8646    if ad.adb.getprop("persist.vendor.radio.adb_log_on") != "1":
8647        ad.log.info("Enable radio adb_log_on and reboot")
8648        adb_disable_verity(ad)
8649        ad.adb.shell("setprop persist.vendor.radio.adb_log_on 1")
8650        reboot_device(ad)
8651
8652
8653def adb_disable_verity(ad):
8654    if ad.adb.getprop("ro.boot.veritymode") == "enforcing":
8655        ad.adb.disable_verity()
8656        reboot_device(ad)
8657        ad.adb.remount()
8658
8659
8660def recover_build_id(ad):
8661    build_fingerprint = ad.adb.getprop(
8662        "ro.vendor.build.fingerprint") or ad.adb.getprop(
8663            "ro.build.fingerprint")
8664    if not build_fingerprint:
8665        return
8666    build_id = build_fingerprint.split("/")[3]
8667    if ad.adb.getprop("ro.build.id") != build_id:
8668        build_id_override(ad, build_id)
8669
8670
8671def enable_privacy_usage_diagnostics(ad):
8672    try:
8673        ad.ensure_screen_on()
8674        ad.send_keycode('HOME')
8675    # open the UI page on which we need to enable the setting
8676        cmd = ('am start -n com.google.android.gms/com.google.android.gms.'
8677               'usagereporting.settings.UsageReportingActivity')
8678        ad.adb.shell(cmd)
8679    # perform the toggle
8680        ad.send_keycode('TAB')
8681        ad.send_keycode('ENTER')
8682    except Exception:
8683        ad.log.info("Unable to toggle Usage and Diagnostics")
8684
8685
8686def build_id_override(ad, new_build_id=None, postfix=None):
8687    build_fingerprint = ad.adb.getprop(
8688        "ro.build.fingerprint") or ad.adb.getprop(
8689            "ro.vendor.build.fingerprint")
8690    if build_fingerprint:
8691        build_id = build_fingerprint.split("/")[3]
8692    else:
8693        build_id = None
8694    existing_build_id = ad.adb.getprop("ro.build.id")
8695    if postfix is not None and postfix in build_id:
8696        ad.log.info("Build id already contains %s", postfix)
8697        return
8698    if not new_build_id:
8699        if postfix and build_id:
8700            new_build_id = "%s.%s" % (build_id, postfix)
8701    if not new_build_id or existing_build_id == new_build_id:
8702        return
8703    ad.log.info("Override build id %s with %s", existing_build_id,
8704                new_build_id)
8705    enable_privacy_usage_diagnostics(ad)
8706    adb_disable_verity(ad)
8707    ad.adb.remount()
8708    if "backup.prop" not in ad.adb.shell("ls /sdcard/"):
8709        ad.adb.shell("cp /system/build.prop /sdcard/backup.prop")
8710    ad.adb.shell("cat /system/build.prop | grep -v ro.build.id > /sdcard/test.prop")
8711    ad.adb.shell("echo ro.build.id=%s >> /sdcard/test.prop" % new_build_id)
8712    ad.adb.shell("cp /sdcard/test.prop /system/build.prop")
8713    reboot_device(ad)
8714    ad.log.info("ro.build.id = %s", ad.adb.getprop("ro.build.id"))
8715
8716
8717def enable_connectivity_metrics(ad):
8718    cmds = [
8719        "pm enable com.android.connectivity.metrics",
8720        "am startservice -a com.google.android.gms.usagereporting.OPTIN_UR",
8721        "am broadcast -a com.google.gservices.intent.action.GSERVICES_OVERRIDE"
8722        " -e usagestats:connectivity_metrics:enable_data_collection 1",
8723        "am broadcast -a com.google.gservices.intent.action.GSERVICES_OVERRIDE"
8724        " -e usagestats:connectivity_metrics:telephony_snapshot_period_millis 180000"
8725        # By default it turn on all modules
8726        #"am broadcast -a com.google.gservices.intent.action.GSERVICES_OVERRIDE"
8727        #" -e usagestats:connectivity_metrics:data_collection_bitmap 62"
8728    ]
8729    for cmd in cmds:
8730        ad.adb.shell(cmd, ignore_status=True)
8731
8732
8733def force_connectivity_metrics_upload(ad):
8734    cmd = "cmd jobscheduler run --force com.android.connectivity.metrics %s"
8735    for job_id in [2, 3, 5, 4, 1, 6]:
8736        ad.adb.shell(cmd % job_id, ignore_status=True)
8737
8738
8739def system_file_push(ad, src_file_path, dst_file_path):
8740    """Push system file on a device.
8741
8742    Push system file need to change some system setting and remount.
8743    """
8744    cmd = "%s %s" % (src_file_path, dst_file_path)
8745    out = ad.adb.push(cmd, timeout=300, ignore_status=True)
8746    skip_sl4a = True if "sl4a.apk" in src_file_path else False
8747    if "Read-only file system" in out:
8748        ad.log.info("Change read-only file system")
8749        adb_disable_verity(ad)
8750        out = ad.adb.push(cmd, timeout=300, ignore_status=True)
8751        if "Read-only file system" in out:
8752            ad.reboot(skip_sl4a)
8753            out = ad.adb.push(cmd, timeout=300, ignore_status=True)
8754            if "error" in out:
8755                ad.log.error("%s failed with %s", cmd, out)
8756                return False
8757            else:
8758                ad.log.info("push %s succeed")
8759                if skip_sl4a: ad.reboot(skip_sl4a)
8760                return True
8761        else:
8762            return True
8763    elif "error" in out:
8764        return False
8765    else:
8766        return True
8767
8768
8769def flash_radio(ad, file_path, skip_setup_wizard=True):
8770    """Flash radio image."""
8771    ad.stop_services()
8772    ad.log.info("Reboot to bootloader")
8773    ad.adb.reboot_bootloader(ignore_status=True)
8774    ad.log.info("Flash radio in fastboot")
8775    try:
8776        ad.fastboot.flash("radio %s" % file_path, timeout=300)
8777    except Exception as e:
8778        ad.log.error(e)
8779    ad.fastboot.reboot("bootloader")
8780    time.sleep(5)
8781    output = ad.fastboot.getvar("version-baseband")
8782    result = re.search(r"version-baseband: (\S+)", output)
8783    if not result:
8784        ad.log.error("fastboot getvar version-baseband output = %s", output)
8785        abort_all_tests(ad.log, "Radio version-baseband is not provided")
8786    fastboot_radio_version_output = result.group(1)
8787    for _ in range(2):
8788        try:
8789            ad.log.info("Reboot in fastboot")
8790            ad.fastboot.reboot()
8791            ad.wait_for_boot_completion()
8792            break
8793        except Exception as e:
8794            ad.log.error("Exception error %s", e)
8795    ad.root_adb()
8796    adb_radio_version_output = ad.adb.getprop("gsm.version.baseband")
8797    ad.log.info("adb getprop gsm.version.baseband = %s",
8798                adb_radio_version_output)
8799    if adb_radio_version_output != fastboot_radio_version_output:
8800        msg = ("fastboot radio version output %s does not match with adb"
8801               " radio version output %s" % (fastboot_radio_version_output,
8802                                             adb_radio_version_output))
8803        abort_all_tests(ad.log, msg)
8804    if not ad.ensure_screen_on():
8805        ad.log.error("User window cannot come up")
8806    ad.start_services(skip_setup_wizard=skip_setup_wizard)
8807    unlock_sim(ad)
8808
8809
8810def set_preferred_apn_by_adb(ad, pref_apn_name):
8811    """Select Pref APN
8812       Set Preferred APN on UI using content query/insert
8813       It needs apn name as arg, and it will match with plmn id
8814    """
8815    try:
8816        plmn_id = get_plmn_by_adb(ad)
8817        out = ad.adb.shell("content query --uri content://telephony/carriers "
8818                           "--where \"apn='%s' and numeric='%s'\"" %
8819                           (pref_apn_name, plmn_id))
8820        if "No result found" in out:
8821            ad.log.warning("Cannot find APN %s on device", pref_apn_name)
8822            return False
8823        else:
8824            apn_id = re.search(r'_id=(\d+)', out).group(1)
8825            ad.log.info("APN ID is %s", apn_id)
8826            ad.adb.shell("content insert --uri content:"
8827                         "//telephony/carriers/preferapn --bind apn_id:i:%s" %
8828                         (apn_id))
8829            out = ad.adb.shell("content query --uri "
8830                               "content://telephony/carriers/preferapn")
8831            if "No result found" in out:
8832                ad.log.error("Failed to set prefer APN %s", pref_apn_name)
8833                return False
8834            elif apn_id == re.search(r'_id=(\d+)', out).group(1):
8835                ad.log.info("Preferred APN set to %s", pref_apn_name)
8836                return True
8837    except Exception as e:
8838        ad.log.error("Exception while setting pref apn %s", e)
8839        return True
8840
8841
8842def check_apm_mode_on_by_serial(ad, serial_id):
8843    try:
8844        apm_check_cmd = "|".join(("adb -s %s shell dumpsys wifi" % serial_id,
8845                                  "grep -i airplanemodeon", "cut -f2 -d ' '"))
8846        output = exe_cmd(apm_check_cmd)
8847        if output.decode("utf-8").split("\n")[0] == "true":
8848            return True
8849        else:
8850            return False
8851    except Exception as e:
8852        ad.log.warning("Exception during check apm mode on %s", e)
8853        return True
8854
8855
8856def set_apm_mode_on_by_serial(ad, serial_id):
8857    try:
8858        cmd1 = "adb -s %s shell settings put global airplane_mode_on 1" % serial_id
8859        cmd2 = "adb -s %s shell am broadcast -a android.intent.action.AIRPLANE_MODE" % serial_id
8860        exe_cmd(cmd1)
8861        exe_cmd(cmd2)
8862    except Exception as e:
8863        ad.log.warning("Exception during set apm mode on %s", e)
8864        return True
8865
8866
8867def print_radio_info(ad, extra_msg=""):
8868    for prop in ("gsm.version.baseband", "persist.radio.ver_info",
8869                 "persist.radio.cnv.ver_info"):
8870        output = ad.adb.getprop(prop)
8871        ad.log.info("%s%s = %s", extra_msg, prop, output)
8872
8873
8874def wait_for_state(state_check_func,
8875                   state,
8876                   max_wait_time=MAX_WAIT_TIME_FOR_STATE_CHANGE,
8877                   checking_interval=WAIT_TIME_BETWEEN_STATE_CHECK,
8878                   *args,
8879                   **kwargs):
8880    while max_wait_time >= 0:
8881        if state_check_func(*args, **kwargs) == state:
8882            return True
8883        time.sleep(checking_interval)
8884        max_wait_time -= checking_interval
8885    return False
8886
8887
8888def power_off_sim(ad, sim_slot_id=None,
8889                  timeout=MAX_WAIT_TIME_FOR_STATE_CHANGE):
8890    try:
8891        if sim_slot_id is None:
8892            ad.droid.telephonySetSimPowerState(CARD_POWER_DOWN)
8893            verify_func = ad.droid.telephonyGetSimState
8894            verify_args = []
8895        else:
8896            ad.droid.telephonySetSimStateForSlotId(sim_slot_id,
8897                                                   CARD_POWER_DOWN)
8898            verify_func = ad.droid.telephonyGetSimStateForSlotId
8899            verify_args = [sim_slot_id]
8900    except Exception as e:
8901        ad.log.error(e)
8902        return False
8903    while timeout > 0:
8904        sim_state = verify_func(*verify_args)
8905        if sim_state in (SIM_STATE_UNKNOWN, SIM_STATE_ABSENT):
8906            ad.log.info("SIM slot is powered off, SIM state is %s", sim_state)
8907            return True
8908        timeout = timeout - WAIT_TIME_BETWEEN_STATE_CHECK
8909        time.sleep(WAIT_TIME_BETWEEN_STATE_CHECK)
8910    ad.log.warning("Fail to power off SIM slot, sim_state=%s",
8911                   verify_func(*verify_args))
8912    return False
8913
8914
8915def power_on_sim(ad, sim_slot_id=None):
8916    try:
8917        if sim_slot_id is None:
8918            ad.droid.telephonySetSimPowerState(CARD_POWER_UP)
8919            verify_func = ad.droid.telephonyGetSimState
8920            verify_args = []
8921        else:
8922            ad.droid.telephonySetSimStateForSlotId(sim_slot_id, CARD_POWER_UP)
8923            verify_func = ad.droid.telephonyGetSimStateForSlotId
8924            verify_args = [sim_slot_id]
8925    except Exception as e:
8926        ad.log.error(e)
8927        return False
8928    if wait_for_state(verify_func, SIM_STATE_READY,
8929                      MAX_WAIT_TIME_FOR_STATE_CHANGE,
8930                      WAIT_TIME_BETWEEN_STATE_CHECK, *verify_args):
8931        ad.log.info("SIM slot is powered on, SIM state is READY")
8932        return True
8933    elif verify_func(*verify_args) == SIM_STATE_PIN_REQUIRED:
8934        ad.log.info("SIM is pin locked")
8935        return True
8936    else:
8937        ad.log.error("Fail to power on SIM slot")
8938        return False
8939
8940
8941def extract_test_log(log, src_file, dst_file, test_tag):
8942    os.makedirs(os.path.dirname(dst_file), exist_ok=True)
8943    cmd = "grep -n '%s' %s" % (test_tag, src_file)
8944    result = job.run(cmd, ignore_status=True)
8945    if not result.stdout or result.exit_status == 1:
8946        log.warning("Command %s returns %s", cmd, result)
8947        return
8948    line_nums = re.findall(r"(\d+).*", result.stdout)
8949    if line_nums:
8950        begin_line = int(line_nums[0])
8951        end_line = int(line_nums[-1])
8952        if end_line - begin_line <= 5:
8953            result = job.run("wc -l < %s" % src_file)
8954            if result.stdout:
8955                end_line = int(result.stdout)
8956        log.info("Extract %s from line %s to line %s to %s", src_file,
8957                 begin_line, end_line, dst_file)
8958        job.run("awk 'NR >= %s && NR <= %s' %s > %s" % (begin_line, end_line,
8959                                                        src_file, dst_file))
8960
8961
8962def get_device_epoch_time(ad):
8963    return int(1000 * float(ad.adb.shell("date +%s.%N")))
8964
8965
8966def synchronize_device_time(ad):
8967    ad.adb.shell("put global auto_time 0", ignore_status=True)
8968    try:
8969        ad.adb.droid.setTime(get_current_epoch_time())
8970    except Exception:
8971        try:
8972            ad.adb.shell("date `date +%m%d%H%M%G.%S`")
8973        except Exception:
8974            pass
8975    try:
8976        ad.adb.shell(
8977            "am broadcast -a android.intent.action.TIME_SET",
8978            ignore_status=True)
8979    except Exception:
8980        pass
8981
8982
8983def revert_default_telephony_setting(ad):
8984    toggle_airplane_mode_by_adb(ad.log, ad, True)
8985    default_data_roaming = int(
8986        ad.adb.getprop("ro.com.android.dataroaming") == 'true')
8987    default_network_preference = int(
8988        ad.adb.getprop("ro.telephony.default_network"))
8989    ad.log.info("Default data roaming %s, network preference %s",
8990                default_data_roaming, default_network_preference)
8991    new_data_roaming = abs(default_data_roaming - 1)
8992    new_network_preference = abs(default_network_preference - 1)
8993    ad.log.info(
8994        "Set data roaming = %s, mobile data = 0, network preference = %s",
8995        new_data_roaming, new_network_preference)
8996    ad.adb.shell("settings put global mobile_data 0")
8997    ad.adb.shell("settings put global data_roaming %s" % new_data_roaming)
8998    ad.adb.shell("settings put global preferred_network_mode %s" %
8999                 new_network_preference)
9000
9001
9002def verify_default_telephony_setting(ad):
9003    ad.log.info("carrier_config: %s", dumpsys_carrier_config(ad))
9004    default_data_roaming = int(
9005        ad.adb.getprop("ro.com.android.dataroaming") == 'true')
9006    default_network_preference = int(
9007        ad.adb.getprop("ro.telephony.default_network"))
9008    ad.log.info("Default data roaming %s, network preference %s",
9009                default_data_roaming, default_network_preference)
9010    data_roaming = int(ad.adb.shell("settings get global data_roaming"))
9011    mobile_data = int(ad.adb.shell("settings get global mobile_data"))
9012    network_preference = int(
9013        ad.adb.shell("settings get global preferred_network_mode"))
9014    airplane_mode = int(ad.adb.shell("settings get global airplane_mode_on"))
9015    result = True
9016    ad.log.info("data_roaming = %s, mobile_data = %s, "
9017                "network_perference = %s, airplane_mode = %s", data_roaming,
9018                mobile_data, network_preference, airplane_mode)
9019    if airplane_mode:
9020        ad.log.error("Airplane mode is on")
9021        result = False
9022    if data_roaming != default_data_roaming:
9023        ad.log.error("Data roaming is %s, expecting %s", data_roaming,
9024                     default_data_roaming)
9025        result = False
9026    if not mobile_data:
9027        ad.log.error("Mobile data is off")
9028        result = False
9029    if network_preference != default_network_preference:
9030        ad.log.error("preferred_network_mode is %s, expecting %s",
9031                     network_preference, default_network_preference)
9032        result = False
9033    return result
9034
9035
9036def log_messaging_screen_shot(ad, test_name=""):
9037    ad.ensure_screen_on()
9038    ad.send_keycode("HOME")
9039    ad.adb.shell("am start -n com.google.android.apps.messaging/.ui."
9040                 "ConversationListActivity")
9041    time.sleep(3)
9042    log_screen_shot(ad, test_name)
9043    ad.adb.shell("am start -n com.google.android.apps.messaging/com.google."
9044                 "android.apps.messaging.ui.conversation."
9045                 "LaunchConversationShimActivity -e conversation_id 1")
9046    time.sleep(3)
9047    log_screen_shot(ad, test_name)
9048    ad.send_keycode("HOME")
9049
9050
9051def log_screen_shot(ad, test_name=""):
9052    file_name = "/sdcard/Pictures/screencap"
9053    if test_name:
9054        file_name = "%s_%s" % (file_name, test_name)
9055    file_name = "%s_%s.png" % (file_name, utils.get_current_epoch_time())
9056    try:
9057        ad.adb.shell("screencap -p %s" % file_name)
9058    except:
9059        ad.log.error("Fail to log screen shot to %s", file_name)
9060
9061
9062def get_screen_shot_log(ad, test_name="", begin_time=None):
9063    logs = ad.get_file_names("/sdcard/Pictures", begin_time=begin_time)
9064    if logs:
9065        ad.log.info("Pulling %s", logs)
9066        log_path = os.path.join(ad.device_log_path, "Screenshot_%s" % ad.serial)
9067        os.makedirs(log_path, exist_ok=True)
9068        ad.pull_files(logs, log_path)
9069    ad.adb.shell("rm -rf /sdcard/Pictures/screencap_*", ignore_status=True)
9070
9071
9072def get_screen_shot_logs(ads, test_name="", begin_time=None):
9073    for ad in ads:
9074        get_screen_shot_log(ad, test_name=test_name, begin_time=begin_time)
9075
9076
9077def get_carrier_id_version(ad):
9078    out = ad.adb.shell("dumpsys activity service TelephonyDebugService | " \
9079                       "grep -i carrier_list_version")
9080    if out and ":" in out:
9081        version = out.split(':')[1].lstrip()
9082    else:
9083        version = "0"
9084    ad.log.debug("Carrier Config Version is %s", version)
9085    return version
9086
9087
9088def get_carrier_config_version(ad):
9089    out = ad.adb.shell("dumpsys carrier_config | grep version_string")
9090    if out and "-" in out:
9091        version = out.split('-')[1]
9092    else:
9093        version = "0"
9094    ad.log.debug("Carrier Config Version is %s", version)
9095    return version
9096
9097
9098def get_er_db_id_version(ad):
9099    out = ad.adb.shell("dumpsys activity service TelephonyDebugService | \
9100                        grep -i \"Database Version\"")
9101    if out and ":" in out:
9102        version = out.split(':', 2)[2].lstrip()
9103    else:
9104        version = "0"
9105    ad.log.debug("Emergency database Version is %s", version)
9106    return version
9107
9108def get_database_content(ad):
9109    out = ad.adb.shell("dumpsys activity service TelephonyDebugService | \
9110                        egrep -i \EmergencyNumber:Number-54321")
9111    if out:
9112        return True
9113    result = ad.adb.shell(r"dumpsys activity service TelephonyDebugService | \
9114                egrep -i \updateOtaEmergencyNumberListDatabaseAndNotify")
9115    ad.log.error("Emergency Number is incorrect. %s ", result)
9116    return False
9117
9118
9119def add_whitelisted_account(ad, user_account,user_password, retries=3):
9120    if not ad.is_apk_installed("com.google.android.tradefed.account"):
9121        ad.log.error("GoogleAccountUtil is not installed")
9122        return False
9123    for _ in range(retries):
9124        ad.ensure_screen_on()
9125        output = ad.adb.shell(
9126            'am instrument -w -e account "%s@gmail.com" -e password '
9127            '"%s" -e sync true -e wait-for-checkin false '
9128            'com.google.android.tradefed.account/.AddAccount' %
9129            (user_account, user_password))
9130        if "result=SUCCESS" in output:
9131            ad.log.info("Google account is added successfully")
9132            return True
9133    ad.log.error("Failed to add google account - %s", output)
9134    return False
9135
9136
9137def install_googleaccountutil_apk(ad, account_util):
9138    ad.log.info("Install account_util %s", account_util)
9139    ad.ensure_screen_on()
9140    ad.adb.install("-r %s" % account_util, timeout=300, ignore_status=True)
9141    time.sleep(3)
9142    if not ad.is_apk_installed("com.google.android.tradefed.account"):
9143        ad.log.info("com.google.android.tradefed.account is not installed")
9144        return False
9145    return True
9146
9147
9148def install_googlefi_apk(ad, fi_util):
9149    ad.log.info("Install fi_util %s", fi_util)
9150    ad.ensure_screen_on()
9151    ad.adb.install("-r -g --user 0 %s" % fi_util,
9152                   timeout=300, ignore_status=True)
9153    time.sleep(3)
9154    if not check_fi_apk_installed(ad):
9155        return False
9156    return True
9157
9158
9159def check_fi_apk_installed(ad):
9160    if not ad.is_apk_installed("com.google.android.apps.tycho"):
9161        ad.log.warning("com.google.android.apps.tycho is not installed")
9162        return False
9163    return True
9164
9165
9166def add_google_account(ad, retries=3):
9167    if not ad.is_apk_installed("com.google.android.tradefed.account"):
9168        ad.log.error("GoogleAccountUtil is not installed")
9169        return False
9170    for _ in range(retries):
9171        ad.ensure_screen_on()
9172        output = ad.adb.shell(
9173            'am instrument -w -e account "%s@gmail.com" -e password '
9174            '"%s" -e sync true -e wait-for-checkin false '
9175            'com.google.android.tradefed.account/.AddAccount' %
9176            (ad.user_account, ad.user_password))
9177        if "result=SUCCESS" in output:
9178            ad.log.info("Google account is added successfully")
9179            return True
9180    ad.log.error("Failed to add google account - %s", output)
9181    return False
9182
9183
9184def remove_google_account(ad, retries=3):
9185    if not ad.is_apk_installed("com.google.android.tradefed.account"):
9186        ad.log.error("GoogleAccountUtil is not installed")
9187        return False
9188    for _ in range(retries):
9189        ad.ensure_screen_on()
9190        output = ad.adb.shell(
9191            'am instrument -w '
9192            'com.google.android.tradefed.account/.RemoveAccounts')
9193        if "result=SUCCESS" in output:
9194            ad.log.info("google account is removed successfully")
9195            return True
9196    ad.log.error("Fail to remove google account due to %s", output)
9197    return False
9198
9199
9200def my_current_screen_content(ad, content):
9201    ad.adb.shell("uiautomator dump --window=WINDOW")
9202    out = ad.adb.shell("cat /sdcard/window_dump.xml | grep -E '%s'" % content)
9203    if not out:
9204        ad.log.warning("NOT FOUND - %s", content)
9205        return False
9206    return True
9207
9208
9209def activate_esim_using_suw(ad):
9210    _START_SUW = ('am start -a android.intent.action.MAIN -n '
9211                  'com.google.android.setupwizard/.SetupWizardTestActivity')
9212    _STOP_SUW = ('am start -a com.android.setupwizard.EXIT')
9213
9214    toggle_airplane_mode(ad.log, ad, new_state=False, strict_checking=False)
9215    ad.adb.shell("settings put system screen_off_timeout 1800000")
9216    ad.ensure_screen_on()
9217    ad.send_keycode("MENU")
9218    ad.send_keycode("HOME")
9219    for _ in range(3):
9220        ad.log.info("Attempt %d - activating eSIM", (_ + 1))
9221        ad.adb.shell(_START_SUW)
9222        time.sleep(10)
9223        log_screen_shot(ad, "start_suw")
9224        for _ in range(4):
9225            ad.send_keycode("TAB")
9226            time.sleep(0.5)
9227        ad.send_keycode("ENTER")
9228        time.sleep(15)
9229        log_screen_shot(ad, "activate_esim")
9230        get_screen_shot_log(ad)
9231        ad.adb.shell(_STOP_SUW)
9232        time.sleep(5)
9233        current_sim = get_sim_state(ad)
9234        ad.log.info("Current SIM status is %s", current_sim)
9235        if current_sim not in (SIM_STATE_ABSENT, SIM_STATE_UNKNOWN):
9236            break
9237    return True
9238
9239
9240def activate_google_fi_account(ad, retries=10):
9241    _FI_APK = "com.google.android.apps.tycho"
9242    _FI_ACTIVATE_CMD = ('am start -c android.intent.category.DEFAULT -n '
9243                        'com.google.android.apps.tycho/.AccountDetailsActivity --ez '
9244                        'in_setup_wizard false --ez force_show_account_chooser '
9245                        'false')
9246    toggle_airplane_mode(ad.log, ad, new_state=False, strict_checking=False)
9247    ad.adb.shell("settings put system screen_off_timeout 1800000")
9248    page_match_dict = {
9249       "SelectAccount" : "Choose an account to use",
9250       "Setup" : "Activate Google Fi to use your device for calls",
9251       "Switch" : "Switch to the Google Fi mobile network",
9252       "WiFi" : "Fi to download your SIM",
9253       "Connect" : "Connect to the Google Fi mobile network",
9254       "Move" : "Move number",
9255       "Data" : "first turn on mobile data",
9256       "Activate" : "This takes a minute or two, sometimes longer",
9257       "Welcome" : "Welcome to Google Fi",
9258       "Account" : "Your current cycle ends in"
9259    }
9260    page_list = ["Account", "Setup", "WiFi", "Switch", "Connect",
9261                 "Activate", "Move", "Welcome", "Data"]
9262    for _ in range(retries):
9263        ad.force_stop_apk(_FI_APK)
9264        ad.ensure_screen_on()
9265        ad.send_keycode("MENU")
9266        ad.send_keycode("HOME")
9267        ad.adb.shell(_FI_ACTIVATE_CMD)
9268        time.sleep(15)
9269        for page in page_list:
9270            if my_current_screen_content(ad, page_match_dict[page]):
9271                ad.log.info("Ready for Step %s", page)
9272                log_screen_shot(ad, "fi_activation_step_%s" % page)
9273                if page in ("Setup", "Switch", "Connect", "WiFi"):
9274                    ad.send_keycode("TAB")
9275                    ad.send_keycode("TAB")
9276                    ad.send_keycode("ENTER")
9277                    time.sleep(30)
9278                elif page == "Move" or page == "SelectAccount":
9279                    ad.send_keycode("TAB")
9280                    ad.send_keycode("ENTER")
9281                    time.sleep(5)
9282                elif page == "Welcome":
9283                    ad.send_keycode("TAB")
9284                    ad.send_keycode("TAB")
9285                    ad.send_keycode("TAB")
9286                    ad.send_keycode("ENTER")
9287                    ad.log.info("Activation SUCCESS using Fi App")
9288                    time.sleep(5)
9289                    ad.send_keycode("TAB")
9290                    ad.send_keycode("TAB")
9291                    ad.send_keycode("ENTER")
9292                    return True
9293                elif page == "Activate":
9294                    time.sleep(60)
9295                    if my_current_screen_content(ad, page_match_dict[page]):
9296                        time.sleep(60)
9297                elif page == "Account":
9298                    return True
9299                elif page == "Data":
9300                    ad.log.error("Mobile Data is turned OFF by default")
9301                    ad.send_keycode("TAB")
9302                    ad.send_keycode("TAB")
9303                    ad.send_keycode("ENTER")
9304            else:
9305                ad.log.info("NOT FOUND - Page %s", page)
9306                log_screen_shot(ad, "fi_activation_step_%s_failure" % page)
9307                get_screen_shot_log(ad)
9308    return False
9309
9310
9311def check_google_fi_activated(ad, retries=20):
9312    if check_fi_apk_installed(ad):
9313        _FI_APK = "com.google.android.apps.tycho"
9314        _FI_LAUNCH_CMD = ("am start -n %s/%s.AccountDetailsActivity" \
9315                          % (_FI_APK, _FI_APK))
9316        toggle_airplane_mode(ad.log, ad, new_state=False, strict_checking=False)
9317        ad.adb.shell("settings put system screen_off_timeout 1800000")
9318        ad.force_stop_apk(_FI_APK)
9319        ad.ensure_screen_on()
9320        ad.send_keycode("HOME")
9321        ad.adb.shell(_FI_LAUNCH_CMD)
9322        time.sleep(10)
9323        if not my_current_screen_content(ad, "Your current cycle ends in"):
9324            ad.log.warning("Fi is not activated")
9325            return False
9326        ad.send_keycode("HOME")
9327        return True
9328    else:
9329        ad.log.info("Fi Apk is not yet installed")
9330        return False
9331
9332
9333def cleanup_configupdater(ad):
9334    cmds = ('rm -rf /data/data/com.google.android.configupdater/shared_prefs',
9335            'rm /data/misc/carrierid/carrier_list.pb',
9336            'setprop persist.telephony.test.carrierid.ota true',
9337            'rm /data/user_de/0/com.android.providers.telephony/shared_prefs'
9338            '/CarrierIdProvider.xml')
9339    for cmd in cmds:
9340        ad.log.info("Cleanup ConfigUpdater - %s", cmd)
9341        ad.adb.shell(cmd, ignore_status=True)
9342
9343
9344def pull_carrier_id_files(ad, carrier_id_path):
9345    os.makedirs(carrier_id_path, exist_ok=True)
9346    ad.log.info("Pull CarrierId Files")
9347    cmds = ('/data/data/com.google.android.configupdater/shared_prefs/',
9348            '/data/misc/carrierid/',
9349            '/data/user_de/0/com.android.providers.telephony/shared_prefs/',
9350            '/data/data/com.android.providers.downloads/databases/downloads.db')
9351    for cmd in cmds:
9352        cmd = cmd + " %s" % carrier_id_path
9353        ad.adb.pull(cmd, timeout=30, ignore_status=True)
9354
9355
9356def bring_up_connectivity_monitor(ad):
9357    monitor_apk = None
9358    for apk in ("com.google.telephonymonitor",
9359                "com.google.android.connectivitymonitor"):
9360        if ad.is_apk_installed(apk):
9361            ad.log.info("apk %s is installed", apk)
9362            monitor_apk = apk
9363            break
9364    if not monitor_apk:
9365        ad.log.info("ConnectivityMonitor|TelephonyMonitor is not installed")
9366        return False
9367    toggle_connectivity_monitor_setting(ad, True)
9368
9369    if not ad.is_apk_running(monitor_apk):
9370        ad.log.info("%s is not running", monitor_apk)
9371        # Reboot
9372        ad.log.info("reboot to bring up %s", monitor_apk)
9373        reboot_device(ad)
9374        for i in range(30):
9375            if ad.is_apk_running(monitor_apk):
9376                ad.log.info("%s is running after reboot", monitor_apk)
9377                return True
9378            else:
9379                ad.log.info(
9380                    "%s is not running after reboot. Wait and check again",
9381                    monitor_apk)
9382                time.sleep(30)
9383        ad.log.error("%s is not running after reboot", monitor_apk)
9384        return False
9385    else:
9386        ad.log.info("%s is running", monitor_apk)
9387        return True
9388
9389
9390def get_host_ip_address(ad):
9391    cmd = "|".join(("ifconfig", "grep eno1 -A1", "grep inet", "awk '{$1=$1};1'", "cut -d ' ' -f 2"))
9392    destination_ip = exe_cmd(cmd)
9393    destination_ip = (destination_ip.decode("utf-8")).split("\n")[0]
9394    ad.log.info("Host IP is %s", destination_ip)
9395    return destination_ip
9396
9397
9398def load_scone_cat_simulate_data(ad, simulate_data, sub_id=None):
9399    """ Load radio simulate data
9400    ad: android device controller
9401    simulate_data: JSON object of simulate data
9402    sub_id: RIL sub id, should be 0 or 1
9403    """
9404    ad.log.info("load_scone_cat_simulate_data")
9405
9406    #Check RIL sub id
9407    if sub_id is None or sub_id > 1:
9408        ad.log.error("The value of RIL sub_id should be 0 or 1")
9409        return False
9410
9411    action = "com.google.android.apps.scone.cat.action.SetSimulateData"
9412
9413    #add sub id
9414    simulate_data["SubId"] = sub_id
9415    try:
9416        #dump json
9417        extra = json.dumps(simulate_data)
9418        ad.log.info("send simulate_data=[%s]" % extra)
9419        #send data
9420        ad.adb.shell("am broadcast -a " + action + " --es simulate_data '" + extra + "'")
9421    except Exception as e:
9422        ad.log.error("Exception error to send CAT: %s", e)
9423        return False
9424
9425    return True
9426
9427
9428def load_scone_cat_data_from_file(ad, simulate_file_path, sub_id=None):
9429    """ Load radio simulate data
9430    ad: android device controller
9431    simulate_file_path: JSON file of simulate data
9432    sub_id: RIL sub id, should be 0 or 1
9433    """
9434    ad.log.info("load_radio_simulate_data_from_file from %s" % simulate_file_path)
9435    radio_simulate_data = {}
9436
9437    #Check RIL sub id
9438    if sub_id is None or sub_id > 1:
9439        ad.log.error("The value of RIL sub_id should be 0 or 1")
9440        raise ValueError
9441
9442    with open(simulate_file_path, 'r') as f:
9443        try:
9444            radio_simulate_data = json.load(f)
9445        except Exception as e:
9446            ad.log.error("Exception error to load %s: %s", f, e)
9447            return False
9448
9449    for item in radio_simulate_data:
9450        result = load_scone_cat_simulate_data(ad, item, sub_id)
9451        if result == False:
9452            ad.log.error("Load CAT command fail")
9453            return False
9454        time.sleep(0.1)
9455
9456    return True
9457
9458
9459def toggle_connectivity_monitor_setting(ad, state=True):
9460    monitor_setting = ad.adb.getprop("persist.radio.enable_tel_mon")
9461    ad.log.info("radio.enable_tel_mon setting is %s", monitor_setting)
9462    current_state = True if monitor_setting == "user_enabled" else False
9463    if current_state == state:
9464        return True
9465    elif state is None:
9466        state = not current_state
9467    expected_monitor_setting = "user_enabled" if state else "disabled"
9468    cmd = "setprop persist.radio.enable_tel_mon %s" % expected_monitor_setting
9469    ad.log.info("Toggle connectivity monitor by %s", cmd)
9470    ad.adb.shell(
9471        "am start -n com.android.settings/.DevelopmentSettings",
9472        ignore_status=True)
9473    ad.adb.shell(cmd)
9474    monitor_setting = ad.adb.getprop("persist.radio.enable_tel_mon")
9475    ad.log.info("radio.enable_tel_mon setting is %s", monitor_setting)
9476    return monitor_setting == expected_monitor_setting
9477
9478
9479def get_call_forwarding_by_adb(log, ad, call_forwarding_type="unconditional"):
9480    """ Get call forwarding status by adb shell command
9481        'dumpsys telephony.registry'.
9482
9483        Args:
9484            log: log object
9485            ad: android object
9486            call_forwarding_type:
9487                - "unconditional"
9488                - "busy" (todo)
9489                - "not_answered" (todo)
9490                - "not_reachable" (todo)
9491        Returns:
9492            - "true": if call forwarding unconditional is enabled.
9493            - "false": if call forwarding unconditional is disabled.
9494            - "unknown": if the type is other than 'unconditional'.
9495            - False: any case other than above 3 cases.
9496    """
9497    if call_forwarding_type != "unconditional":
9498        return "unknown"
9499
9500    slot_index_of_default_voice_subid = get_slot_index_from_subid(log, ad,
9501        get_incoming_voice_sub_id(ad))
9502    output = ad.adb.shell("dumpsys telephony.registry | grep mCallForwarding")
9503    if "mCallForwarding" in output:
9504        result_list = re.findall(r"mCallForwarding=(true|false)", output)
9505        if result_list:
9506            result = result_list[slot_index_of_default_voice_subid]
9507            ad.log.info("mCallForwarding is %s", result)
9508
9509            if re.search("false", result, re.I):
9510                return "false"
9511            elif re.search("true", result, re.I):
9512                return "true"
9513            else:
9514                return False
9515        else:
9516            return False
9517    else:
9518        ad.log.error("'mCallForwarding' cannot be found in dumpsys.")
9519        return False
9520
9521
9522def erase_call_forwarding_by_mmi(
9523        log,
9524        ad,
9525        retry=2,
9526        call_forwarding_type="unconditional"):
9527    """ Erase setting of call forwarding (erase the number and disable call
9528    forwarding) by MMI code.
9529
9530    Args:
9531        log: log object
9532        ad: android object
9533        retry: times of retry if the erasure failed.
9534        call_forwarding_type:
9535            - "unconditional"
9536            - "busy"
9537            - "not_answered"
9538            - "not_reachable"
9539    Returns:
9540        True by successful erasure. Otherwise False.
9541    """
9542    operator_name = get_operator_name(log, ad)
9543
9544    run_get_call_forwarding_by_adb = 1
9545    if operator_name in NOT_CHECK_MCALLFORWARDING_OPERATOR_LIST:
9546        run_get_call_forwarding_by_adb = 0
9547
9548    if run_get_call_forwarding_by_adb:
9549        res = get_call_forwarding_by_adb(log, ad,
9550            call_forwarding_type=call_forwarding_type)
9551        if res == "false":
9552            return True
9553
9554    user_config_profile = get_user_config_profile(ad)
9555    is_airplane_mode = user_config_profile["Airplane Mode"]
9556    is_wfc_enabled = user_config_profile["WFC Enabled"]
9557    wfc_mode = user_config_profile["WFC Mode"]
9558    is_wifi_on = user_config_profile["WiFi State"]
9559
9560    if is_airplane_mode:
9561        if not toggle_airplane_mode(log, ad, False):
9562            ad.log.error("Failed to disable airplane mode.")
9563            return False
9564
9565    code_dict = {
9566        "Verizon": {
9567            "unconditional": "73",
9568            "busy": "73",
9569            "not_answered": "73",
9570            "not_reachable": "73",
9571            "mmi": "*%s"
9572        },
9573        "Sprint": {
9574            "unconditional": "720",
9575            "busy": "740",
9576            "not_answered": "730",
9577            "not_reachable": "720",
9578            "mmi": "*%s"
9579        },
9580        "Far EasTone": {
9581            "unconditional": "142",
9582            "busy": "143",
9583            "not_answered": "144",
9584            "not_reachable": "144",
9585            "mmi": "*%s*2"
9586        },
9587        'Generic': {
9588            "unconditional": "21",
9589            "busy": "67",
9590            "not_answered": "61",
9591            "not_reachable": "62",
9592            "mmi": "##%s#"
9593        }
9594    }
9595
9596    if operator_name in code_dict:
9597        code = code_dict[operator_name][call_forwarding_type]
9598        mmi = code_dict[operator_name]["mmi"]
9599    else:
9600        code = code_dict['Generic'][call_forwarding_type]
9601        mmi = code_dict['Generic']["mmi"]
9602
9603    result = False
9604    while retry >= 0:
9605        if run_get_call_forwarding_by_adb:
9606            res = get_call_forwarding_by_adb(
9607                log, ad, call_forwarding_type=call_forwarding_type)
9608            if res == "false":
9609                ad.log.info("Call forwarding is already disabled.")
9610                result = True
9611                break
9612
9613        ad.log.info("Erasing and deactivating call forwarding %s..." %
9614            call_forwarding_type)
9615
9616        ad.droid.telecomDialNumber(mmi % code)
9617
9618        time.sleep(3)
9619        ad.send_keycode("ENTER")
9620        time.sleep(15)
9621
9622        # To dismiss the pop-out dialog
9623        ad.send_keycode("BACK")
9624        time.sleep(5)
9625        ad.send_keycode("BACK")
9626
9627        if run_get_call_forwarding_by_adb:
9628            res = get_call_forwarding_by_adb(
9629                log, ad, call_forwarding_type=call_forwarding_type)
9630            if res == "false" or res == "unknown":
9631                result = True
9632                break
9633            else:
9634                ad.log.error("Failed to erase and deactivate call forwarding by "
9635                    "MMI code ##%s#." % code)
9636                retry = retry - 1
9637                time.sleep(30)
9638        else:
9639            result = True
9640            break
9641
9642    if is_airplane_mode:
9643        if not toggle_airplane_mode(log, ad, True):
9644            ad.log.error("Failed to enable airplane mode again.")
9645        else:
9646            if is_wifi_on:
9647                ad.droid.wifiToggleState(True)
9648                if is_wfc_enabled:
9649                    if not wait_for_wfc_enabled(
9650                        log, ad,max_time=MAX_WAIT_TIME_WFC_ENABLED):
9651                        ad.log.error("WFC is not enabled")
9652
9653    return result
9654
9655def set_call_forwarding_by_mmi(
9656        log,
9657        ad,
9658        ad_forwarded,
9659        call_forwarding_type="unconditional",
9660        retry=2):
9661    """ Set up the forwarded number and enable call forwarding by MMI code.
9662
9663    Args:
9664        log: log object
9665        ad: android object of the device forwarding the call (primary device)
9666        ad_forwarded: android object of the device receiving forwarded call.
9667        retry: times of retry if the erasure failed.
9668        call_forwarding_type:
9669            - "unconditional"
9670            - "busy"
9671            - "not_answered"
9672            - "not_reachable"
9673    Returns:
9674        True by successful erasure. Otherwise False.
9675    """
9676
9677    res = get_call_forwarding_by_adb(log, ad,
9678        call_forwarding_type=call_forwarding_type)
9679    if res == "true":
9680        return True
9681
9682    if ad.droid.connectivityCheckAirplaneMode():
9683        ad.log.warning("%s is now in airplane mode.", ad.serial)
9684        return False
9685
9686    operator_name = get_operator_name(log, ad)
9687
9688    code_dict = {
9689        "Verizon": {
9690            "unconditional": "72",
9691            "busy": "71",
9692            "not_answered": "71",
9693            "not_reachable": "72",
9694            "mmi": "*%s%s"
9695        },
9696        "Sprint": {
9697            "unconditional": "72",
9698            "busy": "74",
9699            "not_answered": "73",
9700            "not_reachable": "72",
9701            "mmi": "*%s%s"
9702        },
9703        "Far EasTone": {
9704            "unconditional": "142",
9705            "busy": "143",
9706            "not_answered": "144",
9707            "not_reachable": "144",
9708            "mmi": "*%s*%s"
9709        },
9710        'Generic': {
9711            "unconditional": "21",
9712            "busy": "67",
9713            "not_answered": "61",
9714            "not_reachable": "62",
9715            "mmi": "*%s*%s#",
9716            "mmi_for_plus_sign": "*%s*"
9717        }
9718    }
9719
9720    if operator_name in code_dict:
9721        code = code_dict[operator_name][call_forwarding_type]
9722        mmi = code_dict[operator_name]["mmi"]
9723        if "mmi_for_plus_sign" in code_dict[operator_name]:
9724            mmi_for_plus_sign = code_dict[operator_name]["mmi_for_plus_sign"]
9725    else:
9726        code = code_dict['Generic'][call_forwarding_type]
9727        mmi = code_dict['Generic']["mmi"]
9728        mmi_for_plus_sign = code_dict['Generic']["mmi_for_plus_sign"]
9729
9730    while retry >= 0:
9731        if not erase_call_forwarding_by_mmi(
9732            log, ad, call_forwarding_type=call_forwarding_type):
9733            retry = retry - 1
9734            continue
9735
9736        forwarded_number = ad_forwarded.telephony['subscription'][
9737            ad_forwarded.droid.subscriptionGetDefaultVoiceSubId()][
9738            'phone_num']
9739        ad.log.info("Registering and activating call forwarding %s to %s..." %
9740            (call_forwarding_type, forwarded_number))
9741
9742        (forwarded_number_no_prefix, _) = _phone_number_remove_prefix(
9743            forwarded_number)
9744
9745        if operator_name == "Far EasTone":
9746            forwarded_number_no_prefix = "0" + forwarded_number_no_prefix
9747
9748        run_get_call_forwarding_by_adb = 1
9749        if operator_name in NOT_CHECK_MCALLFORWARDING_OPERATOR_LIST:
9750            run_get_call_forwarding_by_adb = 0
9751
9752        _found_plus_sign = 0
9753        if re.search("^\+", forwarded_number):
9754            _found_plus_sign = 1
9755            forwarded_number.replace("+", "")
9756
9757        if operator_name in code_dict:
9758            ad.droid.telecomDialNumber(mmi % (code, forwarded_number_no_prefix))
9759        else:
9760            if _found_plus_sign == 0:
9761                ad.droid.telecomDialNumber(mmi % (code, forwarded_number))
9762            else:
9763                ad.droid.telecomDialNumber(mmi_for_plus_sign % code)
9764                ad.send_keycode("PLUS")
9765
9766                if "#" in mmi:
9767                    dial_phone_number(ad, forwarded_number + "#")
9768                else:
9769                    dial_phone_number(ad, forwarded_number)
9770
9771        time.sleep(3)
9772        ad.send_keycode("ENTER")
9773        time.sleep(15)
9774
9775        # To dismiss the pop-out dialog
9776        ad.send_keycode("BACK")
9777        time.sleep(5)
9778        ad.send_keycode("BACK")
9779
9780        if not run_get_call_forwarding_by_adb:
9781            return True
9782
9783        result = get_call_forwarding_by_adb(
9784            log, ad, call_forwarding_type=call_forwarding_type)
9785        if result == "false":
9786            retry = retry - 1
9787        elif result == "true":
9788            return True
9789        elif result == "unknown":
9790            return True
9791        else:
9792            retry = retry - 1
9793
9794        if retry >= 0:
9795            ad.log.warning("Failed to register or activate call forwarding %s "
9796                "to %s. Retry after 15 seconds." % (call_forwarding_type,
9797                    forwarded_number))
9798            time.sleep(15)
9799
9800    ad.log.error("Failed to register or activate call forwarding %s to %s." %
9801        (call_forwarding_type, forwarded_number))
9802    return False
9803
9804
9805def get_call_waiting_status(log, ad):
9806    """ (Todo) Get call waiting status (activated or deactivated) when there is
9807    any proper method available.
9808    """
9809    return True
9810
9811
9812def set_call_waiting(log, ad, enable=1, retry=1):
9813    """ Activate/deactivate call waiting by dialing MMI code.
9814
9815    Args:
9816        log: log object.
9817        ad: android object.
9818        enable: 1 for activation and 0 fir deactivation
9819        retry: times of retry if activation/deactivation fails
9820
9821    Returns:
9822        True by successful activation/deactivation; otherwise False.
9823    """
9824    operator_name = get_operator_name(log, ad)
9825
9826    if operator_name in ["Verizon", "Sprint"]:
9827        return True
9828
9829    while retry >= 0:
9830        if enable:
9831            ad.log.info("Activating call waiting...")
9832            ad.droid.telecomDialNumber("*43#")
9833        else:
9834            ad.log.info("Deactivating call waiting...")
9835            ad.droid.telecomDialNumber("#43#")
9836
9837        time.sleep(3)
9838        ad.send_keycode("ENTER")
9839        time.sleep(15)
9840
9841        ad.send_keycode("BACK")
9842        time.sleep(5)
9843        ad.send_keycode("BACK")
9844
9845        if get_call_waiting_status(log, ad):
9846            return True
9847        else:
9848            retry = retry + 1
9849
9850    return False
9851
9852
9853def get_rx_tx_power_levels(log, ad):
9854    """ Obtains Rx and Tx power levels from the MDS application.
9855
9856    The method requires the MDS app to be installed in the DUT.
9857
9858    Args:
9859        log: logger object
9860        ad: an android device
9861
9862    Return:
9863        A tuple where the first element is an array array with the RSRP value
9864        in Rx chain, and the second element is the transmitted power in dBm.
9865        Values for invalid Rx / Tx chains are set to None.
9866    """
9867    cmd = ('am instrument -w -e request "80 00 e8 03 00 08 00 00 00" -e '
9868           'response wait "com.google.mdstest/com.google.mdstest.instrument.'
9869           'ModemCommandInstrumentation"')
9870    output = ad.adb.shell(cmd)
9871
9872    if 'result=SUCCESS' not in output:
9873        raise RuntimeError('Could not obtain Tx/Rx power levels from MDS. Is '
9874                           'the MDS app installed?')
9875
9876    response = re.search(r"(?<=response=).+", output)
9877
9878    if not response:
9879        raise RuntimeError('Invalid response from the MDS app:\n' + output)
9880
9881    # Obtain a list of bytes in hex format from the response string
9882    response_hex = response.group(0).split(' ')
9883
9884    def get_bool(pos):
9885        """ Obtain a boolean variable from the byte array. """
9886        return response_hex[pos] == '01'
9887
9888    def get_int32(pos):
9889        """ Obtain an int from the byte array. Bytes are printed in
9890        little endian format."""
9891        return struct.unpack(
9892            '<i', bytearray.fromhex(''.join(response_hex[pos:pos + 4])))[0]
9893
9894    rx_power = []
9895    RX_CHAINS = 4
9896
9897    for i in range(RX_CHAINS):
9898        # Calculate starting position for the Rx chain data structure
9899        start = 12 + i * 22
9900
9901        # The first byte in the data structure indicates if the rx chain is
9902        # valid.
9903        if get_bool(start):
9904            rx_power.append(get_int32(start + 2) / 10)
9905        else:
9906            rx_power.append(None)
9907
9908    # Calculate the position for the tx chain data structure
9909    tx_pos = 12 + RX_CHAINS * 22
9910
9911    tx_valid = get_bool(tx_pos)
9912    if tx_valid:
9913        tx_power = get_int32(tx_pos + 2) / -10
9914    else:
9915        tx_power = None
9916
9917    return rx_power, tx_power
9918
9919
9920def sms_in_collision_send_receive_verify(
9921        log,
9922        ad_rx,
9923        ad_rx2,
9924        ad_tx,
9925        ad_tx2,
9926        array_message,
9927        array_message2,
9928        max_wait_time=MAX_WAIT_TIME_SMS_RECEIVE_IN_COLLISION):
9929    """Send 2 SMS', receive both SMS', and verify content and sender's number of
9930       each SMS.
9931
9932        Send 2 SMS'. One from ad_tx to ad_rx and the other from ad_tx2 to ad_rx2.
9933        When ad_rx is identical to ad_rx2, the scenario of SMS' in collision can
9934        be tested.
9935        Verify both SMS' are sent, delivered and received.
9936        Verify received content and sender's number of each SMS is correct.
9937
9938    Args:
9939        log: Log object.
9940        ad_tx: Sender's Android Device Object..
9941        ad_rx: Receiver's Android Device Object.
9942        ad_tx2: 2nd sender's Android Device Object..
9943        ad_rx2: 2nd receiver's Android Device Object.
9944        array_message: the array of message to send/receive from ad_tx to ad_rx
9945        array_message2: the array of message to send/receive from ad_tx2 to
9946        ad_rx2
9947        max_wait_time: Max time to wait for reception of SMS
9948    """
9949
9950    rx_sub_id = get_outgoing_message_sub_id(ad_rx)
9951    rx2_sub_id = get_outgoing_message_sub_id(ad_rx2)
9952
9953    _, tx_sub_id, _ = get_subid_on_same_network_of_host_ad(
9954        [ad_rx, ad_tx, ad_tx2],
9955        host_sub_id=rx_sub_id)
9956    set_subid_for_message(ad_tx, tx_sub_id)
9957
9958    _, _, tx2_sub_id = get_subid_on_same_network_of_host_ad(
9959        [ad_rx2, ad_tx, ad_tx2],
9960        host_sub_id=rx2_sub_id)
9961    set_subid_for_message(ad_tx2, tx2_sub_id)
9962
9963    if not sms_in_collision_send_receive_verify_for_subscription(
9964        log,
9965        ad_tx,
9966        ad_tx2,
9967        ad_rx,
9968        ad_rx2,
9969        tx_sub_id,
9970        tx2_sub_id,
9971        rx_sub_id,
9972        rx_sub_id,
9973        array_message,
9974        array_message2,
9975        max_wait_time):
9976        log_messaging_screen_shot(
9977            ad_rx, test_name="sms rx subid: %s" % rx_sub_id)
9978        log_messaging_screen_shot(
9979            ad_rx2, test_name="sms rx2 subid: %s" % rx2_sub_id)
9980        log_messaging_screen_shot(
9981            ad_tx, test_name="sms tx subid: %s" % tx_sub_id)
9982        log_messaging_screen_shot(
9983            ad_tx2, test_name="sms tx subid: %s" % tx2_sub_id)
9984        return False
9985    return True
9986
9987
9988def sms_in_collision_send_receive_verify_for_subscription(
9989        log,
9990        ad_tx,
9991        ad_tx2,
9992        ad_rx,
9993        ad_rx2,
9994        subid_tx,
9995        subid_tx2,
9996        subid_rx,
9997        subid_rx2,
9998        array_message,
9999        array_message2,
10000        max_wait_time=MAX_WAIT_TIME_SMS_RECEIVE_IN_COLLISION):
10001    """Send 2 SMS', receive both SMS', and verify content and sender's number of
10002       each SMS.
10003
10004        Send 2 SMS'. One from ad_tx to ad_rx and the other from ad_tx2 to ad_rx2.
10005        When ad_rx is identical to ad_rx2, the scenario of SMS' in collision can
10006        be tested.
10007        Verify both SMS' are sent, delivered and received.
10008        Verify received content and sender's number of each SMS is correct.
10009
10010    Args:
10011        log: Log object.
10012        ad_tx: Sender's Android Device Object..
10013        ad_rx: Receiver's Android Device Object.
10014        ad_tx2: 2nd sender's Android Device Object..
10015        ad_rx2: 2nd receiver's Android Device Object.
10016        subid_tx: Sub ID of ad_tx as default Sub ID for outgoing SMS
10017        subid_tx2: Sub ID of ad_tx2 as default Sub ID for outgoing SMS
10018        subid_rx: Sub ID of ad_rx as default Sub ID for incoming SMS
10019        subid_rx2: Sub ID of ad_rx2 as default Sub ID for incoming SMS
10020        array_message: the array of message to send/receive from ad_tx to ad_rx
10021        array_message2: the array of message to send/receive from ad_tx2 to
10022        ad_rx2
10023        max_wait_time: Max time to wait for reception of SMS
10024    """
10025
10026    phonenumber_tx = ad_tx.telephony['subscription'][subid_tx]['phone_num']
10027    phonenumber_tx2 = ad_tx2.telephony['subscription'][subid_tx2]['phone_num']
10028    phonenumber_rx = ad_rx.telephony['subscription'][subid_rx]['phone_num']
10029    phonenumber_rx2 = ad_rx2.telephony['subscription'][subid_rx2]['phone_num']
10030
10031    for ad in (ad_tx, ad_tx2, ad_rx, ad_rx2):
10032        ad.send_keycode("BACK")
10033        if not getattr(ad, "messaging_droid", None):
10034            ad.messaging_droid, ad.messaging_ed = ad.get_droid()
10035            ad.messaging_ed.start()
10036        else:
10037            try:
10038                if not ad.messaging_droid.is_live:
10039                    ad.messaging_droid, ad.messaging_ed = ad.get_droid()
10040                    ad.messaging_ed.start()
10041                else:
10042                    ad.messaging_ed.clear_all_events()
10043                ad.messaging_droid.logI(
10044                    "Start sms_send_receive_verify_for_subscription test")
10045            except Exception:
10046                ad.log.info("Create new sl4a session for messaging")
10047                ad.messaging_droid, ad.messaging_ed = ad.get_droid()
10048                ad.messaging_ed.start()
10049
10050    for text, text2 in zip(array_message, array_message2):
10051        length = len(text)
10052        length2 = len(text2)
10053        ad_tx.log.info("Sending SMS from %s to %s, len: %s, content: %s.",
10054                       phonenumber_tx, phonenumber_rx, length, text)
10055        ad_tx2.log.info("Sending SMS from %s to %s, len: %s, content: %s.",
10056                       phonenumber_tx2, phonenumber_rx2, length2, text2)
10057
10058        try:
10059            ad_rx.messaging_ed.clear_events(EventSmsReceived)
10060            ad_rx2.messaging_ed.clear_events(EventSmsReceived)
10061            ad_tx.messaging_ed.clear_events(EventSmsSentSuccess)
10062            ad_tx.messaging_ed.clear_events(EventSmsSentFailure)
10063            ad_tx2.messaging_ed.clear_events(EventSmsSentSuccess)
10064            ad_tx2.messaging_ed.clear_events(EventSmsSentFailure)
10065            ad_rx.messaging_droid.smsStartTrackingIncomingSmsMessage()
10066            if ad_rx2 != ad_rx:
10067                ad_rx2.messaging_droid.smsStartTrackingIncomingSmsMessage()
10068            time.sleep(1)
10069            ad_tx.messaging_droid.logI("Sending SMS of length %s" % length)
10070            ad_tx2.messaging_droid.logI("Sending SMS of length %s" % length2)
10071            ad_rx.messaging_droid.logI(
10072                "Expecting SMS of length %s from %s" % (length, ad_tx.serial))
10073            ad_rx2.messaging_droid.logI(
10074                "Expecting SMS of length %s from %s" % (length2, ad_tx2.serial))
10075
10076            tasks = [
10077                (ad_tx.messaging_droid.smsSendTextMessage,
10078                (phonenumber_rx, text, True)),
10079                (ad_tx2.messaging_droid.smsSendTextMessage,
10080                (phonenumber_rx2, text2, True))]
10081            multithread_func(log, tasks)
10082            try:
10083                tasks = [
10084                    (ad_tx.messaging_ed.pop_events, ("(%s|%s|%s|%s)" % (
10085                        EventSmsSentSuccess,
10086                        EventSmsSentFailure,
10087                        EventSmsDeliverSuccess,
10088                        EventSmsDeliverFailure), max_wait_time)),
10089                    (ad_tx2.messaging_ed.pop_events, ("(%s|%s|%s|%s)" % (
10090                        EventSmsSentSuccess,
10091                        EventSmsSentFailure,
10092                        EventSmsDeliverSuccess,
10093                        EventSmsDeliverFailure), max_wait_time))
10094                ]
10095                results = run_multithread_func(log, tasks)
10096                res = True
10097                _ad = ad_tx
10098                for ad, events in [(ad_tx, results[0]),(ad_tx2, results[1])]:
10099                    _ad = ad
10100                    for event in events:
10101                        ad.log.info("Got event %s", event["name"])
10102                        if event["name"] == EventSmsSentFailure or \
10103                            event["name"] == EventSmsDeliverFailure:
10104                            if event.get("data") and event["data"].get("Reason"):
10105                                ad.log.error("%s with reason: %s",
10106                                                event["name"],
10107                                                event["data"]["Reason"])
10108                            res = False
10109                        elif event["name"] == EventSmsSentSuccess or \
10110                            event["name"] == EventSmsDeliverSuccess:
10111                            break
10112                if not res:
10113                    return False
10114            except Empty:
10115                _ad.log.error("No %s or %s event for SMS of length %s.",
10116                                EventSmsSentSuccess, EventSmsSentFailure,
10117                                length)
10118                return False
10119            if ad_rx == ad_rx2:
10120                if not wait_for_matching_mt_sms_in_collision(
10121                    log,
10122                    ad_rx,
10123                    phonenumber_tx,
10124                    phonenumber_tx2,
10125                    text,
10126                    text2,
10127                    max_wait_time=MAX_WAIT_TIME_SMS_RECEIVE_IN_COLLISION):
10128
10129                    ad_rx.log.error(
10130                        "No matching received SMS of length %s from %s.",
10131                        length,
10132                        ad_rx.serial)
10133                    return False
10134            else:
10135                if not wait_for_matching_mt_sms_in_collision_with_mo_sms(
10136                    log,
10137                    ad_rx,
10138                    ad_rx2,
10139                    phonenumber_tx,
10140                    phonenumber_tx2,
10141                    text,
10142                    text2,
10143                    max_wait_time=MAX_WAIT_TIME_SMS_RECEIVE_IN_COLLISION):
10144                    return False
10145        except Exception as e:
10146            log.error("Exception error %s", e)
10147            raise
10148        finally:
10149            ad_rx.messaging_droid.smsStopTrackingIncomingSmsMessage()
10150            ad_rx2.messaging_droid.smsStopTrackingIncomingSmsMessage()
10151    return True
10152
10153
10154def sms_rx_power_off_multiple_send_receive_verify(
10155        log,
10156        ad_rx,
10157        ad_tx,
10158        ad_tx2,
10159        array_message_length,
10160        array_message2_length,
10161        num_array_message,
10162        num_array_message2,
10163        max_wait_time=MAX_WAIT_TIME_SMS_RECEIVE_IN_COLLISION):
10164
10165    rx_sub_id = get_outgoing_message_sub_id(ad_rx)
10166
10167    _, tx_sub_id, _ = get_subid_on_same_network_of_host_ad(
10168        [ad_rx, ad_tx, ad_tx2],
10169        host_sub_id=rx_sub_id)
10170    set_subid_for_message(ad_tx, tx_sub_id)
10171
10172    _, _, tx2_sub_id = get_subid_on_same_network_of_host_ad(
10173        [ad_rx, ad_tx, ad_tx2],
10174        host_sub_id=rx_sub_id)
10175    set_subid_for_message(ad_tx2, tx2_sub_id)
10176
10177    if not sms_rx_power_off_multiple_send_receive_verify_for_subscription(
10178        log,
10179        ad_tx,
10180        ad_tx2,
10181        ad_rx,
10182        tx_sub_id,
10183        tx2_sub_id,
10184        rx_sub_id,
10185        rx_sub_id,
10186        array_message_length,
10187        array_message2_length,
10188        num_array_message,
10189        num_array_message2):
10190        log_messaging_screen_shot(
10191            ad_rx, test_name="sms rx subid: %s" % rx_sub_id)
10192        log_messaging_screen_shot(
10193            ad_tx, test_name="sms tx subid: %s" % tx_sub_id)
10194        log_messaging_screen_shot(
10195            ad_tx2, test_name="sms tx subid: %s" % tx2_sub_id)
10196        return False
10197    return True
10198
10199
10200def sms_rx_power_off_multiple_send_receive_verify_for_subscription(
10201        log,
10202        ad_tx,
10203        ad_tx2,
10204        ad_rx,
10205        subid_tx,
10206        subid_tx2,
10207        subid_rx,
10208        subid_rx2,
10209        array_message_length,
10210        array_message2_length,
10211        num_array_message,
10212        num_array_message2,
10213        max_wait_time=MAX_WAIT_TIME_SMS_RECEIVE_IN_COLLISION):
10214
10215    phonenumber_tx = ad_tx.telephony['subscription'][subid_tx]['phone_num']
10216    phonenumber_tx2 = ad_tx2.telephony['subscription'][subid_tx2]['phone_num']
10217    phonenumber_rx = ad_rx.telephony['subscription'][subid_rx]['phone_num']
10218    phonenumber_rx2 = ad_rx.telephony['subscription'][subid_rx2]['phone_num']
10219
10220    if not toggle_airplane_mode(log, ad_rx, True):
10221        ad_rx.log.error("Failed to enable Airplane Mode")
10222        return False
10223    ad_rx.stop_services()
10224    ad_rx.log.info("Rebooting......")
10225    ad_rx.adb.reboot()
10226
10227    message_dict = {phonenumber_tx: [], phonenumber_tx2: []}
10228    for index in range(max(num_array_message, num_array_message2)):
10229        array_message = [rand_ascii_str(array_message_length)]
10230        array_message2 = [rand_ascii_str(array_message2_length)]
10231        for text, text2 in zip(array_message, array_message2):
10232            message_dict[phonenumber_tx].append(text)
10233            message_dict[phonenumber_tx2].append(text2)
10234            length = len(text)
10235            length2 = len(text2)
10236
10237            ad_tx.log.info("Sending SMS from %s to %s, len: %s, content: %s.",
10238                           phonenumber_tx, phonenumber_rx, length, text)
10239            ad_tx2.log.info("Sending SMS from %s to %s, len: %s, content: %s.",
10240                           phonenumber_tx2, phonenumber_rx2, length2, text2)
10241
10242            try:
10243                for ad in (ad_tx, ad_tx2):
10244                    ad.send_keycode("BACK")
10245                    if not getattr(ad, "messaging_droid", None):
10246                        ad.messaging_droid, ad.messaging_ed = ad.get_droid()
10247                        ad.messaging_ed.start()
10248                    else:
10249                        try:
10250                            if not ad.messaging_droid.is_live:
10251                                ad.messaging_droid, ad.messaging_ed = \
10252                                    ad.get_droid()
10253                                ad.messaging_ed.start()
10254                            else:
10255                                ad.messaging_ed.clear_all_events()
10256                            ad.messaging_droid.logI(
10257                                "Start sms_send_receive_verify_for_subscription"
10258                                " test")
10259                        except Exception:
10260                            ad.log.info("Create new sl4a session for messaging")
10261                            ad.messaging_droid, ad.messaging_ed = ad.get_droid()
10262                            ad.messaging_ed.start()
10263
10264                ad_tx.messaging_ed.clear_events(EventSmsSentSuccess)
10265                ad_tx.messaging_ed.clear_events(EventSmsSentFailure)
10266                ad_tx2.messaging_ed.clear_events(EventSmsSentSuccess)
10267                ad_tx2.messaging_ed.clear_events(EventSmsSentFailure)
10268
10269                if index < num_array_message and index < num_array_message2:
10270                    ad_tx.messaging_droid.logI(
10271                        "Sending SMS of length %s" % length)
10272                    ad_tx2.messaging_droid.logI(
10273                        "Sending SMS of length %s" % length2)
10274                    tasks = [
10275                        (ad_tx.messaging_droid.smsSendTextMessage,
10276                        (phonenumber_rx, text, True)),
10277                        (ad_tx2.messaging_droid.smsSendTextMessage,
10278                        (phonenumber_rx2, text2, True))]
10279                    multithread_func(log, tasks)
10280                else:
10281                    if index < num_array_message:
10282                        ad_tx.messaging_droid.logI(
10283                            "Sending SMS of length %s" % length)
10284                        ad_tx.messaging_droid.smsSendTextMessage(
10285                            phonenumber_rx, text, True)
10286                    if index < num_array_message2:
10287                        ad_tx2.messaging_droid.logI(
10288                            "Sending SMS of length %s" % length2)
10289                        ad_tx2.messaging_droid.smsSendTextMessage(
10290                            phonenumber_rx2, text2, True)
10291
10292                try:
10293                    if index < num_array_message and index < num_array_message2:
10294                        tasks = [
10295                            (ad_tx.messaging_ed.pop_events, ("(%s|%s|%s|%s)" % (
10296                                EventSmsSentSuccess,
10297                                EventSmsSentFailure,
10298                                EventSmsDeliverSuccess,
10299                                EventSmsDeliverFailure),
10300                                max_wait_time)),
10301                            (ad_tx2.messaging_ed.pop_events, ("(%s|%s|%s|%s)" % (
10302                                EventSmsSentSuccess,
10303                                EventSmsSentFailure,
10304                                EventSmsDeliverSuccess,
10305                                EventSmsDeliverFailure),
10306                                max_wait_time))
10307                        ]
10308                        results = run_multithread_func(log, tasks)
10309                        res = True
10310                        _ad = ad_tx
10311                        for ad, events in [
10312                            (ad_tx, results[0]), (ad_tx2, results[1])]:
10313                            _ad = ad
10314                            for event in events:
10315                                ad.log.info("Got event %s", event["name"])
10316                                if event["name"] == EventSmsSentFailure or \
10317                                    event["name"] == EventSmsDeliverFailure:
10318                                    if event.get("data") and \
10319                                        event["data"].get("Reason"):
10320                                        ad.log.error("%s with reason: %s",
10321                                                        event["name"],
10322                                                        event["data"]["Reason"])
10323                                    res = False
10324                                elif event["name"] == EventSmsSentSuccess or \
10325                                    event["name"] == EventSmsDeliverSuccess:
10326                                    break
10327                        if not res:
10328                            return False
10329                    else:
10330                        if index < num_array_message:
10331                            result = ad_tx.messaging_ed.pop_events(
10332                                "(%s|%s|%s|%s)" % (
10333                                    EventSmsSentSuccess,
10334                                    EventSmsSentFailure,
10335                                    EventSmsDeliverSuccess,
10336                                    EventSmsDeliverFailure),
10337                                max_wait_time)
10338                            res = True
10339                            _ad = ad_tx
10340                            for ad, events in [(ad_tx, result)]:
10341                                _ad = ad
10342                                for event in events:
10343                                    ad.log.info("Got event %s", event["name"])
10344                                    if event["name"] == EventSmsSentFailure or \
10345                                        event["name"] == EventSmsDeliverFailure:
10346                                        if event.get("data") and \
10347                                            event["data"].get("Reason"):
10348                                            ad.log.error(
10349                                                "%s with reason: %s",
10350                                                event["name"],
10351                                                event["data"]["Reason"])
10352                                        res = False
10353                                    elif event["name"] == EventSmsSentSuccess \
10354                                        or event["name"] == EventSmsDeliverSuccess:
10355                                        break
10356                            if not res:
10357                                return False
10358                        if index < num_array_message2:
10359                            result = ad_tx2.messaging_ed.pop_events(
10360                                "(%s|%s|%s|%s)" % (
10361                                    EventSmsSentSuccess,
10362                                    EventSmsSentFailure,
10363                                    EventSmsDeliverSuccess,
10364                                    EventSmsDeliverFailure),
10365                                max_wait_time)
10366                            res = True
10367                            _ad = ad_tx2
10368                            for ad, events in [(ad_tx2, result)]:
10369                                _ad = ad
10370                                for event in events:
10371                                    ad.log.info("Got event %s", event["name"])
10372                                    if event["name"] == EventSmsSentFailure or \
10373                                        event["name"] == EventSmsDeliverFailure:
10374                                        if event.get("data") and \
10375                                            event["data"].get("Reason"):
10376                                            ad.log.error(
10377                                                "%s with reason: %s",
10378                                                event["name"],
10379                                                event["data"]["Reason"])
10380                                        res = False
10381                                    elif event["name"] == EventSmsSentSuccess \
10382                                        or event["name"] == EventSmsDeliverSuccess:
10383                                        break
10384                            if not res:
10385                                return False
10386
10387
10388                except Empty:
10389                    _ad.log.error("No %s or %s event for SMS of length %s.",
10390                                    EventSmsSentSuccess, EventSmsSentFailure,
10391                                    length)
10392                    return False
10393
10394            except Exception as e:
10395                log.error("Exception error %s", e)
10396                raise
10397
10398    ad_rx.wait_for_boot_completion()
10399    ad_rx.root_adb()
10400    ad_rx.start_services(skip_setup_wizard=False)
10401
10402    output = ad_rx.adb.logcat("-t 1")
10403    match = re.search(r"\d+-\d+\s\d+:\d+:\d+.\d+", output)
10404    if match:
10405        ad_rx.test_log_begin_time = match.group(0)
10406
10407    ad_rx.messaging_droid, ad_rx.messaging_ed = ad_rx.get_droid()
10408    ad_rx.messaging_ed.start()
10409    ad_rx.messaging_droid.smsStartTrackingIncomingSmsMessage()
10410    time.sleep(1)  #sleep 100ms after starting event tracking
10411
10412    if not toggle_airplane_mode(log, ad_rx, False):
10413        ad_rx.log.error("Failed to disable Airplane Mode")
10414        return False
10415
10416    res = True
10417    try:
10418        if not wait_for_matching_multiple_sms(log,
10419                ad_rx,
10420                phonenumber_tx,
10421                phonenumber_tx2,
10422                messages=message_dict,
10423                max_wait_time=max_wait_time):
10424            res =  False
10425    except Exception as e:
10426        log.error("Exception error %s", e)
10427        raise
10428    finally:
10429        ad_rx.messaging_droid.smsStopTrackingIncomingSmsMessage()
10430
10431    return res
10432
10433
10434def wait_for_matching_mt_sms_in_collision(log,
10435                          ad_rx,
10436                          phonenumber_tx,
10437                          phonenumber_tx2,
10438                          text,
10439                          text2,
10440                          allow_multi_part_long_sms=True,
10441                          max_wait_time=MAX_WAIT_TIME_SMS_RECEIVE_IN_COLLISION):
10442
10443    if not allow_multi_part_long_sms:
10444        try:
10445            ad_rx.messaging_ed.wait_for_event(
10446                EventSmsReceived,
10447                is_sms_in_collision_match,
10448                max_wait_time,
10449                phonenumber_tx,
10450                phonenumber_tx2,
10451                text,
10452                text2)
10453            ad_rx.log.info("Got event %s", EventSmsReceived)
10454            return True
10455        except Empty:
10456            ad_rx.log.error("No matched SMS received event.")
10457            return False
10458    else:
10459        try:
10460            received_sms = ''
10461            received_sms2 = ''
10462            remaining_text = text
10463            remaining_text2 = text2
10464            while (remaining_text != '' or remaining_text2 != ''):
10465                event = ad_rx.messaging_ed.wait_for_event(
10466                    EventSmsReceived,
10467                    is_sms_in_collision_partial_match,
10468                    max_wait_time,
10469                    phonenumber_tx,
10470                    phonenumber_tx2,
10471                    remaining_text,
10472                    remaining_text2)
10473                event_text = event['data']['Text'].split(")")[-1].strip()
10474                event_text_length = len(event_text)
10475
10476                if event_text in remaining_text:
10477                    ad_rx.log.info("Got event %s of text length %s from %s",
10478                                   EventSmsReceived, event_text_length,
10479                                   phonenumber_tx)
10480                    remaining_text = remaining_text[event_text_length:]
10481                    received_sms += event_text
10482                elif event_text in remaining_text2:
10483                    ad_rx.log.info("Got event %s of text length %s from %s",
10484                                   EventSmsReceived, event_text_length,
10485                                   phonenumber_tx2)
10486                    remaining_text2 = remaining_text2[event_text_length:]
10487                    received_sms2 += event_text
10488
10489            ad_rx.log.info("Received SMS of length %s", len(received_sms))
10490            ad_rx.log.info("Received SMS of length %s", len(received_sms2))
10491            return True
10492        except Empty:
10493            ad_rx.log.error(
10494                "Missing SMS received event.")
10495            if received_sms != '':
10496                ad_rx.log.error(
10497                    "Only received partial matched SMS of length %s from %s",
10498                    len(received_sms), phonenumber_tx)
10499            if received_sms2 != '':
10500                ad_rx.log.error(
10501                    "Only received partial matched SMS of length %s from %s",
10502                    len(received_sms2), phonenumber_tx2)
10503            return False
10504
10505
10506def wait_for_matching_mt_sms_in_collision_with_mo_sms(log,
10507                          ad_rx,
10508                          ad_rx2,
10509                          phonenumber_tx,
10510                          phonenumber_tx2,
10511                          text,
10512                          text2,
10513                          allow_multi_part_long_sms=True,
10514                          max_wait_time=MAX_WAIT_TIME_SMS_RECEIVE_IN_COLLISION):
10515
10516    if not allow_multi_part_long_sms:
10517        result = True
10518        try:
10519            ad_rx.messaging_ed.wait_for_call_offhook_event(
10520                EventSmsReceived,
10521                is_sms_match,
10522                max_wait_time,
10523                phonenumber_tx,
10524                text)
10525            ad_rx.log.info("Got event %s", EventSmsReceived)
10526        except Empty:
10527            ad_rx.log.error("No matched SMS received event.")
10528            result = False
10529
10530        try:
10531            ad_rx2.messaging_ed.wait_for_call_offhook_event(
10532                EventSmsReceived,
10533                is_sms_match,
10534                max_wait_time,
10535                phonenumber_tx2,
10536                text2)
10537            ad_rx2.log.info("Got event %s", EventSmsReceived)
10538        except Empty:
10539            ad_rx2.log.error("No matched SMS received event.")
10540            result = False
10541
10542        return result
10543    else:
10544        result = True
10545        try:
10546            received_sms = ''
10547            remaining_text = text
10548            while remaining_text != '':
10549                event = ad_rx.messaging_ed.wait_for_event(
10550                    EventSmsReceived, is_sms_partial_match, max_wait_time,
10551                    phonenumber_tx, remaining_text)
10552                event_text = event['data']['Text'].split(")")[-1].strip()
10553                event_text_length = len(event_text)
10554
10555                if event_text in remaining_text:
10556                    ad_rx.log.info("Got event %s of text length %s from %s",
10557                                   EventSmsReceived, event_text_length,
10558                                   phonenumber_tx)
10559                    remaining_text = remaining_text[event_text_length:]
10560                    received_sms += event_text
10561
10562            ad_rx.log.info("Received SMS of length %s", len(received_sms))
10563        except Empty:
10564            ad_rx.log.error(
10565                "Missing SMS received event.")
10566            if received_sms != '':
10567                ad_rx.log.error(
10568                    "Only received partial matched SMS of length %s from %s",
10569                    len(received_sms), phonenumber_tx)
10570            result = False
10571
10572        try:
10573            received_sms2 = ''
10574            remaining_text2 = text2
10575            while remaining_text2 != '':
10576                event2 = ad_rx2.messaging_ed.wait_for_event(
10577                    EventSmsReceived, is_sms_partial_match, max_wait_time,
10578                    phonenumber_tx2, remaining_text2)
10579                event_text2 = event2['data']['Text'].split(")")[-1].strip()
10580                event_text_length2 = len(event_text2)
10581
10582                if event_text2 in remaining_text2:
10583                    ad_rx2.log.info("Got event %s of text length %s from %s",
10584                                   EventSmsReceived, event_text_length2,
10585                                   phonenumber_tx2)
10586                    remaining_text2 = remaining_text2[event_text_length2:]
10587                    received_sms2 += event_text2
10588
10589            ad_rx2.log.info("Received SMS of length %s", len(received_sms2))
10590        except Empty:
10591            ad_rx2.log.error(
10592                "Missing SMS received event.")
10593            if received_sms2 != '':
10594                ad_rx2.log.error(
10595                    "Only received partial matched SMS of length %s from %s",
10596                    len(received_sms2), phonenumber_tx2)
10597            result = False
10598
10599        return result
10600
10601
10602def wait_for_matching_multiple_sms(log,
10603                        ad_rx,
10604                        phonenumber_tx,
10605                        phonenumber_tx2,
10606                        messages={},
10607                        allow_multi_part_long_sms=True,
10608                        max_wait_time=MAX_WAIT_TIME_SMS_RECEIVE):
10609
10610    if not allow_multi_part_long_sms:
10611        try:
10612            ad_rx.messaging_ed.wait_for_event(
10613                EventSmsReceived,
10614                is_sms_match_among_multiple_sms,
10615                max_wait_time,
10616                phonenumber_tx,
10617                phonenumber_tx2,
10618                messages[phonenumber_tx],
10619                messages[phonenumber_tx2])
10620            ad_rx.log.info("Got event %s", EventSmsReceived)
10621            return True
10622        except Empty:
10623            ad_rx.log.error("No matched SMS received event.")
10624            return False
10625    else:
10626        all_msgs = []
10627        for tx, msgs in messages.items():
10628            for msg in msgs:
10629                all_msgs.append([tx, msg, msg, ''])
10630
10631        all_msgs_copy = all_msgs.copy()
10632
10633        try:
10634            while (all_msgs != []):
10635                event = ad_rx.messaging_ed.wait_for_event(
10636                    EventSmsReceived,
10637                    is_sms_partial_match_among_multiple_sms,
10638                    max_wait_time,
10639                    phonenumber_tx,
10640                    phonenumber_tx2,
10641                    messages[phonenumber_tx],
10642                    messages[phonenumber_tx2])
10643                event_text = event['data']['Text'].split(")")[-1].strip()
10644                event_text_length = len(event_text)
10645
10646                for msg in all_msgs_copy:
10647                    if event_text in msg[2]:
10648                        ad_rx.log.info("Got event %s of text length %s from %s",
10649                                       EventSmsReceived, event_text_length,
10650                                       msg[0])
10651                        msg[2] = msg[2][event_text_length:]
10652                        msg[3] += event_text
10653
10654                        if msg[2] == "":
10655                            all_msgs.remove(msg)
10656
10657            ad_rx.log.info("Received all SMS' sent when power-off.")
10658        except Empty:
10659            ad_rx.log.error(
10660                "Missing SMS received event.")
10661
10662            for msg in all_msgs_copy:
10663                if msg[3] != '':
10664                    ad_rx.log.error(
10665                        "Only received partial matched SMS of length %s from %s",
10666                        len(msg[3]), msg[0])
10667            return False
10668
10669        return True
10670
10671
10672def is_sms_in_collision_match(
10673    event, phonenumber_tx, phonenumber_tx2, text, text2):
10674    event_text = event['data']['Text'].strip()
10675    if event_text.startswith("("):
10676        event_text = event_text.split(")")[-1]
10677
10678    for phonenumber, txt in [[phonenumber_tx, text], [phonenumber_tx2, text2]]:
10679        if check_phone_number_match(
10680            event['data']['Sender'], phonenumber) and txt.startswith(event_text):
10681            return True
10682    return False
10683
10684
10685def is_sms_in_collision_partial_match(
10686    event, phonenumber_tx, phonenumber_tx2, text, text2):
10687    for phonenumber, txt in [[phonenumber_tx, text], [phonenumber_tx2, text2]]:
10688        if check_phone_number_match(
10689            event['data']['Sender'], phonenumber) and \
10690                event['data']['Text'].strip() == txt:
10691            return True
10692    return False
10693
10694
10695def is_sms_match_among_multiple_sms(
10696    event, phonenumber_tx, phonenumber_tx2, texts=[], texts2=[]):
10697    for txt in texts:
10698        if check_phone_number_match(
10699            event['data']['Sender'], phonenumber_tx) and \
10700                event['data']['Text'].strip() == txt:
10701                return True
10702
10703    for txt in texts2:
10704        if check_phone_number_match(
10705            event['data']['Sender'], phonenumber_tx2) and \
10706                event['data']['Text'].strip() == txt:
10707                return True
10708
10709    return False
10710
10711
10712def is_sms_partial_match_among_multiple_sms(
10713    event, phonenumber_tx, phonenumber_tx2, texts=[], texts2=[]):
10714    event_text = event['data']['Text'].strip()
10715    if event_text.startswith("("):
10716        event_text = event_text.split(")")[-1]
10717
10718    for txt in texts:
10719        if check_phone_number_match(
10720            event['data']['Sender'], phonenumber_tx) and \
10721                txt.startswith(event_text):
10722                return True
10723
10724    for txt in texts2:
10725        if check_phone_number_match(
10726            event['data']['Sender'], phonenumber_tx2) and \
10727                txt.startswith(event_text):
10728                return True
10729
10730    return False
10731
10732
10733def set_time_sync_from_network(ad, action):
10734    if (action == 'enable'):
10735        ad.log.info('Enabling sync time from network.')
10736        ad.adb.shell('settings put global auto_time 1')
10737
10738    elif (action == 'disable'):
10739        ad.log.info('Disabling sync time from network.')
10740        ad.adb.shell('settings put global auto_time 0')
10741
10742    time.sleep(WAIT_TIME_SYNC_DATE_TIME_FROM_NETWORK)
10743
10744
10745def datetime_handle(ad, action, set_datetime_value='', get_year=False):
10746    get_value = ''
10747    if (action == 'get'):
10748        if (get_year):
10749            datetime_string = ad.adb.shell('date')
10750            datetime_list = datetime_string.split()
10751            try:
10752                get_value = datetime_list[5]
10753            except Exception as e:
10754                ad.log.error("Fail to get year from datetime: %s. " \
10755                                "Exception error: %s", datetime_list
10756                                , str(e))
10757                raise signals.TestSkip("Fail to get year from datetime" \
10758                                    ", the format is changed. Skip the test.")
10759        else:
10760            get_value = ad.adb.shell('date')
10761
10762    elif (action == 'set'):
10763        ad.adb.shell('date %s' % set_datetime_value)
10764        time.sleep(WAIT_TIME_SYNC_DATE_TIME_FROM_NETWORK)
10765        ad.adb.shell('am broadcast -a android.intent.action.TIME_SET')
10766
10767    return get_value
10768
10769
10770def wait_for_sending_sms(ad_tx, max_wait_time=MAX_WAIT_TIME_SMS_RECEIVE):
10771    try:
10772        events = ad_tx.messaging_ed.pop_events(
10773            "(%s|%s|%s|%s)" %
10774            (EventSmsSentSuccess, EventSmsSentFailure,
10775                EventSmsDeliverSuccess,
10776                EventSmsDeliverFailure), max_wait_time)
10777        for event in events:
10778            ad_tx.log.info("Got event %s", event["name"])
10779            if event["name"] == EventSmsSentFailure or \
10780                event["name"] == EventSmsDeliverFailure:
10781                if event.get("data") and event["data"].get("Reason"):
10782                    ad_tx.log.error("%s with reason: %s",
10783                                    event["name"],
10784                                    event["data"]["Reason"])
10785                return False
10786            elif event["name"] == EventSmsSentSuccess or \
10787                event["name"] == EventSmsDeliverSuccess:
10788                return True
10789    except Empty:
10790        ad_tx.log.error("No %s or %s event for SMS.",
10791                        EventSmsSentSuccess, EventSmsSentFailure)
10792        return False
10793
10794
10795def wait_for_call_end(
10796        log,
10797        ad_caller,
10798        ad_callee,
10799        ad_hangup,
10800        verify_caller_func,
10801        verify_callee_func,
10802        call_begin_time,
10803        check_interval=5,
10804        tel_result_wrapper=TelResultWrapper(CallResult('SUCCESS')),
10805        wait_time_in_call=WAIT_TIME_IN_CALL):
10806    elapsed_time = 0
10807    while (elapsed_time < wait_time_in_call):
10808        check_interval = min(check_interval, wait_time_in_call - elapsed_time)
10809        time.sleep(check_interval)
10810        elapsed_time += check_interval
10811        time_message = "at <%s>/<%s> second." % (elapsed_time, wait_time_in_call)
10812        for ad, call_func in [(ad_caller, verify_caller_func),
10813                              (ad_callee, verify_callee_func)]:
10814            if not call_func(log, ad):
10815                ad.log.error(
10816                    "NOT in correct %s state at %s, voice in RAT %s",
10817                    call_func.__name__,
10818                    time_message,
10819                    ad.droid.telephonyGetCurrentVoiceNetworkType())
10820                tel_result_wrapper.result_value = CallResult(
10821                    'CALL_DROP_OR_WRONG_STATE_AFTER_CONNECTED')
10822            else:
10823                ad.log.info("In correct %s state at %s",
10824                    call_func.__name__, time_message)
10825            if not ad.droid.telecomCallGetAudioState():
10826                ad.log.error("Audio is not in call state at %s", time_message)
10827                tel_result_wrapper.result_value = CallResult(
10828                        'AUDIO_STATE_NOT_INCALL_AFTER_CONNECTED')
10829        if not tel_result_wrapper:
10830            return tel_result_wrapper
10831
10832    if ad_hangup:
10833        if not hangup_call(log, ad_hangup):
10834            ad_hangup.log.info("Failed to hang up the call")
10835            tel_result_wrapper.result_value = CallResult('CALL_HANGUP_FAIL')
10836
10837    if not tel_result_wrapper:
10838        for ad in (ad_caller, ad_callee):
10839            last_call_drop_reason(ad, call_begin_time)
10840            try:
10841                if ad.droid.telecomIsInCall():
10842                    ad.log.info("In call. End now.")
10843                    ad.droid.telecomEndCall()
10844            except Exception as e:
10845                log.error(str(e))
10846    if ad_hangup or not tel_result_wrapper:
10847        for ad in (ad_caller, ad_callee):
10848            if not wait_for_call_id_clearing(ad, getattr(ad, "caller_ids", [])):
10849                tel_result_wrapper.result_value = CallResult(
10850                    'CALL_ID_CLEANUP_FAIL')
10851
10852    return tel_result_wrapper
10853
10854
10855def voice_call_in_collision_with_mt_sms_msim(
10856        log,
10857        ad_primary,
10858        ad_sms,
10859        ad_voice,
10860        sms_subid_ad_primary,
10861        sms_subid_ad_sms,
10862        voice_subid_ad_primary,
10863        voice_subid_ad_voice,
10864        array_message,
10865        ad_hangup=None,
10866        verify_caller_func=None,
10867        verify_callee_func=None,
10868        call_direction="mo",
10869        wait_time_in_call=WAIT_TIME_IN_CALL,
10870        incall_ui_display=INCALL_UI_DISPLAY_FOREGROUND,
10871        dialing_number_length=None,
10872        video_state=None):
10873
10874    ad_tx = ad_sms
10875    ad_rx = ad_primary
10876    subid_tx = sms_subid_ad_sms
10877    subid_rx = sms_subid_ad_primary
10878
10879    if call_direction == "mo":
10880        ad_caller = ad_primary
10881        ad_callee = ad_voice
10882        subid_caller = voice_subid_ad_primary
10883        subid_callee = voice_subid_ad_voice
10884    elif call_direction == "mt":
10885        ad_callee = ad_primary
10886        ad_caller = ad_voice
10887        subid_callee = voice_subid_ad_primary
10888        subid_caller = voice_subid_ad_voice
10889
10890
10891    phonenumber_tx = ad_tx.telephony['subscription'][subid_tx]['phone_num']
10892    phonenumber_rx = ad_rx.telephony['subscription'][subid_rx]['phone_num']
10893
10894    tel_result_wrapper = TelResultWrapper(CallResult('SUCCESS'))
10895
10896    for ad in (ad_tx, ad_rx):
10897        ad.send_keycode("BACK")
10898        if not getattr(ad, "messaging_droid", None):
10899            ad.messaging_droid, ad.messaging_ed = ad.get_droid()
10900            ad.messaging_ed.start()
10901        else:
10902            try:
10903                if not ad.messaging_droid.is_live:
10904                    ad.messaging_droid, ad.messaging_ed = ad.get_droid()
10905                    ad.messaging_ed.start()
10906                else:
10907                    ad.messaging_ed.clear_all_events()
10908            except Exception:
10909                ad.log.info("Create new sl4a session for messaging")
10910                ad.messaging_droid, ad.messaging_ed = ad.get_droid()
10911                ad.messaging_ed.start()
10912
10913    if not verify_caller_func:
10914        verify_caller_func = is_phone_in_call
10915    if not verify_callee_func:
10916        verify_callee_func = is_phone_in_call
10917
10918    caller_number = ad_caller.telephony['subscription'][subid_caller][
10919        'phone_num']
10920    callee_number = ad_callee.telephony['subscription'][subid_callee][
10921        'phone_num']
10922    if dialing_number_length:
10923        skip_test = False
10924        trunc_position = 0 - int(dialing_number_length)
10925        try:
10926            caller_area_code = caller_number[:trunc_position]
10927            callee_area_code = callee_number[:trunc_position]
10928            callee_dial_number = callee_number[trunc_position:]
10929        except:
10930            skip_test = True
10931        if caller_area_code != callee_area_code:
10932            skip_test = True
10933        if skip_test:
10934            msg = "Cannot make call from %s to %s by %s digits" % (
10935                caller_number, callee_number, dialing_number_length)
10936            ad_caller.log.info(msg)
10937            raise signals.TestSkip(msg)
10938        else:
10939            callee_number = callee_dial_number
10940
10941    msg = "Call from %s to %s" % (caller_number, callee_number)
10942    if video_state:
10943        msg = "Video %s" % msg
10944        video = True
10945    else:
10946        video = False
10947    if ad_hangup:
10948        msg = "%s for duration of %s seconds" % (msg, wait_time_in_call)
10949    ad_caller.log.info(msg)
10950
10951    for ad in (ad_caller, ad_callee):
10952        call_ids = ad.droid.telecomCallGetCallIds()
10953        setattr(ad, "call_ids", call_ids)
10954        if call_ids:
10955            ad.log.info("Pre-exist CallId %s before making call", call_ids)
10956
10957    ad_caller.ed.clear_events(EventCallStateChanged)
10958    call_begin_time = get_device_epoch_time(ad)
10959    ad_caller.droid.telephonyStartTrackingCallStateForSubscription(subid_caller)
10960
10961    for text in array_message:
10962        length = len(text)
10963        ad_tx.log.info("Sending SMS from %s to %s, len: %s, content: %s.",
10964                       phonenumber_tx, phonenumber_rx, length, text)
10965        try:
10966            ad_rx.messaging_ed.clear_events(EventSmsReceived)
10967            ad_tx.messaging_ed.clear_events(EventSmsSentSuccess)
10968            ad_tx.messaging_ed.clear_events(EventSmsSentFailure)
10969            ad_rx.messaging_droid.smsStartTrackingIncomingSmsMessage()
10970            time.sleep(1)  #sleep 100ms after starting event tracking
10971            ad_tx.messaging_droid.logI("Sending SMS of length %s" % length)
10972            ad_rx.messaging_droid.logI("Expecting SMS of length %s" % length)
10973            ad_caller.log.info("Make a phone call to %s", callee_number)
10974
10975            tasks = [
10976                (ad_tx.messaging_droid.smsSendTextMessage,
10977                (phonenumber_rx, text, True)),
10978                (ad_caller.droid.telecomCallNumber,
10979                (callee_number, video))]
10980
10981            run_multithread_func(log, tasks)
10982
10983            try:
10984                # Verify OFFHOOK state
10985                if not wait_for_call_offhook_for_subscription(
10986                        log,
10987                        ad_caller,
10988                        subid_caller,
10989                        event_tracking_started=True):
10990                    ad_caller.log.info(
10991                        "sub_id %s not in call offhook state", subid_caller)
10992                    last_call_drop_reason(ad_caller, begin_time=call_begin_time)
10993
10994                    ad_caller.log.error("Initiate call failed.")
10995                    tel_result_wrapper.result_value = CallResult(
10996                                                        'INITIATE_FAILED')
10997                    return tel_result_wrapper
10998                else:
10999                    ad_caller.log.info("Caller initate call successfully")
11000            finally:
11001                ad_caller.droid.telephonyStopTrackingCallStateChangeForSubscription(
11002                    subid_caller)
11003                if incall_ui_display == INCALL_UI_DISPLAY_FOREGROUND:
11004                    ad_caller.droid.telecomShowInCallScreen()
11005                elif incall_ui_display == INCALL_UI_DISPLAY_BACKGROUND:
11006                    ad_caller.droid.showHomeScreen()
11007
11008            if not wait_and_answer_call_for_subscription(
11009                    log,
11010                    ad_callee,
11011                    subid_callee,
11012                    incoming_number=caller_number,
11013                    caller=ad_caller,
11014                    incall_ui_display=incall_ui_display,
11015                    video_state=video_state):
11016                ad_callee.log.error("Answer call fail.")
11017                tel_result_wrapper.result_value = CallResult(
11018                    'NO_RING_EVENT_OR_ANSWER_FAILED')
11019                return tel_result_wrapper
11020            else:
11021                ad_callee.log.info("Callee answered the call successfully")
11022
11023            for ad, call_func in zip([ad_caller, ad_callee],
11024                                     [verify_caller_func, verify_callee_func]):
11025                call_ids = ad.droid.telecomCallGetCallIds()
11026                new_call_ids = set(call_ids) - set(ad.call_ids)
11027                if not new_call_ids:
11028                    ad.log.error(
11029                        "No new call ids are found after call establishment")
11030                    ad.log.error("telecomCallGetCallIds returns %s",
11031                                 ad.droid.telecomCallGetCallIds())
11032                    tel_result_wrapper.result_value = CallResult(
11033                                                        'NO_CALL_ID_FOUND')
11034                for new_call_id in new_call_ids:
11035                    if not wait_for_in_call_active(ad, call_id=new_call_id):
11036                        tel_result_wrapper.result_value = CallResult(
11037                            'CALL_STATE_NOT_ACTIVE_DURING_ESTABLISHMENT')
11038                    else:
11039                        ad.log.info(
11040                            "callProperties = %s",
11041                            ad.droid.telecomCallGetProperties(new_call_id))
11042
11043                if not ad.droid.telecomCallGetAudioState():
11044                    ad.log.error("Audio is not in call state")
11045                    tel_result_wrapper.result_value = CallResult(
11046                        'AUDIO_STATE_NOT_INCALL_DURING_ESTABLISHMENT')
11047
11048                if call_func(log, ad):
11049                    ad.log.info("Call is in %s state", call_func.__name__)
11050                else:
11051                    ad.log.error("Call is not in %s state, voice in RAT %s",
11052                                 call_func.__name__,
11053                                 ad.droid.telephonyGetCurrentVoiceNetworkType())
11054                    tel_result_wrapper.result_value = CallResult(
11055                        'CALL_DROP_OR_WRONG_STATE_DURING_ESTABLISHMENT')
11056            if not tel_result_wrapper:
11057                return tel_result_wrapper
11058
11059            if not wait_for_sending_sms(
11060                ad_tx,
11061                max_wait_time=MAX_WAIT_TIME_SMS_SENT_SUCCESS_IN_COLLISION):
11062                return False
11063
11064            tasks = [
11065                (wait_for_matching_sms,
11066                (log, ad_rx, phonenumber_tx, text,
11067                MAX_WAIT_TIME_SMS_RECEIVE_IN_COLLISION, True)),
11068                (wait_for_call_end,
11069                (log, ad_caller, ad_callee, ad_hangup, verify_caller_func,
11070                    verify_callee_func, call_begin_time, 5, tel_result_wrapper,
11071                    WAIT_TIME_IN_CALL))]
11072
11073            results = run_multithread_func(log, tasks)
11074
11075            if not results[0]:
11076                ad_rx.log.error("No matching received SMS of length %s.",
11077                                length)
11078                return False
11079
11080            tel_result_wrapper = results[1]
11081
11082        except Exception as e:
11083            log.error("Exception error %s", e)
11084            raise
11085        finally:
11086            ad_rx.messaging_droid.smsStopTrackingIncomingSmsMessage()
11087
11088    return tel_result_wrapper
11089
11090
11091def change_voice_subid_temporarily(ad, sub_id, state_check_func, params=None):
11092    result = False
11093    voice_sub_id_changed = False
11094    current_sub_id = get_incoming_voice_sub_id(ad)
11095    if current_sub_id != sub_id:
11096        set_incoming_voice_sub_id(ad, sub_id)
11097        voice_sub_id_changed = True
11098
11099    if not params:
11100        if state_check_func():
11101            result = True
11102    else:
11103        if state_check_func(*params):
11104            result = True
11105
11106    if voice_sub_id_changed:
11107        set_incoming_voice_sub_id(ad, current_sub_id)
11108
11109    return result
11110
11111
11112def wait_for_network_service(
11113    log,
11114    ad,
11115    wifi_connected=False,
11116    wifi_ssid=None,
11117    ims_reg=True,
11118    recover=False,
11119    retry=3):
11120    """ Wait for multiple network services in sequence, including:
11121        - service state
11122        - network connection
11123        - wifi connection
11124        - cellular data
11125        - internet connection
11126        - IMS registration
11127
11128        The mechanism (cycling airplane mode) to recover network services is
11129        also provided if any service is not available.
11130
11131        Args:
11132            log: log object
11133            ad: android device
11134            wifi_connected: True if wifi should be connected. Otherwise False.
11135            ims_reg: True if IMS should be registered. Otherwise False.
11136            recover: True if the mechanism (cycling airplane mode) to recover
11137            network services should be enabled (by default False).
11138            retry: times of retry.
11139    """
11140    times = 1
11141    while times <= retry:
11142        while True:
11143            if not wait_for_state(
11144                    get_service_state_by_adb,
11145                    "IN_SERVICE",
11146                    MAX_WAIT_TIME_FOR_STATE_CHANGE,
11147                    WAIT_TIME_BETWEEN_STATE_CHECK,
11148                    log,
11149                    ad):
11150                ad.log.error("Current service state is not 'IN_SERVICE'.")
11151                break
11152
11153            if not wait_for_state(
11154                    ad.droid.connectivityNetworkIsConnected,
11155                    True,
11156                    MAX_WAIT_TIME_FOR_STATE_CHANGE,
11157                    WAIT_TIME_BETWEEN_STATE_CHECK):
11158                ad.log.error("Network is NOT connected!")
11159                break
11160
11161            if wifi_connected and wifi_ssid:
11162                if not wait_for_state(
11163                        check_is_wifi_connected,
11164                        True,
11165                        MAX_WAIT_TIME_FOR_STATE_CHANGE,
11166                        WAIT_TIME_BETWEEN_STATE_CHECK,
11167                        log,
11168                        ad,
11169                        wifi_ssid):
11170                    ad.log.error("Failed to connect Wi-Fi SSID '%s'.", wifi_ssid)
11171                    break
11172            else:
11173                if not wait_for_cell_data_connection(log, ad, True):
11174                    ad.log.error("Failed to enable data connection.")
11175                    break
11176
11177            if not wait_for_state(
11178                    verify_internet_connection,
11179                    True,
11180                    MAX_WAIT_TIME_FOR_STATE_CHANGE,
11181                    WAIT_TIME_BETWEEN_STATE_CHECK,
11182                    log,
11183                    ad):
11184                ad.log.error("Data not available on cell.")
11185                break
11186
11187            if ims_reg:
11188                if not wait_for_ims_registered(log, ad):
11189                    ad.log.error("IMS is not registered.")
11190                    break
11191                ad.log.info("IMS is registered.")
11192            return True
11193
11194        if recover:
11195            ad.log.warning("Trying to recover by cycling airplane mode...")
11196            if not toggle_airplane_mode(log, ad, True):
11197                ad.log.error("Failed to enable airplane mode")
11198                break
11199
11200            time.sleep(5)
11201
11202            if not toggle_airplane_mode(log, ad, False):
11203                ad.log.error("Failed to disable airplane mode")
11204                break
11205
11206            times = times + 1
11207
11208        else:
11209            return False
11210    return False
11211
11212
11213def check_voice_network_type(ads, voice_init=True):
11214    """
11215    Args:
11216        ad: Android device object
11217        voice_init: check voice network type before initiate call
11218    Return:
11219        voice_network_list: Network Type for all android devices
11220    """
11221    voice_network_list = []
11222    for ad in ads:
11223        voice_network_list.append(ad.droid.telephonyGetCurrentVoiceNetworkType())
11224        if voice_init:
11225            ad.log.debug("Voice Network Type Before Call is %s",
11226                            ad.droid.telephonyGetCurrentVoiceNetworkType())
11227        else:
11228            ad.log.debug("Voice Network Type During Call is %s",
11229                            ad.droid.telephonyGetCurrentVoiceNetworkType())
11230    return voice_network_list
11231
11232
11233def check_call_status(ad, voice_type_init=None, voice_type_in_call=None):
11234    """"
11235    Args:
11236        ad: Android device object
11237        voice_type_init: Voice network type before initiate call
11238        voice_type_in_call: Voice network type in call state
11239
11240    Return:
11241         voice_call_type_dict: Voice call status
11242    """
11243    dut = str(ad.serial)
11244    network_type = voice_type_init + "_" + voice_type_in_call
11245    if network_type == "NR_NR":
11246        voice_call_type_dict = update_voice_call_type_dict(dut, "VoNR")
11247    elif network_type == "NR_LTE":
11248        voice_call_type_dict = update_voice_call_type_dict(dut, "EPSFB")
11249    elif network_type == "LTE_LTE":
11250        voice_call_type_dict = update_voice_call_type_dict(dut, "VoLTE")
11251    elif network_type == "LTE_WCDMA":
11252        voice_call_type_dict = update_voice_call_type_dict(dut, "CSFB")
11253    else:
11254        voice_call_type_dict = update_voice_call_type_dict(dut, "UNKNOWN")
11255    return voice_call_type_dict
11256
11257
11258def update_voice_call_type_dict(dut, key):
11259    """
11260    Args:
11261        dut: Serial Number of android device object
11262        key: Network subscription parameter (VoNR or EPSFB or VoLTE or CSFB or UNKNOWN)
11263    Return:
11264        voice_call_type: Voice call status
11265    """
11266    if dut in voice_call_type.keys():
11267        voice_call_type[dut][key] += 1
11268    else:
11269        voice_call_type[dut] = {key:0}
11270        voice_call_type[dut][key] += 1
11271    return voice_call_type
11272
11273
11274def wait_for_log(ad, pattern, begin_time=None, end_time=None, max_wait_time=120):
11275    """Wait for logcat logs matching given pattern. This function searches in
11276    logcat for strings matching given pattern by using search_logcat per second
11277    until max_wait_time reaches.
11278
11279    Args:
11280        ad: android device object
11281        pattern: pattern to be searched in grep format
11282        begin_time: only the lines in logcat with time stamps later than
11283            begin_time will be searched.
11284        end_time: only the lines in logcat with time stamps earlier than
11285            end_time will be searched.
11286        max_wait_time: timeout of this function
11287
11288    Returns:
11289        All matched lines will be returned. If no line matches the given pattern
11290        None will be returned.
11291    """
11292    start_time = datetime.now()
11293    while True:
11294        ad.log.info(
11295            '====== Searching logcat for "%s" ====== ', pattern)
11296        res = ad.search_logcat(
11297            pattern, begin_time=begin_time, end_time=end_time)
11298        if res:
11299            return res
11300        time.sleep(1)
11301        stop_time = datetime.now()
11302        passed_time = (stop_time - start_time).total_seconds()
11303        if passed_time > max_wait_time:
11304            return
11305