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