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