1# Copyright (C) 2024 The Android Open Source Project
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7#      http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14"""HFP proxy module."""
15
16import sys
17import threading
18import time
19
20from mmi2grpc._helpers import assert_description, match_description
21from mmi2grpc._proxy import ProfileProxy
22from pandora.host_grpc import Host
23from pandora.host_pb2 import CONNECTABLE, DISCOVERABLE_GENERAL
24from pandora.security_grpc import Security, SecurityStorage
25from pandora.security_pb2 import PairingEventAnswer
26from pandora_experimental.hfp_grpc import HFP
27from pandora_experimental.hfp_pb2 import (AUDIO_PATH_HANDSFREE, AUDIO_PATH_SPEAKERS)
28
29# Standard time to wait before asking for waitConnection
30WAIT_DELAY_BEFORE_CONNECTION = 2
31
32IXIT_PHONE_NUMBER = 42
33IXIT_SECOND_PHONE_NUMBER = 43
34
35
36class HFPProxy(ProfileProxy):
37
38    def __init__(self, test, channel, rootcanal, modem):
39        super().__init__(channel)
40        self.hfp = HFP(channel)
41        self.host = Host(channel)
42        self.security = Security(channel)
43        self.security_storage = SecurityStorage(channel)
44        self.rootcanal = rootcanal
45        self.modem = modem
46        self.connection = None
47
48        self._auto_confirm_requests()
49
50    def asyncWaitConnection(self, pts_addr, delay=WAIT_DELAY_BEFORE_CONNECTION):
51        """
52        Send a WaitConnection in a grpc callback
53        """
54
55        def waitConnectionCallback(self, pts_addr):
56            self.connection = self.host.WaitConnection(address=pts_addr).connection
57
58        print(f"HFP placeholder mmi: asyncWaitConnection", file=sys.stderr)
59        th = threading.Timer(interval=delay, function=waitConnectionCallback, args=(self, pts_addr))
60        th.start()
61
62    def test_started(self, test: str, pts_addr: bytes, **kwargs):
63        if test not in ("HFP/AG/SLC/BV-02-C", "HFP/AG/SLC/BV-04-C"):
64            self.asyncWaitConnection(pts_addr)
65
66        return "OK"
67
68    @assert_description
69    def TSC_delete_pairing_iut(self, pts_addr: bytes, **kwargs):
70        """
71        Delete the pairing with the PTS using the Implementation Under Test
72        (IUT), then click Ok.
73        """
74
75        self.security_storage.DeleteBond(public=pts_addr)
76        return "OK"
77
78    @assert_description
79    def TSC_iut_enable_slc(self, test: str, pts_addr: bytes, **kwargs):
80        """
81        Click Ok, then initiate a service level connection from the
82        Implementation Under Test (IUT) to the PTS.
83        """
84
85        def enable_slc():
86            time.sleep(2)
87
88            if not self.connection:
89                self.connection = self.host.Connect(address=pts_addr).connection
90
91            if "HFP/HF" in test:
92                self.hfp.EnableSlcAsHandsfree(connection=self.connection)
93            else:
94                self.hfp.EnableSlc(connection=self.connection)
95
96        threading.Thread(target=enable_slc).start()
97
98        return "OK"
99
100    @assert_description
101    def TSC_iut_search(self, **kwargs):
102        """
103        Using the Implementation Under Test (IUT), perform a search for the PTS.
104        If found, click OK.
105        """
106
107        return "OK"
108
109    @assert_description
110    def TSC_iut_connect(self, pts_addr: bytes, **kwargs):
111        """
112        Click Ok, then make a connection request to the PTS from the
113        Implementation Under Test (IUT).
114        """
115
116        def connect():
117            time.sleep(2)
118            self.connection = self.host.Connect(address=pts_addr).connection
119
120        threading.Thread(target=connect).start()
121
122        return "OK"
123
124    @assert_description
125    def TSC_iut_connectable(self, pts_addr: str, test: str, **kwargs):
126        """
127        Make the Implementation Under Test (IUT) connectable, then click Ok.
128        """
129
130        self.host.SetConnectabilityMode(mode=CONNECTABLE)
131        # these two test cases fail if Connection is established in "TSC_iut_enable_slc"
132        if test in ("HFP/AG/SLC/BV-02-C", "HFP/AG/SLC/BV-04-C"):
133            self.connection = self.host.Connect(address=pts_addr).connection
134
135        return "OK"
136
137    @assert_description
138    def TSC_iut_disable_slc(self, test: str, pts_addr: bytes, **kwargs):
139        """
140        Click Ok, then disable the service level connection using the
141        Implementation Under Test (IUT).
142        """
143
144        def disable_slc():
145            time.sleep(2)
146            if "HFP/HF" in test:
147                self.hfp.DisableSlcAsHandsfree(connection=self.connection)
148            else:
149                self.hfp.DisableSlc(connection=self.connection)
150
151        threading.Thread(target=disable_slc).start()
152
153        return "OK"
154
155    @assert_description
156    def TSC_make_battery_charged(self, **kwargs):
157        """
158        Click Ok, then manipulate the Implementation Under Test (IUT) so that
159        the battery is fully charged.
160        """
161
162        self.hfp.SetBatteryLevel(connection=self.connection, battery_percentage=100)
163
164        return "OK"
165
166    @assert_description
167    def TSC_make_battery_discharged(self, **kwargs):
168        """
169        Manipulate the Implementation Under Test (IUT) so that the battery level
170        is not fully charged, then click Ok.
171        """
172
173        self.hfp.SetBatteryLevel(connection=self.connection, battery_percentage=42)
174
175        return "OK"
176
177    @assert_description
178    def TSC_ag_iut_enable_call(self, **kwargs):
179        """
180        Click Ok, then place a call from an external line to the Implementation
181        Under Test (IUT). Do not answer the call unless prompted to do so.
182        """
183
184        def enable_call():
185            time.sleep(2)
186            self.modem.call(IXIT_PHONE_NUMBER)
187
188        threading.Thread(target=enable_call).start()
189
190        return "OK"
191
192    @assert_description
193    def TSC_verify_audio(self, **kwargs):
194        """
195        Verify the presence of an audio connection, then click Ok.
196        """
197
198        # TODO
199        time.sleep(2)  # give it time for SCO to come up
200
201        return "OK"
202
203    @assert_description
204    def TSC_ag_iut_disable_call_external(self, **kwargs):
205        """
206        Click Ok, then end the call using the external terminal.
207        """
208
209        def disable_call_external():
210            time.sleep(2)
211            self.hfp.DeclineCall()
212
213        threading.Thread(target=disable_call_external).start()
214
215        return "OK"
216
217    @assert_description
218    def TSC_iut_enable_audio_using_codec(self, **kwargs):
219        """
220        Click OK, then initiate an audio connection using the Codec Connection
221        Setup procedure.
222        """
223
224        return "OK"
225
226    @assert_description
227    def TSC_iut_disable_audio(self, test: str, pts_addr: bytes, **kwargs):
228        """
229        Click Ok, then close the audio connection (SCO) between the
230        Implementation Under Test (IUT) and the PTS.  Do not close the serivice
231        level connection (SLC) or power-off the IUT.
232        """
233
234        def disable_audio():
235            time.sleep(2)
236            if "HFP/HF" in test:
237                self.hfp.DisconnectToAudioAsHandsfree(connection=self.connection)
238            else:
239                self.hfp.SetAudioPath(audio_path=AUDIO_PATH_SPEAKERS)
240
241        threading.Thread(target=disable_audio).start()
242
243        return "OK"
244
245    @assert_description
246    def TSC_verify_no_audio(self, **kwargs):
247        """
248        Verify the absence of an audio connection (SCO), then click Ok.
249        """
250
251        return "OK"
252
253    @assert_description
254    def TSC_iut_enable_audio(self, test: str, pts_addr: bytes, **kwargs):
255        """
256        Click Ok, then initiate an audio connection (SCO) from the
257        Implementation Under Test (IUT) to the PTS.
258        """
259
260        def enable_audio():
261            time.sleep(2)
262            if "HFP/HF" in test:
263                self.hfp.ConnectToAudioAsHandsfree(connection=self.connection)
264            else:
265                self.hfp.SetAudioPath(audio_path=AUDIO_PATH_HANDSFREE)
266
267        threading.Thread(target=enable_audio).start()
268
269        return "OK"
270
271    @assert_description
272    def TSC_iut_disable_audio_slc_down_ok(self, pts_addr: bytes, **kwargs):
273        """
274        Click OK, then close the audio connection (SCO) between the
275        Implementation Under Test (IUT) and the PTS.  If necessary, it is OK to
276        close the service level connection. Do not power-off the IUT.
277        """
278
279        def disable_slc():
280            time.sleep(2)
281            self.hfp.DisableSlc(connection=self.connection)
282
283        threading.Thread(target=disable_slc).start()
284
285        return "OK"
286
287    @assert_description
288    def TSC_ag_iut_call_no_slc(self, **kwargs):
289        """
290        Place a call from an external line to the Implementation Under Test
291        (IUT).  When the call is active, click Ok.
292        """
293
294        self.modem.call(IXIT_PHONE_NUMBER)
295        time.sleep(5)  # there's a delay before Android registers the call
296        self.hfp.AnswerCall()
297        time.sleep(2)
298
299        return "OK"
300
301    @assert_description
302    def TSC_ag_iut_enable_second_call(self, **kwargs):
303        """
304        Click Ok, then place a second call from an external line to the
305        Implementation Under Test (IUT). Do not answer the call unless prompted
306        to do so.
307        """
308
309        def enable_second_call():
310            time.sleep(2)
311            self.modem.call(IXIT_SECOND_PHONE_NUMBER)
312
313        threading.Thread(target=enable_second_call).start()
314
315        return "OK"
316
317    @assert_description
318    def TSC_ag_iut_call_swap(self, **kwargs):
319        """
320        Click Ok, then place the current call on hold and make the incoming/held
321        call active using the Implementation Under Test (IUT).
322        """
323
324        self.hfp.SwapActiveCall()
325
326        return "OK"
327
328    @assert_description
329    def TSC_verify_audio_second_call(self, **kwargs):
330        """
331        Verify the audio is returned to the 2nd call and then click Ok.  Resume
332        action may be needed.  If the audio is not returned to the 2nd call,
333        click Cancel.
334        """
335
336        return "OK"
337
338    @assert_description
339    def TSC_ag_iut_disable_call_after_verdict(self, **kwargs):
340        """
341        After the test verdict  is given, end all active calls using the
342        external line or the Implementation Under Test (IUT).  Click OK to
343        continue.
344        """
345
346        self.hfp.DeclineCall()
347
348        return "OK"
349
350    @assert_description
351    def TSC_disable_ag_cellular_network_expect_no_notification(self, **kwargs):
352        """
353        Disable the control channel, such that the AG is de-registered. Then,
354        click OK.
355        """
356
357        return "OK"
358
359    @assert_description
360    def TSC_verify_no_ecnr(self, **kwargs):
361        """
362        Verify that EC and NR functionality is disabled, then click Ok.
363        """
364
365        return "OK"
366
367    @assert_description
368    def TSC_disable_inband_ring(self, **kwargs):
369        """
370        Click Ok, then disable the in-band ringtone using the Implemenation
371        Under Test (IUT).
372        """
373
374        self.hfp.SetInBandRingtone(enabled=False)
375        self.host.Reset()
376
377        return "OK"
378
379    @assert_description
380    def TSC_wait_until_ringing(self, **kwargs):
381        """
382        When the Implementation Under Test (IUT) alerts the incoming call, click
383        Ok.
384        """
385
386        # we are triggering a call from modem_simulator, so the alert is immediate
387
388        return "OK"
389
390    @assert_description
391    def TSC_verify_incoming_call_ag(self, **kwargs):
392        """
393        Verify that there is an incoming call on the Implementation Under Test
394        (IUT).
395        """
396
397        # we are triggering a call from modem_simulator, so this is guaranteed
398
399        return "OK"
400
401    @assert_description
402    def TSC_disable_ag_cellular_network_expect_notification(self, pts_addr: bytes, **kwargs):
403        """
404        Click OK. Then, disable the control channel, such that the AG is de-
405        registered.
406        """
407
408        def disable_slc():
409            time.sleep(2)
410            self.hfp.DisableSlc(connection=self.connection)
411
412        threading.Thread(target=disable_slc).start()
413
414        return "OK"
415
416    @assert_description
417    def TSC_adjust_ag_battery_level_expect_no_notification(self, **kwargs):
418        """
419        Adjust the battery level on the AG to a level that should cause a
420        battery level indication to be sent to HF. Then, click OK.
421        """
422
423        self.hfp.SetBatteryLevel(connection=self.connection, battery_percentage=42)
424
425        return "OK"
426
427    def TSC_verify_subscriber_number(self, **kwargs):
428        """
429        Using the Implementation Under Test (IUT), verify that the following is
430        a valid Audio Gateway (AG) subscriber number, then click
431        Ok."+15551234567"nnNOTE: Subscriber service type is 145
432        """
433
434        return "OK"
435
436    def TSC_ag_prepare_at_bldn(self, **kwargs):
437        r"""
438        Place the Implemenation Under Test (IUT) in a state which will accept an
439        outgoing call set-up request from the PTS, then click OK.
440
441        Note:  The
442        PTS will send a request to establish an outgoing call from the IUT to
443        the last dialed number.  Answer the incoming call when alerted.
444        """
445
446        self.hfp.MakeCall(number=str(IXIT_PHONE_NUMBER))
447        self.log("Calling")
448        time.sleep(2)
449        self.hfp.DeclineCall()
450        self.log("Declining")
451        time.sleep(2)
452
453        return "OK"
454
455    @assert_description
456    def TSC_ag_iut_prepare_for_atd(self, **kwargs):
457        """
458        Place the Implementation Under Test (IUT) in a mode that will allow an
459        outgoing call initiated by the PTS, and click Ok.
460        """
461
462        return "OK"
463
464    @assert_description
465    def TSC_terminal_answer_call(self, **kwargs):
466        """
467        Click Ok, then answer the incoming call on the external terminal.
468        """
469
470        def answer_call():
471            time.sleep(2)
472            self.log("Answering")
473            self.modem.answer_outgoing_call(IXIT_PHONE_NUMBER)
474
475        threading.Thread(target=answer_call).start()
476
477        return "OK"
478
479    @match_description
480    def TSC_signal_strength_verify(self, **kwargs):
481        """
482        Verify that the signal reported on the Implementaion Under Test \(IUT\) is
483        proportional to the value \(out of 5\), then click Ok.[0-9]
484        """
485
486        return "OK"
487
488    @assert_description
489    def TSC_signal_strength_impair(self, **kwargs):
490        """
491        Impair the cellular signal by placing the Implementation Under Test
492        (IUT) under partial RF shielding, then click Ok.
493        """
494
495        return "OK"
496
497    @assert_description
498    def TSC_verify_network_operator(self, **kwargs):
499        """
500        Verify the following information matches the network operator reported
501        on the Implementation Under Test (IUT), then click Ok:"Android Virtual "
502        """
503
504        return "OK"
505
506    @assert_description
507    def TSC_INFO_slc_with_30_seconds_wait(self, **kwargs):
508        """
509        After clicking the OK button, PTS will connect to the IUT and then be
510        idle for 30 seconds as part of the test procedure.
511
512        Click OK to proceed.
513        """
514
515        return "OK"
516
517    @assert_description
518    def TSC_ag_iut_disable_call(self, **kwargs):
519        """
520        Click Ok, then end the call using the Implemention Under Test IUT).
521        """
522
523        def disable_call():
524            time.sleep(2)
525            self.hfp.DeclineCall()
526
527        threading.Thread(target=disable_call).start()
528
529        return "OK"
530
531    @match_description
532    def TSC_dtmf_verify(self, **kwargs):
533        """
534        Verify the DTMF code, then click Ok. .
535        """
536
537        return "OK"
538
539    @assert_description
540    def TSC_TWC_instructions(self, **kwargs):
541        """
542        NOTE: The following rules apply for this test case:
543
544        1.
545        TSPX_phone_number - the 1st call
546        2. TSPX_second_phone_number - the 2nd
547        call
548
549        Edits can be made within the IXIT settings for the above phone
550        numbers.
551        """
552
553        return "OK"
554
555    def TSC_call_swap_and_disable_held_tester(self, **kwargs):
556        """
557        Set the Implementation Under Test (IUT) in a state that will allow the
558        PTS to initiate a AT+CHLD=1 operation,  then click Ok.
559
560        Note: Upon
561        receiving the said command, the IUT will simultaneously drop the active
562        call and make the held call active.
563        """
564
565        return "OK"
566
567    @assert_description
568    def TSC_verify_audio_first_call(self, **kwargs):
569        """
570        Verify the audio is returned to the 1st call and click Ok. Resume action
571        my be needed.  If the audio is not present in the 1st call, click
572        Cancel.
573        """
574
575        # TODO
576
577        return "OK"
578
579    @assert_description
580    def TSC_ag_iut_dial_out_second(self, **kwargs):
581        """
582        Verify that the last number dialed on the Implementation Under Test
583        (IUT) matches the TSPX_Second_phone_number entered in the IXIT settings.
584        """
585
586        # TODO
587
588        return "OK"
589
590    @assert_description
591    def TSC_prepare_iut_for_vra(self, pts_addr: bytes, test: str, **kwargs):
592        """
593        Place the Implementation Under Test (IUT) in a state which will allow a
594        request from the PTS to activate voice recognition, then click Ok.
595        """
596
597        if "HFP/HF" not in test:
598            self.hfp.SetVoiceRecognition(
599                enabled=True,
600                connection=self.connection,
601            )
602
603        return "OK"
604
605    @assert_description
606    def TSC_prepare_iut_for_vrd(self, **kwargs):
607        """
608        Place the Implementation Under Test (IUT) in a state which will allow a
609        voice recognition deactivation from PTS, then click Ok.
610        """
611
612        return "OK"
613
614    @assert_description
615    def TSC_ag_iut_clear_call_history(self, **kwargs):
616        """
617        Clear the call history on  the Implementation Under Test (IUT) such that
618        there are zero records of any numbers dialed, then click Ok.
619        """
620
621        self.hfp.ClearCallHistory()
622
623        return "OK"
624
625    @assert_description
626    def TSC_reject_call(self, test: str, pts_addr: bytes, **kwargs):
627        """
628        Click Ok, then reject the incoming call using the Implemention Under
629        Test (IUT).
630        """
631
632        def reject_call():
633            time.sleep(2)
634            if "HFP/HF" in test:
635                self.hfp.DeclineCallAsHandsfree(connection=self.connection)
636            else:
637                self.hfp.DeclineCall()
638
639        threading.Thread(target=reject_call).start()
640
641        return "OK"
642
643    @assert_description
644    def TSC_hf_iut_answer_call(self, pts_addr: bytes, **kwargs):
645        """
646        Click Ok, then answer the incoming call using the Implementation Under
647        Test (IUT).
648        """
649
650        def answer_call():
651            time.sleep(2)
652            self.hfp.AnswerCallAsHandsfree(connection=self.connection)
653
654        threading.Thread(target=answer_call).start()
655
656        return "OK"
657
658    @assert_description
659    def TSC_iut_disable_audio_poweroff_ok(self, **kwargs):
660        """
661        Click Ok, then close the audio connection (SCO) by one of the following
662        ways:
663
664        1. Close the service level connection (SLC)
665        2. Powering off the
666        Implementation Under Test (IUT)
667        """
668
669        self.host.Reset()
670
671        return "OK"
672
673    @assert_description
674    def TSC_verify_inband_ring(self, **kwargs):
675        """
676        Verify that the in-band ringtone is audible, then click Ok.
677        """
678
679        return "OK"
680
681    @assert_description
682    def TSC_verify_inband_ring_muting(self, **kwargs):
683        """
684        Verify that the in-band ringtone is not audible , then click Ok.
685        """
686
687        return "OK"
688
689    @assert_description
690    def TSC_hf_iut_disable_call(self, pts_addr: bytes, **kwargs):
691        """
692        Click Ok, then end the call process from the Implementation Under Test
693        (IUT).
694        """
695
696        def disable_call():
697            time.sleep(2)
698            self.hfp.EndCallAsHandsfree(connection=self.connection)
699
700        threading.Thread(target=disable_call).start()
701
702        return "OK"
703
704    @assert_description
705    def TSC_mute_inband_ring_iut(self, **kwargs):
706        """
707        Mute the in-band ringtone on the Implementation Under Test (IUT) and
708        then click OK.
709        """
710
711        return "OK"
712
713    @assert_description
714    def TSC_verify_iut_alerting(self, **kwargs):
715        """
716        Verify that the Implementation Under Test (IUT) is generating a local
717        alert, then click Ok.
718        """
719
720        return "OK"
721
722    @assert_description
723    def TSC_verify_iut_not_alerting(self, **kwargs):
724        """
725        Verify that the Implementation Under Test (IUT) is not generating a
726        local alert.
727        """
728
729        return "OK"
730
731    @assert_description
732    def TSC_hf_iut_enable_call_number(self, pts_addr: bytes, **kwargs):
733        """
734        Click Ok, then place an outgoing call from the Implementation Under Test
735        (IUT) using an enterted phone number.
736        """
737
738        def disable_call():
739            time.sleep(2)
740            self.hfp.MakeCallAsHandsfree(connection=self.connection, number="42")
741
742        threading.Thread(target=disable_call).start()
743
744        return "OK"
745
746    @assert_description
747    def TSC_hf_iut_enable_call_memory(self, **kwargs):
748        """
749        Click Ok, then place an outgoing call from the Implementation Under Test
750        (IUT) by entering the memory index.  For further clarification please
751        see the HFP 1.5 Specification.
752        """
753
754        def enable_call():
755            time.sleep(2)
756            self.hfp.MakeCallAsHandsfree(connection=self.connection, number=">1")
757
758        threading.Thread(target=enable_call).start()
759
760        return "OK"
761
762    @assert_description
763    def TSC_hf_iut_call_swap_then_disable_held_alternative(self, pts_addr: bytes, **kwargs):
764        """
765        Using the Implementation Under Test (IUT), perform one of the following
766        two actions:
767
768        1. Click OK, make the held/waiting call active, disabling
769        the active call.
770        2. Click OK, make the held/waiting call active, placing
771        the active call on hold.
772        """
773
774        def call_swap_then_disable_held_alternative():
775            time.sleep(2)
776            self.hfp.CallTransferAsHandsfree(connection=self.connection)
777
778        threading.Thread(target=call_swap_then_disable_held_alternative).start()
779
780        return "OK"
781
782    @assert_description
783    def TSC_iut_make_discoverable(self, **kwargs):
784        """
785        Place the Implementation Under Test (IUT) in discoverable mode, then
786        click Ok.
787        """
788
789        self.host.SetDiscoverabilityMode(mode=DISCOVERABLE_GENERAL)
790
791        return "OK"
792
793    @assert_description
794    def TSC_iut_accept_connection(self, **kwargs):
795        """
796        Click Ok, then accept the pairing and connection requests on the
797        Implementation Under Test (IUT), if prompted.
798        """
799
800        return "OK"
801
802    @assert_description
803    def TSC_voice_recognition_enable_iut(self, pts_addr: bytes, **kwargs):
804        """
805        Using the Implementation Under Test (IUT), activate voice recognition.
806        """
807
808        self.hfp.SetVoiceRecognitionAsHandsfree(
809            enabled=True,
810            connection=self.connection,
811        )
812
813        return "OK"
814
815    @assert_description
816    def TSC_voice_recognition_disable_iut(self, pts_addr: bytes, **kwargs):
817        """
818        Using the Implementation Under Test (IUT), deactivate voice recognition.
819        """
820
821        self.hfp.SetVoiceRecognitionAsHandsfree(
822            enabled=False,
823            connection=self.connection,
824        )
825
826        return "OK"
827
828    @match_description
829    def TSC_dtmf_send(self, pts_addr: bytes, dtmf: str, **kwargs):
830        r"""
831        Send the DTMF code, then click Ok. (?P<dtmf>.*)
832        """
833
834        self.hfp.SendDtmfFromHandsfree(
835            connection=self.connection,
836            code=dtmf[0].encode("ascii")[0],
837        )
838
839        return "OK"
840
841    @assert_description
842    def TSC_verify_hf_iut_reports_held_and_active_call(self, **kwargs):
843        """
844        Verify that the Implementation Under Test (IUT) interprets both held and
845        active call signals, then click Ok.  If applicable, verify that the
846        information is correctly displayed on the IUT, then click Ok.
847        """
848
849        return "OK"
850
851    def TSC_rf_shield_iut_or_pts(self, **kwargs):
852        """
853        Click Ok, then move the PTS and the Implementation Under Test (IUT) out
854        of range of each other by performing one of the following IUT specific
855        actions:
856
857        1. Hands Free (HF) IUT - Place the IUT in the RF shield box or
858        physically take out of range from the PTS.
859
860        2. Audio Gateway (AG) IUT-
861        Physically take the IUT out range.  Do not place in the RF shield box as
862        it will interfere with the cellular network.
863
864        Note: The PTS can also be
865        placed in the RF shield box if necessary.
866        """
867
868        def shield_iut_or_pts():
869            time.sleep(2)
870            self.rootcanal.move_out_of_range()
871
872        threading.Thread(target=shield_iut_or_pts).start()
873
874        return "OK"
875
876    @assert_description
877    def TSC_rf_shield_open(self, **kwargs):
878        """
879        Click Ok, then remove the Implementation Under Test (IUT) and/or the PTS
880        from the RF shield.  If the out of range method was used, bring the IUT
881        and PTS back within range.
882        """
883
884        def shield_open():
885            time.sleep(2)
886            self.rootcanal.move_in_range()
887
888        threading.Thread(target=shield_open).start()
889
890        return "OK"
891
892    @match_description
893    def TSC_verify_speaker_volume(self, volume: str, **kwargs):
894        r"""
895        Verify that the Hands Free \(HF\) speaker volume is displayed correctly on
896        the Implementation Under Test \(IUT\).(?P<volume>[0-9]*)
897        """
898
899        return "OK"
900
901    @assert_description
902    def TSC_ag_iut_clear_memory(self, **kwargs):
903        """
904        Clear the memory indexed by TSPX_phone_number_memory on the AG such that
905        the memory slot becomes empty, then Click OK.
906        """
907        self.hfp.ClearCallHistory()
908
909        return "OK"
910
911    @assert_description
912    def TSC_enable_call_memory_invalid_tester(self, **kwargs):
913        """
914        The PTS will send a call request containing an invalid/out of range
915        memory index from the TSPX_phone_number_memory_invalid_index found in
916        the IXIT settings.
917        """
918
919        return "OK"
920
921    @assert_description
922    def TSC_hf_iut_enable_call_memory_invalid(self, pts_addr: bytes, **kwargs):
923        """
924        Click Ok, then attempt to place an outgoing call from the Implementation
925        Under Test (IUT) by entering a memory index which does not equal the
926        TSPX_phone_number_memory.  For further clarification please see the HFP
927        1.5 Specification.
928        """
929
930        def enable_call():
931            time.sleep(2)
932            self.hfp.MakeCallAsHandsfree(connection=self.connection, number=">9999")
933
934        threading.Thread(target=enable_call).start()
935
936        return "OK"
937
938    @assert_description
939    def TSC_hf_iut_verify_call_disable(self, **kwargs):
940        """
941        Verify that the call is disabled on the Implementation Under Test (IUT)
942        and then click Ok.
943        """
944
945        return "OK"
946
947    @assert_description
948    def TSC_verify_subscriber_number_unsupported(self, **kwargs):
949        """
950        Using the Implementation Under Test (IUT), verify that the subscriber
951        number information is not supported by the PTS, then click Ok.
952        """
953
954        return "OK"
955
956    @assert_description
957    def TSC_query_call_list(self, **kwargs):
958        """
959        Using the Implementation Under Test (IUT), query the list of currents
960        calls on the Audio Gateway (AG), then click Ok.
961        """
962
963        return "OK"
964
965    @assert_description
966    def TSC_verify_clcc_receipt(self, **kwargs):
967        """
968        Verify that the +CLCC response(s) received by the Implementation Under
969        Test (IUT) contains the correct call status information, then click Ok.
970        """
971
972        return "OK"
973
974    @assert_description
975    def TSC_impair_ag_signal_expect_no_notification(self, **kwargs):
976        """
977        Impair the signal to the AG so that a reduction in signal strength can
978        be observed. Then, click OK.
979        """
980
981        return "OK"
982
983    @assert_description
984    def TSC_hf_iut_enable_call_last(self, pts_addr: bytes, **kwargs):
985        """
986        Click Ok, then place an outgoing call to the last number dialed on the
987        Implementation Under Test (IUT).
988        """
989
990        def enable_call():
991            time.sleep(2)
992            self.hfp.MakeCallAsHandsfree(connection=self.connection, number="123")
993
994        threading.Thread(target=enable_call).start()
995
996        return "OK"
997
998    @assert_description
999    def TSC_hf_disable_ecnr(self, **kwargs):
1000        """
1001        Using the Implemenation Under Test (IUT), disable  EC/NR, then click Ok.
1002        """
1003
1004        return "OK"
1005
1006    @assert_description
1007    def TSC_ag_iut_answer_call(self, **kwargs):
1008        """
1009        Click Ok, then answer the incoming call on the Implementation Under Test
1010        (IUT).
1011        """
1012
1013        self.hfp.AnswerCall()
1014
1015        return "OK"
1016
1017    @assert_description
1018    def TSC_verify_iut_ignore_wrong_bind(self, **kwargs):
1019        """
1020        Verify IUT ignores unkown or unexpected indication code. Then click OK.
1021        """
1022
1023        return "OK"
1024
1025    def _auto_confirm_requests(self, times=None):
1026
1027        def task():
1028            cnt = 0
1029            pairing_events = self.security.OnPairing()
1030            for event in pairing_events:
1031                if event.WhichOneof("method") in {"just_works", "numeric_comparison"}:
1032                    if times is None or cnt < times:
1033                        cnt += 1
1034                        pairing_events.send(PairingEventAnswer(event=event, confirm=True))
1035
1036        threading.Thread(target=task).start()
1037