• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 urllib.parse
22import time
23
24from queue import Empty
25from acts.controllers.android_device import AndroidDevice
26from acts.controllers.event_dispatcher import EventDispatcher
27from acts.test_utils.tel.tel_defines import AOSP_PREFIX
28from acts.test_utils.tel.tel_defines import CARRIER_UNKNOWN
29from acts.test_utils.tel.tel_defines import DATA_STATE_CONNECTED
30from acts.test_utils.tel.tel_defines import DATA_STATE_DISCONNECTED
31from acts.test_utils.tel.tel_defines import GEN_4G
32from acts.test_utils.tel.tel_defines import GEN_UNKNOWN
33from acts.test_utils.tel.tel_defines import INCALL_UI_DISPLAY_BACKGROUND
34from acts.test_utils.tel.tel_defines import INCALL_UI_DISPLAY_FOREGROUND
35from acts.test_utils.tel.tel_defines import INVALID_SIM_SLOT_INDEX
36from acts.test_utils.tel.tel_defines import INVALID_SUB_ID
37from acts.test_utils.tel.tel_defines import MAX_SAVED_VOICE_MAIL
38from acts.test_utils.tel.tel_defines import MAX_SCREEN_ON_TIME
39from acts.test_utils.tel.tel_defines import \
40    MAX_WAIT_TIME_ACCEPT_CALL_TO_OFFHOOK_EVENT
41from acts.test_utils.tel.tel_defines import MAX_WAIT_TIME_AIRPLANEMODE_EVENT
42from acts.test_utils.tel.tel_defines import MAX_WAIT_TIME_CALL_INITIATION
43from acts.test_utils.tel.tel_defines import MAX_WAIT_TIME_CALLEE_RINGING
44from acts.test_utils.tel.tel_defines import MAX_WAIT_TIME_CONNECTION_STATE_UPDATE
45from acts.test_utils.tel.tel_defines import MAX_WAIT_TIME_DATA_SUB_CHANGE
46from acts.test_utils.tel.tel_defines import MAX_WAIT_TIME_CALL_IDLE_EVENT
47from acts.test_utils.tel.tel_defines import MAX_WAIT_TIME_NW_SELECTION
48from acts.test_utils.tel.tel_defines import MAX_WAIT_TIME_SMS_RECEIVE
49from acts.test_utils.tel.tel_defines import MAX_WAIT_TIME_SMS_SENT_SUCCESS
50from acts.test_utils.tel.tel_defines import MAX_WAIT_TIME_TELECOM_RINGING
51from acts.test_utils.tel.tel_defines import MAX_WAIT_TIME_VOICE_MAIL_COUNT
52from acts.test_utils.tel.tel_defines import MAX_WAIT_TIME_WFC_DISABLED
53from acts.test_utils.tel.tel_defines import MAX_WAIT_TIME_WFC_ENABLED
54from acts.test_utils.tel.tel_defines import NETWORK_MODE_LTE_ONLY
55from acts.test_utils.tel.tel_defines import NETWORK_CONNECTION_TYPE_CELL
56from acts.test_utils.tel.tel_defines import NETWORK_CONNECTION_TYPE_WIFI
57from acts.test_utils.tel.tel_defines import NETWORK_SERVICE_DATA
58from acts.test_utils.tel.tel_defines import NETWORK_SERVICE_VOICE
59from acts.test_utils.tel.tel_defines import PHONE_NUMBER_STRING_FORMAT_7_DIGIT
60from acts.test_utils.tel.tel_defines import PHONE_NUMBER_STRING_FORMAT_10_DIGIT
61from acts.test_utils.tel.tel_defines import PHONE_NUMBER_STRING_FORMAT_11_DIGIT
62from acts.test_utils.tel.tel_defines import PHONE_NUMBER_STRING_FORMAT_12_DIGIT
63from acts.test_utils.tel.tel_defines import RAT_FAMILY_GSM
64from acts.test_utils.tel.tel_defines import RAT_FAMILY_LTE
65from acts.test_utils.tel.tel_defines import RAT_FAMILY_WLAN
66from acts.test_utils.tel.tel_defines import RAT_FAMILY_WCDMA
67from acts.test_utils.tel.tel_defines import RAT_1XRTT
68from acts.test_utils.tel.tel_defines import RAT_UNKNOWN
69from acts.test_utils.tel.tel_defines import SERVICE_STATE_EMERGENCY_ONLY
70from acts.test_utils.tel.tel_defines import SERVICE_STATE_IN_SERVICE
71from acts.test_utils.tel.tel_defines import SERVICE_STATE_OUT_OF_SERVICE
72from acts.test_utils.tel.tel_defines import SERVICE_STATE_POWER_OFF
73from acts.test_utils.tel.tel_defines import SIM_STATE_READY
74from acts.test_utils.tel.tel_defines import TELEPHONY_STATE_IDLE
75from acts.test_utils.tel.tel_defines import TELEPHONY_STATE_OFFHOOK
76from acts.test_utils.tel.tel_defines import TELEPHONY_STATE_RINGING
77from acts.test_utils.tel.tel_defines import VOICEMAIL_DELETE_DIGIT
78from acts.test_utils.tel.tel_defines import WAIT_TIME_1XRTT_VOICE_ATTACH
79from acts.test_utils.tel.tel_defines import WAIT_TIME_ANDROID_STATE_SETTLING
80from acts.test_utils.tel.tel_defines import WAIT_TIME_CHANGE_DATA_SUB_ID
81from acts.test_utils.tel.tel_defines import WAIT_TIME_IN_CALL
82from acts.test_utils.tel.tel_defines import WAIT_TIME_LEAVE_VOICE_MAIL
83from acts.test_utils.tel.tel_defines import WAIT_TIME_REJECT_CALL
84from acts.test_utils.tel.tel_defines import WAIT_TIME_VOICE_MAIL_SERVER_RESPONSE
85from acts.test_utils.tel.tel_defines import WFC_MODE_DISABLED
86from acts.test_utils.tel.tel_defines import EventCallStateChanged
87from acts.test_utils.tel.tel_defines import EventConnectivityChanged
88from acts.test_utils.tel.tel_defines import EventDataConnectionStateChanged
89from acts.test_utils.tel.tel_defines import EventDataSmsReceived
90from acts.test_utils.tel.tel_defines import EventMessageWaitingIndicatorChanged
91from acts.test_utils.tel.tel_defines import EventServiceStateChanged
92from acts.test_utils.tel.tel_defines import EventMmsSentSuccess
93from acts.test_utils.tel.tel_defines import EventSmsReceived
94from acts.test_utils.tel.tel_defines import EventSmsSentSuccess
95from acts.test_utils.tel.tel_defines import CallStateContainer
96from acts.test_utils.tel.tel_defines import DataConnectionStateContainer
97from acts.test_utils.tel.tel_defines import MessageWaitingIndicatorContainer
98from acts.test_utils.tel.tel_defines import NetworkCallbackContainer
99from acts.test_utils.tel.tel_defines import ServiceStateContainer
100from acts.test_utils.tel.tel_lookup_tables import \
101    connection_type_from_type_string
102from acts.test_utils.tel.tel_lookup_tables import is_valid_rat
103from acts.test_utils.tel.tel_lookup_tables import get_allowable_network_preference
104from acts.test_utils.tel.tel_lookup_tables import \
105    get_voice_mail_count_check_function
106from acts.test_utils.tel.tel_lookup_tables import get_voice_mail_number_function
107from acts.test_utils.tel.tel_lookup_tables import \
108    network_preference_for_generaton
109from acts.test_utils.tel.tel_lookup_tables import operator_name_from_plmn_id
110from acts.test_utils.tel.tel_lookup_tables import \
111    rat_families_for_network_preference
112from acts.test_utils.tel.tel_lookup_tables import rat_family_for_generation
113from acts.test_utils.tel.tel_lookup_tables import rat_family_from_rat
114from acts.test_utils.tel.tel_lookup_tables import rat_generation_from_rat
115from acts.test_utils.tel.tel_subscription_utils import \
116    get_default_data_sub_id
117from acts.test_utils.tel.tel_subscription_utils import \
118    get_outgoing_message_sub_id
119from acts.test_utils.tel.tel_subscription_utils import \
120    get_outgoing_voice_sub_id
121from acts.test_utils.tel.tel_subscription_utils import \
122    get_incoming_voice_sub_id
123from acts.test_utils.tel.tel_subscription_utils import \
124    get_incoming_message_sub_id
125from acts.utils import load_config
126from acts.logger import LoggerProxy
127log = LoggerProxy()
128
129
130class TelTestUtilsError(Exception):
131    pass
132
133
134def setup_droid_properties(log, ad, sim_filename):
135
136    # Check to see if droid already has this property
137    if hasattr(ad, 'cfg'):
138        return
139
140    device_props = {}
141    device_props['subscription'] = {}
142
143    try:
144        sim_data = load_config(sim_filename)
145    except Exception:
146        log.warning("Failed to load {}!".format(sim_filename))
147        sim_data = None
148    sub_info_list = ad.droid.subscriptionGetAllSubInfoList()
149    found_sims = 0
150    for sub_info in sub_info_list:
151        sub_id = sub_info['subscriptionId']
152        if sub_info['simSlotIndex'] is not INVALID_SIM_SLOT_INDEX:
153            found_sims += 1
154            sim_record = {}
155            try:
156                sim_serial = ad.droid.telephonyGetSimSerialNumberForSubscription(
157                    sub_id)
158                if not sim_serial:
159                    log.error("Unable to find ICC-ID for SIM on {}!".format(
160                        ad.serial))
161                if sim_data is not None:
162                    number = sim_data[sim_serial]["phone_num"]
163                else:
164                    raise KeyError("No file to load phone number info!")
165            except KeyError:
166                number = ad.droid.telephonyGetLine1NumberForSubscription(
167                    sub_id)
168            if not number or number == "":
169                raise TelTestUtilsError(
170                    "Failed to find valid phone number for {}"
171                    .format(ad.serial))
172
173            sim_record['phone_num'] = number
174            sim_record['operator'] = get_operator_name(log, ad, sub_id)
175            device_props['subscription'][sub_id] = sim_record
176            log.info(
177                "phone_info: <{}:{}>, <subId:{}> {} <{}>, ICC-ID:<{}>".format(
178                    ad.model, ad.serial, sub_id, number, get_operator_name(
179                        log, ad, sub_id),
180                    ad.droid.telephonyGetSimSerialNumberForSubscription(
181                        sub_id)))
182
183    if found_sims == 0:
184        log.warning("No Valid SIMs found in device {}".format(ad.serial))
185
186    setattr(ad, 'cfg', device_props)
187
188
189def refresh_droid_config(log, ad):
190    """ Update Android Device cfg records for each sub_id.
191    1. Update Phone Number using Line1Number (if Line1Number is valid).
192    2. Update Operator name.
193
194    Args:
195        log: log object
196        ad: android device object
197
198    Returns:
199        None
200    """
201    for sub_id in ad.cfg['subscription']:
202        # Update Phone number
203        number = ad.droid.telephonyGetLine1NumberForSubscription(sub_id)
204        if number:
205            number = phone_number_formatter(number)
206            ad.cfg['subscription'][sub_id]['phone_num'] = number
207        # Update Operator Name
208        ad.cfg['subscription'][sub_id]['operator'] = get_operator_name(log, ad,
209                                                                       sub_id)
210
211
212def get_slot_index_from_subid(log, ad, sub_id):
213    try:
214        info = ad.droid.subscriptionGetSubInfoForSubscriber(sub_id)
215        return info['simSlotIndex']
216    except KeyError:
217        return INVALID_SIM_SLOT_INDEX
218
219
220def get_num_active_sims(log, ad):
221    """ Get the number of active SIM cards by counting slots
222
223    Args:
224        ad: android_device object.
225
226    Returns:
227        result: The number of loaded (physical) SIM cards
228    """
229    # using a dictionary as a cheap way to prevent double counting
230    # in the situation where multiple subscriptions are on the same SIM.
231    # yes, this is a corner corner case.
232    valid_sims = {}
233    subInfo = ad.droid.subscriptionGetAllSubInfoList()
234    for info in subInfo:
235        ssidx = info['simSlotIndex']
236        if ssidx == INVALID_SIM_SLOT_INDEX:
237            continue
238        valid_sims[ssidx] = True
239    return len(valid_sims.keys())
240
241
242def toggle_airplane_mode(log, ad, new_state=None):
243    """ Toggle the state of airplane mode.
244
245    Args:
246        ad: android_device object.
247        new_state: Airplane mode state to set to.
248            If None, opposite of the current state.
249
250    Returns:
251        result: True if operation succeed. False if error happens.
252    """
253    return toggle_airplane_mode_msim(log, ad, new_state)
254
255
256def is_expected_event(event_to_check, events_list):
257    """ check whether event is present in the event list
258
259    Args:
260        event_to_check: event to be checked.
261        events_list: list of events
262    Returns:
263        result: True if event present in the list. False if not.
264    """
265    for event in events_list:
266        if event in event_to_check['name']:
267            return True
268    return False
269
270
271def is_sim_ready(log, ad, sim_slot_id=None):
272    """ check whether SIM is ready.
273
274    Args:
275        ad: android_device object.
276        sim_slot_id: check the SIM status for sim_slot_id
277            This is optional. If this is None, check default SIM.
278
279    Returns:
280        result: True if all SIMs are ready. False if not.
281    """
282    if sim_slot_id is None:
283        status = ad.droid.telephonyGetSimState()
284    else:
285        status = ad.droid.telephonyGetSimStateForSlotId(sim_slot_id)
286    if status != SIM_STATE_READY:
287        log.info("Sim not ready")
288        return False
289    return True
290
291
292def _is_expecting_event(event_recv_list):
293    """ check for more event is expected in event list
294
295    Args:
296        event_recv_list: list of events
297    Returns:
298        result: True if more events are expected. False if not.
299    """
300    for state in event_recv_list:
301        if state is False:
302            return True
303    return False
304
305
306def _set_event_list(event_recv_list, sub_id_list, sub_id, value):
307    """ set received event in expected event list
308
309    Args:
310        event_recv_list: list of received events
311        sub_id_list: subscription ID list
312        sub_id: subscription id of current event
313        value: True or False
314    Returns:
315        None.
316    """
317    for i in range(len(sub_id_list)):
318        if sub_id_list[i] == sub_id:
319            event_recv_list[i] = value
320
321
322def toggle_airplane_mode_msim(log, ad, new_state=None):
323    """ Toggle the state of airplane mode.
324
325    Args:
326        ad: android_device object.
327        new_state: Airplane mode state to set to.
328            If None, opposite of the current state.
329
330    Returns:
331        result: True if operation succeed. False if error happens.
332    """
333    serial_number = ad.serial
334
335    ad.ed.clear_all_events()
336    sub_id_list = []
337
338    active_sub_info = ad.droid.subscriptionGetAllSubInfoList()
339    for info in active_sub_info:
340        sub_id_list.append(info['subscriptionId'])
341
342    cur_state = ad.droid.connectivityCheckAirplaneMode()
343    if cur_state == new_state:
344        log.info("Airplane mode already <{}> on {}".format(new_state,
345                                                           serial_number))
346        return True
347    elif new_state is None:
348        log.info("Current State {} New state {}".format(cur_state, new_state))
349
350    if new_state is None:
351        new_state = not cur_state
352
353    service_state_list = []
354    if new_state:
355        service_state_list.append(SERVICE_STATE_POWER_OFF)
356        log.info("Turn on airplane mode: " + serial_number)
357
358    else:
359        # If either one of these 3 events show up, it should be OK.
360        # Normal SIM, phone in service
361        service_state_list.append(SERVICE_STATE_IN_SERVICE)
362        # NO SIM, or Dead SIM, or no Roaming coverage.
363        service_state_list.append(SERVICE_STATE_OUT_OF_SERVICE)
364        service_state_list.append(SERVICE_STATE_EMERGENCY_ONLY)
365        log.info("Turn off airplane mode: " + serial_number)
366
367    for sub_id in sub_id_list:
368        ad.droid.telephonyStartTrackingServiceStateChangeForSubscription(
369            sub_id)
370    ad.droid.connectivityToggleAirplaneMode(new_state)
371
372    event = None
373
374    try:
375        try:
376            event = ad.ed.wait_for_event(
377                EventServiceStateChanged,
378                is_event_match_for_list,
379                timeout=MAX_WAIT_TIME_AIRPLANEMODE_EVENT,
380                field=ServiceStateContainer.SERVICE_STATE,
381                value_list=service_state_list)
382        except Empty:
383            pass
384        if event is None:
385            log.error("Did not get expected service state {}".format(
386                service_state_list))
387        log.info("Received event: {}".format(event))
388    finally:
389        for sub_id in sub_id_list:
390            ad.droid.telephonyStopTrackingServiceStateChangeForSubscription(
391                sub_id)
392
393    if new_state:
394        if (not ad.droid.connectivityCheckAirplaneMode() or
395                ad.droid.wifiCheckState() or ad.droid.bluetoothCheckState()):
396            log.error("Airplane mode ON fail on {}".format(ad.serial))
397            return False
398    else:
399        if ad.droid.connectivityCheckAirplaneMode():
400            log.error("Airplane mode OFF fail on {}".format(ad.serial))
401            return False
402    return True
403
404
405def wait_and_answer_call(log,
406                         ad,
407                         incoming_number=None,
408                         incall_ui_display=INCALL_UI_DISPLAY_FOREGROUND):
409    """Wait for an incoming call on default voice subscription and
410       accepts the call.
411
412    Args:
413        ad: android device object.
414        incoming_number: Expected incoming number.
415            Optional. Default is None
416        incall_ui_display: after answer the call, bring in-call UI to foreground or
417            background. Optional, default value is INCALL_UI_DISPLAY_FOREGROUND.
418            if = INCALL_UI_DISPLAY_FOREGROUND, bring in-call UI to foreground.
419            if = INCALL_UI_DISPLAY_BACKGROUND, bring in-call UI to background.
420            else, do nothing.
421
422    Returns:
423        True: if incoming call is received and answered successfully.
424        False: for errors
425        """
426    return wait_and_answer_call_for_subscription(
427        log, ad, get_incoming_voice_sub_id(ad), incoming_number,
428        incall_ui_display)
429
430
431def wait_for_ringing_event(log, ad, wait_time):
432    log.warning("***DEPRECATED*** wait_for_ringing_event()")
433    return _wait_for_ringing_event(log, ad, wait_time)
434
435
436def _wait_for_ringing_event(log, ad, wait_time):
437    """Wait for ringing event.
438
439    Args:
440        log: log object.
441        ad: android device object.
442        wait_time: max time to wait for ringing event.
443
444    Returns:
445        event_ringing if received ringing event.
446        otherwise return None.
447    """
448    log.info("Wait for ringing.")
449    start_time = time.time()
450    remaining_time = wait_time
451    event_iter_timeout = 4
452    event_ringing = None
453
454    while remaining_time > 0:
455        try:
456            event_ringing = ad.ed.wait_for_event(
457                EventCallStateChanged,
458                is_event_match,
459                timeout=event_iter_timeout,
460                field=CallStateContainer.CALL_STATE,
461                value=TELEPHONY_STATE_RINGING)
462        except Empty:
463            if ad.droid.telecomIsRinging():
464                log.error("No Ringing event. But Callee in Ringing state.")
465                log.error("Test framework dropped event.")
466                return None
467        remaining_time = start_time + wait_time - time.time()
468        if event_ringing is not None:
469            break
470    if event_ringing is None:
471        log.error("No Ringing Event, Callee not in ringing state.")
472        log.error("No incoming call.")
473        return None
474
475    return event_ringing
476
477
478def wait_for_ringing_call(log, ad, incoming_number=None):
479    """Wait for an incoming call on default voice subscription and
480       accepts the call.
481
482    Args:
483        log: log object.
484        ad: android device object.
485        incoming_number: Expected incoming number.
486            Optional. Default is None
487
488    Returns:
489        True: if incoming call is received and answered successfully.
490        False: for errors
491        """
492    return wait_for_ringing_call_for_subscription(
493        log, ad, get_incoming_voice_sub_id(ad), incoming_number)
494
495
496def wait_for_ringing_call_for_subscription(log,
497                                           ad,
498                                           sub_id,
499                                           incoming_number=None):
500    """Wait for an incoming call on specified subscription.
501
502    Args:
503        log: log object.
504        ad: android device object.
505        sub_id: subscription ID
506        incoming_number: Expected incoming number.
507            Optional. Default is None
508
509    Returns:
510        True: if incoming call is received and answered successfully.
511        False: for errors
512    """
513    if (not ad.droid.telecomIsRinging() and
514            ad.droid.telephonyGetCallStateForSubscription(sub_id) !=
515            TELEPHONY_STATE_RINGING):
516        ad.ed.clear_all_events()
517        ad.droid.telephonyStartTrackingCallStateForSubscription(sub_id)
518        event_ringing = _wait_for_ringing_event(log, ad,
519                                                MAX_WAIT_TIME_CALLEE_RINGING)
520        ad.droid.telephonyStopTrackingCallStateChangeForSubscription(sub_id)
521        if event_ringing is None:
522            log.error("No Ringing Event.")
523            return False
524
525        if not incoming_number:
526            result = True
527        else:
528            result = check_phone_number_match(
529                event_ringing['data'][CallStateContainer.INCOMING_NUMBER],
530                incoming_number)
531
532        if not result:
533            log.error("Incoming Number not match")
534            log.error("Expected number:{}, actual number:{}".format(
535                incoming_number, event_ringing['data'][
536                    CallStateContainer.INCOMING_NUMBER]))
537            return False
538    return True
539
540
541def wait_and_answer_call_for_subscription(
542        log,
543        ad,
544        sub_id,
545        incoming_number=None,
546        incall_ui_display=INCALL_UI_DISPLAY_FOREGROUND):
547    """Wait for an incoming call on specified subscription and
548       accepts the call.
549
550    Args:
551        log: log object.
552        ad: android device object.
553        sub_id: subscription ID
554        incoming_number: Expected incoming number.
555            Optional. Default is None
556        incall_ui_display: after answer the call, bring in-call UI to foreground or
557            background. Optional, default value is INCALL_UI_DISPLAY_FOREGROUND.
558            if = INCALL_UI_DISPLAY_FOREGROUND, bring in-call UI to foreground.
559            if = INCALL_UI_DISPLAY_BACKGROUND, bring in-call UI to background.
560            else, do nothing.
561
562    Returns:
563        True: if incoming call is received and answered successfully.
564        False: for errors
565    """
566
567    if not wait_for_ringing_call_for_subscription(log, ad, sub_id,
568                                                  incoming_number):
569        log.error("Could not answer a call: phone never rang.")
570        return False
571
572    ad.ed.clear_all_events()
573    ad.droid.telephonyStartTrackingCallStateForSubscription(sub_id)
574    if not wait_for_telecom_ringing(log, ad, MAX_WAIT_TIME_TELECOM_RINGING):
575        log.error("Telecom is not ringing.")
576        return False
577    log.info("Accept on callee.")
578    ad.droid.telecomAcceptRingingCall()
579    try:
580        ad.ed.wait_for_event(
581            EventCallStateChanged,
582            is_event_match,
583            timeout=MAX_WAIT_TIME_ACCEPT_CALL_TO_OFFHOOK_EVENT,
584            field=CallStateContainer.CALL_STATE,
585            value=TELEPHONY_STATE_OFFHOOK)
586    except Empty:
587        if not ad.droid.telecomIsInCall():
588            log.error("Accept call failed.")
589            return False
590    finally:
591        ad.droid.telephonyStopTrackingCallStateChangeForSubscription(sub_id)
592    if incall_ui_display == INCALL_UI_DISPLAY_FOREGROUND:
593        ad.droid.telecomShowInCallScreen()
594    elif incall_ui_display == INCALL_UI_DISPLAY_BACKGROUND:
595        ad.droid.showHomeScreen()
596    return True
597
598
599def wait_and_reject_call(log,
600                         ad,
601                         incoming_number=None,
602                         delay_reject=WAIT_TIME_REJECT_CALL,
603                         reject=True):
604    """Wait for an incoming call on default voice subscription and
605       reject the call.
606
607    Args:
608        log: log object.
609        ad: android device object.
610        incoming_number: Expected incoming number.
611            Optional. Default is None
612        delay_reject: time to wait before rejecting the call
613            Optional. Default is WAIT_TIME_REJECT_CALL
614
615    Returns:
616        True: if incoming call is received and reject successfully.
617        False: for errors
618    """
619    return wait_and_reject_call_for_subscription(
620        log, ad, get_incoming_voice_sub_id(ad), incoming_number, delay_reject,
621        reject)
622
623
624def wait_and_reject_call_for_subscription(log,
625                                          ad,
626                                          sub_id,
627                                          incoming_number=None,
628                                          delay_reject=WAIT_TIME_REJECT_CALL,
629                                          reject=True):
630    """Wait for an incoming call on specific subscription and
631       reject the call.
632
633    Args:
634        log: log object.
635        ad: android device object.
636        sub_id: subscription ID
637        incoming_number: Expected incoming number.
638            Optional. Default is None
639        delay_reject: time to wait before rejecting the call
640            Optional. Default is WAIT_TIME_REJECT_CALL
641
642    Returns:
643        True: if incoming call is received and reject successfully.
644        False: for errors
645    """
646
647    if not wait_for_ringing_call_for_subscription(log, ad, sub_id,
648                                                  incoming_number):
649        log.error("Could not reject a call: phone never rang.")
650        return False
651
652    ad.ed.clear_all_events()
653    ad.droid.telephonyStartTrackingCallStateForSubscription(sub_id)
654    if reject is True:
655        # Delay between ringing and reject.
656        time.sleep(delay_reject)
657        log.info("Reject on callee.")
658        is_find = False
659        # Loop the call list and find the matched one to disconnect.
660        for call in ad.droid.telecomCallGetCallIds():
661            if check_phone_number_match(
662                    get_number_from_tel_uri(get_call_uri(ad, call)),
663                    incoming_number):
664                ad.droid.telecomCallDisconnect(call)
665                is_find = True
666        if is_find is False:
667            log.error("Did not find matching call to reject.")
668            return False
669    else:
670        # don't reject on callee. Just ignore the incoming call.
671        log.info("Received incoming call. Ignore it.")
672    try:
673        ad.ed.wait_for_event(
674            EventCallStateChanged,
675            is_event_match_for_list,
676            timeout=MAX_WAIT_TIME_CALL_IDLE_EVENT,
677            field=CallStateContainer.CALL_STATE,
678            value_list=[TELEPHONY_STATE_IDLE, TELEPHONY_STATE_OFFHOOK])
679    except Empty:
680        log.error("No onCallStateChangedIdle event received.")
681        return False
682    finally:
683        ad.droid.telephonyStopTrackingCallStateChangeForSubscription(sub_id)
684    return True
685
686
687def hangup_call(log, ad):
688    """Hang up ongoing active call.
689
690    Args:
691        log: log object.
692        ad: android device object.
693
694    Returns:
695        True: if incoming call is received and reject successfully.
696        False: for errors
697    """
698    ad.ed.clear_all_events()
699    ad.droid.telephonyStartTrackingCallState()
700    log.info("Hangup call.")
701    ad.droid.telecomEndCall()
702
703    try:
704        ad.ed.wait_for_event(EventCallStateChanged,
705                             is_event_match,
706                             timeout=MAX_WAIT_TIME_CALL_IDLE_EVENT,
707                             field=CallStateContainer.CALL_STATE,
708                             value=TELEPHONY_STATE_IDLE)
709    except Empty:
710        if ad.droid.telecomIsInCall():
711            log.error("Hangup call failed.")
712            return False
713    finally:
714        ad.droid.telephonyStopTrackingCallStateChange()
715    return True
716
717
718def disconnect_call_by_id(log, ad, call_id):
719    """Disconnect call by call id.
720    """
721    ad.droid.telecomCallDisconnect(call_id)
722    return True
723
724
725def _phone_number_remove_prefix(number):
726    """Remove the country code and other prefix from the input phone number.
727    Currently only handle phone number with the following formats:
728        (US phone number format)
729        +1abcxxxyyyy
730        1abcxxxyyyy
731        abcxxxyyyy
732        abc xxx yyyy
733        abc.xxx.yyyy
734        abc-xxx-yyyy
735        (EEUK phone number format)
736        +44abcxxxyyyy
737        0abcxxxyyyy
738
739    Args:
740        number: input phone number
741
742    Returns:
743        Phone number without country code or prefix
744    """
745    if number is None:
746        return None, None
747    country_code_list = ["+1", "+44"]
748    for country_code in country_code_list:
749        if number.startswith(country_code):
750            return number[len(country_code):], country_code
751    if number[0] == "1" or number[0] == "0":
752        return number[1:], None
753    return number, None
754
755
756def check_phone_number_match(number1, number2):
757    """Check whether two input phone numbers match or not.
758
759    Compare the two input phone numbers.
760    If they match, return True; otherwise, return False.
761    Currently only handle phone number with the following formats:
762        (US phone number format)
763        +1abcxxxyyyy
764        1abcxxxyyyy
765        abcxxxyyyy
766        abc xxx yyyy
767        abc.xxx.yyyy
768        abc-xxx-yyyy
769        (EEUK phone number format)
770        +44abcxxxyyyy
771        0abcxxxyyyy
772
773        There are some scenarios we can not verify, one example is:
774            number1 = +15555555555, number2 = 5555555555
775            (number2 have no country code)
776
777    Args:
778        number1: 1st phone number to be compared.
779        number2: 2nd phone number to be compared.
780
781    Returns:
782        True if two phone numbers match. Otherwise False.
783    """
784    # Remove country code and prefix
785    number1, country_code1 = _phone_number_remove_prefix(number1)
786    number2, country_code2 = _phone_number_remove_prefix(number2)
787    if ((country_code1 is not None) and (country_code2 is not None) and
788        (country_code1 != country_code2)):
789        return False
790    # Remove white spaces, dashes, dots
791    number1 = phone_number_formatter(number1)
792    number2 = phone_number_formatter(number2)
793    return number1 == number2
794
795
796def initiate_call(log, ad_caller, callee_number, emergency=False):
797    """Make phone call from caller to callee.
798
799    Args:
800        ad_caller: Caller android device object.
801        callee_number: Callee phone number.
802        emergency : specify the call is emergency.
803            Optional. Default value is False.
804
805    Returns:
806        result: if phone call is placed successfully.
807    """
808    ad_caller.ed.clear_all_events()
809    sub_id = get_outgoing_voice_sub_id(ad_caller)
810    ad_caller.droid.telephonyStartTrackingCallStateForSubscription(sub_id)
811
812    wait_time_for_incall_state = MAX_WAIT_TIME_CALL_INITIATION
813
814    try:
815        # Make a Call
816        if emergency:
817            ad_caller.droid.telecomCallEmergencyNumber(callee_number)
818        else:
819            ad_caller.droid.telecomCallNumber(callee_number)
820
821        # Verify OFFHOOK event
822        if ad_caller.droid.telephonyGetCallState() != TELEPHONY_STATE_OFFHOOK:
823            event_offhook = ad_caller.ed.wait_for_event(
824                EventCallStateChanged,
825                is_event_match,
826                timeout=wait_time_for_incall_state,
827                field=CallStateContainer.CALL_STATE,
828                value=TELEPHONY_STATE_OFFHOOK)
829    except Empty:
830        log.error("initiate_call did not receive Telephony OFFHOOK event.")
831        return False
832    finally:
833        ad_caller.droid.telephonyStopTrackingCallStateChangeForSubscription(
834            sub_id)
835
836    # Verify call state
837    while wait_time_for_incall_state > 0:
838        wait_time_for_incall_state -= 1
839        if (ad_caller.droid.telecomIsInCall() and
840            (ad_caller.droid.telephonyGetCallState() ==
841             TELEPHONY_STATE_OFFHOOK) and
842            (ad_caller.droid.telecomGetCallState() ==
843             TELEPHONY_STATE_OFFHOOK)):
844            return True
845        time.sleep(1)
846    log.error("Make call fail. telecomIsInCall:{}, Telecom State:{},"
847              " Telephony State:{}".format(ad_caller.droid.telecomIsInCall(
848              ), ad_caller.droid.telephonyGetCallState(
849              ), ad_caller.droid.telecomGetCallState()))
850    return False
851
852
853def call_reject(log, ad_caller, ad_callee, reject=True):
854    """Caller call Callee, then reject on callee.
855
856
857    """
858    subid_caller = ad_caller.droid.subscriptionGetDefaultVoiceSubId()
859    subid_callee = ad_callee.incoming_voice_sub_id
860    log.info("Sub-ID Caller {}, Sub-ID Callee {}".format(subid_caller,
861                                                         subid_callee))
862    return call_reject_for_subscription(log, ad_caller, ad_callee,
863                                        subid_caller, subid_callee, reject)
864
865
866def call_reject_for_subscription(log,
867                                 ad_caller,
868                                 ad_callee,
869                                 subid_caller,
870                                 subid_callee,
871                                 reject=True):
872    """
873    """
874
875    class _CallSequenceException(Exception):
876        pass
877
878    caller_number = ad_caller.cfg['subscription'][subid_caller]['phone_num']
879    callee_number = ad_callee.cfg['subscription'][subid_callee]['phone_num']
880
881    log.info("Call from {} to {}".format(caller_number, callee_number))
882    try:
883        if not initiate_call(log, ad_caller, callee_number):
884            raise _CallSequenceException("Initiate call failed.")
885
886        if not wait_and_reject_call_for_subscription(
887                log, ad_callee, subid_callee, caller_number,
888                WAIT_TIME_REJECT_CALL, reject):
889            raise _CallSequenceException("Reject call fail.")
890        # Check if incoming call is cleared on callee or not.
891        if ad_callee.droid.telephonyGetCallStateForSubscription(
892                subid_callee) == TELEPHONY_STATE_RINGING:
893            raise _CallSequenceException("Incoming call is not cleared.")
894        # Hangup on caller
895        hangup_call(log, ad_caller)
896    except _CallSequenceException as e:
897        log.error(e)
898        return False
899    return True
900
901
902def call_reject_leave_message(log,
903                              ad_caller,
904                              ad_callee,
905                              verify_caller_func=None,
906                              wait_time_in_call=WAIT_TIME_LEAVE_VOICE_MAIL):
907    """On default voice subscription, Call from caller to callee,
908    reject on callee, caller leave a voice mail.
909
910    1. Caller call Callee.
911    2. Callee reject incoming call.
912    3. Caller leave a voice mail.
913    4. Verify callee received the voice mail notification.
914
915    Args:
916        ad_caller: caller android device object.
917        ad_callee: callee android device object.
918        verify_caller_func: function to verify caller is in correct state while in-call.
919            This is optional, default is None.
920        wait_time_in_call: time to wait when leaving a voice mail.
921            This is optional, default is WAIT_TIME_LEAVE_VOICE_MAIL
922
923    Returns:
924        True: if voice message is received on callee successfully.
925        False: for errors
926    """
927    subid_caller = get_outgoing_voice_sub_id(ad_caller)
928    subid_callee = get_incoming_voice_sub_id(ad_callee)
929    return call_reject_leave_message_for_subscription(
930        log, ad_caller, ad_callee, subid_caller, subid_callee,
931        verify_caller_func, wait_time_in_call)
932
933
934def call_reject_leave_message_for_subscription(
935        log,
936        ad_caller,
937        ad_callee,
938        subid_caller,
939        subid_callee,
940        verify_caller_func=None,
941        wait_time_in_call=WAIT_TIME_LEAVE_VOICE_MAIL):
942    """On specific voice subscription, Call from caller to callee,
943    reject on callee, caller leave a voice mail.
944
945    1. Caller call Callee.
946    2. Callee reject incoming call.
947    3. Caller leave a voice mail.
948    4. Verify callee received the voice mail notification.
949
950    Args:
951        ad_caller: caller android device object.
952        ad_callee: callee android device object.
953        subid_caller: caller's subscription id.
954        subid_callee: callee's subscription id.
955        verify_caller_func: function to verify caller is in correct state while in-call.
956            This is optional, default is None.
957        wait_time_in_call: time to wait when leaving a voice mail.
958            This is optional, default is WAIT_TIME_LEAVE_VOICE_MAIL
959
960    Returns:
961        True: if voice message is received on callee successfully.
962        False: for errors
963    """
964
965    class _CallSequenceException(Exception):
966        pass
967    # Currently this test utility only works for TMO and ATT and SPT.
968    # It does not work for VZW (see b/21559800)
969    # "with VVM TelephonyManager APIs won't work for vm"
970
971    caller_number = ad_caller.cfg['subscription'][subid_caller]['phone_num']
972    callee_number = ad_callee.cfg['subscription'][subid_callee]['phone_num']
973
974    log.info("Call from {} to {}".format(caller_number, callee_number))
975
976    try:
977
978        if not initiate_call(log, ad_caller, callee_number):
979            raise _CallSequenceException("Initiate call failed.")
980
981        if not wait_and_reject_call_for_subscription(
982                log,
983                ad_callee,
984                subid_callee,
985                incoming_number=caller_number):
986            raise _CallSequenceException("Reject call fail.")
987
988        ad_callee.droid.telephonyStartTrackingVoiceMailStateChangeForSubscription(
989            subid_callee)
990        voice_mail_count_before = ad_callee.droid.telephonyGetVoiceMailCountForSubscription(
991            subid_callee)
992
993        # -1 means there are unread voice mail, but the count is unknown
994        # 0 means either this API not working (VZW) or no unread voice mail.
995        if voice_mail_count_before != 0:
996            log.warning("--Pending new Voice Mail, please clear on phone.--")
997
998        # ensure that all internal states are updated in telecom
999        time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
1000        ad_callee.ed.clear_all_events()
1001
1002        if verify_caller_func and not verify_caller_func(log, ad_caller):
1003            raise _CallSequenceException("Caller not in correct state!")
1004
1005        # TODO: b/26293512 Need to play some sound to leave message.
1006        # Otherwise carrier voice mail server may drop this voice mail.
1007
1008        time.sleep(wait_time_in_call)
1009
1010        if not verify_caller_func:
1011            caller_state_result = ad_caller.droid.telecomIsInCall()
1012        else:
1013            caller_state_result = verify_caller_func(log, ad_caller)
1014        if not caller_state_result:
1015            raise _CallSequenceException(
1016                "Caller not in correct state after {} seconds".format(
1017                    wait_time_in_call))
1018
1019        if not hangup_call(log, ad_caller):
1020            raise _CallSequenceException("Error in Hanging-Up Call")
1021
1022        log.info("Wait for voice mail indicator on callee.")
1023        try:
1024            event = ad_callee.ed.wait_for_event(
1025                EventMessageWaitingIndicatorChanged,
1026                _is_on_message_waiting_event_true)
1027            log.info(event)
1028        except Empty:
1029            raise _CallSequenceException("No expected event {}.".format(
1030                EventMessageWaitingIndicatorChanged))
1031        voice_mail_count_after = ad_callee.droid.telephonyGetVoiceMailCountForSubscription(
1032            subid_callee)
1033        log.info(
1034            "telephonyGetVoiceMailCount output - before: {}, after: {}".format(
1035                voice_mail_count_before, voice_mail_count_after))
1036
1037        # voice_mail_count_after should:
1038        # either equals to (voice_mail_count_before + 1) [For ATT and SPT]
1039        # or equals to -1 [For TMO]
1040        # -1 means there are unread voice mail, but the count is unknown
1041        if not check_voice_mail_count(log, ad_callee, voice_mail_count_before,
1042                                      voice_mail_count_after):
1043            log.error("telephonyGetVoiceMailCount output is incorrect.")
1044            return False
1045
1046    except _CallSequenceException as e:
1047        log.error(e)
1048        return False
1049    finally:
1050        ad_callee.droid.telephonyStopTrackingVoiceMailStateChangeForSubscription(
1051            subid_callee)
1052    return True
1053
1054
1055def call_voicemail_erase_all_pending_voicemail(log, ad):
1056    """Script for phone to erase all pending voice mail.
1057    This script only works for TMO and ATT and SPT currently.
1058    This script only works if phone have already set up voice mail options,
1059    and phone should disable password protection for voice mail.
1060
1061    1. If phone don't have pending voice message, return True.
1062    2. Dial voice mail number.
1063        For TMO, the number is '123'
1064        For ATT, the number is phone's number
1065        For SPT, the number is phone's number
1066    3. Wait for voice mail connection setup.
1067    4. Wait for voice mail play pending voice message.
1068    5. Send DTMF to delete one message.
1069        The digit is '7'.
1070    6. Repeat steps 4 and 5 until voice mail server drop this call.
1071        (No pending message)
1072    6. Check telephonyGetVoiceMailCount result. it should be 0.
1073
1074    Args:
1075        log: log object
1076        ad: android device object
1077    Returns:
1078        False if error happens. True is succeed.
1079    """
1080    log.info("Erase all pending voice mail.")
1081    if ad.droid.telephonyGetVoiceMailCount() == 0:
1082        log.info("No Pending voice mail.")
1083        return True
1084
1085    voice_mail_number = get_voice_mail_number(log, ad)
1086
1087    if not initiate_call(log, ad, voice_mail_number):
1088        log.error("Initiate call failed.")
1089        return False
1090    time.sleep(WAIT_TIME_VOICE_MAIL_SERVER_RESPONSE)
1091    callId = ad.droid.telecomCallGetCallIds()[0]
1092    time.sleep(WAIT_TIME_VOICE_MAIL_SERVER_RESPONSE)
1093    count = MAX_SAVED_VOICE_MAIL
1094    while (is_phone_in_call(log, ad) and (count > 0)):
1095        log.info("Press 7 to delete voice mail.")
1096        ad.droid.telecomCallPlayDtmfTone(callId, VOICEMAIL_DELETE_DIGIT)
1097        ad.droid.telecomCallStopDtmfTone(callId)
1098        time.sleep(WAIT_TIME_VOICE_MAIL_SERVER_RESPONSE)
1099        count -= 1
1100    log.info("Voice mail server dropped this call.")
1101    # wait for telephonyGetVoiceMailCount to update correct result
1102    remaining_time = MAX_WAIT_TIME_VOICE_MAIL_COUNT
1103    while ((remaining_time > 0) and
1104           (ad.droid.telephonyGetVoiceMailCount() != 0)):
1105        time.sleep(1)
1106        remaining_time -= 1
1107    current_voice_mail_count = ad.droid.telephonyGetVoiceMailCount()
1108    log.info("telephonyGetVoiceMailCount: {}".format(current_voice_mail_count))
1109    return (current_voice_mail_count == 0)
1110
1111
1112def _is_on_message_waiting_event_true(event):
1113    """Private function to return if the received EventMessageWaitingIndicatorChanged
1114    event MessageWaitingIndicatorContainer.IS_MESSAGE_WAITING field is True.
1115    """
1116    return event['data'][MessageWaitingIndicatorContainer.IS_MESSAGE_WAITING]
1117
1118
1119def call_setup_teardown(log,
1120                        ad_caller,
1121                        ad_callee,
1122                        ad_hangup=None,
1123                        verify_caller_func=None,
1124                        verify_callee_func=None,
1125                        wait_time_in_call=WAIT_TIME_IN_CALL,
1126                        incall_ui_display=INCALL_UI_DISPLAY_FOREGROUND):
1127    """ Call process, including make a phone call from caller,
1128    accept from callee, and hang up. The call is on default voice subscription
1129
1130    In call process, call from <droid_caller> to <droid_callee>,
1131    accept the call, (optional)then hang up from <droid_hangup>.
1132
1133    Args:
1134        ad_caller: Caller Android Device Object.
1135        ad_callee: Callee Android Device Object.
1136        ad_hangup: Android Device Object end the phone call.
1137            Optional. Default value is None, and phone call will continue.
1138        verify_call_mode_caller: func_ptr to verify caller in correct mode
1139            Optional. Default is None
1140        verify_call_mode_caller: func_ptr to verify caller in correct mode
1141            Optional. Default is None
1142        incall_ui_display: after answer the call, bring in-call UI to foreground or
1143            background. Optional, default value is INCALL_UI_DISPLAY_FOREGROUND.
1144            if = INCALL_UI_DISPLAY_FOREGROUND, bring in-call UI to foreground.
1145            if = INCALL_UI_DISPLAY_BACKGROUND, bring in-call UI to background.
1146            else, do nothing.
1147
1148    Returns:
1149        True if call process without any error.
1150        False if error happened.
1151
1152    """
1153    subid_caller = get_outgoing_voice_sub_id(ad_caller)
1154    subid_callee = get_incoming_voice_sub_id(ad_callee)
1155    log.info("Sub-ID Caller {}, Sub-ID Callee {}".format(subid_caller,
1156                                                         subid_callee))
1157    return call_setup_teardown_for_subscription(
1158        log, ad_caller, ad_callee, subid_caller, subid_callee, ad_hangup,
1159        verify_caller_func, verify_callee_func, wait_time_in_call,
1160        incall_ui_display)
1161
1162
1163def call_setup_teardown_for_subscription(
1164        log,
1165        ad_caller,
1166        ad_callee,
1167        subid_caller,
1168        subid_callee,
1169        ad_hangup=None,
1170        verify_caller_func=None,
1171        verify_callee_func=None,
1172        wait_time_in_call=WAIT_TIME_IN_CALL,
1173        incall_ui_display=INCALL_UI_DISPLAY_FOREGROUND):
1174    """ Call process, including make a phone call from caller,
1175    accept from callee, and hang up. The call is on specified subscription
1176
1177    In call process, call from <droid_caller> to <droid_callee>,
1178    accept the call, (optional)then hang up from <droid_hangup>.
1179
1180    Args:
1181        ad_caller: Caller Android Device Object.
1182        ad_callee: Callee Android Device Object.
1183        subid_caller: Caller subscription ID
1184        subid_callee: Callee subscription ID
1185        ad_hangup: Android Device Object end the phone call.
1186            Optional. Default value is None, and phone call will continue.
1187        verify_call_mode_caller: func_ptr to verify caller in correct mode
1188            Optional. Default is None
1189        verify_call_mode_caller: func_ptr to verify caller in correct mode
1190            Optional. Default is None
1191        incall_ui_display: after answer the call, bring in-call UI to foreground or
1192            background. Optional, default value is INCALL_UI_DISPLAY_FOREGROUND.
1193            if = INCALL_UI_DISPLAY_FOREGROUND, bring in-call UI to foreground.
1194            if = INCALL_UI_DISPLAY_BACKGROUND, bring in-call UI to background.
1195            else, do nothing.
1196
1197    Returns:
1198        True if call process without any error.
1199        False if error happened.
1200
1201    """
1202    CHECK_INTERVAL = 3
1203
1204    class _CallSequenceException(Exception):
1205        pass
1206
1207    caller_number = ad_caller.cfg['subscription'][subid_caller]['phone_num']
1208    callee_number = ad_callee.cfg['subscription'][subid_callee]['phone_num']
1209
1210    log.info("Call from {} to {}".format(caller_number, callee_number))
1211
1212    try:
1213        if not initiate_call(log, ad_caller, callee_number):
1214            raise _CallSequenceException("Initiate call failed.")
1215
1216        if not wait_and_answer_call_for_subscription(
1217                log,
1218                ad_callee,
1219                subid_callee,
1220                incoming_number=caller_number,
1221                incall_ui_display=incall_ui_display):
1222            raise _CallSequenceException("Answer call fail.")
1223
1224        # ensure that all internal states are updated in telecom
1225        time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
1226
1227        if verify_caller_func and not verify_caller_func(log, ad_caller):
1228            raise _CallSequenceException("Caller not in correct state!")
1229        if verify_callee_func and not verify_callee_func(log, ad_callee):
1230            raise _CallSequenceException("Callee not in correct state!")
1231
1232        elapsed_time = 0
1233        while (elapsed_time < wait_time_in_call):
1234            CHECK_INTERVAL = min(CHECK_INTERVAL,
1235                                 wait_time_in_call - elapsed_time)
1236            time.sleep(CHECK_INTERVAL)
1237            elapsed_time += CHECK_INTERVAL
1238            if not verify_caller_func:
1239                caller_state_result = ad_caller.droid.telecomIsInCall()
1240            else:
1241                caller_state_result = verify_caller_func(log, ad_caller)
1242            if not caller_state_result:
1243                raise _CallSequenceException(
1244                    "Caller not in correct state at <{}>/<{}> second.".format(
1245                        elapsed_time, wait_time_in_call))
1246            if not verify_callee_func:
1247                callee_state_result = ad_callee.droid.telecomIsInCall()
1248            else:
1249                callee_state_result = verify_callee_func(log, ad_callee)
1250            if not callee_state_result:
1251                raise _CallSequenceException(
1252                    "Callee not in correct state at <{}>/<{}> second.".format(
1253                        elapsed_time, wait_time_in_call))
1254
1255        if not ad_hangup:
1256            return True
1257
1258        if not hangup_call(log, ad_hangup):
1259            raise _CallSequenceException("Error in Hanging-Up Call")
1260
1261        return True
1262
1263    except _CallSequenceException as e:
1264        log.error(e)
1265        return False
1266    finally:
1267        if ad_hangup:
1268            for ad in [ad_caller, ad_callee]:
1269                try:
1270                    if ad.droid.telecomIsInCall():
1271                        ad.droid.telecomEndCall()
1272                except Exception as e:
1273                    log.error(str(e))
1274
1275
1276def phone_number_formatter(input_string, format=None):
1277    """Get expected format of input phone number string.
1278
1279    Args:
1280        input_string: (string) input phone number.
1281            The input could be 10/11/12 digital, with or without " "/"-"/"."
1282        format: (int) expected format, this could be 7/10/11/12
1283            if format is 7: output string would be 7 digital number.
1284            if format is 10: output string would be 10 digital (standard) number.
1285            if format is 11: output string would be "1" + 10 digital number.
1286            if format is 12: output string would be "+1" + 10 digital number.
1287
1288    Returns:
1289        If no error happen, return phone number in expected format.
1290        Else, return None.
1291    """
1292    # make sure input_string is 10 digital
1293    # Remove white spaces, dashes, dots
1294    input_string = input_string.replace(" ", "").replace("-", "").replace(".",
1295                                                                          "")
1296    if not format:
1297        return input_string
1298    # Remove "1"  or "+1"from front
1299    if (len(input_string) == PHONE_NUMBER_STRING_FORMAT_11_DIGIT and
1300            input_string[0] == "1"):
1301        input_string = input_string[1:]
1302    elif (len(input_string) == PHONE_NUMBER_STRING_FORMAT_12_DIGIT and
1303          input_string[0:2] == "+1"):
1304        input_string = input_string[2:]
1305    elif (len(input_string) == PHONE_NUMBER_STRING_FORMAT_7_DIGIT and
1306          format == PHONE_NUMBER_STRING_FORMAT_7_DIGIT):
1307        return input_string
1308    elif len(input_string) != PHONE_NUMBER_STRING_FORMAT_10_DIGIT:
1309        return None
1310    # change input_string according to format
1311    if format == PHONE_NUMBER_STRING_FORMAT_12_DIGIT:
1312        input_string = "+1" + input_string
1313    elif format == PHONE_NUMBER_STRING_FORMAT_11_DIGIT:
1314        input_string = "1" + input_string
1315    elif format == PHONE_NUMBER_STRING_FORMAT_10_DIGIT:
1316        input_string = input_string
1317    elif format == PHONE_NUMBER_STRING_FORMAT_7_DIGIT:
1318        input_string = input_string[3:]
1319    else:
1320        return None
1321    return input_string
1322
1323
1324def get_internet_connection_type(log, ad):
1325    """Get current active connection type name.
1326
1327    Args:
1328        log: Log object.
1329        ad: Android Device Object.
1330    Returns:
1331        current active connection type name.
1332    """
1333    if not ad.droid.connectivityNetworkIsConnected():
1334        return 'none'
1335    return connection_type_from_type_string(
1336        ad.droid.connectivityNetworkGetActiveConnectionTypeName())
1337
1338
1339def verify_http_connection(log,
1340                           ad,
1341                           url="http://www.google.com/",
1342                           retry=3,
1343                           retry_interval=5):
1344    """Make ping request and return status.
1345
1346    Args:
1347        log: log object
1348        ad: Android Device Object.
1349        url: Optional. The ping request will be made to this URL.
1350            Default Value is "http://www.google.com/".
1351
1352    """
1353    for i in range(0, retry + 1):
1354
1355        try:
1356            http_response = ad.droid.httpPing(url)
1357        except:
1358            http_response = None
1359
1360        # If httpPing failed, it may return {} (if phone just turn off APM) or
1361        # None (regular fail)
1362        # So here use "if http_response" to see if it pass or fail
1363        if http_response:
1364            log.info("Verify Internet succeeded after {}s.".format(
1365                i * retry_interval) if i > 0 else "Verify Internet succeeded.")
1366            return True
1367        else:
1368            if i < retry:
1369                time.sleep(retry_interval)
1370    log.info("Verify Internet retry failed after {}s"
1371             .format(i * retry_interval))
1372    return False
1373
1374
1375def _connection_state_change(_event, target_state, connection_type):
1376    if connection_type:
1377        if 'TypeName' not in _event['data']:
1378            return False
1379        connection_type_string_in_event = _event['data']['TypeName']
1380        cur_type = connection_type_from_type_string(
1381            connection_type_string_in_event)
1382        if cur_type != connection_type:
1383            log.info(
1384                "_connection_state_change expect: {}, received: {} <type {}>".format(
1385                    connection_type, connection_type_string_in_event,
1386                    cur_type))
1387            return False
1388
1389    if 'isConnected' in _event['data'] and _event['data'][
1390            'isConnected'] == target_state:
1391        return True
1392    return False
1393
1394
1395def wait_for_cell_data_connection(
1396        log,
1397        ad,
1398        state,
1399        timeout_value=EventDispatcher.DEFAULT_TIMEOUT):
1400    """Wait for data connection status to be expected value for default
1401       data subscription.
1402
1403    Wait for the data connection status to be DATA_STATE_CONNECTED
1404        or DATA_STATE_DISCONNECTED.
1405
1406    Args:
1407        log: Log object.
1408        ad: Android Device Object.
1409        state: Expected status: True or False.
1410            If True, it will wait for status to be DATA_STATE_CONNECTED.
1411            If False, it will wait for status ti be DATA_STATE_DISCONNECTED.
1412        timeout_value: wait for cell data timeout value.
1413            This is optional, default value is EventDispatcher.DEFAULT_TIMEOUT
1414
1415    Returns:
1416        True if success.
1417        False if failed.
1418    """
1419    sub_id = get_default_data_sub_id(ad)
1420    return wait_for_cell_data_connection_for_subscription(log, ad, sub_id,
1421                                                          state, timeout_value)
1422
1423
1424def _is_data_connection_state_match(log, ad, expected_data_connection_state):
1425    return (expected_data_connection_state ==
1426            ad.droid.telephonyGetDataConnectionState())
1427
1428
1429def _is_network_connected_state_match(log, ad,
1430                                      expected_network_connected_state):
1431    return (expected_network_connected_state ==
1432            ad.droid.connectivityNetworkIsConnected())
1433
1434
1435def wait_for_cell_data_connection_for_subscription(
1436        log,
1437        ad,
1438        sub_id,
1439        state,
1440        timeout_value=EventDispatcher.DEFAULT_TIMEOUT):
1441    """Wait for data connection status to be expected value for specified
1442       subscrption id.
1443
1444    Wait for the data connection status to be DATA_STATE_CONNECTED
1445        or DATA_STATE_DISCONNECTED.
1446
1447    Args:
1448        log: Log object.
1449        ad: Android Device Object.
1450        sub_id: subscription Id
1451        state: Expected status: True or False.
1452            If True, it will wait for status to be DATA_STATE_CONNECTED.
1453            If False, it will wait for status ti be DATA_STATE_DISCONNECTED.
1454        timeout_value: wait for cell data timeout value.
1455            This is optional, default value is EventDispatcher.DEFAULT_TIMEOUT
1456
1457    Returns:
1458        True if success.
1459        False if failed.
1460    """
1461    state_str = {
1462        True: DATA_STATE_CONNECTED,
1463        False: DATA_STATE_DISCONNECTED
1464    }[state]
1465
1466    ad.ed.clear_all_events()
1467    ad.droid.telephonyStartTrackingDataConnectionStateChangeForSubscription(
1468        sub_id)
1469    ad.droid.connectivityStartTrackingConnectivityStateChange()
1470    try:
1471        # TODO: b/26293147 There is no framework API to get data connection
1472        # state by sub id
1473        data_state = ad.droid.telephonyGetDataConnectionState()
1474        if data_state == state_str:
1475            return _wait_for_nw_data_connection(
1476                log, ad, state, NETWORK_CONNECTION_TYPE_CELL, timeout_value)
1477
1478        try:
1479            event = ad.ed.wait_for_event(
1480                EventDataConnectionStateChanged,
1481                is_event_match,
1482                timeout=timeout_value,
1483                field=DataConnectionStateContainer.DATA_CONNECTION_STATE,
1484                value=state_str)
1485        except Empty:
1486            log.debug(
1487                "No expected event EventDataConnectionStateChanged {}.".format(
1488                    state_str))
1489
1490        # TODO: Wait for <MAX_WAIT_TIME_CONNECTION_STATE_UPDATE> seconds for
1491        # data connection state.
1492        # Otherwise, the network state will not be correct.
1493        # The bug is tracked here: b/20921915
1494
1495        # Previously we use _is_data_connection_state_match,
1496        # but telephonyGetDataConnectionState sometimes return wrong value.
1497        # The bug is tracked here: b/22612607
1498        # So we use _is_network_connected_state_match.
1499
1500        if _wait_for_droid_in_state(log, ad,
1501                                    MAX_WAIT_TIME_CONNECTION_STATE_UPDATE,
1502                                    _is_network_connected_state_match, state):
1503            return _wait_for_nw_data_connection(
1504                log, ad, state, NETWORK_CONNECTION_TYPE_CELL, timeout_value)
1505        else:
1506            return False
1507
1508    finally:
1509        ad.droid.telephonyStopTrackingDataConnectionStateChangeForSubscription(
1510            sub_id)
1511
1512
1513def wait_for_wifi_data_connection(
1514        log,
1515        ad,
1516        state,
1517        timeout_value=EventDispatcher.DEFAULT_TIMEOUT):
1518    """Wait for data connection status to be expected value and connection is by WiFi.
1519
1520    Args:
1521        log: Log object.
1522        ad: Android Device Object.
1523        state: Expected status: True or False.
1524            If True, it will wait for status to be DATA_STATE_CONNECTED.
1525            If False, it will wait for status ti be DATA_STATE_DISCONNECTED.
1526        timeout_value: wait for network data timeout value.
1527            This is optional, default value is EventDispatcher.DEFAULT_TIMEOUT
1528
1529    Returns:
1530        True if success.
1531        False if failed.
1532    """
1533    log.info("{} wait_for_wifi_data_connection".format(ad.serial))
1534    return _wait_for_nw_data_connection(
1535        log, ad, state, NETWORK_CONNECTION_TYPE_WIFI, timeout_value)
1536
1537
1538def wait_for_data_connection(log,
1539                             ad,
1540                             state,
1541                             timeout_value=EventDispatcher.DEFAULT_TIMEOUT):
1542    """Wait for data connection status to be expected value.
1543
1544    Wait for the data connection status to be DATA_STATE_CONNECTED
1545        or DATA_STATE_DISCONNECTED.
1546
1547    Args:
1548        log: Log object.
1549        ad: Android Device Object.
1550        state: Expected status: True or False.
1551            If True, it will wait for status to be DATA_STATE_CONNECTED.
1552            If False, it will wait for status ti be DATA_STATE_DISCONNECTED.
1553        timeout_value: wait for network data timeout value.
1554            This is optional, default value is EventDispatcher.DEFAULT_TIMEOUT
1555
1556    Returns:
1557        True if success.
1558        False if failed.
1559    """
1560    return _wait_for_nw_data_connection(log, ad, state, None, timeout_value)
1561
1562
1563def _wait_for_nw_data_connection(
1564        log,
1565        ad,
1566        is_connected,
1567        connection_type=None,
1568        timeout_value=EventDispatcher.DEFAULT_TIMEOUT):
1569    """Wait for data connection status to be expected value.
1570
1571    Wait for the data connection status to be DATA_STATE_CONNECTED
1572        or DATA_STATE_DISCONNECTED.
1573
1574    Args:
1575        log: Log object.
1576        ad: Android Device Object.
1577        is_connected: Expected connection status: True or False.
1578            If True, it will wait for status to be DATA_STATE_CONNECTED.
1579            If False, it will wait for status ti be DATA_STATE_DISCONNECTED.
1580        connection_type: expected connection type.
1581            This is optional, if it is None, then any connection type will return True.
1582        timeout_value: wait for network data timeout value.
1583            This is optional, default value is EventDispatcher.DEFAULT_TIMEOUT
1584
1585    Returns:
1586        True if success.
1587        False if failed.
1588    """
1589    ad.ed.clear_all_events()
1590    ad.droid.connectivityStartTrackingConnectivityStateChange()
1591    try:
1592        cur_data_connection_state = ad.droid.connectivityNetworkIsConnected()
1593        if is_connected == cur_data_connection_state:
1594            current_type = get_internet_connection_type(log, ad)
1595            log.info(
1596                "_wait_for_nw_data_connection: current connection type: {}".format(
1597                    current_type))
1598            if not connection_type:
1599                return True
1600            else:
1601                if not is_connected and current_type != connection_type:
1602                    log.info(
1603                        "wait_for_nw_data_connection success: {} data not on {}!".format(
1604                            ad.serial, connection_type))
1605                    return True
1606                elif is_connected and current_type == connection_type:
1607                    log.info(
1608                        "wait_for_nw_data_connection success: {} data on {}!".format(
1609                            ad.serial, connection_type))
1610                    return True
1611        else:
1612            log.info("{} current state: {} target: {}".format(
1613                ad.serial, cur_data_connection_state, is_connected))
1614
1615        try:
1616            event = ad.ed.wait_for_event(
1617                EventConnectivityChanged, _connection_state_change,
1618                timeout_value, is_connected, connection_type)
1619            log.info("_wait_for_nw_data_connection received event:{}".format(
1620                event))
1621        except Empty:
1622            pass
1623
1624        log.info(
1625            "_wait_for_nw_data_connection: check connection after wait event.")
1626        # TODO: Wait for <MAX_WAIT_TIME_CONNECTION_STATE_UPDATE> seconds for
1627        # data connection state.
1628        # Otherwise, the network state will not be correct.
1629        # The bug is tracked here: b/20921915
1630        if _wait_for_droid_in_state(
1631                log, ad, MAX_WAIT_TIME_CONNECTION_STATE_UPDATE,
1632                _is_network_connected_state_match, is_connected):
1633            current_type = get_internet_connection_type(log, ad)
1634            log.info(
1635                "_wait_for_nw_data_connection: current connection type: {}".format(
1636                    current_type))
1637            if not connection_type:
1638                return True
1639            else:
1640                if not is_connected and current_type != connection_type:
1641                    log.info(
1642                        "wait_for_nw_data_connection after event wait, success: {} data not on {}!".format(
1643                            ad.serial, connection_type))
1644                    return True
1645                elif is_connected and current_type == connection_type:
1646                    log.info(
1647                        "wait_for_nw_data_connection after event wait, success: {} data on {}!".format(
1648                            ad.serial, connection_type))
1649                    return True
1650                else:
1651                    return False
1652        else:
1653            return False
1654    except Exception as e:
1655        log.error(
1656            "tel_test_utils._wait_for_nw_data_connection threw Random exception {}".format(
1657                str(e)))
1658        return False
1659    finally:
1660        ad.droid.connectivityStopTrackingConnectivityStateChange()
1661
1662
1663def verify_incall_state(log, ads, expected_status):
1664    """Verify phones in incall state or not.
1665
1666    Verify if all phones in the array <ads> are in <expected_status>.
1667
1668    Args:
1669        log: Log object.
1670        ads: Array of Android Device Object. All droid in this array will be tested.
1671        expected_status: If True, verify all Phones in incall state.
1672            If False, verify all Phones not in incall state.
1673
1674    """
1675    result = True
1676    for ad in ads:
1677        if ad.droid.telecomIsInCall() is not expected_status:
1678            log.error("Verify_incall_state: {} status:{}, expected:{}".format(
1679                ad.serial, ad.droid.telecomIsInCall(), expected_status))
1680            result = False
1681    return result
1682
1683
1684def verify_active_call_number(log, ad, expected_number):
1685    """Verify the number of current active call.
1686
1687    Verify if the number of current active call in <ad> is
1688        equal to <expected_number>.
1689
1690    Args:
1691        ad: Android Device Object.
1692        expected_number: Expected active call number.
1693    """
1694    calls = ad.droid.telecomCallGetCallIds()
1695    if calls is None:
1696        actual_number = 0
1697    else:
1698        actual_number = len(calls)
1699    if actual_number != expected_number:
1700        log.error("Active Call number in {}".format(ad.serial))
1701        log.error("Expected:{}, Actual:{}".format(expected_number,
1702                                                  actual_number))
1703        return False
1704    return True
1705
1706
1707def num_active_calls(log, ad):
1708    """Get the count of current active calls.
1709
1710    Args:
1711        log: Log object.
1712        ad: Android Device Object.
1713
1714    Returns:
1715        Count of current active calls.
1716    """
1717    calls = ad.droid.telecomCallGetCallIds()
1718    return len(calls) if calls else 0
1719
1720
1721def toggle_volte(log, ad, new_state=None):
1722    """Toggle enable/disable VoLTE for default voice subscription.
1723
1724    Args:
1725        ad: Android device object.
1726        new_state: VoLTE mode state to set to.
1727            True for enable, False for disable.
1728            If None, opposite of the current state.
1729
1730    Raises:
1731        TelTestUtilsError if platform does not support VoLTE.
1732    """
1733    return toggle_volte_for_subscription(
1734        log, ad, get_outgoing_voice_sub_id(ad), new_state)
1735
1736
1737def toggle_volte_for_subscription(log, ad, sub_id, new_state=None):
1738    """Toggle enable/disable VoLTE for specified voice subscription.
1739
1740    Args:
1741        ad: Android device object.
1742        sub_id: subscription ID
1743        new_state: VoLTE mode state to set to.
1744            True for enable, False for disable.
1745            If None, opposite of the current state.
1746
1747    Raises:
1748        TelTestUtilsError if platform does not support VoLTE.
1749    """
1750    # TODO: b/26293960 No framework API available to set IMS by SubId.
1751    if not ad.droid.imsIsEnhanced4gLteModeSettingEnabledByPlatform():
1752        raise TelTestUtilsError("VoLTE not supported by platform.")
1753    current_state = ad.droid.imsIsEnhanced4gLteModeSettingEnabledByUser()
1754    if new_state is None:
1755        new_state = not current_state
1756    if new_state != current_state:
1757        ad.droid.imsSetEnhanced4gMode(new_state)
1758    return True
1759
1760
1761def set_wfc_mode(log, ad, wfc_mode):
1762    """Set WFC enable/disable and mode.
1763
1764    Args:
1765        log: Log object
1766        ad: Android device object.
1767        wfc_mode: WFC mode to set to.
1768            Valid mode includes: WFC_MODE_WIFI_ONLY, WFC_MODE_CELLULAR_PREFERRED,
1769            WFC_MODE_WIFI_PREFERRED, WFC_MODE_DISABLED.
1770
1771    Returns:
1772        True if success. False if ad does not support WFC or error happened.
1773    """
1774    try:
1775        log.info("{} set wfc mode to {}".format(ad.serial, wfc_mode))
1776        if not ad.droid.imsIsWfcEnabledByPlatform():
1777            if wfc_mode == WFC_MODE_DISABLED:
1778                return True
1779            else:
1780                log.error("WFC not supported by platform.")
1781                return False
1782
1783        ad.droid.imsSetWfcMode(wfc_mode)
1784
1785    except Exception as e:
1786        log.error(e)
1787        return False
1788
1789    return True
1790
1791
1792def _wait_for_droid_in_state(log, ad, max_time, state_check_func, *args,
1793                             **kwargs):
1794    while max_time > 0:
1795        if state_check_func(log, ad, *args, **kwargs):
1796            return True
1797
1798        time.sleep(1)
1799        max_time -= 1
1800
1801    return False
1802
1803
1804def _wait_for_droid_in_state_for_subscription(
1805        log, ad, sub_id, max_time, state_check_func, *args, **kwargs):
1806    while max_time > 0:
1807        if state_check_func(log, ad, sub_id, *args, **kwargs):
1808            return True
1809
1810        time.sleep(1)
1811        max_time -= 1
1812
1813    return False
1814
1815
1816def _wait_for_droids_in_state(log, ads, max_time, state_check_func, *args,
1817                              **kwargs):
1818    while max_time > 0:
1819        success = True
1820        for ad in ads:
1821            if not state_check_func(log, ad, *args, **kwargs):
1822                success = False
1823                break
1824        if success:
1825            return True
1826
1827        time.sleep(1)
1828        max_time -= 1
1829
1830    return False
1831
1832
1833def is_phone_in_call(log, ad):
1834    """Return True if phone in call.
1835
1836    Args:
1837        log: log object.
1838        ad:  android device.
1839    """
1840    return ad.droid.telecomIsInCall()
1841
1842
1843def is_phone_not_in_call(log, ad):
1844    """Return True if phone not in call.
1845
1846    Args:
1847        log: log object.
1848        ad:  android device.
1849    """
1850    return not ad.droid.telecomIsInCall()
1851
1852
1853def wait_for_droid_in_call(log, ad, max_time):
1854    """Wait for android to be in call state.
1855
1856    Args:
1857        log: log object.
1858        ad:  android device.
1859        max_time: maximal wait time.
1860
1861    Returns:
1862        If phone become in call state within max_time, return True.
1863        Return False if timeout.
1864    """
1865    return _wait_for_droid_in_state(log, ad, max_time, is_phone_in_call)
1866
1867
1868def wait_for_telecom_ringing(log, ad, max_time=MAX_WAIT_TIME_TELECOM_RINGING):
1869    """Wait for android to be in telecom ringing state.
1870
1871    Args:
1872        log: log object.
1873        ad:  android device.
1874        max_time: maximal wait time. This is optional.
1875            Default Value is MAX_WAIT_TIME_TELECOM_RINGING.
1876
1877    Returns:
1878        If phone become in telecom ringing state within max_time, return True.
1879        Return False if timeout.
1880    """
1881    return _wait_for_droid_in_state(
1882        log, ad, max_time, lambda log, ad: ad.droid.telecomIsRinging())
1883
1884
1885def wait_for_droid_not_in_call(log, ad, max_time):
1886    """Wait for android to be not in call state.
1887
1888    Args:
1889        log: log object.
1890        ad:  android device.
1891        max_time: maximal wait time.
1892
1893    Returns:
1894        If phone become not in call state within max_time, return True.
1895        Return False if timeout.
1896    """
1897    return _wait_for_droid_in_state(log, ad, max_time, is_phone_not_in_call)
1898
1899
1900def _is_attached(log, ad, voice_or_data):
1901    return _is_attached_for_subscription(
1902        log, ad, ad.droid.subscriptionGetDefaultSubId(), voice_or_data)
1903
1904
1905def _is_attached_for_subscription(log, ad, sub_id, voice_or_data):
1906    if get_network_rat_for_subscription(log, ad, sub_id,
1907                                        voice_or_data) != RAT_UNKNOWN:
1908        return True
1909    else:
1910        return False
1911
1912
1913def wait_for_voice_attach(log, ad, max_time):
1914    """Wait for android device to attach on voice.
1915
1916    Args:
1917        log: log object.
1918        ad:  android device.
1919        max_time: maximal wait time.
1920
1921    Returns:
1922        Return True if device attach voice within max_time.
1923        Return False if timeout.
1924    """
1925    return _wait_for_droid_in_state(log, ad, max_time, _is_attached,
1926                                    NETWORK_SERVICE_VOICE)
1927
1928
1929def wait_for_voice_attach_for_subscription(log, ad, sub_id, max_time):
1930    """Wait for android device to attach on voice in subscription id.
1931
1932    Args:
1933        log: log object.
1934        ad:  android device.
1935        sub_id: subscription id.
1936        max_time: maximal wait time.
1937
1938    Returns:
1939        Return True if device attach voice within max_time.
1940        Return False if timeout.
1941    """
1942    if not _wait_for_droid_in_state_for_subscription(
1943            log, ad, sub_id, max_time, _is_attached_for_subscription,
1944            NETWORK_SERVICE_VOICE):
1945        return False
1946
1947    # TODO: b/26295983 if pone attach to 1xrtt from unknown, phone may not
1948    # receive incoming call immediately.
1949    if ad.droid.telephonyGetCurrentVoiceNetworkType() == RAT_1XRTT:
1950        time.sleep(WAIT_TIME_1XRTT_VOICE_ATTACH)
1951    return True
1952
1953
1954def wait_for_data_attach(log, ad, max_time):
1955    """Wait for android device to attach on data.
1956
1957    Args:
1958        log: log object.
1959        ad:  android device.
1960        max_time: maximal wait time.
1961
1962    Returns:
1963        Return True if device attach data within max_time.
1964        Return False if timeout.
1965    """
1966    return _wait_for_droid_in_state(log, ad, max_time, _is_attached,
1967                                    NETWORK_SERVICE_DATA)
1968
1969
1970def wait_for_data_attach_for_subscription(log, ad, sub_id, max_time):
1971    """Wait for android device to attach on data in subscription id.
1972
1973    Args:
1974        log: log object.
1975        ad:  android device.
1976        sub_id: subscription id.
1977        max_time: maximal wait time.
1978
1979    Returns:
1980        Return True if device attach data within max_time.
1981        Return False if timeout.
1982    """
1983    return _wait_for_droid_in_state_for_subscription(
1984        log, ad, sub_id, max_time, _is_attached_for_subscription,
1985        NETWORK_SERVICE_DATA)
1986
1987
1988def is_ims_registered(log, ad):
1989    """Return True if IMS registered.
1990
1991    Args:
1992        log: log object.
1993        ad: android device.
1994
1995    Returns:
1996        Return True if IMS registered.
1997        Return False if IMS not registered.
1998    """
1999    return ad.droid.telephonyIsImsRegistered()
2000
2001
2002def wait_for_ims_registered(log, ad, max_time):
2003    """Wait for android device to register on ims.
2004
2005    Args:
2006        log: log object.
2007        ad:  android device.
2008        max_time: maximal wait time.
2009
2010    Returns:
2011        Return True if device register ims successfully within max_time.
2012        Return False if timeout.
2013    """
2014    return _wait_for_droid_in_state(log, ad, max_time, is_ims_registered)
2015
2016
2017def is_volte_enabled(log, ad):
2018    """Return True if VoLTE feature bit is True.
2019
2020    Args:
2021        log: log object.
2022        ad: android device.
2023
2024    Returns:
2025        Return True if VoLTE feature bit is True and IMS registered.
2026        Return False if VoLTE feature bit is False or IMS not registered.
2027    """
2028    volte_status = ad.droid.telephonyIsVolteAvailable()
2029    ims_status = is_ims_registered(log, ad)
2030    if volte_status is True and ims_status is False:
2031        log.error("Error! VoLTE is Available, but IMS is not registered.")
2032        return False
2033    return volte_status
2034
2035
2036def is_video_enabled(log, ad):
2037    """Return True if Video Calling feature bit is True.
2038
2039    Args:
2040        log: log object.
2041        ad: android device.
2042
2043    Returns:
2044        Return True if Video Calling feature bit is True and IMS registered.
2045        Return False if Video Calling feature bit is False or IMS not registered.
2046    """
2047    video_status = ad.droid.telephonyIsVideoCallingAvailable()
2048    ims_status = is_ims_registered(log, ad)
2049    if video_status is True and ims_status is False:
2050        log.error("Error! Video Call is Available, but IMS is not registered.")
2051        return False
2052    return video_status
2053
2054
2055def wait_for_volte_enabled(log, ad, max_time):
2056    """Wait for android device to report VoLTE enabled bit true.
2057
2058    Args:
2059        log: log object.
2060        ad:  android device.
2061        max_time: maximal wait time.
2062
2063    Returns:
2064        Return True if device report VoLTE enabled bit true within max_time.
2065        Return False if timeout.
2066    """
2067    return _wait_for_droid_in_state(log, ad, max_time, is_volte_enabled)
2068
2069
2070def wait_for_video_enabled(log, ad, max_time):
2071    """Wait for android device to report Video Telephony enabled bit true.
2072
2073    Args:
2074        log: log object.
2075        ad:  android device.
2076        max_time: maximal wait time.
2077
2078    Returns:
2079        Return True if device report Video Telephony enabled bit true within max_time.
2080        Return False if timeout.
2081    """
2082    return _wait_for_droid_in_state(log, ad, max_time, is_video_enabled)
2083
2084
2085def is_wfc_enabled(log, ad):
2086    """Return True if WiFi Calling feature bit is True.
2087
2088    Args:
2089        log: log object.
2090        ad: android device.
2091
2092    Returns:
2093        Return True if WiFi Calling feature bit is True and IMS registered.
2094        Return False if WiFi Calling feature bit is False or IMS not registered.
2095    """
2096    wfc_status = ad.droid.telephonyIsWifiCallingAvailable()
2097    ims_status = is_ims_registered(log, ad)
2098    if wfc_status is True and ims_status is False:
2099        log.error(
2100            "Error! WiFi Calling is Available, but IMS is not registered.")
2101        return False
2102    return wfc_status
2103
2104
2105def wait_for_wfc_enabled(log, ad, max_time=MAX_WAIT_TIME_WFC_ENABLED):
2106    """Wait for android device to report WiFi Calling enabled bit true.
2107
2108    Args:
2109        log: log object.
2110        ad:  android device.
2111        max_time: maximal wait time.
2112            Default value is MAX_WAIT_TIME_WFC_ENABLED.
2113
2114    Returns:
2115        Return True if device report WiFi Calling enabled bit true within max_time.
2116        Return False if timeout.
2117    """
2118    return _wait_for_droid_in_state(log, ad, max_time, is_wfc_enabled)
2119
2120
2121def wait_for_wfc_disabled(log, ad, max_time=MAX_WAIT_TIME_WFC_DISABLED):
2122    """Wait for android device to report WiFi Calling enabled bit false.
2123
2124    Args:
2125        log: log object.
2126        ad:  android device.
2127        max_time: maximal wait time.
2128            Default value is MAX_WAIT_TIME_WFC_DISABLED.
2129
2130    Returns:
2131        Return True if device report WiFi Calling enabled bit false within max_time.
2132        Return False if timeout.
2133    """
2134    return _wait_for_droid_in_state(
2135        log, ad, max_time, lambda log, ad: not is_wfc_enabled(log, ad))
2136
2137
2138def get_phone_number(log, ad):
2139    """Get phone number for default subscription
2140
2141    Args:
2142        log: log object.
2143        ad: Android device object.
2144
2145    Returns:
2146        Phone number.
2147    """
2148    return get_phone_number_for_subscription(log, ad,
2149                                             get_outgoing_voice_sub_id(ad))
2150
2151
2152def get_phone_number_for_subscription(log, ad, subid):
2153    """Get phone number for subscription
2154
2155    Args:
2156        log: log object.
2157        ad: Android device object.
2158        subid: subscription id.
2159
2160    Returns:
2161        Phone number.
2162    """
2163    number = None
2164    try:
2165        number = ad.cfg['subscription'][subid]['phone_num']
2166    except KeyError:
2167        number = ad.droid.telephonyGetLine1NumberForSubscription(subid)
2168    return number
2169
2170
2171def set_phone_number(log, ad, phone_num):
2172    """Set phone number for default subscription
2173
2174    Args:
2175        log: log object.
2176        ad: Android device object.
2177        phone_num: phone number string.
2178
2179    Returns:
2180        True if success.
2181    """
2182    return set_phone_number_for_subscription(
2183        log, ad, get_outgoing_voice_sub_id(ad), phone_num)
2184
2185
2186def set_phone_number_for_subscription(log, ad, subid, phone_num):
2187    """Set phone number for subscription
2188
2189    Args:
2190        log: log object.
2191        ad: Android device object.
2192        subid: subscription id.
2193        phone_num: phone number string.
2194
2195    Returns:
2196        True if success.
2197    """
2198    try:
2199        ad.cfg['subscription'][subid]['phone_num'] = phone_num
2200    except Exception:
2201        return False
2202    return True
2203
2204
2205def get_operator_name(log, ad, subId=None):
2206    """Get operator name (e.g. vzw, tmo) of droid.
2207
2208    Args:
2209        ad: Android device object.
2210        sub_id: subscription ID
2211            Optional, default is None
2212
2213    Returns:
2214        Operator name.
2215    """
2216    try:
2217        if subId is not None:
2218            result = operator_name_from_plmn_id(
2219                ad.droid.telephonyGetSimOperatorForSubscription(subId))
2220        else:
2221            result = operator_name_from_plmn_id(
2222                ad.droid.telephonyGetSimOperator())
2223    except KeyError:
2224        result = CARRIER_UNKNOWN
2225    return result
2226
2227
2228def get_model_name(ad):
2229    """Get android device model name
2230
2231    Args:
2232        ad: Android device object
2233
2234    Returns:
2235        model name string
2236    """
2237    # TODO: Create translate table.
2238    model = ad.model
2239    if (model.startswith(AOSP_PREFIX)):
2240        model = model[len(AOSP_PREFIX):]
2241    return model
2242
2243
2244def is_sms_match(event, phonenumber_tx, text):
2245    """Return True if 'text' equals to event['data']['Text']
2246        and phone number match.
2247
2248    Args:
2249        event: Event object to verify.
2250        phonenumber_tx: phone number for sender.
2251        text: text string to verify.
2252
2253    Returns:
2254        Return True if 'text' equals to event['data']['Text']
2255            and phone number match.
2256    """
2257    return (
2258        check_phone_number_match(event['data']['Sender'], phonenumber_tx) and
2259        event['data']['Text'] == text)
2260
2261
2262def is_sms_partial_match(event, phonenumber_tx, text):
2263    """Return True if 'text' starts with event['data']['Text']
2264        and phone number match.
2265
2266    Args:
2267        event: Event object to verify.
2268        phonenumber_tx: phone number for sender.
2269        text: text string to verify.
2270
2271    Returns:
2272        Return True if 'text' starts with event['data']['Text']
2273            and phone number match.
2274    """
2275    return (
2276        check_phone_number_match(event['data']['Sender'], phonenumber_tx) and
2277        text.startswith(event['data']['Text']))
2278
2279
2280def sms_send_receive_verify(log, ad_tx, ad_rx, array_message):
2281    """Send SMS, receive SMS, and verify content and sender's number.
2282
2283        Send (several) SMS from droid_tx to droid_rx.
2284        Verify SMS is sent, delivered and received.
2285        Verify received content and sender's number are correct.
2286
2287    Args:
2288        log: Log object.
2289        ad_tx: Sender's Android Device Object
2290        ad_rx: Receiver's Android Device Object
2291        array_message: the array of message to send/receive
2292    """
2293    subid_tx = get_outgoing_message_sub_id(ad_tx)
2294    subid_rx = get_incoming_message_sub_id(ad_rx)
2295    return sms_send_receive_verify_for_subscription(
2296        log, ad_tx, ad_rx, subid_tx, subid_rx, array_message)
2297
2298
2299def wait_for_matching_sms(log,
2300                          ad_rx,
2301                          phonenumber_tx,
2302                          text,
2303                          allow_multi_part_long_sms=True):
2304    """Wait for matching incoming SMS.
2305
2306    Args:
2307        log: Log object.
2308        ad_rx: Receiver's Android Device Object
2309        phonenumber_tx: Sender's phone number.
2310        text: SMS content string.
2311        allow_multi_part_long_sms: is long SMS allowed to be received as
2312            multiple short SMS. This is optional, default value is True.
2313
2314    Returns:
2315        True if matching incoming SMS is received.
2316    """
2317    if not allow_multi_part_long_sms:
2318        try:
2319            ad_rx.ed.wait_for_event(EventSmsReceived, is_sms_match,
2320                                    MAX_WAIT_TIME_SMS_RECEIVE, phonenumber_tx,
2321                                    text)
2322            return True
2323        except Empty:
2324            log.error("No matched SMS received event.")
2325            return False
2326    else:
2327        try:
2328            received_sms = ''
2329            while (text != ''):
2330                event = ad_rx.ed.wait_for_event(
2331                    EventSmsReceived, is_sms_partial_match,
2332                    MAX_WAIT_TIME_SMS_RECEIVE, phonenumber_tx, text)
2333                text = text[len(event['data']['Text']):]
2334                received_sms += event['data']['Text']
2335            return True
2336        except Empty:
2337            log.error("No matched SMS received event.")
2338            if received_sms != '':
2339                log.error("Only received partial matched SMS: {}".format(
2340                    received_sms))
2341            return False
2342
2343
2344def sms_send_receive_verify_for_subscription(log, ad_tx, ad_rx, subid_tx,
2345                                             subid_rx, array_message):
2346    """Send SMS, receive SMS, and verify content and sender's number.
2347
2348        Send (several) SMS from droid_tx to droid_rx.
2349        Verify SMS is sent, delivered and received.
2350        Verify received content and sender's number are correct.
2351
2352    Args:
2353        log: Log object.
2354        ad_tx: Sender's Android Device Object..
2355        ad_rx: Receiver's Android Device Object.
2356        subid_tx: Sender's subsciption ID to be used for SMS
2357        subid_rx: Receiver's subsciption ID to be used for SMS
2358        array_message: the array of message to send/receive
2359    """
2360
2361    phonenumber_tx = ad_tx.cfg['subscription'][subid_tx]['phone_num']
2362    phonenumber_rx = ad_rx.cfg['subscription'][subid_rx]['phone_num']
2363    for text in array_message:
2364        log.info("Sending SMS {} to {}, len: {}, content: {}.".format(
2365            phonenumber_tx, phonenumber_rx, len(text), text))
2366        result = False
2367        ad_rx.ed.clear_all_events()
2368        ad_rx.droid.smsStartTrackingIncomingSmsMessage()
2369        try:
2370            ad_tx.droid.smsSendTextMessage(phonenumber_rx, text, True)
2371
2372            try:
2373                ad_tx.ed.pop_event(EventSmsSentSuccess,
2374                                   MAX_WAIT_TIME_SMS_SENT_SUCCESS)
2375            except Empty:
2376                log.error("No sent_success event.")
2377                return False
2378
2379            if not wait_for_matching_sms(log,
2380                                         ad_rx,
2381                                         phonenumber_tx,
2382                                         text,
2383                                         allow_multi_part_long_sms=True):
2384                return False
2385        finally:
2386            ad_rx.droid.smsStopTrackingIncomingSmsMessage()
2387    return True
2388
2389
2390def mms_send_receive_verify(log, ad_tx, ad_rx, array_message):
2391    """Send SMS, receive SMS, and verify content and sender's number.
2392
2393        Send (several) SMS from droid_tx to droid_rx.
2394        Verify SMS is sent, delivered and received.
2395        Verify received content and sender's number are correct.
2396
2397    Args:
2398        log: Log object.
2399        ad_tx: Sender's Android Device Object
2400        ad_rx: Receiver's Android Device Object
2401        array_message: the array of message to send/receive
2402    """
2403    return mms_send_receive_verify_for_subscription(
2404        log, ad_tx, ad_rx, get_outgoing_message_sub_id(ad_tx),
2405        get_incoming_message_sub_id(ad_rx), array_message)
2406
2407
2408#TODO: b/21569494 This function is still a WIP and is disabled
2409def mms_send_receive_verify_for_subscription(log, ad_tx, ad_rx, subid_tx,
2410                                             subid_rx, array_payload):
2411    """Send SMS, receive SMS, and verify content and sender's number.
2412
2413        Send (several) SMS from droid_tx to droid_rx.
2414        Verify SMS is sent, delivered and received.
2415        Verify received content and sender's number are correct.
2416
2417    Args:
2418        log: Log object.
2419        ad_tx: Sender's Android Device Object..
2420        ad_rx: Receiver's Android Device Object.
2421        subid_tx: Sender's subsciption ID to be used for SMS
2422        subid_rx: Receiver's subsciption ID to be used for SMS
2423        array_message: the array of message to send/receive
2424    """
2425
2426    log.error("Function is non-working: b/21569494")
2427    return False
2428
2429    phonenumber_tx = ad_tx.cfg['subscription'][subid_tx]['phone_num']
2430    phonenumber_rx = ad_rx.cfg['subscription'][subid_rx]['phone_num']
2431    for subject, message, filename in array_payload:
2432        log.info("Sending MMS {} to {}, subject: {}, message: {}.".format(
2433            phonenumber_tx, phonenumber_rx, subject, message))
2434        result = False
2435        ad_rx.ed.clear_all_events()
2436        ad_rx.droid.smsStartTrackingIncomingMmsMessage()
2437        ad_rx.droid.smsStartTrackingIncomingSmsMessage()
2438        try:
2439            ad_tx.droid.smsSendMultimediaMessage(
2440                phonenumber_rx, subject, message, phonenumber_tx, filename)
2441
2442            ad_tx.ed.pop_event(EventMmsSentSuccess,
2443                               MAX_WAIT_TIME_SMS_SENT_SUCCESS)
2444
2445            start_time = time.time()
2446            remaining_time = MAX_WAIT_TIME_SMS_RECEIVE
2447            while remaining_time > 0:
2448                event = ad_rx.ed.pop_event(EventSmsReceived, remaining_time)
2449                if check_phone_number_match(event['data']['Sender'],
2450                                            phonenumber_tx):
2451                    log.debug("Received SMS Indication")
2452                    while remaining_time > 0:
2453                        event = ad_rx.ed.pop_event(EventDataSmsReceived,
2454                                                   remaining_time)
2455                        if check_phone_number_match(event['data']['Sender'],
2456                                                    phonenumber_tx):
2457                            result = True
2458                            break
2459                        remaining_time = time.time() - start_time
2460                remaining_time = time.time() - start_time
2461
2462            if not result:
2463                log.info("Expected sender:" + phonenumber_tx)
2464                log.error("Received sender:" + event['data']['Sender'])
2465                log.error("Failed in verify receiving MMS.")
2466                return False
2467        finally:
2468            ad_rx.droid.smsStopTrackingIncomingSmsMessage()
2469            ad_rx.droid.smsStopTrackingIncomingMmsMessage()
2470    return True
2471
2472
2473def ensure_network_rat(log,
2474                       ad,
2475                       network_preference,
2476                       rat_family,
2477                       voice_or_data=None,
2478                       max_wait_time=MAX_WAIT_TIME_NW_SELECTION,
2479                       toggle_apm_after_setting=False):
2480    """Ensure ad's current network is in expected rat_family.
2481    """
2482    return ensure_network_rat_for_subscription(
2483        log, ad, ad.droid.subscriptionGetDefaultSubId(), network_preference,
2484        rat_family, voice_or_data, max_wait_time, toggle_apm_after_setting)
2485
2486
2487def ensure_network_rat_for_subscription(
2488        log,
2489        ad,
2490        sub_id,
2491        network_preference,
2492        rat_family,
2493        voice_or_data=None,
2494        max_wait_time=MAX_WAIT_TIME_NW_SELECTION,
2495        toggle_apm_after_setting=False):
2496    """Ensure ad's current network is in expected rat_family.
2497    """
2498    if not ad.droid.telephonySetPreferredNetworkTypesForSubscription(
2499            network_preference, sub_id):
2500        log.error("Set Preferred Networks failed.")
2501        return False
2502    if is_droid_in_rat_family_for_subscription(log, ad, sub_id, rat_family,
2503                                               voice_or_data):
2504        return True
2505
2506    if toggle_apm_after_setting:
2507        toggle_airplane_mode(log, ad, True)
2508        time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
2509        toggle_airplane_mode(log, ad, False)
2510
2511    result = wait_for_network_rat_for_subscription(
2512        log, ad, sub_id, rat_family, max_wait_time, voice_or_data)
2513
2514    log.info(
2515        "End of ensure_network_rat_for_subscription for {}. "
2516        "Setting to {}, Expecting {} {}. Current: voice: {}(family: {}), "
2517        "data: {}(family: {})".format(
2518            ad.serial, network_preference, rat_family, voice_or_data,
2519            ad.droid.telephonyGetCurrentVoiceNetworkTypeForSubscription(
2520                sub_id),
2521            rat_family_from_rat(
2522                ad.droid.telephonyGetCurrentVoiceNetworkTypeForSubscription(
2523                    sub_id)),
2524            ad.droid.telephonyGetCurrentDataNetworkTypeForSubscription(
2525                sub_id), rat_family_from_rat(
2526                    ad.droid.telephonyGetCurrentDataNetworkTypeForSubscription(
2527                        sub_id))))
2528    return result
2529
2530
2531def ensure_network_preference(log,
2532                              ad,
2533                              network_preference,
2534                              voice_or_data=None,
2535                              max_wait_time=MAX_WAIT_TIME_NW_SELECTION,
2536                              toggle_apm_after_setting=False):
2537    """Ensure that current rat is within the device's preferred network rats.
2538    """
2539    return ensure_network_preference_for_subscription(
2540        log, ad, ad.droid.subscriptionGetDefaultSubId(), network_preference,
2541        voice_or_data, max_wait_time, toggle_apm_after_setting)
2542
2543
2544def ensure_network_preference_for_subscription(
2545        log,
2546        ad,
2547        sub_id,
2548        network_preference,
2549        voice_or_data=None,
2550        max_wait_time=MAX_WAIT_TIME_NW_SELECTION,
2551        toggle_apm_after_setting=False):
2552    """Ensure ad's network preference is <network_preference> for sub_id.
2553    """
2554    rat_family_list = rat_families_for_network_preference(network_preference)
2555    if not ad.droid.telephonySetPreferredNetworkTypesForSubscription(
2556            network_preference, sub_id):
2557        log.error("Set Preferred Networks failed.")
2558        return False
2559    if is_droid_in_rat_family_list_for_subscription(
2560            log, ad, sub_id, rat_family_list, voice_or_data):
2561        return True
2562
2563    if toggle_apm_after_setting:
2564        toggle_airplane_mode(log, ad, True)
2565        time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
2566        toggle_airplane_mode(log, ad, False)
2567
2568    result = wait_for_preferred_network_for_subscription(
2569        log, ad, sub_id, network_preference, max_wait_time, voice_or_data)
2570
2571    log.info(
2572        "End of ensure_network_preference_for_subscription for {}. "
2573        "Setting to {}, Expecting {} {}. Current: voice: {}(family: {}), "
2574        "data: {}(family: {})".format(
2575            ad.serial, network_preference, rat_family_list, voice_or_data,
2576            ad.droid.telephonyGetCurrentVoiceNetworkTypeForSubscription(
2577                sub_id),
2578            rat_family_from_rat(
2579                ad.droid.telephonyGetCurrentVoiceNetworkTypeForSubscription(
2580                    sub_id)),
2581            ad.droid.telephonyGetCurrentDataNetworkTypeForSubscription(
2582                sub_id), rat_family_from_rat(
2583                    ad.droid.telephonyGetCurrentDataNetworkTypeForSubscription(
2584                        sub_id))))
2585    return result
2586
2587
2588def ensure_network_generation(log,
2589                              ad,
2590                              generation,
2591                              max_wait_time=MAX_WAIT_TIME_NW_SELECTION,
2592                              voice_or_data=None,
2593                              toggle_apm_after_setting=False):
2594    """Ensure ad's network is <network generation> for default subscription ID.
2595
2596    Set preferred network generation to <generation>.
2597    Toggle ON/OFF airplane mode if necessary.
2598    Wait for ad in expected network type.
2599    """
2600    return ensure_network_generation_for_subscription(
2601        log, ad, ad.droid.subscriptionGetDefaultSubId(), generation,
2602        max_wait_time, voice_or_data, toggle_apm_after_setting)
2603
2604
2605def ensure_network_generation_for_subscription(
2606        log,
2607        ad,
2608        sub_id,
2609        generation,
2610        max_wait_time=MAX_WAIT_TIME_NW_SELECTION,
2611        voice_or_data=None,
2612        toggle_apm_after_setting=False):
2613    """Ensure ad's network is <network generation> for specified subscription ID.
2614
2615    Set preferred network generation to <generation>.
2616    Toggle ON/OFF airplane mode if necessary.
2617    Wait for ad in expected network type.
2618    """
2619    if is_droid_in_network_generation_for_subscription(
2620            log, ad, sub_id, generation, voice_or_data):
2621        return True
2622
2623    operator = get_operator_name(log, ad, sub_id)
2624    try:
2625        network_preference = network_preference_for_generaton(generation,
2626                                                              operator)
2627        rat_family = rat_family_for_generation(generation, operator)
2628    except KeyError:
2629        log.error("Failed to find a rat_family entry for "
2630                  "PLMN: {}, operator:{}, generation: {}".format(
2631                      ad.droid.telephonyGetSimOperatorForSubscription(
2632                          sub_id), operator, generation))
2633        return False
2634
2635    if not ad.droid.telephonySetPreferredNetworkTypesForSubscription(
2636            network_preference, sub_id):
2637        log.error("Set Preferred Networks failed.")
2638        return False
2639
2640    if toggle_apm_after_setting:
2641        toggle_airplane_mode(log, ad, True)
2642        time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
2643        toggle_airplane_mode(log, ad, False)
2644
2645    result = wait_for_network_generation_for_subscription(
2646        log, ad, sub_id, generation, max_wait_time, voice_or_data)
2647
2648    log.info(
2649        "End of ensure_network_generation_for_subscription for {}. "
2650        "Setting to {}, Expecting {} {}. Current: voice: {}(family: {}), "
2651        "data: {}(family: {})".format(
2652            ad.serial, network_preference, generation, voice_or_data,
2653            ad.droid.telephonyGetCurrentVoiceNetworkTypeForSubscription(
2654                sub_id),
2655            rat_generation_from_rat(
2656                ad.droid.telephonyGetCurrentVoiceNetworkTypeForSubscription(
2657                    sub_id)),
2658            ad.droid.telephonyGetCurrentDataNetworkTypeForSubscription(
2659                sub_id), rat_generation_from_rat(
2660                    ad.droid.telephonyGetCurrentDataNetworkTypeForSubscription(
2661                        sub_id))))
2662
2663    return result
2664
2665
2666def wait_for_network_rat(log,
2667                         ad,
2668                         rat_family,
2669                         max_wait_time=MAX_WAIT_TIME_NW_SELECTION,
2670                         voice_or_data=None):
2671    return wait_for_network_rat_for_subscription(
2672        log, ad, ad.droid.subscriptionGetDefaultSubId(), rat_family,
2673        max_wait_time, voice_or_data)
2674
2675
2676def wait_for_network_rat_for_subscription(
2677        log,
2678        ad,
2679        sub_id,
2680        rat_family,
2681        max_wait_time=MAX_WAIT_TIME_NW_SELECTION,
2682        voice_or_data=None):
2683    return _wait_for_droid_in_state_for_subscription(
2684        log, ad, sub_id, max_wait_time,
2685        is_droid_in_rat_family_for_subscription, rat_family, voice_or_data)
2686
2687
2688def wait_for_not_network_rat(log,
2689                             ad,
2690                             rat_family,
2691                             max_wait_time=MAX_WAIT_TIME_NW_SELECTION,
2692                             voice_or_data=None):
2693    return wait_for_not_network_rat_for_subscription(
2694        log, ad, ad.droid.subscriptionGetDefaultSubId(), rat_family,
2695        max_wait_time, voice_or_data)
2696
2697
2698def wait_for_not_network_rat_for_subscription(
2699        log,
2700        ad,
2701        sub_id,
2702        rat_family,
2703        max_wait_time=MAX_WAIT_TIME_NW_SELECTION,
2704        voice_or_data=None):
2705    return _wait_for_droid_in_state_for_subscription(
2706        log, ad, sub_id, max_wait_time,
2707        lambda log, ad, sub_id, *args, **kwargs: not is_droid_in_rat_family_for_subscription(log, ad, sub_id, rat_family, voice_or_data))
2708
2709
2710def wait_for_preferred_network(log,
2711                               ad,
2712                               network_preference,
2713                               max_wait_time=MAX_WAIT_TIME_NW_SELECTION,
2714                               voice_or_data=None):
2715    return wait_for_preferred_network_for_subscription(
2716        log, ad, ad.droid.subscriptionGetDefaultSubId(), network_preference,
2717        max_wait_time, voice_or_data)
2718
2719
2720def wait_for_preferred_network_for_subscription(
2721        log,
2722        ad,
2723        sub_id,
2724        network_preference,
2725        max_wait_time=MAX_WAIT_TIME_NW_SELECTION,
2726        voice_or_data=None):
2727    rat_family_list = rat_families_for_network_preference(network_preference)
2728    return _wait_for_droid_in_state_for_subscription(
2729        log, ad, sub_id, max_wait_time,
2730        is_droid_in_rat_family_list_for_subscription, rat_family_list,
2731        voice_or_data)
2732
2733
2734def wait_for_network_generation(log,
2735                                ad,
2736                                generation,
2737                                max_wait_time=MAX_WAIT_TIME_NW_SELECTION,
2738                                voice_or_data=None):
2739    return wait_for_network_generation_for_subscription(
2740        log, ad, ad.droid.subscriptionGetDefaultSubId(), generation,
2741        max_wait_time, voice_or_data)
2742
2743
2744def wait_for_network_generation_for_subscription(
2745        log,
2746        ad,
2747        sub_id,
2748        generation,
2749        max_wait_time=MAX_WAIT_TIME_NW_SELECTION,
2750        voice_or_data=None):
2751    return _wait_for_droid_in_state_for_subscription(
2752        log, ad, sub_id, max_wait_time,
2753        is_droid_in_network_generation_for_subscription, generation,
2754        voice_or_data)
2755
2756
2757def is_droid_in_rat_family(log, ad, rat_family, voice_or_data=None):
2758    return is_droid_in_rat_family_for_subscription(
2759        log, ad, ad.droid.subscriptionGetDefaultSubId(), rat_family,
2760        voice_or_data)
2761
2762
2763def is_droid_in_rat_family_for_subscription(log,
2764                                            ad,
2765                                            sub_id,
2766                                            rat_family,
2767                                            voice_or_data=None):
2768    return is_droid_in_rat_family_list_for_subscription(
2769        log, ad, sub_id, [rat_family], voice_or_data)
2770
2771
2772def is_droid_in_rat_familiy_list(log, ad, rat_family_list, voice_or_data=None):
2773    return is_droid_in_rat_family_list_for_subscription(
2774        log, ad, ad.droid.subscriptionGetDefaultSubId(), rat_family_list,
2775        voice_or_data)
2776
2777
2778def is_droid_in_rat_family_list_for_subscription(log,
2779                                                 ad,
2780                                                 sub_id,
2781                                                 rat_family_list,
2782                                                 voice_or_data=None):
2783    service_list = [NETWORK_SERVICE_DATA, NETWORK_SERVICE_VOICE]
2784    if voice_or_data:
2785        service_list = [voice_or_data]
2786
2787    for service in service_list:
2788        nw_rat = get_network_rat_for_subscription(log, ad, sub_id, service)
2789        if nw_rat == RAT_UNKNOWN or not is_valid_rat(nw_rat):
2790            continue
2791        if rat_family_from_rat(nw_rat) in rat_family_list:
2792            return True
2793    return False
2794
2795
2796def is_droid_in_network_generation(log, ad, nw_gen, voice_or_data):
2797    """Checks if a droid in expected network generation ("2g", "3g" or "4g").
2798
2799    Args:
2800        log: log object.
2801        ad: android device.
2802        nw_gen: expected generation "4g", "3g", "2g".
2803        voice_or_data: check voice network generation or data network generation
2804            This parameter is optional. If voice_or_data is None, then if
2805            either voice or data in expected generation, function will return True.
2806
2807    Returns:
2808        True if droid in expected network generation. Otherwise False.
2809    """
2810    return is_droid_in_network_generation_for_subscription(
2811        log, ad, ad.droid.subscriptionGetDefaultSubId(), nw_gen, voice_or_data)
2812
2813
2814def is_droid_in_network_generation_for_subscription(log, ad, sub_id, nw_gen,
2815                                                    voice_or_data):
2816    """Checks if a droid in expected network generation ("2g", "3g" or "4g").
2817
2818    Args:
2819        log: log object.
2820        ad: android device.
2821        nw_gen: expected generation "4g", "3g", "2g".
2822        voice_or_data: check voice network generation or data network generation
2823            This parameter is optional. If voice_or_data is None, then if
2824            either voice or data in expected generation, function will return True.
2825
2826    Returns:
2827        True if droid in expected network generation. Otherwise False.
2828    """
2829    service_list = [NETWORK_SERVICE_DATA, NETWORK_SERVICE_VOICE]
2830
2831    if voice_or_data:
2832        service_list = [voice_or_data]
2833
2834    for service in service_list:
2835        nw_rat = get_network_rat_for_subscription(log, ad, sub_id, service)
2836
2837        if nw_rat == RAT_UNKNOWN or not is_valid_rat(nw_rat):
2838            continue
2839
2840        if rat_generation_from_rat(nw_rat) == nw_gen:
2841            return True
2842        else:
2843            return False
2844
2845    return False
2846
2847
2848def get_network_rat(log, ad, voice_or_data):
2849    """Get current network type (Voice network type, or data network type)
2850       for default subscription id
2851
2852    Args:
2853        ad: Android Device Object
2854        voice_or_data: Input parameter indicating to get voice network type or
2855            data network type.
2856
2857    Returns:
2858        Current voice/data network type.
2859    """
2860    return get_network_rat_for_subscription(
2861        log, ad, ad.droid.subscriptionGetDefaultSubId(), voice_or_data)
2862
2863
2864def get_network_rat_for_subscription(log, ad, sub_id, voice_or_data):
2865    """Get current network type (Voice network type, or data network type)
2866       for specified subscription id
2867
2868    Args:
2869        ad: Android Device Object
2870        sub_id: subscription ID
2871        voice_or_data: Input parameter indicating to get voice network type or
2872            data network type.
2873
2874    Returns:
2875        Current voice/data network type.
2876    """
2877    if voice_or_data == NETWORK_SERVICE_VOICE:
2878        ret_val = ad.droid.telephonyGetCurrentVoiceNetworkTypeForSubscription(
2879            sub_id)
2880    elif voice_or_data == NETWORK_SERVICE_DATA:
2881        ret_val = ad.droid.telephonyGetCurrentDataNetworkTypeForSubscription(
2882            sub_id)
2883    else:
2884        ret_val = ad.droid.telephonyGetNetworkTypeForSubscription(sub_id)
2885
2886    if ret_val is None:
2887        log.error("get_network_rat(): Unexpected null return value")
2888        return RAT_UNKNOWN
2889    else:
2890        return ret_val
2891
2892
2893def get_network_gen(log, ad, voice_or_data):
2894    """Get current network generation string (Voice network type, or data network type)
2895
2896    Args:
2897        ad: Android Device Object
2898        voice_or_data: Input parameter indicating to get voice network generation
2899            or data network generation.
2900
2901    Returns:
2902        Current voice/data network generation.
2903    """
2904    return get_network_gen_for_subscription(
2905        log, ad, ad.droid.subscriptionGetDefaultSubId(), voice_or_data)
2906
2907
2908def get_network_gen_for_subscription(log, ad, sub_id, voice_or_data):
2909    """Get current network generation string (Voice network type, or data network type)
2910
2911    Args:
2912        ad: Android Device Object
2913        voice_or_data: Input parameter indicating to get voice network generation
2914            or data network generation.
2915
2916    Returns:
2917        Current voice/data network generation.
2918    """
2919    try:
2920        return rat_generation_from_rat(get_network_rat_for_subscription(
2921            log, ad, sub_id, voice_or_data))
2922    except KeyError:
2923        log.error(
2924            "KeyError happened in get_network_gen, ad:{}, d/v: {}, rat: {}".format(
2925                ad.serial, voice_or_data, get_network_rat_for_subscription(
2926                    log, ad, sub_id, voice_or_data)))
2927        return GEN_UNKNOWN
2928
2929
2930def check_voice_mail_count(log, ad, voice_mail_count_before,
2931                           voice_mail_count_after):
2932    """function to check if voice mail count is correct after leaving a new voice message.
2933    """
2934    return get_voice_mail_count_check_function(get_operator_name(log, ad))(
2935        voice_mail_count_before, voice_mail_count_after)
2936
2937
2938def get_voice_mail_number(log, ad):
2939    """function to get the voice mail number
2940    """
2941    voice_mail_number = get_voice_mail_number_function(get_operator_name(log,
2942                                                                         ad))()
2943    if voice_mail_number is None:
2944        return get_phone_number(log, ad)
2945    return voice_mail_number
2946
2947
2948def ensure_phones_idle(log,
2949                       ads,
2950                       settling_time=WAIT_TIME_ANDROID_STATE_SETTLING):
2951    """Ensure ads idle (not in call).
2952    """
2953    for ad in ads:
2954        if ad.droid.telecomIsInCall():
2955            ad.droid.telecomEndCall()
2956    # Leave the delay time to make sure droid can recover to idle from ongoing call.
2957    time.sleep(settling_time)
2958    return True
2959
2960
2961def ensure_phone_idle(log, ad, settling_time=WAIT_TIME_ANDROID_STATE_SETTLING):
2962    """Ensure ad idle (not in call).
2963    """
2964    return ensure_phones_idle(log, [ad], settling_time)
2965
2966
2967def ensure_phone_default_state(log, ad):
2968    """Ensure ad in default state.
2969    Phone not in call.
2970    Phone have no stored WiFi network and WiFi disconnected.
2971    Phone not in airplane mode.
2972    """
2973    result = True
2974    if ad.droid.telecomIsInCall():
2975        ad.droid.telecomEndCall()
2976    set_wfc_mode(log, ad, WFC_MODE_DISABLED)
2977
2978    if not wait_for_not_network_rat(log,
2979                                    ad,
2980                                    RAT_FAMILY_WLAN,
2981                                    voice_or_data=NETWORK_SERVICE_DATA):
2982        log.error(
2983            "ensure_phones_default_state: wait_for_droid_not_in iwlan fail {}.".format(
2984                ad.serial))
2985        result = False
2986    if (not WifiUtils.wifi_reset(log, ad)):
2987        log.error("ensure_phones_default_state:reset WiFi fail {}.".format(
2988            ad.serial))
2989        result = False
2990    if not toggle_airplane_mode(log, ad, False):
2991        log.error(
2992            "ensure_phones_default_state:turn off airplane mode fail {}.".format(
2993                ad.serial))
2994        result = False
2995    # make sure phone data is on
2996    ad.droid.telephonyToggleDataConnection(True)
2997
2998    # Leave the delay time to make sure droid can recover to idle from ongoing call.
2999    time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
3000    return result
3001
3002
3003def ensure_phones_default_state(log, ads):
3004    """Ensure ads in default state.
3005    Phone not in call.
3006    Phone have no stored WiFi network and WiFi disconnected.
3007    Phone not in airplane mode.
3008    """
3009    tasks = []
3010    for ad in ads:
3011        tasks.append((ensure_phone_default_state, (log, ad)))
3012    if not multithread_func(log, tasks):
3013        log.error("Ensure_phones_default_state Fail.")
3014        return False
3015    return True
3016
3017
3018def ensure_wifi_connected(log, ad, wifi_ssid, wifi_pwd=None, retry=0):
3019    """Ensure ad connected to wifi.
3020
3021    Args:
3022        log: Log object.
3023        ad: Android device object.
3024        wifi_ssid: WiFi network SSID.
3025        wifi_pwd: WiFi network password. This is optional.
3026
3027    """
3028    while (retry >= 0):
3029        WifiUtils.wifi_reset(log, ad)
3030        WifiUtils.wifi_toggle_state(log, ad, True)
3031        if WifiUtils.wifi_connect(log, ad, wifi_ssid, wifi_pwd):
3032            return True
3033        else:
3034            log.info("ensure_wifi_connected: Connect WiFi failed")
3035            retry -= 1
3036    return False
3037
3038
3039def reset_preferred_network_type_to_allowable_range(log, ad):
3040    """If preferred network type is not in allowable range, reset to GEN_4G
3041    preferred network type.
3042
3043    Args:
3044        log: log object
3045        ad: android device object
3046
3047    Returns:
3048        None
3049    """
3050    sub_info_list = ad.droid.subscriptionGetAllSubInfoList()
3051    for sub_info in sub_info_list:
3052        sub_id = sub_info['subscriptionId']
3053        operator = get_operator_name(log, ad, sub_id)
3054        current_preference = \
3055            ad.droid.telephonyGetPreferredNetworkTypesForSubscription(sub_id)
3056        try:
3057            if current_preference not in get_allowable_network_preference(
3058                    operator):
3059                network_preference = network_preference_for_generaton(GEN_4G,
3060                                                                      operator)
3061                ad.droid.telephonySetPreferredNetworkTypesForSubscription(
3062                    network_preference, sub_id)
3063        except KeyError:
3064            pass
3065
3066
3067def task_wrapper(task):
3068    """Task wrapper for multithread_func
3069
3070    Args:
3071        task[0]: function to be wrapped.
3072        task[1]: function args.
3073
3074    Returns:
3075        Return value of wrapped function call.
3076    """
3077    func = task[0]
3078    params = task[1]
3079    return func(*params)
3080
3081
3082def multithread_func(log, tasks):
3083    """Multi-thread function wrapper.
3084
3085    Args:
3086        log: log object.
3087        tasks: tasks to be executed in parallel.
3088
3089    Returns:
3090        True if all tasks return True.
3091        False if any task return False.
3092    """
3093    MAX_NUMBER_OF_WORKERS = 4
3094    number_of_workers = min(MAX_NUMBER_OF_WORKERS, len(tasks))
3095    executor = concurrent.futures.ThreadPoolExecutor(
3096        max_workers=number_of_workers)
3097    results = list(executor.map(task_wrapper, tasks))
3098    executor.shutdown()
3099    log.info("multithread_func result: {}".format(results))
3100    for r in results:
3101        if not r:
3102            return False
3103    return True
3104
3105
3106def set_phone_screen_on(log, ad, screen_on_time=MAX_SCREEN_ON_TIME):
3107    """Set phone screen on time.
3108
3109    Args:
3110        log: Log object.
3111        ad: Android device object.
3112        screen_on_time: screen on time.
3113            This is optional, default value is MAX_SCREEN_ON_TIME.
3114    Returns:
3115        True if set successfully.
3116    """
3117    ad.droid.setScreenTimeout(screen_on_time)
3118    return screen_on_time == ad.droid.getScreenTimeout()
3119
3120
3121def set_phone_silent_mode(log, ad, silent_mode=True):
3122    """Set phone silent mode.
3123
3124    Args:
3125        log: Log object.
3126        ad: Android device object.
3127        silent_mode: set phone silent or not.
3128            This is optional, default value is True (silent mode on).
3129    Returns:
3130        True if set successfully.
3131    """
3132    ad.droid.toggleRingerSilentMode(silent_mode)
3133    return silent_mode == ad.droid.checkRingerSilentMode()
3134
3135
3136def set_preferred_subid_for_sms(log, ad, sub_id):
3137    """set subscription id for SMS
3138
3139    Args:
3140        log: Log object.
3141        ad: Android device object.
3142        sub_id :Subscription ID.
3143
3144    """
3145    log.info("Setting subscription:{} as Message SIM for {}".format(sub_id,
3146                                                                    ad.serial))
3147    ad.droid.subscriptionSetDefaultSmsSubId(sub_id)
3148    # Wait to make sure settings take effect
3149    time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
3150    return sub_id == ad.droid.subscriptionGetDefaultSmsSubId()
3151
3152
3153def set_preferred_subid_for_data(log, ad, sub_id):
3154    """set subscription id for data
3155
3156    Args:
3157        log: Log object.
3158        ad: Android device object.
3159        sub_id :Subscription ID.
3160
3161    """
3162    log.info("Setting subscription:{} as Data SIM for {}".format(sub_id,
3163                                                                 ad.serial))
3164    ad.droid.subscriptionSetDefaultDataSubId(sub_id)
3165    time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
3166    # Wait to make sure settings take effect
3167    # Data SIM change takes around 1 min
3168    # Check whether data has changed to selected sim
3169    if not wait_for_data_connection(log, ad, True,
3170                                    MAX_WAIT_TIME_DATA_SUB_CHANGE):
3171        log.error("Data Connection failed - Not able to switch Data SIM")
3172        return False
3173    return True
3174
3175
3176def set_preferred_subid_for_voice(log, ad, sub_id):
3177    """set subscription id for voice
3178
3179    Args:
3180        log: Log object.
3181        ad: Android device object.
3182        sub_id :Subscription ID.
3183
3184    """
3185    log.info("Setting subscription:{} as Voice SIM for {}".format(sub_id,
3186                                                                  ad.serial))
3187    ad.droid.subscriptionSetDefaultVoiceSubId(sub_id)
3188    ad.droid.telecomSetUserSelectedOutgoingPhoneAccountBySubId(sub_id)
3189    # Wait to make sure settings take effect
3190    time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
3191    return True
3192
3193
3194def set_call_state_listen_level(log, ad, value, sub_id):
3195    """Set call state listen level for subscription id.
3196
3197    Args:
3198        log: Log object.
3199        ad: Android device object.
3200        value: True or False
3201        sub_id :Subscription ID.
3202
3203    Returns:
3204        True or False
3205    """
3206    if sub_id == INVALID_SUB_ID:
3207        log.error("Invalid Subscription ID")
3208        return False
3209    ad.droid.telephonyAdjustPreciseCallStateListenLevelForSubscription(
3210        "Foreground", value, sub_id)
3211    ad.droid.telephonyAdjustPreciseCallStateListenLevelForSubscription(
3212        "Ringing", value, sub_id)
3213    ad.droid.telephonyAdjustPreciseCallStateListenLevelForSubscription(
3214        "Background", value, sub_id)
3215    return True
3216
3217
3218def setup_sim(log, ad, sub_id, voice=False, sms=False, data=False):
3219    """set subscription id for voice, sms and data
3220
3221    Args:
3222        log: Log object.
3223        ad: Android device object.
3224        sub_id :Subscription ID.
3225        voice: True if to set subscription as default voice subscription
3226        sms: True if to set subscription as default sms subscription
3227        data: True if to set subscription as default data subscription
3228
3229    """
3230    if sub_id == INVALID_SUB_ID:
3231        log.error("Invalid Subscription ID")
3232        return False
3233    else:
3234        if voice:
3235            if not set_preferred_subid_for_voice(log, ad, sub_id):
3236                return False
3237        if sms:
3238            if not set_preferred_subid_for_sms(log, ad, sub_id):
3239                return False
3240        if data:
3241            if not set_preferred_subid_for_data(log, ad, sub_id):
3242                return False
3243    return True
3244
3245
3246def is_event_match(event, field, value):
3247    """Return if <field> in "event" match <value> or not.
3248
3249    Args:
3250        event: event to test. This event need to have <field>.
3251        field: field to match.
3252        value: value to match.
3253
3254    Returns:
3255        True if <field> in "event" match <value>.
3256        False otherwise.
3257    """
3258    return is_event_match_for_list(event, field, [value])
3259
3260
3261def is_event_match_for_list(event, field, value_list):
3262    """Return if <field> in "event" match any one of the value
3263        in "value_list" or not.
3264
3265    Args:
3266        event: event to test. This event need to have <field>.
3267        field: field to match.
3268        value_list: a list of value to match.
3269
3270    Returns:
3271        True if <field> in "event" match one of the value in "value_list".
3272        False otherwise.
3273    """
3274    try:
3275        value_in_event = event['data'][field]
3276    except KeyError:
3277        return False
3278    for value in value_list:
3279        if value_in_event == value:
3280            return True
3281    return False
3282
3283
3284def is_network_call_back_event_match(event, network_callback_id,
3285                                     network_callback_event):
3286    try:
3287        return ((network_callback_id == event[
3288            'data'][NetworkCallbackContainer.ID]) and
3289                (network_callback_event == event['data'][
3290                    NetworkCallbackContainer.NETWORK_CALLBACK_EVENT]))
3291    except KeyError:
3292        return False
3293
3294
3295def is_build_id(log, ad, build_id):
3296    """Return if ad's build id is the same as input parameter build_id.
3297
3298    Args:
3299        log: log object.
3300        ad: android device object.
3301        build_id: android build id.
3302
3303    Returns:
3304        True if ad's build id is the same as input parameter build_id.
3305        False otherwise.
3306    """
3307    actual_bid = ad.droid.getBuildID()
3308
3309    log.info("{} BUILD DISPLAY: {}"
3310             .format(ad.serial, ad.droid.getBuildDisplay()))
3311    #In case we want to log more stuff/more granularity...
3312    #log.info("{} BUILD ID:{} ".format(ad.serial, ad.droid.getBuildID()))
3313    #log.info("{} BUILD FINGERPRINT: {} "
3314    # .format(ad.serial), ad.droid.getBuildFingerprint())
3315    #log.info("{} BUILD TYPE: {} "
3316    # .format(ad.serial), ad.droid.getBuildType())
3317    #log.info("{} BUILD NUMBER: {} "
3318    # .format(ad.serial), ad.droid.getBuildNumber())
3319    if actual_bid.upper() != build_id.upper():
3320        log.error("{}: Incorrect Build ID".format(ad.model))
3321        return False
3322    return True
3323
3324
3325def is_uri_equivalent(uri1, uri2):
3326    """Check whether two input uris match or not.
3327
3328    Compare Uris.
3329        If Uris are tel URI, it will only take the digit part
3330        and compare as phone number.
3331        Else, it will just do string compare.
3332
3333    Args:
3334        uri1: 1st uri to be compared.
3335        uri2: 2nd uri to be compared.
3336
3337    Returns:
3338        True if two uris match. Otherwise False.
3339    """
3340
3341    #If either is None/empty we return false
3342    if not uri1 or not uri2:
3343        return False
3344
3345    try:
3346        if uri1.startswith('tel:') and uri2.startswith('tel:'):
3347            uri1_number = get_number_from_tel_uri(uri1)
3348            uri2_number = get_number_from_tel_uri(uri2)
3349            return check_phone_number_match(uri1_number, uri2_number)
3350        else:
3351            return uri1 == uri2
3352    except AttributeError as e:
3353        return False
3354
3355
3356def get_call_uri(ad, call_id):
3357    """Get call's uri field.
3358
3359    Get Uri for call_id in ad.
3360
3361    Args:
3362        ad: android device object.
3363        call_id: the call id to get Uri from.
3364
3365    Returns:
3366        call's Uri if call is active and have uri field. None otherwise.
3367    """
3368    try:
3369        call_detail = ad.droid.telecomCallGetDetails(call_id)
3370        return call_detail["Handle"]["Uri"]
3371    except:
3372        return None
3373
3374
3375def get_number_from_tel_uri(uri):
3376    """Get Uri number from tel uri
3377
3378    Args:
3379        uri: input uri
3380
3381    Returns:
3382        If input uri is tel uri, return the number part.
3383        else return None.
3384    """
3385    if uri.startswith('tel:'):
3386        uri_number = ''.join(i for i in urllib.parse.unquote(uri)
3387                             if i.isdigit())
3388        return uri_number
3389    else:
3390        return None
3391
3392
3393# TODO: b/26294018 Remove wrapper class once wifi_utils methods updated
3394class WifiUtils():
3395
3396    from acts.test_utils.wifi.wifi_test_utils \
3397        import reset_wifi as _reset_wifi
3398    from acts.test_utils.wifi.wifi_test_utils \
3399        import wifi_connect as _wifi_connect
3400    from acts.test_utils.wifi.wifi_test_utils \
3401        import wifi_toggle_state as _wifi_toggle_state
3402    from acts.test_utils.wifi.wifi_test_utils \
3403        import start_wifi_tethering as _start_wifi_tethering
3404    from acts.test_utils.wifi.wifi_test_utils \
3405        import stop_wifi_tethering as _stop_wifi_tethering
3406    from acts.test_utils.wifi.wifi_test_utils \
3407        import WifiEnums as _WifiEnums
3408
3409    WIFI_CONFIG_APBAND_2G = _WifiEnums.WIFI_CONFIG_APBAND_2G
3410    WIFI_CONFIG_APBAND_5G = _WifiEnums.WIFI_CONFIG_APBAND_5G
3411    SSID_KEY = _WifiEnums.SSID_KEY
3412    PWD_KEY = _WifiEnums.PWD_KEY
3413
3414    @staticmethod
3415    def wifi_toggle_state(log, ad, state):
3416        """Toggle the WiFi State
3417
3418        Args:
3419            log: log object
3420            ad: AndroidDevice object
3421            state: True, False, or None
3422
3423        Returns:
3424            boolean success (True) or failure (False)
3425        """
3426        try:
3427            WifiUtils._wifi_toggle_state(ad, state)
3428        except Exception as e:
3429            log.error("WifiUtils.wifi_toggle_state exception: {}".format(e))
3430            return False
3431        return True
3432
3433    @staticmethod
3434    def forget_all_networks(log, ad):
3435        """Forget all stored wifi network information
3436
3437        Args:
3438            log: log object
3439            ad: AndroidDevice object
3440
3441        Returns:
3442            boolean success (True) or failure (False)
3443        """
3444        networks = ad.droid.wifiGetConfiguredNetworks()
3445        if networks is None:
3446            return True
3447        for network in networks:
3448            ad.droid.wifiForgetNetwork(network['networkId'])
3449            try:
3450                event = ad.ed.pop_event(WifiEventNames.WIFI_FORGET_NW_SUCCESS,
3451                                        SHORT_TIMEOUT)
3452            except Empty:
3453                log.warning(
3454                    "Could not confirm the removal of network {}.".format(
3455                        network))
3456        networks = ad.droid.ad.droid.wifiGetConfiguredNetworks()
3457        if len(networks):
3458            log.error("Failed to forget all networks {}.".format(networks))
3459            return False
3460        return True
3461
3462    @staticmethod
3463    def wifi_reset(log, ad, disable_wifi=True):
3464        """Forget all stored wifi networks and (optionally) disable WiFi
3465
3466        Args:
3467            log: log object
3468            ad: AndroidDevice object
3469            disable_wifi: boolean to disable wifi, defaults to True
3470        Returns:
3471            boolean success (True) or failure (False)
3472        """
3473        if disable_wifi is True:
3474            if not WifiUtils.wifi_toggle_state(log, ad, False):
3475                log.error("Failed to disable WiFi during reset!")
3476                return False
3477            # Ensure toggle state has human-time to take effect
3478            time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
3479        return WifiUtils.forget_all_networks(log, ad)
3480
3481    @staticmethod
3482    def wifi_connect(log, ad, ssid, password=None):
3483        """Connect to a WiFi network with a provided SSID and Password
3484
3485        Args:
3486            log: log object
3487            ad: AndroidDevice object
3488            ssid: the name of the WiFi network
3489            password: optional password, used for secure networks.
3490        Returns:
3491            boolean success (True) or failure (False)
3492        """
3493        if password == "":
3494            password = None
3495        try:
3496            network = {WifiUtils.SSID_KEY: ssid}
3497            if password:
3498                network[WifiUtils.PWD_KEY] = password
3499            WifiUtils._wifi_connect(ad, network)
3500        except Empty:
3501            # did not get event, then check connection info
3502            try:
3503                if ad.droid.wifiGetConnectionInfo()[
3504                        WifiUtils.SSID_KEY] == ssid:
3505                    return True
3506                else:
3507                    log.error(
3508                        "WifiUtils.wifi_connect not connected."
3509                        "No event received. Expected SSID: {}, current SSID:{}".format(
3510                            ssid, ad.droid.wifiGetConnectionInfo()[
3511                                WifiUtils.SSID_KEY]))
3512                    return False
3513            except Exception as e:
3514                log.error("WifiUtils.wifi_connect not connected, no event.")
3515                return False
3516        except Exception as e:
3517            log.error("WifiUtils.wifi_connect exception: {}".format(e))
3518            return False
3519        return True
3520
3521    @staticmethod
3522    def start_wifi_tethering(log, ad, ssid, password, ap_band=None):
3523        """Start a Tethering Session
3524
3525        Args:
3526            log: log object
3527            ad: AndroidDevice object
3528            ssid: the name of the WiFi network
3529            password: optional password, used for secure networks.
3530            ap_band=DEPRECATED specification of 2G or 5G tethering
3531        Returns:
3532            boolean success (True) or failure (False)
3533        """
3534        try:
3535            return WifiUtils._start_wifi_tethering(ad, ssid, password, ap_band)
3536        except Exception as e:
3537            log.error("WifiUtils.start_wifi_tethering exception: {}".format(e))
3538            return False
3539
3540    @staticmethod
3541    def stop_wifi_tethering(log, ad):
3542        """Stop a Tethering Session
3543
3544        Args:
3545            log: log object
3546            ad: AndroidDevice object
3547        Returns:
3548            boolean success (True) or failure (False)
3549        """
3550        try:
3551            WifiUtils._stop_wifi_tethering(ad)
3552            return True
3553        except Exception as e:
3554            log.error("WifiUtils.stop_wifi_tethering exception: {}".format(e))
3555            return False
3556