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