• 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
17import time
18from queue import Empty
19from acts.test_utils.tel.tel_defines import AUDIO_ROUTE_EARPIECE
20from acts.test_utils.tel.tel_defines import CALL_STATE_RINGING
21from acts.test_utils.tel.tel_defines import INCALL_UI_DISPLAY_BACKGROUND
22from acts.test_utils.tel.tel_defines import INCALL_UI_DISPLAY_FOREGROUND
23from acts.test_utils.tel.tel_defines import MAX_WAIT_TIME_ACCEPT_CALL_TO_OFFHOOK_EVENT
24from acts.test_utils.tel.tel_defines import MAX_WAIT_TIME_CALL_INITIATION
25from acts.test_utils.tel.tel_defines import MAX_WAIT_TIME_CALLEE_RINGING
26from acts.test_utils.tel.tel_defines import MAX_WAIT_TIME_NW_SELECTION
27from acts.test_utils.tel.tel_defines import MAX_WAIT_TIME_TELECOM_RINGING
28from acts.test_utils.tel.tel_defines import MAX_WAIT_TIME_VIDEO_SESSION_EVENT
29from acts.test_utils.tel.tel_defines import MAX_WAIT_TIME_VOLTE_ENABLED
30from acts.test_utils.tel.tel_defines import NETWORK_SERVICE_DATA
31from acts.test_utils.tel.tel_defines import NETWORK_SERVICE_VOICE
32from acts.test_utils.tel.tel_defines import GEN_4G
33from acts.test_utils.tel.tel_defines import TELEPHONY_STATE_OFFHOOK
34from acts.test_utils.tel.tel_defines import TELEPHONY_STATE_RINGING
35from acts.test_utils.tel.tel_defines import VT_STATE_AUDIO_ONLY
36from acts.test_utils.tel.tel_defines import VT_STATE_BIDIRECTIONAL
37from acts.test_utils.tel.tel_defines import VT_STATE_BIDIRECTIONAL_PAUSED
38from acts.test_utils.tel.tel_defines import VT_STATE_RX_ENABLED
39from acts.test_utils.tel.tel_defines import VT_STATE_RX_PAUSED
40from acts.test_utils.tel.tel_defines import VT_STATE_TX_ENABLED
41from acts.test_utils.tel.tel_defines import VT_STATE_TX_PAUSED
42from acts.test_utils.tel.tel_defines import VT_STATE_STATE_INVALID
43from acts.test_utils.tel.tel_defines import VT_VIDEO_QUALITY_DEFAULT
44from acts.test_utils.tel.tel_defines import WAIT_TIME_ACCEPT_VIDEO_CALL_TO_CHECK_STATE
45from acts.test_utils.tel.tel_defines import WAIT_TIME_ANDROID_STATE_SETTLING
46from acts.test_utils.tel.tel_defines import WAIT_TIME_IN_CALL
47from acts.test_utils.tel.tel_defines import WFC_MODE_DISABLED
48from acts.test_utils.tel.tel_defines import EventCallStateChanged
49from acts.test_utils.tel.tel_defines import EventTelecomVideoCallSessionModifyRequestReceived
50from acts.test_utils.tel.tel_defines import EventTelecomVideoCallSessionModifyResponseReceived
51from acts.test_utils.tel.tel_defines import EVENT_VIDEO_SESSION_MODIFY_RESPONSE_RECEIVED
52from acts.test_utils.tel.tel_defines import EVENT_VIDEO_SESSION_MODIFY_REQUEST_RECEIVED
53from acts.test_utils.tel.tel_defines import CallStateContainer
54from acts.test_utils.tel.tel_subscription_utils import get_outgoing_voice_sub_id
55from acts.test_utils.tel.tel_subscription_utils import get_incoming_voice_sub_id
56from acts.test_utils.tel.tel_test_utils import check_phone_number_match
57from acts.test_utils.tel.tel_test_utils import ensure_network_generation
58from acts.test_utils.tel.tel_test_utils import is_event_match
59from acts.test_utils.tel.tel_test_utils import hangup_call
60from acts.test_utils.tel.tel_test_utils import set_wfc_mode
61from acts.test_utils.tel.tel_test_utils import toggle_airplane_mode
62from acts.test_utils.tel.tel_test_utils import toggle_volte
63from acts.test_utils.tel.tel_test_utils import verify_incall_state
64from acts.test_utils.tel.tel_test_utils import wait_for_network_generation
65from acts.test_utils.tel.tel_test_utils import wait_for_network_rat_for_subscription
66from acts.test_utils.tel.tel_test_utils import wait_for_ringing_event
67from acts.test_utils.tel.tel_test_utils import wait_for_telecom_ringing
68from acts.test_utils.tel.tel_test_utils import wait_for_video_enabled
69from acts.test_utils.tel.tel_voice_utils import is_call_hd
70
71
72def phone_setup_video(log, ad):
73    """Setup phone default sub_id to make video call
74
75    Args:
76        log: log object.
77        ad: android device object
78
79    Returns:
80        True if ad (default sub_id) is setup correctly and idle for video call.
81    """
82    return phone_setup_video_for_subscription(log, ad,
83                                              get_outgoing_voice_sub_id(ad))
84
85
86def phone_setup_video_for_subscription(log, ad, sub_id):
87    """Setup phone sub_id to make video call
88
89    Args:
90        log: log object.
91        ad: android device object
92        sub_id: ad's sub id.
93
94    Returns:
95        True if ad (sub_id) is setup correctly and idle for video call.
96    """
97
98    # FIXME: temporarily disable selinux due to b/26953532
99    ad.adb.shell("setenforce", "0")
100
101    toggle_airplane_mode(log, ad, False)
102    if not set_wfc_mode(log, ad, WFC_MODE_DISABLED):
103        log.error("{} Disable WFC failed.".format(ad.serial))
104        return False
105    toggle_volte(log, ad, True)
106
107    if not ensure_network_generation(log,
108                                     ad,
109                                     GEN_4G,
110                                     voice_or_data=NETWORK_SERVICE_DATA):
111        log.error("{} voice not in LTE mode.".format(ad.serial))
112        return False
113
114    return phone_idle_video_for_subscription(log, ad, sub_id)
115
116
117def phone_idle_video(log, ad):
118    """Return if phone (default sub_id) is idle for video call.
119
120    Args:
121        log: log object.
122        ad: android device object
123
124    Returns:
125        True if ad is idle for video call.
126    """
127    return phone_idle_video_for_subscription(log, ad,
128                                             get_outgoing_voice_sub_id(ad))
129
130
131def phone_idle_video_for_subscription(log, ad, sub_id):
132    """Return if phone (sub_id) is idle for video call.
133
134    Args:
135        log: log object.
136        ad: android device object
137        sub_id: ad's sub id
138
139    Returns:
140        True if ad (sub_id) is idle for video call.
141    """
142
143    if not wait_for_network_generation(log, ad, GEN_4G):
144        log.error("{} voice not in LTE mode.".format(ad.serial))
145        return False
146
147    if not wait_for_video_enabled(log, ad, MAX_WAIT_TIME_VOLTE_ENABLED):
148        log.error(
149            "{} failed to <report volte enabled true> within {}s.".format(
150                ad.serial, MAX_WAIT_TIME_VOLTE_ENABLED))
151        return False
152    return True
153
154
155def is_phone_in_call_video(log, ad):
156    """Return if ad is in a video call (in expected video state).
157
158    Args:
159        log: log object.
160        ad: android device object
161        video_state: Expected Video call state.
162            This is optional, if it's None,
163            then TX_ENABLED/RX_ENABLED/BIDIRECTIONAL video call state will
164            return True.
165
166    Returns:
167        True if ad (for sub_id) is in a video call (in expected video state).
168    """
169    return is_phone_in_call_video_for_subscription(
170        log, ad, get_outgoing_voice_sub_id(ad))
171
172
173def is_phone_in_call_video_for_subscription(log, ad, sub_id, video_state=None):
174    """Return if ad (for sub_id) is in a video call (in expected video state).
175    Args:
176        log: log object.
177        ad: android device object
178        sub_id: device sub_id
179        video_state: Expected Video call state.
180            This is optional, if it's None,
181            then TX_ENABLED/RX_ENABLED/BIDIRECTIONAL video call state will
182            return True.
183
184    Returns:
185        True if ad is in a video call (in expected video state).
186    """
187
188    if video_state is None:
189        log.info("Verify if {}(subid {}) in video call.".format(ad.serial,
190                                                                sub_id))
191    if not ad.droid.telecomIsInCall():
192        log.error("{} not in call.".format(ad.serial))
193        return False
194    call_list = ad.droid.telecomCallGetCallIds()
195    for call in call_list:
196        state = ad.droid.telecomCallVideoGetState(call)
197        if video_state is None:
198            if {
199                    VT_STATE_AUDIO_ONLY: False,
200                    VT_STATE_TX_ENABLED: True,
201                    VT_STATE_TX_PAUSED: True,
202                    VT_STATE_RX_ENABLED: True,
203                    VT_STATE_RX_PAUSED: True,
204                    VT_STATE_BIDIRECTIONAL: True,
205                    VT_STATE_BIDIRECTIONAL_PAUSED: True,
206                    VT_STATE_STATE_INVALID: False
207            }[state]:
208                return True
209        else:
210            if state == video_state:
211                return True
212        log.info("Non-Video-State: {}".format(state))
213    log.error("Phone not in video call. Call list: {}".format(call_list))
214    return False
215
216
217def is_phone_in_call_video_bidirectional(log, ad):
218    """Return if phone in bi-directional video call.
219
220    Args:
221        log: log object.
222        ad: android device object
223
224    Returns:
225        True if phone in bi-directional video call.
226    """
227    return is_phone_in_call_video_bidirectional_for_subscription(
228        log, ad, get_outgoing_voice_sub_id(ad))
229
230
231def is_phone_in_call_video_bidirectional_for_subscription(log, ad, sub_id):
232    """Return if phone in bi-directional video call for subscription id.
233
234    Args:
235        log: log object.
236        ad: android device object
237        sub_id: subscription id.
238
239    Returns:
240        True if phone in bi-directional video call.
241    """
242    log.info("Verify if {}(subid {}) in bi-directional video call.".format(
243        ad.serial, sub_id))
244    return is_phone_in_call_video_for_subscription(log, ad, sub_id,
245                                                   VT_STATE_BIDIRECTIONAL)
246
247
248def is_phone_in_call_video_tx_enabled(log, ad):
249    """Return if phone in tx_enabled video call.
250
251    Args:
252        log: log object.
253        ad: android device object
254
255    Returns:
256        True if phone in tx_enabled video call.
257    """
258    return is_phone_in_call_video_tx_enabled_for_subscription(
259        log, ad, get_outgoing_voice_sub_id(ad))
260
261
262def is_phone_in_call_video_tx_enabled_for_subscription(log, ad, sub_id):
263    """Return if phone in tx_enabled video call for subscription id.
264
265    Args:
266        log: log object.
267        ad: android device object
268        sub_id: subscription id.
269
270    Returns:
271        True if phone in tx_enabled video call.
272    """
273    log.info("Verify if {}(subid {}) in tx_enabled video call.".format(
274        ad.serial, sub_id))
275    return is_phone_in_call_video_for_subscription(log, ad, sub_id,
276                                                   VT_STATE_TX_ENABLED)
277
278
279def is_phone_in_call_video_rx_enabled(log, ad):
280    """Return if phone in rx_enabled video call.
281
282    Args:
283        log: log object.
284        ad: android device object
285
286    Returns:
287        True if phone in rx_enabled video call.
288    """
289    return is_phone_in_call_video_rx_enabled_for_subscription(
290        log, ad, get_outgoing_voice_sub_id(ad))
291
292
293def is_phone_in_call_video_rx_enabled_for_subscription(log, ad, sub_id):
294    """Return if phone in rx_enabled video call for subscription id.
295
296    Args:
297        log: log object.
298        ad: android device object
299        sub_id: subscription id.
300
301    Returns:
302        True if phone in rx_enabled video call.
303    """
304    log.info("Verify if {}(subid {}) in rx_enabled video call.".format(
305        ad.serial, sub_id))
306    return is_phone_in_call_video_for_subscription(log, ad, sub_id,
307                                                   VT_STATE_RX_ENABLED)
308
309
310def is_phone_in_call_voice_hd(log, ad):
311    """Return if phone in hd voice call.
312
313    Args:
314        log: log object.
315        ad: android device object
316
317    Returns:
318        True if phone in hd voice call.
319    """
320    return is_phone_in_call_voice_hd_for_subscription(
321        log, ad, get_outgoing_voice_sub_id(ad))
322
323
324def is_phone_in_call_voice_hd_for_subscription(log, ad, sub_id):
325    """Return if phone in hd voice call for subscription id.
326
327    Args:
328        log: log object.
329        ad: android device object
330        sub_id: subscription id.
331
332    Returns:
333        True if phone in hd voice call.
334    """
335    log.info("Verify if {}(subid {}) in hd voice call.".format(ad.serial,
336                                                               sub_id))
337    if not ad.droid.telecomIsInCall():
338        log.error("{} not in call.".format(ad.serial))
339        return False
340    for call in ad.droid.telecomCallGetCallIds():
341        state = ad.droid.telecomCallVideoGetState(call)
342        if (state == VT_STATE_AUDIO_ONLY and is_call_hd(log, ad, call)):
343            return True
344        log.info("Non-HDAudio-State: {}, property: {}".format(
345            state, ad.droid.telecomCallGetProperties(call)))
346    return False
347
348
349def initiate_video_call(log, ad_caller, callee_number):
350    """Make phone call from caller to callee.
351
352    Args:
353        ad_caller: Caller android device object.
354        callee_number: Callee phone number.
355        emergency : specify the call is emergency.
356            Optional. Default value is False.
357
358    Returns:
359        result: if phone call is placed successfully.
360    """
361
362    wait_time_for_incall_state = MAX_WAIT_TIME_CALL_INITIATION
363    ad_caller.droid.telecomCallNumber(callee_number, True)
364    while wait_time_for_incall_state > 0:
365        wait_time_for_incall_state -= 1
366        if ad_caller.droid.telecomIsInCall():
367            return True
368        time.sleep(1)
369    log.error("Make call fail.")
370    return False
371
372
373def wait_and_answer_video_call(log,
374                               ad,
375                               incoming_number=None,
376                               video_state=VT_STATE_BIDIRECTIONAL,
377                               incall_ui_display=INCALL_UI_DISPLAY_FOREGROUND):
378    """Wait for an incoming call on default voice subscription and
379       accepts the call.
380
381    Args:
382        ad: android device object.
383        incoming_number: Expected incoming number.
384            Optional. Default is None
385        incall_ui_display: after answer the call, bring in-call UI to foreground or
386            background. Optional, default value is INCALL_UI_DISPLAY_FOREGROUND.
387            if = INCALL_UI_DISPLAY_FOREGROUND, bring in-call UI to foreground.
388            if = INCALL_UI_DISPLAY_BACKGROUND, bring in-call UI to background.
389            else, do nothing.
390
391    Returns:
392        True: if incoming call is received and answered successfully.
393        False: for errors
394    """
395    return wait_and_answer_video_call_for_subscription(
396        log, ad, get_outgoing_voice_sub_id(ad), incoming_number, video_state,
397        incall_ui_display)
398
399
400def wait_and_answer_video_call_for_subscription(
401        log,
402        ad,
403        sub_id,
404        incoming_number=None,
405        video_state=VT_STATE_BIDIRECTIONAL,
406        incall_ui_display=INCALL_UI_DISPLAY_FOREGROUND):
407    """Wait for an incoming call on specified subscription and
408       accepts the call.
409
410    Args:
411        ad: android device object.
412        sub_id: subscription ID
413        incoming_number: Expected incoming number.
414            Optional. Default is None
415        incall_ui_display: after answer the call, bring in-call UI to foreground or
416            background. Optional, default value is INCALL_UI_DISPLAY_FOREGROUND.
417            if = INCALL_UI_DISPLAY_FOREGROUND, bring in-call UI to foreground.
418            if = INCALL_UI_DISPLAY_BACKGROUND, bring in-call UI to background.
419            else, do nothing.
420
421    Returns:
422        True: if incoming call is received and answered successfully.
423        False: for errors
424    """
425    ad.ed.clear_all_events()
426    ad.droid.telephonyStartTrackingCallStateForSubscription(sub_id)
427    if (not ad.droid.telecomIsRinging() and
428            ad.droid.telephonyGetCallStateForSubscription(sub_id) !=
429            TELEPHONY_STATE_RINGING):
430        try:
431            event_ringing = wait_for_ringing_event(
432                log, ad, MAX_WAIT_TIME_CALLEE_RINGING)
433            if event_ringing is None:
434                log.error("No Ringing Event.")
435                return False
436        finally:
437            ad.droid.telephonyStopTrackingCallStateChangeForSubscription(
438                sub_id)
439
440        if not incoming_number:
441            result = True
442        else:
443            result = check_phone_number_match(
444                event_ringing['data']['incomingNumber'], incoming_number)
445
446        if not result:
447            log.error("Incoming Number not match")
448            log.error("Expected number:{}, actual number:{}".format(
449                incoming_number, event_ringing['data']['incomingNumber']))
450            return False
451
452    ad.ed.clear_all_events()
453
454    ad.droid.telephonyStartTrackingCallStateForSubscription(sub_id)
455
456    if not wait_for_telecom_ringing(log, ad, MAX_WAIT_TIME_TELECOM_RINGING):
457        log.error("Telecom is not ringing.")
458        return False
459
460    log.info("Accept on callee.")
461    ad.droid.telecomAcceptRingingCall(video_state)
462
463    try:
464        ad.ed.wait_for_event(
465            EventCallStateChanged,
466            is_event_match,
467            timeout=MAX_WAIT_TIME_ACCEPT_CALL_TO_OFFHOOK_EVENT,
468            field=CallStateContainer.CALL_STATE,
469            value=TELEPHONY_STATE_OFFHOOK)
470    except Empty:
471        if not ad.droid.telecomIsInCall():
472            log.error("Accept call failed.")
473            return False
474    finally:
475        ad.droid.telephonyStopTrackingCallStateChangeForSubscription(sub_id)
476    if incall_ui_display == INCALL_UI_DISPLAY_FOREGROUND:
477        ad.droid.telecomShowInCallScreen()
478    elif incall_ui_display == INCALL_UI_DISPLAY_BACKGROUND:
479        ad.droid.showHomeScreen()
480    return True
481
482
483def video_call_setup_teardown(log,
484                              ad_caller,
485                              ad_callee,
486                              ad_hangup=None,
487                              video_state=VT_STATE_BIDIRECTIONAL,
488                              verify_caller_func=None,
489                              verify_callee_func=None,
490                              wait_time_in_call=WAIT_TIME_IN_CALL,
491                              incall_ui_display=INCALL_UI_DISPLAY_FOREGROUND):
492    """ Call process, including make a phone call from caller,
493    accept from callee, and hang up. The call is on default subscription
494
495    In call process, call from <droid_caller> to <droid_callee>,
496    accept the call, (optional)then hang up from <droid_hangup>.
497
498    Args:
499        ad_caller: Caller Android Device Object.
500        ad_callee: Callee Android Device Object.
501        ad_hangup: Android Device Object end the phone call.
502            Optional. Default value is None, and phone call will continue.
503        video_state: video state for VT call.
504            Optional. Default value is VT_STATE_BIDIRECTIONAL
505        verify_caller_func: func_ptr to verify caller in correct mode
506            Optional. Default is None
507        verify_callee_func: func_ptr to verify callee in correct mode
508            Optional. Default is None
509        wait_time_in_call: wait time during call.
510            Optional. Default is WAIT_TIME_IN_CALL.
511        incall_ui_display: after answer the call, bring in-call UI to foreground or
512            background. Optional, default value is INCALL_UI_DISPLAY_FOREGROUND.
513            if = INCALL_UI_DISPLAY_FOREGROUND, bring in-call UI to foreground.
514            if = INCALL_UI_DISPLAY_BACKGROUND, bring in-call UI to background.
515            else, do nothing.
516
517    Returns:
518        True if call process without any error.
519        False if error happened.
520
521    """
522    return video_call_setup_teardown_for_subscription(
523        log, ad_caller, ad_callee, get_outgoing_voice_sub_id(ad_caller),
524        get_incoming_voice_sub_id(ad_callee), ad_hangup, video_state,
525        verify_caller_func, verify_callee_func, wait_time_in_call,
526        incall_ui_display)
527
528
529# TODO: b/26337151 Might be able to re-factor call_setup_teardown and add.
530# Minimal changes.
531def video_call_setup_teardown_for_subscription(
532        log,
533        ad_caller,
534        ad_callee,
535        subid_caller,
536        subid_callee,
537        ad_hangup=None,
538        video_state=VT_STATE_BIDIRECTIONAL,
539        verify_caller_func=None,
540        verify_callee_func=None,
541        wait_time_in_call=WAIT_TIME_IN_CALL,
542        incall_ui_display=INCALL_UI_DISPLAY_FOREGROUND):
543    """ Call process, including make a phone call from caller,
544    accept from callee, and hang up. The call is on specified subscription
545
546    In call process, call from <droid_caller> to <droid_callee>,
547    accept the call, (optional)then hang up from <droid_hangup>.
548
549    Args:
550        ad_caller: Caller Android Device Object.
551        ad_callee: Callee Android Device Object.
552        subid_caller: Caller subscription ID
553        subid_callee: Callee subscription ID
554        ad_hangup: Android Device Object end the phone call.
555            Optional. Default value is None, and phone call will continue.
556        video_state: video state for VT call.
557            Optional. Default value is VT_STATE_BIDIRECTIONAL
558        verify_caller_func: func_ptr to verify caller in correct mode
559            Optional. Default is None
560        verify_callee_func: func_ptr to verify callee in correct mode
561            Optional. Default is None
562        wait_time_in_call: wait time during call.
563            Optional. Default is WAIT_TIME_IN_CALL.
564        incall_ui_display: after answer the call, bring in-call UI to foreground or
565            background. Optional, default value is INCALL_UI_DISPLAY_FOREGROUND.
566            if = INCALL_UI_DISPLAY_FOREGROUND, bring in-call UI to foreground.
567            if = INCALL_UI_DISPLAY_BACKGROUND, bring in-call UI to background.
568            else, do nothing.
569
570    Returns:
571        True if call process without any error.
572        False if error happened.
573
574    """
575
576    class _CallSequenceException(Exception):
577        pass
578
579    caller_number = ad_caller.cfg['subscription'][subid_caller]['phone_num']
580    callee_number = ad_callee.cfg['subscription'][subid_callee]['phone_num']
581
582    log.info("Call from {} to {}".format(caller_number, callee_number))
583
584    try:
585        if not initiate_video_call(log, ad_caller, callee_number):
586            raise _CallSequenceException("Initiate call failed.")
587
588        if not wait_and_answer_video_call_for_subscription(
589                log,
590                ad_callee,
591                subid_callee,
592                incoming_number=caller_number,
593                video_state=video_state,
594                incall_ui_display=incall_ui_display):
595            raise _CallSequenceException("Answer call fail.")
596
597        # ensure that all internal states are updated in telecom
598        time.sleep(WAIT_TIME_ACCEPT_VIDEO_CALL_TO_CHECK_STATE)
599
600        # Check if caller/callee dropped call.
601        if not verify_incall_state(log, [ad_callee, ad_caller], True):
602            raise _CallSequenceException("Call Drop!")
603        # Check Callee first
604        # in case of VT call drop, it usually start from callee
605        if verify_callee_func and not verify_callee_func(log, ad_callee):
606            raise _CallSequenceException("Callee not in correct state!")
607        if verify_caller_func and not verify_caller_func(log, ad_caller):
608            raise _CallSequenceException("Caller not in correct state!")
609
610        # TODO: b/26291165 Replace with reducing the volume as we want
611        # to test route switching
612        ad_caller.droid.telecomCallSetAudioRoute(AUDIO_ROUTE_EARPIECE)
613        ad_callee.droid.telecomCallSetAudioRoute(AUDIO_ROUTE_EARPIECE)
614
615        time.sleep(wait_time_in_call)
616
617        # Check Callee first
618        # in case of VT call drop, it usually start from callee
619        if not verify_callee_func:
620            callee_state_result = ad_callee.droid.telecomIsInCall()
621        else:
622            callee_state_result = verify_callee_func(log, ad_callee)
623        if not callee_state_result:
624            raise _CallSequenceException(
625                "Callee not in correct state after {} seconds"
626                .format(wait_time_in_call))
627
628        if not verify_caller_func:
629            caller_state_result = ad_caller.droid.telecomIsInCall()
630        else:
631            caller_state_result = verify_caller_func(log, ad_caller)
632        if not caller_state_result:
633            raise _CallSequenceException(
634                "Caller not in correct state after {} seconds"
635                .format(wait_time_in_call))
636
637        if not ad_hangup:
638            return True
639
640        if not hangup_call(log, ad_hangup):
641            raise _CallSequenceException("Error in Hanging-Up Call")
642        return True
643
644    except _CallSequenceException as e:
645        log.error(e)
646        return False
647    finally:
648        if ad_hangup:
649            for ad in [ad_caller, ad_callee]:
650                try:
651                    if ad.droid.telecomIsInCall():
652                        ad.droid.telecomEndCall()
653                except Exception as e:
654                    log.error(str(e))
655
656
657def video_call_modify_video(log,
658                            ad_requester,
659                            call_id_requester,
660                            ad_responder,
661                            call_id_responder,
662                            video_state_request,
663                            video_quality_request=VT_VIDEO_QUALITY_DEFAULT,
664                            video_state_response=None,
665                            video_quality_response=None,
666                            verify_func_between_request_and_response=None):
667    """Modifies an ongoing call to change the video_call state
668
669    Args:
670        log: logger object
671        ad_requester: android_device object of the requester
672        call_id_requester: the call_id of the call placing the modify request
673        ad_requester: android_device object of the responder
674        call_id_requester: the call_id of the call receiving the modify request
675        video_state_request: the requested video state
676        video_quality_request: the requested video quality, defaults to
677            QUALITY_DEFAULT
678        video_state_response: the responded video state or, or (default)
679            match the request if None
680        video_quality_response: the responded video quality, or (default)
681            match the request if None
682
683    Returns:
684        A call_id corresponding to the first call in the state, or None
685    """
686
687    if not video_state_response:
688        video_state_response = video_state_request
689    if not video_quality_response:
690        video_quality_response = video_quality_request
691
692    cur_video_state = ad_requester.droid.telecomCallVideoGetState(
693        call_id_requester)
694
695    log.info("State change request from {} to {} requested"
696             .format(cur_video_state, video_state_request))
697
698    if cur_video_state == video_state_request:
699        return True
700
701    ad_responder.ed.clear_events(
702        EventTelecomVideoCallSessionModifyRequestReceived)
703
704    ad_responder.droid.telecomCallVideoStartListeningForEvent(
705        call_id_responder, EVENT_VIDEO_SESSION_MODIFY_REQUEST_RECEIVED)
706
707    ad_requester.droid.telecomCallVideoSendSessionModifyRequest(
708        call_id_requester, video_state_request, video_quality_request)
709
710    try:
711        request_event = ad_responder.ed.pop_event(
712            EventTelecomVideoCallSessionModifyRequestReceived,
713            MAX_WAIT_TIME_VIDEO_SESSION_EVENT)
714        log.info(request_event)
715    except Empty:
716        log.error("Failed to receive SessionModifyRequest!")
717        return False
718    finally:
719        ad_responder.droid.telecomCallVideoStopListeningForEvent(
720            call_id_responder, EVENT_VIDEO_SESSION_MODIFY_REQUEST_RECEIVED)
721
722    if (verify_func_between_request_and_response and
723            not verify_func_between_request_and_response()):
724        log.error("verify_func_between_request_and_response failed.")
725        return False
726
727    # TODO: b/26291165 Replace with reducing the volume as we want
728    # to test route switching
729    ad_requester.droid.telecomCallSetAudioRoute(AUDIO_ROUTE_EARPIECE)
730
731    ad_requester.droid.telecomCallVideoStartListeningForEvent(
732        call_id_requester, EVENT_VIDEO_SESSION_MODIFY_RESPONSE_RECEIVED)
733
734    ad_responder.droid.telecomCallVideoSendSessionModifyResponse(
735        call_id_responder, video_state_response, video_quality_response)
736
737    try:
738        response_event = ad_requester.ed.pop_event(
739            EventTelecomVideoCallSessionModifyResponseReceived,
740            MAX_WAIT_TIME_VIDEO_SESSION_EVENT)
741        log.info(response_event)
742    except Empty:
743        log.error("Failed to receive SessionModifyResponse!")
744        return False
745    finally:
746        ad_requester.droid.telecomCallVideoStopListeningForEvent(
747            call_id_requester, EVENT_VIDEO_SESSION_MODIFY_RESPONSE_RECEIVED)
748
749    # TODO: b/26291165 Replace with reducing the volume as we want
750    # to test route switching
751    ad_responder.droid.telecomCallSetAudioRoute(AUDIO_ROUTE_EARPIECE)
752
753    return True
754
755
756def is_call_id_in_video_state(log, ad, call_id, video_state):
757    """Return is the call_id is in expected video_state
758
759    Args:
760        log: logger object
761        ad: android_device object
762        call_id: call id
763        video_state: valid VIDEO_STATE
764
765    Returns:
766        True is call_id in expected video_state; False if not.
767    """
768    return video_state == ad.droid.telecomCallVideoGetState(call_id)
769
770
771def get_call_id_in_video_state(log, ad, video_state):
772    """Gets the first call reporting a given video_state
773        from among the active calls
774
775    Args:
776        log: logger object
777        ad: android_device object
778        video_state: valid VIDEO_STATE
779
780    Returns:
781        A call_id corresponding to the first call in the state, or None
782    """
783
784    if not ad.droid.telecomIsInCall():
785        log.error("{} not in call.".format(ad.serial))
786        return None
787    for call in ad.droid.telecomCallGetCallIds():
788        if is_call_id_in_video_state(log, ad, call, video_state):
789            return call
790    return None
791
792
793def video_call_downgrade(log,
794                         ad_requester,
795                         call_id_requester,
796                         ad_responder,
797                         call_id_responder,
798                         video_state_request=None,
799                         video_quality_request=VT_VIDEO_QUALITY_DEFAULT):
800    """Downgrade Video call to video_state_request.
801    Send telecomCallVideoSendSessionModifyRequest from ad_requester.
802    Get video call state from ad_requester and ad_responder.
803    Verify video calls states are correct and downgrade succeed.
804
805    Args:
806        log: logger object
807        ad_requester: android_device object of the requester
808        call_id_requester: the call_id of the call placing the modify request
809        ad_requester: android_device object of the responder
810        call_id_requester: the call_id of the call receiving the modify request
811        video_state_request: the requested downgrade video state
812            This parameter is optional. If this parameter is None:
813                if call_id_requester current is bi-directional, will downgrade to RX_ENABLED
814                if call_id_requester current is RX_ENABLED, will downgrade to AUDIO_ONLY
815        video_quality_request: the requested video quality, defaults to
816            QUALITY_DEFAULT
817    Returns:
818        True if downgrade succeed.
819    """
820    if (call_id_requester is None) or (call_id_responder is None):
821        log.error("call_id_requester: {}, call_id_responder: {}".format(
822            call_id_requester, call_id_responder))
823        return False
824    current_video_state_requester = ad_requester.droid.telecomCallVideoGetState(
825        call_id_requester)
826    if video_state_request is None:
827        if (current_video_state_requester == VT_STATE_BIDIRECTIONAL or
828                current_video_state_requester ==
829                VT_STATE_BIDIRECTIONAL_PAUSED):
830            video_state_request = VT_STATE_RX_ENABLED
831        elif (current_video_state_requester == VT_STATE_TX_ENABLED or
832              current_video_state_requester == VT_STATE_TX_PAUSED):
833            video_state_request = VT_STATE_AUDIO_ONLY
834        else:
835            log.error("Can Not Downgrade. ad: {}, current state {}".format(
836                ad_requester.serial, current_video_state_requester))
837            return False
838    expected_video_state_responder = {
839        VT_STATE_AUDIO_ONLY: VT_STATE_AUDIO_ONLY,
840        VT_STATE_RX_ENABLED: VT_STATE_TX_ENABLED
841    }[video_state_request]
842
843    ad_requester.droid.telecomCallVideoStartListeningForEvent(
844        call_id_requester, EVENT_VIDEO_SESSION_MODIFY_RESPONSE_RECEIVED)
845
846    ad_requester.droid.telecomCallVideoSendSessionModifyRequest(
847        call_id_requester, video_state_request, video_quality_request)
848
849    try:
850        response_event = ad_requester.ed.pop_event(
851            EventTelecomVideoCallSessionModifyResponseReceived,
852            MAX_WAIT_TIME_VIDEO_SESSION_EVENT)
853        log.info(response_event)
854    except Empty:
855        log.error("Failed to receive SessionModifyResponse!")
856        return False
857    finally:
858        ad_requester.droid.telecomCallVideoStopListeningForEvent(
859            call_id_requester, EVENT_VIDEO_SESSION_MODIFY_RESPONSE_RECEIVED)
860
861    time.sleep(WAIT_TIME_ANDROID_STATE_SETTLING)
862    # TODO: b/26291165 Replace with reducing the volume as we want
863    # to test route switching
864    ad_requester.droid.telecomCallSetAudioRoute(AUDIO_ROUTE_EARPIECE)
865    ad_responder.droid.telecomCallSetAudioRoute(AUDIO_ROUTE_EARPIECE)
866
867    time.sleep(WAIT_TIME_IN_CALL)
868    if video_state_request != ad_requester.droid.telecomCallVideoGetState(
869            call_id_requester):
870        log.error("requester not in correct state. expected:{}, current:{}"
871                  .format(video_state_request,
872                          ad_requester.droid.telecomCallVideoGetState(
873                              call_id_requester)))
874        return False
875    if (expected_video_state_responder !=
876            ad_responder.droid.telecomCallVideoGetState(call_id_responder)):
877        log.error(
878            "responder not in correct state. expected:{}, current:{}".format(
879                expected_video_state_responder,
880                ad_responder.droid.telecomCallVideoGetState(
881                    call_id_responder)))
882        return False
883
884    return True
885
886
887def verify_video_call_in_expected_state(log, ad, call_id, call_video_state,
888                                        call_state):
889    """Return True if video call is in expected video state and call state.
890
891    Args:
892        log: logger object
893        ad: android_device object
894        call_id: ad's call id
895        call_video_state: video state to validate.
896        call_state: call state to validate.
897
898    Returns:
899        True if video call is in expected video state and call state.
900    """
901    if not is_call_id_in_video_state(log, ad, call_id, call_video_state):
902        log.error("Call is not in expected {} state. Current state {}".format(
903            call_video_state, ad.droid.telecomCallVideoGetState(call_id)))
904        return False
905    if ad.droid.telecomCallGetCallState(call_id) != call_state:
906        log.error("Call is not in expected {} state. Current state {}".format(
907            call_state, ad.droid.telecomCallGetCallState(call_id)))
908        return False
909    return True
910