#!/usr/bin/env python3.4 # # Copyright (C) 2017 The Android Open Source Project # # Licensed under the Apache License, Version 2.0 (the "License"); you may not # use this file except in compliance with the License. You may obtain a copy of # the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations under # the License. """ Bluetooth HID Device Test. """ from acts.base_test import BaseTestClass from acts.test_decorators import test_tracker_info from acts_contrib.test_utils.bt.BluetoothBaseTest import BluetoothBaseTest from acts_contrib.test_utils.bt.bt_test_utils import setup_multiple_devices_for_bt_test from acts_contrib.test_utils.bt.bt_test_utils import clear_bonded_devices from acts_contrib.test_utils.bt.bt_test_utils import pair_pri_to_sec from acts_contrib.test_utils.bt.bt_test_utils import hid_keyboard_report from acts_contrib.test_utils.bt.bt_test_utils import hid_device_send_key_data_report from acts_contrib.test_utils.bt.bt_constants import hid_connection_timeout from acts_contrib.test_utils.bt import bt_constants import time class HidDeviceTest(BluetoothBaseTest): tests = None default_timeout = 10 def setup_class(self): super().setup_class() self.host_ad = self.android_devices[0] self.device_ad = self.android_devices[1] def setup_test(self): for a in self.android_devices: if not clear_bonded_devices(a): return False for a in self.android_devices: a.ed.clear_all_events() i = 0 while not self.device_ad.droid.bluetoothHidDeviceIsReady(): time.sleep(1) i += 1 self.log.info("BluetoothHidDevice NOT Ready") if i == 10: return False if not self.device_ad.droid.bluetoothHidDeviceRegisterApp(): self.log.error("Device: registration failed") return False self.log.info("Device: registration done") return True def teardown_test(self): self.log.info("Device: unregister") self.device_ad.droid.bluetoothHidDeviceUnregisterApp() time.sleep(2) return True @BluetoothBaseTest.bt_test_wrap @test_tracker_info(uuid='047afb31-96c5-4a56-acb5-2b216037f35d') def test_hid(self): """Test HID Host and Device basic functionality Test the HID Device framework app registration; test HID Host sending report through HID control channel and interrupt channel. Steps: 1. Bluetooth HID device registers the Bluetooth input device service. 2. Get the MAC address of the HID host and HID device. 3. Establish HID profile connection from the HID host to the HID device. 4. HID host sends set_report, get_report, set_protocol, send_data to the HID device, and check if the HID device receives them. 5. HID device sends data report, report_error, reply_report commands to the HID host, and check if the HID host receives them. Expected Result: HID profile connection is successfully established; all commands and data reports are correctly handled. Returns: Pass if True Fail if False TAGS: Classic, HID Priority: 1 """ test_result = True pair_pri_to_sec(self.host_ad, self.device_ad, attempts=3) self.log.info("Device bonded: {}".format( self.device_ad.droid.bluetoothGetBondedDevices())) self.log.info("Host bonded: {}".format( self.host_ad.droid.bluetoothGetBondedDevices())) host_id = self.host_ad.droid.bluetoothGetLocalAddress() device_id = self.device_ad.droid.bluetoothGetLocalAddress() self.host_ad.droid.bluetoothConnectBonded(device_id) time.sleep(hid_connection_timeout) self.log.info("Device: connected: {}".format( self.device_ad.droid.bluetoothHidDeviceGetConnectedDevices())) self.log.info("Host: set report") self.host_ad.droid.bluetoothHidSetReport( device_id, 1, bt_constants.hid_default_set_report_payload) try: hid_device_callback = self.device_ad.ed.pop_event( bt_constants.hid_on_set_report_event, bt_constants.hid_default_event_timeout) except Empty as err: self.log.error("Callback not received: {}".format(err)) test_result = False self.log.info("Host: get report") self.host_ad.droid.bluetoothHidGetReport(device_id, 1, 1, 1024) try: hid_device_callback = self.device_ad.ed.pop_event( bt_constants.hid_on_get_report_event, bt_constants.hid_default_event_timeout) except Empty as err: self.log.error("Callback not received: {}".format(err)) test_result = False self.log.info("Host: set_protocol") self.host_ad.droid.bluetoothHidSetProtocolMode(device_id, 1) try: hid_device_callback = self.device_ad.ed.pop_event( bt_constants.hid_on_set_protocol_event, bt_constants.hid_default_event_timeout) except Empty as err: self.log.error("Callback not received: {}".format(err)) test_result = False self.log.info("Host: send data") self.host_ad.droid.bluetoothHidSendData(device_id, "It's a report") try: hid_device_callback = self.device_ad.ed.pop_event( bt_constants.hid_on_intr_data_event, bt_constants.hid_default_event_timeout) except Empty as err: self.log.error("Callback not received: {}".format(err)) test_result = False self.log.info("Device: send data report through interrupt channel") hid_device_send_key_data_report(host_id, self.device_ad, "04") hid_device_send_key_data_report(host_id, self.device_ad, "05") self.log.info("Device: report error") self.device_ad.droid.bluetoothHidDeviceReportError(host_id, 1) self.log.info("Device: reply report") self.device_ad.droid.bluetoothHidDeviceReplyReport( host_id, 1, 1, hid_keyboard_report("04")) self.log.info("Device bonded: {}".format( self.device_ad.droid.bluetoothGetBondedDevices())) self.log.info("Host bonded: {}".format( self.host_ad.droid.bluetoothGetBondedDevices())) return test_result @BluetoothBaseTest.bt_test_wrap @test_tracker_info(uuid='5ddc3eb1-2b8d-43b5-bdc4-ba577d90481d') def test_hid_host_unplug(self): """Test HID Host Virtual_cable_unplug Test the HID host and HID device handle Virtual_cable_unplug correctly Steps: 1. Bluetooth HID device registers the Bluetooth input device service. 2. Get the MAC address of the HID host and HID device. 3. Establish HID profile connection from the HID host to the HID device. 4. HID host sends virtual_cable_unplug command to the HID device. Expected Result: HID profile connection is successfully established; After the HID host sends virtual_cable_unplug command to the HID device, both disconnect each other, but not unpair. Returns: Pass if True Fail if False TAGS: Classic, HID Priority: 2 """ test_result = True pair_pri_to_sec(self.host_ad, self.device_ad, attempts=3) self.log.info("Device bonded: {}".format( self.device_ad.droid.bluetoothGetBondedDevices())) self.log.info("Host bonded: {}".format( self.host_ad.droid.bluetoothGetBondedDevices())) host_id = self.host_ad.droid.bluetoothGetLocalAddress() device_id = self.device_ad.droid.bluetoothGetLocalAddress() self.host_ad.droid.bluetoothConnectBonded(device_id) time.sleep(hid_connection_timeout) self.log.info("Device connected: {}".format( self.device_ad.droid.bluetoothHidDeviceGetConnectedDevices())) self.log.info("Device: send data report through interrupt channel") hid_device_send_key_data_report(host_id, self.device_ad, "04") hid_device_send_key_data_report(host_id, self.device_ad, "05") self.log.info("Host: virtual unplug") self.host_ad.droid.bluetoothHidVirtualUnplug(device_id) try: hid_device_callback = self.device_ad.ed.pop_event( bt_constants.hid_on_virtual_cable_unplug_event, bt_constants.hid_default_event_timeout) except Empty as err: self.log.error("Callback not received: {}".format(err)) test_result = False self.log.info("Device bonded: {}".format( self.device_ad.droid.bluetoothGetBondedDevices())) self.log.info("Host bonded: {}".format( self.host_ad.droid.bluetoothGetBondedDevices())) if self.device_ad.droid.bluetoothGetBondedDevices(): self.log.error("HID device didn't unbond on virtual_cable_unplug") test_result = False if self.host_ad.droid.bluetoothGetBondedDevices(): self.log.error("HID host didn't unbond on virtual_cable_unplug") test_result = False return test_result