xref: /aosp_15_r20/external/autotest/server/cros/bluetooth/bluetooth_device.py (revision 9c5db1993ded3edbeafc8092d69fe5de2ee02df7)
1*9c5db199SXin Li# Lint as: python2, python3
2*9c5db199SXin Li# Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
3*9c5db199SXin Li# Use of this source code is governed by a BSD-style license that can be
4*9c5db199SXin Li# found in the LICENSE file.
5*9c5db199SXin Li
6*9c5db199SXin Lifrom __future__ import absolute_import
7*9c5db199SXin Li
8*9c5db199SXin Liimport base64
9*9c5db199SXin Liimport functools
10*9c5db199SXin Liimport json
11*9c5db199SXin Liimport logging
12*9c5db199SXin Liimport threading
13*9c5db199SXin Lifrom datetime import datetime
14*9c5db199SXin Li
15*9c5db199SXin Liimport common
16*9c5db199SXin Lifrom autotest_lib.client.bin import utils
17*9c5db199SXin Lifrom autotest_lib.client.cros import constants
18*9c5db199SXin Lifrom autotest_lib.server import autotest
19*9c5db199SXin Li
20*9c5db199SXin Lidef proxy_thread_safe(method):
21*9c5db199SXin Li    """A decorator enabling thread-safe XmlRpc calls"""
22*9c5db199SXin Li
23*9c5db199SXin Li    @functools.wraps(method)
24*9c5db199SXin Li    def wrapper(self, *args, **kwargs):
25*9c5db199SXin Li        """A wrapper of the decorated method"""
26*9c5db199SXin Li        with self._proxy_lock:
27*9c5db199SXin Li            return method(self, *args, **kwargs)
28*9c5db199SXin Li
29*9c5db199SXin Li    return wrapper
30*9c5db199SXin Li
31*9c5db199SXin Li
32*9c5db199SXin Liclass BluetoothDevice(object):
33*9c5db199SXin Li    """BluetoothDevice is a thin layer of logic over a remote DUT.
34*9c5db199SXin Li
35*9c5db199SXin Li    The Autotest host object representing the remote DUT, passed to this
36*9c5db199SXin Li    class on initialization, can be accessed from its host property.
37*9c5db199SXin Li
38*9c5db199SXin Li    """
39*9c5db199SXin Li
40*9c5db199SXin Li    XMLRPC_BRINGUP_TIMEOUT_SECONDS = 60
41*9c5db199SXin Li    XMLRPC_LOG_PATH = '/var/log/bluetooth_xmlrpc_device.log'
42*9c5db199SXin Li    XMLRPC_REQUEST_TIMEOUT_SECONDS = 180
43*9c5db199SXin Li
44*9c5db199SXin Li    # We currently get dates back in string format due to some inconsistencies
45*9c5db199SXin Li    # between python2 and python3. This is the standard date format we use.
46*9c5db199SXin Li    STANDARD_DATE_FORMAT = '%Y-%m-%d %H:%M:%S.%f'
47*9c5db199SXin Li
48*9c5db199SXin Li    def __init__(self, device_host, remote_facade_proxy=None, floss=False):
49*9c5db199SXin Li        """Construct a BluetoothDevice.
50*9c5db199SXin Li
51*9c5db199SXin Li        @param device_host: host object representing a remote host.
52*9c5db199SXin Li
53*9c5db199SXin Li        """
54*9c5db199SXin Li        self.host = device_host
55*9c5db199SXin Li        self.floss = floss
56*9c5db199SXin Li        self._remote_proxy = remote_facade_proxy
57*9c5db199SXin Li
58*9c5db199SXin Li        # Make sure the client library is on the device so that the proxy code
59*9c5db199SXin Li        # is there when we try to call it.
60*9c5db199SXin Li        client_at = autotest.Autotest(self.host)
61*9c5db199SXin Li        client_at.install()
62*9c5db199SXin Li        self._proxy_lock = threading.Lock()
63*9c5db199SXin Li
64*9c5db199SXin Li        # Assign the correct _proxy based on the remote facade
65*9c5db199SXin Li        if self._remote_proxy:
66*9c5db199SXin Li            if self.floss:
67*9c5db199SXin Li                self._proxy = self._remote_proxy.floss
68*9c5db199SXin Li            else:
69*9c5db199SXin Li                self._proxy = self._remote_proxy.bluetooth
70*9c5db199SXin Li        else:
71*9c5db199SXin Li            # If remote facade wasn't already created, connect directly here
72*9c5db199SXin Li            self._proxy = self._connect_xmlrpc_directly()
73*9c5db199SXin Li
74*9c5db199SXin Li    def __getattr__(self, name):
75*9c5db199SXin Li        """Override default attribute behavior to call proxy methods.
76*9c5db199SXin Li
77*9c5db199SXin Li        To remove duplicate code in this class, we allow methods in the proxy
78*9c5db199SXin Li        class to be called directly from the bluetooth device class. If an
79*9c5db199SXin Li        attribute is contained within this class, we return it. Otherwise, if
80*9c5db199SXin Li        the proxy object contains a callable attribute of that name, we return a
81*9c5db199SXin Li        function that calls that object when invoked.
82*9c5db199SXin Li
83*9c5db199SXin Li        All methods called on the proxy in this way will hold the proxy lock.
84*9c5db199SXin Li        """
85*9c5db199SXin Li        try:
86*9c5db199SXin Li            return object.__getattr__(self, name)
87*9c5db199SXin Li        except AttributeError as ae:
88*9c5db199SXin Li            pass
89*9c5db199SXin Li
90*9c5db199SXin Li        # We only return proxied methods if no such attribute exists on this
91*9c5db199SXin Li        # class. Any attribute errors here will be raised at the end if attr
92*9c5db199SXin Li        # is None
93*9c5db199SXin Li        try:
94*9c5db199SXin Li            proxy = object.__getattribute__(self, '_proxy')
95*9c5db199SXin Li            proxy_lock = object.__getattribute__(self, '_proxy_lock')
96*9c5db199SXin Li            attr = proxy.__getattr__(name)
97*9c5db199SXin Li            if attr:
98*9c5db199SXin Li
99*9c5db199SXin Li                def wrapper(*args, **kwargs):
100*9c5db199SXin Li                    """Call target function while holding proxy lock."""
101*9c5db199SXin Li                    with proxy_lock:
102*9c5db199SXin Li                        return attr(*args, **kwargs)
103*9c5db199SXin Li
104*9c5db199SXin Li                return wrapper
105*9c5db199SXin Li        except AttributeError as ae:
106*9c5db199SXin Li            pass
107*9c5db199SXin Li
108*9c5db199SXin Li        # Couldn't find the attribute in either self or self._proxy.
109*9c5db199SXin Li        raise AttributeError('{} has no attribute: {}'.format(
110*9c5db199SXin Li                type(self).__name__, name))
111*9c5db199SXin Li
112*9c5db199SXin Li    def is_floss(self):
113*9c5db199SXin Li        """Is the current facade running Floss?"""
114*9c5db199SXin Li        return self.floss
115*9c5db199SXin Li
116*9c5db199SXin Li    def _connect_xmlrpc_directly(self):
117*9c5db199SXin Li        """Connects to the bluetooth facade directly via xmlrpc."""
118*9c5db199SXin Li        # When the xmlrpc server is already created (using the
119*9c5db199SXin Li        # RemoteFacadeFactory), we will use the BluezFacadeLocal inside the
120*9c5db199SXin Li        # remote proxy. Otherwise, we will use the xmlrpc server started from
121*9c5db199SXin Li        # this class. Currently, there are a few users outside of the Bluetooth
122*9c5db199SXin Li        # autotests that use this and this can be removed once those users
123*9c5db199SXin Li        # migrate to using the RemoteFacadeFactory to generate the xmlrpc
124*9c5db199SXin Li        # connection.
125*9c5db199SXin Li        proxy = self.host.rpc_server_tracker.xmlrpc_connect(
126*9c5db199SXin Li                constants.BLUETOOTH_DEVICE_XMLRPC_SERVER_COMMAND,
127*9c5db199SXin Li                constants.BLUETOOTH_DEVICE_XMLRPC_SERVER_PORT,
128*9c5db199SXin Li                command_name=constants.
129*9c5db199SXin Li                BLUETOOTH_DEVICE_XMLRPC_SERVER_CLEANUP_PATTERN,
130*9c5db199SXin Li                ready_test_name=constants.
131*9c5db199SXin Li                BLUETOOTH_DEVICE_XMLRPC_SERVER_READY_METHOD,
132*9c5db199SXin Li                timeout_seconds=self.XMLRPC_BRINGUP_TIMEOUT_SECONDS,
133*9c5db199SXin Li                logfile=self.XMLRPC_LOG_PATH,
134*9c5db199SXin Li                request_timeout_seconds=self.XMLRPC_REQUEST_TIMEOUT_SECONDS)
135*9c5db199SXin Li
136*9c5db199SXin Li        self._bt_direct_proxy = proxy
137*9c5db199SXin Li        return proxy
138*9c5db199SXin Li
139*9c5db199SXin Li    @property
140*9c5db199SXin Li    @proxy_thread_safe
141*9c5db199SXin Li    def address(self):
142*9c5db199SXin Li        """Get the adapter address."""
143*9c5db199SXin Li        return self._proxy.get_address()
144*9c5db199SXin Li
145*9c5db199SXin Li    @property
146*9c5db199SXin Li    @proxy_thread_safe
147*9c5db199SXin Li    def bluez_version(self):
148*9c5db199SXin Li        """Get the bluez version."""
149*9c5db199SXin Li        return self._proxy.get_bluez_version()
150*9c5db199SXin Li
151*9c5db199SXin Li    @property
152*9c5db199SXin Li    @proxy_thread_safe
153*9c5db199SXin Li    def bluetooth_class(self):
154*9c5db199SXin Li        """Get the bluetooth class."""
155*9c5db199SXin Li        return self._proxy.get_bluetooth_class()
156*9c5db199SXin Li
157*9c5db199SXin Li    @proxy_thread_safe
158*9c5db199SXin Li    def set_debug_log_levels(self, bluez_vb, kernel_vb):
159*9c5db199SXin Li        """Enable or disable the debug logs of bluetooth
160*9c5db199SXin Li
161*9c5db199SXin Li        @param bluez_vb: verbosity of bluez debug log, either 0 or 1
162*9c5db199SXin Li        @param kernel_vb: verbosity of kernel debug log, either 0 or 1
163*9c5db199SXin Li
164*9c5db199SXin Li        """
165*9c5db199SXin Li        return self._proxy.set_debug_log_levels(bluez_vb, kernel_vb)
166*9c5db199SXin Li
167*9c5db199SXin Li    @proxy_thread_safe
168*9c5db199SXin Li    def set_quality_debug_log(self, enable):
169*9c5db199SXin Li        """Enable or disable bluez quality debug log in the DUT
170*9c5db199SXin Li        @param enable: True to enable all of the debug log,
171*9c5db199SXin Li                       False to disable all of the debug log.
172*9c5db199SXin Li        """
173*9c5db199SXin Li        return self._proxy.set_quality_debug_log(enable)
174*9c5db199SXin Li
175*9c5db199SXin Li    @proxy_thread_safe
176*9c5db199SXin Li    def log_message(self, msg, dut=True, peer=True):
177*9c5db199SXin Li        """ Log a message in DUT log and peer logs with timestamp.
178*9c5db199SXin Li
179*9c5db199SXin Li        @param msg: message to be logged.
180*9c5db199SXin Li        @param dut: log message on DUT
181*9c5db199SXin Li        @param peer: log message on peer devices
182*9c5db199SXin Li        """
183*9c5db199SXin Li        try:
184*9c5db199SXin Li            # TODO(b/146671469) Implement logging to tester
185*9c5db199SXin Li
186*9c5db199SXin Li            date =  datetime.strftime(datetime.now(),"%Y:%m:%d %H:%M:%S:%f")
187*9c5db199SXin Li            msg = "bluetooth autotest --- %s : %s ---" % (date, msg)
188*9c5db199SXin Li            logging.debug("Broadcasting '%s'",msg)
189*9c5db199SXin Li
190*9c5db199SXin Li            if dut:
191*9c5db199SXin Li                self._proxy.log_message(msg)
192*9c5db199SXin Li
193*9c5db199SXin Li            if peer:
194*9c5db199SXin Li                for btpeer in self.host.btpeer_list:
195*9c5db199SXin Li                    btpeer.log_message(msg)
196*9c5db199SXin Li        except Exception as e:
197*9c5db199SXin Li            logging.error("Exception '%s' in log_message '%s'", str(e), msg)
198*9c5db199SXin Li
199*9c5db199SXin Li
200*9c5db199SXin Li    @proxy_thread_safe
201*9c5db199SXin Li    def is_wrt_supported(self):
202*9c5db199SXin Li        """ Check if Bluetooth adapter support WRT logs.
203*9c5db199SXin Li
204*9c5db199SXin Li        Intel adapter support WRT (except of WP2 and StP2)
205*9c5db199SXin Li
206*9c5db199SXin Li        @returns: True if adapter support WRT logs
207*9c5db199SXin Li        """
208*9c5db199SXin Li        return self._proxy.is_wrt_supported()
209*9c5db199SXin Li
210*9c5db199SXin Li
211*9c5db199SXin Li    @proxy_thread_safe
212*9c5db199SXin Li    def enable_wrt_logs(self):
213*9c5db199SXin Li        """Enable wrt logs on Intel adapters."""
214*9c5db199SXin Li        return self._proxy.enable_wrt_logs()
215*9c5db199SXin Li
216*9c5db199SXin Li
217*9c5db199SXin Li    @proxy_thread_safe
218*9c5db199SXin Li    def collect_wrt_logs(self):
219*9c5db199SXin Li        """Collect wrt logs on Intel adapters."""
220*9c5db199SXin Li        return self._proxy.collect_wrt_logs()
221*9c5db199SXin Li
222*9c5db199SXin Li
223*9c5db199SXin Li    @proxy_thread_safe
224*9c5db199SXin Li    def start_bluetoothd(self):
225*9c5db199SXin Li        """start bluetoothd.
226*9c5db199SXin Li
227*9c5db199SXin Li        @returns: True if bluetoothd is started correctly.
228*9c5db199SXin Li                  False otherwise.
229*9c5db199SXin Li
230*9c5db199SXin Li        """
231*9c5db199SXin Li        return self._proxy.start_bluetoothd()
232*9c5db199SXin Li
233*9c5db199SXin Li
234*9c5db199SXin Li    @proxy_thread_safe
235*9c5db199SXin Li    def stop_bluetoothd(self):
236*9c5db199SXin Li        """stop bluetoothd.
237*9c5db199SXin Li
238*9c5db199SXin Li        @returns: True if bluetoothd is stopped correctly.
239*9c5db199SXin Li                  False otherwise.
240*9c5db199SXin Li
241*9c5db199SXin Li        """
242*9c5db199SXin Li        return self._proxy.stop_bluetoothd()
243*9c5db199SXin Li
244*9c5db199SXin Li
245*9c5db199SXin Li    @proxy_thread_safe
246*9c5db199SXin Li    def is_bluetoothd_running(self):
247*9c5db199SXin Li        """Is bluetoothd running?
248*9c5db199SXin Li
249*9c5db199SXin Li        @returns: True if bluetoothd is running
250*9c5db199SXin Li
251*9c5db199SXin Li        """
252*9c5db199SXin Li        return self._proxy.is_bluetoothd_running()
253*9c5db199SXin Li
254*9c5db199SXin Li
255*9c5db199SXin Li    @proxy_thread_safe
256*9c5db199SXin Li    def is_bluetoothd_valid(self):
257*9c5db199SXin Li        """Checks whether the current bluetoothd session is ok.
258*9c5db199SXin Li
259*9c5db199SXin Li        Returns:
260*9c5db199SXin Li            True if the current bluetoothd session is ok. False if bluetoothd is
261*9c5db199SXin Li            not running or it is a new session.
262*9c5db199SXin Li        """
263*9c5db199SXin Li        return self._proxy.is_bluetoothd_proxy_valid()
264*9c5db199SXin Li
265*9c5db199SXin Li    @proxy_thread_safe
266*9c5db199SXin Li    def has_adapter(self):
267*9c5db199SXin Li        """@return True if an adapter is present, False if not."""
268*9c5db199SXin Li        return self._proxy.has_adapter()
269*9c5db199SXin Li
270*9c5db199SXin Li
271*9c5db199SXin Li    @proxy_thread_safe
272*9c5db199SXin Li    def is_wake_enabled(self):
273*9c5db199SXin Li        """@return True if adapter is wake enabled, False if not."""
274*9c5db199SXin Li        return self._proxy.is_wake_enabled()
275*9c5db199SXin Li
276*9c5db199SXin Li
277*9c5db199SXin Li    @proxy_thread_safe
278*9c5db199SXin Li    def set_wake_enabled(self, value):
279*9c5db199SXin Li        """ Sets the power/wakeup value for the adapter.
280*9c5db199SXin Li
281*9c5db199SXin Li        Args:
282*9c5db199SXin Li            value: Whether the adapter can wake from suspend
283*9c5db199SXin Li
284*9c5db199SXin Li        @return True if able to set it to value, False if not."""
285*9c5db199SXin Li        return self._proxy.set_wake_enabled(value)
286*9c5db199SXin Li
287*9c5db199SXin Li
288*9c5db199SXin Li    def get_hci(self):
289*9c5db199SXin Li        """Get hci of the adapter; normally, it is 'hci0'.
290*9c5db199SXin Li
291*9c5db199SXin Li        @returns: the hci name of the adapter.
292*9c5db199SXin Li
293*9c5db199SXin Li        """
294*9c5db199SXin Li        dev_info = self.get_dev_info()
295*9c5db199SXin Li        hci = (dev_info[1] if isinstance(dev_info, list) and
296*9c5db199SXin Li               len(dev_info) > 1 else None)
297*9c5db199SXin Li        return hci
298*9c5db199SXin Li
299*9c5db199SXin Li
300*9c5db199SXin Li    def get_UUIDs(self):
301*9c5db199SXin Li        """Get the UUIDs.
302*9c5db199SXin Li
303*9c5db199SXin Li        The UUIDs can be dynamically changed at run time due to adapter/CRAS
304*9c5db199SXin Li        services availability. Therefore, always query them from the adapter,
305*9c5db199SXin Li        not from the cache.
306*9c5db199SXin Li
307*9c5db199SXin Li        An example of UUIDs:
308*9c5db199SXin Li            [u'00001112-0000-1000-8000-00805f9b34fb',
309*9c5db199SXin Li             u'00001801-0000-1000-8000-00805f9b34fb',
310*9c5db199SXin Li             u'0000110a-0000-1000-8000-00805f9b34fb',
311*9c5db199SXin Li             u'0000111f-0000-1000-8000-00805f9b34fb',
312*9c5db199SXin Li             u'00001200-0000-1000-8000-00805f9b34fb',
313*9c5db199SXin Li             u'00001800-0000-1000-8000-00805f9b34fb']
314*9c5db199SXin Li
315*9c5db199SXin Li        @returns: the list of the UUIDs.
316*9c5db199SXin Li
317*9c5db199SXin Li        """
318*9c5db199SXin Li        properties = self.get_adapter_properties()
319*9c5db199SXin Li        return properties.get('UUIDs')
320*9c5db199SXin Li
321*9c5db199SXin Li
322*9c5db199SXin Li    @proxy_thread_safe
323*9c5db199SXin Li    def set_pairable_timeout(self, pairable_timeout):
324*9c5db199SXin Li        """Set the adapter PairableTimeout.
325*9c5db199SXin Li
326*9c5db199SXin Li        @param pairable_timeout: adapter PairableTimeout
327*9c5db199SXin Li                value to set in seconds (Integer).
328*9c5db199SXin Li
329*9c5db199SXin Li        @return True on success, False otherwise.
330*9c5db199SXin Li
331*9c5db199SXin Li        """
332*9c5db199SXin Li        return self._proxy.set_pairable_timeout(pairable_timeout)
333*9c5db199SXin Li
334*9c5db199SXin Li
335*9c5db199SXin Li    @proxy_thread_safe
336*9c5db199SXin Li    def get_pairable_timeout(self):
337*9c5db199SXin Li        """Get the adapter PairableTimeout.
338*9c5db199SXin Li
339*9c5db199SXin Li        @return Value of property PairableTimeout in seconds (Integer).
340*9c5db199SXin Li
341*9c5db199SXin Li        """
342*9c5db199SXin Li        return self._proxy.get_pairable_timeout()
343*9c5db199SXin Li
344*9c5db199SXin Li
345*9c5db199SXin Li    @proxy_thread_safe
346*9c5db199SXin Li    def set_pairable(self, pairable):
347*9c5db199SXin Li        """Set the adapter pairable state.
348*9c5db199SXin Li
349*9c5db199SXin Li        @param pairable: adapter pairable state to set (True or False).
350*9c5db199SXin Li
351*9c5db199SXin Li        @return True on success, False otherwise.
352*9c5db199SXin Li
353*9c5db199SXin Li        """
354*9c5db199SXin Li        return self._proxy.set_pairable(pairable)
355*9c5db199SXin Li
356*9c5db199SXin Li
357*9c5db199SXin Li    @proxy_thread_safe
358*9c5db199SXin Li    def is_pairable(self):
359*9c5db199SXin Li        """Is the adapter in the pairable state?
360*9c5db199SXin Li
361*9c5db199SXin Li        @return True if pairable. False otherwise.
362*9c5db199SXin Li
363*9c5db199SXin Li        """
364*9c5db199SXin Li        return self._proxy.get_pairable()
365*9c5db199SXin Li
366*9c5db199SXin Li    @proxy_thread_safe
367*9c5db199SXin Li    def set_adapter_alias(self, alias):
368*9c5db199SXin Li        """Set the adapter alias.
369*9c5db199SXin Li
370*9c5db199SXin Li        A note on Alias property - providing an empty string ('') will reset the
371*9c5db199SXin Li        Alias property to the system default
372*9c5db199SXin Li
373*9c5db199SXin Li        @param alias: adapter alias to set with type String
374*9c5db199SXin Li
375*9c5db199SXin Li        @return True on success, False otherwise.
376*9c5db199SXin Li        """
377*9c5db199SXin Li
378*9c5db199SXin Li        return self._proxy.set_adapter_alias(alias)
379*9c5db199SXin Li
380*9c5db199SXin Li    @proxy_thread_safe
381*9c5db199SXin Li    def get_adapter_properties(self):
382*9c5db199SXin Li        """Read the adapter properties from the Bluetooth Daemon.
383*9c5db199SXin Li
384*9c5db199SXin Li        An example of the adapter properties looks like
385*9c5db199SXin Li        {u'Name': u'BlueZ 5.35',
386*9c5db199SXin Li         u'Alias': u'Chromebook',
387*9c5db199SXin Li         u'Modalias': u'bluetooth:v00E0p2436d0400',
388*9c5db199SXin Li         u'Powered': 1,
389*9c5db199SXin Li         u'DiscoverableTimeout': 180,
390*9c5db199SXin Li         u'PairableTimeout': 0,
391*9c5db199SXin Li         u'Discoverable': 0,
392*9c5db199SXin Li         u'Address': u'6C:29:95:1A:D4:6F',
393*9c5db199SXin Li         u'Discovering': 0,
394*9c5db199SXin Li         u'Pairable': 1,
395*9c5db199SXin Li         u'Class': 4718852,
396*9c5db199SXin Li         u'UUIDs': [u'00001112-0000-1000-8000-00805f9b34fb',
397*9c5db199SXin Li                    u'00001801-0000-1000-8000-00805f9b34fb',
398*9c5db199SXin Li                    u'0000110a-0000-1000-8000-00805f9b34fb',
399*9c5db199SXin Li                    u'0000111f-0000-1000-8000-00805f9b34fb',
400*9c5db199SXin Li                    u'00001200-0000-1000-8000-00805f9b34fb',
401*9c5db199SXin Li                    u'00001800-0000-1000-8000-00805f9b34fb']}
402*9c5db199SXin Li
403*9c5db199SXin Li        @return the properties as a dictionary on success,
404*9c5db199SXin Li            the value False otherwise.
405*9c5db199SXin Li
406*9c5db199SXin Li        """
407*9c5db199SXin Li        return json.loads(self._proxy.get_adapter_properties())
408*9c5db199SXin Li
409*9c5db199SXin Li
410*9c5db199SXin Li    @proxy_thread_safe
411*9c5db199SXin Li    def read_version(self):
412*9c5db199SXin Li        """Read the version of the management interface from the Kernel.
413*9c5db199SXin Li
414*9c5db199SXin Li        @return the version as a tuple of:
415*9c5db199SXin Li          ( version, revision )
416*9c5db199SXin Li
417*9c5db199SXin Li        """
418*9c5db199SXin Li        return json.loads(self._proxy.read_version())
419*9c5db199SXin Li
420*9c5db199SXin Li
421*9c5db199SXin Li    @proxy_thread_safe
422*9c5db199SXin Li    def read_supported_commands(self):
423*9c5db199SXin Li        """Read the set of supported commands from the Kernel.
424*9c5db199SXin Li
425*9c5db199SXin Li        @return set of supported commands as arrays in a tuple of:
426*9c5db199SXin Li          ( commands, events )
427*9c5db199SXin Li
428*9c5db199SXin Li        """
429*9c5db199SXin Li        return json.loads(self._proxy.read_supported_commands())
430*9c5db199SXin Li
431*9c5db199SXin Li
432*9c5db199SXin Li    @proxy_thread_safe
433*9c5db199SXin Li    def read_index_list(self):
434*9c5db199SXin Li        """Read the list of currently known controllers from the Kernel.
435*9c5db199SXin Li
436*9c5db199SXin Li        @return array of controller indexes.
437*9c5db199SXin Li
438*9c5db199SXin Li        """
439*9c5db199SXin Li        return json.loads(self._proxy.read_index_list())
440*9c5db199SXin Li
441*9c5db199SXin Li
442*9c5db199SXin Li    @proxy_thread_safe
443*9c5db199SXin Li    def read_info(self):
444*9c5db199SXin Li        """Read the adapter information from the Kernel.
445*9c5db199SXin Li
446*9c5db199SXin Li        An example of the adapter information looks like
447*9c5db199SXin Li        [u'6C:29:95:1A:D4:6F', 6, 2, 65535, 2769, 4718852, u'Chromebook', u'']
448*9c5db199SXin Li
449*9c5db199SXin Li        @return the information as a tuple of:
450*9c5db199SXin Li          ( address, bluetooth_version, manufacturer_id,
451*9c5db199SXin Li            supported_settings, current_settings, class_of_device,
452*9c5db199SXin Li            name, short_name )
453*9c5db199SXin Li
454*9c5db199SXin Li        """
455*9c5db199SXin Li        return json.loads(self._proxy.read_info())
456*9c5db199SXin Li
457*9c5db199SXin Li
458*9c5db199SXin Li    @proxy_thread_safe
459*9c5db199SXin Li    def add_device(self, address, address_type, action):
460*9c5db199SXin Li        """Add a device to the Kernel action list.
461*9c5db199SXin Li
462*9c5db199SXin Li        @param address: Address of the device to add.
463*9c5db199SXin Li        @param address_type: Type of device in @address.
464*9c5db199SXin Li        @param action: Action to take.
465*9c5db199SXin Li
466*9c5db199SXin Li        @return tuple of ( address, address_type ) on success,
467*9c5db199SXin Li          None on failure.
468*9c5db199SXin Li
469*9c5db199SXin Li        """
470*9c5db199SXin Li        return json.loads(self._proxy.add_device(address, address_type, action))
471*9c5db199SXin Li
472*9c5db199SXin Li
473*9c5db199SXin Li    @proxy_thread_safe
474*9c5db199SXin Li    def remove_device(self, address, address_type):
475*9c5db199SXin Li        """Remove a device from the Kernel action list.
476*9c5db199SXin Li
477*9c5db199SXin Li        @param address: Address of the device to remove.
478*9c5db199SXin Li        @param address_type: Type of device in @address.
479*9c5db199SXin Li
480*9c5db199SXin Li        @return tuple of ( address, address_type ) on success,
481*9c5db199SXin Li          None on failure.
482*9c5db199SXin Li
483*9c5db199SXin Li        """
484*9c5db199SXin Li        return json.loads(self._proxy.remove_device(address, address_type))
485*9c5db199SXin Li
486*9c5db199SXin Li    def _decode_json_base64(self, data):
487*9c5db199SXin Li        """Load serialized JSON and then base64 decode it
488*9c5db199SXin Li
489*9c5db199SXin Li        Required to handle non-ascii data
490*9c5db199SXin Li        @param data: data to be JSON and base64 decode
491*9c5db199SXin Li
492*9c5db199SXin Li        @return : JSON and base64 decoded data
493*9c5db199SXin Li
494*9c5db199SXin Li
495*9c5db199SXin Li        """
496*9c5db199SXin Li        logging.debug("_decode_json_base64 raw data is %s", data)
497*9c5db199SXin Li        json_encoded = json.loads(data)
498*9c5db199SXin Li        logging.debug("JSON encoded data is %s", json_encoded)
499*9c5db199SXin Li        base64_decoded = utils.base64_recursive_decode(json_encoded)
500*9c5db199SXin Li        logging.debug("base64 decoded data is %s", base64_decoded)
501*9c5db199SXin Li        return base64_decoded
502*9c5db199SXin Li
503*9c5db199SXin Li
504*9c5db199SXin Li    @proxy_thread_safe
505*9c5db199SXin Li    def get_devices(self):
506*9c5db199SXin Li        """Read information about remote devices known to the adapter.
507*9c5db199SXin Li
508*9c5db199SXin Li        An example of the device information of RN-42 looks like
509*9c5db199SXin Li        [{u'Name': u'RNBT-A96F',
510*9c5db199SXin Li          u'Alias': u'RNBT-A96F',
511*9c5db199SXin Li          u'Adapter': u'/org/bluez/hci0',
512*9c5db199SXin Li          u'LegacyPairing': 0,
513*9c5db199SXin Li          u'Paired': 1,
514*9c5db199SXin Li          u'Connected': 0,
515*9c5db199SXin Li          u'UUIDs': [u'00001124-0000-1000-8000-00805f9b34fb'],
516*9c5db199SXin Li          u'Address': u'00:06:66:75:A9:6F',
517*9c5db199SXin Li          u'Icon': u'input-mouse',
518*9c5db199SXin Li          u'Class': 1408,
519*9c5db199SXin Li          u'Trusted': 1,
520*9c5db199SXin Li          u'Blocked': 0}]
521*9c5db199SXin Li
522*9c5db199SXin Li        @return the properties of each device as an array of
523*9c5db199SXin Li            dictionaries on success, the value False otherwise.
524*9c5db199SXin Li
525*9c5db199SXin Li        """
526*9c5db199SXin Li        return json.loads(self._proxy.get_devices())
527*9c5db199SXin Li
528*9c5db199SXin Li
529*9c5db199SXin Li    @proxy_thread_safe
530*9c5db199SXin Li    def get_device_property(self, address, prop_name):
531*9c5db199SXin Li        """Read a property of BT device by directly querying device dbus object
532*9c5db199SXin Li
533*9c5db199SXin Li        @param address: Address of the device to query
534*9c5db199SXin Li        @param prop_name: Property to be queried
535*9c5db199SXin Li
536*9c5db199SXin Li        @return The property if device is found and has property, None otherwise
537*9c5db199SXin Li        """
538*9c5db199SXin Li
539*9c5db199SXin Li        prop_val = self._proxy.get_device_property(address, prop_name)
540*9c5db199SXin Li
541*9c5db199SXin Li        # Handle dbus error case returned by dbus_safe decorator
542*9c5db199SXin Li        if prop_val is None:
543*9c5db199SXin Li            return None
544*9c5db199SXin Li
545*9c5db199SXin Li        # Decode and return property value
546*9c5db199SXin Li        return json.loads(prop_val)
547*9c5db199SXin Li
548*9c5db199SXin Li
549*9c5db199SXin Li    @proxy_thread_safe
550*9c5db199SXin Li    def get_battery_property(self, address, prop_name):
551*9c5db199SXin Li        """Read a property of battery by directly querying the dbus object
552*9c5db199SXin Li
553*9c5db199SXin Li        @param address: Address of the device to query
554*9c5db199SXin Li        @param prop_name: Property to be queried
555*9c5db199SXin Li
556*9c5db199SXin Li        @return The property if battery is found and has property,
557*9c5db199SXin Li          None otherwise
558*9c5db199SXin Li        """
559*9c5db199SXin Li
560*9c5db199SXin Li        return self._proxy.get_battery_property(address, prop_name)
561*9c5db199SXin Li
562*9c5db199SXin Li    @proxy_thread_safe
563*9c5db199SXin Li    def get_dev_info(self):
564*9c5db199SXin Li        """Read raw HCI device information.
565*9c5db199SXin Li
566*9c5db199SXin Li        An example of the device information looks like:
567*9c5db199SXin Li        [0, u'hci0', u'6C:29:95:1A:D4:6F', 13, 0, 1, 581900950526, 52472, 7,
568*9c5db199SXin Li         32768, 1021, 5, 96, 6, 0, 0, 151, 151, 0, 0, 0, 0, 1968, 12507]
569*9c5db199SXin Li
570*9c5db199SXin Li        @return tuple of (index, name, address, flags, device_type, bus_type,
571*9c5db199SXin Li                       features, pkt_type, link_policy, link_mode,
572*9c5db199SXin Li                       acl_mtu, acl_pkts, sco_mtu, sco_pkts,
573*9c5db199SXin Li                       err_rx, err_tx, cmd_tx, evt_rx, acl_tx, acl_rx,
574*9c5db199SXin Li                       sco_tx, sco_rx, byte_rx, byte_tx) on success,
575*9c5db199SXin Li                None on failure.
576*9c5db199SXin Li
577*9c5db199SXin Li        """
578*9c5db199SXin Li        return json.loads(self._proxy.get_dev_info())
579*9c5db199SXin Li
580*9c5db199SXin Li
581*9c5db199SXin Li    @proxy_thread_safe
582*9c5db199SXin Li    def get_supported_capabilities(self):
583*9c5db199SXin Li        """ Get the supported_capabilities of the adapter
584*9c5db199SXin Li        @returns (capabilities,None) on success (None, <error>) on failure
585*9c5db199SXin Li        """
586*9c5db199SXin Li        capabilities, error = self._proxy.get_supported_capabilities()
587*9c5db199SXin Li        return (json.loads(capabilities), error)
588*9c5db199SXin Li
589*9c5db199SXin Li
590*9c5db199SXin Li    @proxy_thread_safe
591*9c5db199SXin Li    def register_profile(self, path, uuid, options):
592*9c5db199SXin Li        """Register new profile (service).
593*9c5db199SXin Li
594*9c5db199SXin Li        @param path: Path to the profile object.
595*9c5db199SXin Li        @param uuid: Service Class ID of the service as string.
596*9c5db199SXin Li        @param options: Dictionary of options for the new service, compliant
597*9c5db199SXin Li                        with BlueZ D-Bus Profile API standard.
598*9c5db199SXin Li
599*9c5db199SXin Li        @return True on success, False otherwise.
600*9c5db199SXin Li
601*9c5db199SXin Li        """
602*9c5db199SXin Li        return self._proxy.register_profile(path, uuid, options)
603*9c5db199SXin Li
604*9c5db199SXin Li
605*9c5db199SXin Li    @proxy_thread_safe
606*9c5db199SXin Li    def has_device(self, address):
607*9c5db199SXin Li        """Checks if the device with a given address exists.
608*9c5db199SXin Li
609*9c5db199SXin Li        @param address: Address of the device.
610*9c5db199SXin Li
611*9c5db199SXin Li        @returns: True if there is a device with that address.
612*9c5db199SXin Li                  False otherwise.
613*9c5db199SXin Li
614*9c5db199SXin Li        """
615*9c5db199SXin Li        return self._proxy.has_device(address)
616*9c5db199SXin Li
617*9c5db199SXin Li
618*9c5db199SXin Li    @proxy_thread_safe
619*9c5db199SXin Li    def device_is_paired(self, address):
620*9c5db199SXin Li        """Checks if a device is paired.
621*9c5db199SXin Li
622*9c5db199SXin Li        @param address: address of the device.
623*9c5db199SXin Li
624*9c5db199SXin Li        @returns: True if device is paired. False otherwise.
625*9c5db199SXin Li
626*9c5db199SXin Li        """
627*9c5db199SXin Li        return self._proxy.device_is_paired(address)
628*9c5db199SXin Li
629*9c5db199SXin Li
630*9c5db199SXin Li    @proxy_thread_safe
631*9c5db199SXin Li    def device_services_resolved(self, address):
632*9c5db199SXin Li        """Checks if services are resolved for a device.
633*9c5db199SXin Li
634*9c5db199SXin Li        @param address: address of the device.
635*9c5db199SXin Li
636*9c5db199SXin Li        @returns: True if services are resolved. False otherwise.
637*9c5db199SXin Li
638*9c5db199SXin Li        """
639*9c5db199SXin Li        return self._proxy.device_services_resolved(address)
640*9c5db199SXin Li
641*9c5db199SXin Li
642*9c5db199SXin Li    @proxy_thread_safe
643*9c5db199SXin Li    def set_trusted(self, address, trusted=True):
644*9c5db199SXin Li        """Set the device trusted.
645*9c5db199SXin Li
646*9c5db199SXin Li        @param address: The bluetooth address of the device.
647*9c5db199SXin Li        @param trusted: True or False indicating whether to set trusted or not.
648*9c5db199SXin Li
649*9c5db199SXin Li        @returns: True if successful. False otherwise.
650*9c5db199SXin Li
651*9c5db199SXin Li        """
652*9c5db199SXin Li        return self._proxy.set_trusted(address, trusted)
653*9c5db199SXin Li
654*9c5db199SXin Li
655*9c5db199SXin Li    @proxy_thread_safe
656*9c5db199SXin Li    def pair_legacy_device(self, address, pin, trusted, timeout):
657*9c5db199SXin Li        """Pairs a device with a given pin code.
658*9c5db199SXin Li
659*9c5db199SXin Li        Registers an agent who handles pin code request and
660*9c5db199SXin Li        pairs a device with known pin code.
661*9c5db199SXin Li
662*9c5db199SXin Li        @param address: Address of the device to pair.
663*9c5db199SXin Li        @param pin: The pin code of the device to pair.
664*9c5db199SXin Li        @param trusted: indicating whether to set the device trusted.
665*9c5db199SXin Li        @param timeout: The timeout in seconds for pairing.
666*9c5db199SXin Li
667*9c5db199SXin Li        @returns: True on success. False otherwise.
668*9c5db199SXin Li
669*9c5db199SXin Li        """
670*9c5db199SXin Li        return self._proxy.pair_legacy_device(address, pin, trusted, timeout)
671*9c5db199SXin Li
672*9c5db199SXin Li
673*9c5db199SXin Li    @proxy_thread_safe
674*9c5db199SXin Li    def remove_device_object(self, address):
675*9c5db199SXin Li        """Removes a device object and the pairing information.
676*9c5db199SXin Li
677*9c5db199SXin Li        Calls RemoveDevice method to remove remote device
678*9c5db199SXin Li        object and the pairing information.
679*9c5db199SXin Li
680*9c5db199SXin Li        @param address: address of the device to unpair.
681*9c5db199SXin Li
682*9c5db199SXin Li        @returns: True on success. False otherwise.
683*9c5db199SXin Li
684*9c5db199SXin Li        """
685*9c5db199SXin Li        return self._proxy.remove_device_object(address)
686*9c5db199SXin Li
687*9c5db199SXin Li
688*9c5db199SXin Li    @proxy_thread_safe
689*9c5db199SXin Li    def connect_device(self, address):
690*9c5db199SXin Li        """Connects a device.
691*9c5db199SXin Li
692*9c5db199SXin Li        Connects a device if it is not connected.
693*9c5db199SXin Li
694*9c5db199SXin Li        @param address: Address of the device to connect.
695*9c5db199SXin Li
696*9c5db199SXin Li        @returns: True on success. False otherwise.
697*9c5db199SXin Li
698*9c5db199SXin Li        """
699*9c5db199SXin Li        return self._proxy.connect_device(address)
700*9c5db199SXin Li
701*9c5db199SXin Li
702*9c5db199SXin Li    @proxy_thread_safe
703*9c5db199SXin Li    def device_is_connected(self, address):
704*9c5db199SXin Li        """Checks if a device is connected.
705*9c5db199SXin Li
706*9c5db199SXin Li        @param address: Address of the device to check if it is connected.
707*9c5db199SXin Li
708*9c5db199SXin Li        @returns: True if device is connected. False otherwise.
709*9c5db199SXin Li
710*9c5db199SXin Li        """
711*9c5db199SXin Li        return self._proxy.device_is_connected(address)
712*9c5db199SXin Li
713*9c5db199SXin Li
714*9c5db199SXin Li    @proxy_thread_safe
715*9c5db199SXin Li    def disconnect_device(self, address):
716*9c5db199SXin Li        """Disconnects a device.
717*9c5db199SXin Li
718*9c5db199SXin Li        Disconnects a device if it is connected.
719*9c5db199SXin Li
720*9c5db199SXin Li        @param address: Address of the device to disconnect.
721*9c5db199SXin Li
722*9c5db199SXin Li        @returns: True on success. False otherwise.
723*9c5db199SXin Li
724*9c5db199SXin Li        """
725*9c5db199SXin Li        return self._proxy.disconnect_device(address)
726*9c5db199SXin Li
727*9c5db199SXin Li
728*9c5db199SXin Li    @proxy_thread_safe
729*9c5db199SXin Li    def btmon_start(self):
730*9c5db199SXin Li        """Start btmon monitoring."""
731*9c5db199SXin Li        self._proxy.btmon_start()
732*9c5db199SXin Li
733*9c5db199SXin Li
734*9c5db199SXin Li    @proxy_thread_safe
735*9c5db199SXin Li    def btmon_stop(self):
736*9c5db199SXin Li        """Stop btmon monitoring."""
737*9c5db199SXin Li        self._proxy.btmon_stop()
738*9c5db199SXin Li
739*9c5db199SXin Li
740*9c5db199SXin Li    @proxy_thread_safe
741*9c5db199SXin Li    def btmon_get(self, search_str='', start_str=''):
742*9c5db199SXin Li        """Get btmon output contents.
743*9c5db199SXin Li
744*9c5db199SXin Li        @param search_str: only lines with search_str would be kept.
745*9c5db199SXin Li        @param start_str: all lines before the occurrence of start_str would be
746*9c5db199SXin Li                filtered.
747*9c5db199SXin Li
748*9c5db199SXin Li        @returns: the recorded btmon output.
749*9c5db199SXin Li
750*9c5db199SXin Li        """
751*9c5db199SXin Li        return self._proxy.btmon_get(search_str, start_str)
752*9c5db199SXin Li
753*9c5db199SXin Li
754*9c5db199SXin Li    @proxy_thread_safe
755*9c5db199SXin Li    def btmon_find(self, pattern_str):
756*9c5db199SXin Li        """Find if a pattern string exists in btmon output.
757*9c5db199SXin Li
758*9c5db199SXin Li        @param pattern_str: the pattern string to find.
759*9c5db199SXin Li
760*9c5db199SXin Li        @returns: True on success. False otherwise.
761*9c5db199SXin Li
762*9c5db199SXin Li        """
763*9c5db199SXin Li        return self._proxy.btmon_find(pattern_str)
764*9c5db199SXin Li
765*9c5db199SXin Li
766*9c5db199SXin Li    @proxy_thread_safe
767*9c5db199SXin Li    def advmon_check_manager_interface_exist(self):
768*9c5db199SXin Li        """Check if AdvertisementMonitorManager1 interface is available.
769*9c5db199SXin Li
770*9c5db199SXin Li        @returns: True if Manager interface is available, False otherwise.
771*9c5db199SXin Li
772*9c5db199SXin Li        """
773*9c5db199SXin Li        return self._proxy.advmon_check_manager_interface_exist()
774*9c5db199SXin Li
775*9c5db199SXin Li
776*9c5db199SXin Li    @proxy_thread_safe
777*9c5db199SXin Li    def advmon_read_supported_types(self):
778*9c5db199SXin Li        """Read the Advertisement Monitor supported monitor types.
779*9c5db199SXin Li
780*9c5db199SXin Li        @returns: List of supported advertisement monitor types.
781*9c5db199SXin Li
782*9c5db199SXin Li        """
783*9c5db199SXin Li        return self._proxy.advmon_read_supported_types()
784*9c5db199SXin Li
785*9c5db199SXin Li
786*9c5db199SXin Li    @proxy_thread_safe
787*9c5db199SXin Li    def advmon_read_supported_features(self):
788*9c5db199SXin Li        """Read the Advertisement Monitor supported features.
789*9c5db199SXin Li
790*9c5db199SXin Li        @returns: List of supported advertisement monitor features.
791*9c5db199SXin Li
792*9c5db199SXin Li        """
793*9c5db199SXin Li        return self._proxy.advmon_read_supported_features()
794*9c5db199SXin Li
795*9c5db199SXin Li
796*9c5db199SXin Li    @proxy_thread_safe
797*9c5db199SXin Li    def advmon_create_app(self):
798*9c5db199SXin Li        """Create an advertisement monitor app.
799*9c5db199SXin Li
800*9c5db199SXin Li        @returns: app id, once the app is created.
801*9c5db199SXin Li
802*9c5db199SXin Li        """
803*9c5db199SXin Li        return self._proxy.advmon_create_app()
804*9c5db199SXin Li
805*9c5db199SXin Li
806*9c5db199SXin Li    @proxy_thread_safe
807*9c5db199SXin Li    def advmon_exit_app(self, app_id):
808*9c5db199SXin Li        """Exit an advertisement monitor app.
809*9c5db199SXin Li
810*9c5db199SXin Li        @param app_id: the app id.
811*9c5db199SXin Li
812*9c5db199SXin Li        @returns: True on success, False otherwise.
813*9c5db199SXin Li
814*9c5db199SXin Li        """
815*9c5db199SXin Li        return self._proxy.advmon_exit_app(app_id)
816*9c5db199SXin Li
817*9c5db199SXin Li
818*9c5db199SXin Li    @proxy_thread_safe
819*9c5db199SXin Li    def advmon_kill_app(self, app_id):
820*9c5db199SXin Li        """Kill an advertisement monitor app by sending SIGKILL.
821*9c5db199SXin Li
822*9c5db199SXin Li        @param app_id: the app id.
823*9c5db199SXin Li
824*9c5db199SXin Li        @returns: True on success, False otherwise.
825*9c5db199SXin Li
826*9c5db199SXin Li        """
827*9c5db199SXin Li        return self._proxy.advmon_kill_app(app_id)
828*9c5db199SXin Li
829*9c5db199SXin Li
830*9c5db199SXin Li    @proxy_thread_safe
831*9c5db199SXin Li    def advmon_register_app(self, app_id):
832*9c5db199SXin Li        """Register an advertisement monitor app.
833*9c5db199SXin Li
834*9c5db199SXin Li        @param app_id: the app id.
835*9c5db199SXin Li
836*9c5db199SXin Li        @returns: True on success, False otherwise.
837*9c5db199SXin Li
838*9c5db199SXin Li        """
839*9c5db199SXin Li        return self._proxy.advmon_register_app(app_id)
840*9c5db199SXin Li
841*9c5db199SXin Li
842*9c5db199SXin Li    @proxy_thread_safe
843*9c5db199SXin Li    def advmon_unregister_app(self, app_id):
844*9c5db199SXin Li        """Unregister an advertisement monitor app.
845*9c5db199SXin Li
846*9c5db199SXin Li        @param app_id: the app id.
847*9c5db199SXin Li
848*9c5db199SXin Li        @returns: True on success, False otherwise.
849*9c5db199SXin Li
850*9c5db199SXin Li        """
851*9c5db199SXin Li        return self._proxy.advmon_unregister_app(app_id)
852*9c5db199SXin Li
853*9c5db199SXin Li
854*9c5db199SXin Li    @proxy_thread_safe
855*9c5db199SXin Li    def advmon_add_monitor(self, app_id, monitor_data):
856*9c5db199SXin Li        """Create an Advertisement Monitor object.
857*9c5db199SXin Li
858*9c5db199SXin Li        @param app_id: the app id.
859*9c5db199SXin Li        @param monitor_data: the list containing monitor type, RSSI filter
860*9c5db199SXin Li                             values and patterns.
861*9c5db199SXin Li
862*9c5db199SXin Li        @returns: monitor id, once the monitor is created, None otherwise.
863*9c5db199SXin Li
864*9c5db199SXin Li        """
865*9c5db199SXin Li        return self._proxy.advmon_add_monitor(app_id, monitor_data)
866*9c5db199SXin Li
867*9c5db199SXin Li
868*9c5db199SXin Li    @proxy_thread_safe
869*9c5db199SXin Li    def advmon_remove_monitor(self, app_id, monitor_id):
870*9c5db199SXin Li        """Remove the Advertisement Monitor object.
871*9c5db199SXin Li
872*9c5db199SXin Li        @param app_id: the app id.
873*9c5db199SXin Li        @param monitor_id: the monitor id.
874*9c5db199SXin Li
875*9c5db199SXin Li        @returns: True on success, False otherwise.
876*9c5db199SXin Li
877*9c5db199SXin Li        """
878*9c5db199SXin Li        return self._proxy.advmon_remove_monitor(app_id, monitor_id)
879*9c5db199SXin Li
880*9c5db199SXin Li
881*9c5db199SXin Li    @proxy_thread_safe
882*9c5db199SXin Li    def advmon_get_event_count(self, app_id, monitor_id, event):
883*9c5db199SXin Li        """Read the count of a particular event on the given monitor.
884*9c5db199SXin Li
885*9c5db199SXin Li        @param app_id: the app id.
886*9c5db199SXin Li        @param monitor_id: the monitor id.
887*9c5db199SXin Li        @param event: name of the specific event or 'All' for all events.
888*9c5db199SXin Li
889*9c5db199SXin Li        @returns: count of the specific event or dict of counts of all events.
890*9c5db199SXin Li
891*9c5db199SXin Li        """
892*9c5db199SXin Li        return self._proxy.advmon_get_event_count(app_id, monitor_id, event)
893*9c5db199SXin Li
894*9c5db199SXin Li
895*9c5db199SXin Li    @proxy_thread_safe
896*9c5db199SXin Li    def advmon_reset_event_count(self, app_id, monitor_id, event):
897*9c5db199SXin Li        """Reset the count of a particular event on the given monitor.
898*9c5db199SXin Li
899*9c5db199SXin Li        @param app_id: the app id.
900*9c5db199SXin Li        @param monitor_id: the monitor id.
901*9c5db199SXin Li        @param event: name of the specific event or 'All' for all events.
902*9c5db199SXin Li
903*9c5db199SXin Li        @returns: True on success, False otherwise.
904*9c5db199SXin Li
905*9c5db199SXin Li        """
906*9c5db199SXin Li        return self._proxy.advmon_reset_event_count(app_id, monitor_id, event)
907*9c5db199SXin Li
908*9c5db199SXin Li    @proxy_thread_safe
909*9c5db199SXin Li    def advmon_set_target_devices(self, app_id, monitor_id, devices):
910*9c5db199SXin Li        """Set the target devices to the given monitor.
911*9c5db199SXin Li
912*9c5db199SXin Li        DeviceFound and DeviceLost will only be counted if it is triggered by a
913*9c5db199SXin Li        target device.
914*9c5db199SXin Li
915*9c5db199SXin Li        @param app_id: the app id.
916*9c5db199SXin Li        @param monitor_id: the monitor id.
917*9c5db199SXin Li        @param devices: a list of devices in MAC address
918*9c5db199SXin Li
919*9c5db199SXin Li        @returns: True on success, False otherwise.
920*9c5db199SXin Li
921*9c5db199SXin Li        """
922*9c5db199SXin Li        return self._proxy.advmon_set_target_devices(app_id, monitor_id,
923*9c5db199SXin Li                                                     devices)
924*9c5db199SXin Li
925*9c5db199SXin Li    @proxy_thread_safe
926*9c5db199SXin Li    def advmon_interleave_scan_logger_start(self):
927*9c5db199SXin Li        """ Start interleave logger recording
928*9c5db199SXin Li        """
929*9c5db199SXin Li        self._proxy.advmon_interleave_scan_logger_start()
930*9c5db199SXin Li
931*9c5db199SXin Li    @proxy_thread_safe
932*9c5db199SXin Li    def advmon_interleave_scan_logger_stop(self):
933*9c5db199SXin Li        """ Stop interleave logger recording
934*9c5db199SXin Li
935*9c5db199SXin Li        @returns: True if logs were successfully collected,
936*9c5db199SXin Li                  False otherwise.
937*9c5db199SXin Li
938*9c5db199SXin Li        """
939*9c5db199SXin Li        return self._proxy.advmon_interleave_scan_logger_stop()
940*9c5db199SXin Li
941*9c5db199SXin Li    @proxy_thread_safe
942*9c5db199SXin Li    def advmon_interleave_scan_logger_get_records(self):
943*9c5db199SXin Li        """ Get records in previous log collections
944*9c5db199SXin Li
945*9c5db199SXin Li        @returns: a list of records, where each item is a record of
946*9c5db199SXin Li                  interleave |state| and the |time| the state starts.
947*9c5db199SXin Li                  |state| could be {'no filter', 'allowlist'}
948*9c5db199SXin Li                  |time| is system time in sec
949*9c5db199SXin Li
950*9c5db199SXin Li        """
951*9c5db199SXin Li        return self._proxy.advmon_interleave_scan_logger_get_records()
952*9c5db199SXin Li
953*9c5db199SXin Li    @proxy_thread_safe
954*9c5db199SXin Li    def advmon_interleave_scan_logger_get_cancel_events(self):
955*9c5db199SXin Li        """ Get cancel events in previous log collections
956*9c5db199SXin Li
957*9c5db199SXin Li        @returns: a list of cancel |time| when a interleave cancel event log
958*9c5db199SXin Li                  was found.
959*9c5db199SXin Li                  |time| is system time in sec
960*9c5db199SXin Li
961*9c5db199SXin Li        """
962*9c5db199SXin Li        return self._proxy.advmon_interleave_scan_logger_get_cancel_events()
963*9c5db199SXin Li
964*9c5db199SXin Li    @proxy_thread_safe
965*9c5db199SXin Li    def advmon_interleave_scan_get_durations(self):
966*9c5db199SXin Li        """Get durations of allowlist scan and no filter scan
967*9c5db199SXin Li
968*9c5db199SXin Li        @returns: a dict of {'allowlist': allowlist_duration,
969*9c5db199SXin Li                             'no filter': no_filter_duration},
970*9c5db199SXin Li                  or None if something went wrong
971*9c5db199SXin Li        """
972*9c5db199SXin Li        return self._proxy.get_advmon_interleave_durations()
973*9c5db199SXin Li
974*9c5db199SXin Li    @proxy_thread_safe
975*9c5db199SXin Li    def messages_start(self):
976*9c5db199SXin Li        """Start messages monitoring."""
977*9c5db199SXin Li        self._proxy.messages_start()
978*9c5db199SXin Li
979*9c5db199SXin Li    @proxy_thread_safe
980*9c5db199SXin Li    def messages_stop(self):
981*9c5db199SXin Li        """Stop messages monitoring.
982*9c5db199SXin Li
983*9c5db199SXin Li        @returns: True if logs were successfully gathered since logging started,
984*9c5db199SXin Li                else False
985*9c5db199SXin Li        """
986*9c5db199SXin Li        return self._proxy.messages_stop()
987*9c5db199SXin Li
988*9c5db199SXin Li    @proxy_thread_safe
989*9c5db199SXin Li    def messages_find(self, pattern_str):
990*9c5db199SXin Li        """Find if a pattern string exists in messages output.
991*9c5db199SXin Li
992*9c5db199SXin Li        @param pattern_str: the pattern string to find.
993*9c5db199SXin Li
994*9c5db199SXin Li        @returns: True on success. False otherwise.
995*9c5db199SXin Li
996*9c5db199SXin Li        """
997*9c5db199SXin Li        return self._proxy.messages_find(pattern_str)
998*9c5db199SXin Li
999*9c5db199SXin Li    @proxy_thread_safe
1000*9c5db199SXin Li    def clean_bluetooth_kernel_log(self, log_level=7):
1001*9c5db199SXin Li        """Remove Bluetooth kernel logs in /var/log/messages with loglevel
1002*9c5db199SXin Li           equal to or greater than |log_level|
1003*9c5db199SXin Li
1004*9c5db199SXin Li        @param log_level: int in range [0..7]
1005*9c5db199SXin Li        """
1006*9c5db199SXin Li        self._proxy.clean_bluetooth_kernel_log(log_level)
1007*9c5db199SXin Li
1008*9c5db199SXin Li    @proxy_thread_safe
1009*9c5db199SXin Li    def register_advertisement(self, advertisement_data):
1010*9c5db199SXin Li        """Register an advertisement.
1011*9c5db199SXin Li
1012*9c5db199SXin Li        Note that rpc supports only conformable types. Hence, a
1013*9c5db199SXin Li        dict about the advertisement is passed as a parameter such
1014*9c5db199SXin Li        that the advertisement object could be contructed on the host.
1015*9c5db199SXin Li
1016*9c5db199SXin Li        @param advertisement_data: a dict of the advertisement for
1017*9c5db199SXin Li                                   the adapter to register.
1018*9c5db199SXin Li
1019*9c5db199SXin Li        @returns: True on success. False otherwise.
1020*9c5db199SXin Li
1021*9c5db199SXin Li        """
1022*9c5db199SXin Li        return self._proxy.register_advertisement(advertisement_data)
1023*9c5db199SXin Li
1024*9c5db199SXin Li
1025*9c5db199SXin Li    @proxy_thread_safe
1026*9c5db199SXin Li    def unregister_advertisement(self, advertisement_data):
1027*9c5db199SXin Li        """Unregister an advertisement.
1028*9c5db199SXin Li
1029*9c5db199SXin Li        @param advertisement_data: a dict of the advertisement to unregister.
1030*9c5db199SXin Li
1031*9c5db199SXin Li        @returns: True on success. False otherwise.
1032*9c5db199SXin Li
1033*9c5db199SXin Li        """
1034*9c5db199SXin Li        return self._proxy.unregister_advertisement(advertisement_data)
1035*9c5db199SXin Li
1036*9c5db199SXin Li
1037*9c5db199SXin Li    @proxy_thread_safe
1038*9c5db199SXin Li    def set_advertising_intervals(self, min_adv_interval_ms,
1039*9c5db199SXin Li                                  max_adv_interval_ms):
1040*9c5db199SXin Li        """Set advertising intervals.
1041*9c5db199SXin Li
1042*9c5db199SXin Li        @param min_adv_interval_ms: the min advertising interval in ms.
1043*9c5db199SXin Li        @param max_adv_interval_ms: the max advertising interval in ms.
1044*9c5db199SXin Li
1045*9c5db199SXin Li        @returns: True on success. False otherwise.
1046*9c5db199SXin Li
1047*9c5db199SXin Li        """
1048*9c5db199SXin Li        return self._proxy.set_advertising_intervals(min_adv_interval_ms,
1049*9c5db199SXin Li                                                     max_adv_interval_ms)
1050*9c5db199SXin Li
1051*9c5db199SXin Li
1052*9c5db199SXin Li    @proxy_thread_safe
1053*9c5db199SXin Li    def get_advertisement_property(self, adv_path, prop_name):
1054*9c5db199SXin Li        """Grab property of an advertisement registered on the DUT
1055*9c5db199SXin Li
1056*9c5db199SXin Li        The service on the DUT registers a dbus object and holds it. During the
1057*9c5db199SXin Li        test, some properties on the object may change, so this allows the test
1058*9c5db199SXin Li        access to the properties at run-time.
1059*9c5db199SXin Li
1060*9c5db199SXin Li        @param adv_path: string path of the dbus object
1061*9c5db199SXin Li        @param prop_name: string name of the property required
1062*9c5db199SXin Li
1063*9c5db199SXin Li        @returns: the value of the property in standard (non-dbus) type if the
1064*9c5db199SXin Li                    property exists, else None
1065*9c5db199SXin Li        """
1066*9c5db199SXin Li
1067*9c5db199SXin Li        return self._proxy.get_advertisement_property(adv_path, prop_name)
1068*9c5db199SXin Li
1069*9c5db199SXin Li    @proxy_thread_safe
1070*9c5db199SXin Li    def get_advertising_manager_property(self, prop_name):
1071*9c5db199SXin Li        """Grab property of the bluez advertising manager
1072*9c5db199SXin Li
1073*9c5db199SXin Li        This allows us to understand the DUT's advertising capabilities, for
1074*9c5db199SXin Li        instance the maximum number of advertising instances supported, so that
1075*9c5db199SXin Li        we can test these capabilities.
1076*9c5db199SXin Li
1077*9c5db199SXin Li        @param adv_path: string path of the dbus object
1078*9c5db199SXin Li        @param prop_name: string name of the property required
1079*9c5db199SXin Li
1080*9c5db199SXin Li        @returns: the value of the property in standard (non-dbus) type if the
1081*9c5db199SXin Li                    property exists, else None
1082*9c5db199SXin Li        """
1083*9c5db199SXin Li
1084*9c5db199SXin Li        return self._proxy.get_advertising_manager_property(prop_name)
1085*9c5db199SXin Li
1086*9c5db199SXin Li    @proxy_thread_safe
1087*9c5db199SXin Li    def reset_advertising(self):
1088*9c5db199SXin Li        """Reset advertising.
1089*9c5db199SXin Li
1090*9c5db199SXin Li        This includes unregister all advertisements, reset advertising
1091*9c5db199SXin Li        intervals, and disable advertising.
1092*9c5db199SXin Li
1093*9c5db199SXin Li        @returns: True on success. False otherwise.
1094*9c5db199SXin Li
1095*9c5db199SXin Li        """
1096*9c5db199SXin Li        return self._proxy.reset_advertising()
1097*9c5db199SXin Li
1098*9c5db199SXin Li
1099*9c5db199SXin Li    @proxy_thread_safe
1100*9c5db199SXin Li    def create_audio_record_directory(self, audio_record_dir):
1101*9c5db199SXin Li        """Create the audio recording directory.
1102*9c5db199SXin Li
1103*9c5db199SXin Li        @param audio_record_dir: the audio recording directory
1104*9c5db199SXin Li
1105*9c5db199SXin Li        @returns: True on success. False otherwise.
1106*9c5db199SXin Li        """
1107*9c5db199SXin Li        return self._proxy.create_audio_record_directory(audio_record_dir)
1108*9c5db199SXin Li
1109*9c5db199SXin Li    @proxy_thread_safe
1110*9c5db199SXin Li    def get_audio_thread_summary(self):
1111*9c5db199SXin Li        """Dumps audio thread info.
1112*9c5db199SXin Li
1113*9c5db199SXin Li        @returns: a list of cras audio information.
1114*9c5db199SXin Li        """
1115*9c5db199SXin Li        return self._proxy.get_audio_thread_summary()
1116*9c5db199SXin Li
1117*9c5db199SXin Li    @proxy_thread_safe
1118*9c5db199SXin Li    def get_device_id_from_node_type(self, node_type, is_input):
1119*9c5db199SXin Li        """Gets device id from node type.
1120*9c5db199SXin Li
1121*9c5db199SXin Li        @param node_type: a node type defined in CRAS_NODE_TYPES.
1122*9c5db199SXin Li        @param is_input: True if the node is input. False otherwise.
1123*9c5db199SXin Li
1124*9c5db199SXin Li        @returns: a string for device id.
1125*9c5db199SXin Li        """
1126*9c5db199SXin Li        return self._proxy.get_device_id_from_node_type(node_type, is_input)
1127*9c5db199SXin Li
1128*9c5db199SXin Li    @proxy_thread_safe
1129*9c5db199SXin Li    def start_capturing_audio_subprocess(self, audio_data, recording_device):
1130*9c5db199SXin Li        """Start capturing audio in a subprocess.
1131*9c5db199SXin Li
1132*9c5db199SXin Li        @param audio_data: the audio test data
1133*9c5db199SXin Li        @param recording_device: which device recorded the audio,
1134*9c5db199SXin Li                possible values are 'recorded_by_dut' or 'recorded_by_peer'
1135*9c5db199SXin Li
1136*9c5db199SXin Li        @returns: True on success. False otherwise.
1137*9c5db199SXin Li        """
1138*9c5db199SXin Li        return self._proxy.start_capturing_audio_subprocess(
1139*9c5db199SXin Li                json.dumps(audio_data), recording_device)
1140*9c5db199SXin Li
1141*9c5db199SXin Li
1142*9c5db199SXin Li    @proxy_thread_safe
1143*9c5db199SXin Li    def stop_capturing_audio_subprocess(self):
1144*9c5db199SXin Li        """Stop capturing audio.
1145*9c5db199SXin Li
1146*9c5db199SXin Li        @returns: True on success. False otherwise.
1147*9c5db199SXin Li        """
1148*9c5db199SXin Li        return self._proxy.stop_capturing_audio_subprocess()
1149*9c5db199SXin Li
1150*9c5db199SXin Li
1151*9c5db199SXin Li    @proxy_thread_safe
1152*9c5db199SXin Li    def start_playing_audio_subprocess(self, audio_data, pin_device=None):
1153*9c5db199SXin Li        """Start playing audio in a subprocess.
1154*9c5db199SXin Li
1155*9c5db199SXin Li        @param audio_data: the audio test data.
1156*9c5db199SXin Li        @param pin_device: the device id to play audio.
1157*9c5db199SXin Li
1158*9c5db199SXin Li        @returns: True on success. False otherwise.
1159*9c5db199SXin Li        """
1160*9c5db199SXin Li        audio_data = json.dumps(audio_data)
1161*9c5db199SXin Li        return self._proxy.start_playing_audio_subprocess(
1162*9c5db199SXin Li                audio_data, pin_device)
1163*9c5db199SXin Li
1164*9c5db199SXin Li
1165*9c5db199SXin Li    @proxy_thread_safe
1166*9c5db199SXin Li    def stop_playing_audio_subprocess(self):
1167*9c5db199SXin Li        """Stop playing audio in the subprocess.
1168*9c5db199SXin Li
1169*9c5db199SXin Li        @returns: True on success. False otherwise.
1170*9c5db199SXin Li        """
1171*9c5db199SXin Li        return self._proxy.stop_playing_audio_subprocess()
1172*9c5db199SXin Li
1173*9c5db199SXin Li
1174*9c5db199SXin Li    @proxy_thread_safe
1175*9c5db199SXin Li    def play_audio(self, audio_data):
1176*9c5db199SXin Li        """Play audio.
1177*9c5db199SXin Li
1178*9c5db199SXin Li        It blocks until it has completed playing back the audio.
1179*9c5db199SXin Li
1180*9c5db199SXin Li        @param audio_data: the audio test data
1181*9c5db199SXin Li
1182*9c5db199SXin Li        @returns: True on success. False otherwise.
1183*9c5db199SXin Li        """
1184*9c5db199SXin Li        return self._proxy.play_audio(json.dumps(audio_data))
1185*9c5db199SXin Li
1186*9c5db199SXin Li
1187*9c5db199SXin Li    @proxy_thread_safe
1188*9c5db199SXin Li    def check_audio_frames_legitimacy(self, audio_test_data, recording_device,
1189*9c5db199SXin Li                                      recorded_file):
1190*9c5db199SXin Li        """Get the number of frames in the recorded audio file.
1191*9c5db199SXin Li        @param audio_test_data: the audio test data
1192*9c5db199SXin Li        @param recording_device: which device recorded the audio,
1193*9c5db199SXin Li                possible values are 'recorded_by_dut' or 'recorded_by_peer'
1194*9c5db199SXin Li        @param recorded_file: the recorded file name
1195*9c5db199SXin Li
1196*9c5db199SXin Li        @returns: True if audio frames are legitimate.
1197*9c5db199SXin Li        """
1198*9c5db199SXin Li        return self._proxy.check_audio_frames_legitimacy(
1199*9c5db199SXin Li                json.dumps(audio_test_data), recording_device, recorded_file)
1200*9c5db199SXin Li
1201*9c5db199SXin Li
1202*9c5db199SXin Li    @proxy_thread_safe
1203*9c5db199SXin Li    def convert_audio_sample_rate(self, input_file, out_file, test_data,
1204*9c5db199SXin Li                                  new_rate):
1205*9c5db199SXin Li        """Convert audio file to new sample rate.
1206*9c5db199SXin Li
1207*9c5db199SXin Li        @param input_file: Path to file to upsample.
1208*9c5db199SXin Li        @param out_file: Path to create upsampled file.
1209*9c5db199SXin Li        @param test_data: Dictionary with information about file.
1210*9c5db199SXin Li        @param new_rate: New rate to upsample file to.
1211*9c5db199SXin Li
1212*9c5db199SXin Li        @returns: True if upsampling succeeded, False otherwise.
1213*9c5db199SXin Li        """
1214*9c5db199SXin Li        return self._proxy.convert_audio_sample_rate(input_file, out_file,
1215*9c5db199SXin Li                                                     json.dumps(test_data),
1216*9c5db199SXin Li                                                     new_rate)
1217*9c5db199SXin Li
1218*9c5db199SXin Li
1219*9c5db199SXin Li    @proxy_thread_safe
1220*9c5db199SXin Li    def trim_wav_file(self, in_file, out_file, new_duration, test_data,
1221*9c5db199SXin Li                      tolerance=0.1):
1222*9c5db199SXin Li        """Trim long file to desired length.
1223*9c5db199SXin Li
1224*9c5db199SXin Li        Trims audio file to length by cutting out silence from beginning and
1225*9c5db199SXin Li        end.
1226*9c5db199SXin Li
1227*9c5db199SXin Li        @param in_file: Path to audio file to be trimmed.
1228*9c5db199SXin Li        @param out_file: Path to trimmed audio file to create.
1229*9c5db199SXin Li        @param new_duration: A float representing the desired duration of
1230*9c5db199SXin Li                the resulting trimmed file.
1231*9c5db199SXin Li        @param test_data: Dictionary containing information about the test file.
1232*9c5db199SXin Li        @param tolerance: (optional) A float representing the allowable
1233*9c5db199SXin Li                difference between trimmed file length and desired duration
1234*9c5db199SXin Li
1235*9c5db199SXin Li        @returns: True if file was trimmed successfully, False otherwise.
1236*9c5db199SXin Li        """
1237*9c5db199SXin Li        return self._proxy.trim_wav_file(in_file, out_file, new_duration,
1238*9c5db199SXin Li                                         json.dumps(test_data), tolerance)
1239*9c5db199SXin Li
1240*9c5db199SXin Li
1241*9c5db199SXin Li    @proxy_thread_safe
1242*9c5db199SXin Li    def unzip_audio_test_data(self, tar_path, data_dir):
1243*9c5db199SXin Li        """Unzip audio test data files.
1244*9c5db199SXin Li
1245*9c5db199SXin Li        @param tar_path: Path to audio test data tarball on DUT.
1246*9c5db199SXin Li        @oaram data_dir: Path to directory where to extract test data directory.
1247*9c5db199SXin Li
1248*9c5db199SXin Li        @returns: True if audio test data folder exists, False otherwise.
1249*9c5db199SXin Li        """
1250*9c5db199SXin Li        return self._proxy.unzip_audio_test_data(tar_path, data_dir)
1251*9c5db199SXin Li
1252*9c5db199SXin Li
1253*9c5db199SXin Li    @proxy_thread_safe
1254*9c5db199SXin Li    def convert_raw_to_wav(self, input_file, output_file, test_data):
1255*9c5db199SXin Li        """Convert raw audio file to wav file.
1256*9c5db199SXin Li
1257*9c5db199SXin Li        @oaram input_file: The location of the raw file.
1258*9c5db199SXin Li        @param output_file: The location to place the resulting wav file.
1259*9c5db199SXin Li        @param test_data: The data for the file being converted.
1260*9c5db199SXin Li
1261*9c5db199SXin Li        @returns: True if conversion was successful, otherwise false.
1262*9c5db199SXin Li        """
1263*9c5db199SXin Li        return self._proxy.convert_raw_to_wav(input_file, output_file,
1264*9c5db199SXin Li                                              json.dumps(test_data))
1265*9c5db199SXin Li
1266*9c5db199SXin Li
1267*9c5db199SXin Li    @proxy_thread_safe
1268*9c5db199SXin Li    def get_primary_frequencies(self, audio_test_data, recording_device,
1269*9c5db199SXin Li                                recorded_file):
1270*9c5db199SXin Li        """Get primary frequencies of the audio test file.
1271*9c5db199SXin Li
1272*9c5db199SXin Li        @param audio_test_data: the audio test data
1273*9c5db199SXin Li        @param recording_device: which device recorded the audio,
1274*9c5db199SXin Li                possible values are 'recorded_by_dut' or 'recorded_by_peer'
1275*9c5db199SXin Li        @param recorded_file: the recorded file name
1276*9c5db199SXin Li
1277*9c5db199SXin Li        @returns: a list of primary frequencies of channels in the audio file
1278*9c5db199SXin Li        """
1279*9c5db199SXin Li        return self._proxy.get_primary_frequencies(
1280*9c5db199SXin Li                json.dumps(audio_test_data), recording_device, recorded_file)
1281*9c5db199SXin Li
1282*9c5db199SXin Li
1283*9c5db199SXin Li    @proxy_thread_safe
1284*9c5db199SXin Li    def enable_wbs(self, value):
1285*9c5db199SXin Li        """Enable or disable wideband speech (wbs) per the value.
1286*9c5db199SXin Li
1287*9c5db199SXin Li        @param value: True to enable wbs.
1288*9c5db199SXin Li
1289*9c5db199SXin Li        @returns: True if the operation succeeds.
1290*9c5db199SXin Li        """
1291*9c5db199SXin Li        logging.debug('%s wbs', 'enable' if value else 'disable')
1292*9c5db199SXin Li        return self._proxy.enable_wbs(value)
1293*9c5db199SXin Li
1294*9c5db199SXin Li
1295*9c5db199SXin Li    @proxy_thread_safe
1296*9c5db199SXin Li    def set_player_playback_status(self, status):
1297*9c5db199SXin Li        """Set playback status for the registered media player.
1298*9c5db199SXin Li
1299*9c5db199SXin Li        @param status: playback status in string.
1300*9c5db199SXin Li
1301*9c5db199SXin Li        """
1302*9c5db199SXin Li        logging.debug('Set media player playback status to %s', status)
1303*9c5db199SXin Li        return self._proxy.set_player_playback_status(status)
1304*9c5db199SXin Li
1305*9c5db199SXin Li
1306*9c5db199SXin Li    @proxy_thread_safe
1307*9c5db199SXin Li    def set_player_position(self, position):
1308*9c5db199SXin Li        """Set media position for the registered media player.
1309*9c5db199SXin Li
1310*9c5db199SXin Li        @param position: position in micro seconds.
1311*9c5db199SXin Li
1312*9c5db199SXin Li        """
1313*9c5db199SXin Li        logging.debug('Set media player position to %d', position)
1314*9c5db199SXin Li        return self._proxy.set_player_position(position)
1315*9c5db199SXin Li
1316*9c5db199SXin Li
1317*9c5db199SXin Li    @proxy_thread_safe
1318*9c5db199SXin Li    def set_player_metadata(self, metadata):
1319*9c5db199SXin Li        """Set metadata for the registered media player.
1320*9c5db199SXin Li
1321*9c5db199SXin Li        @param metadata: dictionary of media metadata.
1322*9c5db199SXin Li
1323*9c5db199SXin Li        """
1324*9c5db199SXin Li        logging.debug('Set media player album:%s artist:%s title:%s',
1325*9c5db199SXin Li                      metadata.get("album"), metadata.get("artist"),
1326*9c5db199SXin Li                      metadata.get("title"))
1327*9c5db199SXin Li        return self._proxy.set_player_metadata(metadata)
1328*9c5db199SXin Li
1329*9c5db199SXin Li
1330*9c5db199SXin Li    @proxy_thread_safe
1331*9c5db199SXin Li    def set_player_length(self, length):
1332*9c5db199SXin Li        """Set media length for the registered media player.
1333*9c5db199SXin Li
1334*9c5db199SXin Li        @param length: length in micro seconds.
1335*9c5db199SXin Li
1336*9c5db199SXin Li        """
1337*9c5db199SXin Li        logging.debug('Set media player length to %d', length)
1338*9c5db199SXin Li        return self._proxy.set_player_length(length)
1339*9c5db199SXin Li
1340*9c5db199SXin Li
1341*9c5db199SXin Li    @proxy_thread_safe
1342*9c5db199SXin Li    def select_input_device(self, device_name):
1343*9c5db199SXin Li        """Select the audio input device.
1344*9c5db199SXin Li
1345*9c5db199SXin Li        @param device_name: the name of the Bluetooth peer device
1346*9c5db199SXin Li
1347*9c5db199SXin Li        @returns: True if the operation succeeds.
1348*9c5db199SXin Li        """
1349*9c5db199SXin Li        return self._proxy.select_input_device(device_name)
1350*9c5db199SXin Li
1351*9c5db199SXin Li
1352*9c5db199SXin Li    @proxy_thread_safe
1353*9c5db199SXin Li    def select_output_node(self, node_type):
1354*9c5db199SXin Li        """Select the audio output node.
1355*9c5db199SXin Li
1356*9c5db199SXin Li        @param node_type: the node type of the Bluetooth peer device
1357*9c5db199SXin Li
1358*9c5db199SXin Li        @returns: True if the operation succeeds.
1359*9c5db199SXin Li        """
1360*9c5db199SXin Li        return self._proxy.select_output_node(node_type)
1361*9c5db199SXin Li
1362*9c5db199SXin Li
1363*9c5db199SXin Li    @proxy_thread_safe
1364*9c5db199SXin Li    def get_selected_output_device_type(self):
1365*9c5db199SXin Li        """Get the selected audio output node type.
1366*9c5db199SXin Li
1367*9c5db199SXin Li        @returns: the node type of the selected output device.
1368*9c5db199SXin Li        """
1369*9c5db199SXin Li        return self._proxy.get_selected_output_device_type()
1370*9c5db199SXin Li
1371*9c5db199SXin Li
1372*9c5db199SXin Li    @proxy_thread_safe
1373*9c5db199SXin Li    def read_characteristic(self, uuid, address):
1374*9c5db199SXin Li        """Reads the value of a gatt characteristic.
1375*9c5db199SXin Li
1376*9c5db199SXin Li        Reads the current value of a gatt characteristic.
1377*9c5db199SXin Li
1378*9c5db199SXin Li        @param uuid: The uuid of the characteristic to read, as a string.
1379*9c5db199SXin Li        @param address: The MAC address of the remote device.
1380*9c5db199SXin Li
1381*9c5db199SXin Li        @returns: A byte array containing the value of the if the uuid/address
1382*9c5db199SXin Li                      was found in the object tree.
1383*9c5db199SXin Li                  None if the uuid/address was not found in the object tree, or
1384*9c5db199SXin Li                      if a DBus exception was raised by the read operation.
1385*9c5db199SXin Li
1386*9c5db199SXin Li        """
1387*9c5db199SXin Li        value = self._proxy.read_characteristic(uuid, address)
1388*9c5db199SXin Li        if value is None:
1389*9c5db199SXin Li            return None
1390*9c5db199SXin Li        return bytearray(base64.standard_b64decode(value))
1391*9c5db199SXin Li
1392*9c5db199SXin Li
1393*9c5db199SXin Li    @proxy_thread_safe
1394*9c5db199SXin Li    def write_characteristic(self, uuid, address, bytes_to_write):
1395*9c5db199SXin Li        """Performs a write operation on a gatt characteristic.
1396*9c5db199SXin Li
1397*9c5db199SXin Li        Writes to a GATT characteristic on a remote device.
1398*9c5db199SXin Li
1399*9c5db199SXin Li        @param uuid: The uuid of the characteristic to write to, as a string.
1400*9c5db199SXin Li        @param address: The MAC address of the remote device, as a string.
1401*9c5db199SXin Li        @param bytes_to_write: A byte array containing the data to write.
1402*9c5db199SXin Li
1403*9c5db199SXin Li        @returns: True if the write operation does not raise an exception.
1404*9c5db199SXin Li                  None if the uuid/address was not found in the object tree, or
1405*9c5db199SXin Li                      if a DBus exception was raised by the write operation.
1406*9c5db199SXin Li
1407*9c5db199SXin Li        """
1408*9c5db199SXin Li        return self._proxy.write_characteristic(
1409*9c5db199SXin Li            uuid, address, base64.standard_b64encode(bytes_to_write))
1410*9c5db199SXin Li
1411*9c5db199SXin Li
1412*9c5db199SXin Li    @proxy_thread_safe
1413*9c5db199SXin Li    def exchange_messages(self, tx_object_path, rx_object_path, bytes_to_write):
1414*9c5db199SXin Li        """Performs a write operation on a gatt characteristic and wait for
1415*9c5db199SXin Li        the response on another characteristic.
1416*9c5db199SXin Li
1417*9c5db199SXin Li        @param tx_object_path: the object path of the characteristic to write.
1418*9c5db199SXin Li        @param rx_object_path: the object path of the characteristic to read.
1419*9c5db199SXin Li        @param value: A byte array containing the data to write.
1420*9c5db199SXin Li
1421*9c5db199SXin Li        @returns: The value of the characteristic to read from.
1422*9c5db199SXin Li                  None if the uuid/address was not found in the object tree, or
1423*9c5db199SXin Li                      if a DBus exception was raised by the write operation.
1424*9c5db199SXin Li
1425*9c5db199SXin Li        """
1426*9c5db199SXin Li        return self._proxy.exchange_messages(
1427*9c5db199SXin Li            tx_object_path, rx_object_path,
1428*9c5db199SXin Li            base64.standard_b64encode(bytes_to_write))
1429*9c5db199SXin Li
1430*9c5db199SXin Li
1431*9c5db199SXin Li    @proxy_thread_safe
1432*9c5db199SXin Li    def start_notify(self, object_path, cccd_value):
1433*9c5db199SXin Li        """Starts the notification session on the gatt characteristic.
1434*9c5db199SXin Li
1435*9c5db199SXin Li        @param object_path: the object path of the characteristic.
1436*9c5db199SXin Li        @param cccd_value: Possible CCCD values include
1437*9c5db199SXin Li               0x00 - inferred from the remote characteristic's properties
1438*9c5db199SXin Li               0x01 - notification
1439*9c5db199SXin Li               0x02 - indication
1440*9c5db199SXin Li
1441*9c5db199SXin Li        @returns: True if the operation succeeds.
1442*9c5db199SXin Li                  False if the characteristic is not found, or
1443*9c5db199SXin Li                      if a DBus exception was raised by the operation.
1444*9c5db199SXin Li
1445*9c5db199SXin Li        """
1446*9c5db199SXin Li        return self._proxy.start_notify(object_path, cccd_value)
1447*9c5db199SXin Li
1448*9c5db199SXin Li
1449*9c5db199SXin Li    @proxy_thread_safe
1450*9c5db199SXin Li    def stop_notify(self, object_path):
1451*9c5db199SXin Li        """Stops the notification session on the gatt characteristic.
1452*9c5db199SXin Li
1453*9c5db199SXin Li        @param object_path: the object path of the characteristic.
1454*9c5db199SXin Li
1455*9c5db199SXin Li        @returns: True if the operation succeeds.
1456*9c5db199SXin Li                  False if the characteristic is not found, or
1457*9c5db199SXin Li                      if a DBus exception was raised by the operation.
1458*9c5db199SXin Li
1459*9c5db199SXin Li        """
1460*9c5db199SXin Li        return self._proxy.stop_notify(object_path)
1461*9c5db199SXin Li
1462*9c5db199SXin Li
1463*9c5db199SXin Li    @proxy_thread_safe
1464*9c5db199SXin Li    def is_notifying(self, object_path):
1465*9c5db199SXin Li        """Is the GATT characteristic in a notifying session?
1466*9c5db199SXin Li
1467*9c5db199SXin Li        @param object_path: the object path of the characteristic.
1468*9c5db199SXin Li
1469*9c5db199SXin Li        @return True if it is in a notification session. False otherwise.
1470*9c5db199SXin Li
1471*9c5db199SXin Li        """
1472*9c5db199SXin Li        return self._proxy.is_notifying(object_path)
1473*9c5db199SXin Li
1474*9c5db199SXin Li
1475*9c5db199SXin Li    @proxy_thread_safe
1476*9c5db199SXin Li    def is_characteristic_path_resolved(self, uuid, address):
1477*9c5db199SXin Li        """Checks whether a characteristic is in the object tree.
1478*9c5db199SXin Li
1479*9c5db199SXin Li        Checks whether a characteristic is curently found in the object tree.
1480*9c5db199SXin Li
1481*9c5db199SXin Li        @param uuid: The uuid of the characteristic to search for.
1482*9c5db199SXin Li        @param address: The MAC address of the device on which to search for
1483*9c5db199SXin Li            the characteristic.
1484*9c5db199SXin Li
1485*9c5db199SXin Li        @returns: True if the characteristic is found, False otherwise.
1486*9c5db199SXin Li
1487*9c5db199SXin Li        """
1488*9c5db199SXin Li        return self._proxy.is_characteristic_path_resolved(uuid, address)
1489*9c5db199SXin Li
1490*9c5db199SXin Li
1491*9c5db199SXin Li    @proxy_thread_safe
1492*9c5db199SXin Li    def get_gatt_attributes_map(self, address):
1493*9c5db199SXin Li        """Return a JSON formated string of the GATT attributes of a device,
1494*9c5db199SXin Li        keyed by UUID
1495*9c5db199SXin Li        @param address: a string of the MAC address of the device
1496*9c5db199SXin Li
1497*9c5db199SXin Li        @return: JSON formated string, stored the nested structure of the
1498*9c5db199SXin Li        attributes. Each attribute has 'path' and ['chrcs' | 'descs'], which
1499*9c5db199SXin Li        store their object path and children respectively.
1500*9c5db199SXin Li        """
1501*9c5db199SXin Li        return self._proxy.get_gatt_attributes_map(address)
1502*9c5db199SXin Li
1503*9c5db199SXin Li
1504*9c5db199SXin Li    @proxy_thread_safe
1505*9c5db199SXin Li    def get_gatt_service_property(self, object_path, property_name):
1506*9c5db199SXin Li        """Get property from a service attribute
1507*9c5db199SXin Li        @param object_path: a string of the object path of the service
1508*9c5db199SXin Li        @param property_name: a string of a property, ex: 'Value', 'UUID'
1509*9c5db199SXin Li
1510*9c5db199SXin Li        @return: the property if success,
1511*9c5db199SXin Li                 None otherwise
1512*9c5db199SXin Li        """
1513*9c5db199SXin Li        return self._proxy.get_gatt_service_property(object_path, property_name)
1514*9c5db199SXin Li
1515*9c5db199SXin Li
1516*9c5db199SXin Li    @proxy_thread_safe
1517*9c5db199SXin Li    def get_gatt_characteristic_property(self, object_path, property_name):
1518*9c5db199SXin Li        """Get property from a characteristic attribute
1519*9c5db199SXin Li        @param object_path: a string of the object path of the characteristic
1520*9c5db199SXin Li        @param property_name: a string of a property, ex: 'Value', 'UUID'
1521*9c5db199SXin Li
1522*9c5db199SXin Li        @return: the property if success,
1523*9c5db199SXin Li                 None otherwise
1524*9c5db199SXin Li        """
1525*9c5db199SXin Li        return self._proxy.get_gatt_characteristic_property(object_path,
1526*9c5db199SXin Li                                                            property_name)
1527*9c5db199SXin Li
1528*9c5db199SXin Li
1529*9c5db199SXin Li    @proxy_thread_safe
1530*9c5db199SXin Li    def get_gatt_descriptor_property(self, object_path, property_name):
1531*9c5db199SXin Li        """Get property from a descriptor attribute
1532*9c5db199SXin Li        @param object_path: a string of the object path of the descriptor
1533*9c5db199SXin Li        @param property_name: a string of a property, ex: 'Value', 'UUID'
1534*9c5db199SXin Li
1535*9c5db199SXin Li        @return: the property if success,
1536*9c5db199SXin Li                 None otherwise
1537*9c5db199SXin Li        """
1538*9c5db199SXin Li        return self._proxy.get_gatt_descriptor_property(object_path,
1539*9c5db199SXin Li                                                        property_name)
1540*9c5db199SXin Li
1541*9c5db199SXin Li
1542*9c5db199SXin Li    @proxy_thread_safe
1543*9c5db199SXin Li    def gatt_characteristic_read_value(self, uuid, object_path):
1544*9c5db199SXin Li        """Perform method ReadValue on a characteristic attribute
1545*9c5db199SXin Li        @param uuid: a string of uuid
1546*9c5db199SXin Li        @param object_path: a string of the object path of the characteristic
1547*9c5db199SXin Li
1548*9c5db199SXin Li        @return: base64 string of dbus bytearray
1549*9c5db199SXin Li        """
1550*9c5db199SXin Li        return self._proxy.gatt_characteristic_read_value(uuid, object_path)
1551*9c5db199SXin Li
1552*9c5db199SXin Li
1553*9c5db199SXin Li    @proxy_thread_safe
1554*9c5db199SXin Li    def gatt_descriptor_read_value(self, uuid, object_path):
1555*9c5db199SXin Li        """Perform method ReadValue on a descriptor attribute
1556*9c5db199SXin Li        @param uuid: a string of uuid
1557*9c5db199SXin Li        @param object_path: a string of the object path of the descriptor
1558*9c5db199SXin Li
1559*9c5db199SXin Li        @return: base64 string of dbus bytearray
1560*9c5db199SXin Li        """
1561*9c5db199SXin Li        return self._proxy.gatt_descriptor_read_value(uuid, object_path)
1562*9c5db199SXin Li
1563*9c5db199SXin Li
1564*9c5db199SXin Li    @proxy_thread_safe
1565*9c5db199SXin Li    def get_gatt_object_path(self, address, uuid):
1566*9c5db199SXin Li        """Get property from a characteristic attribute
1567*9c5db199SXin Li
1568*9c5db199SXin Li        @param address: The MAC address of the remote device.
1569*9c5db199SXin Li        @param uuid: The uuid of the attribute.
1570*9c5db199SXin Li
1571*9c5db199SXin Li        @return: the object path of the attribute if success,
1572*9c5db199SXin Li                 none otherwise
1573*9c5db199SXin Li
1574*9c5db199SXin Li        """
1575*9c5db199SXin Li        return self._proxy.get_gatt_object_path(address, uuid)
1576*9c5db199SXin Li
1577*9c5db199SXin Li
1578*9c5db199SXin Li    def copy_logs(self, destination):
1579*9c5db199SXin Li        """Copy the logs generated by this device to a given location.
1580*9c5db199SXin Li
1581*9c5db199SXin Li        @param destination: destination directory for the logs.
1582*9c5db199SXin Li
1583*9c5db199SXin Li        """
1584*9c5db199SXin Li        self.host.collect_logs(self.XMLRPC_LOG_PATH, destination)
1585*9c5db199SXin Li
1586*9c5db199SXin Li
1587*9c5db199SXin Li    @proxy_thread_safe
1588*9c5db199SXin Li    def get_connection_info(self, address):
1589*9c5db199SXin Li        """Get device connection info.
1590*9c5db199SXin Li
1591*9c5db199SXin Li        @param address: The MAC address of the device.
1592*9c5db199SXin Li
1593*9c5db199SXin Li        @returns: On success, a tuple of:
1594*9c5db199SXin Li                      ( RSSI, transmit_power, max_transmit_power )
1595*9c5db199SXin Li                  None otherwise.
1596*9c5db199SXin Li
1597*9c5db199SXin Li        """
1598*9c5db199SXin Li        return self._proxy.get_connection_info(address)
1599*9c5db199SXin Li
1600*9c5db199SXin Li
1601*9c5db199SXin Li    @proxy_thread_safe
1602*9c5db199SXin Li    def set_discovery_filter(self, filter):
1603*9c5db199SXin Li        """Set the discovery filter.
1604*9c5db199SXin Li
1605*9c5db199SXin Li        @param filter: The discovery filter to set.
1606*9c5db199SXin Li
1607*9c5db199SXin Li        @return True on success, False otherwise.
1608*9c5db199SXin Li
1609*9c5db199SXin Li        """
1610*9c5db199SXin Li        return self._proxy.set_discovery_filter(filter)
1611*9c5db199SXin Li
1612*9c5db199SXin Li
1613*9c5db199SXin Li    @proxy_thread_safe
1614*9c5db199SXin Li    def set_le_connection_parameters(self, address, parameters):
1615*9c5db199SXin Li        """Set the LE connection parameters.
1616*9c5db199SXin Li
1617*9c5db199SXin Li        @param address: The MAC address of the device.
1618*9c5db199SXin Li        @param parameters: The LE connection parameters to set.
1619*9c5db199SXin Li
1620*9c5db199SXin Li        @return: True on success. False otherwise.
1621*9c5db199SXin Li
1622*9c5db199SXin Li        """
1623*9c5db199SXin Li        return self._proxy.set_le_connection_parameters(address, parameters)
1624*9c5db199SXin Li
1625*9c5db199SXin Li
1626*9c5db199SXin Li    @proxy_thread_safe
1627*9c5db199SXin Li    def wait_for_hid_device(self,
1628*9c5db199SXin Li                            device_address,
1629*9c5db199SXin Li                            timeout=None,
1630*9c5db199SXin Li                            sleep_interval=None):
1631*9c5db199SXin Li        """Wait for hid device with given device address.
1632*9c5db199SXin Li
1633*9c5db199SXin Li        Args:
1634*9c5db199SXin Li            device_address: Peripheral Address
1635*9c5db199SXin Li            timeout: maximum number of seconds to wait
1636*9c5db199SXin Li            sleep_interval: time to sleep between polls
1637*9c5db199SXin Li
1638*9c5db199SXin Li        Returns:
1639*9c5db199SXin Li            True if hid device is found.
1640*9c5db199SXin Li        """
1641*9c5db199SXin Li        return self._proxy.wait_for_hid_device(device_address, timeout,
1642*9c5db199SXin Li                                               sleep_interval)
1643*9c5db199SXin Li
1644*9c5db199SXin Li
1645*9c5db199SXin Li    @proxy_thread_safe
1646*9c5db199SXin Li    def bt_caused_last_resume(self):
1647*9c5db199SXin Li        """Checks if last resume from suspend was caused by bluetooth
1648*9c5db199SXin Li
1649*9c5db199SXin Li        @return: True if BT wake path was cause of resume, False otherwise
1650*9c5db199SXin Li        """
1651*9c5db199SXin Li
1652*9c5db199SXin Li        return self._proxy.bt_caused_last_resume()
1653*9c5db199SXin Li
1654*9c5db199SXin Li    @proxy_thread_safe
1655*9c5db199SXin Li    def find_last_suspend_via_powerd_logs(self):
1656*9c5db199SXin Li        """Finds the last suspend attempt via powerd logs.
1657*9c5db199SXin Li
1658*9c5db199SXin Li        @return: Tuple (suspend start time, suspend end time, suspend result) or
1659*9c5db199SXin Li                 None
1660*9c5db199SXin Li        """
1661*9c5db199SXin Li        info = self._proxy.find_last_suspend_via_powerd_logs()
1662*9c5db199SXin Li
1663*9c5db199SXin Li        # Currently, we get the date back in string format due to python2/3
1664*9c5db199SXin Li        # inconsistencies. We can get rid of this once everything is running
1665*9c5db199SXin Li        # python3 (hopefully)
1666*9c5db199SXin Li        # TODO - Revisit converting date to string and back in this method
1667*9c5db199SXin Li        if info:
1668*9c5db199SXin Li            start_date = datetime.strptime(info[0], self.STANDARD_DATE_FORMAT)
1669*9c5db199SXin Li            end_date = datetime.strptime(info[1], self.STANDARD_DATE_FORMAT)
1670*9c5db199SXin Li            ret = info[2]
1671*9c5db199SXin Li
1672*9c5db199SXin Li            return (start_date, end_date, ret)
1673*9c5db199SXin Li
1674*9c5db199SXin Li        return None
1675*9c5db199SXin Li
1676*9c5db199SXin Li    @proxy_thread_safe
1677*9c5db199SXin Li    def do_suspend(self, seconds, expect_bt_wake):
1678*9c5db199SXin Li        """Suspend DUT using the power manager.
1679*9c5db199SXin Li
1680*9c5db199SXin Li        @param seconds: The number of seconds to suspend the device.
1681*9c5db199SXin Li        @param expect_bt_wake: Whether we expect bluetooth to wake us from
1682*9c5db199SXin Li            suspend. If true, we expect this resume will occur early
1683*9c5db199SXin Li        """
1684*9c5db199SXin Li
1685*9c5db199SXin Li        # Do not retry this RPC if it fails or times out
1686*9c5db199SXin Li        return self._proxy.do_suspend(seconds, expect_bt_wake, __no_retry=True)
1687*9c5db199SXin Li
1688*9c5db199SXin Li
1689*9c5db199SXin Li    @proxy_thread_safe
1690*9c5db199SXin Li    def get_wlan_vid_pid(self):
1691*9c5db199SXin Li        """ Return vendor id and product id of the wlan chip on BT/WiFi module
1692*9c5db199SXin Li
1693*9c5db199SXin Li        @returns: (vid,pid) on success; (None,None) on failure
1694*9c5db199SXin Li        """
1695*9c5db199SXin Li        return self._proxy.get_wlan_vid_pid()
1696*9c5db199SXin Li
1697*9c5db199SXin Li    @proxy_thread_safe
1698*9c5db199SXin Li    def get_bt_transport(self):
1699*9c5db199SXin Li        """ Return the transport used by Bluetooth module
1700*9c5db199SXin Li
1701*9c5db199SXin Li        @returns: USB/UART/SDIO on success; None on failure
1702*9c5db199SXin Li        """
1703*9c5db199SXin Li        return self._proxy.get_bt_transport()
1704*9c5db199SXin Li
1705*9c5db199SXin Li    @proxy_thread_safe
1706*9c5db199SXin Li    def get_bt_module_name(self):
1707*9c5db199SXin Li        """ Return bluetooth module name for non-USB devices
1708*9c5db199SXin Li
1709*9c5db199SXin Li        @returns: Name of the Bluetooth module (or string read from device on
1710*9c5db199SXin Li                  success); '' on failure
1711*9c5db199SXin Li        """
1712*9c5db199SXin Li        return self._proxy.get_bt_module_name()
1713*9c5db199SXin Li
1714*9c5db199SXin Li    @proxy_thread_safe
1715*9c5db199SXin Li    def get_chipset_name(self):
1716*9c5db199SXin Li        """ Get the name of BT/WiFi chipset on this host
1717*9c5db199SXin Li
1718*9c5db199SXin Li        @returns chipset name if successful else ''
1719*9c5db199SXin Li        """
1720*9c5db199SXin Li        return self._proxy.get_chipset_name()
1721*9c5db199SXin Li
1722*9c5db199SXin Li    @proxy_thread_safe
1723*9c5db199SXin Li    def get_device_utc_time(self):
1724*9c5db199SXin Li        """ Get the current device time in UTC. """
1725*9c5db199SXin Li        return datetime.strptime(self._proxy.get_device_utc_time(),
1726*9c5db199SXin Li                                 self.STANDARD_DATE_FORMAT)
1727*9c5db199SXin Li
1728*9c5db199SXin Li    @proxy_thread_safe
1729*9c5db199SXin Li    def get_bt_usb_disconnect_str(self):
1730*9c5db199SXin Li        """ Return the expected log error on USB disconnect
1731*9c5db199SXin Li
1732*9c5db199SXin Li        Locate the descriptor that will be used from the list of all usb
1733*9c5db199SXin Li        descriptors associated with our bluetooth chip, and format into the
1734*9c5db199SXin Li        expected string error for USB disconnect
1735*9c5db199SXin Li
1736*9c5db199SXin Li        @returns: string representing expected usb disconnect log entry if usb
1737*9c5db199SXin Li                  device could be identified, None otherwise
1738*9c5db199SXin Li        """
1739*9c5db199SXin Li        return self._proxy.get_bt_usb_disconnect_str()
1740*9c5db199SXin Li
1741*9c5db199SXin Li    @proxy_thread_safe
1742*9c5db199SXin Li    def close(self, close_host=True):
1743*9c5db199SXin Li        """Tear down state associated with the client.
1744*9c5db199SXin Li
1745*9c5db199SXin Li        @param close_host: If True, shut down the xml rpc server by closing the
1746*9c5db199SXin Li            underlying host object (which also shuts down all other xml rpc
1747*9c5db199SXin Li            servers running on the DUT). Otherwise, only shut down the
1748*9c5db199SXin Li            bluetooth device xml rpc server, which can be desirable if the host
1749*9c5db199SXin Li            object and/or other xml rpc servers need to be used afterwards.
1750*9c5db199SXin Li        """
1751*9c5db199SXin Li        # Turn off the discoverable flag since it may affect future tests.
1752*9c5db199SXin Li        self._proxy.set_discoverable(False)
1753*9c5db199SXin Li        # Reset the adapter and leave it on.
1754*9c5db199SXin Li        self._proxy.reset_on()
1755*9c5db199SXin Li        # This kills the RPC server.
1756*9c5db199SXin Li        if close_host:
1757*9c5db199SXin Li            self.host.close()
1758*9c5db199SXin Li        elif hasattr(self, '_bt_direct_proxy'):
1759*9c5db199SXin Li            self.host.rpc_server_tracker.disconnect(
1760*9c5db199SXin Li                    constants.BLUETOOTH_DEVICE_XMLRPC_SERVER_PORT)
1761*9c5db199SXin Li
1762*9c5db199SXin Li
1763*9c5db199SXin Li    @proxy_thread_safe
1764*9c5db199SXin Li    def policy_get_service_allow_list(self):
1765*9c5db199SXin Li        """Get the service allow list for enterprise policy.
1766*9c5db199SXin Li
1767*9c5db199SXin Li        @returns: array of strings representing the allowed service UUIDs.
1768*9c5db199SXin Li        """
1769*9c5db199SXin Li        return self._proxy.policy_get_service_allow_list()
1770*9c5db199SXin Li
1771*9c5db199SXin Li
1772*9c5db199SXin Li    @proxy_thread_safe
1773*9c5db199SXin Li    def policy_set_service_allow_list(self, uuids):
1774*9c5db199SXin Li        """Get the service allow list for enterprise policy.
1775*9c5db199SXin Li
1776*9c5db199SXin Li        @param uuids: a string representing the uuids
1777*9c5db199SXin Li                      e.g., "0x1234,0xabcd" or ""
1778*9c5db199SXin Li
1779*9c5db199SXin Li        @returns: (True, '') on success, (False, '<error>') on failure
1780*9c5db199SXin Li        """
1781*9c5db199SXin Li        return self._proxy.policy_set_service_allow_list(uuids)
1782*9c5db199SXin Li
1783*9c5db199SXin Li    @proxy_thread_safe
1784*9c5db199SXin Li    def policy_get_device_affected(self, device_address):
1785*9c5db199SXin Li        """Get if the device is affected by enterprise policy.
1786*9c5db199SXin Li
1787*9c5db199SXin Li        @param device_address: address of the device
1788*9c5db199SXin Li                               e.g. '6C:29:95:1A:D4:6F'
1789*9c5db199SXin Li
1790*9c5db199SXin Li        @returns: True if the device is affected by the enterprise policy.
1791*9c5db199SXin Li                  False if not. None if the device is not found.
1792*9c5db199SXin Li        """
1793*9c5db199SXin Li        return self._proxy.policy_get_device_affected(device_address)
1794