1#!/usr/bin/env python3.4
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 utils
29from queue import Empty
30from acts.asserts import abort_all
31from acts.controllers.adb import AdbError
32from acts.controllers.android_device import DEFAULT_QXDM_LOG_PATH
33from acts.controllers.android_device import SL4A_APK_NAME
34from acts.controllers.sl4a_lib.event_dispatcher import EventDispatcher
35from acts.test_utils.tel.tel_defines import AOSP_PREFIX
36from acts.test_utils.tel.tel_defines import CARD_POWER_DOWN
37from acts.test_utils.tel.tel_defines import CARD_POWER_UP
38from acts.test_utils.tel.tel_defines import CARRIER_UNKNOWN
39from acts.test_utils.tel.tel_defines import COUNTRY_CODE_LIST
40from acts.test_utils.tel.tel_defines import DATA_STATE_CONNECTED
41from acts.test_utils.tel.tel_defines import DATA_STATE_DISCONNECTED
42from acts.test_utils.tel.tel_defines import DATA_ROAMING_ENABLE
43from acts.test_utils.tel.tel_defines import DATA_ROAMING_DISABLE
44from acts.test_utils.tel.tel_defines import GEN_4G
45from acts.test_utils.tel.tel_defines import GEN_UNKNOWN
46from acts.test_utils.tel.tel_defines import INCALL_UI_DISPLAY_BACKGROUND
47from acts.test_utils.tel.tel_defines import INCALL_UI_DISPLAY_FOREGROUND
48from acts.test_utils.tel.tel_defines import INVALID_SIM_SLOT_INDEX
49from acts.test_utils.tel.tel_defines import INVALID_SUB_ID
50from acts.test_utils.tel.tel_defines import MAX_SAVED_VOICE_MAIL
51from acts.test_utils.tel.tel_defines import MAX_SCREEN_ON_TIME
52from acts.test_utils.tel.tel_defines import \
53    MAX_WAIT_TIME_ACCEPT_CALL_TO_OFFHOOK_EVENT
54from acts.test_utils.tel.tel_defines import MAX_WAIT_TIME_AIRPLANEMODE_EVENT
55from acts.test_utils.tel.tel_defines import MAX_WAIT_TIME_CALL_DROP
56from acts.test_utils.tel.tel_defines import MAX_WAIT_TIME_CALL_INITIATION
57from acts.test_utils.tel.tel_defines import MAX_WAIT_TIME_CALLEE_RINGING
58from acts.test_utils.tel.tel_defines import MAX_WAIT_TIME_CONNECTION_STATE_UPDATE
59from acts.test_utils.tel.tel_defines import MAX_WAIT_TIME_DATA_SUB_CHANGE
60from acts.test_utils.tel.tel_defines import MAX_WAIT_TIME_CALL_IDLE_EVENT
61from acts.test_utils.tel.tel_defines import MAX_WAIT_TIME_NW_SELECTION
62from acts.test_utils.tel.tel_defines import MAX_WAIT_TIME_SMS_RECEIVE
63from acts.test_utils.tel.tel_defines import MAX_WAIT_TIME_SMS_SENT_SUCCESS
64from acts.test_utils.tel.tel_defines import MAX_WAIT_TIME_TELECOM_RINGING
65from acts.test_utils.tel.tel_defines import MAX_WAIT_TIME_VOICE_MAIL_COUNT
66from acts.test_utils.tel.tel_defines import MAX_WAIT_TIME_WFC_DISABLED
67from acts.test_utils.tel.tel_defines import MAX_WAIT_TIME_WFC_ENABLED
68from acts.test_utils.tel.tel_defines import NETWORK_MODE_LTE_ONLY
69from acts.test_utils.tel.tel_defines import NETWORK_CONNECTION_TYPE_CELL
70from acts.test_utils.tel.tel_defines import NETWORK_CONNECTION_TYPE_WIFI
71from acts.test_utils.tel.tel_defines import NETWORK_SERVICE_DATA
72from acts.test_utils.tel.tel_defines import NETWORK_SERVICE_VOICE
73from acts.test_utils.tel.tel_defines import PHONE_NUMBER_STRING_FORMAT_7_DIGIT
74from acts.test_utils.tel.tel_defines import PHONE_NUMBER_STRING_FORMAT_10_DIGIT
75from acts.test_utils.tel.tel_defines import PHONE_NUMBER_STRING_FORMAT_11_DIGIT
76from acts.test_utils.tel.tel_defines import PHONE_NUMBER_STRING_FORMAT_12_DIGIT
77from acts.test_utils.tel.tel_defines import RAT_FAMILY_GSM
78from acts.test_utils.tel.tel_defines import RAT_FAMILY_LTE
79from acts.test_utils.tel.tel_defines import RAT_FAMILY_WLAN
80from acts.test_utils.tel.tel_defines import RAT_FAMILY_WCDMA
81from acts.test_utils.tel.tel_defines import RAT_1XRTT
82from acts.test_utils.tel.tel_defines import RAT_UNKNOWN
83from acts.test_utils.tel.tel_defines import SERVICE_STATE_EMERGENCY_ONLY
84from acts.test_utils.tel.tel_defines import SERVICE_STATE_IN_SERVICE
85from acts.test_utils.tel.tel_defines import SERVICE_STATE_MAPPING
86from acts.test_utils.tel.tel_defines import SERVICE_STATE_OUT_OF_SERVICE
87from acts.test_utils.tel.tel_defines import SERVICE_STATE_POWER_OFF
88from acts.test_utils.tel.tel_defines import SIM_STATE_LOADED
89from acts.test_utils.tel.tel_defines import SIM_STATE_NOT_READY
90from acts.test_utils.tel.tel_defines import SIM_STATE_PIN_REQUIRED
91from acts.test_utils.tel.tel_defines import SIM_STATE_READY
92from acts.test_utils.tel.tel_defines import SIM_STATE_UNKNOWN
93from acts.test_utils.tel.tel_defines import TELEPHONY_STATE_IDLE
94from acts.test_utils.tel.tel_defines import TELEPHONY_STATE_OFFHOOK
95from acts.test_utils.tel.tel_defines import TELEPHONY_STATE_RINGING
96from acts.test_utils.tel.tel_defines import VOICEMAIL_DELETE_DIGIT
97from acts.test_utils.tel.tel_defines import WAIT_TIME_1XRTT_VOICE_ATTACH
98from acts.test_utils.tel.tel_defines import WAIT_TIME_ANDROID_STATE_SETTLING
99from acts.test_utils.tel.tel_defines import WAIT_TIME_BETWEEN_STATE_CHECK
100from acts.test_utils.tel.tel_defines import MAX_WAIT_TIME_FOR_STATE_CHANGE
101from acts.test_utils.tel.tel_defines import WAIT_TIME_CHANGE_DATA_SUB_ID
102from acts.test_utils.tel.tel_defines import WAIT_TIME_IN_CALL
103from acts.test_utils.tel.tel_defines import WAIT_TIME_LEAVE_VOICE_MAIL
104from acts.test_utils.tel.tel_defines import WAIT_TIME_REJECT_CALL
105from acts.test_utils.tel.tel_defines import WAIT_TIME_VOICE_MAIL_SERVER_RESPONSE
106from acts.test_utils.tel.tel_defines import WFC_MODE_DISABLED
107from acts.test_utils.tel.tel_defines import TYPE_MOBILE
108from acts.test_utils.tel.tel_defines import TYPE_WIFI
109from acts.test_utils.tel.tel_defines import EventCallStateChanged
110from acts.test_utils.tel.tel_defines import EventConnectivityChanged
111from acts.test_utils.tel.tel_defines import EventDataConnectionStateChanged
112from acts.test_utils.tel.tel_defines import EventDataSmsReceived
113from acts.test_utils.tel.tel_defines import EventMessageWaitingIndicatorChanged
114from acts.test_utils.tel.tel_defines import EventServiceStateChanged
115from acts.test_utils.tel.tel_defines import EventMmsSentSuccess
116from acts.test_utils.tel.tel_defines import EventMmsDownloaded
117from acts.test_utils.tel.tel_defines import EventSmsReceived
118from acts.test_utils.tel.tel_defines import EventSmsSentSuccess
119from acts.test_utils.tel.tel_defines import CallStateContainer
120from acts.test_utils.tel.tel_defines import DataConnectionStateContainer
121from acts.test_utils.tel.tel_defines import MessageWaitingIndicatorContainer
122from acts.test_utils.tel.tel_defines import NetworkCallbackContainer
123from acts.test_utils.tel.tel_defines import ServiceStateContainer
124from acts.test_utils.tel.tel_lookup_tables import \
125    connection_type_from_type_string
126from acts.test_utils.tel.tel_lookup_tables import is_valid_rat
127from acts.test_utils.tel.tel_lookup_tables import get_allowable_network_preference
128from acts.test_utils.tel.tel_lookup_tables import \
129    get_voice_mail_count_check_function
130from acts.test_utils.tel.tel_lookup_tables import get_voice_mail_check_number
131from acts.test_utils.tel.tel_lookup_tables import get_voice_mail_delete_digit
132from acts.test_utils.tel.tel_lookup_tables import \
133    network_preference_for_generation
134from acts.test_utils.tel.tel_lookup_tables import operator_name_from_plmn_id
135from acts.test_utils.tel.tel_lookup_tables import \
136    rat_families_for_network_preference
137from acts.test_utils.tel.tel_lookup_tables import rat_family_for_generation
138from acts.test_utils.tel.tel_lookup_tables import rat_family_from_rat
139from acts.test_utils.tel.tel_lookup_tables import rat_generation_from_rat
140from acts.test_utils.tel.tel_subscription_utils import \
141    get_default_data_sub_id
142from acts.test_utils.tel.tel_subscription_utils import \
143    get_outgoing_message_sub_id
144from acts.test_utils.tel.tel_subscription_utils import \
145    get_outgoing_voice_sub_id
146from acts.test_utils.tel.tel_subscription_utils import \
147    get_incoming_voice_sub_id
148from acts.test_utils.tel.tel_subscription_utils import \
149    get_incoming_message_sub_id
150from acts.test_utils.wifi import wifi_test_utils
151from acts.test_utils.wifi import wifi_constants
152from acts.utils import adb_shell_ping
153from acts.utils import load_config
154from acts.utils import create_dir
155from acts.utils import start_standing_subprocess
156from acts.utils import stop_standing_subprocess
157from acts.logger import epoch_to_log_line_timestamp
158from acts.logger import normalize_log_line_timestamp
159from acts.utils import get_current_epoch_time
160from acts.utils import exe_cmd
161
162WIFI_SSID_KEY = wifi_test_utils.WifiEnums.SSID_KEY
163WIFI_PWD_KEY = wifi_test_utils.WifiEnums.PWD_KEY
164WIFI_CONFIG_APBAND_2G = wifi_test_utils.WifiEnums.WIFI_CONFIG_APBAND_2G
165WIFI_CONFIG_APBAND_5G = wifi_test_utils.WifiEnums.WIFI_CONFIG_APBAND_5G
166WIFI_CONFIG_APBAND_AUTO = wifi_test_utils.WifiEnums.WIFI_CONFIG_APBAND_AUTO
167log = logging
168STORY_LINE = "+19523521350"
169
170
171class _CallSequenceException(Exception):
172    pass
173
174
175class TelTestUtilsError(Exception):
176    pass
177
178
179def abort_all_tests(log, msg):
180    log.error("Aborting all ongoing tests due to: %s.", msg)
181    abort_all(msg)
182
183
184def get_phone_number_by_adb(ad):
185    return phone_number_formatter(
186        ad.adb.shell("service call iphonesubinfo 13"))
187
188
189def get_iccid_by_adb(ad):
190    return ad.adb.shell("service call iphonesubinfo 11")
191
192
193def get_operator_by_adb(ad):
194    return ad.adb.getprop("gsm.sim.operator.alpha")
195
196
197def get_plmn_by_adb(ad):
198    return ad.adb.getprop("gsm.sim.operator.numeric")
199
200
201def get_sub_id_by_adb(ad):
202    return ad.adb.shell("service call iphonesubinfo 5")
203
204
205def setup_droid_properties_by_adb(log, ad, sim_filename=None):
206
207    # Check to see if droid already has this property
208    if hasattr(ad, 'cfg'):
209        return
210
211    sim_data = None
212    if sim_filename:
213        try:
214            sim_data = load_config(sim_filename)
215        except Exception:
216            log.warning("Failed to load %s!", sim_filename)
217
218    sub_id = get_sub_id_by_adb(ad)
219    iccid = get_iccid_by_adb(ad)
220    ad.log.info("iccid = %s", iccid)
221    if sim_data.get(iccid) and sim_data[iccid].get("phone_num"):
222        phone_number = phone_number_formatter(sim_data[iccid]["phone_num"])
223    else:
224        phone_number = get_phone_number_by_adb(ad)
225        if not phone_number and hasattr(ad, phone_number):
226            phone_number = ad.phone_number
227    if not phone_number:
228        ad.log.error("Failed to find valid phone number for %s", iccid)
229        abort_all_tests("Failed to find valid phone number for %s" % ad.serial)
230    sim_record = {
231        'phone_num': phone_number,
232        'iccid': get_iccid_by_adb(ad),
233        'sim_operator_name': get_operator_by_adb(ad),
234        'operator': operator_name_from_plmn_id(get_plmn_by_adb(ad))
235    }
236    device_props = {'subscription': {sub_id: sim_record}}
237    ad.log.info("subId %s SIM record: %s", sub_id, sim_record)
238    setattr(ad, 'cfg', device_props)
239
240
241def setup_droid_properties(log, ad, sim_filename=None):
242
243    # Check to see if droid already has this property
244    if hasattr(ad, 'cfg'):
245        return
246
247    if ad.skip_sl4a:
248        return setup_droid_properties_by_adb(
249            log, ad, sim_filename=sim_filename)
250
251    refresh_droid_config(log, ad)
252    device_props = {}
253    device_props['subscription'] = {}
254
255    sim_data = {}
256    if sim_filename:
257        try:
258            sim_data = load_config(sim_filename)
259        except Exception:
260            log.warning("Failed to load %s!", sim_filename)
261    if not ad.cfg["subscription"]:
262        abort_all_tests(ad.log, "No Valid SIMs found in device")
263    result = True
264    active_sub_id = get_outgoing_voice_sub_id(ad)
265    for sub_id, sub_info in ad.cfg["subscription"].items():
266        sub_info["operator"] = get_operator_name(log, ad, sub_id)
267        iccid = sub_info["iccid"]
268        if not iccid:
269            ad.log.warn("Unable to find ICC-ID for SIM")
270            continue
271        if sub_info.get("phone_num"):
272            if getattr(ad, "phone_number", None) and check_phone_number_match(
273                    sub_info["phone_num"], ad.phone_number):
274                sub_info["phone_num"] = ad.phone_number
275            elif iccid and iccid in sim_data and sim_data[iccid].get(
276                    "phone_num"):
277                if check_phone_number_match(sim_data[iccid]["phone_num"],
278                                            sub_info["phone_num"]):
279                    sub_info["phone_num"] = sim_data[iccid]["phone_num"]
280                else:
281                    ad.log.warning(
282                        "phone_num %s in sim card data file for iccid %s"
283                        "  do not match phone_num %s in droid subscription",
284                        sim_data[iccid]["phone_num"], iccid,
285                        sub_info["phone_num"])
286        elif iccid and iccid in sim_data and sim_data[iccid].get("phone_num"):
287            sub_info["phone_num"] = sim_data[iccid]["phone_num"]
288        elif sub_id == active_sub_id:
289            phone_number = get_phone_number_by_secret_code(
290                ad, sub_info["sim_operator_name"])
291            if phone_number:
292                sub_info["phone_num"] = phone_number
293            elif getattr(ad, "phone_num", None):
294                sub_info["phone_num"] = ad.phone_number
295        if (not sub_info.get("phone_num")) and sub_id == active_sub_id:
296            ad.log.info("sub_id %s sub_info = %s", sub_id, sub_info)
297            ad.log.error(
298                "Unable to retrieve phone number for sub %s with iccid"
299                " %s from device or testbed config or sim card file %s",
300                sub_id, iccid, sim_filename)
301            result = False
302        if not hasattr(
303                ad, 'roaming'
304        ) and sub_info["sim_plmn"] != sub_info["network_plmn"] and (
305                sub_info["sim_operator_name"].strip() not in
306                sub_info["network_operator_name"].strip()):
307            ad.log.info("roaming is not enabled, enable it")
308            setattr(ad, 'roaming', True)
309        ad.log.info("SubId %s info: %s", sub_id, sorted(sub_info.items()))
310    data_roaming = getattr(ad, 'roaming', False)
311    if get_cell_data_roaming_state_by_adb(ad) != data_roaming:
312        set_cell_data_roaming_state_by_adb(ad, data_roaming)
313    if not result:
314        abort_all_tests(ad.log, "Failed to find valid phone number")
315
316    ad.log.debug("cfg = %s", ad.cfg)
317
318
319def refresh_droid_config(log, ad):
320    """ Update Android Device cfg records for each sub_id.
321
322    Args:
323        log: log object
324        ad: android device object
325
326    Returns:
327        None
328    """
329    if hasattr(ad, 'cfg'):
330        cfg = ad.cfg.copy()
331    else:
332        cfg = {"subscription": {}}
333    droid = ad.droid
334    sub_info_list = droid.subscriptionGetAllSubInfoList()
335    for sub_info in sub_info_list:
336        sub_id = sub_info["subscriptionId"]
337        sim_slot = sub_info["simSlotIndex"]
338        if sim_slot != INVALID_SIM_SLOT_INDEX:
339            sim_record = {}
340            if sub_info.get("iccId"):
341                sim_record["iccid"] = sub_info["iccId"]
342            else:
343                sim_record[
344                    "iccid"] = droid.telephonyGetSimSerialNumberForSubscription(
345                        sub_id)
346            sim_record["sim_slot"] = sim_slot
347            try:
348                sim_record[
349                    "phone_type"] = droid.telephonyGetPhoneTypeForSubscription(
350                        sub_id)
351            except:
352                sim_record["phone_type"] = droid.telephonyGetPhoneType()
353            if sub_info.get("mcc"):
354                sim_record["mcc"] = sub_info["mcc"]
355            if sub_info.get("mnc"):
356                sim_record["mnc"] = sub_info["mnc"]
357            sim_record[
358                "sim_plmn"] = droid.telephonyGetSimOperatorForSubscription(
359                    sub_id)
360            sim_record["display_name"] = sub_info["displayName"]
361            sim_record[
362                "sim_operator_name"] = droid.telephonyGetSimOperatorNameForSubscription(
363                    sub_id)
364            sim_record[
365                "network_plmn"] = droid.telephonyGetNetworkOperatorForSubscription(
366                    sub_id)
367            sim_record[
368                "network_operator_name"] = droid.telephonyGetNetworkOperatorNameForSubscription(
369                    sub_id)
370            sim_record[
371                "network_type"] = droid.telephonyGetNetworkTypeForSubscription(
372                    sub_id)
373            sim_record[
374                "sim_country"] = droid.telephonyGetSimCountryIsoForSubscription(
375                    sub_id)
376            if sub_info.get("number"):
377                sim_record["phone_num"] = sub_info["number"]
378            else:
379                sim_record["phone_num"] = phone_number_formatter(
380                    droid.telephonyGetLine1NumberForSubscription(sub_id))
381            sim_record[
382                "phone_tag"] = droid.telephonyGetLine1AlphaTagForSubscription(
383                    sub_id)
384            if (not sim_record["phone_num"]
385                ) and cfg["subscription"].get(sub_id):
386                sim_record["phone_num"] = cfg["subscription"][sub_id][
387                    "phone_num"]
388            cfg['subscription'][sub_id] = sim_record
389            ad.log.debug("SubId %s SIM record: %s", sub_id, sim_record)
390    setattr(ad, 'cfg', cfg)
391
392
393def get_phone_number_by_secret_code(ad, operator):
394    if "T-Mobile" in operator:
395        ad.droid.telecomDialNumber("#686#")
396        ad.send_keycode("ENTER")
397        for _ in range(12):
398            output = ad.search_logcat("mobile number")
399            if output:
400                result = re.findall(r"mobile number is (\S+)",
401                                    output[-1]["log_message"])
402                ad.send_keycode("BACK")
403                return result[0]
404            else:
405                time.sleep(5)
406    return ""
407
408
409def get_slot_index_from_subid(log, ad, sub_id):
410    try:
411        info = ad.droid.subscriptionGetSubInfoForSubscriber(sub_id)
412        return info['simSlotIndex']
413    except KeyError:
414        return INVALID_SIM_SLOT_INDEX
415
416
417def get_num_active_sims(log, ad):
418    """ Get the number of active SIM cards by counting slots
419
420    Args:
421        ad: android_device object.
422
423    Returns:
424        result: The number of loaded (physical) SIM cards
425    """
426    # using a dictionary as a cheap way to prevent double counting
427    # in the situation where multiple subscriptions are on the same SIM.
428    # yes, this is a corner corner case.
429    valid_sims = {}
430    subInfo = ad.droid.subscriptionGetAllSubInfoList()
431    for info in subInfo:
432        ssidx = info['simSlotIndex']
433        if ssidx == INVALID_SIM_SLOT_INDEX:
434            continue
435        valid_sims[ssidx] = True
436    return len(valid_sims.keys())
437
438
439def toggle_airplane_mode_by_adb(log, ad, new_state=None):
440    """ Toggle the state of airplane mode.
441
442    Args:
443        log: log handler.
444        ad: android_device object.
445        new_state: Airplane mode state to set to.
446            If None, opposite of the current state.
447        strict_checking: Whether to turn on strict checking that checks all features.
448
449    Returns:
450        result: True if operation succeed. False if error happens.
451    """
452    cur_state = bool(int(ad.adb.shell("settings get global airplane_mode_on")))
453    if new_state == cur_state:
454        ad.log.info("Airplane mode already in %s", new_state)
455        return True
456    elif new_state is None:
457        new_state = not cur_state
458
459    ad.adb.shell("settings put global airplane_mode_on %s" % int(new_state))
460    ad.adb.shell("am broadcast -a android.intent.action.AIRPLANE_MODE")
461    return True
462
463
464def toggle_airplane_mode(log, ad, new_state=None, strict_checking=True):
465    """ Toggle the state of airplane mode.
466
467    Args:
468        log: log handler.
469        ad: android_device object.
470        new_state: Airplane mode state to set to.
471            If None, opposite of the current state.
472        strict_checking: Whether to turn on strict checking that checks all features.
473
474    Returns:
475        result: True if operation succeed. False if error happens.
476    """
477    if ad.skip_sl4a:
478        return toggle_airplane_mode_by_adb(log, ad, new_state)
479    else:
480        return toggle_airplane_mode_msim(
481            log, ad, new_state, strict_checking=strict_checking)
482
483
484def get_telephony_signal_strength(ad):
485    signal_strength = ad.droid.telephonyGetSignalStrength()
486    #{'evdoEcio': -1, 'asuLevel': 28, 'lteSignalStrength': 14, 'gsmLevel': 0,
487    # 'cdmaAsuLevel': 99, 'evdoDbm': -120, 'gsmDbm': -1, 'cdmaEcio': -160,
488    # 'level': 2, 'lteLevel': 2, 'cdmaDbm': -120, 'dbm': -112, 'cdmaLevel': 0,
489    # 'lteAsuLevel': 28, 'gsmAsuLevel': 99, 'gsmBitErrorRate': 0,
490    # 'lteDbm': -112, 'gsmSignalStrength': 99}
491    if not signal_strength: signal_strength = {}
492    out = ad.adb.shell("dumpsys telephony.registry | grep -i signalstrength")
493    signals = re.findall(r"(-*\d+)", out)
494    for i, val in enumerate(
495        ("gsmSignalStrength", "gsmBitErrorRate", "cdmaDbm", "cdmaEcio",
496         "evdoDbm", "evdoEcio", "evdoSnr", "lteSignalStrength", "lteRsrp",
497         "lteRsrq", "lteRssnr", "lteCqi", "lteRsrpBoost")):
498        signal_strength[val] = signal_strength.get(val, int(signals[i]))
499    ad.log.info("Telephony Signal strength = %s", signal_strength)
500    return signal_strength
501
502
503def get_wifi_signal_strength(ad):
504    signal_strength = ad.droid.wifiGetConnectionInfo()['rssi']
505    ad.log.info("WiFi Signal Strength is %s" % signal_strength)
506    return signal_strength
507
508
509def is_expected_event(event_to_check, events_list):
510    """ check whether event is present in the event list
511
512    Args:
513        event_to_check: event to be checked.
514        events_list: list of events
515    Returns:
516        result: True if event present in the list. False if not.
517    """
518    for event in events_list:
519        if event in event_to_check['name']:
520            return True
521    return False
522
523
524def is_sim_ready(log, ad, sim_slot_id=None):
525    """ check whether SIM is ready.
526
527    Args:
528        ad: android_device object.
529        sim_slot_id: check the SIM status for sim_slot_id
530            This is optional. If this is None, check default SIM.
531
532    Returns:
533        result: True if all SIMs are ready. False if not.
534    """
535    if sim_slot_id is None:
536        status = ad.droid.telephonyGetSimState()
537    else:
538        status = ad.droid.telephonyGetSimStateForSlotId(sim_slot_id)
539    if status != SIM_STATE_READY:
540        log.info("Sim not ready")
541        return False
542    return True
543
544
545def is_sim_ready_by_adb(log, ad):
546    state = ad.adb.getprop("gsm.sim.state")
547    return state == SIM_STATE_READY or state == SIM_STATE_LOADED
548
549
550def wait_for_sim_ready_by_adb(log, ad, wait_time=90):
551    return _wait_for_droid_in_state(log, ad, wait_time, is_sim_ready_by_adb)
552
553
554def get_service_state_by_adb(log, ad):
555    output = ad.adb.shell("dumpsys telephony.registry | grep mServiceState")
556    if "mVoiceRegState" in output:
557        result = re.search(r"mVoiceRegState=(\S+)\((\S+)\)", output)
558        if result:
559            ad.log.info("mVoiceRegState is %s %s", result.group(1),
560                        result.group(2))
561            return result.group(2)
562    else:
563        result = re.search(r"mServiceState=(\S+)", output)
564        if result:
565            ad.log.info("mServiceState=%s %s", result.group(1),
566                        SERVICE_STATE_MAPPING[result.group(1)])
567            return SERVICE_STATE_MAPPING[result.group(1)]
568
569
570def _is_expecting_event(event_recv_list):
571    """ check for more event is expected in event list
572
573    Args:
574        event_recv_list: list of events
575    Returns:
576        result: True if more events are expected. False if not.
577    """
578    for state in event_recv_list:
579        if state is False:
580            return True
581    return False
582
583
584def _set_event_list(event_recv_list, sub_id_list, sub_id, value):
585    """ set received event in expected event list
586
587    Args:
588        event_recv_list: list of received events
589        sub_id_list: subscription ID list
590        sub_id: subscription id of current event
591        value: True or False
592    Returns:
593        None.
594    """
595    for i in range(len(sub_id_list)):
596        if sub_id_list[i] == sub_id:
597            event_recv_list[i] = value
598
599
600def _wait_for_bluetooth_in_state(log, ad, state, max_wait):
601    # FIXME: These event names should be defined in a common location
602    _BLUETOOTH_STATE_ON_EVENT = 'BluetoothStateChangedOn'
603    _BLUETOOTH_STATE_OFF_EVENT = 'BluetoothStateChangedOff'
604    ad.ed.clear_events(_BLUETOOTH_STATE_ON_EVENT)
605    ad.ed.clear_events(_BLUETOOTH_STATE_OFF_EVENT)
606
607    ad.droid.bluetoothStartListeningForAdapterStateChange()
608    try:
609        bt_state = ad.droid.bluetoothCheckState()
610        if bt_state == state:
611            return True
612        if max_wait <= 0:
613            ad.log.error("Time out: bluetooth state still %s, expecting %s",
614                         bt_state, state)
615            return False
616
617        event = {
618            False: _BLUETOOTH_STATE_OFF_EVENT,
619            True: _BLUETOOTH_STATE_ON_EVENT
620        }[state]
621        ad.ed.pop_event(event, max_wait)
622        return True
623    except Empty:
624        ad.log.error("Time out: bluetooth state still in %s, expecting %s",
625                     bt_state, state)
626        return False
627    finally:
628        ad.droid.bluetoothStopListeningForAdapterStateChange()
629
630
631# TODO: replace this with an event-based function
632def _wait_for_wifi_in_state(log, ad, state, max_wait):
633    return _wait_for_droid_in_state(log, ad, max_wait,
634        lambda log, ad, state: \
635                (True if ad.droid.wifiCheckState() == state else False),
636                state)
637
638
639def toggle_airplane_mode_msim(log, ad, new_state=None, strict_checking=True):
640    """ Toggle the state of airplane mode.
641
642    Args:
643        log: log handler.
644        ad: android_device object.
645        new_state: Airplane mode state to set to.
646            If None, opposite of the current state.
647        strict_checking: Whether to turn on strict checking that checks all features.
648
649    Returns:
650        result: True if operation succeed. False if error happens.
651    """
652
653    ad.ed.clear_all_events()
654    sub_id_list = []
655
656    active_sub_info = ad.droid.subscriptionGetAllSubInfoList()
657    for info in active_sub_info:
658        sub_id_list.append(info['subscriptionId'])
659
660    cur_state = ad.droid.connectivityCheckAirplaneMode()
661    if cur_state == new_state:
662        ad.log.info("Airplane mode already in %s", new_state)
663        return True
664    elif new_state is None:
665        ad.log.info("APM Current State %s New state %s", cur_state, new_state)
666
667    if new_state is None:
668        new_state = not cur_state
669
670    service_state_list = []
671    if new_state:
672        service_state_list.append(SERVICE_STATE_POWER_OFF)
673        ad.log.info("Turn on airplane mode")
674
675    else:
676        # If either one of these 3 events show up, it should be OK.
677        # Normal SIM, phone in service
678        service_state_list.append(SERVICE_STATE_IN_SERVICE)
679        # NO SIM, or Dead SIM, or no Roaming coverage.
680        service_state_list.append(SERVICE_STATE_OUT_OF_SERVICE)
681        service_state_list.append(SERVICE_STATE_EMERGENCY_ONLY)
682        ad.log.info("Turn off airplane mode")
683
684    for sub_id in sub_id_list:
685        ad.droid.telephonyStartTrackingServiceStateChangeForSubscription(
686            sub_id)
687
688    timeout_time = time.time() + MAX_WAIT_TIME_AIRPLANEMODE_EVENT
689    ad.droid.connectivityToggleAirplaneMode(new_state)
690
691    event = None
692
693    try:
694        try:
695            event = ad.ed.wait_for_event(
696                EventServiceStateChanged,
697                is_event_match_for_list,
698                timeout=MAX_WAIT_TIME_AIRPLANEMODE_EVENT,
699                field=ServiceStateContainer.SERVICE_STATE,
700                value_list=service_state_list)
701        except Empty:
702            pass
703        if event is None:
704            ad.log.error("Did not get expected service state %s",
705                         service_state_list)
706            return False
707        else:
708            ad.log.info("Received event: %s", event)
709    finally:
710        for sub_id in sub_id_list:
711            ad.droid.telephonyStopTrackingServiceStateChangeForSubscription(
712                sub_id)
713
714    # APM on (new_state=True) will turn off bluetooth but may not turn it on
715    try:
716        if new_state and not _wait_for_bluetooth_in_state(
717                log, ad, False, timeout_time - time.time()):
718            ad.log.error(
719                "Failed waiting for bluetooth during airplane mode toggle")
720            if strict_checking: return False
721    except Exception as e:
722        ad.log.error("Failed to check bluetooth state due to %s", e)
723        if strict_checking:
724            raise
725
726    # APM on (new_state=True) will turn off wifi but may not turn it on
727    if new_state and not _wait_for_wifi_in_state(log, ad, False,
728                                                 timeout_time - time.time()):
729        ad.log.error("Failed waiting for wifi during airplane mode toggle on")
730        if strict_checking: return False
731
732    if ad.droid.connectivityCheckAirplaneMode() != new_state:
733        ad.log.error("Set airplane mode to %s failed", new_state)
734        return False
735    return True
736
737
738def wait_and_answer_call(log,
739                         ad,
740                         incoming_number=None,
741                         incall_ui_display=INCALL_UI_DISPLAY_FOREGROUND,
742                         caller=None):
743    """Wait for an incoming call on default voice subscription and
744       accepts the call.
745
746    Args:
747        ad: android device object.
748        incoming_number: Expected incoming number.
749            Optional. Default is None
750        incall_ui_display: after answer the call, bring in-call UI to foreground or
751            background. Optional, default value is INCALL_UI_DISPLAY_FOREGROUND.
752            if = INCALL_UI_DISPLAY_FOREGROUND, bring in-call UI to foreground.
753            if = INCALL_UI_DISPLAY_BACKGROUND, bring in-call UI to background.
754            else, do nothing.
755
756    Returns:
757        True: if incoming call is received and answered successfully.
758        False: for errors
759        """
760    return wait_and_answer_call_for_subscription(
761        log,
762        ad,
763        get_incoming_voice_sub_id(ad),
764        incoming_number,
765        incall_ui_display=incall_ui_display,
766        caller=caller)
767
768
769def wait_for_ringing_event(log, ad, wait_time):
770    log.warning("***DEPRECATED*** wait_for_ringing_event()")
771    return _wait_for_ringing_event(log, ad, wait_time)
772
773
774def _wait_for_ringing_event(log, ad, wait_time):
775    """Wait for ringing event.
776
777    Args:
778        log: log object.
779        ad: android device object.
780        wait_time: max time to wait for ringing event.
781
782    Returns:
783        event_ringing if received ringing event.
784        otherwise return None.
785    """
786    event_ringing = None
787
788    try:
789        event_ringing = ad.ed.wait_for_event(
790            EventCallStateChanged,
791            is_event_match,
792            timeout=wait_time,
793            field=CallStateContainer.CALL_STATE,
794            value=TELEPHONY_STATE_RINGING)
795        ad.log.info("Receive ringing event")
796    except Empty:
797        ad.log.info("No Ringing Event")
798    finally:
799        return event_ringing
800
801
802def wait_for_ringing_call(log, ad, incoming_number=None):
803    """Wait for an incoming call on default voice subscription and
804       accepts the call.
805
806    Args:
807        log: log object.
808        ad: android device object.
809        incoming_number: Expected incoming number.
810            Optional. Default is None
811
812    Returns:
813        True: if incoming call is received and answered successfully.
814        False: for errors
815        """
816    return wait_for_ringing_call_for_subscription(
817        log, ad, get_incoming_voice_sub_id(ad), incoming_number)
818
819
820def wait_for_ringing_call_for_subscription(
821        log,
822        ad,
823        sub_id,
824        incoming_number=None,
825        caller=None,
826        event_tracking_started=False,
827        timeout=MAX_WAIT_TIME_CALLEE_RINGING,
828        retries=1):
829    """Wait for an incoming call on specified subscription.
830
831    Args:
832        log: log object.
833        ad: android device object.
834        sub_id: subscription ID
835        incoming_number: Expected incoming number. Default is None
836        event_tracking_started: True if event tracking already state outside
837        timeout: time to wait for ring
838
839    Returns:
840        True: if incoming call is received and answered successfully.
841        False: for errors
842    """
843    if not event_tracking_started:
844        ad.ed.clear_events(EventCallStateChanged)
845        ad.droid.telephonyStartTrackingCallStateForSubscription(sub_id)
846    event_ringing = None
847    for i in range(retries):
848        event_ringing = _wait_for_ringing_event(log, ad, timeout)
849        if event_ringing:
850            ad.log.info("callee received ring event")
851            break
852        if ad.droid.telephonyGetCallStateForSubscription(
853                sub_id
854        ) == TELEPHONY_STATE_RINGING or ad.droid.telecomIsRinging():
855            ad.log.info("callee in ringing state")
856            break
857        if i == retries - 1:
858            ad.log.info(
859                "callee didn't receive ring event or got into ringing state")
860            return False
861    if not event_tracking_started:
862        ad.droid.telephonyStopTrackingCallStateChangeForSubscription(sub_id)
863    if caller and not caller.droid.telecomIsInCall():
864        caller.log.error("Caller not in call state")
865        raise _CallSequenceException("Caller not in call state")
866    if not incoming_number:
867        return True
868
869    if event_ringing and not check_phone_number_match(
870            event_ringing['data'][CallStateContainer.INCOMING_NUMBER],
871            incoming_number):
872        ad.log.error(
873            "Incoming Number not match. Expected number:%s, actual number:%s",
874            incoming_number,
875            event_ringing['data'][CallStateContainer.INCOMING_NUMBER])
876        return False
877    return True
878
879
880def wait_for_call_offhook_event(
881        log,
882        ad,
883        sub_id,
884        event_tracking_started=False,
885        timeout=MAX_WAIT_TIME_ACCEPT_CALL_TO_OFFHOOK_EVENT):
886    """Wait for an incoming call on specified subscription.
887
888    Args:
889        log: log object.
890        ad: android device object.
891        event_tracking_started: True if event tracking already state outside
892        timeout: time to wait for event
893
894    Returns:
895        True: if call offhook event is received.
896        False: if call offhook event is not received.
897    """
898    if not event_tracking_started:
899        ad.ed.clear_events(EventCallStateChanged)
900        ad.droid.telephonyStartTrackingCallStateForSubscription(sub_id)
901    try:
902        ad.ed.wait_for_event(
903            EventCallStateChanged,
904            is_event_match,
905            timeout=timeout,
906            field=CallStateContainer.CALL_STATE,
907            value=TELEPHONY_STATE_OFFHOOK)
908    except Empty:
909        ad.log.info("No event for call state change to OFFHOOK")
910        return False
911    finally:
912        if not event_tracking_started:
913            ad.droid.telephonyStopTrackingCallStateChangeForSubscription(
914                sub_id)
915    return True
916
917
918def wait_and_answer_call_for_subscription(
919        log,
920        ad,
921        sub_id,
922        incoming_number=None,
923        incall_ui_display=INCALL_UI_DISPLAY_FOREGROUND,
924        timeout=MAX_WAIT_TIME_CALLEE_RINGING,
925        caller=None):
926    """Wait for an incoming call on specified subscription and
927       accepts the call.
928
929    Args:
930        log: log object.
931        ad: android device object.
932        sub_id: subscription ID
933        incoming_number: Expected incoming number.
934            Optional. Default is None
935        incall_ui_display: after answer the call, bring in-call UI to foreground or
936            background. Optional, default value is INCALL_UI_DISPLAY_FOREGROUND.
937            if = INCALL_UI_DISPLAY_FOREGROUND, bring in-call UI to foreground.
938            if = INCALL_UI_DISPLAY_BACKGROUND, bring in-call UI to background.
939            else, do nothing.
940
941    Returns:
942        True: if incoming call is received and answered successfully.
943        False: for errors
944    """
945    ad.ed.clear_events(EventCallStateChanged)
946    ad.droid.telephonyStartTrackingCallStateForSubscription(sub_id)
947    try:
948        if not _wait_for_droid_in_state(
949                log,
950                ad,
951                timeout,
952                wait_for_ringing_call_for_subscription,
953                sub_id,
954                incoming_number=None,
955                caller=caller,
956                event_tracking_started=True,
957                timeout=WAIT_TIME_BETWEEN_STATE_CHECK):
958            ad.log.info("Could not answer a call: phone never rang.")
959            return False
960        time.sleep(WAIT_TIME_BETWEEN_STATE_CHECK)
961        ad.log.info("Accept the ring call")
962        ad.droid.telecomAcceptRingingCall()
963
964        if ad.droid.telecomIsInCall() or wait_for_call_offhook_event(
965                log, ad, sub_id, event_tracking_started=True,
966                timeout=timeout) or ad.droid.telecomIsInCall():
967            ad.log.info("Call answered successfully.")
968            return True
969        else:
970            ad.log.error("Could not answer the call.")
971            return False
972    except Exception as e:
973        log.error(e)
974        return False
975    finally:
976        ad.droid.telephonyStopTrackingCallStateChangeForSubscription(sub_id)
977        if incall_ui_display == INCALL_UI_DISPLAY_FOREGROUND:
978            ad.droid.telecomShowInCallScreen()
979        elif incall_ui_display == INCALL_UI_DISPLAY_BACKGROUND:
980            ad.droid.showHomeScreen()
981
982
983def wait_and_reject_call(log,
984                         ad,
985                         incoming_number=None,
986                         delay_reject=WAIT_TIME_REJECT_CALL,
987                         reject=True):
988    """Wait for an incoming call on default voice subscription and
989       reject the call.
990
991    Args:
992        log: log object.
993        ad: android device object.
994        incoming_number: Expected incoming number.
995            Optional. Default is None
996        delay_reject: time to wait before rejecting the call
997            Optional. Default is WAIT_TIME_REJECT_CALL
998
999    Returns:
1000        True: if incoming call is received and reject successfully.
1001        False: for errors
1002    """
1003    return wait_and_reject_call_for_subscription(log, ad,
1004                                                 get_incoming_voice_sub_id(ad),
1005                                                 incoming_number, delay_reject,
1006                                                 reject)
1007
1008
1009def wait_and_reject_call_for_subscription(log,
1010                                          ad,
1011                                          sub_id,
1012                                          incoming_number=None,
1013                                          delay_reject=WAIT_TIME_REJECT_CALL,
1014                                          reject=True):
1015    """Wait for an incoming call on specific subscription and
1016       reject the call.
1017
1018    Args:
1019        log: log object.
1020        ad: android device object.
1021        sub_id: subscription ID
1022        incoming_number: Expected incoming number.
1023            Optional. Default is None
1024        delay_reject: time to wait before rejecting the call
1025            Optional. Default is WAIT_TIME_REJECT_CALL
1026
1027    Returns:
1028        True: if incoming call is received and reject successfully.
1029        False: for errors
1030    """
1031
1032    if not wait_for_ringing_call_for_subscription(log, ad, sub_id,
1033                                                  incoming_number):
1034        ad.log.error("Could not reject a call: phone never rang.")
1035        return False
1036
1037    ad.ed.clear_events(EventCallStateChanged)
1038    ad.droid.telephonyStartTrackingCallStateForSubscription(sub_id)
1039    if reject is True:
1040        # Delay between ringing and reject.
1041        time.sleep(delay_reject)
1042        is_find = False
1043        # Loop the call list and find the matched one to disconnect.
1044        for call in ad.droid.telecomCallGetCallIds():
1045            if check_phone_number_match(
1046                    get_number_from_tel_uri(get_call_uri(ad, call)),
1047                    incoming_number):
1048                ad.droid.telecomCallDisconnect(call)
1049                ad.log.info("Callee reject the call")
1050                is_find = True
1051        if is_find is False:
1052            ad.log.error("Callee did not find matching call to reject.")
1053            return False
1054    else:
1055        # don't reject on callee. Just ignore the incoming call.
1056        ad.log.info("Callee received incoming call. Ignore it.")
1057    try:
1058        ad.ed.wait_for_event(
1059            EventCallStateChanged,
1060            is_event_match_for_list,
1061            timeout=MAX_WAIT_TIME_CALL_IDLE_EVENT,
1062            field=CallStateContainer.CALL_STATE,
1063            value_list=[TELEPHONY_STATE_IDLE, TELEPHONY_STATE_OFFHOOK])
1064    except Empty:
1065        ad.log.error("No onCallStateChangedIdle event received.")
1066        return False
1067    finally:
1068        ad.droid.telephonyStopTrackingCallStateChangeForSubscription(sub_id)
1069    return True
1070
1071
1072def hangup_call(log, ad):
1073    """Hang up ongoing active call.
1074
1075    Args:
1076        log: log object.
1077        ad: android device object.
1078
1079    Returns:
1080        True: if all calls are cleared
1081        False: for errors
1082    """
1083    # short circuit in case no calls are active
1084    if not ad.droid.telecomIsInCall():
1085        return True
1086    ad.ed.clear_events(EventCallStateChanged)
1087    ad.droid.telephonyStartTrackingCallState()
1088    ad.log.info("Hangup call.")
1089    ad.droid.telecomEndCall()
1090
1091    try:
1092        ad.ed.wait_for_event(
1093            EventCallStateChanged,
1094            is_event_match,
1095            timeout=MAX_WAIT_TIME_CALL_IDLE_EVENT,
1096            field=CallStateContainer.CALL_STATE,
1097            value=TELEPHONY_STATE_IDLE)
1098    except Empty:
1099        if ad.droid.telecomIsInCall():
1100            log.error("Hangup call failed.")
1101            return False
1102    finally:
1103        ad.droid.telephonyStopTrackingCallStateChange()
1104    return not ad.droid.telecomIsInCall()
1105
1106
1107def disconnect_call_by_id(log, ad, call_id):
1108    """Disconnect call by call id.
1109    """
1110    ad.droid.telecomCallDisconnect(call_id)
1111    return True
1112
1113
1114def _phone_number_remove_prefix(number):
1115    """Remove the country code and other prefix from the input phone number.
1116    Currently only handle phone number with the following formats:
1117        (US phone number format)
1118        +1abcxxxyyyy
1119        1abcxxxyyyy
1120        abcxxxyyyy
1121        abc xxx yyyy
1122        abc.xxx.yyyy
1123        abc-xxx-yyyy
1124        (EEUK phone number format)
1125        +44abcxxxyyyy
1126        0abcxxxyyyy
1127
1128    Args:
1129        number: input phone number
1130
1131    Returns:
1132        Phone number without country code or prefix
1133    """
1134    if number is None:
1135        return None, None
1136    for country_code in COUNTRY_CODE_LIST:
1137        if number.startswith(country_code):
1138            return number[len(country_code):], country_code
1139    if number[0] == "1" or number[0] == "0":
1140        return number[1:], None
1141    return number, None
1142
1143
1144def check_phone_number_match(number1, number2):
1145    """Check whether two input phone numbers match or not.
1146
1147    Compare the two input phone numbers.
1148    If they match, return True; otherwise, return False.
1149    Currently only handle phone number with the following formats:
1150        (US phone number format)
1151        +1abcxxxyyyy
1152        1abcxxxyyyy
1153        abcxxxyyyy
1154        abc xxx yyyy
1155        abc.xxx.yyyy
1156        abc-xxx-yyyy
1157        (EEUK phone number format)
1158        +44abcxxxyyyy
1159        0abcxxxyyyy
1160
1161        There are some scenarios we can not verify, one example is:
1162            number1 = +15555555555, number2 = 5555555555
1163            (number2 have no country code)
1164
1165    Args:
1166        number1: 1st phone number to be compared.
1167        number2: 2nd phone number to be compared.
1168
1169    Returns:
1170        True if two phone numbers match. Otherwise False.
1171    """
1172    number1 = phone_number_formatter(number1)
1173    number2 = phone_number_formatter(number2)
1174    # Handle extra country code attachment when matching phone number
1175    if number1[-7:] in number2 or number2[-7:] in number1:
1176        return True
1177    else:
1178        logging.info("phone number1 %s and number2 %s does not match" %
1179                     (number1, number2))
1180        return False
1181
1182
1183def initiate_call(log,
1184                  ad,
1185                  callee_number,
1186                  emergency=False,
1187                  timeout=MAX_WAIT_TIME_CALL_INITIATION,
1188                  checking_interval=5,
1189                  wait_time_betwn_call_initcheck=0):
1190    """Make phone call from caller to callee.
1191
1192    Args:
1193        ad_caller: Caller android device object.
1194        callee_number: Callee phone number.
1195        emergency : specify the call is emergency.
1196            Optional. Default value is False.
1197
1198    Returns:
1199        result: if phone call is placed successfully.
1200    """
1201    ad.ed.clear_events(EventCallStateChanged)
1202    sub_id = get_outgoing_voice_sub_id(ad)
1203    ad.droid.telephonyStartTrackingCallStateForSubscription(sub_id)
1204
1205    try:
1206        # Make a Call
1207        ad.log.info("Make a phone call to %s", callee_number)
1208        if emergency:
1209            ad.droid.telecomCallEmergencyNumber(callee_number)
1210        else:
1211            ad.droid.telecomCallNumber(callee_number)
1212
1213        # Sleep time for stress test b/64915613
1214        time.sleep(wait_time_betwn_call_initcheck)
1215
1216        # Verify OFFHOOK event
1217        checking_retries = int(timeout / checking_interval)
1218        for i in range(checking_retries):
1219            if (ad.droid.telecomIsInCall() and
1220                    ad.droid.telephonyGetCallState() == TELEPHONY_STATE_OFFHOOK
1221                    and ad.droid.telecomGetCallState() ==
1222                    TELEPHONY_STATE_OFFHOOK) or wait_for_call_offhook_event(
1223                        log, ad, sub_id, True, checking_interval):
1224                return True
1225        ad.log.info(
1226            "Make call to %s fail. telecomIsInCall:%s, Telecom State:%s,"
1227            " Telephony State:%s", callee_number, ad.droid.telecomIsInCall(),
1228            ad.droid.telephonyGetCallState(), ad.droid.telecomGetCallState())
1229        reasons = ad.search_logcat(
1230            "qcril_qmi_voice_map_qmi_to_ril_last_call_failure_cause")
1231        if reasons:
1232            ad.log.info(reasons[-1]["log_message"])
1233        return False
1234    finally:
1235        ad.droid.telephonyStopTrackingCallStateChangeForSubscription(sub_id)
1236
1237
1238def dial_phone_number(ad, callee_number):
1239    for number in str(callee_number):
1240        if number == "#":
1241            ad.send_keycode("POUND")
1242        elif number == "*":
1243            ad.send_keycode("STAR")
1244        elif number in ["1", "2", "3", "4", "5", "6", "7", "8", "9", "0"]:
1245            ad.send_keycode("%s" % number)
1246
1247
1248def get_call_state_by_adb(ad):
1249    return ad.adb.shell("dumpsys telephony.registry | grep mCallState")
1250
1251
1252def check_call_state_connected_by_adb(ad):
1253    return "2" in get_call_state_by_adb(ad)
1254
1255
1256def check_call_state_idle_by_adb(ad):
1257    return "0" in get_call_state_by_adb(ad)
1258
1259
1260def check_call_state_ring_by_adb(ad):
1261    return "1" in get_call_state_by_adb(ad)
1262
1263
1264def get_incoming_call_number_by_adb(ad):
1265    output = ad.adb.shell(
1266        "dumpsys telephony.registry | grep mCallIncomingNumber")
1267    return re.search(r"mCallIncomingNumber=(.*)", output).group(1)
1268
1269
1270def emergency_dialer_call_by_keyevent(ad, callee_number):
1271    for i in range(3):
1272        if "EmergencyDialer" in ad.get_my_current_focus_window():
1273            ad.log.info("EmergencyDialer is the current focus window")
1274            break
1275        elif i <= 2:
1276            ad.adb.shell("am start -a com.android.phone.EmergencyDialer.DIAL")
1277            time.sleep(1)
1278        else:
1279            ad.log.error("Unable to bring up EmergencyDialer")
1280            return False
1281    ad.log.info("Make a phone call to %s", callee_number)
1282    dial_phone_number(ad, callee_number)
1283    ad.send_keycode("CALL")
1284
1285
1286def initiate_emergency_dialer_call_by_adb(
1287        log,
1288        ad,
1289        callee_number,
1290        timeout=MAX_WAIT_TIME_CALL_INITIATION,
1291        checking_interval=5):
1292    """Make emergency call by EmergencyDialer.
1293
1294    Args:
1295        ad: Caller android device object.
1296        callee_number: Callee phone number.
1297        emergency : specify the call is emergency.
1298        Optional. Default value is False.
1299
1300    Returns:
1301        result: if phone call is placed successfully.
1302    """
1303    try:
1304        # Make a Call
1305        ad.wakeup_screen()
1306        ad.send_keycode("MENU")
1307        ad.log.info("Call %s", callee_number)
1308        ad.adb.shell("am start -a com.android.phone.EmergencyDialer.DIAL")
1309        ad.adb.shell(
1310            "am start -a android.intent.action.CALL_EMERGENCY -d tel:%s" %
1311            callee_number)
1312        ad.log.info("Check call state")
1313        # Verify Call State
1314        elapsed_time = 0
1315        while elapsed_time < timeout:
1316            time.sleep(checking_interval)
1317            elapsed_time += checking_interval
1318            if check_call_state_connected_by_adb(ad):
1319                ad.log.info("Call to %s is connected", callee_number)
1320                return True
1321            if check_call_state_idle_by_adb(ad):
1322                ad.log.info("Call to %s failed", callee_number)
1323                return False
1324        ad.log.info("Make call to %s failed", callee_number)
1325        return False
1326    except Exception as e:
1327        ad.log.error("initiate emergency call failed with error %s", e)
1328
1329
1330def hangup_call_by_adb(ad):
1331    """Make emergency call by EmergencyDialer.
1332
1333    Args:
1334        ad: Caller android device object.
1335        callee_number: Callee phone number.
1336    """
1337    ad.log.info("End call by adb")
1338    ad.send_keycode("ENDCALL")
1339
1340
1341def dumpsys_telecom_call_info(ad):
1342    """ Get call information by dumpsys telecom. """
1343    output = ad.adb.shell("dumpsys telecom")
1344    calls = re.findall("Call TC@\d+: {(.*?)}", output, re.DOTALL)
1345    calls_info = []
1346    for call in calls:
1347        call_info = {}
1348        for attr in ("startTime", "endTime", "direction", "isInterrupted",
1349                     "callTechnologies", "callTerminationsReason",
1350                     "connectionService", "isVedeoCall", "callProperties"):
1351            match = re.search(r"%s: (.*)" % attr, call)
1352            if match:
1353                call_info[attr] = match.group(1)
1354        call_info["inCallServices"] = re.findall(r"name: (.*)", call)
1355        calls_info.append(call_info)
1356    ad.log.debug("calls_info = %s", calls_info)
1357    return calls_info
1358
1359
1360def call_reject(log, ad_caller, ad_callee, reject=True):
1361    """Caller call Callee, then reject on callee.
1362
1363
1364    """
1365    subid_caller = ad_caller.droid.subscriptionGetDefaultVoiceSubId()
1366    subid_callee = ad_callee.incoming_voice_sub_id
1367    ad_caller.log.info("Sub-ID Caller %s, Sub-ID Callee %s", subid_caller,
1368                       subid_callee)
1369    return call_reject_for_subscription(log, ad_caller, ad_callee,
1370                                        subid_caller, subid_callee, reject)
1371
1372
1373def call_reject_for_subscription(log,
1374                                 ad_caller,
1375                                 ad_callee,
1376                                 subid_caller,
1377                                 subid_callee,
1378                                 reject=True):
1379    """
1380    """
1381
1382    caller_number = ad_caller.cfg['subscription'][subid_caller]['phone_num']
1383    callee_number = ad_callee.cfg['subscription'][subid_callee]['phone_num']
1384
1385    ad_caller.log.info("Call from %s to %s", caller_number, callee_number)
1386    try:
1387        if not initiate_call(log, ad_caller, callee_number):
1388            raise _CallSequenceException("Initiate call failed.")
1389
1390        if not wait_and_reject_call_for_subscription(
1391                log, ad_callee, subid_callee, caller_number,
1392                WAIT_TIME_REJECT_CALL, reject):
1393            raise _CallSequenceException("Reject call fail.")
1394        # Check if incoming call is cleared on callee or not.
1395        if ad_callee.droid.telephonyGetCallStateForSubscription(
1396                subid_callee) == TELEPHONY_STATE_RINGING:
1397            raise _CallSequenceException("Incoming call is not cleared.")
1398        # Hangup on caller
1399        hangup_call(log, ad_caller)
1400    except _CallSequenceException as e:
1401        log.error(e)
1402        return False
1403    return True
1404
1405
1406def call_reject_leave_message(log,
1407                              ad_caller,
1408                              ad_callee,
1409                              verify_caller_func=None,
1410                              wait_time_in_call=WAIT_TIME_LEAVE_VOICE_MAIL):
1411    """On default voice subscription, Call from caller to callee,
1412    reject on callee, caller leave a voice mail.
1413
1414    1. Caller call Callee.
1415    2. Callee reject incoming call.
1416    3. Caller leave a voice mail.
1417    4. Verify callee received the voice mail notification.
1418
1419    Args:
1420        ad_caller: caller android device object.
1421        ad_callee: callee android device object.
1422        verify_caller_func: function to verify caller is in correct state while in-call.
1423            This is optional, default is None.
1424        wait_time_in_call: time to wait when leaving a voice mail.
1425            This is optional, default is WAIT_TIME_LEAVE_VOICE_MAIL
1426
1427    Returns:
1428        True: if voice message is received on callee successfully.
1429        False: for errors
1430    """
1431    subid_caller = get_outgoing_voice_sub_id(ad_caller)
1432    subid_callee = get_incoming_voice_sub_id(ad_callee)
1433    return call_reject_leave_message_for_subscription(
1434        log, ad_caller, ad_callee, subid_caller, subid_callee,
1435        verify_caller_func, wait_time_in_call)
1436
1437
1438def call_reject_leave_message_for_subscription(
1439        log,
1440        ad_caller,
1441        ad_callee,
1442        subid_caller,
1443        subid_callee,
1444        verify_caller_func=None,
1445        wait_time_in_call=WAIT_TIME_LEAVE_VOICE_MAIL):
1446    """On specific voice subscription, Call from caller to callee,
1447    reject on callee, caller leave a voice mail.
1448
1449    1. Caller call Callee.
1450    2. Callee reject incoming call.
1451    3. Caller leave a voice mail.
1452    4. Verify callee received the voice mail notification.
1453
1454    Args:
1455        ad_caller: caller android device object.
1456        ad_callee: callee android device object.
1457        subid_caller: caller's subscription id.
1458        subid_callee: callee's subscription id.
1459        verify_caller_func: function to verify caller is in correct state while in-call.
1460            This is optional, default is None.
1461        wait_time_in_call: time to wait when leaving a voice mail.
1462            This is optional, default is WAIT_TIME_LEAVE_VOICE_MAIL
1463
1464    Returns:
1465        True: if voice message is received on callee successfully.
1466        False: for errors
1467    """
1468
1469    # Currently this test utility only works for TMO and ATT and SPT.
1470    # It does not work for VZW (see b/21559800)
1471    # "with VVM TelephonyManager APIs won't work for vm"
1472
1473    caller_number = ad_caller.cfg['subscription'][subid_caller]['phone_num']
1474    callee_number = ad_callee.cfg['subscription'][subid_callee]['phone_num']
1475
1476    ad_caller.log.info("Call from %s to %s", caller_number, callee_number)
1477
1478    try:
1479        voice_mail_count_before = ad_callee.droid.telephonyGetVoiceMailCountForSubscription(
1480            subid_callee)
1481        ad_callee.log.info("voice mail count is %s", voice_mail_count_before)
1482        # -1 means there are unread voice mail, but the count is unknown
1483        # 0 means either this API not working (VZW) or no unread voice mail.
1484        if voice_mail_count_before != 0:
1485            log.warning("--Pending new Voice Mail, please clear on phone.--")
1486
1487        if not initiate_call(log, ad_caller, callee_number):
1488            raise _CallSequenceException("Initiate call failed.")
1489
1490        if not wait_and_reject_call_for_subscription(
1491                log, ad_callee, subid_callee, incoming_number=caller_number):
1492            raise _CallSequenceException("Reject call fail.")
1493
1494        ad_callee.droid.telephonyStartTrackingVoiceMailStateChangeForSubscription(
1495            subid_callee)
1496
1497        # ensure that all internal states are updated in telecom
1498        time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
1499        ad_callee.ed.ad.ed.clear_events(EventCallStateChanged)
1500
1501        if verify_caller_func and not verify_caller_func(log, ad_caller):
1502            raise _CallSequenceException("Caller not in correct state!")
1503
1504        # TODO: b/26293512 Need to play some sound to leave message.
1505        # Otherwise carrier voice mail server may drop this voice mail.
1506        time.sleep(wait_time_in_call)
1507
1508        if not verify_caller_func:
1509            caller_state_result = ad_caller.droid.telecomIsInCall()
1510        else:
1511            caller_state_result = verify_caller_func(log, ad_caller)
1512        if not caller_state_result:
1513            raise _CallSequenceException(
1514                "Caller %s not in correct state after %s seconds" %
1515                (ad_caller.serial, wait_time_in_call))
1516
1517        if not hangup_call(log, ad_caller):
1518            raise _CallSequenceException("Error in Hanging-Up Call")
1519
1520        log.info("Wait for voice mail indicator on callee.")
1521        try:
1522            event = ad_callee.ed.wait_for_event(
1523                EventMessageWaitingIndicatorChanged,
1524                _is_on_message_waiting_event_true)
1525            log.info(event)
1526        except Empty:
1527            ad_callee.log.warning("No expected event %s",
1528                                  EventMessageWaitingIndicatorChanged)
1529            raise _CallSequenceException("No expected event {}.".format(
1530                EventMessageWaitingIndicatorChanged))
1531        voice_mail_count_after = ad_callee.droid.telephonyGetVoiceMailCountForSubscription(
1532            subid_callee)
1533        ad_callee.log.info(
1534            "telephonyGetVoiceMailCount output - before: %s, after: %s",
1535            voice_mail_count_before, voice_mail_count_after)
1536
1537        # voice_mail_count_after should:
1538        # either equals to (voice_mail_count_before + 1) [For ATT and SPT]
1539        # or equals to -1 [For TMO]
1540        # -1 means there are unread voice mail, but the count is unknown
1541        if not check_voice_mail_count(log, ad_callee, voice_mail_count_before,
1542                                      voice_mail_count_after):
1543            log.error("before and after voice mail count is not incorrect.")
1544            return False
1545
1546    except _CallSequenceException as e:
1547        log.error(e)
1548        return False
1549    finally:
1550        ad_callee.droid.telephonyStopTrackingVoiceMailStateChangeForSubscription(
1551            subid_callee)
1552    return True
1553
1554
1555def call_voicemail_erase_all_pending_voicemail(log, ad):
1556    """Script for phone to erase all pending voice mail.
1557    This script only works for TMO and ATT and SPT currently.
1558    This script only works if phone have already set up voice mail options,
1559    and phone should disable password protection for voice mail.
1560
1561    1. If phone don't have pending voice message, return True.
1562    2. Dial voice mail number.
1563        For TMO, the number is '123'
1564        For ATT, the number is phone's number
1565        For SPT, the number is phone's number
1566    3. Wait for voice mail connection setup.
1567    4. Wait for voice mail play pending voice message.
1568    5. Send DTMF to delete one message.
1569        The digit is '7'.
1570    6. Repeat steps 4 and 5 until voice mail server drop this call.
1571        (No pending message)
1572    6. Check telephonyGetVoiceMailCount result. it should be 0.
1573
1574    Args:
1575        log: log object
1576        ad: android device object
1577    Returns:
1578        False if error happens. True is succeed.
1579    """
1580    log.info("Erase all pending voice mail.")
1581    count = ad.droid.telephonyGetVoiceMailCount()
1582    if count == 0:
1583        ad.log.info("No Pending voice mail.")
1584        return True
1585    if count == -1:
1586        ad.log.info("There is pending voice mail, but the count is unknown")
1587        count = MAX_SAVED_VOICE_MAIL
1588    else:
1589        ad.log.info("There are %s voicemails", count)
1590
1591    voice_mail_number = get_voice_mail_number(log, ad)
1592    delete_digit = get_voice_mail_delete_digit(get_operator_name(log, ad))
1593    if not initiate_call(log, ad, voice_mail_number):
1594        log.error("Initiate call to voice mail failed.")
1595        return False
1596    time.sleep(WAIT_TIME_VOICE_MAIL_SERVER_RESPONSE)
1597    callId = ad.droid.telecomCallGetCallIds()[0]
1598    time.sleep(WAIT_TIME_VOICE_MAIL_SERVER_RESPONSE)
1599    while (is_phone_in_call(log, ad) and (count > 0)):
1600        ad.log.info("Press %s to delete voice mail.", delete_digit)
1601        ad.droid.telecomCallPlayDtmfTone(callId, delete_digit)
1602        ad.droid.telecomCallStopDtmfTone(callId)
1603        time.sleep(WAIT_TIME_VOICE_MAIL_SERVER_RESPONSE)
1604        count -= 1
1605    if is_phone_in_call(log, ad):
1606        hangup_call(log, ad)
1607
1608    # wait for telephonyGetVoiceMailCount to update correct result
1609    remaining_time = MAX_WAIT_TIME_VOICE_MAIL_COUNT
1610    while ((remaining_time > 0)
1611           and (ad.droid.telephonyGetVoiceMailCount() != 0)):
1612        time.sleep(1)
1613        remaining_time -= 1
1614    current_voice_mail_count = ad.droid.telephonyGetVoiceMailCount()
1615    ad.log.info("telephonyGetVoiceMailCount: %s", current_voice_mail_count)
1616    return (current_voice_mail_count == 0)
1617
1618
1619def _is_on_message_waiting_event_true(event):
1620    """Private function to return if the received EventMessageWaitingIndicatorChanged
1621    event MessageWaitingIndicatorContainer.IS_MESSAGE_WAITING field is True.
1622    """
1623    return event['data'][MessageWaitingIndicatorContainer.IS_MESSAGE_WAITING]
1624
1625
1626def call_setup_teardown(log,
1627                        ad_caller,
1628                        ad_callee,
1629                        ad_hangup=None,
1630                        verify_caller_func=None,
1631                        verify_callee_func=None,
1632                        wait_time_in_call=WAIT_TIME_IN_CALL,
1633                        incall_ui_display=INCALL_UI_DISPLAY_FOREGROUND,
1634                        extra_sleep=0):
1635    """ Call process, including make a phone call from caller,
1636    accept from callee, and hang up. The call is on default voice subscription
1637
1638    In call process, call from <droid_caller> to <droid_callee>,
1639    accept the call, (optional)then hang up from <droid_hangup>.
1640
1641    Args:
1642        ad_caller: Caller Android Device Object.
1643        ad_callee: Callee Android Device Object.
1644        ad_hangup: Android Device Object end the phone call.
1645            Optional. Default value is None, and phone call will continue.
1646        verify_call_mode_caller: func_ptr to verify caller in correct mode
1647            Optional. Default is None
1648        verify_call_mode_caller: func_ptr to verify caller in correct mode
1649            Optional. Default is None
1650        incall_ui_display: after answer the call, bring in-call UI to foreground or
1651            background. Optional, default value is INCALL_UI_DISPLAY_FOREGROUND.
1652            if = INCALL_UI_DISPLAY_FOREGROUND, bring in-call UI to foreground.
1653            if = INCALL_UI_DISPLAY_BACKGROUND, bring in-call UI to background.
1654            else, do nothing.
1655        extra_sleep: for stress test only - b/64915613
1656
1657    Returns:
1658        True if call process without any error.
1659        False if error happened.
1660
1661    """
1662    subid_caller = get_outgoing_voice_sub_id(ad_caller)
1663    subid_callee = get_incoming_voice_sub_id(ad_callee)
1664    return call_setup_teardown_for_subscription(
1665        log, ad_caller, ad_callee, subid_caller, subid_callee, ad_hangup,
1666        verify_caller_func, verify_callee_func, wait_time_in_call,
1667        incall_ui_display, extra_sleep)
1668
1669
1670def call_setup_teardown_for_subscription(
1671        log,
1672        ad_caller,
1673        ad_callee,
1674        subid_caller,
1675        subid_callee,
1676        ad_hangup=None,
1677        verify_caller_func=None,
1678        verify_callee_func=None,
1679        wait_time_in_call=WAIT_TIME_IN_CALL,
1680        incall_ui_display=INCALL_UI_DISPLAY_FOREGROUND,
1681        extra_sleep=0):
1682    """ Call process, including make a phone call from caller,
1683    accept from callee, and hang up. The call is on specified subscription
1684
1685    In call process, call from <droid_caller> to <droid_callee>,
1686    accept the call, (optional)then hang up from <droid_hangup>.
1687
1688    Args:
1689        ad_caller: Caller Android Device Object.
1690        ad_callee: Callee Android Device Object.
1691        subid_caller: Caller subscription ID
1692        subid_callee: Callee subscription ID
1693        ad_hangup: Android Device Object end the phone call.
1694            Optional. Default value is None, and phone call will continue.
1695        verify_call_mode_caller: func_ptr to verify caller in correct mode
1696            Optional. Default is None
1697        verify_call_mode_caller: func_ptr to verify caller in correct mode
1698            Optional. Default is None
1699        incall_ui_display: after answer the call, bring in-call UI to foreground or
1700            background. Optional, default value is INCALL_UI_DISPLAY_FOREGROUND.
1701            if = INCALL_UI_DISPLAY_FOREGROUND, bring in-call UI to foreground.
1702            if = INCALL_UI_DISPLAY_BACKGROUND, bring in-call UI to background.
1703            else, do nothing.
1704        extra_sleep: for stress test only - b/64915613
1705
1706    Returns:
1707        True if call process without any error.
1708        False if error happened.
1709
1710    """
1711    CHECK_INTERVAL = 5
1712    begin_time = get_current_epoch_time()
1713
1714    caller_number = ad_caller.cfg['subscription'][subid_caller]['phone_num']
1715    callee_number = ad_callee.cfg['subscription'][subid_callee]['phone_num']
1716
1717    if not verify_caller_func:
1718        verify_caller_func = is_phone_in_call
1719    if not verify_callee_func:
1720        verify_callee_func = is_phone_in_call
1721    result = True
1722    msg = "Call from %s to %s" % (caller_number, callee_number)
1723    if ad_hangup:
1724        msg = "%s for duration of %s seconds" % (msg, wait_time_in_call)
1725    ad_caller.log.info(msg)
1726
1727    for ad in (ad_caller, ad_callee):
1728        call_ids = ad.droid.telecomCallGetCallIds()
1729        setattr(ad, "call_ids", call_ids)
1730        ad.log.info("Before making call, existing phone calls %s", call_ids)
1731    try:
1732        if not initiate_call(
1733                log,
1734                ad_caller,
1735                callee_number,
1736                wait_time_betwn_call_initcheck=extra_sleep):
1737            ad_caller.log.error("Initiate call failed.")
1738            return False
1739        else:
1740            ad_caller.log.info("Caller initate call successfully")
1741        if not wait_and_answer_call_for_subscription(
1742                log,
1743                ad_callee,
1744                subid_callee,
1745                incoming_number=caller_number,
1746                caller=ad_caller,
1747                incall_ui_display=incall_ui_display):
1748            ad_callee.log.error("Answer call fail.")
1749            return False
1750        else:
1751            ad_callee.log.info("Callee answered the call successfully")
1752
1753        for ad in (ad_caller, ad_callee):
1754            call_ids = ad.droid.telecomCallGetCallIds()
1755            new_call_id = list(set(call_ids) - set(ad.call_ids))[0]
1756            if not wait_for_in_call_active(ad, call_id=new_call_id):
1757                result = False
1758            if not ad.droid.telecomCallGetAudioState():
1759                ad.log.error("Audio is not in call state")
1760                result = False
1761
1762        elapsed_time = 0
1763        while (elapsed_time < wait_time_in_call):
1764            CHECK_INTERVAL = min(CHECK_INTERVAL,
1765                                 wait_time_in_call - elapsed_time)
1766            time.sleep(CHECK_INTERVAL)
1767            elapsed_time += CHECK_INTERVAL
1768            time_message = "at <%s>/<%s> second." % (elapsed_time,
1769                                                     wait_time_in_call)
1770            for ad, call_func in [(ad_caller, verify_caller_func),
1771                                  (ad_callee, verify_callee_func)]:
1772                if not call_func(log, ad):
1773                    ad.log.error("NOT in correct %s state at %s",
1774                                 call_func.__name__, time_message)
1775                    result = False
1776                else:
1777                    ad.log.info("In correct %s state at %s",
1778                                call_func.__name__, time_message)
1779                if not ad.droid.telecomCallGetAudioState():
1780                    ad.log.error("Audio is not in call state at %s",
1781                                 time_message)
1782                    result = False
1783                if not result:
1784                    break
1785        if ad_hangup and not hangup_call(log, ad_hangup):
1786            ad_hangup.log.info("Failed to hang up the call")
1787            result = False
1788        return result
1789    finally:
1790        if not result:
1791            for ad in [ad_caller, ad_callee]:
1792                reasons = ad.search_logcat(
1793                    "qcril_qmi_voice_map_qmi_to_ril_last_call_failure_cause",
1794                    begin_time)
1795                if reasons:
1796                    ad.log.info(reasons[-1]["log_message"])
1797                try:
1798                    if ad.droid.telecomIsInCall():
1799                        ad.droid.telecomEndCall()
1800                except Exception as e:
1801                    log.error(str(e))
1802
1803
1804def phone_number_formatter(input_string, formatter=None):
1805    """Get expected format of input phone number string.
1806
1807    Args:
1808        input_string: (string) input phone number.
1809            The input could be 10/11/12 digital, with or without " "/"-"/"."
1810        formatter: (int) expected format, this could be 7/10/11/12
1811            if formatter is 7: output string would be 7 digital number.
1812            if formatter is 10: output string would be 10 digital (standard) number.
1813            if formatter is 11: output string would be "1" + 10 digital number.
1814            if formatter is 12: output string would be "+1" + 10 digital number.
1815
1816    Returns:
1817        If no error happen, return phone number in expected format.
1818        Else, return None.
1819    """
1820    if not input_string:
1821        return ""
1822    # make sure input_string is 10 digital
1823    # Remove white spaces, dashes, dots
1824    input_string = input_string.replace(" ", "").replace("-", "").replace(
1825        ".", "").lstrip("0")
1826    if not formatter:
1827        return input_string
1828    # Remove "1"  or "+1"from front
1829    if (len(input_string) == PHONE_NUMBER_STRING_FORMAT_11_DIGIT
1830            and input_string[0] == "1"):
1831        input_string = input_string[1:]
1832    elif (len(input_string) == PHONE_NUMBER_STRING_FORMAT_12_DIGIT
1833          and input_string[0:2] == "+1"):
1834        input_string = input_string[2:]
1835    elif (len(input_string) == PHONE_NUMBER_STRING_FORMAT_7_DIGIT
1836          and formatter == PHONE_NUMBER_STRING_FORMAT_7_DIGIT):
1837        return input_string
1838    elif len(input_string) != PHONE_NUMBER_STRING_FORMAT_10_DIGIT:
1839        return None
1840    # change input_string according to format
1841    if formatter == PHONE_NUMBER_STRING_FORMAT_12_DIGIT:
1842        input_string = "+1" + input_string
1843    elif formatter == PHONE_NUMBER_STRING_FORMAT_11_DIGIT:
1844        input_string = "1" + input_string
1845    elif formatter == PHONE_NUMBER_STRING_FORMAT_10_DIGIT:
1846        input_string = input_string
1847    elif formatter == PHONE_NUMBER_STRING_FORMAT_7_DIGIT:
1848        input_string = input_string[3:]
1849    else:
1850        return None
1851    return input_string
1852
1853
1854def get_internet_connection_type(log, ad):
1855    """Get current active connection type name.
1856
1857    Args:
1858        log: Log object.
1859        ad: Android Device Object.
1860    Returns:
1861        current active connection type name.
1862    """
1863    if not ad.droid.connectivityNetworkIsConnected():
1864        return 'none'
1865    return connection_type_from_type_string(
1866        ad.droid.connectivityNetworkGetActiveConnectionTypeName())
1867
1868
1869def verify_http_connection(log,
1870                           ad,
1871                           url="www.google.com",
1872                           retry=5,
1873                           retry_interval=15,
1874                           expected_state=True):
1875    """Make ping request and return status.
1876
1877    Args:
1878        log: log object
1879        ad: Android Device Object.
1880        url: Optional. The ping request will be made to this URL.
1881            Default Value is "http://www.google.com/".
1882
1883    """
1884    for i in range(0, retry + 1):
1885        # b/18899134 httpPing will hang
1886        #try:
1887        #    http_response = ad.droid.httpPing(url)
1888        #except:
1889        #    http_response = None
1890        # If httpPing failed, it may return {} (if phone just turn off APM) or
1891        # None (regular fail)
1892        state = ad.droid.pingHost(url)
1893        ad.log.info("Connection to %s is %s", url, state)
1894        if expected_state == state:
1895            ad.log.info("Verify Internet connection state is %s succeeded",
1896                        str(expected_state))
1897            return True
1898        if i < retry:
1899            ad.log.info(
1900                "Verify Internet connection state=%s failed. Try again",
1901                str(expected_state))
1902            time.sleep(retry_interval)
1903    ad.log.info("Verify Internet state=%s failed after %s second",
1904                expected_state, i * retry_interval)
1905    return False
1906
1907
1908def _generate_file_directory_and_file_name(url, out_path):
1909    file_name = url.split("/")[-1]
1910    if not out_path:
1911        file_directory = "/sdcard/Download/"
1912    elif not out_path.endswith("/"):
1913        file_directory, file_name = os.path.split(out_path)
1914    else:
1915        file_directory = out_path
1916    return file_directory, file_name
1917
1918
1919def _check_file_existance(ad, file_path, expected_file_size=None):
1920    """Check file existance by file_path. If expected_file_size
1921       is provided, then also check if the file meet the file size requirement.
1922    """
1923    out = None
1924    try:
1925        out = ad.adb.shell('stat -c "%%s" %s' % file_path)
1926    except AdbError:
1927        pass
1928    # Handle some old version adb returns error message "No such" into std_out
1929    if out and "No such" not in out:
1930        if expected_file_size:
1931            file_size = int(out)
1932            if file_size >= expected_file_size:
1933                ad.log.info("File %s of size %s exists", file_path, file_size)
1934                return True
1935            else:
1936                ad.log.info("File %s is of size %s, does not meet expected %s",
1937                            file_path, file_size, expected_file_size)
1938                return False
1939        else:
1940            ad.log.info("File %s exists", file_path)
1941            return True
1942    else:
1943        ad.log.info("File %s does not exist.", file_path)
1944        return False
1945
1946
1947def check_curl_availability(ad):
1948    if not hasattr(ad, "curl_capable"):
1949        try:
1950            out = ad.adb.shell("/data/curl --version")
1951            if not out or "not found" in out:
1952                setattr(ad, "curl_capable", False)
1953                ad.log.info("curl is unavailable, use chrome to download file")
1954            else:
1955                setattr(ad, "curl_capable", True)
1956        except Exception:
1957            setattr(ad, "curl_capable", False)
1958            ad.log.info("curl is unavailable, use chrome to download file")
1959    return ad.curl_capable
1960
1961
1962def active_file_download_task(log, ad, file_name="5MB", method="chrome"):
1963    # files available for download on the same website:
1964    # 1GB.zip, 512MB.zip, 200MB.zip, 50MB.zip, 20MB.zip, 10MB.zip, 5MB.zip
1965    # download file by adb command, as phone call will use sl4a
1966    file_map_dict = {
1967        '5MB': 5000000,
1968        '10MB': 10000000,
1969        '20MB': 20000000,
1970        '50MB': 50000000,
1971        '100MB': 100000000,
1972        '200MB': 200000000,
1973        '512MB': 512000000
1974    }
1975    file_size = file_map_dict.get(file_name)
1976    if not file_size:
1977        log.warning("file_name %s for download is not available", file_name)
1978        return False
1979    timeout = min(max(file_size / 100000, 600), 3600)
1980    output_path = "/sdcard/Download/" + file_name + ".zip"
1981    url = "http://ipv4.download.thinkbroadband.com/" + file_name + ".zip"
1982    if method == "sl4a":
1983        return (http_file_download_by_sl4a, (ad, url, output_path, file_size,
1984                                             True, timeout))
1985    if method == "curl" and check_curl_availability(ad):
1986        url = "http://146.148.91.8/download/" + file_name + ".zip"
1987        return (http_file_download_by_curl, (ad, url, output_path, file_size,
1988                                             True, timeout))
1989    elif method == "sl4a":
1990        return (http_file_download_by_sl4a, (ad, url, output_path, file_size,
1991                                             True, timeout))
1992    else:
1993        return (http_file_download_by_chrome, (ad, url, file_size, True,
1994                                               timeout))
1995
1996
1997def active_file_download_test(log, ad, file_name="5MB", method="chrome"):
1998    task = active_file_download_task(log, ad, file_name, method=method)
1999    return task[0](*task[1])
2000
2001
2002def verify_internet_connection(log, ad, retries=1):
2003    """Verify internet connection by ping test.
2004
2005    Args:
2006        log: log object
2007        ad: Android Device Object.
2008
2009    """
2010    for i in range(retries):
2011        ad.log.info("Verify internet connection - attempt %d", i + 1)
2012        dest_to_ping = ["www.google.com", "www.amazon.com", "54.230.144.105"]
2013        for dest in dest_to_ping:
2014            result = adb_shell_ping(
2015                ad, count=5, timeout=60, loss_tolerance=40, dest_ip=dest)
2016            if result:
2017                return True
2018    return False
2019
2020
2021def iperf_test_by_adb(log,
2022                      ad,
2023                      iperf_server,
2024                      port_num=None,
2025                      reverse=False,
2026                      timeout=180,
2027                      limit_rate=None,
2028                      omit=10,
2029                      ipv6=False,
2030                      rate_dict=None,
2031                      blocking=True,
2032                      log_file_path=None):
2033    """Iperf test by adb.
2034
2035    Args:
2036        log: log object
2037        ad: Android Device Object.
2038        iperf_Server: The iperf host url".
2039        port_num: TCP/UDP server port
2040        timeout: timeout for file download to complete.
2041        limit_rate: iperf bandwidth option. None by default
2042        omit: the omit option provided in iperf command.
2043    """
2044    iperf_option = "-t %s -O %s -J" % (timeout, omit)
2045    if limit_rate: iperf_option += " -b %s" % limit_rate
2046    if port_num: iperf_option += " -p %s" % port_num
2047    if ipv6: iperf_option += " -6"
2048    if reverse: iperf_option += " -R"
2049    try:
2050        if log_file_path:
2051            ad.adb.shell("rm %s" % log_file_path, ignore_status=True)
2052        ad.log.info("Running adb iperf test with server %s", iperf_server)
2053        if not blocking:
2054            ad.run_iperf_client_nb(
2055                iperf_server,
2056                iperf_option,
2057                timeout=timeout + 60,
2058                log_file_path=log_file_path)
2059            return True
2060        result, data = ad.run_iperf_client(
2061            iperf_server, iperf_option, timeout=timeout + 60)
2062        ad.log.info("Iperf test result with server %s is %s", iperf_server,
2063                    result)
2064        if result:
2065            data_json = json.loads(''.join(data))
2066            tx_rate = data_json['end']['sum_sent']['bits_per_second']
2067            rx_rate = data_json['end']['sum_received']['bits_per_second']
2068            ad.log.info(
2069                'iPerf3 upload speed is %sbps, download speed is %sbps',
2070                tx_rate, rx_rate)
2071            if rate_dict is not None:
2072                rate_dict["Uplink"] = tx_rate
2073                rate_dict["Downlink"] = rx_rate
2074        return result
2075    except Exception as e:
2076        ad.log.warning("Fail to run iperf test with exception %s", e)
2077        return False
2078
2079
2080def http_file_download_by_curl(ad,
2081                               url,
2082                               out_path=None,
2083                               expected_file_size=None,
2084                               remove_file_after_check=True,
2085                               timeout=3600,
2086                               limit_rate=None,
2087                               retry=3):
2088    """Download http file by adb curl.
2089
2090    Args:
2091        ad: Android Device Object.
2092        url: The url that file to be downloaded from".
2093        out_path: Optional. Where to download file to.
2094                  out_path is /sdcard/Download/ by default.
2095        expected_file_size: Optional. Provided if checking the download file meet
2096                            expected file size in unit of byte.
2097        remove_file_after_check: Whether to remove the downloaded file after
2098                                 check.
2099        timeout: timeout for file download to complete.
2100        limit_rate: download rate in bps. None, if do not apply rate limit.
2101        retry: the retry request times provided in curl command.
2102    """
2103    file_directory, file_name = _generate_file_directory_and_file_name(
2104        url, out_path)
2105    file_path = os.path.join(file_directory, file_name)
2106    curl_cmd = "/data/curl"
2107    if limit_rate:
2108        curl_cmd += " --limit-rate %s" % limit_rate
2109    if retry:
2110        curl_cmd += " --retry %s" % retry
2111    curl_cmd += " --url %s > %s" % (url, file_path)
2112    accounting_apk = "com.android.server.telecom"  #"com.quicinc.cne.CNEService"
2113    result = True
2114    try:
2115        data_accounting = {
2116            "mobile_rx_bytes":
2117            ad.droid.getMobileRxBytes(),
2118            "subscriber_mobile_data_usage":
2119            get_mobile_data_usage(ad, None, None),
2120            "curl_mobile_data_usage":
2121            get_mobile_data_usage(ad, None, accounting_apk)
2122        }
2123        ad.log.info("Before downloading: %s", data_accounting)
2124        ad.log.info("Download %s to %s by adb shell command %s", url,
2125                    file_path, curl_cmd)
2126        ad.adb.shell(curl_cmd, timeout=timeout)
2127        if _check_file_existance(ad, file_path, expected_file_size):
2128            ad.log.info("%s is downloaded to %s successfully", url, file_path)
2129            new_data_accounting = {
2130                "mobile_rx_bytes":
2131                ad.droid.getMobileRxBytes(),
2132                "subscriber_mobile_data_usage":
2133                get_mobile_data_usage(ad, None, None),
2134                "curl_mobile_data_usage":
2135                get_mobile_data_usage(ad, None, accounting_apk)
2136            }
2137            ad.log.info("After downloading: %s", new_data_accounting)
2138            accounting_diff = {
2139                key: value - data_accounting[key]
2140                for key, value in new_data_accounting.items()
2141            }
2142            ad.log.info("Data accounting difference: %s", accounting_diff)
2143            if getattr(ad, "on_mobile_data", False):
2144                for key, value in accounting_diff.items():
2145                    if value < expected_file_size:
2146                        ad.log.warning("%s diff is %s less than %s", key,
2147                                       value, expected_file_size)
2148                        ad.data_accounting["%s_failure" % key] += 1
2149            else:
2150                for key, value in accounting_diff.items():
2151                    if value >= expected_file_size:
2152                        ad.log.error("%s diff is %s. File download is "
2153                                     "consuming mobile data", key, value)
2154                        result = False
2155            ad.log.info("data_accounting_failure: %s", dict(
2156                ad.data_accounting))
2157            return result
2158        else:
2159            ad.log.warning("Fail to download %s", url)
2160            return False
2161    except Exception as e:
2162        ad.log.warning("Download %s failed with exception %s", url, e)
2163        return False
2164    finally:
2165        if remove_file_after_check:
2166            ad.log.info("Remove the downloaded file %s", file_path)
2167            ad.adb.shell("rm %s" % file_path, ignore_status=True)
2168
2169
2170def open_url_by_adb(ad, url):
2171    ad.adb.shell('am start -a android.intent.action.VIEW -d "%s"' % url)
2172
2173
2174def http_file_download_by_chrome(ad,
2175                                 url,
2176                                 expected_file_size=None,
2177                                 remove_file_after_check=True,
2178                                 timeout=3600):
2179    """Download http file by chrome.
2180
2181    Args:
2182        ad: Android Device Object.
2183        url: The url that file to be downloaded from".
2184        expected_file_size: Optional. Provided if checking the download file meet
2185                            expected file size in unit of byte.
2186        remove_file_after_check: Whether to remove the downloaded file after
2187                                 check.
2188        timeout: timeout for file download to complete.
2189    """
2190    chrome_apk = "com.android.chrome"
2191    file_directory, file_name = _generate_file_directory_and_file_name(
2192        url, "/sdcard/Download/")
2193    file_path = os.path.join(file_directory, file_name)
2194    # Remove pre-existing file
2195    ad.force_stop_apk(chrome_apk)
2196    file_to_be_delete = os.path.join(file_directory, "*%s*" % file_name)
2197    ad.adb.shell("rm -f %s" % file_to_be_delete)
2198    ad.adb.shell("rm -rf /sdcard/Download/.*")
2199    ad.adb.shell("rm -f /sdcard/Download/.*")
2200    data_accounting = {
2201        "total_rx_bytes": ad.droid.getTotalRxBytes(),
2202        "mobile_rx_bytes": ad.droid.getMobileRxBytes(),
2203        "subscriber_mobile_data_usage": get_mobile_data_usage(ad, None, None),
2204        "chrome_mobile_data_usage": get_mobile_data_usage(
2205            ad, None, chrome_apk)
2206    }
2207    ad.log.info("Before downloading: %s", data_accounting)
2208    ad.ensure_screen_on()
2209    ad.log.info("Download %s with timeout %s", url, timeout)
2210    open_url_by_adb(ad, url)
2211    elapse_time = 0
2212    result = True
2213    while elapse_time < timeout:
2214        time.sleep(30)
2215        if _check_file_existance(ad, file_path, expected_file_size):
2216            ad.log.info("%s is downloaded successfully", url)
2217            if remove_file_after_check:
2218                ad.log.info("Remove the downloaded file %s", file_path)
2219                ad.adb.shell("rm -f %s" % file_to_be_delete)
2220                ad.adb.shell("rm -rf /sdcard/Download/.*")
2221                ad.adb.shell("rm -f /sdcard/Download/.*")
2222            #time.sleep(30)
2223            new_data_accounting = {
2224                "mobile_rx_bytes":
2225                ad.droid.getMobileRxBytes(),
2226                "subscriber_mobile_data_usage":
2227                get_mobile_data_usage(ad, None, None),
2228                "chrome_mobile_data_usage":
2229                get_mobile_data_usage(ad, None, chrome_apk)
2230            }
2231            ad.log.info("After downloading: %s", new_data_accounting)
2232            accounting_diff = {
2233                key: value - data_accounting[key]
2234                for key, value in new_data_accounting.items()
2235            }
2236            ad.log.info("Data accounting difference: %s", accounting_diff)
2237            if getattr(ad, "on_mobile_data", False):
2238                for key, value in accounting_diff.items():
2239                    if value < expected_file_size:
2240                        ad.log.warning("%s diff is %s less than %s", key,
2241                                       value, expected_file_size)
2242                        ad.data_accounting["%s_failure" % key] += 1
2243            else:
2244                for key, value in accounting_diff.items():
2245                    if value >= expected_file_size:
2246                        ad.log.error("%s diff is %s. File download is "
2247                                     "consuming mobile data", key, value)
2248                        result = False
2249            return result
2250        elif _check_file_existance(ad, "%s.crdownload" % file_path):
2251            ad.log.info("Chrome is downloading %s", url)
2252        elif elapse_time < 60:
2253            # download not started, retry download wit chrome again
2254            open_url_by_adb(ad, url)
2255        else:
2256            ad.log.error("Unable to download file from %s", url)
2257            break
2258        elapse_time += 30
2259    ad.log.warning("Fail to download file from %s", url)
2260    ad.force_stop_apk("com.android.chrome")
2261    ad.adb.shell("rm -f %s" % file_to_be_delete)
2262    ad.adb.shell("rm -rf /sdcard/Download/.*")
2263    ad.adb.shell("rm -f /sdcard/Download/.*")
2264    return False
2265
2266
2267def http_file_download_by_sl4a(ad,
2268                               url,
2269                               out_path=None,
2270                               expected_file_size=None,
2271                               remove_file_after_check=True,
2272                               timeout=300):
2273    """Download http file by sl4a RPC call.
2274
2275    Args:
2276        ad: Android Device Object.
2277        url: The url that file to be downloaded from".
2278        out_path: Optional. Where to download file to.
2279                  out_path is /sdcard/Download/ by default.
2280        expected_file_size: Optional. Provided if checking the download file meet
2281                            expected file size in unit of byte.
2282        remove_file_after_check: Whether to remove the downloaded file after
2283                                 check.
2284        timeout: timeout for file download to complete.
2285    """
2286    file_folder, file_name = _generate_file_directory_and_file_name(
2287        url, out_path)
2288    file_path = os.path.join(file_folder, file_name)
2289    ad.adb.shell("rm -f %s" % file_path)
2290    accounting_apk = SL4A_APK_NAME
2291    result = True
2292    try:
2293        if not getattr(ad, "downloading_droid", None):
2294            ad.downloading_droid, ad.downloading_ed = ad.get_droid()
2295            ad.downloading_ed.start()
2296        else:
2297            try:
2298                if not ad.downloading_droid.is_live:
2299                    ad.downloading_droid, ad.downloading_ed = ad.get_droid()
2300                    ad.downloading_ed.start()
2301            except Exception as e:
2302                ad.log.info(e)
2303                ad.downloading_droid, ad.downloading_ed = ad.get_droid()
2304                ad.downloading_ed.start()
2305        data_accounting = {
2306            "mobile_rx_bytes":
2307            ad.droid.getMobileRxBytes(),
2308            "subscriber_mobile_data_usage":
2309            get_mobile_data_usage(ad, None, None),
2310            "sl4a_mobile_data_usage":
2311            get_mobile_data_usage(ad, None, accounting_apk)
2312        }
2313        ad.log.info("Before downloading: %s", data_accounting)
2314        ad.log.info("Download file from %s to %s by sl4a RPC call", url,
2315                    file_path)
2316        try:
2317            ad.downloading_droid.httpDownloadFile(
2318                url, file_path, timeout=timeout)
2319        except Exception as e:
2320            ad.log.warning("SL4A file download error: %s", e)
2321            return False
2322        if _check_file_existance(ad, file_path, expected_file_size):
2323            ad.log.info("%s is downloaded successfully", url)
2324            new_data_accounting = {
2325                "mobile_rx_bytes":
2326                ad.droid.getMobileRxBytes(),
2327                "subscriber_mobile_data_usage":
2328                get_mobile_data_usage(ad, None, None),
2329                "sl4a_mobile_data_usage":
2330                get_mobile_data_usage(ad, None, accounting_apk)
2331            }
2332            ad.log.info("After downloading: %s", new_data_accounting)
2333            accounting_diff = {
2334                key: value - data_accounting[key]
2335                for key, value in new_data_accounting.items()
2336            }
2337            ad.log.info("Data accounting difference: %s", accounting_diff)
2338            if getattr(ad, "on_mobile_data", False):
2339                for key, value in accounting_diff.items():
2340                    if value < expected_file_size:
2341                        ad.log.warning("%s diff is %s less than %s", key,
2342                                       value, expected_file_size)
2343                        ad.data_accounting["%s_failure"] += 1
2344            else:
2345                for key, value in accounting_diff.items():
2346                    if value >= expected_file_size:
2347                        ad.log.error("%s diff is %s. File download is "
2348                                     "consuming mobile data", key, value)
2349                        result = False
2350            return result
2351        else:
2352            ad.log.warning("Fail to download %s", url)
2353            return False
2354    except Exception as e:
2355        ad.log.error("Download %s failed with exception %s", url, e)
2356        raise
2357    finally:
2358        if remove_file_after_check:
2359            ad.log.info("Remove the downloaded file %s", file_path)
2360            ad.adb.shell("rm %s" % file_path, ignore_status=True)
2361
2362
2363def get_mobile_data_usage(ad, subscriber_id=None, apk=None):
2364    if not subscriber_id:
2365        subscriber_id = ad.droid.telephonyGetSubscriberId()
2366    if not getattr(ad, "data_metering_begin_time", None) or not getattr(
2367            ad, "data_metering_end_time", None):
2368        current_time = int(time.time() * 1000)
2369        setattr(ad, "data_metering_begin_time",
2370                current_time - 24 * 60 * 60 * 1000)
2371        setattr(ad, "data_metering_end_time",
2372                current_time + 30 * 24 * 60 * 60 * 1000)
2373    begin_time = ad.data_metering_begin_time
2374    end_time = ad.data_metering_end_time
2375    if apk:
2376        uid = ad.get_apk_uid(apk)
2377        try:
2378            usage = ad.droid.connectivityQueryDetailsForUid(
2379                TYPE_MOBILE, subscriber_id, begin_time, end_time, uid)
2380        except Exception:
2381            usage = ad.droid.connectivityQueryDetailsForUid(
2382                subscriber_id, begin_time, end_time, uid)
2383        ad.log.debug("The mobile data usage for apk %s is %s", apk, usage)
2384    else:
2385        try:
2386            usage = ad.droid.connectivityQuerySummaryForDevice(
2387                TYPE_MOBILE, subscriber_id, begin_time, end_time)
2388        except Exception:
2389            usage = ad.droid.connectivityQuerySummaryForDevice(
2390                subscriber_id, begin_time, end_time)
2391        ad.log.debug("The mobile data usage for subscriber is %s", usage)
2392    return usage
2393
2394
2395def set_mobile_data_usage_limit(ad, limit, subscriber_id=None):
2396    if not subscriber_id:
2397        subscriber_id = ad.droid.telephonyGetSubscriberId()
2398    ad.log.info("Set subscriber mobile data usage limit to %s", limit)
2399    ad.droid.connectivitySetDataUsageLimit(subscriber_id, str(limit))
2400
2401
2402def remove_mobile_data_usage_limit(ad, subscriber_id=None):
2403    if not subscriber_id:
2404        subscriber_id = ad.droid.telephonyGetSubscriberId()
2405    ad.log.info("Remove subscriber mobile data usage limit")
2406    ad.droid.connectivitySetDataUsageLimit(subscriber_id, "-1")
2407
2408
2409def trigger_modem_crash(ad, timeout=120):
2410    cmd = "echo restart > /sys/kernel/debug/msm_subsys/modem"
2411    ad.log.info("Triggering Modem Crash from kernel using adb command %s", cmd)
2412    ad.adb.shell(cmd)
2413    time.sleep(timeout)
2414    return True
2415
2416
2417def trigger_modem_crash_by_modem(ad, timeout=120):
2418    begin_time = get_current_epoch_time()
2419    ad.adb.shell(
2420        "setprop persist.vendor.sys.modem.diag.mdlog false", ignore_status=True)
2421    # Legacy pixels use persist.sys.modem.diag.mdlog.
2422    ad.adb.shell(
2423        "setprop persist.sys.modem.diag.mdlog false", ignore_status=True)
2424    stop_qxdm_logger(ad)
2425    cmd = ('am instrument -w -e request "4b 25 03 00" '
2426           '"com.google.mdstest/com.google.mdstest.instrument.'
2427           'ModemCommandInstrumentation"')
2428    ad.log.info("Crash modem by %s", cmd)
2429    ad.adb.shell(cmd, ignore_status=True)
2430    time.sleep(timeout)  # sleep time for sl4a stability
2431    reasons = ad.search_logcat("modem subsystem failure reason", begin_time)
2432    if reasons:
2433        ad.log.info("Modem crash is triggered successfully")
2434        ad.log.info(reasons[-1]["log_message"])
2435        return True
2436    else:
2437        ad.log.info("Modem crash is not triggered successfully")
2438        return False
2439
2440
2441def _connection_state_change(_event, target_state, connection_type):
2442    if connection_type:
2443        if 'TypeName' not in _event['data']:
2444            return False
2445        connection_type_string_in_event = _event['data']['TypeName']
2446        cur_type = connection_type_from_type_string(
2447            connection_type_string_in_event)
2448        if cur_type != connection_type:
2449            log.info(
2450                "_connection_state_change expect: %s, received: %s <type %s>",
2451                connection_type, connection_type_string_in_event, cur_type)
2452            return False
2453
2454    if 'isConnected' in _event['data'] and _event['data']['isConnected'] == target_state:
2455        return True
2456    return False
2457
2458
2459def wait_for_cell_data_connection(
2460        log, ad, state, timeout_value=MAX_WAIT_TIME_CONNECTION_STATE_UPDATE):
2461    """Wait for data connection status to be expected value for default
2462       data subscription.
2463
2464    Wait for the data connection status to be DATA_STATE_CONNECTED
2465        or DATA_STATE_DISCONNECTED.
2466
2467    Args:
2468        log: Log object.
2469        ad: Android Device Object.
2470        state: Expected status: True or False.
2471            If True, it will wait for status to be DATA_STATE_CONNECTED.
2472            If False, it will wait for status ti be DATA_STATE_DISCONNECTED.
2473        timeout_value: wait for cell data timeout value.
2474            This is optional, default value is MAX_WAIT_TIME_CONNECTION_STATE_UPDATE
2475
2476    Returns:
2477        True if success.
2478        False if failed.
2479    """
2480    sub_id = get_default_data_sub_id(ad)
2481    return wait_for_cell_data_connection_for_subscription(
2482        log, ad, sub_id, state, timeout_value)
2483
2484
2485def _is_data_connection_state_match(log, ad, expected_data_connection_state):
2486    return (expected_data_connection_state ==
2487            ad.droid.telephonyGetDataConnectionState())
2488
2489
2490def _is_network_connected_state_match(log, ad,
2491                                      expected_network_connected_state):
2492    return (expected_network_connected_state ==
2493            ad.droid.connectivityNetworkIsConnected())
2494
2495
2496def wait_for_cell_data_connection_for_subscription(
2497        log,
2498        ad,
2499        sub_id,
2500        state,
2501        timeout_value=MAX_WAIT_TIME_CONNECTION_STATE_UPDATE):
2502    """Wait for data connection status to be expected value for specified
2503       subscrption id.
2504
2505    Wait for the data connection status to be DATA_STATE_CONNECTED
2506        or DATA_STATE_DISCONNECTED.
2507
2508    Args:
2509        log: Log object.
2510        ad: Android Device Object.
2511        sub_id: subscription Id
2512        state: Expected status: True or False.
2513            If True, it will wait for status to be DATA_STATE_CONNECTED.
2514            If False, it will wait for status ti be DATA_STATE_DISCONNECTED.
2515        timeout_value: wait for cell data timeout value.
2516            This is optional, default value is MAX_WAIT_TIME_CONNECTION_STATE_UPDATE
2517
2518    Returns:
2519        True if success.
2520        False if failed.
2521    """
2522    state_str = {
2523        True: DATA_STATE_CONNECTED,
2524        False: DATA_STATE_DISCONNECTED
2525    }[state]
2526
2527    data_state = ad.droid.telephonyGetDataConnectionState()
2528    if not state and ad.droid.telephonyGetDataConnectionState() == state_str:
2529        return True
2530    ad.ed.clear_events(EventDataConnectionStateChanged)
2531    ad.droid.telephonyStartTrackingDataConnectionStateChangeForSubscription(
2532        sub_id)
2533    ad.droid.connectivityStartTrackingConnectivityStateChange()
2534    try:
2535        # TODO: b/26293147 There is no framework API to get data connection
2536        # state by sub id
2537        data_state = ad.droid.telephonyGetDataConnectionState()
2538        if data_state == state_str:
2539            return _wait_for_nw_data_connection(
2540                log, ad, state, NETWORK_CONNECTION_TYPE_CELL, timeout_value)
2541
2542        try:
2543            event = ad.ed.wait_for_event(
2544                EventDataConnectionStateChanged,
2545                is_event_match,
2546                timeout=timeout_value,
2547                field=DataConnectionStateContainer.DATA_CONNECTION_STATE,
2548                value=state_str)
2549        except Empty:
2550            ad.log.info("No expected event EventDataConnectionStateChanged %s",
2551                        state_str)
2552
2553        # TODO: Wait for <MAX_WAIT_TIME_CONNECTION_STATE_UPDATE> seconds for
2554        # data connection state.
2555        # Otherwise, the network state will not be correct.
2556        # The bug is tracked here: b/20921915
2557
2558        # Previously we use _is_data_connection_state_match,
2559        # but telephonyGetDataConnectionState sometimes return wrong value.
2560        # The bug is tracked here: b/22612607
2561        # So we use _is_network_connected_state_match.
2562
2563        if _wait_for_droid_in_state(log, ad, timeout_value,
2564                                    _is_network_connected_state_match, state):
2565            return _wait_for_nw_data_connection(
2566                log, ad, state, NETWORK_CONNECTION_TYPE_CELL, timeout_value)
2567        else:
2568            return False
2569
2570    finally:
2571        ad.droid.telephonyStopTrackingDataConnectionStateChangeForSubscription(
2572            sub_id)
2573
2574
2575def wait_for_wifi_data_connection(
2576        log, ad, state, timeout_value=MAX_WAIT_TIME_CONNECTION_STATE_UPDATE):
2577    """Wait for data connection status to be expected value and connection is by WiFi.
2578
2579    Args:
2580        log: Log object.
2581        ad: Android Device Object.
2582        state: Expected status: True or False.
2583            If True, it will wait for status to be DATA_STATE_CONNECTED.
2584            If False, it will wait for status ti be DATA_STATE_DISCONNECTED.
2585        timeout_value: wait for network data timeout value.
2586            This is optional, default value is MAX_WAIT_TIME_NW_SELECTION
2587
2588    Returns:
2589        True if success.
2590        False if failed.
2591    """
2592    ad.log.info("wait_for_wifi_data_connection")
2593    return _wait_for_nw_data_connection(
2594        log, ad, state, NETWORK_CONNECTION_TYPE_WIFI, timeout_value)
2595
2596
2597def wait_for_data_connection(
2598        log, ad, state, timeout_value=MAX_WAIT_TIME_CONNECTION_STATE_UPDATE):
2599    """Wait for data connection status to be expected value.
2600
2601    Wait for the data connection status to be DATA_STATE_CONNECTED
2602        or DATA_STATE_DISCONNECTED.
2603
2604    Args:
2605        log: Log object.
2606        ad: Android Device Object.
2607        state: Expected status: True or False.
2608            If True, it will wait for status to be DATA_STATE_CONNECTED.
2609            If False, it will wait for status ti be DATA_STATE_DISCONNECTED.
2610        timeout_value: wait for network data timeout value.
2611            This is optional, default value is MAX_WAIT_TIME_CONNECTION_STATE_UPDATE
2612
2613    Returns:
2614        True if success.
2615        False if failed.
2616    """
2617    return _wait_for_nw_data_connection(log, ad, state, None, timeout_value)
2618
2619
2620def _wait_for_nw_data_connection(
2621        log,
2622        ad,
2623        is_connected,
2624        connection_type=None,
2625        timeout_value=MAX_WAIT_TIME_CONNECTION_STATE_UPDATE):
2626    """Wait for data connection status to be expected value.
2627
2628    Wait for the data connection status to be DATA_STATE_CONNECTED
2629        or DATA_STATE_DISCONNECTED.
2630
2631    Args:
2632        log: Log object.
2633        ad: Android Device Object.
2634        is_connected: Expected connection status: True or False.
2635            If True, it will wait for status to be DATA_STATE_CONNECTED.
2636            If False, it will wait for status ti be DATA_STATE_DISCONNECTED.
2637        connection_type: expected connection type.
2638            This is optional, if it is None, then any connection type will return True.
2639        timeout_value: wait for network data timeout value.
2640            This is optional, default value is MAX_WAIT_TIME_CONNECTION_STATE_UPDATE
2641
2642    Returns:
2643        True if success.
2644        False if failed.
2645    """
2646    ad.ed.clear_events(EventConnectivityChanged)
2647    ad.droid.connectivityStartTrackingConnectivityStateChange()
2648    try:
2649        cur_data_connection_state = ad.droid.connectivityNetworkIsConnected()
2650        if is_connected == cur_data_connection_state:
2651            current_type = get_internet_connection_type(log, ad)
2652            ad.log.info("current data connection type: %s", current_type)
2653            if not connection_type:
2654                return True
2655            else:
2656                if not is_connected and current_type != connection_type:
2657                    ad.log.info("data connection not on %s!", connection_type)
2658                    return True
2659                elif is_connected and current_type == connection_type:
2660                    ad.log.info("data connection on %s as expected",
2661                                connection_type)
2662                    return True
2663        else:
2664            ad.log.info("current data connection state: %s target: %s",
2665                        cur_data_connection_state, is_connected)
2666
2667        try:
2668            event = ad.ed.wait_for_event(
2669                EventConnectivityChanged, _connection_state_change,
2670                timeout_value, is_connected, connection_type)
2671            ad.log.info("received event: %s", event)
2672        except Empty:
2673            pass
2674
2675        log.info(
2676            "_wait_for_nw_data_connection: check connection after wait event.")
2677        # TODO: Wait for <MAX_WAIT_TIME_CONNECTION_STATE_UPDATE> seconds for
2678        # data connection state.
2679        # Otherwise, the network state will not be correct.
2680        # The bug is tracked here: b/20921915
2681        if _wait_for_droid_in_state(log, ad, timeout_value,
2682                                    _is_network_connected_state_match,
2683                                    is_connected):
2684            current_type = get_internet_connection_type(log, ad)
2685            ad.log.info("current data connection type: %s", current_type)
2686            if not connection_type:
2687                return True
2688            else:
2689                if not is_connected and current_type != connection_type:
2690                    ad.log.info("data connection not on %s", connection_type)
2691                    return True
2692                elif is_connected and current_type == connection_type:
2693                    ad.log.info("after event wait, data connection on %s",
2694                                connection_type)
2695                    return True
2696                else:
2697                    return False
2698        else:
2699            return False
2700    except Exception as e:
2701        ad.log.error("Exception error %s", str(e))
2702        return False
2703    finally:
2704        ad.droid.connectivityStopTrackingConnectivityStateChange()
2705
2706
2707def get_cell_data_roaming_state_by_adb(ad):
2708    """Get Cell Data Roaming state. True for enabled, False for disabled"""
2709    adb_str = {"1": True, "0": False}
2710    out = ad.adb.shell("settings get global data_roaming")
2711    return adb_str[out]
2712
2713
2714def get_cell_data_roaming_state_by_adb(ad):
2715    """Get Cell Data Roaming state. True for enabled, False for disabled"""
2716    state_mapping = {"1": True, "0": False}
2717    return state_mapping[ad.adb.shell("settings get global data_roaming")]
2718
2719
2720def set_cell_data_roaming_state_by_adb(ad, state):
2721    """Set Cell Data Roaming state."""
2722    state_mapping = {True: "1", False: "0"}
2723    ad.log.info("Set data roaming to %s", state)
2724    ad.adb.shell("settings put global data_roaming %s" % state_mapping[state])
2725
2726
2727def toggle_cell_data_roaming(ad, state):
2728    """Enable cell data roaming for default data subscription.
2729
2730    Wait for the data roaming status to be DATA_STATE_CONNECTED
2731        or DATA_STATE_DISCONNECTED.
2732
2733    Args:
2734        log: Log object.
2735        ad: Android Device Object.
2736        state: True or False for enable or disable cell data roaming.
2737
2738    Returns:
2739        True if success.
2740        False if failed.
2741    """
2742    state_int = {True: DATA_ROAMING_ENABLE, False: DATA_ROAMING_DISABLE}[state]
2743    action_str = {True: "Enable", False: "Disable"}[state]
2744    if ad.droid.connectivityCheckDataRoamingMode() == state:
2745        ad.log.info("Data roaming is already in state %s", state)
2746        return True
2747    if not ad.droid.connectivitySetDataRoaming(state_int):
2748        ad.error.info("Fail to config data roaming into state %s", state)
2749        return False
2750    if ad.droid.connectivityCheckDataRoamingMode() == state:
2751        ad.log.info("Data roaming is configured into state %s", state)
2752        return True
2753    else:
2754        ad.log.error("Data roaming is not configured into state %s", state)
2755        return False
2756
2757
2758def verify_incall_state(log, ads, expected_status):
2759    """Verify phones in incall state or not.
2760
2761    Verify if all phones in the array <ads> are in <expected_status>.
2762
2763    Args:
2764        log: Log object.
2765        ads: Array of Android Device Object. All droid in this array will be tested.
2766        expected_status: If True, verify all Phones in incall state.
2767            If False, verify all Phones not in incall state.
2768
2769    """
2770    result = True
2771    for ad in ads:
2772        if ad.droid.telecomIsInCall() is not expected_status:
2773            ad.log.error("InCall status:%s, expected:%s",
2774                         ad.droid.telecomIsInCall(), expected_status)
2775            result = False
2776    return result
2777
2778
2779def verify_active_call_number(log, ad, expected_number):
2780    """Verify the number of current active call.
2781
2782    Verify if the number of current active call in <ad> is
2783        equal to <expected_number>.
2784
2785    Args:
2786        ad: Android Device Object.
2787        expected_number: Expected active call number.
2788    """
2789    calls = ad.droid.telecomCallGetCallIds()
2790    if calls is None:
2791        actual_number = 0
2792    else:
2793        actual_number = len(calls)
2794    if actual_number != expected_number:
2795        ad.log.error("Active Call number is %s, expecting", actual_number,
2796                     expected_number)
2797        return False
2798    return True
2799
2800
2801def num_active_calls(log, ad):
2802    """Get the count of current active calls.
2803
2804    Args:
2805        log: Log object.
2806        ad: Android Device Object.
2807
2808    Returns:
2809        Count of current active calls.
2810    """
2811    calls = ad.droid.telecomCallGetCallIds()
2812    return len(calls) if calls else 0
2813
2814
2815def toggle_volte(log, ad, new_state=None):
2816    """Toggle enable/disable VoLTE for default voice subscription.
2817
2818    Args:
2819        ad: Android device object.
2820        new_state: VoLTE mode state to set to.
2821            True for enable, False for disable.
2822            If None, opposite of the current state.
2823
2824    Raises:
2825        TelTestUtilsError if platform does not support VoLTE.
2826    """
2827    return toggle_volte_for_subscription(
2828        log, ad, get_outgoing_voice_sub_id(ad), new_state)
2829
2830
2831def toggle_volte_for_subscription(log, ad, sub_id, new_state=None):
2832    """Toggle enable/disable VoLTE for specified voice subscription.
2833
2834    Args:
2835        ad: Android device object.
2836        sub_id: subscription ID
2837        new_state: VoLTE mode state to set to.
2838            True for enable, False for disable.
2839            If None, opposite of the current state.
2840
2841    Raises:
2842        TelTestUtilsError if platform does not support VoLTE.
2843    """
2844    # TODO: b/26293960 No framework API available to set IMS by SubId.
2845    if not ad.droid.imsIsEnhanced4gLteModeSettingEnabledByPlatform():
2846        ad.log.info("VoLTE not supported by platform.")
2847        raise TelTestUtilsError(
2848            "VoLTE not supported by platform %s." % ad.serial)
2849    current_state = ad.droid.imsIsEnhanced4gLteModeSettingEnabledByUser()
2850    if new_state is None:
2851        new_state = not current_state
2852    if new_state != current_state:
2853        ad.droid.imsSetEnhanced4gMode(new_state)
2854    return True
2855
2856
2857def set_wfc_mode(log, ad, wfc_mode):
2858    """Set WFC enable/disable and mode.
2859
2860    Args:
2861        log: Log object
2862        ad: Android device object.
2863        wfc_mode: WFC mode to set to.
2864            Valid mode includes: WFC_MODE_WIFI_ONLY, WFC_MODE_CELLULAR_PREFERRED,
2865            WFC_MODE_WIFI_PREFERRED, WFC_MODE_DISABLED.
2866
2867    Returns:
2868        True if success. False if ad does not support WFC or error happened.
2869    """
2870    try:
2871        ad.log.info("Set wfc mode to %s", wfc_mode)
2872        if not ad.droid.imsIsWfcEnabledByPlatform():
2873            if wfc_mode == WFC_MODE_DISABLED:
2874                return True
2875            else:
2876                ad.log.error("WFC not supported by platform.")
2877                return False
2878        ad.droid.imsSetWfcMode(wfc_mode)
2879        mode = ad.droid.imsGetWfcMode()
2880        if mode != wfc_mode:
2881            ad.log.error("WFC mode is %s, not in %s", mode, wfc_mode)
2882            return False
2883    except Exception as e:
2884        log.error(e)
2885        return False
2886    return True
2887
2888
2889def toggle_video_calling(log, ad, new_state=None):
2890    """Toggle enable/disable Video calling for default voice subscription.
2891
2892    Args:
2893        ad: Android device object.
2894        new_state: Video mode state to set to.
2895            True for enable, False for disable.
2896            If None, opposite of the current state.
2897
2898    Raises:
2899        TelTestUtilsError if platform does not support Video calling.
2900    """
2901    if not ad.droid.imsIsVtEnabledByPlatform():
2902        if new_state is not False:
2903            raise TelTestUtilsError("VT not supported by platform.")
2904        # if the user sets VT false and it's unavailable we just let it go
2905        return False
2906
2907    current_state = ad.droid.imsIsVtEnabledByUser()
2908    if new_state is None:
2909        new_state = not current_state
2910    if new_state != current_state:
2911        ad.droid.imsSetVtSetting(new_state)
2912    return True
2913
2914
2915def _wait_for_droid_in_state(log, ad, max_time, state_check_func, *args,
2916                             **kwargs):
2917    while max_time >= 0:
2918        if state_check_func(log, ad, *args, **kwargs):
2919            return True
2920
2921        time.sleep(WAIT_TIME_BETWEEN_STATE_CHECK)
2922        max_time -= WAIT_TIME_BETWEEN_STATE_CHECK
2923
2924    return False
2925
2926
2927def _wait_for_droid_in_state_for_subscription(
2928        log, ad, sub_id, max_time, state_check_func, *args, **kwargs):
2929    while max_time >= 0:
2930        if state_check_func(log, ad, sub_id, *args, **kwargs):
2931            return True
2932
2933        time.sleep(WAIT_TIME_BETWEEN_STATE_CHECK)
2934        max_time -= WAIT_TIME_BETWEEN_STATE_CHECK
2935
2936    return False
2937
2938
2939def _wait_for_droids_in_state(log, ads, max_time, state_check_func, *args,
2940                              **kwargs):
2941    while max_time > 0:
2942        success = True
2943        for ad in ads:
2944            if not state_check_func(log, ad, *args, **kwargs):
2945                success = False
2946                break
2947        if success:
2948            return True
2949
2950        time.sleep(WAIT_TIME_BETWEEN_STATE_CHECK)
2951        max_time -= WAIT_TIME_BETWEEN_STATE_CHECK
2952
2953    return False
2954
2955
2956def is_phone_in_call(log, ad):
2957    """Return True if phone in call.
2958
2959    Args:
2960        log: log object.
2961        ad:  android device.
2962    """
2963    try:
2964        return ad.droid.telecomIsInCall()
2965    except:
2966        return "mCallState=2" in ad.adb.shell(
2967            "dumpsys telephony.registry | grep mCallState")
2968
2969
2970def is_phone_not_in_call(log, ad):
2971    """Return True if phone not in call.
2972
2973    Args:
2974        log: log object.
2975        ad:  android device.
2976    """
2977    in_call = ad.droid.telecomIsInCall()
2978    call_state = ad.droid.telephonyGetCallState()
2979    if in_call:
2980        ad.log.info("Device is In Call")
2981    if call_state != TELEPHONY_STATE_IDLE:
2982        ad.log.info("Call_state is %s, not %s", call_state,
2983                    TELEPHONY_STATE_IDLE)
2984    return ((not in_call) and (call_state == TELEPHONY_STATE_IDLE))
2985
2986
2987def wait_for_droid_in_call(log, ad, max_time):
2988    """Wait for android to be in call state.
2989
2990    Args:
2991        log: log object.
2992        ad:  android device.
2993        max_time: maximal wait time.
2994
2995    Returns:
2996        If phone become in call state within max_time, return True.
2997        Return False if timeout.
2998    """
2999    return _wait_for_droid_in_state(log, ad, max_time, is_phone_in_call)
3000
3001
3002def is_phone_in_call_active(ad, call_id=None):
3003    """Return True if phone in active call.
3004
3005    Args:
3006        log: log object.
3007        ad:  android device.
3008        call_id: the call id
3009    """
3010    if not call_id:
3011        call_id = ad.droid.telecomCallGetCallIds()[0]
3012    call_state = ad.droid.telecomCallGetCallState(call_id)
3013    ad.log.info("%s state is %s", call_id, call_state)
3014    return call_state == "ACTIVE"
3015
3016
3017def wait_for_in_call_active(ad, timeout=5, interval=1, call_id=None):
3018    """Wait for call reach active state.
3019
3020    Args:
3021        log: log object.
3022        ad:  android device.
3023        call_id: the call id
3024    """
3025    if not call_id:
3026        call_id = ad.droid.telecomCallGetCallIds()[0]
3027    args = [ad, call_id]
3028    if not wait_for_state(is_phone_in_call_active, True, timeout, interval,
3029                          *args):
3030        ad.log.error("Call did not reach ACTIVE state")
3031        return False
3032    else:
3033        return True
3034
3035
3036def wait_for_telecom_ringing(log, ad, max_time=MAX_WAIT_TIME_TELECOM_RINGING):
3037    """Wait for android to be in telecom ringing state.
3038
3039    Args:
3040        log: log object.
3041        ad:  android device.
3042        max_time: maximal wait time. This is optional.
3043            Default Value is MAX_WAIT_TIME_TELECOM_RINGING.
3044
3045    Returns:
3046        If phone become in telecom ringing state within max_time, return True.
3047        Return False if timeout.
3048    """
3049    return _wait_for_droid_in_state(
3050        log, ad, max_time, lambda log, ad: ad.droid.telecomIsRinging())
3051
3052
3053def wait_for_droid_not_in_call(log, ad, max_time=MAX_WAIT_TIME_CALL_DROP):
3054    """Wait for android to be not in call state.
3055
3056    Args:
3057        log: log object.
3058        ad:  android device.
3059        max_time: maximal wait time.
3060
3061    Returns:
3062        If phone become not in call state within max_time, return True.
3063        Return False if timeout.
3064    """
3065    return _wait_for_droid_in_state(log, ad, max_time, is_phone_not_in_call)
3066
3067
3068def _is_attached(log, ad, voice_or_data):
3069    return _is_attached_for_subscription(
3070        log, ad, ad.droid.subscriptionGetDefaultSubId(), voice_or_data)
3071
3072
3073def _is_attached_for_subscription(log, ad, sub_id, voice_or_data):
3074    rat = get_network_rat_for_subscription(log, ad, sub_id, voice_or_data)
3075    ad.log.info("Sub_id %s network RAT is %s for %s", sub_id, rat,
3076                voice_or_data)
3077    return rat != RAT_UNKNOWN
3078
3079
3080def is_voice_attached(log, ad):
3081    return _is_attached_for_subscription(
3082        log, ad, ad.droid.subscriptionGetDefaultSubId(), NETWORK_SERVICE_VOICE)
3083
3084
3085def wait_for_voice_attach(log, ad, max_time):
3086    """Wait for android device to attach on voice.
3087
3088    Args:
3089        log: log object.
3090        ad:  android device.
3091        max_time: maximal wait time.
3092
3093    Returns:
3094        Return True if device attach voice within max_time.
3095        Return False if timeout.
3096    """
3097    return _wait_for_droid_in_state(log, ad, max_time, _is_attached,
3098                                    NETWORK_SERVICE_VOICE)
3099
3100
3101def wait_for_voice_attach_for_subscription(log, ad, sub_id, max_time):
3102    """Wait for android device to attach on voice in subscription id.
3103
3104    Args:
3105        log: log object.
3106        ad:  android device.
3107        sub_id: subscription id.
3108        max_time: maximal wait time.
3109
3110    Returns:
3111        Return True if device attach voice within max_time.
3112        Return False if timeout.
3113    """
3114    if not _wait_for_droid_in_state_for_subscription(
3115            log, ad, sub_id, max_time, _is_attached_for_subscription,
3116            NETWORK_SERVICE_VOICE):
3117        return False
3118
3119    # TODO: b/26295983 if pone attach to 1xrtt from unknown, phone may not
3120    # receive incoming call immediately.
3121    if ad.droid.telephonyGetCurrentVoiceNetworkType() == RAT_1XRTT:
3122        time.sleep(WAIT_TIME_1XRTT_VOICE_ATTACH)
3123    return True
3124
3125
3126def wait_for_data_attach(log, ad, max_time):
3127    """Wait for android device to attach on data.
3128
3129    Args:
3130        log: log object.
3131        ad:  android device.
3132        max_time: maximal wait time.
3133
3134    Returns:
3135        Return True if device attach data within max_time.
3136        Return False if timeout.
3137    """
3138    return _wait_for_droid_in_state(log, ad, max_time, _is_attached,
3139                                    NETWORK_SERVICE_DATA)
3140
3141
3142def wait_for_data_attach_for_subscription(log, ad, sub_id, max_time):
3143    """Wait for android device to attach on data in subscription id.
3144
3145    Args:
3146        log: log object.
3147        ad:  android device.
3148        sub_id: subscription id.
3149        max_time: maximal wait time.
3150
3151    Returns:
3152        Return True if device attach data within max_time.
3153        Return False if timeout.
3154    """
3155    return _wait_for_droid_in_state_for_subscription(
3156        log, ad, sub_id, max_time, _is_attached_for_subscription,
3157        NETWORK_SERVICE_DATA)
3158
3159
3160def is_ims_registered(log, ad):
3161    """Return True if IMS registered.
3162
3163    Args:
3164        log: log object.
3165        ad: android device.
3166
3167    Returns:
3168        Return True if IMS registered.
3169        Return False if IMS not registered.
3170    """
3171    return ad.droid.telephonyIsImsRegistered()
3172
3173
3174def wait_for_ims_registered(log, ad, max_time):
3175    """Wait for android device to register on ims.
3176
3177    Args:
3178        log: log object.
3179        ad:  android device.
3180        max_time: maximal wait time.
3181
3182    Returns:
3183        Return True if device register ims successfully within max_time.
3184        Return False if timeout.
3185    """
3186    return _wait_for_droid_in_state(log, ad, max_time, is_ims_registered)
3187
3188
3189def is_volte_enabled(log, ad):
3190    """Return True if VoLTE feature bit is True.
3191
3192    Args:
3193        log: log object.
3194        ad: android device.
3195
3196    Returns:
3197        Return True if VoLTE feature bit is True and IMS registered.
3198        Return False if VoLTE feature bit is False or IMS not registered.
3199    """
3200    result = True
3201    if not ad.droid.telephonyIsVolteAvailable():
3202        ad.log.info("IsVolteCallingAvailble is False")
3203        result = False
3204    else:
3205        ad.log.info("IsVolteCallingAvailble is True")
3206    if not is_ims_registered(log, ad):
3207        ad.log.info("IMS is not registered.")
3208        result = False
3209    else:
3210        ad.log.info("IMS is registered")
3211    return result
3212
3213
3214def is_video_enabled(log, ad):
3215    """Return True if Video Calling feature bit is True.
3216
3217    Args:
3218        log: log object.
3219        ad: android device.
3220
3221    Returns:
3222        Return True if Video Calling feature bit is True and IMS registered.
3223        Return False if Video Calling feature bit is False or IMS not registered.
3224    """
3225    video_status = ad.droid.telephonyIsVideoCallingAvailable()
3226    if video_status is True and is_ims_registered(log, ad) is False:
3227        log.error("Error! Video Call is Available, but IMS is not registered.")
3228        return False
3229    return video_status
3230
3231
3232def wait_for_volte_enabled(log, ad, max_time):
3233    """Wait for android device to report VoLTE enabled bit true.
3234
3235    Args:
3236        log: log object.
3237        ad:  android device.
3238        max_time: maximal wait time.
3239
3240    Returns:
3241        Return True if device report VoLTE enabled bit true within max_time.
3242        Return False if timeout.
3243    """
3244    return _wait_for_droid_in_state(log, ad, max_time, is_volte_enabled)
3245
3246
3247def wait_for_video_enabled(log, ad, max_time):
3248    """Wait for android device to report Video Telephony enabled bit true.
3249
3250    Args:
3251        log: log object.
3252        ad:  android device.
3253        max_time: maximal wait time.
3254
3255    Returns:
3256        Return True if device report Video Telephony enabled bit true within max_time.
3257        Return False if timeout.
3258    """
3259    return _wait_for_droid_in_state(log, ad, max_time, is_video_enabled)
3260
3261
3262def is_wfc_enabled(log, ad):
3263    """Return True if WiFi Calling feature bit is True.
3264
3265    Args:
3266        log: log object.
3267        ad: android device.
3268
3269    Returns:
3270        Return True if WiFi Calling feature bit is True and IMS registered.
3271        Return False if WiFi Calling feature bit is False or IMS not registered.
3272    """
3273    if not ad.droid.telephonyIsWifiCallingAvailable():
3274        ad.log.info("IsWifiCallingAvailble is False")
3275        return False
3276    else:
3277        ad.log.info("IsWifiCallingAvailble is True")
3278        if not is_ims_registered(log, ad):
3279            ad.log.info(
3280                "WiFi Calling is Available, but IMS is not registered.")
3281            return False
3282        return True
3283
3284
3285def wait_for_wfc_enabled(log, ad, max_time=MAX_WAIT_TIME_WFC_ENABLED):
3286    """Wait for android device to report WiFi Calling enabled bit true.
3287
3288    Args:
3289        log: log object.
3290        ad:  android device.
3291        max_time: maximal wait time.
3292            Default value is MAX_WAIT_TIME_WFC_ENABLED.
3293
3294    Returns:
3295        Return True if device report WiFi Calling enabled bit true within max_time.
3296        Return False if timeout.
3297    """
3298    return _wait_for_droid_in_state(log, ad, max_time, is_wfc_enabled)
3299
3300
3301def wait_for_wfc_disabled(log, ad, max_time=MAX_WAIT_TIME_WFC_DISABLED):
3302    """Wait for android device to report WiFi Calling enabled bit false.
3303
3304    Args:
3305        log: log object.
3306        ad:  android device.
3307        max_time: maximal wait time.
3308            Default value is MAX_WAIT_TIME_WFC_DISABLED.
3309
3310    Returns:
3311        Return True if device report WiFi Calling enabled bit false within max_time.
3312        Return False if timeout.
3313    """
3314    return _wait_for_droid_in_state(
3315        log, ad, max_time, lambda log, ad: not is_wfc_enabled(log, ad))
3316
3317
3318def get_phone_number(log, ad):
3319    """Get phone number for default subscription
3320
3321    Args:
3322        log: log object.
3323        ad: Android device object.
3324
3325    Returns:
3326        Phone number.
3327    """
3328    return get_phone_number_for_subscription(log, ad,
3329                                             get_outgoing_voice_sub_id(ad))
3330
3331
3332def get_phone_number_for_subscription(log, ad, subid):
3333    """Get phone number for subscription
3334
3335    Args:
3336        log: log object.
3337        ad: Android device object.
3338        subid: subscription id.
3339
3340    Returns:
3341        Phone number.
3342    """
3343    number = None
3344    try:
3345        number = ad.cfg['subscription'][subid]['phone_num']
3346    except KeyError:
3347        number = ad.droid.telephonyGetLine1NumberForSubscription(subid)
3348    return number
3349
3350
3351def set_phone_number(log, ad, phone_num):
3352    """Set phone number for default subscription
3353
3354    Args:
3355        log: log object.
3356        ad: Android device object.
3357        phone_num: phone number string.
3358
3359    Returns:
3360        True if success.
3361    """
3362    return set_phone_number_for_subscription(log, ad,
3363                                             get_outgoing_voice_sub_id(ad),
3364                                             phone_num)
3365
3366
3367def set_phone_number_for_subscription(log, ad, subid, phone_num):
3368    """Set phone number for subscription
3369
3370    Args:
3371        log: log object.
3372        ad: Android device object.
3373        subid: subscription id.
3374        phone_num: phone number string.
3375
3376    Returns:
3377        True if success.
3378    """
3379    try:
3380        ad.cfg['subscription'][subid]['phone_num'] = phone_num
3381    except Exception:
3382        return False
3383    return True
3384
3385
3386def get_operator_name(log, ad, subId=None):
3387    """Get operator name (e.g. vzw, tmo) of droid.
3388
3389    Args:
3390        ad: Android device object.
3391        sub_id: subscription ID
3392            Optional, default is None
3393
3394    Returns:
3395        Operator name.
3396    """
3397    try:
3398        if subId is not None:
3399            result = operator_name_from_plmn_id(
3400                ad.droid.telephonyGetNetworkOperatorForSubscription(subId))
3401        else:
3402            result = operator_name_from_plmn_id(
3403                ad.droid.telephonyGetNetworkOperator())
3404    except KeyError:
3405        result = CARRIER_UNKNOWN
3406    return result
3407
3408
3409def get_model_name(ad):
3410    """Get android device model name
3411
3412    Args:
3413        ad: Android device object
3414
3415    Returns:
3416        model name string
3417    """
3418    # TODO: Create translate table.
3419    model = ad.model
3420    if (model.startswith(AOSP_PREFIX)):
3421        model = model[len(AOSP_PREFIX):]
3422    return model
3423
3424
3425def is_sms_match(event, phonenumber_tx, text):
3426    """Return True if 'text' equals to event['data']['Text']
3427        and phone number match.
3428
3429    Args:
3430        event: Event object to verify.
3431        phonenumber_tx: phone number for sender.
3432        text: text string to verify.
3433
3434    Returns:
3435        Return True if 'text' equals to event['data']['Text']
3436            and phone number match.
3437    """
3438    return (check_phone_number_match(event['data']['Sender'], phonenumber_tx)
3439            and event['data']['Text'] == text)
3440
3441
3442def is_sms_partial_match(event, phonenumber_tx, text):
3443    """Return True if 'text' starts with event['data']['Text']
3444        and phone number match.
3445
3446    Args:
3447        event: Event object to verify.
3448        phonenumber_tx: phone number for sender.
3449        text: text string to verify.
3450
3451    Returns:
3452        Return True if 'text' starts with event['data']['Text']
3453            and phone number match.
3454    """
3455    return (check_phone_number_match(event['data']['Sender'], phonenumber_tx)
3456            and text.startswith(event['data']['Text']))
3457
3458
3459def sms_send_receive_verify(log,
3460                            ad_tx,
3461                            ad_rx,
3462                            array_message,
3463                            max_wait_time=MAX_WAIT_TIME_SMS_RECEIVE):
3464    """Send SMS, receive SMS, and verify content and sender's number.
3465
3466        Send (several) SMS from droid_tx to droid_rx.
3467        Verify SMS is sent, delivered and received.
3468        Verify received content and sender's number are correct.
3469
3470    Args:
3471        log: Log object.
3472        ad_tx: Sender's Android Device Object
3473        ad_rx: Receiver's Android Device Object
3474        array_message: the array of message to send/receive
3475    """
3476    subid_tx = get_outgoing_message_sub_id(ad_tx)
3477    subid_rx = get_incoming_message_sub_id(ad_rx)
3478    return sms_send_receive_verify_for_subscription(
3479        log, ad_tx, ad_rx, subid_tx, subid_rx, array_message, max_wait_time)
3480
3481
3482def wait_for_matching_sms(log,
3483                          ad_rx,
3484                          phonenumber_tx,
3485                          text,
3486                          allow_multi_part_long_sms=True,
3487                          begin_time=None,
3488                          max_wait_time=MAX_WAIT_TIME_SMS_RECEIVE):
3489    """Wait for matching incoming SMS.
3490
3491    Args:
3492        log: Log object.
3493        ad_rx: Receiver's Android Device Object
3494        phonenumber_tx: Sender's phone number.
3495        text: SMS content string.
3496        allow_multi_part_long_sms: is long SMS allowed to be received as
3497            multiple short SMS. This is optional, default value is True.
3498
3499    Returns:
3500        True if matching incoming SMS is received.
3501    """
3502    if not allow_multi_part_long_sms:
3503        try:
3504            ad_rx.messaging_ed.wait_for_event(EventSmsReceived, is_sms_match,
3505                                              max_wait_time, phonenumber_tx,
3506                                              text)
3507            return True
3508        except Empty:
3509            ad_rx.log.error("No matched SMS received event.")
3510            if begin_time:
3511                if sms_mms_receive_logcat_check(ad_rx, "sms", begin_time):
3512                    ad_rx.log.info("Receivd SMS message is seen in logcat")
3513            return False
3514    else:
3515        try:
3516            received_sms = ''
3517            while (text != ''):
3518                event = ad_rx.messaging_ed.wait_for_event(
3519                    EventSmsReceived, is_sms_partial_match, max_wait_time,
3520                    phonenumber_tx, text)
3521                text = text[len(event['data']['Text']):]
3522                received_sms += event['data']['Text']
3523            return True
3524        except Empty:
3525            ad_rx.log.error("No matched SMS received event.")
3526            if begin_time:
3527                if sms_mms_receive_logcat_check(ad_rx, "sms", begin_time):
3528                    ad_rx.log.info("Receivd SMS message is seen in logcat")
3529            if received_sms != '':
3530                ad_rx.log.error("Only received partial matched SMS: %s",
3531                                received_sms)
3532            return False
3533
3534
3535def is_mms_match(event, phonenumber_tx, text):
3536    """Return True if 'text' equals to event['data']['Text']
3537        and phone number match.
3538
3539    Args:
3540        event: Event object to verify.
3541        phonenumber_tx: phone number for sender.
3542        text: text string to verify.
3543
3544    Returns:
3545        Return True if 'text' equals to event['data']['Text']
3546            and phone number match.
3547    """
3548    #TODO:  add mms matching after mms message parser is added in sl4a. b/34276948
3549    return True
3550
3551
3552def wait_for_matching_mms(log,
3553                          ad_rx,
3554                          phonenumber_tx,
3555                          text,
3556                          begin_time=None,
3557                          max_wait_time=MAX_WAIT_TIME_SMS_RECEIVE):
3558    """Wait for matching incoming SMS.
3559
3560    Args:
3561        log: Log object.
3562        ad_rx: Receiver's Android Device Object
3563        phonenumber_tx: Sender's phone number.
3564        text: SMS content string.
3565        allow_multi_part_long_sms: is long SMS allowed to be received as
3566            multiple short SMS. This is optional, default value is True.
3567
3568    Returns:
3569        True if matching incoming SMS is received.
3570    """
3571    try:
3572        #TODO: add mms matching after mms message parser is added in sl4a. b/34276948
3573        ad_rx.messaging_ed.wait_for_event(EventMmsDownloaded, is_mms_match,
3574                                          max_wait_time, phonenumber_tx, text)
3575        return True
3576    except Empty:
3577        ad_rx.log.warning("No matched MMS downloaded event.")
3578        if begin_time:
3579            if sms_mms_receive_logcat_check(ad_rx, "mms", begin_time):
3580                return True
3581        return False
3582
3583
3584def sms_send_receive_verify_for_subscription(
3585        log,
3586        ad_tx,
3587        ad_rx,
3588        subid_tx,
3589        subid_rx,
3590        array_message,
3591        max_wait_time=MAX_WAIT_TIME_SMS_RECEIVE):
3592    """Send SMS, receive SMS, and verify content and sender's number.
3593
3594        Send (several) SMS from droid_tx to droid_rx.
3595        Verify SMS is sent, delivered and received.
3596        Verify received content and sender's number are correct.
3597
3598    Args:
3599        log: Log object.
3600        ad_tx: Sender's Android Device Object..
3601        ad_rx: Receiver's Android Device Object.
3602        subid_tx: Sender's subsciption ID to be used for SMS
3603        subid_rx: Receiver's subsciption ID to be used for SMS
3604        array_message: the array of message to send/receive
3605    """
3606    phonenumber_tx = ad_tx.cfg['subscription'][subid_tx]['phone_num']
3607    phonenumber_rx = ad_rx.cfg['subscription'][subid_rx]['phone_num']
3608
3609    for ad in (ad_tx, ad_rx):
3610        if not getattr(ad, "messaging_droid", None):
3611            ad.messaging_droid, ad.messaging_ed = ad.get_droid()
3612            ad.messaging_ed.start()
3613        else:
3614            try:
3615                if not ad.messaging_droid.is_live:
3616                    ad.messaging_droid, ad.messaging_ed = ad.get_droid()
3617                    ad.messaging_ed.start()
3618            except Exception as e:
3619                ad.log.info(e)
3620                ad.messaging_droid, ad.messaging_ed = ad.get_droid()
3621                ad.messaging_ed.start()
3622
3623    for text in array_message:
3624        # set begin_time 300ms before current time to system time discrepency
3625        begin_time = get_current_epoch_time() - 300
3626        length = len(text)
3627        ad_tx.log.info("Sending SMS from %s to %s, len: %s, content: %s.",
3628                       phonenumber_tx, phonenumber_rx, length, text)
3629        try:
3630            ad_rx.messaging_ed.clear_events(EventSmsReceived)
3631            ad_tx.messaging_ed.clear_events(EventSmsSentSuccess)
3632            ad_rx.messaging_droid.smsStartTrackingIncomingSmsMessage()
3633            time.sleep(1)  #sleep 100ms after starting event tracking
3634            ad_tx.messaging_droid.smsSendTextMessage(phonenumber_rx, text,
3635                                                     False)
3636            try:
3637                ad_tx.messaging_ed.pop_event(EventSmsSentSuccess,
3638                                             max_wait_time)
3639            except Empty:
3640                ad_tx.log.error("No sent_success event for SMS of length %s.",
3641                                length)
3642                # check log message as a work around for the missing sl4a
3643                # event dispatcher event
3644                if not sms_mms_send_logcat_check(ad_tx, "sms", begin_time):
3645                    return False
3646
3647            if not wait_for_matching_sms(
3648                    log,
3649                    ad_rx,
3650                    phonenumber_tx,
3651                    text,
3652                    allow_multi_part_long_sms=True,
3653                    begin_time=begin_time):
3654                ad_rx.log.error("No matching received SMS of length %s.",
3655                                length)
3656                return False
3657        except Exception as e:
3658            log.error("Exception error %s", e)
3659            raise
3660        finally:
3661            ad_rx.messaging_droid.smsStopTrackingIncomingSmsMessage()
3662    return True
3663
3664
3665def mms_send_receive_verify(log,
3666                            ad_tx,
3667                            ad_rx,
3668                            array_message,
3669                            max_wait_time=MAX_WAIT_TIME_SMS_RECEIVE):
3670    """Send MMS, receive MMS, and verify content and sender's number.
3671
3672        Send (several) MMS from droid_tx to droid_rx.
3673        Verify MMS is sent, delivered and received.
3674        Verify received content and sender's number are correct.
3675
3676    Args:
3677        log: Log object.
3678        ad_tx: Sender's Android Device Object
3679        ad_rx: Receiver's Android Device Object
3680        array_message: the array of message to send/receive
3681    """
3682    return mms_send_receive_verify_for_subscription(
3683        log, ad_tx, ad_rx, get_outgoing_message_sub_id(ad_tx),
3684        get_incoming_message_sub_id(ad_rx), array_message, max_wait_time)
3685
3686
3687def sms_mms_send_logcat_check(ad, type, begin_time):
3688    type = type.upper()
3689    log_results = ad.search_logcat(
3690        "%s Message sent successfully" % type, begin_time=begin_time)
3691    if log_results:
3692        ad.log.info("Found %s sent succeessful log message: %s", type,
3693                    log_results[-1]["log_message"])
3694        return True
3695    else:
3696        log_results = ad.search_logcat(
3697            "ProcessSentMessageAction: Done sending %s message" % type,
3698            begin_time=begin_time)
3699        if log_results:
3700            for log_result in log_results:
3701                if "status is SUCCEEDED" in log_result["log_message"]:
3702                    ad.log.info(
3703                        "Found BugleDataModel %s send succeed log message: %s",
3704                        type, log_result["log_message"])
3705                    return True
3706    return False
3707
3708
3709def sms_mms_receive_logcat_check(ad, type, begin_time):
3710    type = type.upper()
3711    log_results = ad.search_logcat(
3712        "New %s Received" % type, begin_time=begin_time) or \
3713        ad.search_logcat("New %s Downloaded" % type, begin_time=begin_time)
3714    if log_results:
3715        ad.log.info("Found SL4A %s received log message: %s", type,
3716                    log_results[-1]["log_message"])
3717        return True
3718    else:
3719        log_results = ad.search_logcat(
3720            "Received %s message" % type, begin_time=begin_time)
3721        if log_results:
3722            ad.log.info("Found %s received log message: %s", type,
3723                        log_results[-1]["log_message"])
3724            return True
3725    return False
3726
3727
3728#TODO: add mms matching after mms message parser is added in sl4a. b/34276948
3729def mms_send_receive_verify_for_subscription(
3730        log,
3731        ad_tx,
3732        ad_rx,
3733        subid_tx,
3734        subid_rx,
3735        array_payload,
3736        max_wait_time=MAX_WAIT_TIME_SMS_RECEIVE):
3737    """Send MMS, receive MMS, and verify content and sender's number.
3738
3739        Send (several) MMS from droid_tx to droid_rx.
3740        Verify MMS is sent, delivered and received.
3741        Verify received content and sender's number are correct.
3742
3743    Args:
3744        log: Log object.
3745        ad_tx: Sender's Android Device Object..
3746        ad_rx: Receiver's Android Device Object.
3747        subid_tx: Sender's subsciption ID to be used for SMS
3748        subid_rx: Receiver's subsciption ID to be used for SMS
3749        array_message: the array of message to send/receive
3750    """
3751
3752    phonenumber_tx = ad_tx.cfg['subscription'][subid_tx]['phone_num']
3753    phonenumber_rx = ad_rx.cfg['subscription'][subid_rx]['phone_num']
3754
3755    for ad in (ad_rx, ad_tx):
3756        if "Permissive" not in ad.adb.shell("su root getenforce"):
3757            ad.adb.shell("su root setenforce 0")
3758        if not getattr(ad, "messaging_droid", None):
3759            ad.messaging_droid, ad.messaging_ed = ad.get_droid()
3760            ad.messaging_ed.start()
3761
3762    for subject, message, filename in array_payload:
3763        begin_time = get_current_epoch_time()
3764        ad_tx.messaging_ed.clear_events(EventMmsSentSuccess)
3765        ad_rx.messaging_ed.clear_events(EventMmsDownloaded)
3766        ad_rx.messaging_droid.smsStartTrackingIncomingMmsMessage()
3767        ad_tx.log.info(
3768            "Sending MMS from %s to %s, subject: %s, message: %s, file: %s.",
3769            phonenumber_tx, phonenumber_rx, subject, message, filename)
3770        try:
3771            ad_tx.messaging_droid.smsSendMultimediaMessage(
3772                phonenumber_rx, subject, message, phonenumber_tx, filename)
3773            try:
3774                ad_tx.messaging_ed.pop_event(EventMmsSentSuccess,
3775                                             max_wait_time)
3776            except Empty:
3777                ad_tx.log.warning("No sent_success event.")
3778                # check log message as a work around for the missing sl4a
3779                # event dispatcher event
3780                if not sms_mms_send_logcat_check(ad_tx, "mms", begin_time):
3781                    return False
3782
3783            if not wait_for_matching_mms(
3784                    log, ad_rx, phonenumber_tx, message,
3785                    begin_time=begin_time):
3786                return False
3787        except Exception as e:
3788            log.error("Exception error %s", e)
3789            raise
3790        finally:
3791            ad_rx.droid.smsStopTrackingIncomingMmsMessage()
3792    return True
3793
3794
3795def mms_receive_verify_after_call_hangup(
3796        log, ad_tx, ad_rx, array_message,
3797        max_wait_time=MAX_WAIT_TIME_SMS_RECEIVE):
3798    """Verify the suspanded MMS during call will send out after call release.
3799
3800        Hangup call from droid_tx to droid_rx.
3801        Verify MMS is sent, delivered and received.
3802        Verify received content and sender's number are correct.
3803
3804    Args:
3805        log: Log object.
3806        ad_tx: Sender's Android Device Object
3807        ad_rx: Receiver's Android Device Object
3808        array_message: the array of message to send/receive
3809    """
3810    return mms_receive_verify_after_call_hangup_for_subscription(
3811        log, ad_tx, ad_rx, get_outgoing_message_sub_id(ad_tx),
3812        get_incoming_message_sub_id(ad_rx), array_message, max_wait_time)
3813
3814
3815#TODO: add mms matching after mms message parser is added in sl4a. b/34276948
3816def mms_receive_verify_after_call_hangup_for_subscription(
3817        log,
3818        ad_tx,
3819        ad_rx,
3820        subid_tx,
3821        subid_rx,
3822        array_payload,
3823        max_wait_time=MAX_WAIT_TIME_SMS_RECEIVE):
3824    """Verify the suspanded MMS during call will send out after call release.
3825
3826        Hangup call from droid_tx to droid_rx.
3827        Verify MMS is sent, delivered and received.
3828        Verify received content and sender's number are correct.
3829
3830    Args:
3831        log: Log object.
3832        ad_tx: Sender's Android Device Object..
3833        ad_rx: Receiver's Android Device Object.
3834        subid_tx: Sender's subsciption ID to be used for SMS
3835        subid_rx: Receiver's subsciption ID to be used for SMS
3836        array_message: the array of message to send/receive
3837    """
3838
3839    phonenumber_tx = ad_tx.cfg['subscription'][subid_tx]['phone_num']
3840    phonenumber_rx = ad_rx.cfg['subscription'][subid_rx]['phone_num']
3841    for ad in (ad_tx, ad_rx):
3842        if not getattr(ad, "messaging_droid", None):
3843            ad.messaging_droid, ad.messaging_ed = ad.get_droid()
3844            ad.messaging_ed.start()
3845    for subject, message, filename in array_payload:
3846        begin_time = get_current_epoch_time()
3847        ad_rx.log.info(
3848            "Waiting MMS from %s to %s, subject: %s, message: %s, file: %s.",
3849            phonenumber_tx, phonenumber_rx, subject, message, filename)
3850        ad_rx.messaging_droid.smsStartTrackingIncomingMmsMessage()
3851        time.sleep(5)
3852        try:
3853            hangup_call(log, ad_tx)
3854            hangup_call(log, ad_rx)
3855            try:
3856                ad_tx.messaging_ed.pop_event(EventMmsSentSuccess,
3857                                             max_wait_time)
3858            except Empty:
3859                log.warning("No sent_success event.")
3860                if not sms_mms_send_logcat_check(ad_tx, "mms", begin_time):
3861                    return False
3862            if not wait_for_matching_mms(
3863                    log, ad_rx, phonenumber_tx, message,
3864                    begin_time=begin_time):
3865                return False
3866        finally:
3867            ad_rx.droid.smsStopTrackingIncomingMmsMessage()
3868    return True
3869
3870
3871def ensure_network_rat(log,
3872                       ad,
3873                       network_preference,
3874                       rat_family,
3875                       voice_or_data=None,
3876                       max_wait_time=MAX_WAIT_TIME_NW_SELECTION,
3877                       toggle_apm_after_setting=False):
3878    """Ensure ad's current network is in expected rat_family.
3879    """
3880    return ensure_network_rat_for_subscription(
3881        log, ad, ad.droid.subscriptionGetDefaultSubId(), network_preference,
3882        rat_family, voice_or_data, max_wait_time, toggle_apm_after_setting)
3883
3884
3885def ensure_network_rat_for_subscription(
3886        log,
3887        ad,
3888        sub_id,
3889        network_preference,
3890        rat_family,
3891        voice_or_data=None,
3892        max_wait_time=MAX_WAIT_TIME_NW_SELECTION,
3893        toggle_apm_after_setting=False):
3894    """Ensure ad's current network is in expected rat_family.
3895    """
3896    if not ad.droid.telephonySetPreferredNetworkTypesForSubscription(
3897            network_preference, sub_id):
3898        ad.log.error("Set sub_id %s Preferred Networks Type %s failed.",
3899                     sub_id, network_preference)
3900        return False
3901    if is_droid_in_rat_family_for_subscription(log, ad, sub_id, rat_family,
3902                                               voice_or_data):
3903        ad.log.info("Sub_id %s in RAT %s for %s", sub_id, rat_family,
3904                    voice_or_data)
3905        return True
3906
3907    if toggle_apm_after_setting:
3908        toggle_airplane_mode(log, ad, new_state=True, strict_checking=False)
3909        time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
3910        toggle_airplane_mode(log, ad, new_state=None, strict_checking=False)
3911
3912    result = wait_for_network_rat_for_subscription(
3913        log, ad, sub_id, rat_family, max_wait_time, voice_or_data)
3914
3915    log.info(
3916        "End of ensure_network_rat_for_subscription for %s. "
3917        "Setting to %s, Expecting %s %s. Current: voice: %s(family: %s), "
3918        "data: %s(family: %s)", ad.serial, network_preference, rat_family,
3919        voice_or_data,
3920        ad.droid.telephonyGetCurrentVoiceNetworkTypeForSubscription(sub_id),
3921        rat_family_from_rat(
3922            ad.droid.telephonyGetCurrentVoiceNetworkTypeForSubscription(
3923                sub_id)),
3924        ad.droid.telephonyGetCurrentDataNetworkTypeForSubscription(sub_id),
3925        rat_family_from_rat(
3926            ad.droid.telephonyGetCurrentDataNetworkTypeForSubscription(
3927                sub_id)))
3928    return result
3929
3930
3931def ensure_network_preference(log,
3932                              ad,
3933                              network_preference,
3934                              voice_or_data=None,
3935                              max_wait_time=MAX_WAIT_TIME_NW_SELECTION,
3936                              toggle_apm_after_setting=False):
3937    """Ensure that current rat is within the device's preferred network rats.
3938    """
3939    return ensure_network_preference_for_subscription(
3940        log, ad, ad.droid.subscriptionGetDefaultSubId(), network_preference,
3941        voice_or_data, max_wait_time, toggle_apm_after_setting)
3942
3943
3944def ensure_network_preference_for_subscription(
3945        log,
3946        ad,
3947        sub_id,
3948        network_preference,
3949        voice_or_data=None,
3950        max_wait_time=MAX_WAIT_TIME_NW_SELECTION,
3951        toggle_apm_after_setting=False):
3952    """Ensure ad's network preference is <network_preference> for sub_id.
3953    """
3954    rat_family_list = rat_families_for_network_preference(network_preference)
3955    if not ad.droid.telephonySetPreferredNetworkTypesForSubscription(
3956            network_preference, sub_id):
3957        log.error("Set Preferred Networks failed.")
3958        return False
3959    if is_droid_in_rat_family_list_for_subscription(
3960            log, ad, sub_id, rat_family_list, voice_or_data):
3961        return True
3962
3963    if toggle_apm_after_setting:
3964        toggle_airplane_mode(log, ad, new_state=True, strict_checking=False)
3965        time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
3966        toggle_airplane_mode(log, ad, new_state=False, strict_checking=False)
3967
3968    result = wait_for_preferred_network_for_subscription(
3969        log, ad, sub_id, network_preference, max_wait_time, voice_or_data)
3970
3971    ad.log.info(
3972        "End of ensure_network_preference_for_subscription. "
3973        "Setting to %s, Expecting %s %s. Current: voice: %s(family: %s), "
3974        "data: %s(family: %s)", network_preference, rat_family_list,
3975        voice_or_data,
3976        ad.droid.telephonyGetCurrentVoiceNetworkTypeForSubscription(sub_id),
3977        rat_family_from_rat(
3978            ad.droid.telephonyGetCurrentVoiceNetworkTypeForSubscription(
3979                sub_id)),
3980        ad.droid.telephonyGetCurrentDataNetworkTypeForSubscription(sub_id),
3981        rat_family_from_rat(
3982            ad.droid.telephonyGetCurrentDataNetworkTypeForSubscription(
3983                sub_id)))
3984    return result
3985
3986
3987def ensure_network_generation(log,
3988                              ad,
3989                              generation,
3990                              max_wait_time=MAX_WAIT_TIME_NW_SELECTION,
3991                              voice_or_data=None,
3992                              toggle_apm_after_setting=False):
3993    """Ensure ad's network is <network generation> for default subscription ID.
3994
3995    Set preferred network generation to <generation>.
3996    Toggle ON/OFF airplane mode if necessary.
3997    Wait for ad in expected network type.
3998    """
3999    return ensure_network_generation_for_subscription(
4000        log, ad, ad.droid.subscriptionGetDefaultSubId(), generation,
4001        max_wait_time, voice_or_data, toggle_apm_after_setting)
4002
4003
4004def ensure_network_generation_for_subscription(
4005        log,
4006        ad,
4007        sub_id,
4008        generation,
4009        max_wait_time=MAX_WAIT_TIME_NW_SELECTION,
4010        voice_or_data=None,
4011        toggle_apm_after_setting=False):
4012    """Ensure ad's network is <network generation> for specified subscription ID.
4013
4014    Set preferred network generation to <generation>.
4015    Toggle ON/OFF airplane mode if necessary.
4016    Wait for ad in expected network type.
4017    """
4018    ad.log.info(
4019        "RAT network type voice: %s, data: %s",
4020        ad.droid.telephonyGetCurrentVoiceNetworkTypeForSubscription(sub_id),
4021        ad.droid.telephonyGetCurrentDataNetworkTypeForSubscription(sub_id))
4022
4023    try:
4024        ad.log.info("Finding the network preference for generation %s for "
4025                    "operator %s phone type %s", generation,
4026                    ad.cfg["subscription"][sub_id]["operator"],
4027                    ad.cfg["subscription"][sub_id]["phone_type"])
4028        network_preference = network_preference_for_generation(
4029            generation, ad.cfg["subscription"][sub_id]["operator"],
4030            ad.cfg["subscription"][sub_id]["phone_type"])
4031        ad.log.info("Network preference for %s is %s", generation,
4032                    network_preference)
4033        rat_family = rat_family_for_generation(
4034            generation, ad.cfg["subscription"][sub_id]["operator"],
4035            ad.cfg["subscription"][sub_id]["phone_type"])
4036    except KeyError as e:
4037        ad.log.error("Failed to find a rat_family entry for generation %s"
4038                     " for subscriber %s with error %s", generation,
4039                     ad.cfg["subscription"][sub_id], e)
4040        return False
4041
4042    current_network_preference = \
4043            ad.droid.telephonyGetPreferredNetworkTypesForSubscription(
4044                sub_id)
4045    for _ in range(3):
4046        if current_network_preference == network_preference:
4047            break
4048        if not ad.droid.telephonySetPreferredNetworkTypesForSubscription(
4049                network_preference, sub_id):
4050            ad.log.info(
4051                "Network preference is %s. Set Preferred Networks to %s failed.",
4052                current_network_preference, network_preference)
4053            reasons = ad.search_logcat(
4054                "REQUEST_SET_PREFERRED_NETWORK_TYPE error")
4055            if reasons:
4056                reason_log = reasons[-1]["log_message"]
4057                ad.log.info(reason_log)
4058                if "DEVICE_IN_USE" in reason_log:
4059                    time.sleep(5)
4060                else:
4061                    ad.log.error("Failed to set Preferred Networks to %s",
4062                                 network_preference)
4063                    return False
4064            else:
4065                ad.log.error("Failed to set Preferred Networks to %s",
4066                             network_preference)
4067                return False
4068
4069    if is_droid_in_network_generation_for_subscription(
4070            log, ad, sub_id, generation, voice_or_data):
4071        return True
4072
4073    if toggle_apm_after_setting:
4074        toggle_airplane_mode(log, ad, new_state=True, strict_checking=False)
4075        time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
4076        toggle_airplane_mode(log, ad, new_state=False, strict_checking=False)
4077
4078    result = wait_for_network_generation_for_subscription(
4079        log, ad, sub_id, generation, max_wait_time, voice_or_data)
4080
4081    ad.log.info(
4082        "Ensure network %s %s %s. With network preference %s, "
4083        "current: voice: %s(family: %s), data: %s(family: %s)", generation,
4084        voice_or_data, result, network_preference,
4085        ad.droid.telephonyGetCurrentVoiceNetworkTypeForSubscription(sub_id),
4086        rat_generation_from_rat(
4087            ad.droid.telephonyGetCurrentVoiceNetworkTypeForSubscription(
4088                sub_id)),
4089        ad.droid.telephonyGetCurrentDataNetworkTypeForSubscription(sub_id),
4090        rat_generation_from_rat(
4091            ad.droid.telephonyGetCurrentDataNetworkTypeForSubscription(
4092                sub_id)))
4093    if not result:
4094        ad.log.info("singal strength = %s", get_telephony_signal_strength(ad))
4095    return result
4096
4097
4098def wait_for_network_rat(log,
4099                         ad,
4100                         rat_family,
4101                         max_wait_time=MAX_WAIT_TIME_NW_SELECTION,
4102                         voice_or_data=None):
4103    return wait_for_network_rat_for_subscription(
4104        log, ad, ad.droid.subscriptionGetDefaultSubId(), rat_family,
4105        max_wait_time, voice_or_data)
4106
4107
4108def wait_for_network_rat_for_subscription(
4109        log,
4110        ad,
4111        sub_id,
4112        rat_family,
4113        max_wait_time=MAX_WAIT_TIME_NW_SELECTION,
4114        voice_or_data=None):
4115    return _wait_for_droid_in_state_for_subscription(
4116        log, ad, sub_id, max_wait_time,
4117        is_droid_in_rat_family_for_subscription, rat_family, voice_or_data)
4118
4119
4120def wait_for_not_network_rat(log,
4121                             ad,
4122                             rat_family,
4123                             max_wait_time=MAX_WAIT_TIME_NW_SELECTION,
4124                             voice_or_data=None):
4125    return wait_for_not_network_rat_for_subscription(
4126        log, ad, ad.droid.subscriptionGetDefaultSubId(), rat_family,
4127        max_wait_time, voice_or_data)
4128
4129
4130def wait_for_not_network_rat_for_subscription(
4131        log,
4132        ad,
4133        sub_id,
4134        rat_family,
4135        max_wait_time=MAX_WAIT_TIME_NW_SELECTION,
4136        voice_or_data=None):
4137    return _wait_for_droid_in_state_for_subscription(
4138        log, ad, sub_id, max_wait_time,
4139        lambda log, ad, sub_id, *args, **kwargs: not is_droid_in_rat_family_for_subscription(log, ad, sub_id, rat_family, voice_or_data)
4140    )
4141
4142
4143def wait_for_preferred_network(log,
4144                               ad,
4145                               network_preference,
4146                               max_wait_time=MAX_WAIT_TIME_NW_SELECTION,
4147                               voice_or_data=None):
4148    return wait_for_preferred_network_for_subscription(
4149        log, ad, ad.droid.subscriptionGetDefaultSubId(), network_preference,
4150        max_wait_time, voice_or_data)
4151
4152
4153def wait_for_preferred_network_for_subscription(
4154        log,
4155        ad,
4156        sub_id,
4157        network_preference,
4158        max_wait_time=MAX_WAIT_TIME_NW_SELECTION,
4159        voice_or_data=None):
4160    rat_family_list = rat_families_for_network_preference(network_preference)
4161    return _wait_for_droid_in_state_for_subscription(
4162        log, ad, sub_id, max_wait_time,
4163        is_droid_in_rat_family_list_for_subscription, rat_family_list,
4164        voice_or_data)
4165
4166
4167def wait_for_network_generation(log,
4168                                ad,
4169                                generation,
4170                                max_wait_time=MAX_WAIT_TIME_NW_SELECTION,
4171                                voice_or_data=None):
4172    return wait_for_network_generation_for_subscription(
4173        log, ad, ad.droid.subscriptionGetDefaultSubId(), generation,
4174        max_wait_time, voice_or_data)
4175
4176
4177def wait_for_network_generation_for_subscription(
4178        log,
4179        ad,
4180        sub_id,
4181        generation,
4182        max_wait_time=MAX_WAIT_TIME_NW_SELECTION,
4183        voice_or_data=None):
4184    return _wait_for_droid_in_state_for_subscription(
4185        log, ad, sub_id, max_wait_time,
4186        is_droid_in_network_generation_for_subscription, generation,
4187        voice_or_data)
4188
4189
4190def is_droid_in_rat_family(log, ad, rat_family, voice_or_data=None):
4191    return is_droid_in_rat_family_for_subscription(
4192        log, ad, ad.droid.subscriptionGetDefaultSubId(), rat_family,
4193        voice_or_data)
4194
4195
4196def is_droid_in_rat_family_for_subscription(log,
4197                                            ad,
4198                                            sub_id,
4199                                            rat_family,
4200                                            voice_or_data=None):
4201    return is_droid_in_rat_family_list_for_subscription(
4202        log, ad, sub_id, [rat_family], voice_or_data)
4203
4204
4205def is_droid_in_rat_familiy_list(log, ad, rat_family_list, voice_or_data=None):
4206    return is_droid_in_rat_family_list_for_subscription(
4207        log, ad, ad.droid.subscriptionGetDefaultSubId(), rat_family_list,
4208        voice_or_data)
4209
4210
4211def is_droid_in_rat_family_list_for_subscription(log,
4212                                                 ad,
4213                                                 sub_id,
4214                                                 rat_family_list,
4215                                                 voice_or_data=None):
4216    service_list = [NETWORK_SERVICE_DATA, NETWORK_SERVICE_VOICE]
4217    if voice_or_data:
4218        service_list = [voice_or_data]
4219
4220    for service in service_list:
4221        nw_rat = get_network_rat_for_subscription(log, ad, sub_id, service)
4222        if nw_rat == RAT_UNKNOWN or not is_valid_rat(nw_rat):
4223            continue
4224        if rat_family_from_rat(nw_rat) in rat_family_list:
4225            return True
4226    return False
4227
4228
4229def is_droid_in_network_generation(log, ad, nw_gen, voice_or_data):
4230    """Checks if a droid in expected network generation ("2g", "3g" or "4g").
4231
4232    Args:
4233        log: log object.
4234        ad: android device.
4235        nw_gen: expected generation "4g", "3g", "2g".
4236        voice_or_data: check voice network generation or data network generation
4237            This parameter is optional. If voice_or_data is None, then if
4238            either voice or data in expected generation, function will return True.
4239
4240    Returns:
4241        True if droid in expected network generation. Otherwise False.
4242    """
4243    return is_droid_in_network_generation_for_subscription(
4244        log, ad, ad.droid.subscriptionGetDefaultSubId(), nw_gen, voice_or_data)
4245
4246
4247def is_droid_in_network_generation_for_subscription(log, ad, sub_id, nw_gen,
4248                                                    voice_or_data):
4249    """Checks if a droid in expected network generation ("2g", "3g" or "4g").
4250
4251    Args:
4252        log: log object.
4253        ad: android device.
4254        nw_gen: expected generation "4g", "3g", "2g".
4255        voice_or_data: check voice network generation or data network generation
4256            This parameter is optional. If voice_or_data is None, then if
4257            either voice or data in expected generation, function will return True.
4258
4259    Returns:
4260        True if droid in expected network generation. Otherwise False.
4261    """
4262    service_list = [NETWORK_SERVICE_DATA, NETWORK_SERVICE_VOICE]
4263
4264    if voice_or_data:
4265        service_list = [voice_or_data]
4266
4267    for service in service_list:
4268        nw_rat = get_network_rat_for_subscription(log, ad, sub_id, service)
4269        ad.log.info("%s network rat is %s", service, nw_rat)
4270        if nw_rat == RAT_UNKNOWN or not is_valid_rat(nw_rat):
4271            continue
4272
4273        if rat_generation_from_rat(nw_rat) == nw_gen:
4274            ad.log.info("%s network rat %s is expected %s", service, nw_rat,
4275                        nw_gen)
4276            return True
4277        else:
4278            ad.log.info("%s network rat %s is %s, does not meet expected %s",
4279                        service, nw_rat, rat_generation_from_rat(nw_rat),
4280                        nw_gen)
4281            return False
4282
4283    return False
4284
4285
4286def get_network_rat(log, ad, voice_or_data):
4287    """Get current network type (Voice network type, or data network type)
4288       for default subscription id
4289
4290    Args:
4291        ad: Android Device Object
4292        voice_or_data: Input parameter indicating to get voice network type or
4293            data network type.
4294
4295    Returns:
4296        Current voice/data network type.
4297    """
4298    return get_network_rat_for_subscription(
4299        log, ad, ad.droid.subscriptionGetDefaultSubId(), voice_or_data)
4300
4301
4302def get_network_rat_for_subscription(log, ad, sub_id, voice_or_data):
4303    """Get current network type (Voice network type, or data network type)
4304       for specified subscription id
4305
4306    Args:
4307        ad: Android Device Object
4308        sub_id: subscription ID
4309        voice_or_data: Input parameter indicating to get voice network type or
4310            data network type.
4311
4312    Returns:
4313        Current voice/data network type.
4314    """
4315    if voice_or_data == NETWORK_SERVICE_VOICE:
4316        ret_val = ad.droid.telephonyGetCurrentVoiceNetworkTypeForSubscription(
4317            sub_id)
4318    elif voice_or_data == NETWORK_SERVICE_DATA:
4319        ret_val = ad.droid.telephonyGetCurrentDataNetworkTypeForSubscription(
4320            sub_id)
4321    else:
4322        ret_val = ad.droid.telephonyGetNetworkTypeForSubscription(sub_id)
4323
4324    if ret_val is None:
4325        log.error("get_network_rat(): Unexpected null return value")
4326        return RAT_UNKNOWN
4327    else:
4328        return ret_val
4329
4330
4331def get_network_gen(log, ad, voice_or_data):
4332    """Get current network generation string (Voice network type, or data network type)
4333
4334    Args:
4335        ad: Android Device Object
4336        voice_or_data: Input parameter indicating to get voice network generation
4337            or data network generation.
4338
4339    Returns:
4340        Current voice/data network generation.
4341    """
4342    return get_network_gen_for_subscription(
4343        log, ad, ad.droid.subscriptionGetDefaultSubId(), voice_or_data)
4344
4345
4346def get_network_gen_for_subscription(log, ad, sub_id, voice_or_data):
4347    """Get current network generation string (Voice network type, or data network type)
4348
4349    Args:
4350        ad: Android Device Object
4351        voice_or_data: Input parameter indicating to get voice network generation
4352            or data network generation.
4353
4354    Returns:
4355        Current voice/data network generation.
4356    """
4357    try:
4358        return rat_generation_from_rat(
4359            get_network_rat_for_subscription(log, ad, sub_id, voice_or_data))
4360    except KeyError as e:
4361        ad.log.error("KeyError %s", e)
4362        return GEN_UNKNOWN
4363
4364
4365def check_voice_mail_count(log, ad, voice_mail_count_before,
4366                           voice_mail_count_after):
4367    """function to check if voice mail count is correct after leaving a new voice message.
4368    """
4369    return get_voice_mail_count_check_function(get_operator_name(log, ad))(
4370        voice_mail_count_before, voice_mail_count_after)
4371
4372
4373def get_voice_mail_number(log, ad):
4374    """function to get the voice mail number
4375    """
4376    voice_mail_number = get_voice_mail_check_number(get_operator_name(log, ad))
4377    if voice_mail_number is None:
4378        return get_phone_number(log, ad)
4379    return voice_mail_number
4380
4381
4382def ensure_phones_idle(log, ads, max_time=MAX_WAIT_TIME_CALL_DROP):
4383    """Ensure ads idle (not in call).
4384    """
4385    result = True
4386    for ad in ads:
4387        if not ensure_phone_idle(log, ad, max_time=max_time):
4388            result = False
4389    return result
4390
4391
4392def ensure_phone_idle(log, ad, max_time=MAX_WAIT_TIME_CALL_DROP):
4393    """Ensure ad idle (not in call).
4394    """
4395    if ad.droid.telecomIsInCall():
4396        ad.droid.telecomEndCall()
4397    if not wait_for_droid_not_in_call(log, ad, max_time=max_time):
4398        ad.log.error("Failed to end call")
4399        return False
4400    return True
4401
4402
4403def ensure_phone_subscription(log, ad):
4404    """Ensure Phone Subscription.
4405    """
4406    #check for sim and service
4407    duration = 0
4408    while duration < MAX_WAIT_TIME_NW_SELECTION:
4409        subInfo = ad.droid.subscriptionGetAllSubInfoList()
4410        if subInfo and len(subInfo) >= 1:
4411            ad.log.debug("Find valid subcription %s", subInfo)
4412            break
4413        else:
4414            ad.log.info("Did not find a valid subscription")
4415            time.sleep(5)
4416            duration += 5
4417    else:
4418        ad.log.error("Unable to find A valid subscription!")
4419        return False
4420    if ad.droid.subscriptionGetDefaultDataSubId() <= INVALID_SUB_ID and (
4421            ad.droid.subscriptionGetDefaultVoiceSubId() <= INVALID_SUB_ID):
4422        ad.log.error("No Valid Voice or Data Sub ID")
4423        return False
4424    voice_sub_id = ad.droid.subscriptionGetDefaultVoiceSubId()
4425    data_sub_id = ad.droid.subscriptionGetDefaultVoiceSubId()
4426    if not wait_for_voice_attach_for_subscription(
4427            log, ad, voice_sub_id, MAX_WAIT_TIME_NW_SELECTION -
4428            duration) and not wait_for_data_attach_for_subscription(
4429                log, ad, data_sub_id, MAX_WAIT_TIME_NW_SELECTION - duration):
4430        ad.log.error("Did Not Attach For Voice or Data Services")
4431        return False
4432    return True
4433
4434
4435def ensure_phone_default_state(log, ad, check_subscription=True):
4436    """Ensure ad in default state.
4437    Phone not in call.
4438    Phone have no stored WiFi network and WiFi disconnected.
4439    Phone not in airplane mode.
4440    """
4441    result = True
4442    if not toggle_airplane_mode(log, ad, False, False):
4443        ad.log.error("Fail to turn off airplane mode")
4444        result = False
4445    try:
4446        set_wifi_to_default(log, ad)
4447        if ad.droid.telecomIsInCall():
4448            ad.droid.telecomEndCall()
4449            if not wait_for_droid_not_in_call(log, ad):
4450                ad.log.error("Failed to end call")
4451        ad.droid.telephonyFactoryReset()
4452        ad.droid.imsFactoryReset()
4453        data_roaming = getattr(ad, 'roaming', False)
4454        if get_cell_data_roaming_state_by_adb(ad) != data_roaming:
4455            set_cell_data_roaming_state_by_adb(ad, data_roaming)
4456        remove_mobile_data_usage_limit(ad)
4457        if not wait_for_not_network_rat(
4458                log, ad, RAT_FAMILY_WLAN, voice_or_data=NETWORK_SERVICE_DATA):
4459            ad.log.error("%s still in %s", NETWORK_SERVICE_DATA,
4460                         RAT_FAMILY_WLAN)
4461            result = False
4462
4463        if check_subscription and not ensure_phone_subscription(log, ad):
4464            ad.log.error("Unable to find a valid subscription!")
4465            result = False
4466    except Exception as e:
4467        ad.log.error("%s failure, toggle APM instead", e)
4468        toggle_airplane_mode_by_adb(log, ad, True)
4469        toggle_airplane_mode_by_adb(log, ad, False)
4470        ad.send_keycode("ENDCALL")
4471        ad.adb.shell("settings put global wfc_ims_enabled 0")
4472        ad.adb.shell("settings put global mobile_data 1")
4473
4474    return result
4475
4476
4477def ensure_phones_default_state(log, ads, check_subscription=True):
4478    """Ensure ads in default state.
4479    Phone not in call.
4480    Phone have no stored WiFi network and WiFi disconnected.
4481    Phone not in airplane mode.
4482
4483    Returns:
4484        True if all steps of restoring default state succeed.
4485        False if any of the steps to restore default state fails.
4486    """
4487    tasks = []
4488    for ad in ads:
4489        tasks.append((ensure_phone_default_state, (log, ad,
4490                                                   check_subscription)))
4491    if not multithread_func(log, tasks):
4492        log.error("Ensure_phones_default_state Fail.")
4493        return False
4494    return True
4495
4496
4497def check_is_wifi_connected(log, ad, wifi_ssid):
4498    """Check if ad is connected to wifi wifi_ssid.
4499
4500    Args:
4501        log: Log object.
4502        ad: Android device object.
4503        wifi_ssid: WiFi network SSID.
4504
4505    Returns:
4506        True if wifi is connected to wifi_ssid
4507        False if wifi is not connected to wifi_ssid
4508    """
4509    wifi_info = ad.droid.wifiGetConnectionInfo()
4510    if wifi_info["supplicant_state"] == "completed" and wifi_info["SSID"] == wifi_ssid:
4511        ad.log.info("Wifi is connected to %s", wifi_ssid)
4512        ad.on_mobile_data = False
4513        return True
4514    else:
4515        ad.log.info("Wifi is not connected to %s", wifi_ssid)
4516        ad.log.debug("Wifi connection_info=%s", wifi_info)
4517        ad.on_mobile_data = True
4518        return False
4519
4520
4521def ensure_wifi_connected(log, ad, wifi_ssid, wifi_pwd=None, retries=3):
4522    """Ensure ad connected to wifi on network wifi_ssid.
4523
4524    Args:
4525        log: Log object.
4526        ad: Android device object.
4527        wifi_ssid: WiFi network SSID.
4528        wifi_pwd: optional secure network password.
4529        retries: the number of retries.
4530
4531    Returns:
4532        True if wifi is connected to wifi_ssid
4533        False if wifi is not connected to wifi_ssid
4534    """
4535    network = {WIFI_SSID_KEY: wifi_ssid}
4536    if wifi_pwd:
4537        network[WIFI_PWD_KEY] = wifi_pwd
4538    for i in range(retries):
4539        if not ad.droid.wifiCheckState():
4540            ad.log.info("Wifi state is down. Turn on Wifi")
4541            ad.droid.wifiToggleState(True)
4542        if check_is_wifi_connected(log, ad, wifi_ssid):
4543            ad.log.info("Wifi is connected to %s", wifi_ssid)
4544            return True
4545        else:
4546            ad.log.info("Connecting to wifi %s", wifi_ssid)
4547            try:
4548                ad.droid.wifiConnectByConfig(network)
4549            except Exception:
4550                ad.log.info("Connecting to wifi by wifiConnect instead")
4551                ad.droid.wifiConnect(network)
4552            time.sleep(20)
4553            if check_is_wifi_connected(log, ad, wifi_ssid):
4554                ad.log.info("Connected to Wifi %s", wifi_ssid)
4555                return True
4556    ad.log.info("Fail to connected to wifi %s", wifi_ssid)
4557    return False
4558
4559
4560def forget_all_wifi_networks(log, ad):
4561    """Forget all stored wifi network information
4562
4563    Args:
4564        log: log object
4565        ad: AndroidDevice object
4566
4567    Returns:
4568        boolean success (True) or failure (False)
4569    """
4570    if not ad.droid.wifiGetConfiguredNetworks():
4571        ad.on_mobile_data = True
4572        return True
4573    try:
4574        old_state = ad.droid.wifiCheckState()
4575        wifi_test_utils.reset_wifi(ad)
4576        wifi_toggle_state(log, ad, old_state)
4577    except Exception as e:
4578        log.error("forget_all_wifi_networks with exception: %s", e)
4579        return False
4580    ad.on_mobile_data = True
4581    return True
4582
4583
4584def wifi_reset(log, ad, disable_wifi=True):
4585    """Forget all stored wifi networks and (optionally) disable WiFi
4586
4587    Args:
4588        log: log object
4589        ad: AndroidDevice object
4590        disable_wifi: boolean to disable wifi, defaults to True
4591    Returns:
4592        boolean success (True) or failure (False)
4593    """
4594    if not forget_all_wifi_networks(log, ad):
4595        ad.log.error("Unable to forget all networks")
4596        return False
4597    if not wifi_toggle_state(log, ad, not disable_wifi):
4598        ad.log.error("Failed to toggle WiFi state to %s!", not disable_wifi)
4599        return False
4600    return True
4601
4602
4603def set_wifi_to_default(log, ad):
4604    """Set wifi to default state (Wifi disabled and no configured network)
4605
4606    Args:
4607        log: log object
4608        ad: AndroidDevice object
4609
4610    Returns:
4611        boolean success (True) or failure (False)
4612    """
4613    ad.droid.wifiFactoryReset()
4614    ad.droid.wifiToggleState(False)
4615    ad.on_mobile_data = True
4616
4617
4618def wifi_toggle_state(log, ad, state, retries=3):
4619    """Toggle the WiFi State
4620
4621    Args:
4622        log: log object
4623        ad: AndroidDevice object
4624        state: True, False, or None
4625
4626    Returns:
4627        boolean success (True) or failure (False)
4628    """
4629    for i in range(retries):
4630        if wifi_test_utils.wifi_toggle_state(ad, state, assert_on_fail=False):
4631            ad.on_mobile_data = not state
4632            return True
4633        time.sleep(WAIT_TIME_BETWEEN_STATE_CHECK)
4634    return False
4635
4636
4637def start_wifi_tethering(log, ad, ssid, password, ap_band=None):
4638    """Start a Tethering Session
4639
4640    Args:
4641        log: log object
4642        ad: AndroidDevice object
4643        ssid: the name of the WiFi network
4644        password: optional password, used for secure networks.
4645        ap_band=DEPRECATED specification of 2G or 5G tethering
4646    Returns:
4647        boolean success (True) or failure (False)
4648    """
4649    return wifi_test_utils._assert_on_fail_handler(
4650        wifi_test_utils.start_wifi_tethering,
4651        False,
4652        ad,
4653        ssid,
4654        password,
4655        band=ap_band)
4656
4657
4658def stop_wifi_tethering(log, ad):
4659    """Stop a Tethering Session
4660
4661    Args:
4662        log: log object
4663        ad: AndroidDevice object
4664    Returns:
4665        boolean success (True) or failure (False)
4666    """
4667    return wifi_test_utils._assert_on_fail_handler(
4668        wifi_test_utils.stop_wifi_tethering, False, ad)
4669
4670
4671def reset_preferred_network_type_to_allowable_range(log, ad):
4672    """If preferred network type is not in allowable range, reset to GEN_4G
4673    preferred network type.
4674
4675    Args:
4676        log: log object
4677        ad: android device object
4678
4679    Returns:
4680        None
4681    """
4682    for sub_id, sub_info in ad.cfg["subscription"].items():
4683        current_preference = \
4684            ad.droid.telephonyGetPreferredNetworkTypesForSubscription(sub_id)
4685        ad.log.debug("sub_id network preference is %s", current_preference)
4686        try:
4687            if current_preference not in get_allowable_network_preference(
4688                    sub_info["operator"], sub_info["phone_type"]):
4689                network_preference = network_preference_for_generation(
4690                    GEN_4G, sub_info["operator"], sub_info["phone_type"])
4691                ad.droid.telephonySetPreferredNetworkTypesForSubscription(
4692                    network_preference, sub_id)
4693        except KeyError:
4694            pass
4695
4696
4697def task_wrapper(task):
4698    """Task wrapper for multithread_func
4699
4700    Args:
4701        task[0]: function to be wrapped.
4702        task[1]: function args.
4703
4704    Returns:
4705        Return value of wrapped function call.
4706    """
4707    func = task[0]
4708    params = task[1]
4709    return func(*params)
4710
4711
4712def run_multithread_func_async(log, task):
4713    """Starts a multi-threaded function asynchronously.
4714
4715    Args:
4716        log: log object.
4717        task: a task to be executed in parallel.
4718
4719    Returns:
4720        Future object representing the execution of the task.
4721    """
4722    executor = concurrent.futures.ThreadPoolExecutor(max_workers=1)
4723    try:
4724        future_object = executor.submit(task_wrapper, task)
4725    except Exception as e:
4726        log.error("Exception error %s", e)
4727        raise
4728    return future_object
4729
4730
4731def run_multithread_func(log, tasks):
4732    """Run multi-thread functions and return results.
4733
4734    Args:
4735        log: log object.
4736        tasks: a list of tasks to be executed in parallel.
4737
4738    Returns:
4739        results for tasks.
4740    """
4741    MAX_NUMBER_OF_WORKERS = 10
4742    number_of_workers = min(MAX_NUMBER_OF_WORKERS, len(tasks))
4743    executor = concurrent.futures.ThreadPoolExecutor(
4744        max_workers=number_of_workers)
4745    if not log: log = logging
4746    try:
4747        results = list(executor.map(task_wrapper, tasks))
4748    except Exception as e:
4749        log.error("Exception error %s", e)
4750        raise
4751    executor.shutdown()
4752    if log:
4753        log.info("multithread_func %s result: %s",
4754                 [task[0].__name__ for task in tasks], results)
4755    return results
4756
4757
4758def multithread_func(log, tasks):
4759    """Multi-thread function wrapper.
4760
4761    Args:
4762        log: log object.
4763        tasks: tasks to be executed in parallel.
4764
4765    Returns:
4766        True if all tasks return True.
4767        False if any task return False.
4768    """
4769    results = run_multithread_func(log, tasks)
4770    for r in results:
4771        if not r:
4772            return False
4773    return True
4774
4775
4776def multithread_func_and_check_results(log, tasks, expected_results):
4777    """Multi-thread function wrapper.
4778
4779    Args:
4780        log: log object.
4781        tasks: tasks to be executed in parallel.
4782        expected_results: check if the results from tasks match expected_results.
4783
4784    Returns:
4785        True if expected_results are met.
4786        False if expected_results are not met.
4787    """
4788    return_value = True
4789    results = run_multithread_func(log, tasks)
4790    log.info("multithread_func result: %s, expecting %s", results,
4791             expected_results)
4792    for task, result, expected_result in zip(tasks, results, expected_results):
4793        if result != expected_result:
4794            logging.info("Result for task %s is %s, expecting %s", task[0],
4795                         result, expected_result)
4796            return_value = False
4797    return return_value
4798
4799
4800def set_phone_screen_on(log, ad, screen_on_time=MAX_SCREEN_ON_TIME):
4801    """Set phone screen on time.
4802
4803    Args:
4804        log: Log object.
4805        ad: Android device object.
4806        screen_on_time: screen on time.
4807            This is optional, default value is MAX_SCREEN_ON_TIME.
4808    Returns:
4809        True if set successfully.
4810    """
4811    ad.droid.setScreenTimeout(screen_on_time)
4812    return screen_on_time == ad.droid.getScreenTimeout()
4813
4814
4815def set_phone_silent_mode(log, ad, silent_mode=True):
4816    """Set phone silent mode.
4817
4818    Args:
4819        log: Log object.
4820        ad: Android device object.
4821        silent_mode: set phone silent or not.
4822            This is optional, default value is True (silent mode on).
4823    Returns:
4824        True if set successfully.
4825    """
4826    ad.droid.toggleRingerSilentMode(silent_mode)
4827    ad.droid.setMediaVolume(0)
4828    ad.droid.setVoiceCallVolume(0)
4829    ad.droid.setAlarmVolume(0)
4830    out = ad.adb.shell("settings list system | grep volume")
4831    for attr in re.findall(r"(volume_.*)=\d+", out):
4832        ad.adb.shell("settings put system %s 0" % attr)
4833    return silent_mode == ad.droid.checkRingerSilentMode()
4834
4835
4836def set_preferred_network_mode_pref(log, ad, sub_id, network_preference):
4837    """Set Preferred Network Mode for Sub_id
4838    Args:
4839        log: Log object.
4840        ad: Android device object.
4841        sub_id: Subscription ID.
4842        network_preference: Network Mode Type
4843    """
4844    ad.log.info("Setting ModePref to %s for Sub %s", network_preference,
4845                sub_id)
4846    if not ad.droid.telephonySetPreferredNetworkTypesForSubscription(
4847            network_preference, sub_id):
4848        ad.log.error("Set sub_id %s PreferredNetworkType %s failed", sub_id,
4849                     network_preference)
4850        return False
4851    return True
4852
4853
4854def set_preferred_subid_for_sms(log, ad, sub_id):
4855    """set subscription id for SMS
4856
4857    Args:
4858        log: Log object.
4859        ad: Android device object.
4860        sub_id :Subscription ID.
4861
4862    """
4863    ad.log.info("Setting subscription %s as preferred SMS SIM", sub_id)
4864    ad.droid.subscriptionSetDefaultSmsSubId(sub_id)
4865    # Wait to make sure settings take effect
4866    time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
4867    return sub_id == ad.droid.subscriptionGetDefaultSmsSubId()
4868
4869
4870def set_preferred_subid_for_data(log, ad, sub_id):
4871    """set subscription id for data
4872
4873    Args:
4874        log: Log object.
4875        ad: Android device object.
4876        sub_id :Subscription ID.
4877
4878    """
4879    ad.log.info("Setting subscription %s as preferred Data SIM", sub_id)
4880    ad.droid.subscriptionSetDefaultDataSubId(sub_id)
4881    time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
4882    # Wait to make sure settings take effect
4883    # Data SIM change takes around 1 min
4884    # Check whether data has changed to selected sim
4885    if not wait_for_data_connection(log, ad, True,
4886                                    MAX_WAIT_TIME_DATA_SUB_CHANGE):
4887        log.error("Data Connection failed - Not able to switch Data SIM")
4888        return False
4889    return True
4890
4891
4892def set_preferred_subid_for_voice(log, ad, sub_id):
4893    """set subscription id for voice
4894
4895    Args:
4896        log: Log object.
4897        ad: Android device object.
4898        sub_id :Subscription ID.
4899
4900    """
4901    ad.log.info("Setting subscription %s as Voice SIM", sub_id)
4902    ad.droid.subscriptionSetDefaultVoiceSubId(sub_id)
4903    ad.droid.telecomSetUserSelectedOutgoingPhoneAccountBySubId(sub_id)
4904    # Wait to make sure settings take effect
4905    time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
4906    return True
4907
4908
4909def set_call_state_listen_level(log, ad, value, sub_id):
4910    """Set call state listen level for subscription id.
4911
4912    Args:
4913        log: Log object.
4914        ad: Android device object.
4915        value: True or False
4916        sub_id :Subscription ID.
4917
4918    Returns:
4919        True or False
4920    """
4921    if sub_id == INVALID_SUB_ID:
4922        log.error("Invalid Subscription ID")
4923        return False
4924    ad.droid.telephonyAdjustPreciseCallStateListenLevelForSubscription(
4925        "Foreground", value, sub_id)
4926    ad.droid.telephonyAdjustPreciseCallStateListenLevelForSubscription(
4927        "Ringing", value, sub_id)
4928    ad.droid.telephonyAdjustPreciseCallStateListenLevelForSubscription(
4929        "Background", value, sub_id)
4930    return True
4931
4932
4933def setup_sim(log, ad, sub_id, voice=False, sms=False, data=False):
4934    """set subscription id for voice, sms and data
4935
4936    Args:
4937        log: Log object.
4938        ad: Android device object.
4939        sub_id :Subscription ID.
4940        voice: True if to set subscription as default voice subscription
4941        sms: True if to set subscription as default sms subscription
4942        data: True if to set subscription as default data subscription
4943
4944    """
4945    if sub_id == INVALID_SUB_ID:
4946        log.error("Invalid Subscription ID")
4947        return False
4948    else:
4949        if voice:
4950            if not set_preferred_subid_for_voice(log, ad, sub_id):
4951                return False
4952        if sms:
4953            if not set_preferred_subid_for_sms(log, ad, sub_id):
4954                return False
4955        if data:
4956            if not set_preferred_subid_for_data(log, ad, sub_id):
4957                return False
4958    return True
4959
4960
4961def is_event_match(event, field, value):
4962    """Return if <field> in "event" match <value> or not.
4963
4964    Args:
4965        event: event to test. This event need to have <field>.
4966        field: field to match.
4967        value: value to match.
4968
4969    Returns:
4970        True if <field> in "event" match <value>.
4971        False otherwise.
4972    """
4973    return is_event_match_for_list(event, field, [value])
4974
4975
4976def is_event_match_for_list(event, field, value_list):
4977    """Return if <field> in "event" match any one of the value
4978        in "value_list" or not.
4979
4980    Args:
4981        event: event to test. This event need to have <field>.
4982        field: field to match.
4983        value_list: a list of value to match.
4984
4985    Returns:
4986        True if <field> in "event" match one of the value in "value_list".
4987        False otherwise.
4988    """
4989    try:
4990        value_in_event = event['data'][field]
4991    except KeyError:
4992        return False
4993    for value in value_list:
4994        if value_in_event == value:
4995            return True
4996    return False
4997
4998
4999def is_network_call_back_event_match(event, network_callback_id,
5000                                     network_callback_event):
5001    try:
5002        return (
5003            (network_callback_id == event['data'][NetworkCallbackContainer.ID])
5004            and (network_callback_event == event['data']
5005                 [NetworkCallbackContainer.NETWORK_CALLBACK_EVENT]))
5006    except KeyError:
5007        return False
5008
5009
5010def is_build_id(log, ad, build_id):
5011    """Return if ad's build id is the same as input parameter build_id.
5012
5013    Args:
5014        log: log object.
5015        ad: android device object.
5016        build_id: android build id.
5017
5018    Returns:
5019        True if ad's build id is the same as input parameter build_id.
5020        False otherwise.
5021    """
5022    actual_bid = ad.droid.getBuildID()
5023
5024    ad.log.info("BUILD DISPLAY: %s", ad.droid.getBuildDisplay())
5025    #In case we want to log more stuff/more granularity...
5026    #log.info("{} BUILD ID:{} ".format(ad.serial, ad.droid.getBuildID()))
5027    #log.info("{} BUILD FINGERPRINT: {} "
5028    # .format(ad.serial), ad.droid.getBuildFingerprint())
5029    #log.info("{} BUILD TYPE: {} "
5030    # .format(ad.serial), ad.droid.getBuildType())
5031    #log.info("{} BUILD NUMBER: {} "
5032    # .format(ad.serial), ad.droid.getBuildNumber())
5033    if actual_bid.upper() != build_id.upper():
5034        ad.log.error("%s: Incorrect Build ID", ad.model)
5035        return False
5036    return True
5037
5038
5039def is_uri_equivalent(uri1, uri2):
5040    """Check whether two input uris match or not.
5041
5042    Compare Uris.
5043        If Uris are tel URI, it will only take the digit part
5044        and compare as phone number.
5045        Else, it will just do string compare.
5046
5047    Args:
5048        uri1: 1st uri to be compared.
5049        uri2: 2nd uri to be compared.
5050
5051    Returns:
5052        True if two uris match. Otherwise False.
5053    """
5054
5055    #If either is None/empty we return false
5056    if not uri1 or not uri2:
5057        return False
5058
5059    try:
5060        if uri1.startswith('tel:') and uri2.startswith('tel:'):
5061            uri1_number = get_number_from_tel_uri(uri1)
5062            uri2_number = get_number_from_tel_uri(uri2)
5063            return check_phone_number_match(uri1_number, uri2_number)
5064        else:
5065            return uri1 == uri2
5066    except AttributeError as e:
5067        return False
5068
5069
5070def get_call_uri(ad, call_id):
5071    """Get call's uri field.
5072
5073    Get Uri for call_id in ad.
5074
5075    Args:
5076        ad: android device object.
5077        call_id: the call id to get Uri from.
5078
5079    Returns:
5080        call's Uri if call is active and have uri field. None otherwise.
5081    """
5082    try:
5083        call_detail = ad.droid.telecomCallGetDetails(call_id)
5084        return call_detail["Handle"]["Uri"]
5085    except:
5086        return None
5087
5088
5089def get_number_from_tel_uri(uri):
5090    """Get Uri number from tel uri
5091
5092    Args:
5093        uri: input uri
5094
5095    Returns:
5096        If input uri is tel uri, return the number part.
5097        else return None.
5098    """
5099    if uri.startswith('tel:'):
5100        uri_number = ''.join(
5101            i for i in urllib.parse.unquote(uri) if i.isdigit())
5102        return uri_number
5103    else:
5104        return None
5105
5106
5107def find_qxdm_log_mask(ad, mask="default.cfg"):
5108    """Find QXDM logger mask."""
5109    if "/" not in mask:
5110        # Call nexuslogger to generate log mask
5111        start_nexuslogger(ad)
5112        # Find the log mask path
5113        for path in (DEFAULT_QXDM_LOG_PATH, "/data/diag_logs",
5114                     "/vendor/etc/mdlog/"):
5115            out = ad.adb.shell(
5116                "find %s -type f -iname %s" % (path, mask), ignore_status=True)
5117            if out and "No such" not in out and "Permission denied" not in out:
5118                if path.startswith("/vendor/"):
5119                    ad.qxdm_log_path = DEFAULT_QXDM_LOG_PATH
5120                else:
5121                    ad.qxdm_log_path = path
5122                return out.split("\n")[0]
5123        if mask in ad.adb.shell("ls /vendor/etc/mdlog/"):
5124            ad.qxdm_log_path = DEFAULT_QXDM_LOG_PATH
5125            return "%s/%s" % ("/vendor/etc/mdlog/", mask)
5126    else:
5127        out = ad.adb.shell("ls %s" % mask, ignore_status=True)
5128        if out and "No such" not in out:
5129            ad.qxdm_log_path = "/data/vendor/radio/diag_logs"
5130            return mask
5131    ad.log.warning("Could NOT find QXDM logger mask path for %s", mask)
5132
5133
5134def set_qxdm_logger_command(ad, mask=None):
5135    """Set QXDM logger always on.
5136
5137    Args:
5138        ad: android device object.
5139
5140    """
5141    ## Neet to check if log mask will be generated without starting nexus logger
5142    masks = []
5143    mask_path = None
5144    if mask:
5145        masks = [mask]
5146    masks.extend(["QC_Default.cfg", "default.cfg"])
5147    for mask in masks:
5148        mask_path = find_qxdm_log_mask(ad, mask)
5149        if mask_path: break
5150    if not mask_path:
5151        ad.log.error("Cannot find QXDM mask %s", mask)
5152        ad.qxdm_logger_command = None
5153        return False
5154    else:
5155        ad.log.info("Use QXDM log mask %s", mask_path)
5156        ad.log.debug("qxdm_log_path = %s", ad.qxdm_log_path)
5157        output_path = os.path.join(ad.qxdm_log_path, "logs")
5158        ad.qxdm_logger_command = ("diag_mdlog -f %s -o %s -s 50 -c" %
5159                                  (mask_path, output_path))
5160        conf_path = os.path.join(ad.qxdm_log_path, "diag.conf")
5161        # Enable qxdm always on so that after device reboot, qxdm will be
5162        # turned on automatically
5163        ad.adb.shell('echo "%s" > %s' % (ad.qxdm_logger_command, conf_path))
5164        ad.adb.shell(
5165            "setprop persist.vendor.sys.modem.diag.mdlog true", ignore_status=True)
5166        # Legacy pixels use persist.sys.modem.diag.mdlog.
5167        ad.adb.shell(
5168            "setprop persist.sys.modem.diag.mdlog true", ignore_status=True)
5169        return True
5170
5171
5172def stop_qxdm_logger(ad):
5173    """Stop QXDM logger."""
5174    for cmd in ("diag_mdlog -k", "killall diag_mdlog"):
5175        output = ad.adb.shell("ps -ef | grep mdlog") or ""
5176        if "diag_mdlog" not in output:
5177            break
5178        ad.log.debug("Kill the existing qxdm process")
5179        ad.adb.shell(cmd, ignore_status=True)
5180        time.sleep(5)
5181
5182
5183def start_qxdm_logger(ad, begin_time=None):
5184    """Start QXDM logger."""
5185    if not getattr(ad, "qxdm_log", True): return
5186    # Delete existing QXDM logs 5 minutes earlier than the begin_time
5187    if getattr(ad, "qxdm_log_path", None):
5188        seconds = None
5189        if begin_time:
5190            current_time = get_current_epoch_time()
5191            seconds = int((current_time - begin_time) / 1000.0) + 10 * 60
5192        elif len(ad.get_file_names(ad.qxdm_log_path)) > 50:
5193            seconds = 900
5194        if seconds:
5195            ad.adb.shell(
5196                "find %s -type f -iname *.qmdl -not -mtime -%ss -delete" %
5197                (ad.qxdm_log_path, seconds))
5198    if getattr(ad, "qxdm_logger_command", None):
5199        output = ad.adb.shell("ps -ef | grep mdlog") or ""
5200        if ad.qxdm_logger_command not in output:
5201            ad.log.debug("QXDM logging command %s is not running",
5202                         ad.qxdm_logger_command)
5203            if "diag_mdlog" in output:
5204                # Kill the existing diag_mdlog process
5205                # Only one diag_mdlog process can be run
5206                stop_qxdm_logger(ad)
5207            ad.log.info("Start QXDM logger")
5208            ad.adb.shell_nb(ad.qxdm_logger_command)
5209        elif not ad.get_file_names(ad.qxdm_log_path, 60):
5210            ad.log.debug("Existing diag_mdlog is not generating logs")
5211            stop_qxdm_logger(ad)
5212            ad.adb.shell_nb(ad.qxdm_logger_command)
5213        return True
5214
5215
5216def start_qxdm_loggers(log, ads, begin_time=None):
5217    tasks = [(start_qxdm_logger, [ad, begin_time]) for ad in ads
5218             if getattr(ad, "qxdm_log", True)]
5219    if tasks: run_multithread_func(log, tasks)
5220
5221
5222def stop_qxdm_loggers(log, ads):
5223    tasks = [(stop_qxdm_logger, [ad]) for ad in ads]
5224    run_multithread_func(log, tasks)
5225
5226
5227def start_nexuslogger(ad):
5228    """Start Nexus/Pixel Logger Apk."""
5229    qxdm_logger_apk = None
5230    for apk, activity in (("com.android.nexuslogger", ".MainActivity"),
5231                          ("com.android.pixellogger",
5232                           ".ui.main.MainActivity")):
5233        if ad.is_apk_installed(apk):
5234            qxdm_logger_apk = apk
5235            break
5236    if not qxdm_logger_apk: return
5237    if ad.is_apk_running(qxdm_logger_apk):
5238        if "granted=true" in ad.adb.shell(
5239                "dumpsys package %s | grep WRITE_EXTERN" % qxdm_logger_apk):
5240            return True
5241        else:
5242            ad.log.info("Kill %s" % qxdm_logger_apk)
5243            ad.force_stop_apk(qxdm_logger_apk)
5244            time.sleep(5)
5245    for perm in ("READ", "WRITE"):
5246        ad.adb.shell("pm grant %s android.permission.%s_EXTERNAL_STORAGE" %
5247                     (qxdm_logger_apk, perm))
5248    time.sleep(2)
5249    for i in range(3):
5250        ad.log.info("Start %s Attempt %d" % (qxdm_logger_apk, i + 1))
5251        ad.adb.shell("am start -n %s/%s" % (qxdm_logger_apk, activity))
5252        time.sleep(5)
5253        if ad.is_apk_running(qxdm_logger_apk):
5254            ad.send_keycode("HOME")
5255            return True
5256    return False
5257
5258
5259def check_qxdm_logger_mask(ad, mask_file="QC_Default.cfg"):
5260    """Check if QXDM logger always on is set.
5261
5262    Args:
5263        ad: android device object.
5264
5265    """
5266    output = ad.adb.shell(
5267        "ls /data/vendor/radio/diag_logs/", ignore_status=True)
5268    if not output or "No such" in output:
5269        return True
5270    if mask_file not in ad.adb.shell(
5271            "cat /data/vendor/radio/diag_logs/diag.conf", ignore_status=True):
5272        return False
5273    return True
5274
5275
5276def start_adb_tcpdump(ad, test_name, mask="ims"):
5277    """Start tcpdump on any iface
5278
5279    Args:
5280        ad: android device object.
5281        test_name: tcpdump file name will have this
5282
5283    """
5284    ad.log.debug("Ensuring no tcpdump is running in background")
5285    try:
5286        ad.adb.shell("killall -9 tcpdump")
5287    except AdbError:
5288        ad.log.warn("Killing existing tcpdump processes failed")
5289    out = ad.adb.shell("ls -l /sdcard/tcpdump/")
5290    if "No such file" in out or not out:
5291        ad.adb.shell("mkdir /sdcard/tcpdump")
5292    else:
5293        ad.adb.shell("rm -rf /sdcard/tcpdump/*", ignore_status=True)
5294
5295    begin_time = epoch_to_log_line_timestamp(get_current_epoch_time())
5296    begin_time = normalize_log_line_timestamp(begin_time)
5297
5298    file_name = "/sdcard/tcpdump/tcpdump_%s_%s_%s.pcap" % (ad.serial,
5299                                                           test_name,
5300                                                           begin_time)
5301    ad.log.info("tcpdump file is %s", file_name)
5302    if mask == "all":
5303        cmd = "adb -s {} shell tcpdump -i any -s0 -w {}" . \
5304                  format(ad.serial, file_name)
5305    else:
5306        cmd = "adb -s {} shell tcpdump -i any -s0 -n -p udp port 500 or \
5307              udp port 4500 -w {}".format(ad.serial, file_name)
5308    ad.log.debug("%s" % cmd)
5309    return start_standing_subprocess(cmd, 5)
5310
5311
5312def stop_adb_tcpdump(ad, proc=None, pull_tcpdump=False, test_name=""):
5313    """Stops tcpdump on any iface
5314       Pulls the tcpdump file in the tcpdump dir
5315
5316    Args:
5317        ad: android device object.
5318        tcpdump_pid: need to know which pid to stop
5319        tcpdump_file: filename needed to pull out
5320
5321    """
5322    ad.log.info("Stopping and pulling tcpdump if any")
5323    try:
5324        if proc is not None:
5325            stop_standing_subprocess(proc)
5326    except Exception as e:
5327        ad.log.warning(e)
5328    if pull_tcpdump:
5329        log_path = os.path.join(ad.log_path, test_name,
5330                                "TCPDUMP_%s" % ad.serial)
5331        utils.create_dir(log_path)
5332        ad.adb.pull("/sdcard/tcpdump/. %s" % log_path)
5333    ad.adb.shell("rm -rf /sdcard/tcpdump/*", ignore_status=True)
5334    return True
5335
5336
5337def fastboot_wipe(ad, skip_setup_wizard=True):
5338    """Wipe the device in fastboot mode.
5339
5340    Pull sl4a apk from device. Terminate all sl4a sessions,
5341    Reboot the device to bootloader, wipe the device by fastboot.
5342    Reboot the device. wait for device to complete booting
5343    Re-intall and start an sl4a session.
5344    """
5345    status = True
5346    # Pull sl4a apk from device
5347    out = ad.adb.shell("pm path %s" % SL4A_APK_NAME)
5348    result = re.search(r"package:(.*)", out)
5349    if not result:
5350        ad.log.error("Couldn't find sl4a apk")
5351    else:
5352        sl4a_apk = result.group(1)
5353        ad.log.info("Get sl4a apk from %s", sl4a_apk)
5354        ad.pull_files([sl4a_apk], "/tmp/")
5355    ad.stop_services()
5356    ad.log.info("Reboot to bootloader")
5357    ad.adb.reboot_bootloader(ignore_status=True)
5358    ad.log.info("Wipe in fastboot")
5359    try:
5360        ad.fastboot._w()
5361    except Exception as e:
5362        ad.log.error(e)
5363        status = False
5364    time.sleep(30)  #sleep time after fastboot wipe
5365    for _ in range(2):
5366        try:
5367            ad.log.info("Reboot in fastboot")
5368            ad.fastboot.reboot()
5369            ad.wait_for_boot_completion()
5370            break
5371        except Exception as e:
5372            ad.log.error("Exception error %s", e)
5373    ad.root_adb()
5374    if result:
5375        # Try to reinstall for three times as the device might not be
5376        # ready to apk install shortly after boot complete.
5377        for _ in range(3):
5378            if ad.is_sl4a_installed():
5379                break
5380            ad.log.info("Re-install sl4a")
5381            ad.adb.install("-r /tmp/base.apk", ignore_status=True)
5382            time.sleep(10)
5383    try:
5384        ad.start_adb_logcat()
5385    except:
5386        ad.log.exception("Failed to start adb logcat!")
5387    if skip_setup_wizard:
5388        ad.exit_setup_wizard()
5389    if ad.skip_sl4a: return status
5390    bring_up_sl4a(ad)
5391
5392    return status
5393
5394
5395def bring_up_sl4a(ad, attemps=3):
5396    for i in range(attemps):
5397        try:
5398            droid, ed = ad.get_droid()
5399            ed.start()
5400            ad.log.info("Broght up new sl4a session")
5401        except Exception as e:
5402            if i < attemps - 1:
5403                ad.log.info(e)
5404                time.sleep(10)
5405            else:
5406                ad.log.error(e)
5407                raise
5408
5409
5410def reboot_device(ad):
5411    ad.reboot()
5412    ad.ensure_screen_on()
5413    unlock_sim(ad)
5414
5415
5416def unlocking_device(ad, device_password=None):
5417    """First unlock device attempt, required after reboot"""
5418    ad.unlock_screen(device_password)
5419    time.sleep(2)
5420    ad.adb.wait_for_device(timeout=180)
5421    if not ad.is_waiting_for_unlock_pin():
5422        return True
5423    else:
5424        ad.unlock_screen(device_password)
5425        time.sleep(2)
5426        ad.adb.wait_for_device(timeout=180)
5427        if ad.wait_for_window_ready():
5428            return True
5429    ad.log.error("Unable to unlock to user window")
5430    return False
5431
5432
5433def refresh_sl4a_session(ad):
5434    try:
5435        ad.droid.logI("Checking SL4A connection")
5436        ad.log.info("Existing sl4a session is active")
5437    except:
5438        ad.terminate_all_sessions()
5439        ad.ensure_screen_on()
5440        ad.log.info("Open new sl4a connection")
5441        bring_up_sl4a(ad)
5442
5443
5444def reset_device_password(ad, device_password=None):
5445    # Enable or Disable Device Password per test bed config
5446    unlock_sim(ad)
5447    screen_lock = ad.is_screen_lock_enabled()
5448    if device_password:
5449        try:
5450            refresh_sl4a_session(ad)
5451            ad.droid.setDevicePassword(device_password)
5452        except Exception as e:
5453            ad.log.warning("setDevicePassword failed with %s", e)
5454            try:
5455                ad.droid.setDevicePassword(device_password, "1111")
5456            except Exception as e:
5457                ad.log.warning(
5458                    "setDevicePassword providing previous password error: %s",
5459                    e)
5460        time.sleep(2)
5461        if screen_lock:
5462            # existing password changed
5463            return
5464        else:
5465            # enable device password and log in for the first time
5466            ad.log.info("Enable device password")
5467            ad.adb.wait_for_device(timeout=180)
5468    else:
5469        if not screen_lock:
5470            # no existing password, do not set password
5471            return
5472        else:
5473            # password is enabled on the device
5474            # need to disable the password and log in on the first time
5475            # with unlocking with a swipe
5476            ad.log.info("Disable device password")
5477            ad.unlock_screen(password="1111")
5478            refresh_sl4a_session(ad)
5479            ad.ensure_screen_on()
5480            try:
5481                ad.droid.disableDevicePassword()
5482            except Exception as e:
5483                ad.log.warning("disableDevicePassword failed with %s", e)
5484                fastboot_wipe(ad)
5485            time.sleep(2)
5486            ad.adb.wait_for_device(timeout=180)
5487    refresh_sl4a_session(ad)
5488    if not ad.is_adb_logcat_on:
5489        ad.start_adb_logcat()
5490
5491
5492def get_sim_state(ad):
5493    try:
5494        state = ad.droid.telephonyGetSimState()
5495    except:
5496        state = ad.adb.getprop("gsm.sim.state")
5497    return state
5498
5499
5500def is_sim_locked(ad):
5501    return get_sim_state(ad) == SIM_STATE_PIN_REQUIRED
5502
5503
5504def unlock_sim(ad):
5505    #The puk and pin can be provided in testbed config file.
5506    #"AndroidDevice": [{"serial": "84B5T15A29018214",
5507    #                   "adb_logcat_param": "-b all",
5508    #                   "puk": "12345678",
5509    #                   "puk_pin": "1234"}]
5510    if not is_sim_locked(ad):
5511        return True
5512    else:
5513        ad.is_sim_locked = True
5514    puk_pin = getattr(ad, "puk_pin", "1111")
5515    try:
5516        if not hasattr(ad, 'puk'):
5517            ad.log.info("Enter SIM pin code")
5518            ad.droid.telephonySupplyPin(puk_pin)
5519        else:
5520            ad.log.info("Enter PUK code and pin")
5521            ad.droid.telephonySupplyPuk(ad.puk, puk_pin)
5522    except:
5523        # if sl4a is not available, use adb command
5524        ad.unlock_screen(puk_pin)
5525        if is_sim_locked(ad):
5526            ad.unlock_screen(puk_pin)
5527    time.sleep(30)
5528    return not is_sim_locked(ad)
5529
5530
5531def send_dialer_secret_code(ad, secret_code):
5532    """Send dialer secret code.
5533
5534    ad: android device controller
5535    secret_code: the secret code to be sent to dialer. the string between
5536                 code prefix *#*# and code postfix #*#*. *#*#<xxx>#*#*
5537    """
5538    action = 'android.provider.Telephony.SECRET_CODE'
5539    uri = 'android_secret_code://%s' % secret_code
5540    intent = ad.droid.makeIntent(
5541        action,
5542        uri,
5543        None,  # type
5544        None,  # extras
5545        None,  # categories,
5546        None,  # packagename,
5547        None,  # classname,
5548        0x01000000)  # flags
5549    ad.log.info('Issuing dialer secret dialer code: %s', secret_code)
5550    ad.droid.sendBroadcastIntent(intent)
5551
5552
5553def system_file_push(ad, src_file_path, dst_file_path):
5554    """Push system file on a device.
5555
5556    Push system file need to change some system setting and remount.
5557    """
5558    cmd = "%s %s" % (src_file_path, dst_file_path)
5559    out = ad.adb.push(cmd, timeout=300, ignore_status=True)
5560    skip_sl4a = True if "sl4a.apk" in src_file_path else False
5561    if "Read-only file system" in out:
5562        ad.log.info("Change read-only file system")
5563        ad.adb.disable_verity()
5564        ad.reboot(skip_sl4a)
5565        ad.adb.remount()
5566        out = ad.adb.push(cmd, timeout=300, ignore_status=True)
5567        if "Read-only file system" in out:
5568            ad.reboot(skip_sl4a)
5569            out = ad.adb.push(cmd, timeout=300, ignore_status=True)
5570            if "error" in out:
5571                ad.log.error("%s failed with %s", cmd, out)
5572                return False
5573            else:
5574                ad.log.info("push %s succeed")
5575                if skip_sl4a: ad.reboot(skip_sl4a)
5576                return True
5577        else:
5578            return True
5579    elif "error" in out:
5580        return False
5581    else:
5582        return True
5583
5584
5585def flash_radio(ad, file_path, skip_setup_wizard=True):
5586    """Flash radio image."""
5587    ad.stop_services()
5588    ad.log.info("Reboot to bootloader")
5589    ad.adb.reboot_bootloader(ignore_status=True)
5590    ad.log.info("Flash radio in fastboot")
5591    try:
5592        ad.fastboot.flash("radio %s" % file_path, timeout=300)
5593    except Exception as e:
5594        ad.log.error(e)
5595    for _ in range(2):
5596        try:
5597            ad.log.info("Reboot in fastboot")
5598            ad.fastboot.reboot()
5599            ad.wait_for_boot_completion()
5600            break
5601        except Exception as e:
5602            ad.log.error("Exception error %s", e)
5603    ad.root_adb()
5604    if not ad.ensure_screen_on():
5605        ad.log.error("User window cannot come up")
5606    ad.start_services(ad.skip_sl4a, skip_setup_wizard=skip_setup_wizard)
5607    unlock_sim(ad)
5608
5609
5610def set_preferred_apn_by_adb(ad, pref_apn_name):
5611    """Select Pref APN
5612       Set Preferred APN on UI using content query/insert
5613       It needs apn name as arg, and it will match with plmn id
5614    """
5615    try:
5616        plmn_id = get_plmn_by_adb(ad)
5617        out = ad.adb.shell("content query --uri content://telephony/carriers "
5618                           "--where \"apn='%s' and numeric='%s'\"" %
5619                           (pref_apn_name, plmn_id))
5620        if "No result found" in out:
5621            ad.log.warning("Cannot find APN %s on device", pref_apn_name)
5622            return False
5623        else:
5624            apn_id = re.search(r'_id=(\d+)', out).group(1)
5625            ad.log.info("APN ID is %s", apn_id)
5626            ad.adb.shell("content insert --uri content:"
5627                         "//telephony/carriers/preferapn --bind apn_id:i:%s" %
5628                         (apn_id))
5629            out = ad.adb.shell("content query --uri "
5630                               "content://telephony/carriers/preferapn")
5631            if "No result found" in out:
5632                ad.log.error("Failed to set prefer APN %s", pref_apn_name)
5633                return False
5634            elif apn_id == re.search(r'_id=(\d+)', out).group(1):
5635                ad.log.info("Preferred APN set to %s", pref_apn_name)
5636                return True
5637    except Exception as e:
5638        ad.log.error("Exception while setting pref apn %s", e)
5639        return True
5640
5641
5642def check_apm_mode_on_by_serial(ad, serial_id):
5643    try:
5644        apm_check_cmd = "|".join(("adb -s %s shell dumpsys wifi" % serial_id,
5645                                  "grep -i airplanemodeon", "cut -f2 -d ' '"))
5646        output = exe_cmd(apm_check_cmd)
5647        if output.decode("utf-8").split("\n")[0] == "true":
5648            return True
5649        else:
5650            return False
5651    except Exception as e:
5652        ad.log.warning("Exception during check apm mode on %s", e)
5653        return True
5654
5655
5656def set_apm_mode_on_by_serial(ad, serial_id):
5657    try:
5658        cmd1 = "adb -s %s shell settings put global airplane_mode_on 1" % serial_id
5659        cmd2 = "adb -s %s shell am broadcast -a android.intent.action.AIRPLANE_MODE" % serial_id
5660        exe_cmd(cmd1)
5661        exe_cmd(cmd2)
5662    except Exception as e:
5663        ad.log.warning("Exception during set apm mode on %s", e)
5664        return True
5665
5666
5667def print_radio_info(ad, extra_msg=""):
5668    for prop in ("gsm.version.baseband", "persist.radio.ver_info",
5669                 "persist.radio.cnv.ver_info"):
5670        output = ad.adb.getprop(prop)
5671        ad.log.info("%s%s = %s", extra_msg, prop, output)
5672
5673
5674def wait_for_state(state_check_func,
5675                   state,
5676                   max_wait_time=MAX_WAIT_TIME_FOR_STATE_CHANGE,
5677                   checking_interval=WAIT_TIME_BETWEEN_STATE_CHECK,
5678                   *args,
5679                   **kwargs):
5680    while max_wait_time >= 0:
5681        if state_check_func(*args, **kwargs) == state:
5682            return True
5683        time.sleep(checking_interval)
5684        max_wait_time -= checking_interval
5685    return False
5686
5687
5688def power_off_sim(ad, sim_slot_id=None):
5689    try:
5690        if sim_slot_id is None:
5691            ad.droid.telephonySetSimPowerState(CARD_POWER_DOWN)
5692            verify_func = ad.droid.telephonyGetSimState
5693            verify_args = []
5694        else:
5695            ad.droid.telephonySetSimStateForSlotId(sim_slot_id,
5696                                                   CARD_POWER_DOWN)
5697            verify_func = ad.droid.telephonyGetSimStateForSlotId
5698            verify_args = [sim_slot_id]
5699    except Exception as e:
5700        ad.log.error(e)
5701        return False
5702    if wait_for_state(verify_func, SIM_STATE_UNKNOWN,
5703                      MAX_WAIT_TIME_FOR_STATE_CHANGE,
5704                      WAIT_TIME_BETWEEN_STATE_CHECK, *verify_args):
5705        ad.log.info("SIM slot is powered off, SIM state is UNKNOWN")
5706        return True
5707    else:
5708        ad.log.info("SIM state = %s", verify_func(*verify_args))
5709        ad.log.warning("Fail to power off SIM slot")
5710        return False
5711
5712
5713def power_on_sim(ad, sim_slot_id=None):
5714    try:
5715        if sim_slot_id is None:
5716            ad.droid.telephonySetSimPowerState(CARD_POWER_UP)
5717            verify_func = ad.droid.telephonyGetSimState
5718            verify_args = []
5719        else:
5720            ad.droid.telephonySetSimStateForSlotId(sim_slot_id, CARD_POWER_UP)
5721            verify_func = ad.droid.telephonyGetSimStateForSlotId
5722            verify_args = [sim_slot_id]
5723    except Exception as e:
5724        ad.log.error(e)
5725        return False
5726    if wait_for_state(verify_func, SIM_STATE_READY,
5727                      MAX_WAIT_TIME_FOR_STATE_CHANGE,
5728                      WAIT_TIME_BETWEEN_STATE_CHECK, *verify_args):
5729        ad.log.info("SIM slot is powered on, SIM state is READY")
5730        return True
5731    elif verify_func(*verify_args) == SIM_STATE_PIN_REQUIRED:
5732        ad.log.info("SIM is pin locked")
5733        return True
5734    else:
5735        ad.log.error("Fail to power on SIM slot")
5736        return False
5737
5738
5739def log_screen_shot(ad, test_name):
5740    file_name = "/sdcard/Pictures/screencap_%s.png" % (
5741        utils.get_current_epoch_time())
5742    screen_shot_path = os.path.join(ad.log_path, test_name,
5743                                    "Screenshot_%s" % ad.serial)
5744    utils.create_dir(screen_shot_path)
5745    ad.adb.shell("screencap -p %s" % file_name)
5746    ad.adb.pull("%s %s" % (file_name, screen_shot_path))
5747