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