1#!/usr/bin/env python3
2#
3#   Copyright 2021 - 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 acts import signals
18import re
19import time
20
21from acts.utils import get_current_epoch_time
22from acts_contrib.test_utils.tel.tel_defines import INCALL_UI_DISPLAY_FOREGROUND
23from acts_contrib.test_utils.tel.tel_defines import MAX_WAIT_TIME_WFC_ENABLED
24from acts_contrib.test_utils.tel.tel_defines import NOT_CHECK_MCALLFORWARDING_OPERATOR_LIST
25from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_BETWEEN_REG_AND_CALL
26from acts_contrib.test_utils.tel.tel_defines import WAIT_TIME_IN_CALL
27from acts_contrib.test_utils.tel.tel_ims_utils import wait_for_wfc_enabled
28from acts_contrib.test_utils.tel.tel_phone_setup_utils import ensure_phones_idle
29from acts_contrib.test_utils.tel.tel_subscription_utils import get_incoming_voice_sub_id
30from acts_contrib.test_utils.tel.tel_subscription_utils import get_outgoing_voice_sub_id
31from acts_contrib.test_utils.tel.tel_subscription_utils import get_slot_index_from_subid
32from acts_contrib.test_utils.tel.tel_test_utils import _phone_number_remove_prefix
33from acts_contrib.test_utils.tel.tel_test_utils import check_call_state_ring_by_adb
34from acts_contrib.test_utils.tel.tel_test_utils import check_call_state_idle_by_adb
35from acts_contrib.test_utils.tel.tel_test_utils import get_operator_name
36from acts_contrib.test_utils.tel.tel_test_utils import get_user_config_profile
37from acts_contrib.test_utils.tel.tel_test_utils import toggle_airplane_mode
38from acts_contrib.test_utils.tel.tel_test_utils import toggle_airplane_mode_msim
39from acts_contrib.test_utils.tel.tel_voice_utils import call_setup_teardown_for_subscription
40from acts_contrib.test_utils.tel.tel_voice_utils import dial_phone_number
41from acts_contrib.test_utils.tel.tel_voice_utils import disconnect_call_by_id
42from acts_contrib.test_utils.tel.tel_voice_utils import hangup_call
43from acts_contrib.test_utils.tel.tel_voice_utils import initiate_call
44from acts_contrib.test_utils.tel.tel_voice_utils import is_phone_in_call
45from acts_contrib.test_utils.tel.tel_voice_utils import last_call_drop_reason
46from acts_contrib.test_utils.tel.tel_voice_utils import wait_and_answer_call_for_subscription
47from acts_contrib.test_utils.tel.tel_voice_utils import wait_for_call_id_clearing
48from acts_contrib.test_utils.tel.tel_voice_utils import wait_for_call_offhook_for_subscription
49from acts_contrib.test_utils.tel.tel_voice_utils import wait_for_in_call_active
50from acts_contrib.test_utils.tel.tel_voice_utils import wait_for_ringing_call_for_subscription
51
52
53def call_setup_teardown_for_call_forwarding(
54    log,
55    ad_caller,
56    ad_callee,
57    forwarded_callee,
58    ad_hangup=None,
59    verify_callee_func=None,
60    verify_after_cf_disabled=None,
61    wait_time_in_call=WAIT_TIME_IN_CALL,
62    incall_ui_display=INCALL_UI_DISPLAY_FOREGROUND,
63    dialing_number_length=None,
64    video_state=None,
65    call_forwarding_type="unconditional"):
66    """ Call process for call forwarding, including make a phone call from
67    caller, forward from callee, accept from the forwarded callee and hang up.
68    The call is on default voice subscription
69
70    In call process, call from <ad_caller> to <ad_callee>, forwarded to
71    <forwarded_callee>, accept the call, (optional) and then hang up from
72    <ad_hangup>.
73
74    Args:
75        ad_caller: Caller Android Device Object.
76        ad_callee: Callee Android Device Object which forwards the call.
77        forwarded_callee: Callee Android Device Object which answers the call.
78        ad_hangup: Android Device Object end the phone call.
79            Optional. Default value is None, and phone call will continue.
80        verify_callee_func: func_ptr to verify callee in correct mode
81            Optional. Default is None
82        verify_after_cf_disabled: If True the test of disabling call forwarding
83        will be appended.
84        wait_time_in_call: the call duration of a connected call
85        incall_ui_display: after answer the call, bring in-call UI to foreground
86        or background.
87            Optional, default value is INCALL_UI_DISPLAY_FOREGROUND.
88            if = INCALL_UI_DISPLAY_FOREGROUND, bring in-call UI to foreground.
89            if = INCALL_UI_DISPLAY_BACKGROUND, bring in-call UI to background.
90            else, do nothing.
91        dialing_number_length: the number of digits used for dialing
92        video_state: video call or voice call. Default is voice call.
93        call_forwarding_type: type of call forwarding listed below:
94            - unconditional
95            - busy
96            - not_answered
97            - not_reachable
98
99    Returns:
100        True if call process without any error.
101        False if error happened.
102
103    """
104    subid_caller = get_outgoing_voice_sub_id(ad_caller)
105    subid_callee = get_incoming_voice_sub_id(ad_callee)
106    subid_forwarded_callee = get_incoming_voice_sub_id(forwarded_callee)
107    return call_setup_teardown_for_call_forwarding_for_subscription(
108        log,
109        ad_caller,
110        ad_callee,
111        forwarded_callee,
112        subid_caller,
113        subid_callee,
114        subid_forwarded_callee,
115        ad_hangup,
116        verify_callee_func,
117        wait_time_in_call,
118        incall_ui_display,
119        dialing_number_length,
120        video_state,
121        call_forwarding_type,
122        verify_after_cf_disabled)
123
124
125def call_setup_teardown_for_call_forwarding_for_subscription(
126        log,
127        ad_caller,
128        ad_callee,
129        forwarded_callee,
130        subid_caller,
131        subid_callee,
132        subid_forwarded_callee,
133        ad_hangup=None,
134        verify_callee_func=None,
135        wait_time_in_call=WAIT_TIME_IN_CALL,
136        incall_ui_display=INCALL_UI_DISPLAY_FOREGROUND,
137        dialing_number_length=None,
138        video_state=None,
139        call_forwarding_type="unconditional",
140        verify_after_cf_disabled=None):
141    """ Call process for call forwarding, including make a phone call from caller,
142    forward from callee, accept from the forwarded callee and hang up.
143    The call is on specified subscription
144
145    In call process, call from <ad_caller> to <ad_callee>, forwarded to
146    <forwarded_callee>, accept the call, (optional) and then hang up from
147    <ad_hangup>.
148
149    Args:
150        ad_caller: Caller Android Device Object.
151        ad_callee: Callee Android Device Object which forwards the call.
152        forwarded_callee: Callee Android Device Object which answers the call.
153        subid_caller: Caller subscription ID
154        subid_callee: Callee subscription ID
155        subid_forwarded_callee: Forwarded callee subscription ID
156        ad_hangup: Android Device Object end the phone call.
157            Optional. Default value is None, and phone call will continue.
158        verify_callee_func: func_ptr to verify callee in correct mode
159            Optional. Default is None
160        wait_time_in_call: the call duration of a connected call
161        incall_ui_display: after answer the call, bring in-call UI to foreground
162        or background. Optional, default value is INCALL_UI_DISPLAY_FOREGROUND.
163            if = INCALL_UI_DISPLAY_FOREGROUND, bring in-call UI to foreground.
164            if = INCALL_UI_DISPLAY_BACKGROUND, bring in-call UI to background.
165            else, do nothing.
166        dialing_number_length: the number of digits used for dialing
167        video_state: video call or voice call. Default is voice call.
168        call_forwarding_type: type of call forwarding listed below:
169            - unconditional
170            - busy
171            - not_answered
172            - not_reachable
173        verify_after_cf_disabled: If True the call forwarding will not be
174        enabled. This argument is used to verify if the call can be received
175        successfully after call forwarding was disabled.
176
177    Returns:
178        True if call process without any error.
179        False if error happened.
180
181    """
182    CHECK_INTERVAL = 5
183    begin_time = get_current_epoch_time()
184    verify_caller_func = is_phone_in_call
185    if not verify_callee_func:
186        verify_callee_func = is_phone_in_call
187    verify_forwarded_callee_func = is_phone_in_call
188
189    caller_number = ad_caller.telephony['subscription'][subid_caller][
190        'phone_num']
191    callee_number = ad_callee.telephony['subscription'][subid_callee][
192        'phone_num']
193    forwarded_callee_number = forwarded_callee.telephony['subscription'][
194        subid_forwarded_callee]['phone_num']
195
196    if dialing_number_length:
197        skip_test = False
198        trunc_position = 0 - int(dialing_number_length)
199        try:
200            caller_area_code = caller_number[:trunc_position]
201            callee_area_code = callee_number[:trunc_position]
202            callee_dial_number = callee_number[trunc_position:]
203        except:
204            skip_test = True
205        if caller_area_code != callee_area_code:
206            skip_test = True
207        if skip_test:
208            msg = "Cannot make call from %s to %s by %s digits" % (
209                caller_number, callee_number, dialing_number_length)
210            ad_caller.log.info(msg)
211            raise signals.TestSkip(msg)
212        else:
213            callee_number = callee_dial_number
214
215    result = True
216    msg = "Call from %s to %s (forwarded to %s)" % (
217        caller_number, callee_number, forwarded_callee_number)
218    if video_state:
219        msg = "Video %s" % msg
220        video = True
221    else:
222        video = False
223    if ad_hangup:
224        msg = "%s for duration of %s seconds" % (msg, wait_time_in_call)
225    ad_caller.log.info(msg)
226
227    for ad in (ad_caller, forwarded_callee):
228        call_ids = ad.droid.telecomCallGetCallIds()
229        setattr(ad, "call_ids", call_ids)
230        if call_ids:
231            ad.log.info("Pre-exist CallId %s before making call", call_ids)
232
233    if not verify_after_cf_disabled:
234        if not set_call_forwarding_by_mmi(
235            log,
236            ad_callee,
237            forwarded_callee,
238            call_forwarding_type=call_forwarding_type):
239            raise signals.TestFailure(
240                    "Failed to register or activate call forwarding.",
241                    extras={"fail_reason": "Failed to register or activate call"
242                    " forwarding."})
243
244    if call_forwarding_type == "not_reachable":
245        if not toggle_airplane_mode_msim(
246            log,
247            ad_callee,
248            new_state=True,
249            strict_checking=True):
250            return False
251
252    if call_forwarding_type == "busy":
253        ad_callee.log.info("Callee is making a phone call to 0000000000 to make"
254            " itself busy.")
255        ad_callee.droid.telecomCallNumber("0000000000", False)
256        time.sleep(2)
257
258        if check_call_state_idle_by_adb(ad_callee):
259            ad_callee.log.error("Call state of the callee is idle.")
260            if not verify_after_cf_disabled:
261                erase_call_forwarding_by_mmi(
262                    log,
263                    ad_callee,
264                    call_forwarding_type=call_forwarding_type)
265            return False
266
267    try:
268        if not initiate_call(
269                log,
270                ad_caller,
271                callee_number,
272                incall_ui_display=incall_ui_display,
273                video=video):
274
275            ad_caller.log.error("Caller failed to initiate the call.")
276            result = False
277
278            if call_forwarding_type == "not_reachable":
279                if toggle_airplane_mode_msim(
280                    log,
281                    ad_callee,
282                    new_state=False,
283                    strict_checking=True):
284                    time.sleep(10)
285            elif call_forwarding_type == "busy":
286                hangup_call(log, ad_callee)
287
288            if not verify_after_cf_disabled:
289                erase_call_forwarding_by_mmi(
290                    log,
291                    ad_callee,
292                    call_forwarding_type=call_forwarding_type)
293            return False
294        else:
295            ad_caller.log.info("Caller initated the call successfully.")
296
297        if call_forwarding_type == "not_answered":
298            if not wait_for_ringing_call_for_subscription(
299                    log,
300                    ad_callee,
301                    subid_callee,
302                    incoming_number=caller_number,
303                    caller=ad_caller,
304                    event_tracking_started=True):
305                ad.log.info("Incoming call ringing check failed.")
306                return False
307
308            _timeout = 30
309            while check_call_state_ring_by_adb(ad_callee) == 1 and _timeout >= 0:
310                time.sleep(1)
311                _timeout = _timeout - 1
312
313        if not wait_and_answer_call_for_subscription(
314                log,
315                forwarded_callee,
316                subid_forwarded_callee,
317                incoming_number=caller_number,
318                caller=ad_caller,
319                incall_ui_display=incall_ui_display,
320                video_state=video_state):
321
322            if not verify_after_cf_disabled:
323                forwarded_callee.log.error("Forwarded callee failed to receive"
324                    "or answer the call.")
325                result = False
326            else:
327                forwarded_callee.log.info("Forwarded callee did not receive or"
328                    " answer the call.")
329
330            if call_forwarding_type == "not_reachable":
331                if toggle_airplane_mode_msim(
332                    log,
333                    ad_callee,
334                    new_state=False,
335                    strict_checking=True):
336                    time.sleep(10)
337            elif call_forwarding_type == "busy":
338                hangup_call(log, ad_callee)
339
340            if not verify_after_cf_disabled:
341                erase_call_forwarding_by_mmi(
342                    log,
343                    ad_callee,
344                    call_forwarding_type=call_forwarding_type)
345                return False
346
347        else:
348            if not verify_after_cf_disabled:
349                forwarded_callee.log.info("Forwarded callee answered the call"
350                    " successfully.")
351            else:
352                forwarded_callee.log.error("Forwarded callee should not be able"
353                    " to answer the call.")
354                hangup_call(log, ad_caller)
355                result = False
356
357        for ad, subid, call_func in zip(
358                [ad_caller, forwarded_callee],
359                [subid_caller, subid_forwarded_callee],
360                [verify_caller_func, verify_forwarded_callee_func]):
361            call_ids = ad.droid.telecomCallGetCallIds()
362            new_call_ids = set(call_ids) - set(ad.call_ids)
363            if not new_call_ids:
364                if not verify_after_cf_disabled:
365                    ad.log.error(
366                        "No new call ids are found after call establishment")
367                    ad.log.error("telecomCallGetCallIds returns %s",
368                                 ad.droid.telecomCallGetCallIds())
369                result = False
370            for new_call_id in new_call_ids:
371                if not verify_after_cf_disabled:
372                    if not wait_for_in_call_active(ad, call_id=new_call_id):
373                        result = False
374                    else:
375                        ad.log.info("callProperties = %s",
376                            ad.droid.telecomCallGetProperties(new_call_id))
377                else:
378                    ad.log.error("No new call id should be found.")
379
380            if not ad.droid.telecomCallGetAudioState():
381                if not verify_after_cf_disabled:
382                    ad.log.error("Audio is not in call state")
383                    result = False
384
385            if call_func(log, ad):
386                if not verify_after_cf_disabled:
387                    ad.log.info("Call is in %s state", call_func.__name__)
388                else:
389                    ad.log.error("Call is in %s state", call_func.__name__)
390            else:
391                if not verify_after_cf_disabled:
392                    ad.log.error(
393                        "Call is not in %s state, voice in RAT %s",
394                        call_func.__name__,
395                        ad.droid.telephonyGetCurrentVoiceNetworkTypeForSubscription(subid))
396                    result = False
397
398        if not result:
399            if call_forwarding_type == "not_reachable":
400                if toggle_airplane_mode_msim(
401                    log,
402                    ad_callee,
403                    new_state=False,
404                    strict_checking=True):
405                    time.sleep(10)
406            elif call_forwarding_type == "busy":
407                hangup_call(log, ad_callee)
408
409            if not verify_after_cf_disabled:
410                erase_call_forwarding_by_mmi(
411                    log,
412                    ad_callee,
413                    call_forwarding_type=call_forwarding_type)
414                return False
415
416        elapsed_time = 0
417        while (elapsed_time < wait_time_in_call):
418            CHECK_INTERVAL = min(CHECK_INTERVAL,
419                                 wait_time_in_call - elapsed_time)
420            time.sleep(CHECK_INTERVAL)
421            elapsed_time += CHECK_INTERVAL
422            time_message = "at <%s>/<%s> second." % (elapsed_time,
423                                                     wait_time_in_call)
424            for ad, subid, call_func in [
425                (ad_caller, subid_caller, verify_caller_func),
426                (forwarded_callee, subid_forwarded_callee,
427                    verify_forwarded_callee_func)]:
428                if not call_func(log, ad):
429                    if not verify_after_cf_disabled:
430                        ad.log.error(
431                            "NOT in correct %s state at %s, voice in RAT %s",
432                            call_func.__name__, time_message,
433                            ad.droid.telephonyGetCurrentVoiceNetworkTypeForSubscription(subid))
434                    result = False
435                else:
436                    if not verify_after_cf_disabled:
437                        ad.log.info("In correct %s state at %s",
438                                    call_func.__name__, time_message)
439                    else:
440                        ad.log.error("In correct %s state at %s",
441                                    call_func.__name__, time_message)
442
443                if not ad.droid.telecomCallGetAudioState():
444                    if not verify_after_cf_disabled:
445                        ad.log.error("Audio is not in call state at %s",
446                                     time_message)
447                    result = False
448
449            if not result:
450                if call_forwarding_type == "not_reachable":
451                    if toggle_airplane_mode_msim(
452                        log,
453                        ad_callee,
454                        new_state=False,
455                        strict_checking=True):
456                        time.sleep(10)
457                elif call_forwarding_type == "busy":
458                    hangup_call(log, ad_callee)
459
460                if not verify_after_cf_disabled:
461                    erase_call_forwarding_by_mmi(
462                        log,
463                        ad_callee,
464                        call_forwarding_type=call_forwarding_type)
465                    return False
466
467        if ad_hangup:
468            if not hangup_call(log, ad_hangup):
469                ad_hangup.log.info("Failed to hang up the call")
470                result = False
471                if call_forwarding_type == "not_reachable":
472                    if toggle_airplane_mode_msim(
473                        log,
474                        ad_callee,
475                        new_state=False,
476                        strict_checking=True):
477                        time.sleep(10)
478                elif call_forwarding_type == "busy":
479                    hangup_call(log, ad_callee)
480
481                if not verify_after_cf_disabled:
482                    erase_call_forwarding_by_mmi(
483                        log,
484                        ad_callee,
485                        call_forwarding_type=call_forwarding_type)
486                return False
487    finally:
488        if not result:
489            if verify_after_cf_disabled:
490                result = True
491            else:
492                for ad in (ad_caller, forwarded_callee):
493                    last_call_drop_reason(ad, begin_time)
494                    try:
495                        if ad.droid.telecomIsInCall():
496                            ad.log.info("In call. End now.")
497                            ad.droid.telecomEndCall()
498                    except Exception as e:
499                        log.error(str(e))
500
501        if ad_hangup or not result:
502            for ad in (ad_caller, forwarded_callee):
503                if not wait_for_call_id_clearing(
504                        ad, getattr(ad, "caller_ids", [])):
505                    result = False
506
507    if call_forwarding_type == "not_reachable":
508        if toggle_airplane_mode_msim(
509            log,
510            ad_callee,
511            new_state=False,
512            strict_checking=True):
513            time.sleep(10)
514    elif call_forwarding_type == "busy":
515        hangup_call(log, ad_callee)
516
517    if not verify_after_cf_disabled:
518        erase_call_forwarding_by_mmi(
519            log,
520            ad_callee,
521            call_forwarding_type=call_forwarding_type)
522
523    if not result:
524        return result
525
526    ad_caller.log.info(
527        "Make a normal call to callee to ensure the call can be connected after"
528        " call forwarding was disabled")
529    return call_setup_teardown_for_subscription(
530        log, ad_caller, ad_callee, subid_caller, subid_callee, ad_caller,
531        verify_caller_func, verify_callee_func, wait_time_in_call,
532        incall_ui_display, dialing_number_length, video_state)
533
534
535def get_call_forwarding_by_adb(log, ad, call_forwarding_type="unconditional"):
536    """ Get call forwarding status by adb shell command
537        'dumpsys telephony.registry'.
538
539        Args:
540            log: log object
541            ad: android object
542            call_forwarding_type:
543                - "unconditional"
544                - "busy" (todo)
545                - "not_answered" (todo)
546                - "not_reachable" (todo)
547        Returns:
548            - "true": if call forwarding unconditional is enabled.
549            - "false": if call forwarding unconditional is disabled.
550            - "unknown": if the type is other than 'unconditional'.
551            - False: any case other than above 3 cases.
552    """
553    if call_forwarding_type != "unconditional":
554        return "unknown"
555
556    slot_index_of_default_voice_subid = get_slot_index_from_subid(ad,
557        get_incoming_voice_sub_id(ad))
558    output = ad.adb.shell("dumpsys telephony.registry | grep mCallForwarding")
559    if "mCallForwarding" in output:
560        result_list = re.findall(r"mCallForwarding=(true|false)", output)
561        if result_list:
562            result = result_list[slot_index_of_default_voice_subid]
563            ad.log.info("mCallForwarding is %s", result)
564
565            if re.search("false", result, re.I):
566                return "false"
567            elif re.search("true", result, re.I):
568                return "true"
569            else:
570                return False
571        else:
572            return False
573    else:
574        ad.log.error("'mCallForwarding' cannot be found in dumpsys.")
575        return False
576
577
578def erase_call_forwarding_by_mmi(
579        log,
580        ad,
581        retry=2,
582        call_forwarding_type="unconditional"):
583    """ Erase setting of call forwarding (erase the number and disable call
584    forwarding) by MMI code.
585
586    Args:
587        log: log object
588        ad: android object
589        retry: times of retry if the erasure failed.
590        call_forwarding_type:
591            - "unconditional"
592            - "busy"
593            - "not_answered"
594            - "not_reachable"
595    Returns:
596        True by successful erasure. Otherwise False.
597    """
598    operator_name = get_operator_name(log, ad)
599
600    run_get_call_forwarding_by_adb = 1
601    if operator_name in NOT_CHECK_MCALLFORWARDING_OPERATOR_LIST:
602        run_get_call_forwarding_by_adb = 0
603
604    if run_get_call_forwarding_by_adb:
605        res = get_call_forwarding_by_adb(log, ad,
606            call_forwarding_type=call_forwarding_type)
607        if res == "false":
608            return True
609
610    user_config_profile = get_user_config_profile(ad)
611    is_airplane_mode = user_config_profile["Airplane Mode"]
612    is_wfc_enabled = user_config_profile["WFC Enabled"]
613    wfc_mode = user_config_profile["WFC Mode"]
614    is_wifi_on = user_config_profile["WiFi State"]
615
616    if is_airplane_mode:
617        if not toggle_airplane_mode(log, ad, False):
618            ad.log.error("Failed to disable airplane mode.")
619            return False
620
621    code_dict = {
622        "Verizon": {
623            "unconditional": "73",
624            "busy": "73",
625            "not_answered": "73",
626            "not_reachable": "73",
627            "mmi": "*%s"
628        },
629        "Sprint": {
630            "unconditional": "720",
631            "busy": "740",
632            "not_answered": "730",
633            "not_reachable": "720",
634            "mmi": "*%s"
635        },
636        "Far EasTone": {
637            "unconditional": "142",
638            "busy": "143",
639            "not_answered": "144",
640            "not_reachable": "144",
641            "mmi": "*%s*2"
642        },
643        'Generic': {
644            "unconditional": "21",
645            "busy": "67",
646            "not_answered": "61",
647            "not_reachable": "62",
648            "mmi": "##%s#"
649        }
650    }
651
652    if operator_name in code_dict:
653        code = code_dict[operator_name][call_forwarding_type]
654        mmi = code_dict[operator_name]["mmi"]
655    else:
656        code = code_dict['Generic'][call_forwarding_type]
657        mmi = code_dict['Generic']["mmi"]
658
659    result = False
660    while retry >= 0:
661        if run_get_call_forwarding_by_adb:
662            res = get_call_forwarding_by_adb(
663                log, ad, call_forwarding_type=call_forwarding_type)
664            if res == "false":
665                ad.log.info("Call forwarding is already disabled.")
666                result = True
667                break
668
669        ad.log.info("Erasing and deactivating call forwarding %s..." %
670            call_forwarding_type)
671
672        ad.droid.telecomDialNumber(mmi % code)
673
674        time.sleep(3)
675        ad.send_keycode("ENTER")
676        time.sleep(15)
677
678        # To dismiss the pop-out dialog
679        ad.send_keycode("BACK")
680        time.sleep(5)
681        ad.send_keycode("BACK")
682
683        if run_get_call_forwarding_by_adb:
684            res = get_call_forwarding_by_adb(
685                log, ad, call_forwarding_type=call_forwarding_type)
686            if res == "false" or res == "unknown":
687                result = True
688                break
689            else:
690                ad.log.error("Failed to erase and deactivate call forwarding by "
691                    "MMI code ##%s#." % code)
692                retry = retry - 1
693                time.sleep(30)
694        else:
695            result = True
696            break
697
698    if is_airplane_mode:
699        if not toggle_airplane_mode(log, ad, True):
700            ad.log.error("Failed to enable airplane mode again.")
701        else:
702            if is_wifi_on:
703                ad.droid.wifiToggleState(True)
704                if is_wfc_enabled:
705                    if not wait_for_wfc_enabled(
706                        log, ad,max_time=MAX_WAIT_TIME_WFC_ENABLED):
707                        ad.log.error("WFC is not enabled")
708
709    return result
710
711def set_call_forwarding_by_mmi(
712        log,
713        ad,
714        ad_forwarded,
715        call_forwarding_type="unconditional",
716        retry=2):
717    """ Set up the forwarded number and enable call forwarding by MMI code.
718
719    Args:
720        log: log object
721        ad: android object of the device forwarding the call (primary device)
722        ad_forwarded: android object of the device receiving forwarded call.
723        retry: times of retry if the erasure failed.
724        call_forwarding_type:
725            - "unconditional"
726            - "busy"
727            - "not_answered"
728            - "not_reachable"
729    Returns:
730        True by successful erasure. Otherwise False.
731    """
732
733    res = get_call_forwarding_by_adb(log, ad,
734        call_forwarding_type=call_forwarding_type)
735    if res == "true":
736        return True
737
738    if ad.droid.connectivityCheckAirplaneMode():
739        ad.log.warning("%s is now in airplane mode.", ad.serial)
740        return True
741
742    operator_name = get_operator_name(log, ad)
743
744    code_dict = {
745        "Verizon": {
746            "unconditional": "72",
747            "busy": "71",
748            "not_answered": "71",
749            "not_reachable": "72",
750            "mmi": "*%s%s"
751        },
752        "Sprint": {
753            "unconditional": "72",
754            "busy": "74",
755            "not_answered": "73",
756            "not_reachable": "72",
757            "mmi": "*%s%s"
758        },
759        "Far EasTone": {
760            "unconditional": "142",
761            "busy": "143",
762            "not_answered": "144",
763            "not_reachable": "144",
764            "mmi": "*%s*%s"
765        },
766        'Generic': {
767            "unconditional": "21",
768            "busy": "67",
769            "not_answered": "61",
770            "not_reachable": "62",
771            "mmi": "*%s*%s#",
772            "mmi_for_plus_sign": "*%s*"
773        }
774    }
775
776    if operator_name in code_dict:
777        code = code_dict[operator_name][call_forwarding_type]
778        mmi = code_dict[operator_name]["mmi"]
779        if "mmi_for_plus_sign" in code_dict[operator_name]:
780            mmi_for_plus_sign = code_dict[operator_name]["mmi_for_plus_sign"]
781    else:
782        code = code_dict['Generic'][call_forwarding_type]
783        mmi = code_dict['Generic']["mmi"]
784        mmi_for_plus_sign = code_dict['Generic']["mmi_for_plus_sign"]
785
786    while retry >= 0:
787        if not erase_call_forwarding_by_mmi(
788            log, ad, call_forwarding_type=call_forwarding_type):
789            retry = retry - 1
790            continue
791
792        forwarded_number = ad_forwarded.telephony['subscription'][
793            ad_forwarded.droid.subscriptionGetDefaultVoiceSubId()][
794            'phone_num']
795        ad.log.info("Registering and activating call forwarding %s to %s..." %
796            (call_forwarding_type, forwarded_number))
797
798        (forwarded_number_no_prefix, _) = _phone_number_remove_prefix(
799            forwarded_number)
800
801        if operator_name == "Far EasTone":
802            forwarded_number_no_prefix = "0" + forwarded_number_no_prefix
803
804        run_get_call_forwarding_by_adb = 1
805        if operator_name in NOT_CHECK_MCALLFORWARDING_OPERATOR_LIST:
806            run_get_call_forwarding_by_adb = 0
807
808        _found_plus_sign = 0
809        if re.search("^\+", forwarded_number):
810            _found_plus_sign = 1
811            forwarded_number.replace("+", "")
812
813        if operator_name in code_dict:
814            ad.droid.telecomDialNumber(mmi % (code, forwarded_number_no_prefix))
815        else:
816            if _found_plus_sign == 0:
817                ad.droid.telecomDialNumber(mmi % (code, forwarded_number))
818            else:
819                ad.droid.telecomDialNumber(mmi_for_plus_sign % code)
820                ad.send_keycode("PLUS")
821
822                if "#" in mmi:
823                    dial_phone_number(ad, forwarded_number + "#")
824                else:
825                    dial_phone_number(ad, forwarded_number)
826
827        time.sleep(3)
828        ad.send_keycode("ENTER")
829        time.sleep(15)
830
831        # To dismiss the pop-out dialog
832        ad.send_keycode("BACK")
833        time.sleep(5)
834        ad.send_keycode("BACK")
835
836        if not run_get_call_forwarding_by_adb:
837            return True
838
839        result = get_call_forwarding_by_adb(
840            log, ad, call_forwarding_type=call_forwarding_type)
841        if result == "false":
842            retry = retry - 1
843        elif result == "true":
844            return True
845        elif result == "unknown":
846            return True
847        else:
848            retry = retry - 1
849
850        if retry >= 0:
851            ad.log.warning("Failed to register or activate call forwarding %s "
852                "to %s. Retry after 15 seconds." % (call_forwarding_type,
853                    forwarded_number))
854            time.sleep(15)
855
856    ad.log.error("Failed to register or activate call forwarding %s to %s." %
857        (call_forwarding_type, forwarded_number))
858    return False
859
860
861def call_setup_teardown_for_call_waiting(log,
862                        ad_caller,
863                        ad_callee,
864                        ad_caller2,
865                        ad_hangup=None,
866                        ad_hangup2=None,
867                        verify_callee_func=None,
868                        end_first_call_before_answering_second_call=True,
869                        wait_time_in_call=WAIT_TIME_IN_CALL,
870                        incall_ui_display=INCALL_UI_DISPLAY_FOREGROUND,
871                        dialing_number_length=None,
872                        video_state=None,
873                        call_waiting=True):
874    """ Call process for call waiting, including make the 1st phone call from
875    caller, answer the call by the callee, and receive the 2nd call from the
876    caller2. The call is on default voice subscription
877
878    In call process, 1st call from <ad_caller> to <ad_callee>, 2nd call from
879    <ad_caller2> to <ad_callee>, hang up the existing call or reject the
880    incoming call according to the test scenario.
881
882    Args:
883        ad_caller: Caller Android Device Object.
884        ad_callee: Callee Android Device Object.
885        ad_caller2: Caller2 Android Device Object.
886        ad_hangup: Android Device Object end the 1st phone call.
887            Optional. Default value is None, and phone call will continue.
888        ad_hangup2: Android Device Object end the 2nd phone call.
889            Optional. Default value is None, and phone call will continue.
890        verify_callee_func: func_ptr to verify callee in correct mode
891            Optional. Default is None
892        end_first_call_before_answering_second_call: If True the 2nd call will
893            be rejected on the ringing stage.
894        wait_time_in_call: the call duration of a connected call
895        incall_ui_display: after answer the call, bring in-call UI to foreground
896        or background.
897            Optional, default value is INCALL_UI_DISPLAY_FOREGROUND.
898            if = INCALL_UI_DISPLAY_FOREGROUND, bring in-call UI to foreground.
899            if = INCALL_UI_DISPLAY_BACKGROUND, bring in-call UI to background.
900            else, do nothing.
901        dialing_number_length: the number of digits used for dialing
902        video_state: video call or voice call. Default is voice call.
903        call_waiting: True to enable call waiting and False to disable.
904
905    Returns:
906        True if call process without any error.
907        False if error happened.
908
909    """
910    subid_caller = get_outgoing_voice_sub_id(ad_caller)
911    subid_callee = get_incoming_voice_sub_id(ad_callee)
912    subid_caller2 = get_incoming_voice_sub_id(ad_caller2)
913    return call_setup_teardown_for_call_waiting_for_subscription(
914        log,
915        ad_caller,
916        ad_callee,
917        ad_caller2,
918        subid_caller,
919        subid_callee,
920        subid_caller2,
921        ad_hangup, ad_hangup2,
922        verify_callee_func,
923        end_first_call_before_answering_second_call,
924        wait_time_in_call,
925        incall_ui_display,
926        dialing_number_length,
927        video_state,
928        call_waiting)
929
930
931def call_setup_teardown_for_call_waiting_for_subscription(
932        log,
933        ad_caller,
934        ad_callee,
935        ad_caller2,
936        subid_caller,
937        subid_callee,
938        subid_caller2,
939        ad_hangup=None,
940        ad_hangup2=None,
941        verify_callee_func=None,
942        end_first_call_before_answering_second_call=True,
943        wait_time_in_call=WAIT_TIME_IN_CALL,
944        incall_ui_display=INCALL_UI_DISPLAY_FOREGROUND,
945        dialing_number_length=None,
946        video_state=None,
947        call_waiting=True):
948    """ Call process for call waiting, including make the 1st phone call from
949    caller, answer the call by the callee, and receive the 2nd call from the
950    caller2. The call is on specified subscription.
951
952    In call process, 1st call from <ad_caller> to <ad_callee>, 2nd call from
953    <ad_caller2> to <ad_callee>, hang up the existing call or reject the
954    incoming call according to the test scenario.
955
956    Args:
957        ad_caller: Caller Android Device Object.
958        ad_callee: Callee Android Device Object.
959        ad_caller2: Caller2 Android Device Object.
960        subid_caller: Caller subscription ID.
961        subid_callee: Callee subscription ID.
962        subid_caller2: Caller2 subscription ID.
963        ad_hangup: Android Device Object end the 1st phone call.
964            Optional. Default value is None, and phone call will continue.
965        ad_hangup2: Android Device Object end the 2nd phone call.
966            Optional. Default value is None, and phone call will continue.
967        verify_callee_func: func_ptr to verify callee in correct mode
968            Optional. Default is None
969        end_first_call_before_answering_second_call: If True the 2nd call will
970            be rejected on the ringing stage.
971        wait_time_in_call: the call duration of a connected call
972        incall_ui_display: after answer the call, bring in-call UI to foreground
973        or background. Optional, default value is INCALL_UI_DISPLAY_FOREGROUND.
974            if = INCALL_UI_DISPLAY_FOREGROUND, bring in-call UI to foreground.
975            if = INCALL_UI_DISPLAY_BACKGROUND, bring in-call UI to background.
976            else, do nothing.
977        dialing_number_length: the number of digits used for dialing
978        video_state: video call or voice call. Default is voice call.
979        call_waiting: True to enable call waiting and False to disable.
980
981    Returns:
982        True if call process without any error.
983        False if error happened.
984
985    """
986
987    CHECK_INTERVAL = 5
988    begin_time = get_current_epoch_time()
989    verify_caller_func = is_phone_in_call
990    if not verify_callee_func:
991        verify_callee_func = is_phone_in_call
992    verify_caller2_func = is_phone_in_call
993
994    caller_number = ad_caller.telephony['subscription'][subid_caller][
995        'phone_num']
996    callee_number = ad_callee.telephony['subscription'][subid_callee][
997        'phone_num']
998    caller2_number = ad_caller2.telephony['subscription'][subid_caller2][
999        'phone_num']
1000    if dialing_number_length:
1001        skip_test = False
1002        trunc_position = 0 - int(dialing_number_length)
1003        try:
1004            caller_area_code = caller_number[:trunc_position]
1005            callee_area_code = callee_number[:trunc_position]
1006            callee_dial_number = callee_number[trunc_position:]
1007        except:
1008            skip_test = True
1009        if caller_area_code != callee_area_code:
1010            skip_test = True
1011        if skip_test:
1012            msg = "Cannot make call from %s to %s by %s digits" % (
1013                caller_number, callee_number, dialing_number_length)
1014            ad_caller.log.info(msg)
1015            raise signals.TestSkip(msg)
1016        else:
1017            callee_number = callee_dial_number
1018
1019    result = True
1020    msg = "Call from %s to %s" % (caller_number, callee_number)
1021    if video_state:
1022        msg = "Video %s" % msg
1023        video = True
1024    else:
1025        video = False
1026    if ad_hangup:
1027        msg = "%s for duration of %s seconds" % (msg, wait_time_in_call)
1028    ad_caller.log.info(msg)
1029
1030    for ad in (ad_caller, ad_callee, ad_caller2):
1031        call_ids = ad.droid.telecomCallGetCallIds()
1032        setattr(ad, "call_ids", call_ids)
1033        if call_ids:
1034            ad.log.info("Pre-exist CallId %s before making call", call_ids)
1035
1036    if not call_waiting:
1037        set_call_waiting(log, ad_callee, enable=0)
1038    else:
1039        set_call_waiting(log, ad_callee, enable=1)
1040
1041    first_call_ids = []
1042    try:
1043        if not initiate_call(
1044                log,
1045                ad_caller,
1046                callee_number,
1047                incall_ui_display=incall_ui_display,
1048                video=video):
1049            ad_caller.log.error("Initiate call failed.")
1050            if not call_waiting:
1051                set_call_waiting(log, ad_callee, enable=1)
1052            result = False
1053            return False
1054        else:
1055            ad_caller.log.info("Caller initate call successfully")
1056        if not wait_and_answer_call_for_subscription(
1057                log,
1058                ad_callee,
1059                subid_callee,
1060                incoming_number=caller_number,
1061                caller=ad_caller,
1062                incall_ui_display=incall_ui_display,
1063                video_state=video_state):
1064            ad_callee.log.error("Answer call fail.")
1065            if not call_waiting:
1066                set_call_waiting(log, ad_callee, enable=1)
1067            result = False
1068            return False
1069        else:
1070            ad_callee.log.info("Callee answered the call successfully")
1071
1072        for ad, subid, call_func in zip(
1073            [ad_caller, ad_callee],
1074            [subid_caller, subid_callee],
1075            [verify_caller_func, verify_callee_func]):
1076            call_ids = ad.droid.telecomCallGetCallIds()
1077            new_call_ids = set(call_ids) - set(ad.call_ids)
1078            if not new_call_ids:
1079                ad.log.error(
1080                    "No new call ids are found after call establishment")
1081                ad.log.error("telecomCallGetCallIds returns %s",
1082                             ad.droid.telecomCallGetCallIds())
1083                result = False
1084            for new_call_id in new_call_ids:
1085                first_call_ids.append(new_call_id)
1086                if not wait_for_in_call_active(ad, call_id=new_call_id):
1087                    result = False
1088                else:
1089                    ad.log.info("callProperties = %s",
1090                                ad.droid.telecomCallGetProperties(new_call_id))
1091
1092            if not ad.droid.telecomCallGetAudioState():
1093                ad.log.error("Audio is not in call state")
1094                result = False
1095
1096            if call_func(log, ad):
1097                ad.log.info("Call is in %s state", call_func.__name__)
1098            else:
1099                ad.log.error("Call is not in %s state, voice in RAT %s",
1100                             call_func.__name__,
1101                             ad.droid.telephonyGetCurrentVoiceNetworkTypeForSubscription(subid))
1102                result = False
1103        if not result:
1104            if not call_waiting:
1105                set_call_waiting(log, ad_callee, enable=1)
1106            return False
1107
1108        time.sleep(3)
1109        if not call_waiting:
1110            if not initiate_call(
1111                    log,
1112                    ad_caller2,
1113                    callee_number,
1114                    incall_ui_display=incall_ui_display,
1115                    video=video):
1116                ad_caller2.log.info("Initiate call failed.")
1117                if not call_waiting:
1118                    set_call_waiting(log, ad_callee, enable=1)
1119                result = False
1120                return False
1121            else:
1122                ad_caller2.log.info("Caller 2 initate 2nd call successfully")
1123
1124            if not wait_and_answer_call_for_subscription(
1125                    log,
1126                    ad_callee,
1127                    subid_callee,
1128                    incoming_number=caller2_number,
1129                    caller=ad_caller2,
1130                    incall_ui_display=incall_ui_display,
1131                    video_state=video_state):
1132                ad_callee.log.info(
1133                    "Answering 2nd call fail due to call waiting deactivate.")
1134            else:
1135                ad_callee.log.error("Callee should not be able to answer the"
1136                    " 2nd call due to call waiting deactivated.")
1137                if not call_waiting:
1138                    set_call_waiting(log, ad_callee, enable=1)
1139                result = False
1140                return False
1141
1142            time.sleep(3)
1143            if not hangup_call(log, ad_caller2):
1144                ad_caller2.log.info("Failed to hang up the 2nd call")
1145                if not call_waiting:
1146                    set_call_waiting(log, ad_callee, enable=1)
1147                result = False
1148                return False
1149
1150        else:
1151
1152            for ad in (ad_callee, ad_caller2):
1153                call_ids = ad.droid.telecomCallGetCallIds()
1154                setattr(ad, "call_ids", call_ids)
1155                if call_ids:
1156                    ad.log.info("Current existing CallId %s before making the"
1157                        " second call.", call_ids)
1158
1159            if not initiate_call(
1160                    log,
1161                    ad_caller2,
1162                    callee_number,
1163                    incall_ui_display=incall_ui_display,
1164                    video=video):
1165                ad_caller2.log.info("Initiate 2nd call failed.")
1166                if not call_waiting:
1167                    set_call_waiting(log, ad_callee, enable=1)
1168                result = False
1169                return False
1170            else:
1171                ad_caller2.log.info("Caller 2 initate 2nd call successfully")
1172
1173            if end_first_call_before_answering_second_call:
1174                try:
1175                    if not wait_for_ringing_call_for_subscription(
1176                            log,
1177                            ad_callee,
1178                            subid_callee,
1179                            incoming_number=caller2_number,
1180                            caller=ad_caller2,
1181                            event_tracking_started=True):
1182                        ad_callee.log.info(
1183                            "2nd incoming call ringing check failed.")
1184                        if not call_waiting:
1185                            set_call_waiting(log, ad_callee, enable=1)
1186                        return False
1187
1188                    time.sleep(3)
1189
1190                    ad_hangup.log.info("Disconnecting first call...")
1191                    for call_id in first_call_ids:
1192                        disconnect_call_by_id(log, ad_hangup, call_id)
1193                    time.sleep(3)
1194
1195                    ad_callee.log.info("Answering the 2nd ring call...")
1196                    ad_callee.droid.telecomAcceptRingingCall(video_state)
1197
1198                    if wait_for_call_offhook_for_subscription(
1199                            log,
1200                            ad_callee,
1201                            subid_callee,
1202                            event_tracking_started=True):
1203                        ad_callee.log.info(
1204                            "Callee answered the 2nd call successfully.")
1205                    else:
1206                        ad_callee.log.error("Could not answer the 2nd call.")
1207                        if not call_waiting:
1208                            set_call_waiting(log, ad_callee, enable=1)
1209                        return False
1210                except Exception as e:
1211                    log.error(e)
1212                    if not call_waiting:
1213                        set_call_waiting(log, ad_callee, enable=1)
1214                    return False
1215
1216            else:
1217                if not wait_and_answer_call_for_subscription(
1218                        log,
1219                        ad_callee,
1220                        subid_callee,
1221                        incoming_number=caller2_number,
1222                        caller=ad_caller2,
1223                        incall_ui_display=incall_ui_display,
1224                        video_state=video_state):
1225                    ad_callee.log.error("Failed to answer 2nd call.")
1226                    if not call_waiting:
1227                        set_call_waiting(log, ad_callee, enable=1)
1228                    result = False
1229                    return False
1230                else:
1231                    ad_callee.log.info(
1232                        "Callee answered the 2nd call successfully.")
1233
1234            for ad, subid, call_func in zip(
1235                [ad_callee, ad_caller2],
1236                [subid_callee, subid_caller2],
1237                [verify_callee_func, verify_caller2_func]):
1238                call_ids = ad.droid.telecomCallGetCallIds()
1239                new_call_ids = set(call_ids) - set(ad.call_ids)
1240                if not new_call_ids:
1241                    ad.log.error(
1242                        "No new call ids are found after 2nd call establishment")
1243                    ad.log.error("telecomCallGetCallIds returns %s",
1244                                 ad.droid.telecomCallGetCallIds())
1245                    result = False
1246                for new_call_id in new_call_ids:
1247                    if not wait_for_in_call_active(ad, call_id=new_call_id):
1248                        result = False
1249                    else:
1250                        ad.log.info("callProperties = %s",
1251                            ad.droid.telecomCallGetProperties(new_call_id))
1252
1253                if not ad.droid.telecomCallGetAudioState():
1254                    ad.log.error("Audio is not in 2nd call state")
1255                    result = False
1256
1257                if call_func(log, ad):
1258                    ad.log.info("2nd call is in %s state", call_func.__name__)
1259                else:
1260                    ad.log.error("2nd call is not in %s state, voice in RAT %s",
1261                                 call_func.__name__,
1262                                 ad.droid.telephonyGetCurrentVoiceNetworkTypeForSubscription(subid))
1263                    result = False
1264            if not result:
1265                if not call_waiting:
1266                    set_call_waiting(log, ad_callee, enable=1)
1267                return False
1268
1269        elapsed_time = 0
1270        while (elapsed_time < wait_time_in_call):
1271            CHECK_INTERVAL = min(CHECK_INTERVAL,
1272                                 wait_time_in_call - elapsed_time)
1273            time.sleep(CHECK_INTERVAL)
1274            elapsed_time += CHECK_INTERVAL
1275            time_message = "at <%s>/<%s> second." % (elapsed_time,
1276                                                     wait_time_in_call)
1277
1278            if not end_first_call_before_answering_second_call or \
1279                not call_waiting:
1280                for ad, subid, call_func in [
1281                    (ad_caller, subid_caller, verify_caller_func),
1282                    (ad_callee, subid_callee, verify_callee_func)]:
1283                    if not call_func(log, ad):
1284                        ad.log.error(
1285                            "The first call NOT in correct %s state at %s,"
1286                            " voice in RAT %s",
1287                            call_func.__name__, time_message,
1288                            ad.droid.telephonyGetCurrentVoiceNetworkTypeForSubscription(subid))
1289                        result = False
1290                    else:
1291                        ad.log.info("The first call in correct %s state at %s",
1292                                    call_func.__name__, time_message)
1293                    if not ad.droid.telecomCallGetAudioState():
1294                        ad.log.error(
1295                            "The first call audio is not in call state at %s",
1296                            time_message)
1297                        result = False
1298                if not result:
1299                    if not call_waiting:
1300                        set_call_waiting(log, ad_callee, enable=1)
1301                    return False
1302
1303            if call_waiting:
1304                for ad, call_func in [(ad_caller2, verify_caller2_func),
1305                                      (ad_callee, verify_callee_func)]:
1306                    if not call_func(log, ad):
1307                        ad.log.error(
1308                            "The 2nd call NOT in correct %s state at %s,"
1309                            " voice in RAT %s",
1310                            call_func.__name__, time_message,
1311                            ad.droid.telephonyGetCurrentVoiceNetworkTypeForSubscription(subid))
1312                        result = False
1313                    else:
1314                        ad.log.info("The 2nd call in correct %s state at %s",
1315                                    call_func.__name__, time_message)
1316                    if not ad.droid.telecomCallGetAudioState():
1317                        ad.log.error(
1318                            "The 2nd call audio is not in call state at %s",
1319                            time_message)
1320                        result = False
1321            if not result:
1322                if not call_waiting:
1323                    set_call_waiting(log, ad_callee, enable=1)
1324                return False
1325
1326        if not end_first_call_before_answering_second_call or not call_waiting:
1327            ad_hangup.log.info("Hanging up the first call...")
1328            for call_id in first_call_ids:
1329                disconnect_call_by_id(log, ad_hangup, call_id)
1330            time.sleep(5)
1331
1332        if ad_hangup2 and call_waiting:
1333            if not hangup_call(log, ad_hangup2):
1334                ad_hangup2.log.info("Failed to hang up the 2nd call")
1335                if not call_waiting:
1336                    set_call_waiting(log, ad_callee, enable=1)
1337                result = False
1338                return False
1339    finally:
1340        if not result:
1341            for ad in (ad_caller, ad_callee, ad_caller2):
1342                last_call_drop_reason(ad, begin_time)
1343                try:
1344                    if ad.droid.telecomIsInCall():
1345                        ad.log.info("In call. End now.")
1346                        ad.droid.telecomEndCall()
1347                except Exception as e:
1348                    log.error(str(e))
1349
1350        if ad_hangup or not result:
1351            for ad in (ad_caller, ad_callee):
1352                if not wait_for_call_id_clearing(
1353                        ad, getattr(ad, "caller_ids", [])):
1354                    result = False
1355
1356        if call_waiting:
1357            if ad_hangup2 or not result:
1358                for ad in (ad_caller2, ad_callee):
1359                    if not wait_for_call_id_clearing(
1360                            ad, getattr(ad, "caller_ids", [])):
1361                        result = False
1362    if not call_waiting:
1363        set_call_waiting(log, ad_callee, enable=1)
1364    return result
1365
1366
1367def get_call_waiting_status(log, ad):
1368    """ (Todo) Get call waiting status (activated or deactivated) when there is
1369    any proper method available.
1370    """
1371    return True
1372
1373
1374def set_call_waiting(log, ad, enable=1, retry=1):
1375    """ Activate/deactivate call waiting by dialing MMI code.
1376
1377    Args:
1378        log: log object.
1379        ad: android object.
1380        enable: 1 for activation and 0 fir deactivation
1381        retry: times of retry if activation/deactivation fails
1382
1383    Returns:
1384        True by successful activation/deactivation; otherwise False.
1385    """
1386    operator_name = get_operator_name(log, ad)
1387
1388    if operator_name in ["Verizon", "Sprint"]:
1389        return True
1390
1391    while retry >= 0:
1392        if enable:
1393            ad.log.info("Activating call waiting...")
1394            ad.droid.telecomDialNumber("*43#")
1395        else:
1396            ad.log.info("Deactivating call waiting...")
1397            ad.droid.telecomDialNumber("#43#")
1398
1399        time.sleep(3)
1400        ad.send_keycode("ENTER")
1401        time.sleep(15)
1402
1403        ad.send_keycode("BACK")
1404        time.sleep(5)
1405        ad.send_keycode("BACK")
1406
1407        if get_call_waiting_status(log, ad):
1408            return True
1409        else:
1410            retry = retry + 1
1411
1412    return False
1413
1414
1415def three_phone_call_forwarding_short_seq(log,
1416                             phone_a,
1417                             phone_a_idle_func,
1418                             phone_a_in_call_check_func,
1419                             phone_b,
1420                             phone_c,
1421                             wait_time_in_call=WAIT_TIME_IN_CALL,
1422                             call_forwarding_type="unconditional",
1423                             retry=2):
1424    """Short sequence of call process with call forwarding.
1425    Test steps:
1426        1. Ensure all phones are initially in idle state.
1427        2. Enable call forwarding on Phone A.
1428        3. Make a call from Phone B to Phone A, The call should be forwarded to
1429           PhoneC. Accept the call on Phone C.
1430        4. Ensure the call is connected and in correct phone state.
1431        5. Hang up the call on Phone B.
1432        6. Ensure all phones are in idle state.
1433        7. Disable call forwarding on Phone A.
1434        7. Make a call from Phone B to Phone A, The call should NOT be forwarded
1435           to PhoneC. Accept the call on Phone A.
1436        8. Ensure the call is connected and in correct phone state.
1437        9. Hang up the call on Phone B.
1438
1439    Args:
1440        phone_a: android object of Phone A
1441        phone_a_idle_func: function to check idle state on Phone A
1442        phone_a_in_call_check_func: function to check in-call state on Phone A
1443        phone_b: android object of Phone B
1444        phone_c: android object of Phone C
1445        wait_time_in_call: time to wait in call.
1446            This is optional, default is WAIT_TIME_IN_CALL
1447        call_forwarding_type:
1448            - "unconditional"
1449            - "busy"
1450            - "not_answered"
1451            - "not_reachable"
1452        retry: times of retry
1453
1454    Returns:
1455        True: if call sequence succeed.
1456        False: for errors
1457    """
1458    ads = [phone_a, phone_b, phone_c]
1459
1460    call_params = [
1461        (ads[1], ads[0], ads[2], ads[1], phone_a_in_call_check_func, False)
1462    ]
1463
1464    if call_forwarding_type != "unconditional":
1465        call_params.append((
1466            ads[1],
1467            ads[0],
1468            ads[2],
1469            ads[1],
1470            phone_a_in_call_check_func,
1471            True))
1472
1473    for param in call_params:
1474        ensure_phones_idle(log, ads)
1475        if phone_a_idle_func and not phone_a_idle_func(log, phone_a):
1476            phone_a.log.error("Phone A Failed to Reselect")
1477            return False
1478
1479        time.sleep(WAIT_TIME_BETWEEN_REG_AND_CALL)
1480
1481        log.info(
1482            "---> Call forwarding %s (caller: %s, callee: %s, callee forwarded:"
1483            " %s) <---",
1484            call_forwarding_type,
1485            param[0].serial,
1486            param[1].serial,
1487            param[2].serial)
1488        while not call_setup_teardown_for_call_forwarding(
1489                log,
1490                *param,
1491                wait_time_in_call=wait_time_in_call,
1492                call_forwarding_type=call_forwarding_type) and retry >= 0:
1493
1494            if retry <= 0:
1495                log.error("Call forwarding %s failed." % call_forwarding_type)
1496                return False
1497            else:
1498                log.info(
1499                    "RERUN the test case: 'Call forwarding %s'" %
1500                    call_forwarding_type)
1501
1502            retry = retry - 1
1503
1504    return True
1505
1506def three_phone_call_waiting_short_seq(log,
1507                             phone_a,
1508                             phone_a_idle_func,
1509                             phone_a_in_call_check_func,
1510                             phone_b,
1511                             phone_c,
1512                             wait_time_in_call=WAIT_TIME_IN_CALL,
1513                             call_waiting=True,
1514                             scenario=None,
1515                             retry=2):
1516    """Short sequence of call process with call waiting.
1517    Test steps:
1518        1. Ensure all phones are initially in idle state.
1519        2. Enable call waiting on Phone A.
1520        3. Make the 1st call from Phone B to Phone A. Accept the call on Phone B.
1521        4. Ensure the call is connected and in correct phone state.
1522        5. Make the 2nd call from Phone C to Phone A. The call should be able to
1523           income correctly. Whether or not the 2nd call should be answered by
1524           Phone A depends on the scenario listed in the next step.
1525        6. Following 8 scenarios will be tested:
1526           - 1st call ended first by Phone B during 2nd call incoming. 2nd call
1527             ended by Phone C
1528           - 1st call ended first by Phone B during 2nd call incoming. 2nd call
1529             ended by Phone A
1530           - 1st call ended first by Phone A during 2nd call incoming. 2nd call
1531             ended by Phone C
1532           - 1st call ended first by Phone A during 2nd call incoming. 2nd call
1533             ended by Phone A
1534           - 1st call ended by Phone B. 2nd call ended by Phone C
1535           - 1st call ended by Phone B. 2nd call ended by Phone A
1536           - 1st call ended by Phone A. 2nd call ended by Phone C
1537           - 1st call ended by Phone A. 2nd call ended by Phone A
1538        7. Ensure all phones are in idle state.
1539
1540    Args:
1541        phone_a: android object of Phone A
1542        phone_a_idle_func: function to check idle state on Phone A
1543        phone_a_in_call_check_func: function to check in-call state on Phone A
1544        phone_b: android object of Phone B
1545        phone_c: android object of Phone C
1546        wait_time_in_call: time to wait in call.
1547            This is optional, default is WAIT_TIME_IN_CALL
1548        call_waiting: True for call waiting enabled and False for disabled
1549        scenario: 1-8 for scenarios listed above
1550        retry: times of retry
1551
1552    Returns:
1553        True: if call sequence succeed.
1554        False: for errors
1555    """
1556    ads = [phone_a, phone_b, phone_c]
1557
1558    sub_test_cases = [
1559        {
1560            "description": "1st call ended first by caller1 during 2nd call"
1561                " incoming. 2nd call ended by caller2",
1562            "params": (
1563                ads[1],
1564                ads[0],
1565                ads[2],
1566                ads[1],
1567                ads[2],
1568                phone_a_in_call_check_func,
1569                True)},
1570        {
1571            "description": "1st call ended first by caller1 during 2nd call"
1572                " incoming. 2nd call ended by callee",
1573            "params": (
1574                ads[1],
1575                ads[0],
1576                ads[2],
1577                ads[1],
1578                ads[0],
1579                phone_a_in_call_check_func,
1580                True)},
1581        {
1582            "description": "1st call ended first by callee during 2nd call"
1583                " incoming. 2nd call ended by caller2",
1584            "params": (
1585                ads[1],
1586                ads[0],
1587                ads[2],
1588                ads[0],
1589                ads[2],
1590                phone_a_in_call_check_func,
1591                True)},
1592        {
1593            "description": "1st call ended first by callee during 2nd call"
1594                " incoming. 2nd call ended by callee",
1595            "params": (
1596                ads[1],
1597                ads[0],
1598                ads[2],
1599                ads[0],
1600                ads[0],
1601                phone_a_in_call_check_func,
1602                True)},
1603        {
1604            "description": "1st call ended by caller1. 2nd call ended by"
1605                " caller2",
1606            "params": (
1607                ads[1],
1608                ads[0],
1609                ads[2],
1610                ads[1],
1611                ads[2],
1612                phone_a_in_call_check_func,
1613                False)},
1614        {
1615            "description": "1st call ended by caller1. 2nd call ended by callee",
1616            "params": (
1617                ads[1],
1618                ads[0],
1619                ads[2],
1620                ads[1],
1621                ads[0],
1622                phone_a_in_call_check_func,
1623                False)},
1624        {
1625            "description": "1st call ended by callee. 2nd call ended by caller2",
1626            "params": (
1627                ads[1],
1628                ads[0],
1629                ads[2],
1630                ads[0],
1631                ads[2],
1632                phone_a_in_call_check_func,
1633                False)},
1634        {
1635            "description": "1st call ended by callee. 2nd call ended by callee",
1636            "params": (
1637                ads[1],
1638                ads[0],
1639                ads[2],
1640                ads[0],
1641                ads[0],
1642                phone_a_in_call_check_func,
1643                False)}
1644    ]
1645
1646    if call_waiting:
1647        if not scenario:
1648            test_cases = sub_test_cases
1649        else:
1650            test_cases = [sub_test_cases[scenario-1]]
1651    else:
1652        test_cases = [
1653            {
1654                "description": "Call waiting deactivated",
1655                "params": (
1656                    ads[1],
1657                    ads[0],
1658                    ads[2],
1659                    ads[0],
1660                    ads[0],
1661                    phone_a_in_call_check_func,
1662                    False)}
1663        ]
1664
1665    results = []
1666
1667    for test_case in test_cases:
1668        ensure_phones_idle(log, ads)
1669        if phone_a_idle_func and not phone_a_idle_func(log, phone_a):
1670            phone_a.log.error("Phone A Failed to Reselect")
1671            return False
1672
1673        time.sleep(WAIT_TIME_BETWEEN_REG_AND_CALL)
1674
1675        log.info(
1676            "---> %s (caller1: %s, caller2: %s, callee: %s) <---",
1677            test_case["description"],
1678            test_case["params"][1].serial,
1679            test_case["params"][2].serial,
1680            test_case["params"][0].serial)
1681
1682        while not call_setup_teardown_for_call_waiting(
1683            log,
1684            *test_case["params"],
1685            wait_time_in_call=wait_time_in_call,
1686            call_waiting=call_waiting) and retry >= 0:
1687
1688            if retry <= 0:
1689                log.error("Call waiting sub-case: '%s' failed." % test_case[
1690                    "description"])
1691                results.append(False)
1692            else:
1693                log.info("RERUN the sub-case: '%s'" % test_case["description"])
1694
1695            retry = retry - 1
1696
1697    for result in results:
1698        if not result:
1699            return False
1700
1701    return True