• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#/usr/bin/env python3.4
2#
3# Copyright (C) 2016 The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License"); you may not
6# use this file except in compliance with the License. You may obtain a copy of
7# 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, WITHOUT
13# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14# License for the specific language governing permissions and limitations under
15# the License.
16
17"""
18Test the HFP profile for basic calling functionality.
19"""
20
21import time
22
23from acts.test_utils.bt.BluetoothBaseTest import BluetoothBaseTest
24from acts.test_utils.bt import BtEnum
25from acts.test_utils.bt import bt_test_utils
26from acts.test_utils.car import car_telecom_utils
27from acts.test_utils.tel import tel_defines
28
29BLUETOOTH_PKG_NAME = "com.android.bluetooth"
30CALL_TYPE_OUTGOING = "CALL_TYPE_OUTGOING"
31CALL_TYPE_INCOMING = "CALL_TYPE_INCOMING"
32default_timeout = 20
33
34class BtCarHfpTest(BluetoothBaseTest):
35    def setup_class(self):
36        self.hf = self.android_devices[0]
37        self.ag = self.android_devices[1]
38        self.re = self.android_devices[2]
39        self.ag_phone_number = "tel:{}".format(
40            self.ag.droid.telephonyGetLine1Number())
41        self.re_phone_number = "tel:{}".format(
42            self.re.droid.telephonyGetLine1Number())
43        self.log.info("ag tel: {} re tel: {}".format(
44            self.ag_phone_number, self.re_phone_number))
45
46        # Setup includes pairing and connecting the devices.
47        bt_test_utils.setup_multiple_devices_for_bt_test([self.hf, self.ag])
48        bt_test_utils.reset_bluetooth([self.hf, self.ag])
49
50        # Pair and connect the devices.
51        if not bt_test_utils.pair_pri_to_sec(self.hf.droid, self.ag.droid):
52            self.log.error("Failed to pair")
53            return False
54
55        # Connect the devices now, try twice.
56        attempts = 2
57        connected = False
58        while attempts > 0 and not connected:
59            connected = bt_test_utils.connect_pri_to_sec(
60                self.log, self.hf, self.ag.droid,
61                set([BtEnum.BluetoothProfile.HEADSET_CLIENT.value]))
62            self.log.info("Connected {}".format(connected))
63            attempts -= 1
64        return connected
65
66    def setup_test(self):
67        # Reset the devices.
68        for d in self.android_devices:
69            d.ed.clear_all_events()
70
71    def on_fail(self, test_name, begin_time):
72        self.log.debug("Test {} failed.".format(test_name))
73
74    @BluetoothBaseTest.bt_test_wrap
75    def test_default_calling_account(self):
76        """
77        Tests if the default calling account is coming from the
78        bluetooth pacakge.
79
80        Precondition:
81        1. Devices are connected.
82
83        Steps:
84        1. Check if the default calling account is via Bluetooth package.
85
86        Returns:
87          Pass if True
88          Fail if False
89
90        Priority: 0
91        """
92        selected_acc = \
93            self.hf.droid.telecomGetUserSelectedOutgoingPhoneAccount()
94        if not selected_acc:
95            self.log.info("No default account found.")
96            return False
97
98        # Check if the default account is from the Bluetooth package. This is a
99        # light weight check.
100        try:
101            acc_component_id = selected_acc['ComponentName']
102        except KeyError:
103            self.log.info(
104                "No component name for account {}".format(selected_acc))
105            return False
106        if not acc_component_id.startswith(BLUETOOTH_PKG_NAME):
107            self.log.info(
108                "Component name does not start with pkg name {}".format(
109                    selected_acc))
110            return False
111
112    @BluetoothBaseTest.bt_test_wrap
113    def test_outgoing_call_hf(self):
114        """
115        Tests if we can make a phone call from HF role and disconnect from HF
116        role.
117
118        Precondition:
119        1. Devices are connected.
120
121        Steps:
122        1. Make a call from HF role.
123        2. Wait for the HF, AG to be dialing and RE to see the call ringing.
124        3. Hangup the call on HF role.
125        4. Wait for all devices to hangup the call.
126
127        Returns:
128          Pass if True
129          Fail if False
130
131        Priority: 0
132        """
133        return self.dial_a_hangup_b(self.hf, self.hf)
134
135
136    @BluetoothBaseTest.bt_test_wrap
137    def test_outgoing_call_ag(self):
138        """
139        Tests if we can make a phone call from AG role and disconnect from AG
140        role.
141
142        Precondition:
143        1. Devices are connected.
144
145        Steps:
146        1. Make a call from AG role.
147        2. Wait for the HF, AG to be in dialing and RE to see the call ringing.
148        3. Hangup the call on AG role.
149        4. Wait for all devices to hangup the call.
150
151        Returns:
152          Pass if True
153          Fail if False
154
155        Priority: 0
156        """
157        return self.dial_a_hangup_b(self.ag, self.ag)
158
159    @BluetoothBaseTest.bt_test_wrap
160    def test_outgoing_dial_ag_hangup_hf(self):
161        """
162        Tests if we can make a phone call from AG role and disconnect from HF
163        role.
164
165        Precondition:
166        1. Devices are connected.
167
168        Steps:
169        1. Make a call from AG role.
170        2. Wait for the HF, AG to show dialing and RE to see the call ringing.
171        3. Hangup the call on HF role.
172        4. Wait for all devices to hangup the call.
173
174        Returns:
175          Pass if True
176          Fail if False
177
178        Priority: 0
179        """
180        return self.dial_a_hangup_b(self.ag, self.hf)
181
182    @BluetoothBaseTest.bt_test_wrap
183    def test_outgoing_dial_hf_hangup_ag(self):
184        """
185        Tests if we can make a phone call from HF role and disconnect from AG
186        role.
187
188        Precondition:
189        1. Devices are connected.
190
191        Steps:
192        1. Make a call from HF role.
193        2. Wait for the HF, AG to show dialing and RE to see the call ringing.
194        3. Hangup the call on AG role.
195        4. Wait for all devices to hangup the call.
196
197        Returns:
198          Pass if True
199          Fail if False
200
201        Priority: 0
202        """
203        return self.dial_a_hangup_b(self.hf, self.ag)
204
205    @BluetoothBaseTest.bt_test_wrap
206    def test_incoming_dial_re_hangup_re(self):
207        """
208        Tests if we can make a phone call from remote and disconnect from
209        remote.
210
211        Precondition:
212        1. Devices are connected.
213
214        Steps:
215        1. Make a call from RE role.
216        2. Wait for the HF, AG to show ringing and RE to see the call dialing.
217        3. Hangup the call on RE role.
218        4. Wait for all devices to hangup the call.
219
220        Returns:
221          Pass if True
222          Fail if False
223
224        Priority: 0
225        """
226        return self.dial_a_hangup_b(self.re, self.re, self.ag_phone_number)
227
228    def dial_a_hangup_b(self, a, b, ph=""):
229        """
230        a, b and c can be either of AG, HF or Remote.
231        1. Make a call from 'a' on a fixed number.
232        2. Wait for the call to get connected (check on both 'a' and 'b')
233           Check that 'c' is in ringing state.
234        3. Hangup the call on 'b'.
235        4. Wait for call to get completely disconnected
236        (check on both 'a' and 'b')
237        It is assumed that scenarios will not go into voice mail.
238        """
239        if ph == "": ph = self.re_phone_number
240
241        # Determine if this is outgoing or incoming call.
242        call_type = None
243        if a == self.ag or a == self.hf:
244            call_type = CALL_TYPE_OUTGOING
245            if b != self.ag and b != self.hf:
246                self.log.info("outgoing call should terminate at AG or HF")
247                return False
248        elif a == self.re:
249            call_type = CALL_TYPE_INCOMING
250            if b != self.re:
251                self.log.info("Incoming call should terminate at Re")
252                return False
253
254        self.log.info("Call type is {}".format(call_type))
255
256        # make a call on 'a'
257        if not car_telecom_utils.dial_number(self.log, a, ph):
258            return False
259
260        # Check that everyone is in dialing/ringing state.
261        ret = True
262        if call_type == CALL_TYPE_OUTGOING:
263            ret &= car_telecom_utils.wait_for_dialing(self.log, self.hf)
264            ret &= car_telecom_utils.wait_for_dialing(self.log, self.ag)
265            ret &= car_telecom_utils.wait_for_ringing(self.log, self.re)
266        else:
267            ret &= car_telecom_utils.wait_for_ringing(self.log, self.hf)
268            ret &= car_telecom_utils.wait_for_ringing(self.log, self.ag)
269            ret &= car_telecom_utils.wait_for_dialing(self.log, self.re)
270        if not ret:
271            return False
272
273        # Check if we have any calls with dialing or active state on 'b'.
274        # We assume we never disconnect from 'ringing' state since it will lead
275        # to voicemail.
276        call_state_dialing_or_active = \
277            [tel_defines.CALL_STATE_CONNECTING,
278             tel_defines.CALL_STATE_DIALING,
279             tel_defines.CALL_STATE_ACTIVE]
280
281        calls_in_dialing_or_active = car_telecom_utils.get_calls_in_states(
282            self.log, b, call_state_dialing_or_active)
283
284        # Make sure there is only one!
285        if len(calls_in_dialing_or_active) != 1:
286            self.log.info("Call State in dialing or active failed {}".format(
287                calls_in_dialing_or_active))
288            return False
289
290        # Hangup the *only* call on 'b'
291        if not car_telecom_utils.hangup_call(
292            self.log, b, calls_in_dialing_or_active[0]):
293            return False
294
295        # Make sure everyone got out of in call state.
296        for d in self.android_devices:
297            ret &= car_telecom_utils.wait_for_not_in_call(self.log, d)
298        return ret
299