1#!/usr/bin/env python3
2#
3#   Copyright 2022 - Google
4#
5#   Licensed under the Apache License, Version 2.0 (the "License");
6#   you may not use this file except in compliance with the License.
7#   You may obtain a copy of the License at
8#
9#       http://www.apache.org/licenses/LICENSE-2.0
10#
11#   Unless required by applicable law or agreed to in writing, software
12#   distributed under the License is distributed on an "AS IS" BASIS,
13#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14#   See the License for the specific language governing permissions and
15#   limitations under the License.
16
17from typing import Sequence
18from future import standard_library
19standard_library.install_aliases()
20
21import json
22import logging
23import re
24import os
25import urllib.parse
26import time
27import acts.controllers.iperf_server as ipf
28import struct
29
30from acts import signals
31from acts.controllers.android_device import AndroidDevice
32from queue import Empty
33from acts.asserts import abort_all
34from acts.controllers.adb_lib.error import AdbCommandError, AdbError
35from acts.controllers.android_device import list_adb_devices
36from acts.controllers.android_device import list_fastboot_devices
37
38from acts.libs.proc.job import TimeoutError
39from acts_contrib.test_utils.net import ui_utils
40from acts_contrib.test_utils.tel.loggers.protos.telephony_metric_pb2 import TelephonyVoiceTestResult
41from acts_contrib.test_utils.tel.tel_defines import CarrierConfigs
42from acts_contrib.test_utils.tel.tel_defines import AOSP_PREFIX
43from acts_contrib.test_utils.tel.tel_defines import CARD_POWER_DOWN
44from acts_contrib.test_utils.tel.tel_defines import CARD_POWER_UP
45from acts_contrib.test_utils.tel.tel_defines import CAPABILITY_CONFERENCE
46from acts_contrib.test_utils.tel.tel_defines import CAPABILITY_VOLTE
47from acts_contrib.test_utils.tel.tel_defines import CAPABILITY_VOLTE_PROVISIONING
48from acts_contrib.test_utils.tel.tel_defines import CAPABILITY_VOLTE_OVERRIDE_WFC_PROVISIONING
49from acts_contrib.test_utils.tel.tel_defines import CAPABILITY_HIDE_ENHANCED_4G_LTE_BOOL
50from acts_contrib.test_utils.tel.tel_defines import CAPABILITY_VT
51from acts_contrib.test_utils.tel.tel_defines import CAPABILITY_WFC
52from acts_contrib.test_utils.tel.tel_defines import CAPABILITY_WFC_MODE_CHANGE
53from acts_contrib.test_utils.tel.tel_defines import CARRIER_UNKNOWN
54from acts_contrib.test_utils.tel.tel_defines import COUNTRY_CODE_LIST
55from acts_contrib.test_utils.tel.tel_defines import DIALER_PACKAGE_NAME
56from acts_contrib.test_utils.tel.tel_defines import DATA_ROAMING_ENABLE
57from acts_contrib.test_utils.tel.tel_defines import DATA_ROAMING_DISABLE
58from acts_contrib.test_utils.tel.tel_defines import GEN_4G
59from acts_contrib.test_utils.tel.tel_defines import GEN_UNKNOWN
60from acts_contrib.test_utils.tel.tel_defines import INVALID_SIM_SLOT_INDEX
61from acts_contrib.test_utils.tel.tel_defines import INVALID_SUB_ID
62from acts_contrib.test_utils.tel.tel_defines import MAX_SCREEN_ON_TIME
63from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_AIRPLANEMODE_EVENT
64from acts_contrib.test_utils.tel.tel_defines import MESSAGE_PACKAGE_NAME
65from acts_contrib.test_utils.tel.tel_defines import NETWORK_SERVICE_DATA
66from acts_contrib.test_utils.tel.tel_defines import NETWORK_SERVICE_VOICE
67from acts_contrib.test_utils.tel.tel_defines import PHONE_NUMBER_STRING_FORMAT_7_DIGIT
68from acts_contrib.test_utils.tel.tel_defines import PHONE_NUMBER_STRING_FORMAT_10_DIGIT
69from acts_contrib.test_utils.tel.tel_defines import PHONE_NUMBER_STRING_FORMAT_11_DIGIT
70from acts_contrib.test_utils.tel.tel_defines import PHONE_NUMBER_STRING_FORMAT_12_DIGIT
71from acts_contrib.test_utils.tel.tel_defines import SimSlotInfo
72from acts_contrib.test_utils.tel.tel_defines import RAT_UNKNOWN
73from acts_contrib.test_utils.tel.tel_defines import SERVICE_STATE_EMERGENCY_ONLY
74from acts_contrib.test_utils.tel.tel_defines import SERVICE_STATE_IN_SERVICE
75from acts_contrib.test_utils.tel.tel_defines import SERVICE_STATE_MAPPING
76from acts_contrib.test_utils.tel.tel_defines import SERVICE_STATE_OUT_OF_SERVICE
77from acts_contrib.test_utils.tel.tel_defines import SERVICE_STATE_POWER_OFF
78from acts_contrib.test_utils.tel.tel_defines import SIM_STATE_ABSENT
79from acts_contrib.test_utils.tel.tel_defines import SIM_STATE_LOADED
80from acts_contrib.test_utils.tel.tel_defines import SIM_STATE_NOT_READY
81from acts_contrib.test_utils.tel.tel_defines import SIM_STATE_PIN_REQUIRED
82from acts_contrib.test_utils.tel.tel_defines import SIM_STATE_READY
83from acts_contrib.test_utils.tel.tel_defines import SIM_STATE_UNKNOWN
84from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_ANDROID_STATE_SETTLING
85from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_BETWEEN_STATE_CHECK
86from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_FOR_STATE_CHANGE
87from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_SYNC_DATE_TIME_FROM_NETWORK
88from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_CELLULAR_PREFERRED
89from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_WIFI_ONLY
90from acts_contrib.test_utils.tel.tel_defines import WFC_MODE_WIFI_PREFERRED
91from acts_contrib.test_utils.tel.tel_defines import EventActiveDataSubIdChanged
92from acts_contrib.test_utils.tel.tel_defines import EventDisplayInfoChanged
93from acts_contrib.test_utils.tel.tel_defines import EventServiceStateChanged
94from acts_contrib.test_utils.tel.tel_defines import NetworkCallbackContainer
95from acts_contrib.test_utils.tel.tel_defines import ServiceStateContainer
96from acts_contrib.test_utils.tel.tel_defines import DisplayInfoContainer
97from acts_contrib.test_utils.tel.tel_defines import OverrideNetworkContainer
98from acts_contrib.test_utils.tel.tel_logging_utils import disable_qxdm_logger
99from acts_contrib.test_utils.tel.tel_logging_utils import get_screen_shot_log
100from acts_contrib.test_utils.tel.tel_logging_utils import log_screen_shot
101from acts_contrib.test_utils.tel.tel_logging_utils import start_qxdm_logger
102from acts_contrib.test_utils.tel.tel_lookup_tables import connection_type_from_type_string
103from acts_contrib.test_utils.tel.tel_lookup_tables import is_valid_rat
104from acts_contrib.test_utils.tel.tel_lookup_tables import get_allowable_network_preference
105from acts_contrib.test_utils.tel.tel_lookup_tables import get_voice_mail_count_check_function
106from acts_contrib.test_utils.tel.tel_lookup_tables import get_voice_mail_check_number
107from acts_contrib.test_utils.tel.tel_lookup_tables import network_preference_for_generation
108from acts_contrib.test_utils.tel.tel_lookup_tables import operator_name_from_network_name
109from acts_contrib.test_utils.tel.tel_lookup_tables import operator_name_from_plmn_id
110from acts_contrib.test_utils.tel.tel_lookup_tables import rat_family_from_rat
111from acts_contrib.test_utils.tel.tel_lookup_tables import rat_generation_from_rat
112from acts_contrib.test_utils.tel.tel_subscription_utils import get_slot_index_from_subid
113from acts_contrib.test_utils.tel.tel_subscription_utils import get_subid_by_adb
114from acts_contrib.test_utils.tel.tel_subscription_utils import get_subid_from_logical_slot
115from acts_contrib.test_utils.tel.tel_subscription_utils import get_subid_from_slot_index
116from acts_contrib.test_utils.tel.tel_subscription_utils import get_outgoing_voice_sub_id
117from acts_contrib.test_utils.tel.tel_subscription_utils import get_incoming_voice_sub_id
118from acts_contrib.test_utils.tel.tel_subscription_utils import set_incoming_voice_sub_id
119from acts.utils import adb_shell_ping
120from acts.utils import load_config
121from acts.logger import epoch_to_log_line_timestamp
122from acts.utils import get_current_epoch_time
123from acts.utils import exe_cmd
124
125log = logging
126STORY_LINE = "+19523521350"
127CallResult = TelephonyVoiceTestResult.CallResult.Value
128
129
130class TelResultWrapper(object):
131    """Test results wrapper for Telephony test utils.
132
133    In order to enable metrics reporting without refactoring
134    all of the test utils this class is used to keep the
135    current return boolean scheme in tact.
136    """
137
138    def __init__(self, result_value):
139        self._result_value = result_value
140
141    @property
142    def result_value(self):
143        return self._result_value
144
145    @result_value.setter
146    def result_value(self, result_value):
147        self._result_value = result_value
148
149    def __bool__(self):
150        return self._result_value == CallResult('SUCCESS')
151
152
153def abort_all_tests(log, msg):
154    log.error("Aborting all ongoing tests due to: %s.", msg)
155    abort_all(msg)
156
157
158def get_phone_number_by_adb(ad):
159    return phone_number_formatter(
160        ad.adb.shell("service call iphonesubinfo 13"))
161
162
163def get_iccid_by_adb(ad):
164    return ad.adb.shell("service call iphonesubinfo 11")
165
166
167def get_operator_by_adb(ad):
168    operator = ad.adb.getprop("gsm.sim.operator.alpha")
169    if "," in operator:
170        operator = operator.strip()[0]
171    return operator
172
173
174def get_plmn_by_adb(ad):
175    plmn_id = ad.adb.getprop("gsm.sim.operator.numeric")
176    if "," in plmn_id:
177        plmn_id = plmn_id.strip()[0]
178    return plmn_id
179
180
181def get_sub_id_by_adb(ad):
182    return ad.adb.shell("service call iphonesubinfo 5")
183
184
185def setup_droid_properties_by_adb(log, ad, sim_filename=None):
186
187    sim_data = None
188    if sim_filename:
189        try:
190            sim_data = load_config(sim_filename)
191        except Exception:
192            log.warning("Failed to load %s!", sim_filename)
193
194    sub_id = get_sub_id_by_adb(ad)
195    iccid = get_iccid_by_adb(ad)
196    ad.log.info("iccid = %s", iccid)
197    if sim_data.get(iccid) and sim_data[iccid].get("phone_num"):
198        phone_number = phone_number_formatter(sim_data[iccid]["phone_num"])
199    else:
200        phone_number = get_phone_number_by_adb(ad)
201        if not phone_number and hasattr(ad, phone_number):
202            phone_number = ad.phone_number
203    if not phone_number:
204        ad.log.error("Failed to find valid phone number for %s", iccid)
205        abort_all_tests(ad.log, "Failed to find valid phone number for %s")
206    sub_record = {
207        'phone_num': phone_number,
208        'iccid': get_iccid_by_adb(ad),
209        'sim_operator_name': get_operator_by_adb(ad),
210        'operator': operator_name_from_plmn_id(get_plmn_by_adb(ad))
211    }
212    device_props = {'subscription': {sub_id: sub_record}}
213    ad.log.info("subId %s SIM record: %s", sub_id, sub_record)
214    setattr(ad, 'telephony', device_props)
215
216
217def setup_droid_properties(log, ad, sim_filename=None, all_sub=False):
218
219    if ad.skip_sl4a:
220        return setup_droid_properties_by_adb(
221            log, ad, sim_filename=sim_filename)
222    refresh_droid_config(log, ad, all_sub)
223    sim_data = {}
224    if sim_filename:
225        try:
226            sim_data = load_config(sim_filename)
227        except Exception:
228            log.warning("Failed to load %s!", sim_filename)
229    if not ad.telephony["subscription"]:
230        abort_all_tests(ad.log, "No valid subscription")
231    ad.log.debug("Subscription DB %s", ad.telephony["subscription"])
232    result = True
233    active_sub_id = get_outgoing_voice_sub_id(ad)
234    for sub_id, sub_info in ad.telephony["subscription"].items():
235        ad.log.debug("Loop for Subid %s", sub_id)
236        sub_info["operator"] = get_operator_name(log, ad, sub_id)
237        iccid = sub_info["iccid"]
238        if not iccid:
239            ad.log.warning("Unable to find ICC-ID for subscriber %s", sub_id)
240            continue
241        if sub_info.get("phone_num"):
242            if iccid in sim_data and sim_data[iccid].get("phone_num"):
243                if not check_phone_number_match(sim_data[iccid]["phone_num"],
244                                                sub_info["phone_num"]):
245                    ad.log.warning(
246                        "phone_num %s in sim card data file for iccid %s"
247                        "  do not match phone_num %s from subscription",
248                        sim_data[iccid]["phone_num"], iccid,
249                        sub_info["phone_num"])
250                sub_info["phone_num"] = sim_data[iccid]["phone_num"]
251        else:
252            if iccid in sim_data and sim_data[iccid].get("phone_num"):
253                sub_info["phone_num"] = sim_data[iccid]["phone_num"]
254            elif sub_id == active_sub_id:
255                phone_number = get_phone_number_by_secret_code(
256                    ad, sub_info["sim_operator_name"])
257                if phone_number:
258                    sub_info["phone_num"] = phone_number
259                elif getattr(ad, "phone_num", None):
260                    sub_info["phone_num"] = ad.phone_number
261        if (not sub_info.get("phone_num")) and sub_id == active_sub_id:
262            ad.log.info("sub_id %s sub_info = %s", sub_id, sub_info)
263            ad.log.error(
264                "Unable to retrieve phone number for sub %s with iccid"
265                " %s from device or testbed config or sim card file %s",
266                sub_id, iccid, sim_filename)
267            result = False
268        if not hasattr(
269                ad, 'roaming'
270        ) and sub_info["sim_plmn"] != sub_info["network_plmn"] and sub_info["sim_operator_name"].strip(
271        ) not in sub_info["network_operator_name"].strip():
272            ad.log.info("roaming is not enabled, enable it")
273            setattr(ad, 'roaming', True)
274        ad.log.info("SubId %s info: %s", sub_id, sorted(sub_info.items()))
275    get_phone_capability(ad)
276    data_roaming = getattr(ad, 'roaming', False)
277    if get_cell_data_roaming_state_by_adb(ad) != data_roaming:
278        set_cell_data_roaming_state_by_adb(ad, data_roaming)
279        # Setup VoWiFi MDN for Verizon. b/33187374
280    if not result:
281        abort_all_tests(ad.log, "Failed to find valid phone number")
282
283    ad.log.debug("telephony = %s", ad.telephony)
284
285
286def refresh_droid_config(log, ad, all_sub = False):
287    """ Update Android Device telephony records for each sub_id.
288
289    Args:
290        log: log object
291        ad: android device object
292        all_sub: True to record all sub id(include inactive SIM.)
293
294    Returns:
295        None
296    """
297    if not getattr(ad, 'telephony', {}):
298        setattr(ad, 'telephony', {"subscription": {}})
299    droid = ad.droid
300    sub_info_list = droid.subscriptionGetAllSubInfoList()
301    ad.log.info("SubInfoList is %s", sub_info_list)
302    if not sub_info_list: return
303    active_sub_id = get_outgoing_voice_sub_id(ad)
304    for sub_info in sub_info_list:
305        sub_id = sub_info["subscriptionId"]
306        sim_slot = sub_info["simSlotIndex"]
307        if sub_info.get("carrierId"):
308            carrier_id = sub_info["carrierId"]
309        else:
310            carrier_id = -1
311        if sub_info.get("isOpportunistic"):
312            isopportunistic = sub_info["isOpportunistic"]
313        else:
314            isopportunistic = -1
315
316        if sim_slot != INVALID_SIM_SLOT_INDEX or all_sub:
317            if sub_id not in ad.telephony["subscription"]:
318                ad.telephony["subscription"][sub_id] = {}
319            sub_record = ad.telephony["subscription"][sub_id]
320            if sub_info.get("iccId"):
321                sub_record["iccid"] = sub_info["iccId"]
322            else:
323                sub_record[
324                    "iccid"] = droid.telephonyGetSimSerialNumberForSubscription(
325                        sub_id)
326            sub_record["sim_slot"] = sim_slot
327            if sub_info.get("mcc"):
328                sub_record["mcc"] = sub_info["mcc"]
329            if sub_info.get("mnc"):
330                sub_record["mnc"] = sub_info["mnc"]
331            if sub_info.get("displayName"):
332                sub_record["display_name"] = sub_info["displayName"]
333            try:
334                sub_record[
335                    "phone_type"] = droid.telephonyGetPhoneTypeForSubscription(
336                        sub_id)
337            except:
338                if not sub_record.get("phone_type"):
339                    sub_record["phone_type"] = droid.telephonyGetPhoneType()
340            sub_record[
341                "sim_plmn"] = droid.telephonyGetSimOperatorForSubscription(
342                    sub_id)
343            sub_record[
344                "sim_operator_name"] = droid.telephonyGetSimOperatorNameForSubscription(
345                    sub_id)
346            sub_record[
347                "network_plmn"] = droid.telephonyGetNetworkOperatorForSubscription(
348                    sub_id)
349            sub_record[
350                "network_operator_name"] = droid.telephonyGetNetworkOperatorNameForSubscription(
351                    sub_id)
352            sub_record[
353                "sim_country"] = droid.telephonyGetSimCountryIsoForSubscription(
354                    sub_id)
355            if active_sub_id == sub_id:
356                try:
357                    sub_record[
358                        "carrier_id"] = ad.droid.telephonyGetSimCarrierId()
359                    sub_record[
360                        "carrier_id_name"] = ad.droid.telephonyGetSimCarrierIdName(
361                        )
362                except:
363                    ad.log.info("Carrier ID is not supported")
364            if carrier_id == 2340:
365                ad.log.info("SubId %s info: %s", sub_id, sorted(
366                    sub_record.items()))
367                continue
368            if carrier_id == 1989 and isopportunistic == "true":
369                ad.log.info("SubId %s info: %s", sub_id, sorted(
370                    sub_record.items()))
371                continue
372            if not sub_info.get("number"):
373                sub_info[
374                    "number"] = droid.telephonyGetLine1NumberForSubscription(
375                        sub_id)
376            if sub_info.get("number"):
377                if sub_record.get("phone_num"):
378                    # Use the phone number provided in sim info file by default
379                    # as the sub_info["number"] may not be formatted in a
380                    # dialable number
381                    if not check_phone_number_match(sub_info["number"],
382                                                    sub_record["phone_num"]):
383                        ad.log.info(
384                            "Subscriber phone number changed from %s to %s",
385                            sub_record["phone_num"], sub_info["number"])
386                        sub_record["phone_num"] = sub_info["number"]
387                else:
388                    sub_record["phone_num"] = phone_number_formatter(
389                        sub_info["number"])
390            ad.log.info("SubId %s info: %s", sub_id, sorted(
391                sub_record.items()))
392
393
394def get_phone_number_by_secret_code(ad, operator):
395    if "T-Mobile" in operator:
396        ad.droid.telecomDialNumber("#686#")
397        ad.send_keycode("ENTER")
398        for _ in range(12):
399            output = ad.search_logcat("mobile number")
400            if output:
401                result = re.findall(r"mobile number is (\S+)",
402                                    output[-1]["log_message"])
403                ad.send_keycode("BACK")
404                return result[0]
405            else:
406                time.sleep(5)
407    return ""
408
409
410def get_user_config_profile(ad):
411    return {
412        "Airplane Mode":
413        ad.droid.connectivityCheckAirplaneMode(),
414        "IMS Registered":
415        ad.droid.telephonyIsImsRegistered(),
416        "Preferred Network Type":
417        ad.droid.telephonyGetPreferredNetworkTypes(),
418        "VoLTE Platform Enabled":
419        ad.droid.imsIsEnhanced4gLteModeSettingEnabledByPlatform(),
420        "VoLTE Enabled":
421        ad.droid.imsIsEnhanced4gLteModeSettingEnabledByUser(),
422        "VoLTE Available":
423        ad.droid.telephonyIsVolteAvailable(),
424        "VT Available":
425        ad.droid.telephonyIsVideoCallingAvailable(),
426        "VT Enabled":
427        ad.droid.imsIsVtEnabledByUser(),
428        "VT Platform Enabled":
429        ad.droid.imsIsVtEnabledByPlatform(),
430        "WiFi State":
431        ad.droid.wifiCheckState(),
432        "WFC Available":
433        ad.droid.telephonyIsWifiCallingAvailable(),
434        "WFC Enabled":
435        ad.droid.imsIsWfcEnabledByUser(),
436        "WFC Platform Enabled":
437        ad.droid.imsIsWfcEnabledByPlatform(),
438        "WFC Mode":
439        ad.droid.imsGetWfcMode()
440    }
441
442
443def get_num_active_sims(log, ad):
444    """ Get the number of active SIM cards by counting slots
445
446    Args:
447        ad: android_device object.
448
449    Returns:
450        result: The number of loaded (physical) SIM cards
451    """
452    # using a dictionary as a cheap way to prevent double counting
453    # in the situation where multiple subscriptions are on the same SIM.
454    # yes, this is a corner corner case.
455    valid_sims = {}
456    subInfo = ad.droid.subscriptionGetAllSubInfoList()
457    for info in subInfo:
458        ssidx = info['simSlotIndex']
459        if ssidx == INVALID_SIM_SLOT_INDEX:
460            continue
461        valid_sims[ssidx] = True
462    return len(valid_sims.keys())
463
464
465def toggle_airplane_mode_by_adb(log, ad, new_state=None):
466    """ Toggle the state of airplane mode.
467
468    Args:
469        log: log handler.
470        ad: android_device object.
471        new_state: Airplane mode state to set to.
472            If None, opposite of the current state.
473        strict_checking: Whether to turn on strict checking that checks all features.
474
475    Returns:
476        result: True if operation succeed. False if error happens.
477    """
478    cur_state = bool(int(ad.adb.shell("settings get global airplane_mode_on")))
479    if new_state == cur_state:
480        ad.log.info("Airplane mode already in %s", new_state)
481        return True
482    elif new_state is None:
483        new_state = not cur_state
484    ad.log.info("Change airplane mode from %s to %s", cur_state, new_state)
485    try:
486        ad.adb.shell("settings put global airplane_mode_on %s" % int(new_state))
487        ad.adb.shell("am broadcast -a android.intent.action.AIRPLANE_MODE "
488                     "--ez state %s" % new_state)
489    except Exception as e:
490        ad.log.error(e)
491        return False
492    changed_state = bool(int(ad.adb.shell("settings get global airplane_mode_on")))
493    return changed_state == new_state
494
495
496def toggle_airplane_mode(log, ad, new_state=None, strict_checking=True):
497    """ Toggle the state of airplane mode.
498
499    Args:
500        log: log handler.
501        ad: android_device object.
502        new_state: Airplane mode state to set to.
503            If None, opposite of the current state.
504        strict_checking: Whether to turn on strict checking that checks all features.
505
506    Returns:
507        result: True if operation succeed. False if error happens.
508    """
509    if ad.skip_sl4a:
510        return toggle_airplane_mode_by_adb(log, ad, new_state)
511    else:
512        return toggle_airplane_mode_msim(
513            log, ad, new_state, strict_checking=strict_checking)
514
515
516def get_telephony_signal_strength(ad):
517    #{'evdoEcio': -1, 'asuLevel': 28, 'lteSignalStrength': 14, 'gsmLevel': 0,
518    # 'cdmaAsuLevel': 99, 'evdoDbm': -120, 'gsmDbm': -1, 'cdmaEcio': -160,
519    # 'level': 2, 'lteLevel': 2, 'cdmaDbm': -120, 'dbm': -112, 'cdmaLevel': 0,
520    # 'lteAsuLevel': 28, 'gsmAsuLevel': 99, 'gsmBitErrorRate': 0,
521    # 'lteDbm': -112, 'gsmSignalStrength': 99}
522    try:
523        signal_strength = ad.droid.telephonyGetSignalStrength()
524        if not signal_strength:
525            signal_strength = {}
526    except Exception as e:
527        ad.log.error(e)
528        signal_strength = {}
529    return signal_strength
530
531
532def get_lte_rsrp(ad):
533    try:
534        if ad.adb.getprop("ro.build.version.release")[0] in ("9", "P"):
535            out = ad.adb.shell(
536                "dumpsys telephony.registry | grep -i signalstrength")
537            if out:
538                lte_rsrp = out.split()[9]
539                if lte_rsrp:
540                    ad.log.info("lte_rsrp: %s ", lte_rsrp)
541                    return lte_rsrp
542        else:
543            out = ad.adb.shell(
544            "dumpsys telephony.registry |grep -i primary=CellSignalStrengthLte")
545            if out:
546                lte_cell_info = out.split('mLte=')[1]
547                lte_rsrp = re.match(r'.*rsrp=(\S+).*', lte_cell_info).group(1)
548                if lte_rsrp:
549                    ad.log.info("lte_rsrp: %s ", lte_rsrp)
550                    return lte_rsrp
551    except Exception as e:
552        ad.log.error(e)
553    return None
554
555
556def break_internet_except_sl4a_port(ad, sl4a_port):
557    ad.log.info("Breaking internet using iptables rules")
558    ad.adb.shell("iptables -I INPUT 1 -p tcp --dport %s -j ACCEPT" % sl4a_port,
559                 ignore_status=True)
560    ad.adb.shell("iptables -I INPUT 2 -p tcp --sport %s -j ACCEPT" % sl4a_port,
561                 ignore_status=True)
562    ad.adb.shell("iptables -I INPUT 3 -j DROP", ignore_status=True)
563    ad.adb.shell("ip6tables -I INPUT -j DROP", ignore_status=True)
564    return True
565
566
567def resume_internet_with_sl4a_port(ad, sl4a_port):
568    ad.log.info("Bring internet back using iptables rules")
569    ad.adb.shell("iptables -D INPUT -p tcp --dport %s -j ACCEPT" % sl4a_port,
570                 ignore_status=True)
571    ad.adb.shell("iptables -D INPUT -p tcp --sport %s -j ACCEPT" % sl4a_port,
572                 ignore_status=True)
573    ad.adb.shell("iptables -D INPUT -j DROP", ignore_status=True)
574    ad.adb.shell("ip6tables -D INPUT -j DROP", ignore_status=True)
575    return True
576
577
578def test_data_browsing_success_using_sl4a(log, ad):
579    result = True
580    web_page_list = ['https://www.google.com', 'https://www.yahoo.com',
581                     'https://www.amazon.com', 'https://www.nike.com',
582                     'https://www.facebook.com']
583    for website in web_page_list:
584        if not verify_http_connection(log, ad, website, retry=0):
585            ad.log.error("Failed to browse %s successfully!", website)
586            result = False
587    return result
588
589
590def test_data_browsing_failure_using_sl4a(log, ad):
591    result = True
592    web_page_list = ['https://www.youtube.com', 'https://www.cnn.com',
593                     'https://www.att.com', 'https://www.nbc.com',
594                     'https://www.verizonwireless.com']
595    for website in web_page_list:
596        if not verify_http_connection(log, ad, website, retry=0,
597                                      expected_state=False):
598            ad.log.error("Browsing to %s worked!", website)
599            result = False
600    return result
601
602
603def is_expected_event(event_to_check, events_list):
604    """ check whether event is present in the event list
605
606    Args:
607        event_to_check: event to be checked.
608        events_list: list of events
609    Returns:
610        result: True if event present in the list. False if not.
611    """
612    for event in events_list:
613        if event in event_to_check['name']:
614            return True
615    return False
616
617
618def is_sim_ready(log, ad, sim_slot_id=None):
619    """ check whether SIM is ready.
620
621    Args:
622        ad: android_device object.
623        sim_slot_id: check the SIM status for sim_slot_id
624            This is optional. If this is None, check default SIM.
625
626    Returns:
627        result: True if all SIMs are ready. False if not.
628    """
629    if sim_slot_id is None:
630        status = ad.droid.telephonyGetSimState()
631    else:
632        status = ad.droid.telephonyGetSimStateForSlotId(sim_slot_id)
633    if status != SIM_STATE_READY:
634        ad.log.info("Sim state is %s, not ready", status)
635        return False
636    return True
637
638
639def is_sim_ready_by_adb(log, ad):
640    state = ad.adb.getprop("gsm.sim.state")
641    ad.log.info("gsm.sim.state = %s", state)
642    return state == SIM_STATE_READY or state == SIM_STATE_LOADED
643
644
645def wait_for_sim_ready_by_adb(log, ad, wait_time=90):
646    return _wait_for_droid_in_state(log, ad, wait_time, is_sim_ready_by_adb)
647
648
649def is_sims_ready_by_adb(log, ad):
650    states = list(ad.adb.getprop("gsm.sim.state").split(","))
651    ad.log.info("gsm.sim.state = %s", states)
652    for state in states:
653        if state != SIM_STATE_READY and state != SIM_STATE_LOADED:
654            return False
655    return True
656
657
658def wait_for_sims_ready_by_adb(log, ad, wait_time=90):
659    return _wait_for_droid_in_state(log, ad, wait_time, is_sims_ready_by_adb)
660
661
662def get_service_state_by_adb(log, ad):
663    output = ad.adb.shell("dumpsys telephony.registry | grep mServiceState")
664    if "mVoiceRegState" in output:
665        result = re.findall(r"mVoiceRegState=(\S+)\((\S+)\)", output)
666        if result:
667            if getattr(ad, 'dsds', False):
668                default_slot = getattr(ad, 'default_slot', 0)
669                ad.log.info("mVoiceRegState is %s %s", result[default_slot][0],
670                            result[default_slot][1])
671                return result[default_slot][1]
672            else:
673                ad.log.info("mVoiceRegState is %s %s", result[0][0],
674                            result[0][1])
675                return result[0][1]
676    else:
677        result = re.search(r"mServiceState=(\S+)", output)
678        if result:
679            ad.log.info("mServiceState=%s %s", result.group(1),
680                        SERVICE_STATE_MAPPING[result.group(1)])
681            return SERVICE_STATE_MAPPING[result.group(1)]
682
683
684def _is_expecting_event(event_recv_list):
685    """ check for more event is expected in event list
686
687    Args:
688        event_recv_list: list of events
689    Returns:
690        result: True if more events are expected. False if not.
691    """
692    for state in event_recv_list:
693        if state is False:
694            return True
695    return False
696
697
698def _set_event_list(event_recv_list, sub_id_list, sub_id, value):
699    """ set received event in expected event list
700
701    Args:
702        event_recv_list: list of received events
703        sub_id_list: subscription ID list
704        sub_id: subscription id of current event
705        value: True or False
706    Returns:
707        None.
708    """
709    for i in range(len(sub_id_list)):
710        if sub_id_list[i] == sub_id:
711            event_recv_list[i] = value
712
713
714def _wait_for_bluetooth_in_state(log, ad, state, max_wait):
715    # FIXME: These event names should be defined in a common location
716    _BLUETOOTH_STATE_ON_EVENT = 'BluetoothStateChangedOn'
717    _BLUETOOTH_STATE_OFF_EVENT = 'BluetoothStateChangedOff'
718    ad.ed.clear_events(_BLUETOOTH_STATE_ON_EVENT)
719    ad.ed.clear_events(_BLUETOOTH_STATE_OFF_EVENT)
720
721    ad.droid.bluetoothStartListeningForAdapterStateChange()
722    try:
723        bt_state = ad.droid.bluetoothCheckState()
724        if bt_state == state:
725            return True
726        if max_wait <= 0:
727            ad.log.error("Time out: bluetooth state still %s, expecting %s",
728                         bt_state, state)
729            return False
730
731        event = {
732            False: _BLUETOOTH_STATE_OFF_EVENT,
733            True: _BLUETOOTH_STATE_ON_EVENT
734        }[state]
735        event = ad.ed.pop_event(event, max_wait)
736        ad.log.info("Got event %s", event['name'])
737        return True
738    except Empty:
739        ad.log.error("Time out: bluetooth state still in %s, expecting %s",
740                     bt_state, state)
741        return False
742    finally:
743        ad.droid.bluetoothStopListeningForAdapterStateChange()
744
745
746# TODO: replace this with an event-based function
747def _wait_for_wifi_in_state(log, ad, state, max_wait):
748    return _wait_for_droid_in_state(log, ad, max_wait,
749        lambda log, ad, state: \
750                (True if ad.droid.wifiCheckState() == state else False),
751                state)
752
753
754def toggle_airplane_mode_msim(log, ad, new_state=None, strict_checking=True):
755    """ Toggle the state of airplane mode.
756
757    Args:
758        log: log handler.
759        ad: android_device object.
760        new_state: Airplane mode state to set to.
761            If None, opposite of the current state.
762        strict_checking: Whether to turn on strict checking that checks all features.
763
764    Returns:
765        result: True if operation succeed. False if error happens.
766    """
767
768    cur_state = ad.droid.connectivityCheckAirplaneMode()
769    if cur_state == new_state:
770        ad.log.info("Airplane mode already in %s", new_state)
771        return True
772    elif new_state is None:
773        new_state = not cur_state
774        ad.log.info("Toggle APM mode, from current tate %s to %s", cur_state,
775                    new_state)
776    sub_id_list = []
777    active_sub_info = ad.droid.subscriptionGetAllSubInfoList()
778    if active_sub_info:
779        for info in active_sub_info:
780            sub_id_list.append(info['subscriptionId'])
781
782    ad.ed.clear_all_events()
783    time.sleep(0.1)
784    service_state_list = []
785    if new_state:
786        service_state_list.append(SERVICE_STATE_POWER_OFF)
787        ad.log.info("Turn on airplane mode")
788
789    else:
790        # If either one of these 3 events show up, it should be OK.
791        # Normal SIM, phone in service
792        service_state_list.append(SERVICE_STATE_IN_SERVICE)
793        # NO SIM, or Dead SIM, or no Roaming coverage.
794        service_state_list.append(SERVICE_STATE_OUT_OF_SERVICE)
795        service_state_list.append(SERVICE_STATE_EMERGENCY_ONLY)
796        ad.log.info("Turn off airplane mode")
797
798    for sub_id in sub_id_list:
799        ad.droid.telephonyStartTrackingServiceStateChangeForSubscription(
800            sub_id)
801
802    timeout_time = time.time() + MAX_WAIT_TIME_AIRPLANEMODE_EVENT
803    ad.droid.connectivityToggleAirplaneMode(new_state)
804
805    try:
806        try:
807            event = ad.ed.wait_for_event(
808                EventServiceStateChanged,
809                is_event_match_for_list,
810                timeout=MAX_WAIT_TIME_AIRPLANEMODE_EVENT,
811                field=ServiceStateContainer.SERVICE_STATE,
812                value_list=service_state_list)
813            ad.log.info("Got event %s", event)
814        except Empty:
815            ad.log.warning("Did not get expected service state change to %s",
816                           service_state_list)
817        finally:
818            for sub_id in sub_id_list:
819                ad.droid.telephonyStopTrackingServiceStateChangeForSubscription(
820                    sub_id)
821    except Exception as e:
822        ad.log.error(e)
823
824    # APM on (new_state=True) will turn off bluetooth but may not turn it on
825    try:
826        if new_state and not _wait_for_bluetooth_in_state(
827                log, ad, False, timeout_time - time.time()):
828            ad.log.error(
829                "Failed waiting for bluetooth during airplane mode toggle")
830            if strict_checking: return False
831    except Exception as e:
832        ad.log.error("Failed to check bluetooth state due to %s", e)
833        if strict_checking:
834            raise
835
836    # APM on (new_state=True) will turn off wifi but may not turn it on
837    if new_state and not _wait_for_wifi_in_state(log, ad, False,
838                                                 timeout_time - time.time()):
839        ad.log.error("Failed waiting for wifi during airplane mode toggle on")
840        if strict_checking: return False
841
842    if ad.droid.connectivityCheckAirplaneMode() != new_state:
843        ad.log.error("Set airplane mode to %s failed", new_state)
844        return False
845    return True
846
847
848def wait_for_cbrs_data_active_sub_change_event(
849        ad,
850        event_tracking_started=False,
851        timeout=120):
852    """Wait for an data change event on specified subscription.
853
854    Args:
855        ad: android device object.
856        event_tracking_started: True if event tracking already state outside
857        timeout: time to wait for event
858
859    Returns:
860        True: if data change event is received.
861        False: if data change event is not received.
862    """
863    if not event_tracking_started:
864        ad.ed.clear_events(EventActiveDataSubIdChanged)
865        ad.droid.telephonyStartTrackingActiveDataChange()
866    try:
867        ad.ed.wait_for_event(
868            EventActiveDataSubIdChanged,
869            is_event_match,
870            timeout=timeout)
871        ad.log.info("Got event activedatasubidchanged")
872    except Empty:
873        ad.log.info("No event for data subid change")
874        return False
875    finally:
876        if not event_tracking_started:
877            ad.droid.telephonyStopTrackingActiveDataChange()
878    return True
879
880
881def is_current_data_on_cbrs(ad, cbrs_subid):
882    """Verifies if current data sub is on CBRS
883
884    Args:
885        ad: android device object.
886        cbrs_subid: sub_id against which we need to check
887
888    Returns:
889        True: if data is on cbrs
890        False: if data is not on cbrs
891    """
892    if cbrs_subid is None:
893        return False
894    current_data = ad.droid.subscriptionGetActiveDataSubscriptionId()
895    ad.log.info("Current Data subid %s cbrs_subid %s", current_data, cbrs_subid)
896    if current_data == cbrs_subid:
897        return True
898    else:
899        return False
900
901
902def get_current_override_network_type(ad, timeout=30):
903    """Returns current override network type
904
905    Args:
906        ad: android device object.
907        timeout: max time to wait for event
908
909    Returns:
910        value: current override type
911        -1: if no event received
912    """
913    override_value_list = [OverrideNetworkContainer.OVERRIDE_NETWORK_TYPE_NR_NSA,
914                           OverrideNetworkContainer.OVERRIDE_NETWORK_TYPE_NONE,
915                           OverrideNetworkContainer.OVERRIDE_NETWORK_TYPE_NR_MMWAVE,
916                           OverrideNetworkContainer.OVERRIDE_NETWORK_TYPE_LTE_CA,
917                           OverrideNetworkContainer.OVERRIDE_NETWORK_TYPE_LTE_ADVANCED_PRO]
918    ad.ed.clear_events(EventDisplayInfoChanged)
919    ad.droid.telephonyStartTrackingDisplayInfoChange()
920    try:
921        event = ad.ed.wait_for_event(
922                    EventDisplayInfoChanged,
923                    is_event_match_for_list,
924                    timeout=timeout,
925                    field=DisplayInfoContainer.OVERRIDE,
926                    value_list=override_value_list)
927        override_type = event['data']['override']
928        ad.log.info("Current Override Type is %s", override_type)
929        return override_type
930    except Empty:
931        ad.log.info("No event for display info change")
932        return -1
933    finally:
934        ad.droid.telephonyStopTrackingDisplayInfoChange()
935    return -1
936
937
938def _phone_number_remove_prefix(number):
939    """Remove the country code and other prefix from the input phone number.
940    Currently only handle phone number with the following formats:
941        (US phone number format)
942        +1abcxxxyyyy
943        1abcxxxyyyy
944        abcxxxyyyy
945        abc xxx yyyy
946        abc.xxx.yyyy
947        abc-xxx-yyyy
948        (EEUK phone number format)
949        +44abcxxxyyyy
950        0abcxxxyyyy
951
952    Args:
953        number: input phone number
954
955    Returns:
956        Phone number without country code or prefix
957    """
958    if number is None:
959        return None, None
960    for country_code in COUNTRY_CODE_LIST:
961        if number.startswith(country_code):
962            return number[len(country_code):], country_code
963    if number[0] == "1" or number[0] == "0":
964        return number[1:], None
965    return number, None
966
967
968def check_phone_number_match(number1, number2):
969    """Check whether two input phone numbers match or not.
970
971    Compare the two input phone numbers.
972    If they match, return True; otherwise, return False.
973    Currently only handle phone number with the following formats:
974        (US phone number format)
975        +1abcxxxyyyy
976        1abcxxxyyyy
977        abcxxxyyyy
978        abc xxx yyyy
979        abc.xxx.yyyy
980        abc-xxx-yyyy
981        (EEUK phone number format)
982        +44abcxxxyyyy
983        0abcxxxyyyy
984
985        There are some scenarios we can not verify, one example is:
986            number1 = +15555555555, number2 = 5555555555
987            (number2 have no country code)
988
989    Args:
990        number1: 1st phone number to be compared.
991        number2: 2nd phone number to be compared.
992
993    Returns:
994        True if two phone numbers match. Otherwise False.
995    """
996    number1 = phone_number_formatter(number1)
997    number2 = phone_number_formatter(number2)
998    # Handle extra country code attachment when matching phone number
999    if number1[-7:] in number2 or number2[-7:] in number1:
1000        return True
1001    else:
1002        logging.info("phone number1 %s and number2 %s does not match" %
1003                     (number1, number2))
1004        return False
1005
1006
1007def get_call_state_by_adb(ad):
1008    slot_index_of_default_voice_subid = get_slot_index_from_subid(ad,
1009        get_incoming_voice_sub_id(ad))
1010    output = ad.adb.shell("dumpsys telephony.registry | grep mCallState")
1011    if "mCallState" in output:
1012        call_state_list = re.findall("mCallState=(\d)", output)
1013        if call_state_list:
1014            return call_state_list[slot_index_of_default_voice_subid]
1015
1016
1017def check_call_state_connected_by_adb(ad):
1018    return "2" in get_call_state_by_adb(ad)
1019
1020
1021def check_call_state_idle_by_adb(ad):
1022    return "0" in get_call_state_by_adb(ad)
1023
1024
1025def check_call_state_ring_by_adb(ad):
1026    return "1" in get_call_state_by_adb(ad)
1027
1028
1029def get_incoming_call_number_by_adb(ad):
1030    output = ad.adb.shell(
1031        "dumpsys telephony.registry | grep mCallIncomingNumber")
1032    return re.search(r"mCallIncomingNumber=(.*)", output).group(1)
1033
1034
1035def dumpsys_all_call_info(ad):
1036    """ Get call information by dumpsys telecom. """
1037    output = ad.adb.shell("dumpsys telecom")
1038    calls = re.findall("Call TC@\d+: {(.*?)}", output, re.DOTALL)
1039    calls_info = []
1040    for call in calls:
1041        call_info = {}
1042        for attr in ("startTime", "endTime", "direction", "isInterrupted",
1043                     "callTechnologies", "callTerminationsReason",
1044                     "connectionService", "isVideoCall", "callProperties"):
1045            match = re.search(r"%s: (.*)" % attr, call)
1046            if match:
1047                if attr in ("startTime", "endTime"):
1048                    call_info[attr] = epoch_to_log_line_timestamp(
1049                        int(match.group(1)))
1050                else:
1051                    call_info[attr] = match.group(1)
1052        call_info["inCallServices"] = re.findall(r"name: (.*)", call)
1053        calls_info.append(call_info)
1054    ad.log.debug("calls_info = %s", calls_info)
1055    return calls_info
1056
1057
1058def dumpsys_carrier_config(ad):
1059    output = ad.adb.shell("dumpsys carrier_config").split("\n")
1060    output_phone_id_0 = []
1061    output_phone_id_1 = []
1062    current_output = []
1063    for line in output:
1064        if "Phone Id = 0" in line:
1065            current_output = output_phone_id_0
1066        elif "Phone Id = 1" in line:
1067            current_output = output_phone_id_1
1068        current_output.append(line.strip())
1069
1070    configs = {}
1071    if ad.adb.getprop("ro.build.version.release")[0] in ("9", "P"):
1072        phone_count = 1
1073        if "," in ad.adb.getprop("gsm.network.type"):
1074            phone_count = 2
1075    else:
1076        phone_count = ad.droid.telephonyGetPhoneCount()
1077
1078    slot_0_subid = get_subid_from_logical_slot(ad, 0)
1079    if slot_0_subid != INVALID_SUB_ID:
1080        configs[slot_0_subid] = {}
1081
1082    if phone_count == 2:
1083        slot_1_subid = get_subid_from_logical_slot(ad, 1)
1084        if slot_1_subid != INVALID_SUB_ID:
1085            configs[slot_1_subid] = {}
1086
1087    attrs = [attr for attr in dir(CarrierConfigs) if not attr.startswith("__")]
1088    for attr in attrs:
1089        attr_string = getattr(CarrierConfigs, attr)
1090        values = re.findall(
1091            r"%s = (\S+)" % attr_string, "\n".join(output_phone_id_0))
1092
1093        if slot_0_subid != INVALID_SUB_ID:
1094            if values:
1095                value = values[-1]
1096                if value == "true":
1097                    configs[slot_0_subid][attr_string] = True
1098                elif value == "false":
1099                    configs[slot_0_subid][attr_string] = False
1100                elif attr_string == CarrierConfigs.DEFAULT_WFC_IMS_MODE_INT:
1101                    if value == "0":
1102                        configs[slot_0_subid][attr_string] = WFC_MODE_WIFI_ONLY
1103                    elif value == "1":
1104                        configs[slot_0_subid][attr_string] = \
1105                            WFC_MODE_CELLULAR_PREFERRED
1106                    elif value == "2":
1107                        configs[slot_0_subid][attr_string] = \
1108                            WFC_MODE_WIFI_PREFERRED
1109                else:
1110                    try:
1111                        configs[slot_0_subid][attr_string] = int(value)
1112                    except Exception:
1113                        configs[slot_0_subid][attr_string] = value
1114            else:
1115                configs[slot_0_subid][attr_string] = None
1116
1117        if phone_count == 2:
1118            if slot_1_subid != INVALID_SUB_ID:
1119                values = re.findall(
1120                    r"%s = (\S+)" % attr_string, "\n".join(output_phone_id_1))
1121                if values:
1122                    value = values[-1]
1123                    if value == "true":
1124                        configs[slot_1_subid][attr_string] = True
1125                    elif value == "false":
1126                        configs[slot_1_subid][attr_string] = False
1127                    elif attr_string == CarrierConfigs.DEFAULT_WFC_IMS_MODE_INT:
1128                        if value == "0":
1129                            configs[slot_1_subid][attr_string] = \
1130                                WFC_MODE_WIFI_ONLY
1131                        elif value == "1":
1132                            configs[slot_1_subid][attr_string] = \
1133                                WFC_MODE_CELLULAR_PREFERRED
1134                        elif value == "2":
1135                            configs[slot_1_subid][attr_string] = \
1136                                WFC_MODE_WIFI_PREFERRED
1137                    else:
1138                        try:
1139                            configs[slot_1_subid][attr_string] = int(value)
1140                        except Exception:
1141                            configs[slot_1_subid][attr_string] = value
1142                else:
1143                    configs[slot_1_subid][attr_string] = None
1144    return configs
1145
1146
1147def get_phone_capability(ad):
1148    carrier_configs = dumpsys_carrier_config(ad)
1149    for sub_id in carrier_configs:
1150        capabilities = []
1151        if carrier_configs[sub_id][CarrierConfigs.VOLTE_AVAILABLE_BOOL]:
1152            capabilities.append(CAPABILITY_VOLTE)
1153        if carrier_configs[sub_id][CarrierConfigs.WFC_IMS_AVAILABLE_BOOL]:
1154            capabilities.append(CAPABILITY_WFC)
1155        if carrier_configs[sub_id][CarrierConfigs.EDITABLE_WFC_MODE_BOOL]:
1156            capabilities.append(CAPABILITY_WFC_MODE_CHANGE)
1157        if carrier_configs[sub_id][CarrierConfigs.SUPPORT_CONFERENCE_CALL_BOOL]:
1158            capabilities.append(CAPABILITY_CONFERENCE)
1159        if carrier_configs[sub_id][CarrierConfigs.VT_AVAILABLE_BOOL]:
1160            capabilities.append(CAPABILITY_VT)
1161        if carrier_configs[sub_id][CarrierConfigs.VOLTE_PROVISIONED_BOOL]:
1162            capabilities.append(CAPABILITY_VOLTE_PROVISIONING)
1163        if carrier_configs[sub_id][CarrierConfigs.VOLTE_OVERRIDE_WFC_BOOL]:
1164            capabilities.append(CAPABILITY_VOLTE_OVERRIDE_WFC_PROVISIONING)
1165        if carrier_configs[sub_id][CarrierConfigs.HIDE_ENHANCED_4G_LTE_BOOL]:
1166            capabilities.append(CAPABILITY_HIDE_ENHANCED_4G_LTE_BOOL)
1167
1168        ad.log.info("Capabilities of sub ID %s: %s", sub_id, capabilities)
1169        if not getattr(ad, 'telephony', {}):
1170            ad.telephony["subscription"] = {}
1171            ad.telephony["subscription"][sub_id] = {}
1172            setattr(
1173                ad.telephony["subscription"][sub_id],
1174                'capabilities', capabilities)
1175
1176        else:
1177            ad.telephony["subscription"][sub_id]["capabilities"] = capabilities
1178        if CAPABILITY_WFC not in capabilities:
1179            wfc_modes = []
1180        else:
1181            if carrier_configs[sub_id].get(
1182                CarrierConfigs.EDITABLE_WFC_MODE_BOOL, False):
1183                wfc_modes = [
1184                    WFC_MODE_CELLULAR_PREFERRED,
1185                    WFC_MODE_WIFI_PREFERRED]
1186            else:
1187                wfc_modes = [
1188                    carrier_configs[sub_id].get(
1189                        CarrierConfigs.DEFAULT_WFC_IMS_MODE_INT,
1190                        WFC_MODE_CELLULAR_PREFERRED)
1191                ]
1192        if carrier_configs[sub_id].get(
1193            CarrierConfigs.WFC_SUPPORTS_WIFI_ONLY_BOOL,
1194            False) and WFC_MODE_WIFI_ONLY not in wfc_modes:
1195            wfc_modes.append(WFC_MODE_WIFI_ONLY)
1196        ad.telephony["subscription"][sub_id]["wfc_modes"] = wfc_modes
1197        if wfc_modes:
1198            ad.log.info("Supported WFC modes for sub ID %s: %s", sub_id,
1199                wfc_modes)
1200
1201
1202def get_capability_for_subscription(ad, capability, subid):
1203    if capability in ad.telephony["subscription"][subid].get(
1204        "capabilities", []):
1205        ad.log.info('Capability "%s" is available for sub ID %s.',
1206            capability, subid)
1207        return True
1208    else:
1209        ad.log.info('Capability "%s" is NOT available for sub ID %s.',
1210            capability, subid)
1211        return False
1212
1213
1214def phone_number_formatter(input_string, formatter=None):
1215    """Get expected format of input phone number string.
1216
1217    Args:
1218        input_string: (string) input phone number.
1219            The input could be 10/11/12 digital, with or without " "/"-"/"."
1220        formatter: (int) expected format, this could be 7/10/11/12
1221            if formatter is 7: output string would be 7 digital number.
1222            if formatter is 10: output string would be 10 digital (standard) number.
1223            if formatter is 11: output string would be "1" + 10 digital number.
1224            if formatter is 12: output string would be "+1" + 10 digital number.
1225
1226    Returns:
1227        If no error happen, return phone number in expected format.
1228        Else, return None.
1229    """
1230    if not input_string:
1231        return ""
1232    # make sure input_string is 10 digital
1233    # Remove white spaces, dashes, dots
1234    input_string = input_string.replace(" ", "").replace("-", "").replace(
1235        ".", "")
1236
1237    # Remove a country code with '+' sign and add 0 for Japan/Korea Carriers.
1238    if (len(input_string) == 13
1239            and (input_string[0:3] == "+81" or input_string[0:3] == "+82")):
1240        input_string = "0" + input_string[3:]
1241        return input_string
1242
1243    if not formatter:
1244        return input_string
1245
1246    # Remove leading 0 for the phone with area code started with 0
1247    input_string = input_string.lstrip("0")
1248
1249    # Remove "1"  or "+1"from front
1250    if (len(input_string) == PHONE_NUMBER_STRING_FORMAT_11_DIGIT
1251            and input_string[0] == "1"):
1252        input_string = input_string[1:]
1253    elif (len(input_string) == PHONE_NUMBER_STRING_FORMAT_12_DIGIT
1254          and input_string[0:2] == "+1"):
1255        input_string = input_string[2:]
1256    elif (len(input_string) == PHONE_NUMBER_STRING_FORMAT_7_DIGIT
1257          and formatter == PHONE_NUMBER_STRING_FORMAT_7_DIGIT):
1258        return input_string
1259    elif len(input_string) != PHONE_NUMBER_STRING_FORMAT_10_DIGIT:
1260        return None
1261    # change input_string according to format
1262    if formatter == PHONE_NUMBER_STRING_FORMAT_12_DIGIT:
1263        input_string = "+1" + input_string
1264    elif formatter == PHONE_NUMBER_STRING_FORMAT_11_DIGIT:
1265        input_string = "1" + input_string
1266    elif formatter == PHONE_NUMBER_STRING_FORMAT_10_DIGIT:
1267        input_string = input_string
1268    elif formatter == PHONE_NUMBER_STRING_FORMAT_7_DIGIT:
1269        input_string = input_string[3:]
1270    else:
1271        return None
1272    return input_string
1273
1274
1275def get_internet_connection_type(log, ad):
1276    """Get current active connection type name.
1277
1278    Args:
1279        log: Log object.
1280        ad: Android Device Object.
1281    Returns:
1282        current active connection type name.
1283    """
1284    if not ad.droid.connectivityNetworkIsConnected():
1285        return 'none'
1286    return connection_type_from_type_string(
1287        ad.droid.connectivityNetworkGetActiveConnectionTypeName())
1288
1289
1290def verify_http_connection(log,
1291                           ad,
1292                           url="https://www.google.com",
1293                           retry=5,
1294                           retry_interval=15,
1295                           expected_state=True):
1296    """Make ping request and return status.
1297
1298    Args:
1299        log: log object
1300        ad: Android Device Object.
1301        url: Optional. The ping request will be made to this URL.
1302            Default Value is "http://www.google.com/".
1303
1304    """
1305    if not getattr(ad, "data_droid", None):
1306        ad.data_droid, ad.data_ed = ad.get_droid()
1307        ad.data_ed.start()
1308    else:
1309        try:
1310            if not ad.data_droid.is_live:
1311                ad.data_droid, ad.data_ed = ad.get_droid()
1312                ad.data_ed.start()
1313        except Exception:
1314            ad.log.info("Start new sl4a session for file download")
1315            ad.data_droid, ad.data_ed = ad.get_droid()
1316            ad.data_ed.start()
1317    for i in range(0, retry + 1):
1318        try:
1319            http_response = ad.data_droid.httpPing(url)
1320        except Exception as e:
1321            ad.log.info("httpPing with %s", e)
1322            http_response = None
1323        if (expected_state and http_response) or (not expected_state
1324                                                  and not http_response):
1325            ad.log.info("Http ping response for %s meet expected %s", url,
1326                        expected_state)
1327            return True
1328        if i < retry:
1329            time.sleep(retry_interval)
1330    ad.log.error("Http ping to %s is %s after %s second, expecting %s", url,
1331                 http_response, i * retry_interval, expected_state)
1332    return False
1333
1334
1335def _generate_file_directory_and_file_name(url, out_path):
1336    file_name = url.split("/")[-1]
1337    if not out_path:
1338        file_directory = "/sdcard/Download/"
1339    elif not out_path.endswith("/"):
1340        file_directory, file_name = os.path.split(out_path)
1341    else:
1342        file_directory = out_path
1343    return file_directory, file_name
1344
1345
1346def _check_file_existence(ad, file_path, expected_file_size=None):
1347    """Check file existance by file_path. If expected_file_size
1348       is provided, then also check if the file meet the file size requirement.
1349    """
1350    out = None
1351    try:
1352        out = ad.adb.shell('stat -c "%%s" %s' % file_path)
1353    except AdbError:
1354        pass
1355    # Handle some old version adb returns error message "No such" into std_out
1356    if out and "No such" not in out:
1357        if expected_file_size:
1358            file_size = int(out)
1359            if file_size >= expected_file_size:
1360                ad.log.info("File %s of size %s exists", file_path, file_size)
1361                return True
1362            else:
1363                ad.log.info("File %s is of size %s, does not meet expected %s",
1364                            file_path, file_size, expected_file_size)
1365                return False
1366        else:
1367            ad.log.info("File %s exists", file_path)
1368            return True
1369    else:
1370        ad.log.info("File %s does not exist.", file_path)
1371        return False
1372
1373
1374def verify_internet_connection_by_ping(log,
1375                                       ad,
1376                                       retries=1,
1377                                       expected_state=True,
1378                                       timeout=60):
1379    """Verify internet connection by ping test.
1380
1381    Args:
1382        log: log object
1383        ad: Android Device Object.
1384
1385    """
1386    begin_time = get_current_epoch_time()
1387    ip_addr = "54.230.144.105"
1388    for dest in ("www.google.com", "www.amazon.com", ip_addr):
1389        for i in range(retries):
1390            ad.log.info("Ping %s - attempt %d", dest, i + 1)
1391            result = adb_shell_ping(
1392                ad, count=5, timeout=timeout, loss_tolerance=40, dest_ip=dest)
1393            if result == expected_state:
1394                ad.log.info(
1395                    "Internet connection by pinging to %s is %s as expected",
1396                    dest, expected_state)
1397                if dest == ip_addr:
1398                    ad.log.warning("Suspect dns failure")
1399                    ad.log.info("DNS config: %s",
1400                                ad.adb.shell("getprop | grep dns").replace(
1401                                    "\n", " "))
1402                    return False
1403                return True
1404            else:
1405                ad.log.warning(
1406                    "Internet connection test by pinging %s is %s, expecting %s",
1407                    dest, result, expected_state)
1408                if get_current_epoch_time() - begin_time < timeout * 1000:
1409                    time.sleep(5)
1410    ad.log.error("Ping test doesn't meet expected %s", expected_state)
1411    return False
1412
1413
1414def verify_internet_connection(log, ad, retries=3, expected_state=True):
1415    """Verify internet connection by ping test and http connection.
1416
1417    Args:
1418        log: log object
1419        ad: Android Device Object.
1420
1421    """
1422    if ad.droid.connectivityNetworkIsConnected() != expected_state:
1423        ad.log.info("NetworkIsConnected = %s, expecting %s",
1424                    not expected_state, expected_state)
1425    if verify_internet_connection_by_ping(
1426            log, ad, retries=retries, expected_state=expected_state):
1427        return True
1428    for url in ("https://www.google.com", "https://www.amazon.com"):
1429        if verify_http_connection(
1430                log, ad, url=url, retry=retries,
1431                expected_state=expected_state):
1432            return True
1433    ad.log.info("DNS config: %s", " ".join(
1434        ad.adb.shell("getprop | grep dns").split()))
1435    ad.log.info("Interface info:\n%s", ad.adb.shell("ifconfig"))
1436    ad.log.info("NetworkAgentInfo: %s",
1437                ad.adb.shell("dumpsys connectivity | grep NetworkAgentInfo"))
1438    return False
1439
1440
1441def iperf_test_with_options(log,
1442                            ad,
1443                            iperf_server,
1444                            iperf_option,
1445                            timeout=180,
1446                            rate_dict=None,
1447                            blocking=True,
1448                            log_file_path=None):
1449    """iperf adb run helper.
1450
1451    Args:
1452        log: log object
1453        ad: Android Device Object.
1454        iperf_server: The iperf host url".
1455        iperf_option: The options to pass to iperf client
1456        timeout: timeout for file download to complete.
1457        rate_dict: dictionary that can be passed in to save data
1458        blocking: run iperf in blocking mode if True
1459        log_file_path: location to save logs
1460    Returns:
1461        True if iperf runs without throwing an exception
1462    """
1463    try:
1464        if log_file_path:
1465            ad.adb.shell("rm %s" % log_file_path, ignore_status=True)
1466        ad.log.info("Running adb iperf test with server %s", iperf_server)
1467        ad.log.info("iperf options are %s", iperf_option)
1468        if not blocking:
1469            ad.run_iperf_client_nb(
1470                iperf_server,
1471                iperf_option,
1472                timeout=timeout + 60,
1473                log_file_path=log_file_path)
1474            return True
1475        result, data = ad.run_iperf_client(
1476            iperf_server, iperf_option, timeout=timeout + 120)
1477        ad.log.info("iperf test result with server %s is %s", iperf_server,
1478                    result)
1479        if result:
1480            iperf_str = ''.join(data)
1481            iperf_result = ipf.IPerfResult(iperf_str, 'None')
1482            if "-u" in iperf_option:
1483                udp_rate = iperf_result.avg_rate
1484                if udp_rate is None:
1485                    ad.log.warning(
1486                        "UDP rate is none, IPerf server returned error: %s",
1487                        iperf_result.error)
1488                ad.log.info("iperf3 UDP DL speed is %.6s Mbps", (udp_rate/1000000))
1489            else:
1490                tx_rate = iperf_result.avg_send_rate
1491                rx_rate = iperf_result.avg_receive_rate
1492                if (tx_rate or rx_rate) is None:
1493                    ad.log.warning(
1494                        "A TCP rate is none, iperf server returned error: %s",
1495                        iperf_result.error)
1496                ad.log.info(
1497                    "iperf3 TCP - UL speed is %.6s Mbps, DL speed is %.6s Mbps",
1498                    (tx_rate/1000000), (rx_rate/1000000))
1499            if rate_dict is not None:
1500                rate_dict["Uplink"] = tx_rate
1501                rate_dict["Downlink"] = rx_rate
1502        return result
1503    except AdbError as e:
1504        ad.log.warning("Fail to run iperf test with exception %s", e)
1505        raise
1506
1507
1508def iperf_udp_test_by_adb(log,
1509                          ad,
1510                          iperf_server,
1511                          port_num=None,
1512                          reverse=False,
1513                          timeout=180,
1514                          limit_rate=None,
1515                          pacing_timer=None,
1516                          omit=10,
1517                          ipv6=False,
1518                          rate_dict=None,
1519                          blocking=True,
1520                          log_file_path=None,
1521                          retry=5):
1522    """Iperf test by adb using UDP.
1523
1524    Args:
1525        log: log object
1526        ad: Android Device Object.
1527        iperf_Server: The iperf host url".
1528        port_num: TCP/UDP server port
1529        reverse: whether to test download instead of upload
1530        timeout: timeout for file download to complete.
1531        limit_rate: iperf bandwidth option. None by default
1532        omit: the omit option provided in iperf command.
1533        ipv6: whether to run the test as ipv6
1534        rate_dict: dictionary that can be passed in to save data
1535        blocking: run iperf in blocking mode if True
1536        log_file_path: location to save logs
1537        retry: times of retry when the server is unavailable
1538    """
1539    iperf_option = "-u -i 1 -t %s -O %s -J" % (timeout, omit)
1540    if limit_rate:
1541        iperf_option += " -b %s" % limit_rate
1542    if pacing_timer:
1543        iperf_option += " --pacing-timer %s" % pacing_timer
1544    if ipv6:
1545        iperf_option += " -6"
1546    if reverse:
1547        iperf_option += " -R"
1548    for _ in range(retry):
1549        if port_num:
1550            iperf_option_final = iperf_option + " -p %s" % port_num
1551            port_num += 1
1552        else:
1553            iperf_option_final = iperf_option
1554        try:
1555            return iperf_test_with_options(log,
1556                                           ad,
1557                                           iperf_server,
1558                                           iperf_option_final,
1559                                           timeout,
1560                                           rate_dict,
1561                                           blocking,
1562                                           log_file_path)
1563        except (AdbCommandError, TimeoutError) as error:
1564            continue
1565        except AdbError:
1566            return False
1567
1568
1569def iperf_test_by_adb(log,
1570                      ad,
1571                      iperf_server,
1572                      port_num=None,
1573                      reverse=False,
1574                      timeout=180,
1575                      limit_rate=None,
1576                      omit=10,
1577                      ipv6=False,
1578                      rate_dict=None,
1579                      blocking=True,
1580                      log_file_path=None,
1581                      retry=5):
1582    """Iperf test by adb using TCP.
1583
1584    Args:
1585        log: log object
1586        ad: Android Device Object.
1587        iperf_server: The iperf host url".
1588        port_num: TCP/UDP server port
1589        reverse: whether to test download instead of upload
1590        timeout: timeout for file download to complete.
1591        limit_rate: iperf bandwidth option. None by default
1592        omit: the omit option provided in iperf command.
1593        ipv6: whether to run the test as ipv6
1594        rate_dict: dictionary that can be passed in to save data
1595        blocking: run iperf in blocking mode if True
1596        log_file_path: location to save logs
1597        retry: times of retry when the server is unavailable
1598    """
1599    iperf_option = "-t %s -O %s -J" % (timeout, omit)
1600    if limit_rate:
1601        iperf_option += " -b %s" % limit_rate
1602    if ipv6:
1603        iperf_option += " -6"
1604    if reverse:
1605        iperf_option += " -R"
1606    for _ in range(retry):
1607        if port_num:
1608            iperf_option_final = iperf_option + " -p %s" % port_num
1609            port_num += 1
1610        else:
1611            iperf_option_final = iperf_option
1612        try:
1613            return iperf_test_with_options(log,
1614                                           ad,
1615                                           iperf_server,
1616                                           iperf_option_final,
1617                                           timeout,
1618                                           rate_dict=rate_dict,
1619                                           blocking=blocking,
1620                                           log_file_path=log_file_path)
1621        except (AdbCommandError, TimeoutError) as error:
1622            continue
1623        except AdbError:
1624            return False
1625
1626
1627def trigger_modem_crash(ad, timeout=120):
1628    cmd = "echo restart > /sys/kernel/debug/msm_subsys/modem"
1629    ad.log.info("Triggering Modem Crash from kernel using adb command %s", cmd)
1630    ad.adb.shell(cmd)
1631    time.sleep(timeout)
1632    return True
1633
1634
1635def trigger_modem_crash_by_modem(ad, timeout=120):
1636    begin_time = get_device_epoch_time(ad)
1637    ad.adb.shell(
1638        "setprop persist.vendor.sys.modem.diag.mdlog false",
1639        ignore_status=True)
1640    # Legacy pixels use persist.sys.modem.diag.mdlog.
1641    ad.adb.shell(
1642        "setprop persist.sys.modem.diag.mdlog false", ignore_status=True)
1643    disable_qxdm_logger(ad)
1644    cmd = ('am instrument -w -e request "4b 25 03 00" '
1645           '"com.google.mdstest/com.google.mdstest.instrument.'
1646           'ModemCommandInstrumentation"')
1647    ad.log.info("Crash modem by %s", cmd)
1648    ad.adb.shell(cmd, ignore_status=True)
1649    time.sleep(timeout)  # sleep time for sl4a stability
1650    reasons = ad.search_logcat("modem subsystem failure reason", begin_time)
1651    if reasons:
1652        ad.log.info("Modem crash is triggered successfully")
1653        ad.log.info(reasons[-1]["log_message"])
1654        return True
1655    else:
1656        ad.log.warning("There is no modem subsystem failure reason logcat")
1657        return False
1658
1659
1660def phone_switch_to_msim_mode(ad, retries=3, timeout=60):
1661    result = False
1662    if not ad.is_apk_installed("com.google.mdstest"):
1663        raise signals.TestAbortClass("mdstest is not installed")
1664    mode = ad.droid.telephonyGetPhoneCount()
1665    if mode == 2:
1666        ad.log.info("Device already in MSIM mode")
1667        return True
1668    for i in range(retries):
1669        ad.adb.shell(
1670        "setprop persist.vendor.sys.modem.diag.mdlog false", ignore_status=True)
1671        ad.adb.shell(
1672        "setprop persist.sys.modem.diag.mdlog false", ignore_status=True)
1673        disable_qxdm_logger(ad)
1674        cmd = ('am instrument -w -e request "WriteEFS" -e item '
1675               '"/google/pixel_multisim_config" -e data  "02 00 00 00" '
1676               '"com.google.mdstest/com.google.mdstest.instrument.'
1677               'ModemConfigInstrumentation"')
1678        ad.log.info("Switch to MSIM mode by using %s", cmd)
1679        ad.adb.shell(cmd, ignore_status=True)
1680        time.sleep(timeout)
1681        ad.adb.shell("setprop persist.radio.multisim.config dsds")
1682        reboot_device(ad)
1683        # Verify if device is really in msim mode
1684        mode = ad.droid.telephonyGetPhoneCount()
1685        if mode == 2:
1686            ad.log.info("Device correctly switched to MSIM mode")
1687            result = True
1688            if "Sprint" in ad.adb.getprop("gsm.sim.operator.alpha"):
1689                cmd = ('am instrument -w -e request "WriteEFS" -e item '
1690                       '"/google/pixel_dsds_imei_mapping_slot_record" -e data "03"'
1691                       ' "com.google.mdstest/com.google.mdstest.instrument.'
1692                       'ModemConfigInstrumentation"')
1693                ad.log.info("Switch Sprint to IMEI1 slot using %s", cmd)
1694                ad.adb.shell(cmd, ignore_status=True)
1695                time.sleep(timeout)
1696                reboot_device(ad)
1697            break
1698        else:
1699            ad.log.warning("Attempt %d - failed to switch to MSIM", (i + 1))
1700    return result
1701
1702
1703def phone_switch_to_ssim_mode(ad, retries=3, timeout=30):
1704    result = False
1705    if not ad.is_apk_installed("com.google.mdstest"):
1706        raise signals.TestAbortClass("mdstest is not installed")
1707    mode = ad.droid.telephonyGetPhoneCount()
1708    if mode == 1:
1709        ad.log.info("Device already in SSIM mode")
1710        return True
1711    for i in range(retries):
1712        ad.adb.shell(
1713        "setprop persist.vendor.sys.modem.diag.mdlog false", ignore_status=True)
1714        ad.adb.shell(
1715        "setprop persist.sys.modem.diag.mdlog false", ignore_status=True)
1716        disable_qxdm_logger(ad)
1717        cmds = ('am instrument -w -e request "WriteEFS" -e item '
1718                '"/google/pixel_multisim_config" -e data  "01 00 00 00" '
1719                '"com.google.mdstest/com.google.mdstest.instrument.'
1720                'ModemConfigInstrumentation"',
1721                'am instrument -w -e request "WriteEFS" -e item "/nv/item_files'
1722                '/modem/uim/uimdrv/uim_extended_slot_mapping_config" -e data '
1723                '"00 01 02 01" "com.google.mdstest/com.google.mdstest.'
1724                'instrument.ModemConfigInstrumentation"')
1725        for cmd in cmds:
1726            ad.log.info("Switch to SSIM mode by using %s", cmd)
1727            ad.adb.shell(cmd, ignore_status=True)
1728            time.sleep(timeout)
1729        ad.adb.shell("setprop persist.radio.multisim.config ssss")
1730        reboot_device(ad)
1731        # Verify if device is really in ssim mode
1732        mode = ad.droid.telephonyGetPhoneCount()
1733        if mode == 1:
1734            ad.log.info("Device correctly switched to SSIM mode")
1735            result = True
1736            break
1737        else:
1738            ad.log.warning("Attempt %d - failed to switch to SSIM", (i + 1))
1739    return result
1740
1741
1742def lock_lte_band_by_mds(ad, band):
1743    disable_qxdm_logger(ad)
1744    ad.log.info("Write band %s locking to efs file", band)
1745    if band == "4":
1746        item_string = (
1747            "4B 13 26 00 08 00 00 00 40 00 08 00 0B 00 08 00 00 00 00 00 00 00 "
1748            "2F 6E 76 2F 69 74 65 6D 5F 66 69 6C 65 73 2F 6D 6F 64 65 6D 2F 6D "
1749            "6D 6F 64 65 2F 6C 74 65 5F 62 61 6E 64 70 72 65 66 00")
1750    elif band == "13":
1751        item_string = (
1752            "4B 13 26 00 08 00 00 00 40 00 08 00 0A 00 00 10 00 00 00 00 00 00 "
1753            "2F 6E 76 2F 69 74 65 6D 5F 66 69 6C 65 73 2F 6D 6F 64 65 6D 2F 6D "
1754            "6D 6F 64 65 2F 6C 74 65 5F 62 61 6E 64 70 72 65 66 00")
1755    else:
1756        ad.log.error("Band %s is not supported", band)
1757        return False
1758    cmd = ('am instrument -w -e request "%s" com.google.mdstest/com.google.'
1759           'mdstest.instrument.ModemCommandInstrumentation')
1760    for _ in range(3):
1761        if "SUCCESS" in ad.adb.shell(cmd % item_string, ignore_status=True):
1762            break
1763    else:
1764        ad.log.error("Fail to write band by %s" % (cmd % item_string))
1765        return False
1766
1767    # EFS Sync
1768    item_string = "4B 13 30 00 2A 00 2F 00"
1769
1770    for _ in range(3):
1771        if "SUCCESS" in ad.adb.shell(cmd % item_string, ignore_status=True):
1772            break
1773    else:
1774        ad.log.error("Fail to sync efs by %s" % (cmd % item_string))
1775        return False
1776    time.sleep(5)
1777    reboot_device(ad)
1778
1779
1780def get_cell_data_roaming_state_by_adb(ad):
1781    """Get Cell Data Roaming state. True for enabled, False for disabled"""
1782    state_mapping = {"1": True, "0": False}
1783    return state_mapping[ad.adb.shell("settings get global data_roaming")]
1784
1785
1786def set_cell_data_roaming_state_by_adb(ad, state):
1787    """Set Cell Data Roaming state."""
1788    state_mapping = {True: "1", False: "0"}
1789    ad.log.info("Set data roaming to %s", state)
1790    ad.adb.shell("settings put global data_roaming %s" % state_mapping[state])
1791
1792
1793def toggle_cell_data_roaming(ad, state):
1794    """Enable cell data roaming for default data subscription.
1795
1796    Wait for the data roaming status to be DATA_STATE_CONNECTED
1797        or DATA_STATE_DISCONNECTED.
1798
1799    Args:
1800        log: Log object.
1801        ad: Android Device Object.
1802        state: True or False for enable or disable cell data roaming.
1803
1804    Returns:
1805        True if success.
1806        False if failed.
1807    """
1808    state_int = {True: DATA_ROAMING_ENABLE, False: DATA_ROAMING_DISABLE}[state]
1809    action_str = {True: "Enable", False: "Disable"}[state]
1810    if ad.droid.connectivityCheckDataRoamingMode() == state:
1811        ad.log.info("Data roaming is already in state %s", state)
1812        return True
1813    if not ad.droid.connectivitySetDataRoaming(state_int):
1814        ad.error.info("Fail to config data roaming into state %s", state)
1815        return False
1816    if ad.droid.connectivityCheckDataRoamingMode() == state:
1817        ad.log.info("Data roaming is configured into state %s", state)
1818        return True
1819    else:
1820        ad.log.error("Data roaming is not configured into state %s", state)
1821        return False
1822
1823
1824def verify_incall_state(log, ads, expected_status):
1825    """Verify phones in incall state or not.
1826
1827    Verify if all phones in the array <ads> are in <expected_status>.
1828
1829    Args:
1830        log: Log object.
1831        ads: Array of Android Device Object. All droid in this array will be tested.
1832        expected_status: If True, verify all Phones in incall state.
1833            If False, verify all Phones not in incall state.
1834
1835    """
1836    result = True
1837    for ad in ads:
1838        if ad.droid.telecomIsInCall() is not expected_status:
1839            ad.log.error("InCall status:%s, expected:%s",
1840                         ad.droid.telecomIsInCall(), expected_status)
1841            result = False
1842    return result
1843
1844
1845def verify_active_call_number(log, ad, expected_number):
1846    """Verify the number of current active call.
1847
1848    Verify if the number of current active call in <ad> is
1849        equal to <expected_number>.
1850
1851    Args:
1852        ad: Android Device Object.
1853        expected_number: Expected active call number.
1854    """
1855    calls = ad.droid.telecomCallGetCallIds()
1856    if calls is None:
1857        actual_number = 0
1858    else:
1859        actual_number = len(calls)
1860    if actual_number != expected_number:
1861        ad.log.error("Active Call number is %s, expecting", actual_number,
1862                     expected_number)
1863        return False
1864    return True
1865
1866
1867def num_active_calls(log, ad):
1868    """Get the count of current active calls.
1869
1870    Args:
1871        log: Log object.
1872        ad: Android Device Object.
1873
1874    Returns:
1875        Count of current active calls.
1876    """
1877    calls = ad.droid.telecomCallGetCallIds()
1878    return len(calls) if calls else 0
1879
1880
1881def get_carrier_provisioning_for_subscription(ad, feature_flag,
1882                                              tech, sub_id=None):
1883    """ Gets Provisioning Values for Subscription Id
1884
1885    Args:
1886        ad: Android device object.
1887        sub_id: Subscription Id
1888        feature_flag: voice, video, ut, sms
1889        tech: wlan, wwan
1890
1891    """
1892    try:
1893        if sub_id is None:
1894            sub_id = ad.droid.subscriptionGetDefaultVoiceSubId()
1895        result = ad.droid.imsMmTelIsSupported(sub_id, feature_flag, tech)
1896        ad.log.info("SubId %s - imsMmTelIsSupported for %s on %s - %s",
1897                    sub_id, feature_flag, tech, result)
1898        return result
1899    except Exception as e:
1900        ad.log.error(e)
1901        return False
1902
1903
1904def _wait_for_droid_in_state(log, ad, max_time, state_check_func, *args,
1905                             **kwargs):
1906    while max_time >= 0:
1907        if state_check_func(log, ad, *args, **kwargs):
1908            return True
1909
1910        time.sleep(WAIT_TIME_BETWEEN_STATE_CHECK)
1911        max_time -= WAIT_TIME_BETWEEN_STATE_CHECK
1912
1913    return False
1914
1915
1916def _wait_for_droid_in_state_for_subscription(
1917        log, ad, sub_id, max_time, state_check_func, *args, **kwargs):
1918    while max_time >= 0:
1919        if state_check_func(log, ad, sub_id, *args, **kwargs):
1920            return True
1921
1922        time.sleep(WAIT_TIME_BETWEEN_STATE_CHECK)
1923        max_time -= WAIT_TIME_BETWEEN_STATE_CHECK
1924
1925    return False
1926
1927
1928def _wait_for_droids_in_state(log, ads, max_time, state_check_func, *args,
1929                              **kwargs):
1930    while max_time > 0:
1931        success = True
1932        for ad in ads:
1933            if not state_check_func(log, ad, *args, **kwargs):
1934                success = False
1935                break
1936        if success:
1937            return True
1938
1939        time.sleep(WAIT_TIME_BETWEEN_STATE_CHECK)
1940        max_time -= WAIT_TIME_BETWEEN_STATE_CHECK
1941
1942    return False
1943
1944
1945def _is_attached(log, ad, voice_or_data):
1946    return _is_attached_for_subscription(
1947        log, ad, ad.droid.subscriptionGetDefaultSubId(), voice_or_data)
1948
1949
1950def _is_attached_for_subscription(log, ad, sub_id, voice_or_data):
1951    rat = get_network_rat_for_subscription(log, ad, sub_id, voice_or_data)
1952    ad.log.info("Sub_id %s network RAT is %s for %s", sub_id, rat,
1953                voice_or_data)
1954    return rat != RAT_UNKNOWN
1955
1956
1957def is_voice_attached(log, ad):
1958    return _is_attached_for_subscription(
1959        log, ad, ad.droid.subscriptionGetDefaultSubId(), NETWORK_SERVICE_VOICE)
1960
1961
1962def wait_for_data_attach(log, ad, max_time):
1963    """Wait for android device to attach on data.
1964
1965    Args:
1966        log: log object.
1967        ad:  android device.
1968        max_time: maximal wait time.
1969
1970    Returns:
1971        Return True if device attach data within max_time.
1972        Return False if timeout.
1973    """
1974    return _wait_for_droid_in_state(log, ad, max_time, _is_attached,
1975                                    NETWORK_SERVICE_DATA)
1976
1977
1978def wait_for_data_attach_for_subscription(log, ad, sub_id, max_time):
1979    """Wait for android device to attach on data in subscription id.
1980
1981    Args:
1982        log: log object.
1983        ad:  android device.
1984        sub_id: subscription id.
1985        max_time: maximal wait time.
1986
1987    Returns:
1988        Return True if device attach data within max_time.
1989        Return False if timeout.
1990    """
1991    return _wait_for_droid_in_state_for_subscription(
1992        log, ad, sub_id, max_time, _is_attached_for_subscription,
1993        NETWORK_SERVICE_DATA)
1994
1995
1996def get_phone_number(log, ad):
1997    """Get phone number for default subscription
1998
1999    Args:
2000        log: log object.
2001        ad: Android device object.
2002
2003    Returns:
2004        Phone number.
2005    """
2006    return get_phone_number_for_subscription(log, ad,
2007                                             get_outgoing_voice_sub_id(ad))
2008
2009
2010def get_phone_number_for_subscription(log, ad, subid):
2011    """Get phone number for subscription
2012
2013    Args:
2014        log: log object.
2015        ad: Android device object.
2016        subid: subscription id.
2017
2018    Returns:
2019        Phone number.
2020    """
2021    number = None
2022    try:
2023        number = ad.telephony['subscription'][subid]['phone_num']
2024    except KeyError:
2025        number = ad.droid.telephonyGetLine1NumberForSubscription(subid)
2026    return number
2027
2028
2029def set_phone_number(log, ad, phone_num):
2030    """Set phone number for default subscription
2031
2032    Args:
2033        log: log object.
2034        ad: Android device object.
2035        phone_num: phone number string.
2036
2037    Returns:
2038        True if success.
2039    """
2040    return set_phone_number_for_subscription(log, ad,
2041                                             get_outgoing_voice_sub_id(ad),
2042                                             phone_num)
2043
2044
2045def set_phone_number_for_subscription(log, ad, subid, phone_num):
2046    """Set phone number for subscription
2047
2048    Args:
2049        log: log object.
2050        ad: Android device object.
2051        subid: subscription id.
2052        phone_num: phone number string.
2053
2054    Returns:
2055        True if success.
2056    """
2057    try:
2058        ad.telephony['subscription'][subid]['phone_num'] = phone_num
2059    except Exception:
2060        return False
2061    return True
2062
2063
2064def get_operator_name(log, ad, subId=None):
2065    """Get operator name (e.g. vzw, tmo) of droid.
2066
2067    Args:
2068        ad: Android device object.
2069        sub_id: subscription ID
2070            Optional, default is None
2071
2072    Returns:
2073        Operator name.
2074    """
2075    try:
2076        if subId is not None:
2077            result = operator_name_from_plmn_id(
2078                ad.droid.telephonyGetNetworkOperatorForSubscription(subId))
2079        else:
2080            result = operator_name_from_plmn_id(
2081                ad.droid.telephonyGetNetworkOperator())
2082    except KeyError:
2083        try:
2084            if subId is not None:
2085                result = ad.droid.telephonyGetNetworkOperatorNameForSubscription(
2086                    subId)
2087            else:
2088                result = ad.droid.telephonyGetNetworkOperatorName()
2089            result = operator_name_from_network_name(result)
2090        except Exception:
2091            result = CARRIER_UNKNOWN
2092    ad.log.info("Operator Name is %s", result)
2093    return result
2094
2095
2096def get_model_name(ad):
2097    """Get android device model name
2098
2099    Args:
2100        ad: Android device object
2101
2102    Returns:
2103        model name string
2104    """
2105    # TODO: Create translate table.
2106    model = ad.model
2107    if (model.startswith(AOSP_PREFIX)):
2108        model = model[len(AOSP_PREFIX):]
2109    return model
2110
2111
2112def is_droid_in_rat_family(log, ad, rat_family, voice_or_data=None):
2113    return is_droid_in_rat_family_for_subscription(
2114        log, ad, ad.droid.subscriptionGetDefaultSubId(), rat_family,
2115        voice_or_data)
2116
2117
2118def is_droid_in_rat_family_for_subscription(log,
2119                                            ad,
2120                                            sub_id,
2121                                            rat_family,
2122                                            voice_or_data=None):
2123    return is_droid_in_rat_family_list_for_subscription(
2124        log, ad, sub_id, [rat_family], voice_or_data)
2125
2126
2127def is_droid_in_rat_familiy_list(log, ad, rat_family_list, voice_or_data=None):
2128    return is_droid_in_rat_family_list_for_subscription(
2129        log, ad, ad.droid.subscriptionGetDefaultSubId(), rat_family_list,
2130        voice_or_data)
2131
2132
2133def is_droid_in_rat_family_list_for_subscription(log,
2134                                                 ad,
2135                                                 sub_id,
2136                                                 rat_family_list,
2137                                                 voice_or_data=None):
2138    service_list = [NETWORK_SERVICE_DATA, NETWORK_SERVICE_VOICE]
2139    if voice_or_data:
2140        service_list = [voice_or_data]
2141
2142    for service in service_list:
2143        nw_rat = get_network_rat_for_subscription(log, ad, sub_id, service)
2144        if nw_rat == RAT_UNKNOWN or not is_valid_rat(nw_rat):
2145            continue
2146        if rat_family_from_rat(nw_rat) in rat_family_list:
2147            return True
2148    return False
2149
2150
2151def is_droid_in_network_generation(log, ad, nw_gen, voice_or_data):
2152    """Checks if a droid in expected network generation ("2g", "3g" or "4g").
2153
2154    Args:
2155        log: log object.
2156        ad: android device.
2157        nw_gen: expected generation "4g", "3g", "2g".
2158        voice_or_data: check voice network generation or data network generation
2159            This parameter is optional. If voice_or_data is None, then if
2160            either voice or data in expected generation, function will return True.
2161
2162    Returns:
2163        True if droid in expected network generation. Otherwise False.
2164    """
2165    return is_droid_in_network_generation_for_subscription(
2166        log, ad, ad.droid.subscriptionGetDefaultSubId(), nw_gen, voice_or_data)
2167
2168
2169def is_droid_in_network_generation_for_subscription(log, ad, sub_id, nw_gen,
2170                                                    voice_or_data):
2171    """Checks if a droid in expected network generation ("2g", "3g" or "4g").
2172
2173    Args:
2174        log: log object.
2175        ad: android device.
2176        nw_gen: expected generation "4g", "3g", "2g".
2177        voice_or_data: check voice network generation or data network generation
2178            This parameter is optional. If voice_or_data is None, then if
2179            either voice or data in expected generation, function will return True.
2180
2181    Returns:
2182        True if droid in expected network generation. Otherwise False.
2183    """
2184    service_list = [NETWORK_SERVICE_DATA, NETWORK_SERVICE_VOICE]
2185
2186    if voice_or_data:
2187        service_list = [voice_or_data]
2188
2189    for service in service_list:
2190        nw_rat = get_network_rat_for_subscription(log, ad, sub_id, service)
2191        ad.log.info("%s network rat is %s", service, nw_rat)
2192        if nw_rat == RAT_UNKNOWN or not is_valid_rat(nw_rat):
2193            continue
2194
2195        if rat_generation_from_rat(nw_rat) == nw_gen:
2196            ad.log.info("%s network rat %s is expected %s", service, nw_rat,
2197                        nw_gen)
2198            return True
2199        else:
2200            ad.log.info("%s network rat %s is %s, does not meet expected %s",
2201                        service, nw_rat, rat_generation_from_rat(nw_rat),
2202                        nw_gen)
2203            return False
2204
2205    return False
2206
2207
2208def get_network_rat(log, ad, voice_or_data):
2209    """Get current network type (Voice network type, or data network type)
2210       for default subscription id
2211
2212    Args:
2213        ad: Android Device Object
2214        voice_or_data: Input parameter indicating to get voice network type or
2215            data network type.
2216
2217    Returns:
2218        Current voice/data network type.
2219    """
2220    return get_network_rat_for_subscription(
2221        log, ad, ad.droid.subscriptionGetDefaultSubId(), voice_or_data)
2222
2223
2224def get_network_rat_for_subscription(log, ad, sub_id, voice_or_data):
2225    """Get current network type (Voice network type, or data network type)
2226       for specified subscription id
2227
2228    Args:
2229        ad: Android Device Object
2230        sub_id: subscription ID
2231        voice_or_data: Input parameter indicating to get voice network type or
2232            data network type.
2233
2234    Returns:
2235        Current voice/data network type.
2236    """
2237    if voice_or_data == NETWORK_SERVICE_VOICE:
2238        ret_val = ad.droid.telephonyGetCurrentVoiceNetworkTypeForSubscription(
2239            sub_id)
2240    elif voice_or_data == NETWORK_SERVICE_DATA:
2241        ret_val = ad.droid.telephonyGetCurrentDataNetworkTypeForSubscription(
2242            sub_id)
2243    else:
2244        ret_val = ad.droid.telephonyGetNetworkTypeForSubscription(sub_id)
2245
2246    if ret_val is None:
2247        log.error("get_network_rat(): Unexpected null return value")
2248        return RAT_UNKNOWN
2249    else:
2250        return ret_val
2251
2252
2253def get_network_gen(log, ad, voice_or_data):
2254    """Get current network generation string (Voice network type, or data network type)
2255
2256    Args:
2257        ad: Android Device Object
2258        voice_or_data: Input parameter indicating to get voice network generation
2259            or data network generation.
2260
2261    Returns:
2262        Current voice/data network generation.
2263    """
2264    return get_network_gen_for_subscription(
2265        log, ad, ad.droid.subscriptionGetDefaultSubId(), voice_or_data)
2266
2267
2268def get_network_gen_for_subscription(log, ad, sub_id, voice_or_data):
2269    """Get current network generation string (Voice network type, or data network type)
2270
2271    Args:
2272        ad: Android Device Object
2273        voice_or_data: Input parameter indicating to get voice network generation
2274            or data network generation.
2275
2276    Returns:
2277        Current voice/data network generation.
2278    """
2279    try:
2280        return rat_generation_from_rat(
2281            get_network_rat_for_subscription(log, ad, sub_id, voice_or_data))
2282    except KeyError as e:
2283        ad.log.error("KeyError %s", e)
2284        return GEN_UNKNOWN
2285
2286
2287def check_voice_mail_count(log, ad, voice_mail_count_before,
2288                           voice_mail_count_after):
2289    """function to check if voice mail count is correct after leaving a new voice message.
2290    """
2291    return get_voice_mail_count_check_function(get_operator_name(log, ad))(
2292        voice_mail_count_before, voice_mail_count_after)
2293
2294
2295def get_voice_mail_number(log, ad):
2296    """function to get the voice mail number
2297    """
2298    voice_mail_number = get_voice_mail_check_number(get_operator_name(log, ad))
2299    if voice_mail_number is None:
2300        return get_phone_number(log, ad)
2301    return voice_mail_number
2302
2303
2304def reset_preferred_network_type_to_allowable_range(log, ad):
2305    """If preferred network type is not in allowable range, reset to GEN_4G
2306    preferred network type.
2307
2308    Args:
2309        log: log object
2310        ad: android device object
2311
2312    Returns:
2313        None
2314    """
2315    for sub_id, sub_info in ad.telephony["subscription"].items():
2316        current_preference = \
2317            ad.droid.telephonyGetPreferredNetworkTypesForSubscription(sub_id)
2318        ad.log.debug("sub_id network preference is %s", current_preference)
2319        try:
2320            if current_preference not in get_allowable_network_preference(
2321                    sub_info["operator"], sub_info["phone_type"]):
2322                network_preference = network_preference_for_generation(
2323                    GEN_4G, sub_info["operator"], sub_info["phone_type"])
2324                ad.droid.telephonySetPreferredNetworkTypesForSubscription(
2325                    network_preference, sub_id)
2326        except KeyError:
2327            pass
2328
2329
2330def set_phone_screen_on(log, ad, screen_on_time=MAX_SCREEN_ON_TIME):
2331    """Set phone screen on time.
2332
2333    Args:
2334        log: Log object.
2335        ad: Android device object.
2336        screen_on_time: screen on time.
2337            This is optional, default value is MAX_SCREEN_ON_TIME.
2338    Returns:
2339        True if set successfully.
2340    """
2341    ad.droid.setScreenTimeout(screen_on_time)
2342    return screen_on_time == ad.droid.getScreenTimeout()
2343
2344
2345def set_phone_silent_mode(log, ad, silent_mode=True):
2346    """Set phone silent mode.
2347
2348    Args:
2349        log: Log object.
2350        ad: Android device object.
2351        silent_mode: set phone silent or not.
2352            This is optional, default value is True (silent mode on).
2353    Returns:
2354        True if set successfully.
2355    """
2356    ad.droid.toggleRingerSilentMode(silent_mode)
2357    ad.droid.setMediaVolume(0)
2358    ad.droid.setVoiceCallVolume(0)
2359    ad.droid.setAlarmVolume(0)
2360    ad.adb.ensure_root()
2361    ad.adb.shell("setprop ro.audio.silent 1", ignore_status=True)
2362    ad.adb.shell("cmd notification set_dnd on", ignore_status=True)
2363    return silent_mode == ad.droid.checkRingerSilentMode()
2364
2365
2366def set_preferred_network_mode_pref(log,
2367                                    ad,
2368                                    sub_id,
2369                                    network_preference,
2370                                    timeout=WAIT_TIME_ANDROID_STATE_SETTLING):
2371    """Set Preferred Network Mode for Sub_id
2372    Args:
2373        log: Log object.
2374        ad: Android device object.
2375        sub_id: Subscription ID.
2376        network_preference: Network Mode Type
2377    """
2378    begin_time = get_device_epoch_time(ad)
2379    if ad.droid.telephonyGetPreferredNetworkTypesForSubscription(
2380            sub_id) == network_preference:
2381        ad.log.info("Current ModePref for Sub %s is in %s", sub_id,
2382                    network_preference)
2383        return True
2384    ad.log.info("Setting ModePref to %s for Sub %s", network_preference,
2385                sub_id)
2386    while timeout >= 0:
2387        if ad.droid.telephonySetPreferredNetworkTypesForSubscription(
2388                network_preference, sub_id):
2389            return True
2390        time.sleep(WAIT_TIME_BETWEEN_STATE_CHECK)
2391        timeout = timeout - WAIT_TIME_BETWEEN_STATE_CHECK
2392    error_msg = "Failed to set sub_id %s PreferredNetworkType to %s" % (
2393        sub_id, network_preference)
2394    search_results = ad.search_logcat(
2395        "REQUEST_SET_PREFERRED_NETWORK_TYPE error", begin_time=begin_time)
2396    if search_results:
2397        log_message = search_results[-1]["log_message"]
2398        if "DEVICE_IN_USE" in log_message:
2399            error_msg = "%s due to DEVICE_IN_USE" % error_msg
2400        else:
2401            error_msg = "%s due to %s" % (error_msg, log_message)
2402    ad.log.error(error_msg)
2403    return False
2404
2405
2406def set_call_state_listen_level(log, ad, value, sub_id):
2407    """Set call state listen level for subscription id.
2408
2409    Args:
2410        log: Log object.
2411        ad: Android device object.
2412        value: True or False
2413        sub_id :Subscription ID.
2414
2415    Returns:
2416        True or False
2417    """
2418    if sub_id == INVALID_SUB_ID:
2419        log.error("Invalid Subscription ID")
2420        return False
2421    ad.droid.telephonyAdjustPreciseCallStateListenLevelForSubscription(
2422        "Foreground", value, sub_id)
2423    ad.droid.telephonyAdjustPreciseCallStateListenLevelForSubscription(
2424        "Ringing", value, sub_id)
2425    ad.droid.telephonyAdjustPreciseCallStateListenLevelForSubscription(
2426        "Background", value, sub_id)
2427    return True
2428
2429
2430def is_event_match(event, field, value):
2431    """Return if <field> in "event" match <value> or not.
2432
2433    Args:
2434        event: event to test. This event need to have <field>.
2435        field: field to match.
2436        value: value to match.
2437
2438    Returns:
2439        True if <field> in "event" match <value>.
2440        False otherwise.
2441    """
2442    return is_event_match_for_list(event, field, [value])
2443
2444
2445def is_event_match_for_list(event, field, value_list):
2446    """Return if <field> in "event" match any one of the value
2447        in "value_list" or not.
2448
2449    Args:
2450        event: event to test. This event need to have <field>.
2451        field: field to match.
2452        value_list: a list of value to match.
2453
2454    Returns:
2455        True if <field> in "event" match one of the value in "value_list".
2456        False otherwise.
2457    """
2458    try:
2459        value_in_event = event['data'][field]
2460    except KeyError:
2461        return False
2462    for value in value_list:
2463        if value_in_event == value:
2464            return True
2465    return False
2466
2467
2468def is_network_call_back_event_match(event, network_callback_id,
2469                                     network_callback_event):
2470    try:
2471        return (
2472            (network_callback_id == event['data'][NetworkCallbackContainer.ID])
2473            and (network_callback_event == event['data']
2474                 [NetworkCallbackContainer.NETWORK_CALLBACK_EVENT]))
2475    except KeyError:
2476        return False
2477
2478
2479def is_build_id(log, ad, build_id):
2480    """Return if ad's build id is the same as input parameter build_id.
2481
2482    Args:
2483        log: log object.
2484        ad: android device object.
2485        build_id: android build id.
2486
2487    Returns:
2488        True if ad's build id is the same as input parameter build_id.
2489        False otherwise.
2490    """
2491    actual_bid = ad.droid.getBuildID()
2492
2493    ad.log.info("BUILD DISPLAY: %s", ad.droid.getBuildDisplay())
2494    #In case we want to log more stuff/more granularity...
2495    #log.info("{} BUILD ID:{} ".format(ad.serial, ad.droid.getBuildID()))
2496    #log.info("{} BUILD FINGERPRINT: {} "
2497    # .format(ad.serial), ad.droid.getBuildFingerprint())
2498    #log.info("{} BUILD TYPE: {} "
2499    # .format(ad.serial), ad.droid.getBuildType())
2500    #log.info("{} BUILD NUMBER: {} "
2501    # .format(ad.serial), ad.droid.getBuildNumber())
2502    if actual_bid.upper() != build_id.upper():
2503        ad.log.error("%s: Incorrect Build ID", ad.model)
2504        return False
2505    return True
2506
2507
2508def is_uri_equivalent(uri1, uri2):
2509    """Check whether two input uris match or not.
2510
2511    Compare Uris.
2512        If Uris are tel URI, it will only take the digit part
2513        and compare as phone number.
2514        Else, it will just do string compare.
2515
2516    Args:
2517        uri1: 1st uri to be compared.
2518        uri2: 2nd uri to be compared.
2519
2520    Returns:
2521        True if two uris match. Otherwise False.
2522    """
2523
2524    #If either is None/empty we return false
2525    if not uri1 or not uri2:
2526        return False
2527
2528    try:
2529        if uri1.startswith('tel:') and uri2.startswith('tel:'):
2530            uri1_number = get_number_from_tel_uri(uri1)
2531            uri2_number = get_number_from_tel_uri(uri2)
2532            return check_phone_number_match(uri1_number, uri2_number)
2533        else:
2534            return uri1 == uri2
2535    except AttributeError as e:
2536        return False
2537
2538
2539def get_call_uri(ad, call_id):
2540    """Get call's uri field.
2541
2542    Get Uri for call_id in ad.
2543
2544    Args:
2545        ad: android device object.
2546        call_id: the call id to get Uri from.
2547
2548    Returns:
2549        call's Uri if call is active and have uri field. None otherwise.
2550    """
2551    try:
2552        call_detail = ad.droid.telecomCallGetDetails(call_id)
2553        return call_detail["Handle"]["Uri"]
2554    except:
2555        return None
2556
2557
2558def get_number_from_tel_uri(uri):
2559    """Get Uri number from tel uri
2560
2561    Args:
2562        uri: input uri
2563
2564    Returns:
2565        If input uri is tel uri, return the number part.
2566        else return None.
2567    """
2568    if uri.startswith('tel:'):
2569        uri_number = ''.join(
2570            i for i in urllib.parse.unquote(uri) if i.isdigit())
2571        return uri_number
2572    else:
2573        return None
2574
2575
2576def install_carriersettings_apk(ad, carriersettingsapk, skip_setup_wizard=True):
2577    """ Carrier Setting Installation Steps
2578
2579    Pull sl4a apk from device. Terminate all sl4a sessions,
2580    Reboot the device to bootloader, wipe the device by fastboot.
2581    Reboot the device. wait for device to complete booting
2582    """
2583    status = True
2584    if carriersettingsapk is None:
2585        ad.log.warning("CarrierSettingsApk is not provided, aborting")
2586        return False
2587    ad.log.info("Push carriersettings apk to the Android device.")
2588    android_apk_path = "/product/priv-app/CarrierSettings/CarrierSettings.apk"
2589    ad.adb.push("%s %s" % (carriersettingsapk, android_apk_path))
2590    ad.stop_services()
2591
2592    attempts = 3
2593    for i in range(1, attempts + 1):
2594        try:
2595            if ad.serial in list_adb_devices():
2596                ad.log.info("Reboot to bootloader")
2597                ad.adb.reboot("bootloader", ignore_status=True)
2598                time.sleep(30)
2599            if ad.serial in list_fastboot_devices():
2600                ad.log.info("Reboot in fastboot")
2601                ad.fastboot.reboot()
2602            ad.wait_for_boot_completion()
2603            ad.root_adb()
2604            if ad.is_sl4a_installed():
2605                break
2606            time.sleep(10)
2607            break
2608        except Exception as e:
2609            ad.log.warning(e)
2610            if i == attempts:
2611                abort_all_tests(log, str(e))
2612            time.sleep(5)
2613    try:
2614        ad.start_adb_logcat()
2615    except:
2616        ad.log.error("Failed to start adb logcat!")
2617    if skip_setup_wizard:
2618        ad.exit_setup_wizard()
2619    return status
2620
2621
2622def bring_up_sl4a(ad, attemps=3):
2623    for i in range(attemps):
2624        try:
2625            droid, ed = ad.get_droid()
2626            ed.start()
2627            ad.log.info("Brought up new sl4a session")
2628            break
2629        except Exception as e:
2630            if i < attemps - 1:
2631                ad.log.info(e)
2632                time.sleep(10)
2633            else:
2634                ad.log.error(e)
2635                raise
2636
2637
2638def reboot_device(ad, recover_sim_state=True):
2639    sim_state = is_sim_ready(ad.log, ad)
2640    ad.reboot()
2641    if ad.qxdm_log:
2642        start_qxdm_logger(ad)
2643    ad.unlock_screen()
2644    if recover_sim_state:
2645        if not unlock_sim(ad):
2646            ad.log.error("Unable to unlock SIM")
2647            return False
2648        if sim_state and not _wait_for_droid_in_state(
2649                log, ad, MAX_WAIT_TIME_FOR_STATE_CHANGE, is_sim_ready):
2650            ad.log.error("Sim state didn't reach pre-reboot ready state")
2651            return False
2652    return True
2653
2654
2655def unlocking_device(ad, device_password=None):
2656    """First unlock device attempt, required after reboot"""
2657    ad.unlock_screen(device_password)
2658    time.sleep(2)
2659    ad.adb.wait_for_device(timeout=180)
2660    if not ad.is_waiting_for_unlock_pin():
2661        return True
2662    else:
2663        ad.unlock_screen(device_password)
2664        time.sleep(2)
2665        ad.adb.wait_for_device(timeout=180)
2666        if ad.wait_for_window_ready():
2667            return True
2668    ad.log.error("Unable to unlock to user window")
2669    return False
2670
2671
2672def refresh_sl4a_session(ad):
2673    try:
2674        ad.droid.logI("Checking SL4A connection")
2675        ad.log.debug("Existing sl4a session is active")
2676        return True
2677    except Exception as e:
2678        ad.log.warning("Existing sl4a session is NOT active: %s", e)
2679    try:
2680        ad.terminate_all_sessions()
2681    except Exception as e:
2682        ad.log.info("terminate_all_sessions with error %s", e)
2683    ad.ensure_screen_on()
2684    ad.log.info("Open new sl4a connection")
2685    bring_up_sl4a(ad)
2686
2687
2688def get_sim_state(ad):
2689    try:
2690        state = ad.droid.telephonyGetSimState()
2691    except Exception as e:
2692        ad.log.error(e)
2693        state = ad.adb.getprop("gsm.sim.state")
2694    return state
2695
2696
2697def is_sim_locked(ad):
2698    return get_sim_state(ad) == SIM_STATE_PIN_REQUIRED
2699
2700
2701def is_sim_lock_enabled(ad):
2702    # TODO: add sl4a fascade to check if sim is locked
2703    return getattr(ad, "is_sim_locked", False)
2704
2705
2706def unlock_sim(ad):
2707    #The puk and pin can be provided in testbed config file.
2708    #"AndroidDevice": [{"serial": "84B5T15A29018214",
2709    #                   "adb_logcat_param": "-b all",
2710    #                   "puk": "12345678",
2711    #                   "puk_pin": "1234"}]
2712    if not is_sim_locked(ad):
2713        return True
2714    else:
2715        ad.is_sim_locked = True
2716    puk_pin = getattr(ad, "puk_pin", "1111")
2717    try:
2718        if not hasattr(ad, 'puk'):
2719            ad.log.info("Enter SIM pin code")
2720            ad.droid.telephonySupplyPin(puk_pin)
2721        else:
2722            ad.log.info("Enter PUK code and pin")
2723            ad.droid.telephonySupplyPuk(ad.puk, puk_pin)
2724    except:
2725        # if sl4a is not available, use adb command
2726        ad.unlock_screen(puk_pin)
2727        if is_sim_locked(ad):
2728            ad.unlock_screen(puk_pin)
2729    time.sleep(30)
2730    return not is_sim_locked(ad)
2731
2732
2733def send_dialer_secret_code(ad, secret_code):
2734    """Send dialer secret code.
2735
2736    ad: android device controller
2737    secret_code: the secret code to be sent to dialer. the string between
2738                 code prefix *#*# and code postfix #*#*. *#*#<xxx>#*#*
2739    """
2740    action = 'android.provider.Telephony.SECRET_CODE'
2741    uri = 'android_secret_code://%s' % secret_code
2742    intent = ad.droid.makeIntent(
2743        action,
2744        uri,
2745        None,  # type
2746        None,  # extras
2747        None,  # categories,
2748        None,  # packagename,
2749        None,  # classname,
2750        0x01000000)  # flags
2751    ad.log.info('Issuing dialer secret dialer code: %s', secret_code)
2752    ad.droid.sendBroadcastIntent(intent)
2753
2754
2755def enable_radio_log_on(ad):
2756    if ad.adb.getprop("persist.vendor.radio.adb_log_on") != "1":
2757        ad.log.info("Enable radio adb_log_on and reboot")
2758        adb_disable_verity(ad)
2759        ad.adb.shell("setprop persist.vendor.radio.adb_log_on 1")
2760        reboot_device(ad)
2761
2762
2763def adb_disable_verity(ad):
2764    if ad.adb.getprop("ro.boot.veritymode") == "enforcing":
2765        ad.adb.disable_verity()
2766        reboot_device(ad)
2767        ad.adb.remount()
2768
2769
2770def recover_build_id(ad):
2771    build_fingerprint = ad.adb.getprop(
2772        "ro.vendor.build.fingerprint") or ad.adb.getprop(
2773            "ro.build.fingerprint")
2774    if not build_fingerprint:
2775        return
2776    build_id = build_fingerprint.split("/")[3]
2777    if ad.adb.getprop("ro.build.id") != build_id:
2778        build_id_override(ad, build_id)
2779
2780
2781def check_and_enable_privacy_usage_diagnostics(ad):
2782    try:
2783        ad.ensure_screen_on()
2784        ad.send_keycode('HOME')
2785    # open the UI page on which we need to enable the setting
2786        cmd = ('am start -n com.google.android.gms/com.google.android.gms.'
2787               'usagereporting.settings.UsageReportingActivity')
2788        ad.adb.shell(cmd)
2789    # perform the toggle using UI
2790        resource = {
2791        'resource_id': 'android:id/switch_widget',
2792        }
2793        node = ui_utils.wait_and_get_xml_node(ad,
2794                                        timeout=30,
2795                                        sibling=resource,
2796                                        text="Usage & diagnostics",
2797                                        resource_id="com.google.android.gms:id/switch_text")
2798        current_state = node.attributes['checked'].value
2799
2800        if current_state == "false":
2801            ad.log.info("Enabling Usage & diagnostics")
2802            ui_utils.wait_and_click(ad,
2803                                    text="Usage & diagnostics",
2804                                    resource_id="com.google.android.gms:id/switch_text")
2805        else:
2806            ad.log.info("Usage & diagnostics is already enabled")
2807
2808    except Exception:
2809        ad.log.info("Unable to toggle Usage and Diagnostics")
2810
2811
2812def build_id_override(ad, new_build_id=None, postfix=None):
2813    build_fingerprint = ad.adb.getprop(
2814        "ro.build.fingerprint") or ad.adb.getprop(
2815            "ro.vendor.build.fingerprint")
2816    if build_fingerprint:
2817        build_id = build_fingerprint.split("/")[3]
2818    else:
2819        build_id = None
2820    existing_build_id = ad.adb.getprop("ro.build.id")
2821    if postfix is not None and postfix in build_id:
2822        ad.log.info("Build id already contains %s", postfix)
2823        if postfix == 'STATIONARY_TEST':
2824            check_and_enable_privacy_usage_diagnostics(ad)
2825        return
2826    if not new_build_id:
2827        if postfix and build_id:
2828            new_build_id = "%s.%s" % (build_id, postfix)
2829    if not new_build_id or existing_build_id == new_build_id:
2830        return
2831    ad.log.info("Override build id %s with %s", existing_build_id,
2832                new_build_id)
2833    check_and_enable_privacy_usage_diagnostics(ad)
2834    adb_disable_verity(ad)
2835    ad.adb.remount()
2836    if "backup.prop" not in ad.adb.shell("ls /sdcard/"):
2837        ad.adb.shell("cp /system/build.prop /sdcard/backup.prop")
2838    ad.adb.shell("cat /system/build.prop | grep -v ro.build.id > /sdcard/test.prop")
2839    ad.adb.shell("echo ro.build.id=%s >> /sdcard/test.prop" % new_build_id)
2840    ad.adb.shell("cp /sdcard/test.prop /system/build.prop")
2841    reboot_device(ad)
2842    ad.log.info("ro.build.id = %s", ad.adb.getprop("ro.build.id"))
2843
2844
2845def enable_connectivity_metrics(ad):
2846    cmds = [
2847        "pm enable com.android.connectivity.metrics",
2848        "am startservice -a com.google.android.gms.usagereporting.OPTIN_UR",
2849        "am broadcast -a com.google.gservices.intent.action.GSERVICES_OVERRIDE"
2850        " -e usagestats:connectivity_metrics:enable_data_collection 1",
2851        "am broadcast -a com.google.gservices.intent.action.GSERVICES_OVERRIDE"
2852        " -e usagestats:connectivity_metrics:telephony_snapshot_period_millis 180000"
2853        # By default it turn on all modules
2854        #"am broadcast -a com.google.gservices.intent.action.GSERVICES_OVERRIDE"
2855        #" -e usagestats:connectivity_metrics:data_collection_bitmap 62"
2856    ]
2857    for cmd in cmds:
2858        ad.adb.shell(cmd, ignore_status=True)
2859
2860
2861def force_connectivity_metrics_upload(ad):
2862    cmd = "cmd jobscheduler run --force com.android.connectivity.metrics %s"
2863    for job_id in [2, 3, 5, 4, 1, 6]:
2864        ad.adb.shell(cmd % job_id, ignore_status=True)
2865
2866
2867def system_file_push(ad, src_file_path, dst_file_path):
2868    """Push system file on a device.
2869
2870    Push system file need to change some system setting and remount.
2871    """
2872    cmd = "%s %s" % (src_file_path, dst_file_path)
2873    out = ad.adb.push(cmd, timeout=300, ignore_status=True)
2874    skip_sl4a = True if "sl4a.apk" in src_file_path else False
2875    if "Read-only file system" in out:
2876        ad.log.info("Change read-only file system")
2877        adb_disable_verity(ad)
2878        out = ad.adb.push(cmd, timeout=300, ignore_status=True)
2879        if "Read-only file system" in out:
2880            ad.reboot(skip_sl4a)
2881            out = ad.adb.push(cmd, timeout=300, ignore_status=True)
2882            if "error" in out:
2883                ad.log.error("%s failed with %s", cmd, out)
2884                return False
2885            else:
2886                ad.log.info("push %s succeed")
2887                if skip_sl4a: ad.reboot(skip_sl4a)
2888                return True
2889        else:
2890            return True
2891    elif "error" in out:
2892        return False
2893    else:
2894        return True
2895
2896
2897def set_preferred_apn_by_adb(ad, pref_apn_name):
2898    """Select Pref APN
2899       Set Preferred APN on UI using content query/insert
2900       It needs apn name as arg, and it will match with plmn id
2901    """
2902    try:
2903        plmn_id = get_plmn_by_adb(ad)
2904        out = ad.adb.shell("content query --uri content://telephony/carriers "
2905                           "--where \"apn='%s' and numeric='%s'\"" %
2906                           (pref_apn_name, plmn_id))
2907        if "No result found" in out:
2908            ad.log.warning("Cannot find APN %s on device", pref_apn_name)
2909            return False
2910        else:
2911            apn_id = re.search(r'_id=(\d+)', out).group(1)
2912            ad.log.info("APN ID is %s", apn_id)
2913            ad.adb.shell("content insert --uri content:"
2914                         "//telephony/carriers/preferapn --bind apn_id:i:%s" %
2915                         (apn_id))
2916            out = ad.adb.shell("content query --uri "
2917                               "content://telephony/carriers/preferapn")
2918            if "No result found" in out:
2919                ad.log.error("Failed to set prefer APN %s", pref_apn_name)
2920                return False
2921            elif apn_id == re.search(r'_id=(\d+)', out).group(1):
2922                ad.log.info("Preferred APN set to %s", pref_apn_name)
2923                return True
2924    except Exception as e:
2925        ad.log.error("Exception while setting pref apn %s", e)
2926        return True
2927
2928
2929def check_apm_mode_on_by_serial(ad, serial_id):
2930    try:
2931        apm_check_cmd = "|".join(("adb -s %s shell dumpsys wifi" % serial_id,
2932                                  "grep -i airplanemodeon", "cut -f2 -d ' '"))
2933        output = exe_cmd(apm_check_cmd)
2934        if output.decode("utf-8").split("\n")[0] == "true":
2935            return True
2936        else:
2937            return False
2938    except Exception as e:
2939        ad.log.warning("Exception during check apm mode on %s", e)
2940        return True
2941
2942
2943def set_apm_mode_on_by_serial(ad, serial_id):
2944    try:
2945        cmd1 = "adb -s %s shell settings put global airplane_mode_on 1" % serial_id
2946        cmd2 = "adb -s %s shell am broadcast -a android.intent.action.AIRPLANE_MODE" % serial_id
2947        exe_cmd(cmd1)
2948        exe_cmd(cmd2)
2949    except Exception as e:
2950        ad.log.warning("Exception during set apm mode on %s", e)
2951        return True
2952
2953
2954def print_radio_info(ad, extra_msg=""):
2955    for prop in ("gsm.version.baseband", "persist.radio.ver_info",
2956                 "persist.radio.cnv.ver_info"):
2957        output = ad.adb.getprop(prop)
2958        ad.log.info("%s%s = %s", extra_msg, prop, output)
2959
2960
2961def wait_for_state(state_check_func,
2962                   state,
2963                   max_wait_time=MAX_WAIT_TIME_FOR_STATE_CHANGE,
2964                   checking_interval=WAIT_TIME_BETWEEN_STATE_CHECK,
2965                   *args,
2966                   **kwargs):
2967    while max_wait_time >= 0:
2968        if state_check_func(*args, **kwargs) == state:
2969            return True
2970        time.sleep(checking_interval)
2971        max_wait_time -= checking_interval
2972    return False
2973
2974
2975def power_off_sim_by_adb(ad, sim_slot_id,
2976                         timeout=MAX_WAIT_TIME_FOR_STATE_CHANGE):
2977    """Disable pSIM/eSIM SUB by adb command.
2978
2979    Args:
2980        ad: android device object.
2981        sim_slot_id: slot 0 or slot 1.
2982        timeout: wait time for state change.
2983
2984    Returns:
2985        True if success, False otherwise.
2986    """
2987    release_version =  int(ad.adb.getprop("ro.build.version.release"))
2988    if sim_slot_id == 0 and release_version < 12:
2989        ad.log.error(
2990            "The disable pSIM SUB command only support for Android S or higher "
2991            "version, abort test.")
2992        raise signals.TestSkip(
2993            "The disable pSIM SUB command only support for Android S or higher "
2994            "version, abort test.")
2995    try:
2996        if sim_slot_id:
2997            ad.adb.shell("am broadcast -a android.telephony.euicc.action."
2998                "TEST_PROFILE -n com.google.android.euicc/com.android.euicc."
2999                "receiver.ProfileTestReceiver --es 'operation' 'switch' --ei "
3000                "'subscriptionId' -1")
3001        else:
3002            sub_id = get_subid_by_adb(ad, sim_slot_id)
3003            # The command only support for Android S. (b/159605922)
3004            ad.adb.shell(
3005                "cmd phone disable-physical-subscription %d" % sub_id)
3006    except Exception as e:
3007        ad.log.error(e)
3008        return False
3009    while timeout > 0:
3010        if get_subid_by_adb(ad, sim_slot_id) == INVALID_SUB_ID:
3011            return True
3012        timeout = timeout - WAIT_TIME_BETWEEN_STATE_CHECK
3013        time.sleep(WAIT_TIME_BETWEEN_STATE_CHECK)
3014    sim_state = ad.adb.getprop("gsm.sim.state").split(",")
3015    ad.log.warning("Fail to power off SIM slot %d, sim_state=%s",
3016        sim_slot_id, sim_state[sim_slot_id])
3017    return False
3018
3019
3020def change_slot(ad: AndroidDevice, sim_slot: Sequence[SimSlotInfo],
3021                timeout: int = MAX_WAIT_TIME_FOR_STATE_CHANGE) -> bool:
3022    """Enable Sims for Slot Mapping Mode.
3023
3024    Args:
3025        ad: android device object.
3026        sim_slot: a list which contains 2 slots for logical slot 0 and 1.
3027            e.g. [SimSlotInfo.SLOT_0, SimSlotInfo.SLOT_1]
3028        timeout: wait time for state change.
3029
3030    Returns:
3031        True if success, False otherwise.
3032    """
3033    if not getattr(ad, "mep", False): return
3034
3035    port_id = [sim_slot[0].value[1], sim_slot[1].value[1]]
3036    phy_slot_id = [sim_slot[0].value[2], sim_slot[1].value[2]]
3037    ad.adb.shell(
3038        "am broadcast -a android.telephony.euicc.action.TEST_PROFILE "
3039        "-n com.google.android.euicc/com.android.euicc.receiver."
3040        "ProfileTestReceiver --es 'operation' 'changeSlot' --es "
3041        "'simSlotMapping' \"[{'port':%d,'physical':%d,'logical':0},{'port':%d,"
3042        "'physical':%d,'logical':1}]\"" % (port_id[0], phy_slot_id[0],
3043        port_id[1], phy_slot_id[1]))
3044    time.sleep(WAIT_TIME_BETWEEN_STATE_CHECK)
3045
3046    while timeout > 0:
3047        sim_state = ad.adb.getprop("gsm.sim.state").split(",")
3048        if (get_subid_from_slot_index(
3049            ad.log, ad, sim_slot[0].value[0]) != INVALID_SUB_ID
3050            ) and (get_subid_from_slot_index(
3051                ad.log, ad, sim_slot[1].value[0]) != INVALID_SUB_ID):
3052            if (set(sim_state) - {
3053                SIM_STATE_UNKNOWN, SIM_STATE_ABSENT, SIM_STATE_NOT_READY}):
3054                get_phone_capability(ad)
3055                return True
3056        timeout = timeout - WAIT_TIME_BETWEEN_STATE_CHECK
3057        time.sleep(WAIT_TIME_BETWEEN_STATE_CHECK)
3058
3059    ad.log.warning("Fail to change SIM slot %s, sim_state=%s",
3060        sim_slot, sim_state)
3061    return False
3062
3063
3064def power_on_sim_by_adb(ad, sim_slot_id,
3065                         timeout=MAX_WAIT_TIME_FOR_STATE_CHANGE):
3066    """Enable pSIM/eSIM SUB by adb command.
3067
3068    Args:
3069        ad: android device object.
3070        sim_slot_id: slot 0 or slot 1.
3071        timeout: wait time for state change.
3072
3073    Returns:
3074        True if success, False otherwise.
3075    """
3076    release_version =  int(ad.adb.getprop("ro.build.version.release"))
3077    if sim_slot_id == 0 and release_version < 12:
3078        ad.log.error(
3079            "The enable pSIM SUB command only support for Android S or higher "
3080            "version, abort test.")
3081        raise signals.TestSkip(
3082            "The enable pSIM SUB command only support for Android S or higher "
3083            "version, abort test.")
3084    try:
3085        output = ad.adb.shell(
3086            "dumpsys isub | grep addSubInfoRecord | grep slotIndex=%d" %
3087            sim_slot_id)
3088        pattern = re.compile(r"subId=(\d+)")
3089        sub_id = pattern.findall(output)
3090        sub_id = int(sub_id[-1]) if sub_id else INVALID_SUB_ID
3091        if sim_slot_id:
3092            ad.adb.shell("am broadcast -a android.telephony.euicc.action."
3093                "TEST_PROFILE -n com.google.android.euicc/com.android.euicc."
3094                "receiver.ProfileTestReceiver --es 'operation' 'switch' --ei "
3095                "'subscriptionId' %d" % sub_id)
3096        else:
3097            # The command only support for Android S or higher. (b/159605922)
3098            ad.adb.shell(
3099                "cmd phone enable-physical-subscription %d" % sub_id)
3100    except Exception as e:
3101        ad.log.error(e)
3102        return False
3103    while timeout > 0:
3104        if get_subid_by_adb(ad, sim_slot_id) != INVALID_SUB_ID:
3105            return True
3106        timeout = timeout - WAIT_TIME_BETWEEN_STATE_CHECK
3107        time.sleep(WAIT_TIME_BETWEEN_STATE_CHECK)
3108    sim_state = ad.adb.getprop("gsm.sim.state").split(",")
3109    ad.log.warning("Fail to power on SIM slot %d, sim_state=%s",
3110        sim_slot_id, sim_state[sim_slot_id])
3111    return False
3112
3113
3114def power_off_sim(ad, sim_slot_id=None,
3115                  timeout=MAX_WAIT_TIME_FOR_STATE_CHANGE):
3116    try:
3117        if sim_slot_id is None:
3118            ad.droid.telephonySetSimPowerState(CARD_POWER_DOWN)
3119            verify_func = ad.droid.telephonyGetSimState
3120            verify_args = []
3121        else:
3122            ad.droid.telephonySetSimStateForSlotId(sim_slot_id,
3123                                                   CARD_POWER_DOWN)
3124            verify_func = ad.droid.telephonyGetSimStateForSlotId
3125            verify_args = [sim_slot_id]
3126    except Exception as e:
3127        ad.log.error(e)
3128        return False
3129    while timeout > 0:
3130        sim_state = verify_func(*verify_args)
3131        if sim_state in (
3132            SIM_STATE_UNKNOWN, SIM_STATE_ABSENT, SIM_STATE_NOT_READY):
3133            ad.log.info("SIM slot is powered off, SIM state is %s", sim_state)
3134            return True
3135        timeout = timeout - WAIT_TIME_BETWEEN_STATE_CHECK
3136        time.sleep(WAIT_TIME_BETWEEN_STATE_CHECK)
3137    ad.log.warning("Fail to power off SIM slot, sim_state=%s",
3138                   verify_func(*verify_args))
3139    return False
3140
3141
3142def power_on_sim(ad, sim_slot_id=None):
3143    try:
3144        if sim_slot_id is None:
3145            ad.droid.telephonySetSimPowerState(CARD_POWER_UP)
3146            verify_func = ad.droid.telephonyGetSimState
3147            verify_args = []
3148        else:
3149            ad.droid.telephonySetSimStateForSlotId(sim_slot_id, CARD_POWER_UP)
3150            verify_func = ad.droid.telephonyGetSimStateForSlotId
3151            verify_args = [sim_slot_id]
3152    except Exception as e:
3153        ad.log.error(e)
3154        return False
3155    if wait_for_state(verify_func, SIM_STATE_READY,
3156                      MAX_WAIT_TIME_FOR_STATE_CHANGE,
3157                      WAIT_TIME_BETWEEN_STATE_CHECK, *verify_args):
3158        ad.log.info("SIM slot is powered on, SIM state is READY")
3159        return True
3160    elif verify_func(*verify_args) == SIM_STATE_PIN_REQUIRED:
3161        ad.log.info("SIM is pin locked")
3162        return True
3163    else:
3164        ad.log.error("Fail to power on SIM slot")
3165        return False
3166
3167
3168def get_device_epoch_time(ad):
3169    return int(1000 * float(ad.adb.shell("date +%s.%N")))
3170
3171
3172def synchronize_device_time(ad):
3173    ad.adb.shell("put global auto_time 0", ignore_status=True)
3174    try:
3175        ad.adb.droid.setTime(get_current_epoch_time())
3176    except Exception:
3177        try:
3178            ad.adb.shell("date `date +%m%d%H%M%G.%S`")
3179        except Exception:
3180            pass
3181    try:
3182        ad.adb.shell(
3183            "am broadcast -a android.intent.action.TIME_SET",
3184            ignore_status=True)
3185    except Exception:
3186        pass
3187
3188
3189def revert_default_telephony_setting(ad):
3190    toggle_airplane_mode_by_adb(ad.log, ad, True)
3191    default_data_roaming = int(
3192        ad.adb.getprop("ro.com.android.dataroaming") == 'true')
3193    default_network_preference = int(
3194        ad.adb.getprop("ro.telephony.default_network"))
3195    ad.log.info("Default data roaming %s, network preference %s",
3196                default_data_roaming, default_network_preference)
3197    new_data_roaming = abs(default_data_roaming - 1)
3198    new_network_preference = abs(default_network_preference - 1)
3199    ad.log.info(
3200        "Set data roaming = %s, mobile data = 0, network preference = %s",
3201        new_data_roaming, new_network_preference)
3202    ad.adb.shell("settings put global mobile_data 0")
3203    ad.adb.shell("settings put global data_roaming %s" % new_data_roaming)
3204    ad.adb.shell("settings put global preferred_network_mode %s" %
3205                 new_network_preference)
3206
3207
3208def verify_default_telephony_setting(ad):
3209    ad.log.info("carrier_config: %s", dumpsys_carrier_config(ad))
3210    default_data_roaming = int(
3211        ad.adb.getprop("ro.com.android.dataroaming") == 'true')
3212    default_network_preference = int(
3213        ad.adb.getprop("ro.telephony.default_network"))
3214    ad.log.info("Default data roaming %s, network preference %s",
3215                default_data_roaming, default_network_preference)
3216    data_roaming = int(ad.adb.shell("settings get global data_roaming"))
3217    mobile_data = int(ad.adb.shell("settings get global mobile_data"))
3218    network_preference = int(
3219        ad.adb.shell("settings get global preferred_network_mode"))
3220    airplane_mode = int(ad.adb.shell("settings get global airplane_mode_on"))
3221    result = True
3222    ad.log.info("data_roaming = %s, mobile_data = %s, "
3223                "network_perference = %s, airplane_mode = %s", data_roaming,
3224                mobile_data, network_preference, airplane_mode)
3225    if airplane_mode:
3226        ad.log.error("Airplane mode is on")
3227        result = False
3228    if data_roaming != default_data_roaming:
3229        ad.log.error("Data roaming is %s, expecting %s", data_roaming,
3230                     default_data_roaming)
3231        result = False
3232    if not mobile_data:
3233        ad.log.error("Mobile data is off")
3234        result = False
3235    if network_preference != default_network_preference:
3236        ad.log.error("preferred_network_mode is %s, expecting %s",
3237                     network_preference, default_network_preference)
3238        result = False
3239    return result
3240
3241
3242def get_carrier_id_version(ad):
3243    out = ad.adb.shell("dumpsys activity service TelephonyDebugService | " \
3244                       "grep -i carrier_list_version")
3245    if out and ":" in out:
3246        version = out.split(':')[1].lstrip()
3247    else:
3248        version = "0"
3249    ad.log.debug("Carrier Config Version is %s", version)
3250    return version
3251
3252
3253def get_carrier_config_version(ad):
3254    out = ad.adb.shell("dumpsys carrier_config | grep version_string")
3255    if out and "-" in out:
3256        version = out.split('-')[1]
3257    else:
3258        version = "0"
3259    ad.log.debug("Carrier Config Version is %s", version)
3260    return version
3261
3262
3263def get_er_db_id_version(ad):
3264    out = ad.adb.shell("dumpsys activity service TelephonyDebugService | \
3265                        grep -i \"Database Version\"")
3266    if out and ":" in out:
3267        version = out.split(':', 2)[2].lstrip()
3268    else:
3269        version = "0"
3270    ad.log.debug("Emergency database Version is %s", version)
3271    return version
3272
3273def get_database_content(ad):
3274    out = ad.adb.shell("dumpsys activity service TelephonyDebugService | \
3275                        egrep -i \EmergencyNumber:Number-54321")
3276    if out:
3277        return True
3278    result = ad.adb.shell(r"dumpsys activity service TelephonyDebugService | \
3279                egrep -i \updateOtaEmergencyNumberListDatabaseAndNotify")
3280    ad.log.error("Emergency Number is incorrect. %s ", result)
3281    return False
3282
3283
3284def add_whitelisted_account(ad, user_account,user_password, retries=3):
3285    if not ad.is_apk_installed("com.google.android.tradefed.account"):
3286        ad.log.error("GoogleAccountUtil is not installed")
3287        return False
3288    for _ in range(retries):
3289        ad.ensure_screen_on()
3290        output = ad.adb.shell(
3291            'am instrument -w -e account "%s@gmail.com" -e password '
3292            '"%s" -e sync true -e wait-for-checkin false '
3293            'com.google.android.tradefed.account/.AddAccount' %
3294            (user_account, user_password))
3295        if "result=SUCCESS" in output:
3296            ad.log.info("Google account is added successfully")
3297            return True
3298    ad.log.error("Failed to add google account - %s", output)
3299    return False
3300
3301def install_apk(ad, apk_path, app_package_name):
3302    """Install assigned apk to specific device.
3303
3304    Args:
3305        ad: android device object
3306        apk_path: The path of apk (please refer to the "Resources" section in
3307            go/mhbe-resources for supported file stores.)
3308        app_package_name: package name of the application
3309
3310    Returns:
3311        True if success, False if fail.
3312    """
3313    ad.log.info("Install %s from %s", app_package_name, apk_path)
3314    ad.adb.install("-r -g %s" % apk_path, timeout=300, ignore_status=True)
3315    time.sleep(3)
3316    if not ad.is_apk_installed(app_package_name):
3317        ad.log.info("%s is not installed.", app_package_name)
3318        return False
3319    if ad.get_apk_version(app_package_name):
3320        ad.log.info("Current version of %s: %s", app_package_name,
3321                    ad.get_apk_version(app_package_name))
3322    return True
3323
3324def install_dialer_apk(ad, dialer_util):
3325    """Install dialer.apk to specific device.
3326
3327    Args:
3328        ad: android device object.
3329        dialer_util: path of dialer.apk
3330
3331    Returns:
3332        True if success, False if fail.
3333    """
3334    ad.log.info("Install dialer_util %s", dialer_util)
3335    ad.adb.install("-r -g %s" % dialer_util, timeout=300, ignore_status=True)
3336    time.sleep(3)
3337    if not ad.is_apk_installed(DIALER_PACKAGE_NAME):
3338        ad.log.info("%s is not installed", DIALER_PACKAGE_NAME)
3339        return False
3340    if ad.get_apk_version(DIALER_PACKAGE_NAME):
3341        ad.log.info("Current version of %s: %s", DIALER_PACKAGE_NAME,
3342                    ad.get_apk_version(DIALER_PACKAGE_NAME))
3343    return True
3344
3345
3346def install_message_apk(ad, message_util):
3347    """Install message.apk to specific device.
3348
3349    Args:
3350        ad: android device object.
3351        message_util: path of message.apk
3352
3353    Returns:
3354        True if success, False if fail.
3355    """
3356    ad.log.info("Install message_util %s", message_util)
3357    ad.adb.install("-r -g %s" % message_util, timeout=300, ignore_status=True)
3358    time.sleep(3)
3359    if not ad.is_apk_installed(MESSAGE_PACKAGE_NAME):
3360        ad.log.info("%s is not installed", MESSAGE_PACKAGE_NAME)
3361        return False
3362    if ad.get_apk_version(MESSAGE_PACKAGE_NAME):
3363        ad.log.info("Current version of %s: %s", MESSAGE_PACKAGE_NAME,
3364                    ad.get_apk_version(MESSAGE_PACKAGE_NAME))
3365    return True
3366
3367
3368def install_googleaccountutil_apk(ad, account_util):
3369    ad.log.info("Install account_util %s", account_util)
3370    ad.ensure_screen_on()
3371    ad.adb.install("-r %s" % account_util, timeout=300, ignore_status=True)
3372    time.sleep(3)
3373    if not ad.is_apk_installed("com.google.android.tradefed.account"):
3374        ad.log.info("com.google.android.tradefed.account is not installed")
3375        return False
3376    return True
3377
3378
3379def install_googlefi_apk(ad, fi_util):
3380    ad.log.info("Install fi_util %s", fi_util)
3381    ad.ensure_screen_on()
3382    ad.adb.install("-r -g --user 0 %s" % fi_util,
3383                   timeout=300, ignore_status=True)
3384    time.sleep(3)
3385    if not check_fi_apk_installed(ad):
3386        return False
3387    return True
3388
3389
3390def check_fi_apk_installed(ad):
3391    if not ad.is_apk_installed("com.google.android.apps.tycho"):
3392        ad.log.warning("com.google.android.apps.tycho is not installed")
3393        return False
3394    return True
3395
3396
3397def add_google_account(ad, retries=3):
3398    if not ad.is_apk_installed("com.google.android.tradefed.account"):
3399        ad.log.error("GoogleAccountUtil is not installed")
3400        return False
3401    for _ in range(retries):
3402        ad.ensure_screen_on()
3403        output = ad.adb.shell(
3404            'am instrument -w -e account "%s@gmail.com" -e password '
3405            '"%s" -e sync true -e wait-for-checkin false '
3406            'com.google.android.tradefed.account/.AddAccount' %
3407            (ad.user_account, ad.user_password))
3408        if "result=SUCCESS" in output:
3409            ad.log.info("Google account is added successfully")
3410            return True
3411    ad.log.error("Failed to add google account - %s", output)
3412    return False
3413
3414
3415def remove_google_account(ad, retries=3):
3416    if not ad.is_apk_installed("com.google.android.tradefed.account"):
3417        ad.log.error("GoogleAccountUtil is not installed")
3418        return False
3419    for _ in range(retries):
3420        ad.ensure_screen_on()
3421        output = ad.adb.shell(
3422            'am instrument -w '
3423            'com.google.android.tradefed.account/.RemoveAccounts')
3424        if "result=SUCCESS" in output:
3425            ad.log.info("google account is removed successfully")
3426            return True
3427    ad.log.error("Fail to remove google account due to %s", output)
3428    return False
3429
3430
3431def my_current_screen_content(ad, content):
3432    ad.adb.shell("uiautomator dump --window=WINDOW")
3433    out = ad.adb.shell("cat /sdcard/window_dump.xml | grep -E '%s'" % content)
3434    if not out:
3435        ad.log.warning("NOT FOUND - %s", content)
3436        return False
3437    return True
3438
3439
3440def activate_esim_using_suw(ad):
3441    _START_SUW = ('am start -a android.intent.action.MAIN -n '
3442                  'com.google.android.setupwizard/.SetupWizardTestActivity')
3443    _STOP_SUW = ('am start -a com.android.setupwizard.EXIT')
3444
3445    toggle_airplane_mode(ad.log, ad, new_state=False, strict_checking=False)
3446    ad.adb.shell("settings put system screen_off_timeout 1800000")
3447    ad.ensure_screen_on()
3448    ad.send_keycode("MENU")
3449    ad.send_keycode("HOME")
3450    for _ in range(3):
3451        ad.log.info("Attempt %d - activating eSIM", (_ + 1))
3452        ad.adb.shell(_START_SUW)
3453        time.sleep(10)
3454        log_screen_shot(ad, "start_suw")
3455        for _ in range(4):
3456            ad.send_keycode("TAB")
3457            time.sleep(0.5)
3458        ad.send_keycode("ENTER")
3459        time.sleep(15)
3460        log_screen_shot(ad, "activate_esim")
3461        get_screen_shot_log(ad)
3462        ad.adb.shell(_STOP_SUW)
3463        time.sleep(5)
3464        current_sim = get_sim_state(ad)
3465        ad.log.info("Current SIM status is %s", current_sim)
3466        if current_sim not in (SIM_STATE_ABSENT, SIM_STATE_UNKNOWN):
3467            break
3468    return True
3469
3470
3471def activate_google_fi_account(ad, retries=10):
3472    _FI_APK = "com.google.android.apps.tycho"
3473    _FI_ACTIVATE_CMD = ('am start -c android.intent.category.DEFAULT -n '
3474                        'com.google.android.apps.tycho/.AccountDetailsActivity --ez '
3475                        'in_setup_wizard false --ez force_show_account_chooser '
3476                        'false')
3477    toggle_airplane_mode(ad.log, ad, new_state=False, strict_checking=False)
3478    ad.adb.shell("settings put system screen_off_timeout 1800000")
3479    page_match_dict = {
3480       "SelectAccount" : "Choose an account to use",
3481       "Setup" : "Activate Google Fi to use your device for calls",
3482       "Switch" : "Switch to the Google Fi mobile network",
3483       "WiFi" : "Fi to download your SIM",
3484       "Connect" : "Connect to the Google Fi mobile network",
3485       "Move" : "Move number",
3486       "Data" : "first turn on mobile data",
3487       "Activate" : "This takes a minute or two, sometimes longer",
3488       "Welcome" : "Welcome to Google Fi",
3489       "Account" : "Your current cycle ends in"
3490    }
3491    page_list = ["Account", "Setup", "WiFi", "Switch", "Connect",
3492                 "Activate", "Move", "Welcome", "Data"]
3493    for _ in range(retries):
3494        ad.force_stop_apk(_FI_APK)
3495        ad.ensure_screen_on()
3496        ad.send_keycode("MENU")
3497        ad.send_keycode("HOME")
3498        ad.adb.shell(_FI_ACTIVATE_CMD)
3499        time.sleep(15)
3500        for page in page_list:
3501            if my_current_screen_content(ad, page_match_dict[page]):
3502                ad.log.info("Ready for Step %s", page)
3503                log_screen_shot(ad, "fi_activation_step_%s" % page)
3504                if page in ("Setup", "Switch", "Connect", "WiFi"):
3505                    ad.send_keycode("TAB")
3506                    ad.send_keycode("TAB")
3507                    ad.send_keycode("ENTER")
3508                    time.sleep(30)
3509                elif page == "Move" or page == "SelectAccount":
3510                    ad.send_keycode("TAB")
3511                    ad.send_keycode("ENTER")
3512                    time.sleep(5)
3513                elif page == "Welcome":
3514                    ad.send_keycode("TAB")
3515                    ad.send_keycode("TAB")
3516                    ad.send_keycode("TAB")
3517                    ad.send_keycode("ENTER")
3518                    ad.log.info("Activation SUCCESS using Fi App")
3519                    time.sleep(5)
3520                    ad.send_keycode("TAB")
3521                    ad.send_keycode("TAB")
3522                    ad.send_keycode("ENTER")
3523                    return True
3524                elif page == "Activate":
3525                    time.sleep(60)
3526                    if my_current_screen_content(ad, page_match_dict[page]):
3527                        time.sleep(60)
3528                elif page == "Account":
3529                    return True
3530                elif page == "Data":
3531                    ad.log.error("Mobile Data is turned OFF by default")
3532                    ad.send_keycode("TAB")
3533                    ad.send_keycode("TAB")
3534                    ad.send_keycode("ENTER")
3535            else:
3536                ad.log.info("NOT FOUND - Page %s", page)
3537                log_screen_shot(ad, "fi_activation_step_%s_failure" % page)
3538                get_screen_shot_log(ad)
3539    return False
3540
3541
3542def check_google_fi_activated(ad, retries=20):
3543    if check_fi_apk_installed(ad):
3544        _FI_APK = "com.google.android.apps.tycho"
3545        _FI_LAUNCH_CMD = ("am start -n %s/%s.AccountDetailsActivity" \
3546                          % (_FI_APK, _FI_APK))
3547        toggle_airplane_mode(ad.log, ad, new_state=False, strict_checking=False)
3548        ad.adb.shell("settings put system screen_off_timeout 1800000")
3549        ad.force_stop_apk(_FI_APK)
3550        ad.ensure_screen_on()
3551        ad.send_keycode("HOME")
3552        ad.adb.shell(_FI_LAUNCH_CMD)
3553        time.sleep(10)
3554        if not my_current_screen_content(ad, "Your current cycle ends in"):
3555            ad.log.warning("Fi is not activated")
3556            return False
3557        ad.send_keycode("HOME")
3558        return True
3559    else:
3560        ad.log.info("Fi Apk is not yet installed")
3561        return False
3562
3563
3564def cleanup_configupdater(ad):
3565    cmds = ('rm -rf /data/data/com.google.android.configupdater/shared_prefs',
3566            'rm /data/misc/carrierid/carrier_list.pb',
3567            'setprop persist.telephony.test.carrierid.ota true',
3568            'rm /data/user_de/0/com.android.providers.telephony/shared_prefs'
3569            '/CarrierIdProvider.xml')
3570    for cmd in cmds:
3571        ad.log.info("Cleanup ConfigUpdater - %s", cmd)
3572        ad.adb.shell(cmd, ignore_status=True)
3573
3574
3575def pull_carrier_id_files(ad, carrier_id_path):
3576    os.makedirs(carrier_id_path, exist_ok=True)
3577    ad.log.info("Pull CarrierId Files")
3578    cmds = ('/data/data/com.google.android.configupdater/shared_prefs/',
3579            '/data/misc/carrierid/',
3580            '/data/user_de/0/com.android.providers.telephony/shared_prefs/',
3581            '/data/data/com.android.providers.downloads/databases/downloads.db')
3582    for cmd in cmds:
3583        cmd = cmd + " %s" % carrier_id_path
3584        ad.adb.pull(cmd, timeout=30, ignore_status=True)
3585
3586
3587def bring_up_connectivity_monitor(ad):
3588    monitor_apk = None
3589    for apk in ("com.google.telephonymonitor",
3590                "com.google.android.connectivitymonitor"):
3591        if ad.is_apk_installed(apk):
3592            ad.log.info("apk %s is installed", apk)
3593            monitor_apk = apk
3594            break
3595    if not monitor_apk:
3596        ad.log.info("ConnectivityMonitor|TelephonyMonitor is not installed")
3597        return False
3598    toggle_connectivity_monitor_setting(ad, True)
3599
3600    if not ad.is_apk_running(monitor_apk):
3601        ad.log.info("%s is not running", monitor_apk)
3602        # Reboot
3603        ad.log.info("reboot to bring up %s", monitor_apk)
3604        reboot_device(ad)
3605        for i in range(30):
3606            if ad.is_apk_running(monitor_apk):
3607                ad.log.info("%s is running after reboot", monitor_apk)
3608                return True
3609            else:
3610                ad.log.info(
3611                    "%s is not running after reboot. Wait and check again",
3612                    monitor_apk)
3613                time.sleep(30)
3614        ad.log.error("%s is not running after reboot", monitor_apk)
3615        return False
3616    else:
3617        ad.log.info("%s is running", monitor_apk)
3618        return True
3619
3620
3621def get_host_ip_address(ad):
3622    cmd = "|".join(("ifconfig", "grep eno1 -A1", "grep inet", "awk '{$1=$1};1'", "cut -d ' ' -f 2"))
3623    destination_ip = exe_cmd(cmd)
3624    destination_ip = (destination_ip.decode("utf-8")).split("\n")[0]
3625    ad.log.info("Host IP is %s", destination_ip)
3626    return destination_ip
3627
3628
3629def load_scone_cat_simulate_data(ad, simulate_data, sub_id=None):
3630    """ Load radio simulate data
3631    ad: android device controller
3632    simulate_data: JSON object of simulate data
3633    sub_id: RIL sub id, should be 0 or 1
3634    """
3635    ad.log.info("load_scone_cat_simulate_data")
3636
3637    #Check RIL sub id
3638    if sub_id is None or sub_id > 1:
3639        ad.log.error("The value of RIL sub_id should be 0 or 1")
3640        return False
3641
3642    action = "com.google.android.apps.scone.cat.action.SetSimulateData"
3643
3644    #add sub id
3645    simulate_data["SubId"] = sub_id
3646    try:
3647        #dump json
3648        extra = json.dumps(simulate_data)
3649        ad.log.info("send simulate_data=[%s]" % extra)
3650        #send data
3651        ad.adb.shell("am broadcast -a " + action + " --es simulate_data '" + extra + "'")
3652    except Exception as e:
3653        ad.log.error("Exception error to send CAT: %s", e)
3654        return False
3655
3656    return True
3657
3658
3659def load_scone_cat_data_from_file(ad, simulate_file_path, sub_id=None):
3660    """ Load radio simulate data
3661    ad: android device controller
3662    simulate_file_path: JSON file of simulate data
3663    sub_id: RIL sub id, should be 0 or 1
3664    """
3665    ad.log.info("load_radio_simulate_data_from_file from %s" % simulate_file_path)
3666    radio_simulate_data = {}
3667
3668    #Check RIL sub id
3669    if sub_id is None or sub_id > 1:
3670        ad.log.error("The value of RIL sub_id should be 0 or 1")
3671        raise ValueError
3672
3673    with open(simulate_file_path, 'r') as f:
3674        try:
3675            radio_simulate_data = json.load(f)
3676        except Exception as e:
3677            ad.log.error("Exception error to load %s: %s", f, e)
3678            return False
3679
3680    for item in radio_simulate_data:
3681        result = load_scone_cat_simulate_data(ad, item, sub_id)
3682        if result == False:
3683            ad.log.error("Load CAT command fail")
3684            return False
3685        time.sleep(0.1)
3686
3687    return True
3688
3689
3690def toggle_connectivity_monitor_setting(ad, state=True):
3691    monitor_setting = ad.adb.getprop("persist.radio.enable_tel_mon")
3692    ad.log.info("radio.enable_tel_mon setting is %s", monitor_setting)
3693    current_state = True if monitor_setting == "user_enabled" else False
3694    if current_state == state:
3695        return True
3696    elif state is None:
3697        state = not current_state
3698    expected_monitor_setting = "user_enabled" if state else "disabled"
3699    cmd = "setprop persist.radio.enable_tel_mon %s" % expected_monitor_setting
3700    ad.log.info("Toggle connectivity monitor by %s", cmd)
3701    ad.adb.shell(
3702        "am start -n com.android.settings/.DevelopmentSettings",
3703        ignore_status=True)
3704    ad.adb.shell(cmd)
3705    monitor_setting = ad.adb.getprop("persist.radio.enable_tel_mon")
3706    ad.log.info("radio.enable_tel_mon setting is %s", monitor_setting)
3707    return monitor_setting == expected_monitor_setting
3708
3709
3710def get_rx_tx_power_levels(log, ad):
3711    """ Obtains Rx and Tx power levels from the MDS application.
3712
3713    The method requires the MDS app to be installed in the DUT.
3714
3715    Args:
3716        log: logger object
3717        ad: an android device
3718
3719    Return:
3720        A tuple where the first element is an array array with the RSRP value
3721        in Rx chain, and the second element is the transmitted power in dBm.
3722        Values for invalid Rx / Tx chains are set to None.
3723    """
3724    cmd = ('am instrument -w -e request "80 00 e8 03 00 08 00 00 00" -e '
3725           'response wait "com.google.mdstest/com.google.mdstest.instrument.'
3726           'ModemCommandInstrumentation"')
3727    output = ad.adb.shell(cmd)
3728
3729    if 'result=SUCCESS' not in output:
3730        raise RuntimeError('Could not obtain Tx/Rx power levels from MDS. Is '
3731                           'the MDS app installed?')
3732
3733    response = re.search(r"(?<=response=).+", output)
3734
3735    if not response:
3736        raise RuntimeError('Invalid response from the MDS app:\n' + output)
3737
3738    # Obtain a list of bytes in hex format from the response string
3739    response_hex = response.group(0).split(' ')
3740
3741    def get_bool(pos):
3742        """ Obtain a boolean variable from the byte array. """
3743        return response_hex[pos] == '01'
3744
3745    def get_int32(pos):
3746        """ Obtain an int from the byte array. Bytes are printed in
3747        little endian format."""
3748        return struct.unpack(
3749            '<i', bytearray.fromhex(''.join(response_hex[pos:pos + 4])))[0]
3750
3751    rx_power = []
3752    RX_CHAINS = 4
3753
3754    for i in range(RX_CHAINS):
3755        # Calculate starting position for the Rx chain data structure
3756        start = 12 + i * 22
3757
3758        # The first byte in the data structure indicates if the rx chain is
3759        # valid.
3760        if get_bool(start):
3761            rx_power.append(get_int32(start + 2) / 10)
3762        else:
3763            rx_power.append(None)
3764
3765    # Calculate the position for the tx chain data structure
3766    tx_pos = 12 + RX_CHAINS * 22
3767
3768    tx_valid = get_bool(tx_pos)
3769    if tx_valid:
3770        tx_power = get_int32(tx_pos + 2) / -10
3771    else:
3772        tx_power = None
3773
3774    return rx_power, tx_power
3775
3776
3777def set_time_sync_from_network(ad, action):
3778    if (action == 'enable'):
3779        ad.log.info('Enabling sync time from network.')
3780        ad.adb.shell('settings put global auto_time 1')
3781
3782    elif (action == 'disable'):
3783        ad.log.info('Disabling sync time from network.')
3784        ad.adb.shell('settings put global auto_time 0')
3785
3786    time.sleep(WAIT_TIME_SYNC_DATE_TIME_FROM_NETWORK)
3787
3788
3789def datetime_handle(ad, action, set_datetime_value='', get_year=False):
3790    get_value = ''
3791    if (action == 'get'):
3792        if (get_year):
3793            datetime_string = ad.adb.shell('date')
3794            datetime_list = datetime_string.split()
3795            try:
3796                get_value = datetime_list[5]
3797            except Exception as e:
3798                ad.log.error("Fail to get year from datetime: %s. " \
3799                                "Exception error: %s", datetime_list
3800                                , str(e))
3801                raise signals.TestSkip("Fail to get year from datetime" \
3802                                    ", the format is changed. Skip the test.")
3803        else:
3804            get_value = ad.adb.shell('date')
3805
3806    elif (action == 'set'):
3807        ad.adb.shell('date %s' % set_datetime_value)
3808        time.sleep(WAIT_TIME_SYNC_DATE_TIME_FROM_NETWORK)
3809        ad.adb.shell('am broadcast -a android.intent.action.TIME_SET')
3810
3811    return get_value
3812
3813
3814def change_voice_subid_temporarily(ad, sub_id, state_check_func, params=None):
3815    result = False
3816    voice_sub_id_changed = False
3817    current_sub_id = get_incoming_voice_sub_id(ad)
3818    if current_sub_id != sub_id:
3819        set_incoming_voice_sub_id(ad, sub_id)
3820        voice_sub_id_changed = True
3821
3822    if not params:
3823        if state_check_func():
3824            result = True
3825    else:
3826        if state_check_func(*params):
3827            result = True
3828
3829    if voice_sub_id_changed:
3830        set_incoming_voice_sub_id(ad, current_sub_id)
3831
3832    return result
3833
3834
3835def check_voice_network_type(ads, voice_init=True):
3836    """
3837    Args:
3838        ad: Android device object
3839        voice_init: check voice network type before initiate call
3840    Return:
3841        voice_network_list: Network Type for all android devices
3842    """
3843    voice_network_list = []
3844    for ad in ads:
3845        voice_network_list.append(ad.droid.telephonyGetCurrentVoiceNetworkType())
3846        if voice_init:
3847            ad.log.debug("Voice Network Type Before Call is %s",
3848                            ad.droid.telephonyGetCurrentVoiceNetworkType())
3849        else:
3850            ad.log.debug("Voice Network Type During Call is %s",
3851                            ad.droid.telephonyGetCurrentVoiceNetworkType())
3852    return voice_network_list
3853
3854
3855def cycle_airplane_mode(ad):
3856    """Turn on APM and then off."""
3857    # APM toggle
3858    if not toggle_airplane_mode(ad.log, ad, True):
3859        ad.log.info("Failed to turn on airplane mode.")
3860        return False
3861    if not toggle_airplane_mode(ad.log, ad, False):
3862        ad.log.info("Failed to turn off airplane mode.")
3863        return False
3864    return True