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