Ejemplo n.º 1
0
    def setup_class(self):
        if not super(BtCarPbapTest, self).setup_class():
            return False
        self.pce = self.android_devices[0]
        self.pse = self.android_devices[1]
        self.pse2 = self.android_devices[2]
        self.contacts_destination_path = self.log_path + "/"

        permissions_list = [
            "android.permission.READ_CONTACTS",
            "android.permission.WRITE_CONTACTS",
            "android.permission.READ_EXTERNAL_STORAGE"
        ]
        for device in self.android_devices:
            for permission in permissions_list:
                device.adb.shell(
                    "pm grant com.google.android.contacts {}".format(
                        permission))

        # Pair the devices.
        # This call may block until some specified timeout in bt_test_utils.py.
        # Grace time inbetween stack state changes
        if not bt_test_utils.pair_pri_to_sec(self.pce, self.pse):
            self.log.error("Failed to pair.")
            return False
        time.sleep(3)
        if not bt_test_utils.pair_pri_to_sec(self.pce, self.pse2):
            self.log.error("Failed to pair.")
            return False

        # Disable the HFP and A2DP profiles. This will ensure only PBAP
        # gets connected. Also, this will eliminate the auto-connect loop.
        car_bt_utils.set_car_profile_priorities_off(self.pce, self.pse)
        car_bt_utils.set_car_profile_priorities_off(self.pce, self.pse2)

        # Enable PBAP on PSE & PCE.

        self.pse.droid.bluetoothChangeProfileAccessPermission(
            self.pce.droid.bluetoothGetLocalAddress(),
            BtEnum.BluetoothProfile.PBAP_SERVER.value,
            BtEnum.BluetoothAccessLevel.ACCESS_ALLOWED.value)

        self.pse2.droid.bluetoothChangeProfileAccessPermission(
            self.pce.droid.bluetoothGetLocalAddress(),
            BtEnum.BluetoothProfile.PBAP_SERVER.value,
            BtEnum.BluetoothAccessLevel.ACCESS_ALLOWED.value)

        bt_test_utils.set_profile_priority(
            self.pce, self.pse, [BtEnum.BluetoothProfile.PBAP_CLIENT],
            BtEnum.BluetoothPriorityLevel.PRIORITY_ON)
        bt_test_utils.set_profile_priority(
            self.pce, self.pse2, [BtEnum.BluetoothProfile.PBAP_CLIENT],
            BtEnum.BluetoothPriorityLevel.PRIORITY_ON)

        return True
    def setup_class(self):
        # AVRCP roles
        self.CT = self.android_devices[0]
        self.TG = self.android_devices[1]
        # A2DP roles for the same devices
        self.SNK = self.CT
        self.SRC = self.TG

        # Setup devices
        bt_test_utils.setup_multiple_devices_for_bt_test([self.CT, self.TG])

        self.btAddrCT = self.CT.droid.bluetoothGetLocalAddress()
        self.btAddrTG = self.TG.droid.bluetoothGetLocalAddress()

        # Additional time from the stack reset in setup.
        time.sleep(4)
        # Pair the devices.
        if not bt_test_utils.pair_pri_to_sec(
                self.CT, self.TG, attempts=4, auto_confirm=False):
            self.log.error("Failed to pair")
            return False

        # Disable all
        car_bt_utils.set_car_profile_priorities_off(self.SNK, self.SRC)

        # Enable A2DP
        bt_test_utils.set_profile_priority(
            self.SNK, self.SRC, [BtEnum.BluetoothProfile.A2DP_SINK],
            BtEnum.BluetoothPriorityLevel.PRIORITY_ON)
    def test_factory_reset_bluetooth(self):
        """Test that BluetoothAdapter.factoryReset removes bonded devices

        After having bonded devices, call the factoryReset method
        in BluetoothAdapter to clear all bonded devices. Verify that
        no bonded devices exist after calling function.

        Steps:
        1. Two Android devices should bond successfully.
        2. Factory Reset Bluetooth on dut.
        3. Verify that there are no bonded devices on dut.

        Expected Result:
        BluetoothAdapter should not have any bonded devices.

        Returns:
          Pass if True
          Fail if False

        TAGS: Bluetooth, Factory Reset
        Priority: 2
        """
        if not pair_pri_to_sec(self.pri_dut, self.sec_dut, attempts=1):
            self.log.error("Failed to bond devices.")
            return False
        if not self.pri_dut.droid.bluetoothFactoryReset():
            self.log.error("BluetoothAdapter failed to factory reset.")
        self.log.info("Verifying There are no bonded devices.")
        if len(self.pri_dut.droid.bluetoothGetBondedDevices()) > 0:
            print(self.pri_dut.droid.bluetoothGetBondedDevices())
            self.log.error("Bonded devices still exist.")
            return False
        return True
 def setup_class(self):
     super(BluetoothCarHfpBaseTest, self).setup_class()
     if not "sim_conf_file" in self.user_params.keys():
         self.log.error("Missing mandatory user config \"sim_conf_file\"!")
         return False
     sim_conf_file = self.user_params["sim_conf_file"][0]
     if not os.path.isfile(sim_conf_file):
         sim_conf_file = os.path.join(
             self.user_params[Config.key_config_path.value], sim_conf_file)
         if not os.path.isfile(sim_conf_file):
             self.log.error("Unable to load user config " + sim_conf_file +
                            " from test config file.")
             return False
     setup_droid_properties(self.log, self.ag, sim_conf_file)
     self.ag_phone_number = get_phone_number(self.log, self.ag)
     self.ag.log.info("ag tel: {}".format(self.ag_phone_number))
     if self.re:
         setup_droid_properties(self.log, self.re, sim_conf_file)
         self.re_phone_number = get_phone_number(self.log, self.re)
         self.re.log.info("re tel: {}".format(self.re_phone_number))
     if self.re2:
         setup_droid_properties(self.log, self.re2, sim_conf_file)
         self.re2_phone_number = get_phone_number(self.log, self.re2)
         self.re2.log.info("re2 tel: {}".format(self.re2_phone_number))
     # Pair and connect the devices.
     # Grace time inbetween stack state changes
     time.sleep(5)
     if not pair_pri_to_sec(
             self.hf, self.ag, attempts=4, auto_confirm=False):
         self.log.error("Failed to pair")
         return False
     return True
Ejemplo n.º 5
0
    def setup_class(self):
        self.hf = self.android_devices[0]
        self.ag = self.android_devices[1]
        self.re = self.android_devices[2]
        self.ag_phone_number = "tel:{}".format(
            self.ag.droid.telephonyGetLine1Number())
        self.re_phone_number = "tel:{}".format(
            self.re.droid.telephonyGetLine1Number())
        self.log.info("ag tel: {} re tel: {}".format(self.ag_phone_number,
                                                     self.re_phone_number))

        # Setup includes pairing and connecting the devices.
        bt_test_utils.setup_multiple_devices_for_bt_test([self.hf, self.ag])
        bt_test_utils.reset_bluetooth([self.hf, self.ag])

        # Pair and connect the devices.
        if not bt_test_utils.pair_pri_to_sec(self.hf.droid, self.ag.droid):
            self.log.error("Failed to pair")
            return False

        # Connect the devices now, try twice.
        attempts = 2
        connected = False
        while attempts > 0 and not connected:
            connected = bt_test_utils.connect_pri_to_sec(
                self.log, self.hf, self.ag.droid,
                set([BtEnum.BluetoothProfile.HEADSET_CLIENT.value]))
            self.log.info("Connected {}".format(connected))
            attempts -= 1
        return connected
Ejemplo n.º 6
0
    def setup_class(self):
        if not super(BtCarMediaPassthroughTest, self).setup_class():
            return False
        # AVRCP roles
        self.CT = self.android_devices[0]
        self.TG = self.android_devices[1]
        # A2DP roles for the same devices
        self.SNK = self.CT
        self.SRC = self.TG
        # To keep track of the state of the MediaBrowserService
        self.mediaBrowserServiceRunning = False
        self.btAddrCT = self.CT.droid.bluetoothGetLocalAddress()
        self.btAddrTG = self.TG.droid.bluetoothGetLocalAddress()
        self.android_music_path = ANDROID_MEDIA_PATH

        if not "local_media_path" in self.user_params.keys():
            self.log.error(
                "Missing mandatory user config \"local_media_path\"!")
            return False
        self.local_media_path = self.user_params["local_media_path"]
        if type(self.local_media_path) is list:
            self.log.info("Media ready to push as is.")
        elif not os.path.isdir(self.local_media_path):
            self.local_media_path = os.path.join(
                self.user_params[Config.key_config_path.value],
                self.local_media_path)
            if not os.path.isdir(self.local_media_path):
                self.log.error("Unable to load user config " +
                               self.local_media_path +
                               " from test config file.")
                return False

        # Additional time from the stack reset in setup.
        time.sleep(4)
        # Pair and connect the devices.
        if not bt_test_utils.pair_pri_to_sec(
                self.CT, self.TG, attempts=4, auto_confirm=False):
            self.log.error("Failed to pair")
            return False

        # TODO - check for Avrcp Connection state as well.
        # For now, the passthrough tests will catch Avrcp Connection failures
        # But add an explicit test for it.
        bt_test_utils.connect_pri_to_sec(
            self.SNK, self.SRC, set([BtEnum.BluetoothProfile.A2DP_SINK.value]))

        # Push media files from self.local_media_path to ANDROID_MEDIA_PATH
        # Refer to note in the beginning of file
        if type(self.local_media_path) is list:
            for item in self.local_media_path:
                self.TG.adb.push("{} {}".format(item, self.android_music_path))
        else:
            self.TG.adb.push("{} {}".format(self.local_media_path,
                                            self.android_music_path))

        return True
Ejemplo n.º 7
0
    def test_simple_pairing(self):
        """
        Tests if after first pairing the remote device has the default
        priorities for A2DP and HFP.

        Steps:
        1. Pair the devices (do not connect)
        2. Check the priorities.

        Returns:
          Pass if True
          Fail if False

        Priority: 0
        """
        # Pair the devices.
        if not bt_test_utils.pair_pri_to_sec(
                self.car, self.ph, attempts=1, auto_confirm=False):
            self.log.error("cannot pair")
            return False

        # Sleep because priorities are not event driven.
        time.sleep(BOND_TO_SDP_WAIT)

        # Check that the default priority for HFP and A2DP is ON.
        ph_hfp_p = self.car.droid.bluetoothHfpClientGetPriority(
            self.ph.droid.bluetoothGetLocalAddress())
        if ph_hfp_p != BtEnum.BluetoothPriorityLevel.PRIORITY_ON.value:
            self.log.error("hfp {} priority {} expected {}".format(
                self.ph.serial, ph_hfp_p,
                BtEnum.BluetoothPriorityLevel.PRIORITY_ON.value))
            return False

        ph_a2dp_p = self.car.droid.bluetoothA2dpSinkGetPriority(
            self.ph.droid.bluetoothGetLocalAddress())
        if ph_a2dp_p != BtEnum.BluetoothPriorityLevel.PRIORITY_ON.value:
            self.log.error("a2dp {} priority {} expected {}".format(
                self.ph.serial, ph_a2dp_p,
                BtEnum.BluetoothPriorityLevel.PRIORITY_ON.value))
            return False

        ph_pbap_p = self.car.droid.bluetoothPbapClientGetPriority(
            self.ph.droid.bluetoothGetLocalAddress())
        if ph_pbap_p != BtEnum.BluetoothPriorityLevel.PRIORITY_ON.value:
            self.log.error("pbap {} priority {} expected {}".format(
                self.ph.serial, ph_pbap_p,
                BtEnum.BluetoothPriorityLevel.PRIORITY_ON.value))
            return False
        return True
Ejemplo n.º 8
0
    def test_pair_bluetooth_stress(self):
        """Stress test for pairing BT devices.

        Test the integrity of Bluetooth pairing.

        1. Primary device discover the secondary device
        2. Primary device tries to pair to secondary device
        3. Pair two devices after verifying pin number on both devices are equal
        4. Verify both devices are paired
        5. Unpair devices.
        6. Verify devices unpaired.
        7. Repeat steps 1-6 100 times.


        Expected Result:
        Each iteration of toggling Bluetooth pairing and unpairing
        should succeed.

        Returns:
          Pass if True
          Fail if False

        TAGS: Classic, Stress
        Priority: 1
        """
        for n in range(self.iterations):
            self.log.info("Pair bluetooth iteration {}.".format(n + 1))
            self.start_timer()
            if (not pair_pri_to_sec(self.android_devices[0],
                                    self.android_devices[1],
                                    attempts=1,
                                    auto_confirm=False)):
                self.log.error("Failed to bond devices.")
                return False
            self.log.info("Total time (ms): {}".format(self.end_timer()))
            # A device bond will trigger a number of system routines that need
            # to settle before unbond
            time.sleep(2)
            for ad in self.android_devices:
                if not clear_bonded_devices(ad):
                    return False
                # Necessary sleep time for entries to update unbonded state
                time.sleep(2)
                bonded_devices = ad.droid.bluetoothGetBondedDevices()
                if len(bonded_devices) > 0:
                    self.log.error(
                        "Failed to unbond devices: {}".format(bonded_devices))
                    return False
        return True
    def setup_test(self):
        # Reset the devices in a clean state.
        bt_test_utils.setup_multiple_devices_for_bt_test(self.android_devices)
        bt_test_utils.reset_bluetooth(self.android_devices)
        for a in self.android_devices:
            a.ed.clear_all_events()

        # Pair the devices.
        # This call may block until some specified timeout in bt_test_utils.py.
        result = bt_test_utils.pair_pri_to_sec(self.car.droid, self.ph.droid)

        asserts.assert_true(result, "pair_pri_to_sec returned false.");

        # Check for successful setup of test.
        devices = self.car.droid.bluetoothGetBondedDevices()
        asserts.assert_equal(len(devices), 1, "pair_pri_to_sec succeeded but no bonded devices.")
Ejemplo n.º 10
0
    def test_pair_bluetooth_stress(self):
        """Stress test for pairing BT devices.

        Test the integrity of Bluetooth pairing.

        Steps:
        1. Pair two Android devices
        2. Verify both devices are paired
        3. Unpair devices.
        4. Verify devices unpaired.
        5. Repeat steps 1-4 100 times.

        Expected Result:
        Each iteration of toggling Bluetooth pairing and unpairing
        should succeed.

        Returns:
          Pass if True
          Fail if False

        TAGS: Classic, Stress
        Priority: 1
        """
        for n in range(self.iterations):
            self.log.info("Pair bluetooth iteration {}.".format(n + 1))
            self.start_timer()
            if (not pair_pri_to_sec(self.android_devices[0].droid,
                                self.android_devices[1].droid)):
                self.log.error("Failed to bond devices.")
                return False
            self.log.info("Total time (ms): {}".format(self.end_timer()))
            for ad in self.android_devices:
                if not clear_bonded_devices(ad):
                    return False
                # Necessary sleep time for entries to update unbonded state
                time.sleep(1)
                bonded_devices = ad.droid.bluetoothGetBondedDevices()
                if len(bonded_devices) > 0:
                    self.log.error("Failed to unbond devices: {}".format(
                        bonded_devices))
                    return False
        return True
    def setup_class(self):
        super(BtOtaTest, self).setup_class()
        ota_updater.initialize(self.user_params, self.android_devices)
        self.dut = self.android_devices[0]
        self.pre_ota_name = self.dut.droid.bluetoothGetLocalName()
        self.pre_ota_address = self.dut.droid.bluetoothGetLocalAddress()
        self.sec_address = self.android_devices[
            1].droid.bluetoothGetLocalAddress()

        # Pairing devices
        if not pair_pri_to_sec(self.dut, self.android_devices[1]):
            raise signals.TestAbortClass(
                "Failed to bond devices prior to update")

        #Run OTA below, if ota fails then abort all tests
        try:
            ota_updater.update(self.dut)
        except Exception as err:
            raise signals.TestAbortClass(
                "Failed up apply OTA update. Aborting tests")
    def setup_class(self):
        self.car = self.android_devices[0]
        self.ph = self.android_devices[1]
        self.car_bt_addr = self.car.droid.bluetoothGetLocalAddress()
        self.ph_bt_addr = self.ph.droid.bluetoothGetLocalAddress()

        bt_test_utils.setup_multiple_devices_for_bt_test([self.car, self.ph])

        # Pair the devices.
        # This call may block until some specified timeout in bt_test_utils.py.
        result = bt_test_utils.pair_pri_to_sec(
            self.car, self.ph, auto_confirm=False)

        asserts.assert_true(result, "pair_pri_to_sec returned false.")

        # Check for successful setup of test.
        devices = self.car.droid.bluetoothGetBondedDevices()
        asserts.assert_equal(
            len(devices), 1,
            "pair_pri_to_sec succeeded but no bonded devices.")
    def test_pairing_metric(self):
        """Test if a pairing event generates the correct metric entry

        This test tries to pair two Bluetooth devices and dumps metrics after
        pairing. A correctly implemented stack should record 8 pairing events.

        Steps:
        1. Start pairing between two Bluetooth devices
        2. After pairing is done, dump and parse the metrics
        3. Compare the number of pairing events and the time stamp of the
        pairing event

        Expected Result:
        No errors, 8 pairing events should be generated
        Returns:
          Pass if True
          Fail if False

        TAGS: Classic
        Priority: 1
        """
        time_bonds = []
        for n in range(self.iterations):
            start_time = get_current_epoch_time()
            self.log.info("Pair bluetooth iteration {}.".format(n + 1))
            if (not pair_pri_to_sec(self.android_devices[0],
                                    self.android_devices[1],
                                    attempts=1,
                                    auto_confirm=False)):
                self.log.error("Failed to bond devices.")
                return False
            end_time = get_current_epoch_time()
            time_bonds.append((start_time, end_time))
            # A device bond will trigger a number of system routines that need
            # to settle before unbond
            time.sleep(2)
            for ad in self.android_devices:
                if not clear_bonded_devices(ad):
                    return False
                # Necessary sleep time for entries to update unbonded state
                time.sleep(2)
                bonded_devices = ad.droid.bluetoothGetBondedDevices()
                if len(bonded_devices) > 0:
                    self.log.error(
                        "Failed to unbond devices: {}".format(bonded_devices))
                    return False
        end_time = get_current_epoch_time()
        bluetooth_logs, bluetooth_logs_ascii = \
            self.collect_bluetooth_manager_metrics_logs(
                [self.android_devices[0]])
        bluetooth_log = bluetooth_logs[0]
        bluetooth_log_ascii = bluetooth_logs_ascii[0]
        asserts.assert_equal(len(bluetooth_log.pair_event),
                             8,
                             extras=bluetooth_log_ascii)
        for pair_event in bluetooth_log.pair_event:
            t = pair_event.event_time_millis
            asserts.assert_true(
                start_time <= t <= end_time,
                "Event time %d not within limit [%d, %d]" %
                (t, start_time, end_time))
            device_info = pair_event.device_paired_with
            asserts.assert_true(device_info, "Device info is none")
            asserts.assert_equal(
                device_info.device_type, self.android_devices[0].
                bluetooth_proto_module.DeviceInfo.DEVICE_TYPE_BREDR,
                "Device type does not match")
Ejemplo n.º 14
0
    def test_repairing(self):
        """
        Tests that even if we modify the priorities, on unpair and pair
        we will reset the priorities.

        Steps:
        1. Pair the devices (do not connect)
        2. Unset the priorities for HFP and A2DP
        3. Pair again
        4. Check the priorities, they should be set to default.

        Returns:
          Pass if True
          Fail if False

        Priority: 0
        """
        # Pair the devices.
        self.log.info("Pairing the devices ...")
        if not bt_test_utils.pair_pri_to_sec(
                self.car, self.ph, attempts=1, auto_confirm=False):
            self.log.error("Failed to pair devices.")
            return False

        # Timed wait for the profile priorities to propagate.
        time.sleep(BOND_TO_SDP_WAIT)

        # Set the priority to OFF for ALL car profiles.
        self.car.log.info("Set priorities off ...")
        car_bt_utils.set_car_profile_priorities_off(self.car, self.ph)

        # Now unpair the devices.
        self.log.info("Resetting the devices ...")
        for ad in self.android_devices:
            bt_test_utils.clear_bonded_devices(ad)
        # Give the stack time to unbond.
        time.sleep(UNBOND_TIMEOUT)

        # Pair them again!
        self.log.info("Pairing them again ...")
        if not bt_test_utils.pair_pri_to_sec(
                self.car, self.ph, attempts=1, auto_confirm=False):
            self.log.error("Faild to pair devices.")
            return False

        # Timed wait for the profile priorities to propagate.
        time.sleep(BOND_TO_SDP_WAIT)

        # Check the default priorities.
        ph_hfp_p = self.car.droid.bluetoothHfpClientGetPriority(
            self.ph.droid.bluetoothGetLocalAddress())
        if ph_hfp_p != BtEnum.BluetoothPriorityLevel.PRIORITY_ON.value:
            self.hf.log.error("HFP priority found: {}, expected: {}.".format(
                ph_hfp_p, BtEnum.BluetoothPriorityLevel.PRIORITY_ON.value))
            return False

        ph_a2dp_p = self.car.droid.bluetoothA2dpSinkGetPriority(
            self.ph.droid.bluetoothGetLocalAddress())
        if ph_a2dp_p != BtEnum.BluetoothPriorityLevel.PRIORITY_ON.value:
            self.ph.log.error("A2DP priority found: {}, expected {}.".format(
                ph_a2dp_p, BtEnum.BluetoothPriorityLevel.PRIORITY_ON.value))
            return False

        return True
    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
    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