1#!/usr/bin/env python3.4 2# 3# Copyright (C) 2017 The Android Open Source Project 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); you may not 6# use this file except in compliance with the License. You may obtain a copy of 7# the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 13# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 14# License for the specific language governing permissions and limitations under 15# the License. 16""" 17Bluetooth HID Device Test. 18""" 19 20from acts.base_test import BaseTestClass 21from acts.test_decorators import test_tracker_info 22from acts_contrib.test_utils.bt.BluetoothBaseTest import BluetoothBaseTest 23from acts_contrib.test_utils.bt.bt_test_utils import setup_multiple_devices_for_bt_test 24from acts_contrib.test_utils.bt.bt_test_utils import clear_bonded_devices 25from acts_contrib.test_utils.bt.bt_test_utils import pair_pri_to_sec 26from acts_contrib.test_utils.bt.bt_test_utils import hid_keyboard_report 27from acts_contrib.test_utils.bt.bt_test_utils import hid_device_send_key_data_report 28from acts_contrib.test_utils.bt.bt_constants import hid_connection_timeout 29from acts_contrib.test_utils.bt import bt_constants 30import time 31 32 33class HidDeviceTest(BluetoothBaseTest): 34 tests = None 35 default_timeout = 10 36 37 def setup_class(self): 38 super().setup_class() 39 self.host_ad = self.android_devices[0] 40 self.device_ad = self.android_devices[1] 41 42 def setup_test(self): 43 for a in self.android_devices: 44 if not clear_bonded_devices(a): 45 return False 46 for a in self.android_devices: 47 a.ed.clear_all_events() 48 49 i = 0 50 while not self.device_ad.droid.bluetoothHidDeviceIsReady(): 51 time.sleep(1) 52 i += 1 53 self.log.info("BluetoothHidDevice NOT Ready") 54 if i == 10: 55 return False 56 57 if not self.device_ad.droid.bluetoothHidDeviceRegisterApp(): 58 self.log.error("Device: registration failed") 59 return False 60 61 self.log.info("Device: registration done") 62 return True 63 64 def teardown_test(self): 65 self.log.info("Device: unregister") 66 self.device_ad.droid.bluetoothHidDeviceUnregisterApp() 67 time.sleep(2) 68 return True 69 70 @BluetoothBaseTest.bt_test_wrap 71 @test_tracker_info(uuid='047afb31-96c5-4a56-acb5-2b216037f35d') 72 def test_hid(self): 73 """Test HID Host and Device basic functionality 74 75 Test the HID Device framework app registration; test HID Host sending 76 report through HID control channel and interrupt channel. 77 78 Steps: 79 1. Bluetooth HID device registers the Bluetooth input device service. 80 2. Get the MAC address of the HID host and HID device. 81 3. Establish HID profile connection from the HID host to the HID device. 82 4. HID host sends set_report, get_report, set_protocol, send_data to 83 the HID device, and check if the HID device receives them. 84 5. HID device sends data report, report_error, reply_report commands to 85 the HID host, and check if the HID host receives them. 86 87 Expected Result: 88 HID profile connection is successfully established; all commands and 89 data reports are correctly handled. 90 91 Returns: 92 Pass if True 93 Fail if False 94 95 TAGS: Classic, HID 96 Priority: 1 97 """ 98 99 test_result = True 100 101 pair_pri_to_sec(self.host_ad, self.device_ad, attempts=3) 102 103 self.log.info("Device bonded: {}".format( 104 self.device_ad.droid.bluetoothGetBondedDevices())) 105 self.log.info("Host bonded: {}".format( 106 self.host_ad.droid.bluetoothGetBondedDevices())) 107 108 host_id = self.host_ad.droid.bluetoothGetLocalAddress() 109 device_id = self.device_ad.droid.bluetoothGetLocalAddress() 110 111 self.host_ad.droid.bluetoothConnectBonded(device_id) 112 113 time.sleep(hid_connection_timeout) 114 self.log.info("Device: connected: {}".format( 115 self.device_ad.droid.bluetoothHidDeviceGetConnectedDevices())) 116 117 self.log.info("Host: set report") 118 self.host_ad.droid.bluetoothHidSetReport( 119 device_id, 1, bt_constants.hid_default_set_report_payload) 120 121 try: 122 hid_device_callback = self.device_ad.ed.pop_event( 123 bt_constants.hid_on_set_report_event, 124 bt_constants.hid_default_event_timeout) 125 except Empty as err: 126 self.log.error("Callback not received: {}".format(err)) 127 test_result = False 128 129 self.log.info("Host: get report") 130 self.host_ad.droid.bluetoothHidGetReport(device_id, 1, 1, 1024) 131 132 try: 133 hid_device_callback = self.device_ad.ed.pop_event( 134 bt_constants.hid_on_get_report_event, 135 bt_constants.hid_default_event_timeout) 136 except Empty as err: 137 self.log.error("Callback not received: {}".format(err)) 138 test_result = False 139 140 self.log.info("Host: set_protocol") 141 self.host_ad.droid.bluetoothHidSetProtocolMode(device_id, 1) 142 143 try: 144 hid_device_callback = self.device_ad.ed.pop_event( 145 bt_constants.hid_on_set_protocol_event, 146 bt_constants.hid_default_event_timeout) 147 except Empty as err: 148 self.log.error("Callback not received: {}".format(err)) 149 test_result = False 150 151 self.log.info("Host: send data") 152 self.host_ad.droid.bluetoothHidSendData(device_id, "It's a report") 153 154 try: 155 hid_device_callback = self.device_ad.ed.pop_event( 156 bt_constants.hid_on_intr_data_event, 157 bt_constants.hid_default_event_timeout) 158 except Empty as err: 159 self.log.error("Callback not received: {}".format(err)) 160 test_result = False 161 162 self.log.info("Device: send data report through interrupt channel") 163 hid_device_send_key_data_report(host_id, self.device_ad, "04") 164 hid_device_send_key_data_report(host_id, self.device_ad, "05") 165 166 self.log.info("Device: report error") 167 self.device_ad.droid.bluetoothHidDeviceReportError(host_id, 1) 168 169 self.log.info("Device: reply report") 170 self.device_ad.droid.bluetoothHidDeviceReplyReport( 171 host_id, 1, 1, hid_keyboard_report("04")) 172 173 self.log.info("Device bonded: {}".format( 174 self.device_ad.droid.bluetoothGetBondedDevices())) 175 self.log.info("Host bonded: {}".format( 176 self.host_ad.droid.bluetoothGetBondedDevices())) 177 178 return test_result 179 180 @BluetoothBaseTest.bt_test_wrap 181 @test_tracker_info(uuid='5ddc3eb1-2b8d-43b5-bdc4-ba577d90481d') 182 def test_hid_host_unplug(self): 183 """Test HID Host Virtual_cable_unplug 184 185 Test the HID host and HID device handle Virtual_cable_unplug correctly 186 187 Steps: 188 1. Bluetooth HID device registers the Bluetooth input device service. 189 2. Get the MAC address of the HID host and HID device. 190 3. Establish HID profile connection from the HID host to the HID device. 191 4. HID host sends virtual_cable_unplug command to the HID device. 192 193 Expected Result: 194 HID profile connection is successfully established; After the HID host 195 sends virtual_cable_unplug command to the HID device, both disconnect 196 each other, but not unpair. 197 198 Returns: 199 Pass if True 200 Fail if False 201 202 TAGS: Classic, HID 203 Priority: 2 204 """ 205 206 test_result = True 207 pair_pri_to_sec(self.host_ad, self.device_ad, attempts=3) 208 209 self.log.info("Device bonded: {}".format( 210 self.device_ad.droid.bluetoothGetBondedDevices())) 211 self.log.info("Host bonded: {}".format( 212 self.host_ad.droid.bluetoothGetBondedDevices())) 213 214 host_id = self.host_ad.droid.bluetoothGetLocalAddress() 215 device_id = self.device_ad.droid.bluetoothGetLocalAddress() 216 217 self.host_ad.droid.bluetoothConnectBonded(device_id) 218 219 time.sleep(hid_connection_timeout) 220 self.log.info("Device connected: {}".format( 221 self.device_ad.droid.bluetoothHidDeviceGetConnectedDevices())) 222 223 self.log.info("Device: send data report through interrupt channel") 224 hid_device_send_key_data_report(host_id, self.device_ad, "04") 225 hid_device_send_key_data_report(host_id, self.device_ad, "05") 226 227 self.log.info("Host: virtual unplug") 228 self.host_ad.droid.bluetoothHidVirtualUnplug(device_id) 229 230 try: 231 hid_device_callback = self.device_ad.ed.pop_event( 232 bt_constants.hid_on_virtual_cable_unplug_event, 233 bt_constants.hid_default_event_timeout) 234 except Empty as err: 235 self.log.error("Callback not received: {}".format(err)) 236 test_result = False 237 238 self.log.info("Device bonded: {}".format( 239 self.device_ad.droid.bluetoothGetBondedDevices())) 240 self.log.info("Host bonded: {}".format( 241 self.host_ad.droid.bluetoothGetBondedDevices())) 242 243 if self.device_ad.droid.bluetoothGetBondedDevices(): 244 self.log.error("HID device didn't unbond on virtual_cable_unplug") 245 test_result = False 246 247 if self.host_ad.droid.bluetoothGetBondedDevices(): 248 self.log.error("HID host didn't unbond on virtual_cable_unplug") 249 test_result = False 250 251 return test_result 252 253