Bug 1223729 - HID Connection Implementation, r=jocelyn, sr=mrbkap
authorLouis Chang <lochang@mozilla.com>
Fri, 04 Dec 2015 11:58:55 +0800
changeset 288551 aff73b00706cba2c828db99ad0059448834523f8
parent 288550 acbe5c09bbb702586bd8c4b19c24d150e45f118a
child 288552 eceb5235a54da29b7280153f0a130eece3682d4e
push id18167
push userkwierso@gmail.com
push dateTue, 15 Mar 2016 00:40:50 +0000
treeherderfx-team@992db1cffc5c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjocelyn, mrbkap
bugs1223729
milestone48.0a1
Bug 1223729 - HID Connection Implementation, r=jocelyn, sr=mrbkap
dom/base/nsGkAtomList.h
dom/bluetooth/bluedroid/BluetoothDaemonHelpers.cpp
dom/bluetooth/bluedroid/BluetoothDaemonHelpers.h
dom/bluetooth/bluedroid/BluetoothDaemonHidInterface.cpp
dom/bluetooth/bluedroid/BluetoothDaemonHidInterface.h
dom/bluetooth/bluedroid/BluetoothDaemonInterface.cpp
dom/bluetooth/bluedroid/BluetoothDaemonInterface.h
dom/bluetooth/bluedroid/BluetoothHidManager.cpp
dom/bluetooth/bluedroid/BluetoothHidManager.h
dom/bluetooth/bluedroid/BluetoothServiceBluedroid.cpp
dom/bluetooth/bluez/BluetoothHidManager.cpp
dom/bluetooth/bluez/BluetoothHidManager.h
dom/bluetooth/common/BluetoothCommon.h
dom/bluetooth/common/BluetoothHidManager.cpp
dom/bluetooth/common/BluetoothHidManager.h
dom/bluetooth/common/BluetoothInterface.cpp
dom/bluetooth/common/BluetoothInterface.h
dom/bluetooth/common/BluetoothProfileController.cpp
dom/bluetooth/common/webapi/BluetoothAdapter.cpp
dom/bluetooth/common/webapi/BluetoothAdapter.h
dom/bluetooth/moz.build
dom/webidl/BluetoothAdapter.webidl
--- a/dom/base/nsGkAtomList.h
+++ b/dom/base/nsGkAtomList.h
@@ -793,16 +793,17 @@ GK_ATOM(onfullscreenchange, "onfullscree
 GK_ATOM(onfullscreenerror, "onfullscreenerror")
 GK_ATOM(onspeakerforcedchange, "onspeakerforcedchange")
 GK_ATOM(onget, "onget")
 GK_ATOM(ongroupchange, "ongroupchange")
 GK_ATOM(onhashchange, "onhashchange")
 GK_ATOM(onheadphoneschange, "onheadphoneschange")
 GK_ATOM(onheld, "onheld")
 GK_ATOM(onhfpstatuschanged, "onhfpstatuschanged")
+GK_ATOM(onhidstatuschanged, "onhidstatuschanged")
 GK_ATOM(onholding, "onholding")
 GK_ATOM(oniccchange, "oniccchange")
 GK_ATOM(oniccdetected, "oniccdetected")
 GK_ATOM(oniccinfochange, "oniccinfochange")
 GK_ATOM(oniccundetected, "oniccundetected")
 GK_ATOM(onincoming, "onincoming")
 GK_ATOM(oninput, "oninput")
 GK_ATOM(oninstall, "oninstall")
--- a/dom/bluetooth/bluedroid/BluetoothDaemonHelpers.cpp
+++ b/dom/bluetooth/bluedroid/BluetoothDaemonHelpers.cpp
@@ -510,16 +510,88 @@ Convert(int32_t aIn, BluetoothGattStatus
     aOut = GATT_STATUS_UNKNOWN_ERROR;
   } else {
     aOut = sGattStatus[aIn];
   }
   return NS_OK;
 }
 
 nsresult
+Convert(uint8_t aIn, BluetoothHidProtocolMode& aOut)
+{
+  static const BluetoothHidProtocolMode sMode[] = {
+    [0x00] = HID_PROTOCOL_MODE_REPORT,
+    [0x01] = HID_PROTOCOL_MODE_BOOT
+  };
+  if (aIn == 0xff) {
+    /* This case is handled separately to not populate
+     * |sMode| with empty entries. */
+    aOut = HID_PROTOCOL_MODE_UNSUPPORTED;
+    return NS_OK;
+  }
+  if (MOZ_HAL_IPC_CONVERT_WARN_IF(
+        aIn >= MOZ_ARRAY_LENGTH(sMode), uint8_t, BluetoothHidProtocolMode)) {
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
+  aOut = sMode[aIn];
+  return NS_OK;
+}
+
+nsresult
+Convert(uint8_t aIn, BluetoothHidConnectionState& aOut)
+{
+  static const BluetoothHidConnectionState sConnectionState[] = {
+    [0x00] = HID_CONNECTION_STATE_CONNECTED,
+    [0x01] = HID_CONNECTION_STATE_CONNECTING,
+    [0x02] = HID_CONNECTION_STATE_DISCONNECTED,
+    [0x03] = HID_CONNECTION_STATE_DISCONNECTING,
+    [0x04] = HID_CONNECTION_STATE_FAILED_MOUSE_FROM_HOST,
+    [0x05] = HID_CONNECTION_STATE_FAILED_KEYBOARD_FROM_HOST,
+    [0x06] = HID_CONNECTION_STATE_FAILED_TOO_MANY_DEVICES,
+    [0x07] = HID_CONNECTION_STATE_FAILED_NO_HID_DRIVER,
+    [0x08] = HID_CONNECTION_STATE_FAILED_GENERIC,
+    [0x09] = HID_CONNECTION_STATE_UNKNOWN
+  };
+  if (MOZ_HAL_IPC_CONVERT_WARN_IF(
+        aIn >= MOZ_ARRAY_LENGTH(sConnectionState),
+        uint8_t, BluetoothHidConnectionState)) {
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
+  aOut = sConnectionState[aIn];
+  return NS_OK;
+}
+
+nsresult
+Convert(uint8_t aIn, BluetoothHidStatus& aOut)
+{
+  static const BluetoothHidStatus sStatus[] = {
+    [0x00] = HID_STATUS_OK,
+    [0x01] = HID_STATUS_HANDSHAKE_DEVICE_NOT_READY,
+    [0x02] = HID_STATUS_HANDSHAKE_INVALID_REPORT_ID,
+    [0x03] = HID_STATUS_HANDSHAKE_TRANSACTION_NOT_SPT,
+    [0x04] = HID_STATUS_HANDSHAKE_INVALID_PARAMETER,
+    [0x05] = HID_STATUS_HANDSHAKE_GENERIC_ERROR,
+    [0x06] = HID_STATUS_GENERAL_ERROR,
+    [0x07] = HID_STATUS_SDP_ERROR,
+    [0x08] = HID_STATUS_SET_PROTOCOL_ERROR,
+    [0x09] = HID_STATUS_DEVICE_DATABASE_FULL,
+    [0x0a] = HID_STATUS_DEVICE_TYPE_NOT_SUPPORTED,
+    [0x0b] = HID_STATUS_NO_RESOURCES,
+    [0x0c] = HID_STATUS_AUTHENTICATION_FAILED,
+    [0x0d] = HID_STATUS_HDL
+  };
+  if (MOZ_HAL_IPC_CONVERT_WARN_IF(
+        aIn >= MOZ_ARRAY_LENGTH(sStatus), uint8_t, BluetoothHidStatus)) {
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
+  aOut = sStatus[aIn];
+  return NS_OK;
+}
+
+nsresult
 Convert(nsresult aIn, BluetoothStatus& aOut)
 {
   if (NS_SUCCEEDED(aIn)) {
     aOut = STATUS_SUCCESS;
   } else if (aIn == NS_ERROR_OUT_OF_MEMORY) {
     aOut = STATUS_NOMEM;
   } else {
     aOut = STATUS_FAIL;
@@ -976,16 +1048,57 @@ Convert(BluetoothGattWriteType aIn, int3
         int32_t)) {
     aOut = GATT_WRITE_TYPE_NORMAL; // silences compiler warning
     return NS_ERROR_ILLEGAL_VALUE;
   }
   aOut = sGattWriteType[aIn];
   return NS_OK;
 }
 
+nsresult
+Convert(BluetoothHidProtocolMode aIn, uint8_t& aOut)
+{
+  static const uint8_t sMode[] = {
+    [HID_PROTOCOL_MODE_REPORT] = 0x00,
+    [HID_PROTOCOL_MODE_BOOT] = 0x01
+  };
+  if (aIn == HID_PROTOCOL_MODE_UNSUPPORTED) {
+    /* This case is handled separately to not populate
+     * |sValue| with empty entries. */
+    aOut = 0xff;
+    return NS_OK;
+  }
+  if (MOZ_HAL_IPC_CONVERT_WARN_IF(
+        aIn >= MOZ_ARRAY_LENGTH(sMode), BluetoothHidProtocolMode, uint8_t)) {
+    aOut = 0x00; // silences compiler warning
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
+  aOut = sMode[aIn];
+  return NS_OK;
+}
+
+nsresult
+Convert(BluetoothHidReportType aIn, uint8_t& aOut)
+{
+  static const uint8_t sType[] = {
+    [0x00] = static_cast<BluetoothHidReportType>(0),
+    [HID_REPORT_TYPE_INPUT] = 0x01,
+    [HID_REPORT_TYPE_OUTPUT] = 0x02,
+    [HID_REPORT_TYPE_FEATURE] = 0x03
+  };
+  if (MOZ_HAL_IPC_CONVERT_WARN_IF(
+        aIn >= MOZ_ARRAY_LENGTH(sType),
+        BluetoothHidReportType, uint8_t)) {
+    aOut = 0x00; // silences compiler warning
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
+  aOut = sType[aIn];
+  return NS_OK;
+}
+
 /* |ConvertArray| is a helper for converting arrays. Pass an
  * instance of this structure as the first argument to |Convert|
  * to convert an array. The output type has to support the array
  * subscript operator.
  */
 template <typename T>
 struct ConvertArray
 {
@@ -1401,16 +1514,71 @@ PackPDU(BluetoothGattAuthReq aIn, Daemon
 }
 
 nsresult
 PackPDU(BluetoothGattWriteType aIn, DaemonSocketPDU& aPDU)
 {
   return PackPDU(PackConversion<BluetoothGattWriteType, int32_t>(aIn), aPDU);
 }
 
+nsresult
+PackPDU(const BluetoothHidInfoParam& aIn, DaemonSocketPDU& aPDU)
+{
+  if (MOZ_HAL_IPC_PACK_WARN_IF(
+        aIn.mDescriptorLength > BLUETOOTH_HID_MAX_DESC_LEN,
+        BluetoothHidInfoParam)) {
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
+
+  nsresult rv =  PackPDU(aIn.mAttributeMask,
+                         aIn.mSubclass,
+                         aIn.mApplicationId,
+                         aIn.mVendorId,
+                         aIn.mProductId,
+                         aIn.mVersion,
+                         aIn.mCountryCode,
+                         aIn.mDescriptorLength,
+                         aPDU);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  return PackPDU(
+    PackArray<uint8_t>(aIn.mDescriptorValue, aIn.mDescriptorLength), aPDU);
+}
+
+nsresult
+PackPDU(const BluetoothHidReport& aIn, DaemonSocketPDU& aPDU)
+{
+  uint8_t* reportData =
+    const_cast<uint8_t*>(aIn.mReportData.Elements());
+
+  nsresult rv = PackPDU(
+    PackConversion<uint32_t, uint16_t>(aIn.mReportData.Length()), aPDU);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  return PackPDU(
+    PackArray<uint8_t>(reportData, aIn.mReportData.Length()),
+    aPDU);
+}
+
+nsresult
+PackPDU(BluetoothHidProtocolMode aIn, DaemonSocketPDU& aPDU)
+{
+  return PackPDU(
+    PackConversion<BluetoothHidProtocolMode, uint8_t>(aIn), aPDU);
+}
+
+nsresult
+PackPDU(BluetoothHidReportType aIn, DaemonSocketPDU& aPDU)
+{
+  return PackPDU(
+    PackConversion<BluetoothHidReportType, uint8_t>(aIn), aPDU);
+}
+
 //
 // Unpacking
 //
 
 nsresult
 UnpackPDU(DaemonSocketPDU& aPDU, BluetoothA2dpAudioState& aOut)
 {
   return UnpackPDU(
@@ -1808,9 +1976,90 @@ UnpackPDU(DaemonSocketPDU& aPDU, Bluetoo
   rv = UnpackPDU(aPDU, aOut.mLength);
   if (NS_FAILED(rv)) {
     return rv;
   }
   /* unpack value */
   return aPDU.Read(aOut.mValue, aOut.mLength);
 }
 
+nsresult
+UnpackPDU(DaemonSocketPDU& aPDU, BluetoothHidInfoParam& aOut)
+{
+  /* unpack attribute mask */
+  nsresult rv = UnpackPDU(aPDU, aOut.mAttributeMask);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  /* unpack subclass */
+  rv = UnpackPDU(aPDU, aOut.mSubclass);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  /* unpack application id */
+  rv = UnpackPDU(aPDU, aOut.mApplicationId);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  /* unpack vendor id */
+  rv = UnpackPDU(aPDU, aOut.mVendorId);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  /* unpack product id */
+  rv = UnpackPDU(aPDU, aOut.mProductId);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  /* unpack version */
+  rv = UnpackPDU(aPDU, aOut.mVersion);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  /* unpack country code */
+  rv = UnpackPDU(aPDU, aOut.mCountryCode);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  /* unpack descriptor length */
+  rv = UnpackPDU(aPDU, aOut.mDescriptorLength);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  if (MOZ_HAL_IPC_PACK_WARN_IF(
+        aOut.mDescriptorLength > BLUETOOTH_HID_MAX_DESC_LEN,
+        BluetoothHidInfoParam)) {
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
+  /* unpack descriptor value */
+  return UnpackPDU(
+    aPDU,
+    UnpackArray<uint8_t>(aOut.mDescriptorValue, aOut.mDescriptorLength));
+}
+
+nsresult
+UnpackPDU(DaemonSocketPDU& aPDU, BluetoothHidReport& aOut)
+{
+  return UnpackPDU(aPDU, aOut.mReportData);
+}
+
+nsresult
+UnpackPDU(DaemonSocketPDU& aPDU, BluetoothHidProtocolMode& aOut)
+{
+  return UnpackPDU(
+    aPDU, UnpackConversion<uint8_t, BluetoothHidProtocolMode>(aOut));
+}
+
+nsresult
+UnpackPDU(DaemonSocketPDU& aPDU, BluetoothHidConnectionState& aOut)
+{
+  return UnpackPDU(
+    aPDU, UnpackConversion<uint8_t, BluetoothHidConnectionState>(aOut));
+}
+
+nsresult
+UnpackPDU(DaemonSocketPDU& aPDU, BluetoothHidStatus& aOut)
+{
+  return UnpackPDU(
+    aPDU, UnpackConversion<uint8_t, BluetoothHidStatus>(aOut));
+}
+
 END_BLUETOOTH_NAMESPACE
--- a/dom/bluetooth/bluedroid/BluetoothDaemonHelpers.h
+++ b/dom/bluetooth/bluedroid/BluetoothDaemonHelpers.h
@@ -169,16 +169,25 @@ Convert(uint8_t aIn, BluetoothSspVariant
 
 nsresult
 Convert(uint8_t aIn, BluetoothStatus& aOut);
 
 nsresult
 Convert(int32_t aIn, BluetoothAttributeHandle& aOut);
 
 nsresult
+Convert(uint8_t aIn, BluetoothHidProtocolMode& aOut);
+
+nsresult
+Convert(uint8_t aIn, BluetoothHidConnectionState& aOut);
+
+nsresult
+Convert(uint8_t aIn, BluetoothHidStatus& aOut);
+
+nsresult
 Convert(int32_t aIn, BluetoothGattStatus& aOut);
 
 nsresult
 Convert(const BluetoothAttributeHandle& aIn, int32_t& aOut);
 
 nsresult
 Convert(const BluetoothAttributeHandle& aIn, uint16_t& aOut);
 
@@ -252,16 +261,22 @@ nsresult
 Convert(BluetoothGattAuthReq aIn, uint8_t& aOut);
 
 nsresult
 Convert(BluetoothGattWriteType aIn, int32_t& aOut);
 
 nsresult
 Convert(nsresult aIn, BluetoothStatus& aOut);
 
+nsresult
+Convert(BluetoothHidProtocolMode aIn, uint8_t& aOut);
+
+nsresult
+Convert(BluetoothHidReportType aIn, uint8_t& aOut);
+
 //
 // Packing
 //
 
 nsresult
 PackPDU(const BluetoothAddress& aIn, DaemonSocketPDU& aPDU);
 
 nsresult
@@ -366,16 +381,28 @@ nsresult
 PackPDU(BluetoothGattAuthReq aIn, DaemonSocketPDU& aPDU);
 
 nsresult
 PackPDU(BluetoothGattWriteType aIn, DaemonSocketPDU& aPDU);
 
 nsresult
 PackPDU(BluetoothTransport aIn, DaemonSocketPDU& aPDU);
 
+nsresult
+PackPDU(const BluetoothHidInfoParam& aIn, DaemonSocketPDU& aPDU);
+
+nsresult
+PackPDU(const BluetoothHidReport& aIn, DaemonSocketPDU& aPDU);
+
+nsresult
+PackPDU(BluetoothHidProtocolMode aIn, DaemonSocketPDU& aPDU);
+
+nsresult
+PackPDU(BluetoothHidReportType aIn, DaemonSocketPDU& aPDU);
+
 /* This implementation of |PackPDU| packs |BluetoothUuid| in reversed order.
  * (ex. reversed GATT UUID, see bug 1171866)
  */
 inline nsresult
 PackPDU(const PackReversed<BluetoothUuid>& aIn, DaemonSocketPDU& aPDU)
 {
  return PackPDU(
    PackReversed<PackArray<uint8_t>>(
@@ -508,16 +535,31 @@ nsresult
 UnpackPDU(DaemonSocketPDU& aPDU, BluetoothGattReadParam& aOut);
 
 nsresult
 UnpackPDU(DaemonSocketPDU& aPDU, BluetoothGattWriteParam& aOut);
 
 nsresult
 UnpackPDU(DaemonSocketPDU& aPDU, BluetoothGattNotifyParam& aOut);
 
+nsresult
+UnpackPDU(DaemonSocketPDU& aPDU, BluetoothHidInfoParam& aOut);
+
+nsresult
+UnpackPDU(DaemonSocketPDU& aPDU, BluetoothHidReport& aOut);
+
+nsresult
+UnpackPDU(DaemonSocketPDU& aPDU, BluetoothHidProtocolMode& aOut);
+
+nsresult
+UnpackPDU(DaemonSocketPDU& aPDU, BluetoothHidConnectionState& aOut);
+
+nsresult
+UnpackPDU(DaemonSocketPDU& aPDU, BluetoothHidStatus& aOut);
+
 /* This implementation of |UnpackPDU| unpacks |BluetoothUuid| in reversed
  * order. (ex. reversed GATT UUID, see bug 1171866)
  */
 inline nsresult
 UnpackPDU(DaemonSocketPDU& aPDU, const UnpackReversed<BluetoothUuid>& aOut)
 {
   return UnpackPDU(
     aPDU,
new file mode 100644
--- /dev/null
+++ b/dom/bluetooth/bluedroid/BluetoothDaemonHidInterface.cpp
@@ -0,0 +1,677 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "BluetoothDaemonHidInterface.h"
+#include "mozilla/unused.h"
+
+BEGIN_BLUETOOTH_NAMESPACE
+
+using namespace mozilla::ipc;
+
+//
+// Hid module
+//
+
+BluetoothHidNotificationHandler*
+  BluetoothDaemonHidModule::sNotificationHandler;
+
+void
+BluetoothDaemonHidModule::SetNotificationHandler(
+  BluetoothHidNotificationHandler* aNotificationHandler)
+{
+  sNotificationHandler = aNotificationHandler;
+}
+
+void
+BluetoothDaemonHidModule::HandleSvc(
+  const DaemonSocketPDUHeader& aHeader, DaemonSocketPDU& aPDU,
+  DaemonSocketResultHandler* aRes)
+{
+  static void (BluetoothDaemonHidModule::* const HandleOp[])(
+    const DaemonSocketPDUHeader&, DaemonSocketPDU&,
+    DaemonSocketResultHandler*) = {
+    [0] = &BluetoothDaemonHidModule::HandleRsp,
+    [1] = &BluetoothDaemonHidModule::HandleNtf
+  };
+
+  MOZ_ASSERT(!NS_IsMainThread());
+
+  // Negate twice to map bit to 0/1
+  unsigned long isNtf = !!(aHeader.mOpcode & 0x80);
+
+  (this->*(HandleOp[isNtf]))(aHeader, aPDU, aRes);
+}
+
+// Commands
+//
+
+nsresult
+BluetoothDaemonHidModule::ConnectCmd(
+  const BluetoothAddress& aRemoteAddr, BluetoothHidResultHandler* aRes)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  nsAutoPtr<DaemonSocketPDU> pdu(
+    new DaemonSocketPDU(SERVICE_ID, OPCODE_CONNECT, 6)); // Address
+
+  nsresult rv = PackPDU(aRemoteAddr, *pdu);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  rv = Send(pdu, aRes);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  Unused << pdu.forget();
+  return NS_OK;
+}
+
+nsresult
+BluetoothDaemonHidModule::DisconnectCmd(
+  const BluetoothAddress& aRemoteAddr, BluetoothHidResultHandler* aRes)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  nsAutoPtr<DaemonSocketPDU> pdu(
+    new DaemonSocketPDU(SERVICE_ID, OPCODE_DISCONNECT, 6)); // Address
+
+  nsresult rv = PackPDU(aRemoteAddr, *pdu);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  rv = Send(pdu, aRes);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  Unused << pdu.forget();
+  return NS_OK;
+}
+
+nsresult
+BluetoothDaemonHidModule::VirtualUnplugCmd(
+  const BluetoothAddress& aRemoteAddr, BluetoothHidResultHandler* aRes)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  nsAutoPtr<DaemonSocketPDU> pdu(
+    new DaemonSocketPDU(SERVICE_ID, OPCODE_VIRTUAL_UNPLUG, 6)); // Address
+
+  nsresult rv = PackPDU(aRemoteAddr, *pdu);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  rv = Send(pdu, aRes);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  Unused << pdu.forget();
+  return NS_OK;
+}
+
+nsresult
+BluetoothDaemonHidModule::SetInfoCmd(
+  const BluetoothAddress& aRemoteAddr,
+  const BluetoothHidInfoParam& aHidInfoParam,
+  BluetoothHidResultHandler* aRes)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  nsAutoPtr<DaemonSocketPDU> pdu(
+    new DaemonSocketPDU(SERVICE_ID, OPCODE_SET_INFO, 0));
+
+  nsresult rv = PackPDU(aRemoteAddr, aHidInfoParam, *pdu);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  rv = Send(pdu, aRes);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  Unused << pdu.forget();
+  return NS_OK;
+}
+
+nsresult
+BluetoothDaemonHidModule::GetProtocolCmd(
+  const BluetoothAddress& aRemoteAddr,
+  BluetoothHidProtocolMode aHidProtocolMode,
+  BluetoothHidResultHandler* aRes)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  nsAutoPtr<DaemonSocketPDU> pdu(
+    new DaemonSocketPDU(SERVICE_ID, OPCODE_GET_PROTOCOL,
+                        6 + // Address
+                        1)); // Protocol Mode
+
+  nsresult rv = PackPDU(aRemoteAddr, aHidProtocolMode, *pdu);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  rv = Send(pdu, aRes);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  Unused << pdu.forget();
+  return NS_OK;
+}
+
+nsresult
+BluetoothDaemonHidModule::SetProtocolCmd(
+  const BluetoothAddress& aRemoteAddr,
+  BluetoothHidProtocolMode aHidProtocolMode,
+  BluetoothHidResultHandler* aRes)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  nsAutoPtr<DaemonSocketPDU> pdu(
+    new DaemonSocketPDU(SERVICE_ID, OPCODE_SET_PROTOCOL,
+                        6 + // Remote Address
+                        1)); // Protocol Mode
+
+  nsresult rv = PackPDU(aRemoteAddr, aHidProtocolMode, *pdu);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  rv = Send(pdu, aRes);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  Unused << pdu.forget();
+  return NS_OK;
+}
+
+nsresult
+BluetoothDaemonHidModule::GetReportCmd(
+  const BluetoothAddress& aRemoteAddr, BluetoothHidReportType aType,
+  uint8_t aReportId, uint16_t aBuffSize, BluetoothHidResultHandler* aRes)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  nsAutoPtr<DaemonSocketPDU> pdu(
+    new DaemonSocketPDU(SERVICE_ID, OPCODE_GET_REPORT,
+                        6 + // Address
+                        1 + // Report Type
+                        1 + // Report ID
+                        2)); // Buffer Size
+
+  nsresult rv = PackPDU(aRemoteAddr, aType, aReportId, aBuffSize, *pdu);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  rv = Send(pdu, aRes);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  Unused << pdu.forget();
+  return NS_OK;
+}
+
+nsresult
+BluetoothDaemonHidModule::SetReportCmd(
+  const BluetoothAddress& aRemoteAddr, BluetoothHidReportType aType,
+  const BluetoothHidReport& aReport, BluetoothHidResultHandler* aRes)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  nsAutoPtr<DaemonSocketPDU> pdu(
+    new DaemonSocketPDU(SERVICE_ID, OPCODE_SET_REPORT, 0));
+
+  nsresult rv = PackPDU(aRemoteAddr, aType, aReport, *pdu);
+
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  rv = Send(pdu, aRes);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  Unused << pdu.forget();
+  return NS_OK;
+}
+
+nsresult
+BluetoothDaemonHidModule::SendDataCmd(
+  const BluetoothAddress& aRemoteAddr, uint16_t aDataLen, const uint8_t* aData,
+  BluetoothHidResultHandler* aRes)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  nsAutoPtr<DaemonSocketPDU> pdu(
+    new DaemonSocketPDU(SERVICE_ID, OPCODE_SEND_DATA, 0));
+
+  nsresult rv = PackPDU(aRemoteAddr, aDataLen,
+                        PackArray<uint8_t>(aData, aDataLen), *pdu);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  rv = Send(pdu, aRes);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  Unused << pdu.forget();
+  return NS_OK;
+}
+
+// Responses
+//
+
+void
+BluetoothDaemonHidModule::ErrorRsp(
+  const DaemonSocketPDUHeader& aHeader,
+  DaemonSocketPDU& aPDU, BluetoothHidResultHandler* aRes)
+{
+  ErrorRunnable::Dispatch(
+    aRes, &BluetoothHidResultHandler::OnError, UnpackPDUInitOp(aPDU));
+}
+
+void
+BluetoothDaemonHidModule::ConnectRsp(
+  const DaemonSocketPDUHeader& aHeader,
+  DaemonSocketPDU& aPDU, BluetoothHidResultHandler* aRes)
+{
+  ResultRunnable::Dispatch(
+    aRes, &BluetoothHidResultHandler::Connect, UnpackPDUInitOp(aPDU));
+}
+
+void
+BluetoothDaemonHidModule::DisconnectRsp(
+  const DaemonSocketPDUHeader& aHeader,
+  DaemonSocketPDU& aPDU, BluetoothHidResultHandler* aRes)
+{
+  ResultRunnable::Dispatch(
+    aRes, &BluetoothHidResultHandler::Disconnect, UnpackPDUInitOp(aPDU));
+}
+
+void
+BluetoothDaemonHidModule::VirtualUnplugRsp(
+  const DaemonSocketPDUHeader& aHeader,
+  DaemonSocketPDU& aPDU, BluetoothHidResultHandler* aRes)
+{
+  ResultRunnable::Dispatch(
+    aRes, &BluetoothHidResultHandler::VirtualUnplug, UnpackPDUInitOp(aPDU));
+}
+
+void
+BluetoothDaemonHidModule::SetInfoRsp(
+  const DaemonSocketPDUHeader& aHeader,
+  DaemonSocketPDU& aPDU, BluetoothHidResultHandler* aRes)
+{
+  ResultRunnable::Dispatch(
+    aRes, &BluetoothHidResultHandler::SetInfo, UnpackPDUInitOp(aPDU));
+}
+
+void
+BluetoothDaemonHidModule::GetProtocolRsp(
+  const DaemonSocketPDUHeader& aHeader,
+  DaemonSocketPDU& aPDU, BluetoothHidResultHandler* aRes)
+{
+  ResultRunnable::Dispatch(
+    aRes, &BluetoothHidResultHandler::GetProtocol, UnpackPDUInitOp(aPDU));
+}
+
+void
+BluetoothDaemonHidModule::SetProtocolRsp(
+  const DaemonSocketPDUHeader& aHeader,
+  DaemonSocketPDU& aPDU, BluetoothHidResultHandler* aRes)
+{
+  ResultRunnable::Dispatch(
+    aRes, &BluetoothHidResultHandler::SetProtocol, UnpackPDUInitOp(aPDU));
+}
+
+void
+BluetoothDaemonHidModule::GetReportRsp(
+  const DaemonSocketPDUHeader& aHeader,
+  DaemonSocketPDU& aPDU, BluetoothHidResultHandler* aRes)
+{
+  ResultRunnable::Dispatch(
+    aRes, &BluetoothHidResultHandler::GetReport, UnpackPDUInitOp(aPDU));
+}
+
+void
+BluetoothDaemonHidModule::SetReportRsp(
+  const DaemonSocketPDUHeader& aHeader,
+  DaemonSocketPDU& aPDU, BluetoothHidResultHandler* aRes)
+{
+  ResultRunnable::Dispatch(
+    aRes, &BluetoothHidResultHandler::SetReport, UnpackPDUInitOp(aPDU));
+}
+
+void
+BluetoothDaemonHidModule::SendDataRsp(
+  const DaemonSocketPDUHeader& aHeader,
+  DaemonSocketPDU& aPDU, BluetoothHidResultHandler* aRes)
+{
+  ResultRunnable::Dispatch(
+    aRes, &BluetoothHidResultHandler::SendData, UnpackPDUInitOp(aPDU));
+}
+
+void
+BluetoothDaemonHidModule::HandleRsp(
+  const DaemonSocketPDUHeader& aHeader,
+  DaemonSocketPDU& aPDU, DaemonSocketResultHandler* aRes)
+{
+  static void (BluetoothDaemonHidModule::* const HandleRsp[])(
+    const DaemonSocketPDUHeader&,
+    DaemonSocketPDU&,
+    BluetoothHidResultHandler*) = {
+    [OPCODE_ERROR] = &BluetoothDaemonHidModule::ErrorRsp,
+    [OPCODE_CONNECT] = &BluetoothDaemonHidModule::ConnectRsp,
+    [OPCODE_DISCONNECT] = &BluetoothDaemonHidModule::DisconnectRsp,
+    [OPCODE_VIRTUAL_UNPLUG] = &BluetoothDaemonHidModule::VirtualUnplugRsp,
+    [OPCODE_SET_INFO] = &BluetoothDaemonHidModule::SetInfoRsp,
+    [OPCODE_GET_PROTOCOL] = &BluetoothDaemonHidModule::GetProtocolRsp,
+    [OPCODE_SET_PROTOCOL] = &BluetoothDaemonHidModule::SetProtocolRsp,
+    [OPCODE_GET_REPORT] = &BluetoothDaemonHidModule::GetReportRsp,
+    [OPCODE_SET_REPORT] = &BluetoothDaemonHidModule::SetReportRsp,
+    [OPCODE_SEND_DATA] = &BluetoothDaemonHidModule::SendDataRsp
+  };
+
+  MOZ_ASSERT(!NS_IsMainThread()); // I/O thread
+
+  if (NS_WARN_IF(!(aHeader.mOpcode < MOZ_ARRAY_LENGTH(HandleRsp))) ||
+      NS_WARN_IF(!HandleRsp[aHeader.mOpcode])) {
+    return;
+  }
+
+  RefPtr<BluetoothHidResultHandler> res =
+    static_cast<BluetoothHidResultHandler*>(aRes);
+
+  if (!res) {
+    return; // Return early if no result handler has been set for response
+  }
+
+  (this->*(HandleRsp[aHeader.mOpcode]))(aHeader, aPDU, res);
+}
+
+// Notifications
+//
+
+// Returns the current notification handler to a notification runnable
+class BluetoothDaemonHidModule::NotificationHandlerWrapper final
+{
+public:
+  typedef BluetoothHidNotificationHandler ObjectType;
+
+  static ObjectType* GetInstance()
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+
+    return sNotificationHandler;
+  }
+};
+
+void
+BluetoothDaemonHidModule::ConnectionStateNtf(
+  const DaemonSocketPDUHeader& aHeader, DaemonSocketPDU& aPDU)
+{
+  ConnectionStateNotification::Dispatch(
+    &BluetoothHidNotificationHandler::ConnectionStateNotification,
+    UnpackPDUInitOp(aPDU));
+}
+
+void
+BluetoothDaemonHidModule::HidInfoNtf(
+  const DaemonSocketPDUHeader& aHeader, DaemonSocketPDU& aPDU)
+{
+  HidInfoNotification::Dispatch(
+    &BluetoothHidNotificationHandler::HidInfoNotification,
+    UnpackPDUInitOp(aPDU));
+}
+
+void
+BluetoothDaemonHidModule::ProtocolModeNtf(
+  const DaemonSocketPDUHeader& aHeader, DaemonSocketPDU& aPDU)
+{
+  ProtocolModeNotification::Dispatch(
+    &BluetoothHidNotificationHandler::ProtocolModeNotification,
+    UnpackPDUInitOp(aPDU));
+}
+
+void
+BluetoothDaemonHidModule::IdleTimeNtf(
+  const DaemonSocketPDUHeader& aHeader, DaemonSocketPDU& aPDU)
+{
+  IdleTimeNotification::Dispatch(
+    &BluetoothHidNotificationHandler::IdleTimeNotification,
+    UnpackPDUInitOp(aPDU));
+}
+
+void
+BluetoothDaemonHidModule::GetReportNtf(
+  const DaemonSocketPDUHeader& aHeader, DaemonSocketPDU& aPDU)
+{
+  GetReportNotification::Dispatch(
+    &BluetoothHidNotificationHandler::GetReportNotification,
+    UnpackPDUInitOp(aPDU));
+}
+
+void
+BluetoothDaemonHidModule::VirtualUnplugNtf(
+  const DaemonSocketPDUHeader& aHeader, DaemonSocketPDU& aPDU)
+{
+  VirtualUnplugNotification::Dispatch(
+    &BluetoothHidNotificationHandler::VirtualUnplugNotification,
+    UnpackPDUInitOp(aPDU));
+}
+
+void
+BluetoothDaemonHidModule::HandshakeNtf(
+  const DaemonSocketPDUHeader& aHeader, DaemonSocketPDU& aPDU)
+{
+  HandshakeNotification::Dispatch(
+    &BluetoothHidNotificationHandler::HandshakeNotification,
+    UnpackPDUInitOp(aPDU));
+}
+
+void
+BluetoothDaemonHidModule::HandleNtf(
+  const DaemonSocketPDUHeader& aHeader, DaemonSocketPDU& aPDU,
+  DaemonSocketResultHandler* aRes)
+{
+  static void (BluetoothDaemonHidModule::* const HandleNtf[])(
+    const DaemonSocketPDUHeader&, DaemonSocketPDU&) = {
+      [0] = &BluetoothDaemonHidModule::ConnectionStateNtf,
+      [1] = &BluetoothDaemonHidModule::HidInfoNtf,
+      [2] = &BluetoothDaemonHidModule::ProtocolModeNtf,
+      [3] = &BluetoothDaemonHidModule::IdleTimeNtf,
+      [4] = &BluetoothDaemonHidModule::GetReportNtf,
+      [5] = &BluetoothDaemonHidModule::VirtualUnplugNtf,
+      [6] = &BluetoothDaemonHidModule::HandshakeNtf
+  };
+
+  MOZ_ASSERT(!NS_IsMainThread());
+
+  uint8_t index = aHeader.mOpcode - 0x81;
+
+  if (NS_WARN_IF(!(index < MOZ_ARRAY_LENGTH(HandleNtf))) ||
+      NS_WARN_IF(!HandleNtf[index])) {
+    return;
+  }
+
+  (this->*(HandleNtf[index]))(aHeader, aPDU);
+}
+
+//
+// Hid Interface
+//
+
+BluetoothDaemonHidInterface::BluetoothDaemonHidInterface(
+  BluetoothDaemonHidModule* aModule)
+  : mModule(aModule)
+{ }
+
+BluetoothDaemonHidInterface::~BluetoothDaemonHidInterface()
+{ }
+
+void
+BluetoothDaemonHidInterface::SetNotificationHandler(
+  BluetoothHidNotificationHandler* aNotificationHandler)
+{
+  MOZ_ASSERT(mModule);
+
+  mModule->SetNotificationHandler(aNotificationHandler);
+}
+
+/* Connect / Disconnect */
+
+void
+BluetoothDaemonHidInterface::Connect(
+  const BluetoothAddress& aBdAddr, BluetoothHidResultHandler* aRes)
+{
+  MOZ_ASSERT(mModule);
+
+  nsresult rv = mModule->ConnectCmd(aBdAddr, aRes);
+  if (NS_FAILED(rv)) {
+    DispatchError(aRes, rv);
+  }
+}
+
+void
+BluetoothDaemonHidInterface::Disconnect(
+  const BluetoothAddress& aBdAddr, BluetoothHidResultHandler* aRes)
+{
+  MOZ_ASSERT(mModule);
+
+  nsresult rv = mModule->DisconnectCmd(aBdAddr, aRes);
+  if (NS_FAILED(rv)) {
+    DispatchError(aRes, rv);
+  }
+}
+
+/* Virtual Unplug */
+
+void
+BluetoothDaemonHidInterface::VirtualUnplug(
+  const BluetoothAddress& aBdAddr, BluetoothHidResultHandler* aRes)
+{
+  MOZ_ASSERT(mModule);
+
+  nsresult rv = mModule->VirtualUnplugCmd(aBdAddr, aRes);
+
+  if (NS_FAILED(rv)) {
+    DispatchError(aRes, rv);
+  }
+}
+
+/* Set Info */
+
+void
+BluetoothDaemonHidInterface::SetInfo(
+  const BluetoothAddress& aBdAddr,
+  const BluetoothHidInfoParam& aHidInfoParam,
+  BluetoothHidResultHandler* aRes)
+{
+  MOZ_ASSERT(mModule);
+
+  nsresult rv = mModule->SetInfoCmd(aBdAddr, aHidInfoParam, aRes);
+
+  if (NS_FAILED(rv)) {
+    DispatchError(aRes, rv);
+  }
+}
+
+/* Protocol */
+
+void
+BluetoothDaemonHidInterface::GetProtocol(
+  const BluetoothAddress& aBdAddr,
+  BluetoothHidProtocolMode aHidProtocolMode, BluetoothHidResultHandler* aRes)
+{
+  MOZ_ASSERT(mModule);
+
+  nsresult rv = mModule->GetProtocolCmd(aBdAddr, aHidProtocolMode, aRes);
+
+  if (NS_FAILED(rv)) {
+    DispatchError(aRes, rv);
+  }
+}
+
+void
+BluetoothDaemonHidInterface::SetProtocol(
+  const BluetoothAddress& aBdAddr,
+  BluetoothHidProtocolMode aHidProtocolMode, BluetoothHidResultHandler* aRes)
+{
+  MOZ_ASSERT(mModule);
+
+  nsresult rv = mModule->SetProtocolCmd(aBdAddr, aHidProtocolMode, aRes);
+
+  if (NS_FAILED(rv)) {
+    DispatchError(aRes, rv);
+  }
+}
+
+/* Report */
+
+void
+BluetoothDaemonHidInterface::GetReport(
+  const BluetoothAddress& aBdAddr, BluetoothHidReportType aType,
+  uint8_t aReportId, uint16_t aBuffSize, BluetoothHidResultHandler* aRes)
+{
+  MOZ_ASSERT(mModule);
+
+  nsresult rv = mModule->GetReportCmd(
+    aBdAddr, aType, aReportId, aBuffSize, aRes);
+
+  if (NS_FAILED(rv)) {
+    DispatchError(aRes, rv);
+  }
+}
+
+void
+BluetoothDaemonHidInterface::SetReport(
+  const BluetoothAddress& aBdAddr, BluetoothHidReportType aType,
+  const BluetoothHidReport& aReport, BluetoothHidResultHandler* aRes)
+{
+  MOZ_ASSERT(mModule);
+
+  nsresult rv = mModule->SetReportCmd(
+    aBdAddr, aType, aReport, aRes);
+
+  if (NS_FAILED(rv)) {
+    DispatchError(aRes, rv);
+  }
+}
+
+/* Send Data */
+
+void
+BluetoothDaemonHidInterface::SendData(
+  const BluetoothAddress& aBdAddr, uint16_t aDataLen, const uint8_t* aData,
+  BluetoothHidResultHandler* aRes)
+{
+  MOZ_ASSERT(mModule);
+
+  nsresult rv = mModule->SendDataCmd(aBdAddr, aDataLen, aData, aRes);
+
+  if (NS_FAILED(rv)) {
+    DispatchError(aRes, rv);
+  }
+}
+
+void
+BluetoothDaemonHidInterface::DispatchError(
+  BluetoothHidResultHandler* aRes, BluetoothStatus aStatus)
+{
+  DaemonResultRunnable1<BluetoothHidResultHandler, void,
+                        BluetoothStatus, BluetoothStatus>::Dispatch(
+    aRes, &BluetoothHidResultHandler::OnError,
+    ConstantInitOp1<BluetoothStatus>(aStatus));
+}
+
+void
+BluetoothDaemonHidInterface::DispatchError(
+  BluetoothHidResultHandler* aRes, nsresult aRv)
+{
+  BluetoothStatus status;
+
+  if (NS_WARN_IF(NS_FAILED(Convert(aRv, status)))) {
+    status = STATUS_FAIL;
+  }
+  DispatchError(aRes, status);
+}
+
+END_BLUETOOTH_NAMESPACE
new file mode 100644
--- /dev/null
+++ b/dom/bluetooth/bluedroid/BluetoothDaemonHidInterface.h
@@ -0,0 +1,298 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_bluetooth_bluedroid_BluetoothDaemonHidInterface_h
+#define mozilla_dom_bluetooth_bluedroid_BluetoothDaemonHidInterface_h
+
+#include "BluetoothDaemonHelpers.h"
+#include "BluetoothInterface.h"
+#include "mozilla/ipc/DaemonRunnables.h"
+
+BEGIN_BLUETOOTH_NAMESPACE
+
+using mozilla::ipc::DaemonSocketPDU;
+using mozilla::ipc::DaemonSocketPDUHeader;
+using mozilla::ipc::DaemonSocketResultHandler;
+
+class BluetoothDaemonHidModule
+{
+public:
+  enum {
+    SERVICE_ID = 0x03
+  };
+
+  enum {
+    OPCODE_ERROR = 0x00,
+    OPCODE_CONNECT = 0x01,
+    OPCODE_DISCONNECT = 0x02,
+    OPCODE_VIRTUAL_UNPLUG = 0x03,
+    OPCODE_SET_INFO = 0x04,
+    OPCODE_GET_PROTOCOL = 0x05,
+    OPCODE_SET_PROTOCOL = 0x06,
+    OPCODE_GET_REPORT = 0x07,
+    OPCODE_SET_REPORT = 0x08,
+    OPCODE_SEND_DATA = 0x09
+  };
+
+  virtual nsresult Send(DaemonSocketPDU* aPDU,
+                        DaemonSocketResultHandler* aRes) = 0;
+
+  void SetNotificationHandler(
+    BluetoothHidNotificationHandler* aNotificationHandler);
+
+  //
+  // Commands
+  //
+
+  nsresult ConnectCmd(const BluetoothAddress& aBdAddr,
+                      BluetoothHidResultHandler* aRes);
+  nsresult DisconnectCmd(const BluetoothAddress& aBdAddr,
+                         BluetoothHidResultHandler* aRes);
+
+  /* Virtual Unplug */
+
+  nsresult VirtualUnplugCmd(const BluetoothAddress& aBdAddr,
+                            BluetoothHidResultHandler* aRes);
+
+  /* Set Info */
+
+  nsresult SetInfoCmd(
+    const BluetoothAddress& aBdAddr,
+    const BluetoothHidInfoParam& aHidInfoParam,
+    BluetoothHidResultHandler* aRes);
+
+  /* Protocol */
+
+  nsresult GetProtocolCmd(const BluetoothAddress& aBdAddr,
+                          BluetoothHidProtocolMode aHidProtocolMode,
+                          BluetoothHidResultHandler* aRes);
+  nsresult SetProtocolCmd(const BluetoothAddress& aBdAddr,
+                          BluetoothHidProtocolMode aHidProtocolMode,
+                          BluetoothHidResultHandler* aRes);
+
+  /* Report */
+
+  nsresult GetReportCmd(const BluetoothAddress& aBdAddr,
+                        BluetoothHidReportType aType,
+                        uint8_t aReportId,
+                        uint16_t aBuffSize,
+                        BluetoothHidResultHandler* aRes);
+  nsresult SetReportCmd(const BluetoothAddress& aBdAddr,
+                        BluetoothHidReportType aType,
+                        const BluetoothHidReport& aReport,
+                        BluetoothHidResultHandler* aRes);
+
+  /* Send Data */
+
+  nsresult SendDataCmd(const BluetoothAddress& aBdAddr,
+                       uint16_t aDataLen, const uint8_t* aData,
+                       BluetoothHidResultHandler* aRes);
+
+protected:
+  void HandleSvc(const DaemonSocketPDUHeader& aHeader,
+                 DaemonSocketPDU& aPDU,
+                 DaemonSocketResultHandler* aRes);
+
+  //
+  // Responses
+  //
+
+  typedef mozilla::ipc::DaemonResultRunnable0<
+    BluetoothHidResultHandler, void>
+    ResultRunnable;
+
+  typedef mozilla::ipc::DaemonResultRunnable1<
+    BluetoothHidResultHandler, void, BluetoothStatus, BluetoothStatus>
+    ErrorRunnable;
+
+  void ErrorRsp(const DaemonSocketPDUHeader& aHeader,
+                DaemonSocketPDU& aPDU,
+                BluetoothHidResultHandler* aRes);
+
+  void ConnectRsp(const DaemonSocketPDUHeader& aHeader,
+                  DaemonSocketPDU& aPDU,
+                  BluetoothHidResultHandler* aRes);
+
+  void DisconnectRsp(const DaemonSocketPDUHeader& aHeader,
+                     DaemonSocketPDU& aPDU,
+                     BluetoothHidResultHandler* aRes);
+
+  void VirtualUnplugRsp(const DaemonSocketPDUHeader& aHeader,
+                        DaemonSocketPDU& aPDU,
+                        BluetoothHidResultHandler* aRes);
+
+  void SetInfoRsp(const DaemonSocketPDUHeader& aHeader,
+                  DaemonSocketPDU& aPDU,
+                  BluetoothHidResultHandler* aRes);
+
+  void GetProtocolRsp(const DaemonSocketPDUHeader& aHeader,
+                      DaemonSocketPDU& aPDU,
+                      BluetoothHidResultHandler* aRes);
+
+  void SetProtocolRsp(const DaemonSocketPDUHeader& aHeader,
+                      DaemonSocketPDU& aPDU,
+                      BluetoothHidResultHandler* aRes);
+
+  void GetReportRsp(const DaemonSocketPDUHeader& aHeader,
+                    DaemonSocketPDU& aPDU,
+                    BluetoothHidResultHandler* aRes);
+
+  void SetReportRsp(const DaemonSocketPDUHeader& aHeader,
+                    DaemonSocketPDU& aPDU,
+                    BluetoothHidResultHandler* aRes);
+
+  void SendDataRsp(const DaemonSocketPDUHeader& aHeader,
+                   DaemonSocketPDU& aPDU,
+                   BluetoothHidResultHandler* aRes);
+
+  void HandleRsp(const DaemonSocketPDUHeader& aHeader,
+                 DaemonSocketPDU& aPDU,
+                 DaemonSocketResultHandler* aRes);
+
+  //
+  // Notifications
+  //
+
+  class NotificationHandlerWrapper;
+
+  typedef mozilla::ipc::DaemonNotificationRunnable2<
+    NotificationHandlerWrapper, void,
+    BluetoothAddress, BluetoothHidConnectionState,
+    const BluetoothAddress&, BluetoothHidConnectionState>
+    ConnectionStateNotification;
+
+  typedef mozilla::ipc::DaemonNotificationRunnable2<
+    NotificationHandlerWrapper, void,
+    BluetoothAddress, BluetoothHidInfoParam,
+    const BluetoothAddress&, const BluetoothHidInfoParam&>
+    HidInfoNotification;
+
+  typedef mozilla::ipc::DaemonNotificationRunnable3<
+    NotificationHandlerWrapper, void,
+    BluetoothAddress, BluetoothHidStatus, BluetoothHidProtocolMode,
+    const BluetoothAddress&, BluetoothHidStatus, BluetoothHidProtocolMode>
+    ProtocolModeNotification;
+
+  typedef mozilla::ipc::DaemonNotificationRunnable3<
+    NotificationHandlerWrapper, void,
+    BluetoothAddress, BluetoothHidStatus, uint16_t,
+    const BluetoothAddress&, BluetoothHidStatus, uint16_t>
+    IdleTimeNotification;
+
+  typedef mozilla::ipc::DaemonNotificationRunnable3<
+    NotificationHandlerWrapper, void,
+    BluetoothAddress, BluetoothHidStatus, BluetoothHidReport,
+    const BluetoothAddress&, BluetoothHidStatus,
+    const BluetoothHidReport&>
+    GetReportNotification;
+
+  typedef mozilla::ipc::DaemonNotificationRunnable2<
+    NotificationHandlerWrapper, void,
+    BluetoothAddress, BluetoothHidStatus,
+    const BluetoothAddress&, BluetoothHidStatus>
+    VirtualUnplugNotification;
+
+  typedef mozilla::ipc::DaemonNotificationRunnable2<
+    NotificationHandlerWrapper, void,
+    BluetoothAddress, BluetoothHidStatus,
+    const BluetoothAddress&, BluetoothHidStatus>
+    HandshakeNotification;
+
+  void ConnectionStateNtf(const DaemonSocketPDUHeader& aHeader,
+                          DaemonSocketPDU& aPDU);
+
+  void HidInfoNtf(const DaemonSocketPDUHeader& aHeader,
+                  DaemonSocketPDU& aPDU);
+
+  void ProtocolModeNtf(const DaemonSocketPDUHeader& aHeader,
+                       DaemonSocketPDU& aPDU);
+
+  void IdleTimeNtf(const DaemonSocketPDUHeader& aHeader,
+                   DaemonSocketPDU& aPDU);
+
+  void GetReportNtf(const DaemonSocketPDUHeader& aHeader,
+                    DaemonSocketPDU& aPDU);
+
+  void VirtualUnplugNtf(const DaemonSocketPDUHeader& aHeader,
+                        DaemonSocketPDU& aPDU);
+
+  void HandshakeNtf(const DaemonSocketPDUHeader& aHeader,
+                    DaemonSocketPDU& aPDU);
+
+  void HandleNtf(const DaemonSocketPDUHeader& aHeader,
+                 DaemonSocketPDU& aPDU,
+                 DaemonSocketResultHandler* aRes);
+
+  static BluetoothHidNotificationHandler* sNotificationHandler;
+};
+
+class BluetoothDaemonHidInterface final
+  : public BluetoothHidInterface
+{
+public:
+  BluetoothDaemonHidInterface(BluetoothDaemonHidModule* aModule);
+  ~BluetoothDaemonHidInterface();
+
+  void SetNotificationHandler(
+    BluetoothHidNotificationHandler* aNotificationHandler) override;
+
+  /* Connect / Disconnect */
+
+  void Connect(const BluetoothAddress& aBdAddr,
+               BluetoothHidResultHandler* aRes) override;
+  void Disconnect(const BluetoothAddress& aBdAddr,
+                  BluetoothHidResultHandler* aRes) override;
+
+  /* Virtual Unplug */
+
+  void VirtualUnplug(const BluetoothAddress& aBdAddr,
+                     BluetoothHidResultHandler* aRes) override;
+
+  /* Set Info */
+
+  void SetInfo(
+    const BluetoothAddress& aBdAddr,
+    const BluetoothHidInfoParam& aHidInfoParam,
+    BluetoothHidResultHandler* aRes) override;
+
+  /* Protocol */
+
+  void GetProtocol(const BluetoothAddress& aBdAddr,
+                   BluetoothHidProtocolMode aHidProtoclMode,
+                   BluetoothHidResultHandler* aRes) override;
+
+  void SetProtocol(const BluetoothAddress& aBdAddr,
+                   BluetoothHidProtocolMode aHidProtocolMode,
+                   BluetoothHidResultHandler* aRes) override;
+
+  /* Report */
+
+  void GetReport(const BluetoothAddress& aBdAddr,
+                 BluetoothHidReportType aType,
+                 uint8_t aReportId, uint16_t aBuffSize,
+                 BluetoothHidResultHandler* aRes) override;
+  void SetReport(const BluetoothAddress& aBdAddr,
+                 BluetoothHidReportType aType,
+                 const BluetoothHidReport& aReport,
+                 BluetoothHidResultHandler* aRes) override;
+
+  /* Send Data */
+
+  void SendData(const BluetoothAddress& aBdAddr,
+                uint16_t aDataLen, const uint8_t* aData,
+                BluetoothHidResultHandler* aRes) override;
+
+private:
+  void DispatchError(BluetoothHidResultHandler* aRes,
+                     BluetoothStatus aStatus);
+  void DispatchError(BluetoothHidResultHandler* aRes, nsresult aRv);
+
+  BluetoothDaemonHidModule* mModule;
+};
+
+END_BLUETOOTH_NAMESPACE
+
+#endif // mozilla_dom_bluetooth_bluedroid_BluetoothDaemonHidInterface_h
--- a/dom/bluetooth/bluedroid/BluetoothDaemonInterface.cpp
+++ b/dom/bluetooth/bluedroid/BluetoothDaemonInterface.cpp
@@ -9,16 +9,17 @@
 #include <fcntl.h>
 #include <stdlib.h>
 #include "BluetoothDaemonA2dpInterface.h"
 #include "BluetoothDaemonAvrcpInterface.h"
 #include "BluetoothDaemonCoreInterface.h"
 #include "BluetoothDaemonGattInterface.h"
 #include "BluetoothDaemonHandsfreeInterface.h"
 #include "BluetoothDaemonHelpers.h"
+#include "BluetoothDaemonHidInterface.h"
 #include "BluetoothDaemonSetupInterface.h"
 #include "BluetoothDaemonSocketInterface.h"
 #include "mozilla/Hal.h"
 #include "mozilla/ipc/DaemonRunnables.h"
 #include "mozilla/ipc/DaemonSocket.h"
 #include "mozilla/ipc/DaemonSocketConnector.h"
 #include "mozilla/ipc/ListenSocket.h"
 
@@ -75,16 +76,17 @@ class BluetoothDaemonProtocol final
   : public DaemonSocketIOConsumer
   , public BluetoothDaemonSetupModule
   , public BluetoothDaemonCoreModule
   , public BluetoothDaemonSocketModule
   , public BluetoothDaemonHandsfreeModule
   , public BluetoothDaemonA2dpModule
   , public BluetoothDaemonAvrcpModule
   , public BluetoothDaemonGattModule
+  , public BluetoothDaemonHidModule
 {
 public:
   BluetoothDaemonProtocol();
 
   void SetConnection(DaemonSocket* aConnection);
 
   // Outgoing PDUs
   //
@@ -119,16 +121,19 @@ private:
                      DaemonSocketPDU& aPDU,
                      DaemonSocketResultHandler* aUserData);
   void HandleAvrcpSvc(const DaemonSocketPDUHeader& aHeader,
                       DaemonSocketPDU& aPDU,
                       DaemonSocketResultHandler* aRes);
   void HandleGattSvc(const DaemonSocketPDUHeader& aHeader,
                      DaemonSocketPDU& aPDU,
                      DaemonSocketResultHandler* aRes);
+  void HandleHidSvc(const DaemonSocketPDUHeader& aHeader,
+                    DaemonSocketPDU& aPDU,
+                    DaemonSocketResultHandler* aRes);
 
   DaemonSocket* mConnection;
   nsTArray<RefPtr<DaemonSocketResultHandler>> mResQ;
 };
 
 BluetoothDaemonProtocol::BluetoothDaemonProtocol()
 { }
 
@@ -211,28 +216,37 @@ void
 BluetoothDaemonProtocol::HandleGattSvc(
   const DaemonSocketPDUHeader& aHeader, DaemonSocketPDU& aPDU,
   DaemonSocketResultHandler* aRes)
 {
   BluetoothDaemonGattModule::HandleSvc(aHeader, aPDU, aRes);
 }
 
 void
+BluetoothDaemonProtocol::HandleHidSvc(
+  const DaemonSocketPDUHeader& aHeader, DaemonSocketPDU& aPDU,
+  DaemonSocketResultHandler* aRes)
+{
+  BluetoothDaemonHidModule::HandleSvc(aHeader, aPDU, aRes);
+}
+
+void
 BluetoothDaemonProtocol::Handle(DaemonSocketPDU& aPDU)
 {
   static void (BluetoothDaemonProtocol::* const HandleSvc[])(
     const DaemonSocketPDUHeader&, DaemonSocketPDU&,
     DaemonSocketResultHandler*) = {
     [BluetoothDaemonSetupModule::SERVICE_ID] =
       &BluetoothDaemonProtocol::HandleSetupSvc,
     [BluetoothDaemonCoreModule::SERVICE_ID] =
       &BluetoothDaemonProtocol::HandleCoreSvc,
     [BluetoothDaemonSocketModule::SERVICE_ID] =
       &BluetoothDaemonProtocol::HandleSocketSvc,
-    [0x03] = nullptr, // HID host
+    [BluetoothDaemonHidModule::SERVICE_ID] =
+      &BluetoothDaemonProtocol::HandleHidSvc,
     [0x04] = nullptr, // PAN
     [BluetoothDaemonHandsfreeModule::SERVICE_ID] =
       &BluetoothDaemonProtocol::HandleHandsfreeSvc,
     [BluetoothDaemonA2dpModule::SERVICE_ID] =
       &BluetoothDaemonProtocol::HandleA2dpSvc,
     [0x07] = nullptr, // Health
     [BluetoothDaemonAvrcpModule::SERVICE_ID] =
       &BluetoothDaemonProtocol::HandleAvrcpSvc,
@@ -629,16 +643,28 @@ BluetoothDaemonInterface::GetBluetoothGa
     return mGattInterface;
   }
 
   mGattInterface = new BluetoothDaemonGattInterface(mProtocol);
 
   return mGattInterface;
 }
 
+BluetoothHidInterface*
+BluetoothDaemonInterface::GetBluetoothHidInterface()
+{
+  if (mHidInterface) {
+    return mHidInterface;
+  }
+
+  mHidInterface = new BluetoothDaemonHidInterface(mProtocol);
+
+  return mHidInterface;
+}
+
 // |DaemonSocketConsumer|, |ListenSocketConsumer|
 
 void
 BluetoothDaemonInterface::OnConnectSuccess(int aIndex)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(!mResultHandlerQ.IsEmpty());
 
--- a/dom/bluetooth/bluedroid/BluetoothDaemonInterface.h
+++ b/dom/bluetooth/bluedroid/BluetoothDaemonInterface.h
@@ -25,16 +25,17 @@ BEGIN_BLUETOOTH_NAMESPACE
 class BluetoothDaemonA2dpInterface;
 class BluetoothDaemonAvrcpInterface;
 class BluetoothDaemonCoreInterface;
 class BluetoothDaemonGattInterface;
 class BluetoothDaemonHandsfreeInterface;
 class BluetoothDaemonProtocol;
 class BluetoothDaemonSetupInterface;
 class BluetoothDaemonSocketInterface;
+class BluetoothDaemonHidInterface;
 
 class BluetoothDaemonInterface final
   : public BluetoothInterface
   , public mozilla::ipc::DaemonSocketConsumer
   , public mozilla::ipc::ListenSocketConsumer
 {
 public:
   class CleanupResultHandler;
@@ -53,16 +54,17 @@ public:
 
   BluetoothSetupInterface* GetBluetoothSetupInterface() override;
   BluetoothCoreInterface* GetBluetoothCoreInterface() override;
   BluetoothSocketInterface* GetBluetoothSocketInterface() override;
   BluetoothHandsfreeInterface* GetBluetoothHandsfreeInterface() override;
   BluetoothA2dpInterface* GetBluetoothA2dpInterface() override;
   BluetoothAvrcpInterface* GetBluetoothAvrcpInterface() override;
   BluetoothGattInterface* GetBluetoothGattInterface() override;
+  BluetoothHidInterface* GetBluetoothHidInterface() override;
 
 protected:
   enum Channel {
     LISTEN_SOCKET,
     CMD_CHANNEL,
     NTF_CHANNEL
   };
 
@@ -92,13 +94,14 @@ private:
 
   nsAutoPtr<BluetoothDaemonSetupInterface> mSetupInterface;
   nsAutoPtr<BluetoothDaemonCoreInterface> mCoreInterface;
   nsAutoPtr<BluetoothDaemonSocketInterface> mSocketInterface;
   nsAutoPtr<BluetoothDaemonHandsfreeInterface> mHandsfreeInterface;
   nsAutoPtr<BluetoothDaemonA2dpInterface> mA2dpInterface;
   nsAutoPtr<BluetoothDaemonAvrcpInterface> mAvrcpInterface;
   nsAutoPtr<BluetoothDaemonGattInterface> mGattInterface;
+  nsAutoPtr<BluetoothDaemonHidInterface> mHidInterface;
 };
 
 END_BLUETOOTH_NAMESPACE
 
 #endif // mozilla_dom_bluetooth_bluedroid_BluetoothDaemonInterface_h
new file mode 100644
--- /dev/null
+++ b/dom/bluetooth/bluedroid/BluetoothHidManager.cpp
@@ -0,0 +1,610 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "BluetoothHidManager.h"
+#include "BluetoothService.h"
+#include "BluetoothUtils.h"
+#include "mozilla/Services.h"
+#include "mozilla/StaticPtr.h"
+#include "nsIObserverService.h"
+
+using namespace mozilla;
+USING_BLUETOOTH_NAMESPACE
+
+namespace {
+  StaticRefPtr<BluetoothHidManager> sBluetoothHidManager;
+  static BluetoothHidInterface* sBluetoothHidInterface = nullptr;
+  bool sInShutdown = false;
+} // namesapce
+
+const int BluetoothHidManager::MAX_NUM_CLIENTS = 1;
+
+BluetoothHidManager::BluetoothHidManager()
+  : mHidConnected(false)
+{
+}
+
+void
+BluetoothHidManager::Reset()
+{
+  mDeviceAddress.Clear();
+  mController = nullptr;
+  mHidConnected = false;
+}
+
+class BluetoothHidManager::RegisterModuleResultHandler final
+  : public BluetoothSetupResultHandler
+{
+public:
+  RegisterModuleResultHandler(BluetoothHidInterface* aInterface,
+                              BluetoothProfileResultHandler* aRes)
+    : mInterface(aInterface)
+    , mRes(aRes)
+  {
+    MOZ_ASSERT(mInterface);
+  }
+
+  void OnError(BluetoothStatus aStatus) override
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+
+    BT_WARNING("BluetoothSetupInterface::RegisterModule failed for HID: %d",
+               (int)aStatus);
+
+    mInterface->SetNotificationHandler(nullptr);
+
+    if (mRes) {
+      mRes->OnError(NS_ERROR_FAILURE);
+    }
+  }
+
+  void RegisterModule() override
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+
+    sBluetoothHidInterface = mInterface;
+
+    if (mRes) {
+      mRes->Init();
+    }
+  }
+
+private:
+  BluetoothHidInterface* mInterface;
+  RefPtr<BluetoothProfileResultHandler> mRes;
+};
+
+class BluetoothHidManager::InitProfileResultHandlerRunnable final
+  : public nsRunnable
+{
+public:
+  InitProfileResultHandlerRunnable(BluetoothProfileResultHandler* aRes,
+                                   nsresult aRv)
+    : mRes(aRes)
+    , mRv(aRv)
+  {
+    MOZ_ASSERT(mRes);
+  }
+
+  NS_IMETHOD Run() override
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+
+    if (NS_SUCCEEDED(mRv)) {
+      mRes->Init();
+    } else {
+      mRes->OnError(mRv);
+    }
+    return NS_OK;
+  }
+
+private:
+  RefPtr<BluetoothProfileResultHandler> mRes;
+  nsresult mRv;
+};
+
+// static
+void
+BluetoothHidManager::InitHidInterface(BluetoothProfileResultHandler* aRes)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  if (sBluetoothHidInterface) {
+    BT_LOGR("Bluetooth HID interface is already initialized.");
+    RefPtr<nsRunnable> r =
+      new InitProfileResultHandlerRunnable(aRes, NS_OK);
+    if (NS_FAILED(NS_DispatchToMainThread(r))) {
+      BT_LOGR("Failed to dispatch HID Init runnable");
+    }
+    return;
+  }
+
+  auto btInf = BluetoothInterface::GetInstance();
+
+  if (NS_WARN_IF(!btInf)) {
+    // If there's no backend interface, we dispatch a runnable
+    // that calls the profile result handler.
+    RefPtr<nsRunnable> r =
+      new InitProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
+    if (NS_FAILED(NS_DispatchToMainThread(r))) {
+      BT_LOGR("Failed to dispatch HID OnError runnable");
+    }
+    return;
+  }
+
+  auto setupInterface = btInf->GetBluetoothSetupInterface();
+
+  if (NS_WARN_IF(!setupInterface)) {
+    // If there's no Setup interface, we dispatch a runnable
+    // that calls the profile result handler.
+    RefPtr<nsRunnable> r =
+      new InitProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
+    if (NS_FAILED(NS_DispatchToMainThread(r))) {
+      BT_LOGR("Failed to dispatch HID OnError runnable");
+    }
+    return;
+  }
+
+  auto hidinterface = btInf->GetBluetoothHidInterface();
+
+  if (NS_WARN_IF(!hidinterface)) {
+    // If there's no HID interface, we dispatch a runnable
+    // that calls the profile result handler.
+    RefPtr<nsRunnable> r =
+      new InitProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
+    if (NS_FAILED(NS_DispatchToMainThread(r))) {
+      BT_LOGR("Failed to dispatch HID OnError runnable");
+    }
+    return;
+  }
+
+  // Set notification handler _before_ registering the module. It could
+  // happen that we receive notifications, before the result handler runs.
+  hidinterface->SetNotificationHandler(BluetoothHidManager::Get());
+
+  setupInterface->RegisterModule(
+    SETUP_SERVICE_ID_HID, 0, MAX_NUM_CLIENTS,
+    new RegisterModuleResultHandler(hidinterface, aRes));
+}
+
+BluetoothHidManager::~BluetoothHidManager()
+{ }
+
+void
+BluetoothHidManager::Uninit()
+{
+  nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
+  NS_ENSURE_TRUE_VOID(obs);
+
+  if (NS_FAILED(obs->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID))) {
+    BT_WARNING("Failed to remove shutdown observer!");
+  }
+}
+
+class BluetoothHidManager::UnregisterModuleResultHandler final
+  : public BluetoothSetupResultHandler
+{
+public:
+  UnregisterModuleResultHandler(BluetoothProfileResultHandler* aRes)
+    : mRes(aRes)
+  { }
+
+  void OnError(BluetoothStatus aStatus) override
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+
+    BT_WARNING("BluetoothSetupInterface::UnregisterModule failed for HID: %d",
+               (int)aStatus);
+
+    sBluetoothHidInterface->SetNotificationHandler(nullptr);
+    sBluetoothHidInterface = nullptr;
+
+    sBluetoothHidManager->Uninit();
+    sBluetoothHidManager = nullptr;
+
+    if (mRes) {
+      mRes->OnError(NS_ERROR_FAILURE);
+    }
+  }
+
+  void UnregisterModule() override
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+
+    sBluetoothHidInterface->SetNotificationHandler(nullptr);
+    sBluetoothHidInterface = nullptr;
+
+    sBluetoothHidManager->Uninit();
+    sBluetoothHidManager = nullptr;
+
+    if (mRes) {
+      mRes->Deinit();
+    }
+  }
+
+private:
+  RefPtr<BluetoothProfileResultHandler> mRes;
+};
+
+class BluetoothHidManager::DeinitProfileResultHandlerRunnable final
+  : public nsRunnable
+{
+public:
+  DeinitProfileResultHandlerRunnable(BluetoothProfileResultHandler* aRes,
+                                     nsresult aRv)
+    : mRes(aRes)
+    , mRv(aRv)
+  {
+    MOZ_ASSERT(mRes);
+  }
+
+  NS_IMETHOD Run() override
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+
+    if (NS_SUCCEEDED(mRv)) {
+      mRes->Deinit();
+    } else {
+      mRes->OnError(mRv);
+    }
+    return NS_OK;
+  }
+
+private:
+  RefPtr<BluetoothProfileResultHandler> mRes;
+  nsresult mRv;
+};
+
+// static
+void
+BluetoothHidManager::DeinitHidInterface(BluetoothProfileResultHandler* aRes)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  if (!sBluetoothHidInterface) {
+    BT_LOGR("Bluetooth Hid interface has not been initialized.");
+    RefPtr<nsRunnable> r =
+      new DeinitProfileResultHandlerRunnable(aRes, NS_OK);
+    if (NS_FAILED(NS_DispatchToMainThread(r))) {
+      BT_LOGR("Failed to dispatch HID Deinit runnable");
+    }
+    return;
+  }
+
+  auto btInf = BluetoothInterface::GetInstance();
+
+  if (NS_WARN_IF(!btInf)) {
+    // If there's no backend interface, we dispatch a runnable
+    // that calls the profile result handler.
+    RefPtr<nsRunnable> r =
+      new DeinitProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
+    if (NS_FAILED(NS_DispatchToMainThread(r))) {
+      BT_LOGR("Failed to dispatch HID OnError runnable");
+    }
+    return;
+  }
+
+  auto setupInterface = btInf->GetBluetoothSetupInterface();
+
+  if (NS_WARN_IF(!setupInterface)) {
+    // If there's no Setup interface, we dispatch a runnable
+    // that calls the profile result handler.
+    RefPtr<nsRunnable> r =
+      new DeinitProfileResultHandlerRunnable(aRes, NS_ERROR_FAILURE);
+    if (NS_FAILED(NS_DispatchToMainThread(r))) {
+      BT_LOGR("Failed to dispatch HID OnError runnable");
+    }
+    return;
+  }
+
+  setupInterface->UnregisterModule(
+    SETUP_SERVICE_ID_HID,
+    new UnregisterModuleResultHandler(aRes));
+}
+
+NS_IMETHODIMP
+BluetoothHidManager::Observe(nsISupports* aSubject,
+                            const char* aTopic,
+                            const char16_t* aData)
+{
+  MOZ_ASSERT(sBluetoothHidManager);
+
+  if (!strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) {
+    HandleShutdown();
+    return NS_OK;
+  }
+
+  MOZ_ASSERT(false, "BluetoothHidManager got unexpected topic!");
+  return NS_ERROR_UNEXPECTED;
+}
+
+// static
+BluetoothHidManager*
+BluetoothHidManager::Get()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  // If we already exist, exit early
+  if (sBluetoothHidManager) {
+    return sBluetoothHidManager;
+  }
+
+  // If we're in shutdown, don't create a new instance
+  NS_ENSURE_FALSE(sInShutdown, nullptr);
+
+  // Create a new instance, register, and return
+  sBluetoothHidManager = new BluetoothHidManager();
+
+  return sBluetoothHidManager;
+}
+
+void
+BluetoothHidManager::NotifyConnectionStateChanged(const nsAString& aType)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  // Notify Gecko observers
+  nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
+  NS_ENSURE_TRUE_VOID(obs);
+
+  nsAutoString deviceAddressStr;
+  AddressToString(mDeviceAddress, deviceAddressStr);
+
+  if (NS_FAILED(obs->NotifyObservers(this, NS_ConvertUTF16toUTF8(aType).get(),
+                                     deviceAddressStr.get()))) {
+    BT_WARNING("Failed to notify observsers!");
+  }
+
+  // Dispatch an event of status change
+  DispatchStatusChangedEvent(
+    NS_LITERAL_STRING(HID_STATUS_CHANGED_ID), mDeviceAddress, IsConnected());
+}
+
+bool
+BluetoothHidManager::IsConnected()
+{
+  return mHidConnected;
+}
+
+void
+BluetoothHidManager::OnConnectError()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  mController->NotifyCompletion(NS_LITERAL_STRING(ERR_CONNECTION_FAILED));
+  Reset();
+}
+
+class BluetoothHidManager::ConnectResultHandler final
+  : public BluetoothHidResultHandler
+{
+public:
+  ConnectResultHandler(BluetoothHidManager* aHidManager)
+    : mHidManager(aHidManager)
+  {
+    MOZ_ASSERT(mHidManager);
+  }
+
+  void OnError(BluetoothStatus aStatus) override
+  {
+    BT_WARNING("BluetoothHidInterface::Connect failed: %d",
+               (int)aStatus);
+    mHidManager->OnConnectError();
+  }
+
+private:
+  BluetoothHidManager* mHidManager;
+};
+
+void
+BluetoothHidManager::Connect(const BluetoothAddress& aDeviceAddress,
+                             BluetoothProfileController* aController)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(!aDeviceAddress.IsCleared());
+  MOZ_ASSERT(aController && !mController);
+
+  if(sInShutdown) {
+    aController->NotifyCompletion(NS_LITERAL_STRING(ERR_NO_AVAILABLE_RESOURCE));
+    return;
+  }
+
+  if(IsConnected()) {
+    aController->NotifyCompletion(NS_LITERAL_STRING(ERR_ALREADY_CONNECTED));
+    return;
+  }
+
+  if(!sBluetoothHidInterface) {
+    BT_LOGR("sBluetoothHidInterface is null");
+    aController->NotifyCompletion(NS_LITERAL_STRING(ERR_NO_AVAILABLE_RESOURCE));
+    return;
+  }
+
+  mDeviceAddress = aDeviceAddress;
+  mController = aController;
+
+  sBluetoothHidInterface->Connect(mDeviceAddress,
+                                  new ConnectResultHandler(this));
+}
+
+void
+BluetoothHidManager::OnDisconnectError()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  NS_ENSURE_TRUE_VOID(mController);
+
+  mController->NotifyCompletion(NS_LITERAL_STRING(ERR_CONNECTION_FAILED));
+
+  mController = nullptr;
+}
+
+class BluetoothHidManager::DisconnectResultHandler final
+  : public BluetoothHidResultHandler
+{
+public:
+  DisconnectResultHandler(BluetoothHidManager* aHidManager)
+    : mHidManager(aHidManager)
+  {
+    MOZ_ASSERT(mHidManager);
+  }
+
+  void OnError(BluetoothStatus aStatus) override
+  {
+    BT_WARNING("BluetoothHidInterface::Disconnect failed: %d",
+               (int)aStatus);
+    mHidManager->OnDisconnectError();
+  }
+
+private:
+  BluetoothHidManager* mHidManager;
+};
+
+void
+BluetoothHidManager::Disconnect(BluetoothProfileController* aController)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(!mController);
+
+  if (!IsConnected()) {
+    if (aController) {
+      aController->NotifyCompletion(
+        NS_LITERAL_STRING(ERR_ALREADY_DISCONNECTED));
+    }
+    return;
+  }
+
+  MOZ_ASSERT(!mDeviceAddress.IsCleared());
+
+  if (!sBluetoothHidInterface) {
+    BT_LOGR("sBluetoothHidInterface is null");
+    if (aController) {
+      aController->NotifyCompletion(
+        NS_LITERAL_STRING(ERR_NO_AVAILABLE_RESOURCE));
+    }
+    return;
+  }
+
+  mController = aController;
+
+  sBluetoothHidInterface->Disconnect(mDeviceAddress,
+                                     new DisconnectResultHandler(this));
+}
+
+void
+BluetoothHidManager::OnConnect(const nsAString& aErrorStr)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  /**
+   * On the one hand, notify the controller that we've done for outbound
+   * connections. On the other hand, we do nothing for inbound connections.
+   */
+  NS_ENSURE_TRUE_VOID(mController);
+
+  mController->NotifyCompletion(aErrorStr);
+  mController = nullptr;
+}
+
+void
+BluetoothHidManager::OnDisconnect(const nsAString& aErrorStr)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  /**
+   * On the one hand, notify the controller that we've done for outbound
+   * connections. On the other hand, we do nothing for inbound connections.
+   */
+  NS_ENSURE_TRUE_VOID(mController);
+
+  mController->NotifyCompletion(aErrorStr);
+  Reset();
+}
+
+void
+BluetoothHidManager::HandleShutdown()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  sInShutdown = true;
+  Disconnect(nullptr);
+  sBluetoothHidManager = nullptr;
+}
+
+void
+BluetoothHidManager::HandleBackendError()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  if (mHidConnected) {
+    ConnectionStateNotification(mDeviceAddress,
+                                HID_CONNECTION_STATE_DISCONNECTED);
+  }
+}
+
+void
+BluetoothHidManager::GetAddress(BluetoothAddress& aDeviceAddress)
+{
+  aDeviceAddress = mDeviceAddress;
+}
+
+void
+BluetoothHidManager::OnUpdateSdpRecords(
+  const BluetoothAddress& aDeviceAddress)
+{
+  // Bluedroid handles this part
+  MOZ_ASSERT(false);
+}
+
+void
+BluetoothHidManager::OnGetServiceChannel(
+  const BluetoothAddress& aDeviceAddress,
+  const BluetoothUuid& aServiceUuid,
+  int aChannel)
+{
+  // Bluedroid handles this part
+  MOZ_ASSERT(false);
+}
+
+//
+// Bluetooth notifications
+//
+
+/**
+ * There are totally 10 connection states, and will receive 4 possible
+ * states: "connected", "connecting", "disconnected", "disconnecting".
+ * Here we only handle connected and disconnected states. We do nothing
+ * for remaining states.
+ *
+ * Possible cases are listed below:
+ * CONNECTED:
+ *   1. Successful inbound or outbound connection
+ * DISCONNECTED:
+ *   2. Attempt disconnection succeeded
+ *   3. Attempt connection failed
+ *   4. Either unpair from the remote device or the remote device is
+ *      out of range in connected state
+ */
+void
+BluetoothHidManager::ConnectionStateNotification(
+  const BluetoothAddress& aBdAddr, BluetoothHidConnectionState aState)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  BT_LOGR("state %d", aState);
+
+  if (aState == HID_CONNECTION_STATE_CONNECTED) {
+    mHidConnected = true;
+    mDeviceAddress = aBdAddr;
+    NotifyConnectionStateChanged(
+      NS_LITERAL_STRING(BLUETOOTH_HID_STATUS_CHANGED_ID));
+    OnConnect(EmptyString());
+  } else if (aState == HID_CONNECTION_STATE_DISCONNECTED) {
+    mHidConnected = false;
+    NotifyConnectionStateChanged(
+      NS_LITERAL_STRING(BLUETOOTH_HID_STATUS_CHANGED_ID));
+    OnDisconnect(EmptyString());
+  }
+}
+
+NS_IMPL_ISUPPORTS(BluetoothHidManager, nsIObserver)
new file mode 100644
--- /dev/null
+++ b/dom/bluetooth/bluedroid/BluetoothHidManager.h
@@ -0,0 +1,71 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_bluetooth_bluedroid_BluetoothHidManager_h
+#define mozilla_dom_bluetooth_bluedroid_BluetoothHidMnagaer_h
+
+#include "BluetoothCommon.h"
+#include "BluetoothInterface.h"
+#include "BluetoothProfileController.h"
+#include "BluetoothProfileManagerBase.h"
+
+BEGIN_BLUETOOTH_NAMESPACE
+
+class BluetoothHidManager : public BluetoothProfileManagerBase
+                          , public BluetoothHidNotificationHandler
+{
+public:
+  BT_DECL_PROFILE_MGR_BASE
+
+  static const int MAX_NUM_CLIENTS;
+
+  void OnConnectError();
+  void OnDisconnectError();
+
+  virtual void GetName(nsACString& aName)
+  {
+    aName.AssignLiteral("HID");
+  }
+
+  static BluetoothHidManager* Get();
+  static void InitHidInterface(BluetoothProfileResultHandler* aRes);
+  static void DeinitHidInterface(BluetoothProfileResultHandler* aRes);
+
+  void HandleBackendError();
+
+protected:
+  virtual ~BluetoothHidManager();
+
+private:
+  class DeinitProfileResultHandlerRunnable;
+  class InitProfileResultHandlerRunnable;
+  class RegisterModuleResultHandler;
+  class UnregisterModuleResultHandler;
+
+  class ConnectResultHandler;
+  class DisconnectResultHandler;
+
+  BluetoothHidManager();
+  void Uninit();
+  void HandleShutdown();
+  void NotifyConnectionStateChanged(const nsAString& aType);
+
+  //
+  // Bluetooth notifications
+  //
+
+  void ConnectionStateNotification(
+    const BluetoothAddress& aBdAddr,
+    BluetoothHidConnectionState aState) override;
+
+  bool mHidConnected;
+  BluetoothAddress mDeviceAddress;
+  RefPtr<BluetoothProfileController> mController;
+};
+
+END_BLUETOOTH_NAMESPACE
+
+#endif // mozilla_dom_bluetooth_bluedroid_BluetoothHidManager_h
--- a/dom/bluetooth/bluedroid/BluetoothServiceBluedroid.cpp
+++ b/dom/bluetooth/bluedroid/BluetoothServiceBluedroid.cpp
@@ -2627,23 +2627,27 @@ BluetoothServiceBluedroid::BackendErrorN
   if (!aCrashed) {
     return;
   }
 
   /*
    * Reset following profile manager states for unexpected backend crash.
    * - HFP: connection state and audio state
    * - A2DP: connection state
+   * - HID: connection state
    */
   BluetoothHfpManager* hfp = BluetoothHfpManager::Get();
   NS_ENSURE_TRUE_VOID(hfp);
   hfp->HandleBackendError();
   BluetoothA2dpManager* a2dp = BluetoothA2dpManager::Get();
   NS_ENSURE_TRUE_VOID(a2dp);
   a2dp->HandleBackendError();
+  BluetoothHidManager* hid = BluetoothHidManager::Get();
+  NS_ENSURE_TRUE_VOID(hid);
+  hid->HandleBackendError();
 
   mIsRestart = true;
   BT_LOGR("Recovery step2: stop bluetooth");
   StopBluetooth(false, nullptr);
 }
 
 void
 BluetoothServiceBluedroid::CompleteToggleBt(bool aEnabled)
rename from dom/bluetooth/common/BluetoothHidManager.cpp
rename to dom/bluetooth/bluez/BluetoothHidManager.cpp
rename from dom/bluetooth/common/BluetoothHidManager.h
rename to dom/bluetooth/bluez/BluetoothHidManager.h
--- a/dom/bluetooth/common/BluetoothCommon.h
+++ b/dom/bluetooth/common/BluetoothCommon.h
@@ -202,16 +202,17 @@ extern bool gBluetoothDebugFlag;
 #define BLUETOOTH_SCO_STATUS_CHANGED_ID  "bluetooth-sco-status-changed"
 
 /**
  * When the connection status of a Bluetooth profile is changed, we'll
  * dispatch one of the following events.
  */
 #define A2DP_STATUS_CHANGED_ID               "a2dpstatuschanged"
 #define HFP_STATUS_CHANGED_ID                "hfpstatuschanged"
+#define HID_STATUS_CHANGED_ID                "hidstatuschanged"
 #define SCO_STATUS_CHANGED_ID                "scostatuschanged"
 
 /**
  * Types of pairing requests for constructing BluetoothPairingEvent and
  * BluetoothPairingHandle.
  */
 #define PAIRING_REQ_TYPE_DISPLAYPASSKEY       "displaypasskeyreq"
 #define PAIRING_REQ_TYPE_ENTERPINCODE         "enterpincodereq"
@@ -302,16 +303,23 @@ extern bool gBluetoothDebugFlag;
 #define ERR_INTERNAL_ERROR "InternalError"
 
 /**
  * BT specification v4.1 defines the maximum attribute length as 512 octets.
  * Currently use 600 here to conform to bluedroid's BTGATT_MAX_ATTR_LEN.
  */
 #define BLUETOOTH_GATT_MAX_ATTR_LEN 600
 
+/**
+ * The maximum descriptor length defined in BlueZ ipc spec.
+ * Please refer to http://git.kernel.org/cgit/bluetooth/bluez.git/tree/\
+ * android/hal-ipc-api.txt#n532
+ */
+#define BLUETOOTH_HID_MAX_DESC_LEN 884
+
 BEGIN_BLUETOOTH_NAMESPACE
 
 enum BluetoothStatus {
   STATUS_SUCCESS,
   STATUS_FAIL,
   STATUS_NOT_READY,
   STATUS_NOMEM,
   STATUS_BUSY,
@@ -871,16 +879,74 @@ struct BluetoothProperty {
 
 enum BluetoothSocketType {
   RFCOMM = 1,
   SCO    = 2,
   L2CAP  = 3,
   EL2CAP = 4
 };
 
+struct BluetoothHidInfoParam {
+  uint16_t mAttributeMask;
+  uint8_t mSubclass;
+  uint8_t mApplicationId;
+  uint16_t mVendorId;
+  uint16_t mProductId;
+  uint16_t mVersion;
+  uint8_t mCountryCode;
+  uint16_t mDescriptorLength;
+  uint8_t mDescriptorValue[BLUETOOTH_HID_MAX_DESC_LEN];
+};
+
+struct BluetoothHidReport {
+  nsTArray<uint8_t> mReportData;
+};
+
+enum BluetoothHidProtocolMode {
+  HID_PROTOCOL_MODE_REPORT = 0x00,
+  HID_PROTOCOL_MODE_BOOT = 0x01,
+  HID_PROTOCOL_MODE_UNSUPPORTED = 0xff
+};
+
+enum BluetoothHidReportType {
+  HID_REPORT_TYPE_INPUT = 0x01,
+  HID_REPORT_TYPE_OUTPUT = 0x02,
+  HID_REPORT_TYPE_FEATURE = 0x03
+};
+
+enum BluetoothHidConnectionState {
+  HID_CONNECTION_STATE_CONNECTED,
+  HID_CONNECTION_STATE_CONNECTING,
+  HID_CONNECTION_STATE_DISCONNECTED,
+  HID_CONNECTION_STATE_DISCONNECTING,
+  HID_CONNECTION_STATE_FAILED_MOUSE_FROM_HOST,
+  HID_CONNECTION_STATE_FAILED_KEYBOARD_FROM_HOST,
+  HID_CONNECTION_STATE_FAILED_TOO_MANY_DEVICES,
+  HID_CONNECTION_STATE_FAILED_NO_HID_DRIVER,
+  HID_CONNECTION_STATE_FAILED_GENERIC,
+  HID_CONNECTION_STATE_UNKNOWN
+};
+
+enum BluetoothHidStatus {
+  HID_STATUS_OK,
+  HID_STATUS_HANDSHAKE_DEVICE_NOT_READY,
+  HID_STATUS_HANDSHAKE_INVALID_REPORT_ID,
+  HID_STATUS_HANDSHAKE_TRANSACTION_NOT_SPT,
+  HID_STATUS_HANDSHAKE_INVALID_PARAMETER,
+  HID_STATUS_HANDSHAKE_GENERIC_ERROR,
+  HID_STATUS_GENERAL_ERROR,
+  HID_STATUS_SDP_ERROR,
+  HID_STATUS_SET_PROTOCOL_ERROR,
+  HID_STATUS_DEVICE_DATABASE_FULL,
+  HID_STATUS_DEVICE_TYPE_NOT_SUPPORTED,
+  HID_STATUS_NO_RESOURCES,
+  HID_STATUS_AUTHENTICATION_FAILED,
+  HID_STATUS_HDL
+};
+
 enum BluetoothHandsfreeAtResponse {
   HFP_AT_RESPONSE_ERROR,
   HFP_AT_RESPONSE_OK
 };
 
 enum BluetoothHandsfreeAudioState {
   HFP_AUDIO_STATE_DISCONNECTED,
   HFP_AUDIO_STATE_CONNECTING,
--- a/dom/bluetooth/common/BluetoothInterface.cpp
+++ b/dom/bluetooth/common/BluetoothInterface.cpp
@@ -263,16 +263,121 @@ BluetoothSocketResultHandler::Accept(int
 
 // Interface
 //
 
 BluetoothSocketInterface::~BluetoothSocketInterface()
 { }
 
 //
+//Hid Interface
+//
+
+//Notification handling
+//
+
+BluetoothHidNotificationHandler::BluetoothHidNotificationHandler()
+{ }
+
+BluetoothHidNotificationHandler::~BluetoothHidNotificationHandler()
+{ }
+
+void
+BluetoothHidNotificationHandler::ConnectionStateNotification(
+  const BluetoothAddress& aBdAddr, BluetoothHidConnectionState aState)
+{ }
+
+void
+BluetoothHidNotificationHandler::HidInfoNotification(
+  const BluetoothAddress& aBdAddr,
+  const BluetoothHidInfoParam& aHidInfoParam)
+{ }
+
+void
+BluetoothHidNotificationHandler::ProtocolModeNotification(
+  const BluetoothAddress& aBdAddr, BluetoothHidStatus aStatus,
+  BluetoothHidProtocolMode aProtocolMode)
+{ }
+
+void
+BluetoothHidNotificationHandler::IdleTimeNotification(
+  const BluetoothAddress& aBdAddr,
+  BluetoothHidStatus aStatus, uint16_t aIdleTime)
+{ }
+
+void
+BluetoothHidNotificationHandler::GetReportNotification(
+  const BluetoothAddress& aBdAddr, BluetoothHidStatus aStatus,
+  const BluetoothHidReport& aReport)
+{ }
+
+void
+BluetoothHidNotificationHandler::VirtualUnplugNotification(
+  const BluetoothAddress& aBdAddr, BluetoothHidStatus aStatus)
+{ }
+
+void
+BluetoothHidNotificationHandler::HandshakeNotification(
+  const BluetoothAddress& aBdAddr, BluetoothHidStatus aStatus)
+{ }
+
+// Result handling
+//
+
+void BluetoothHidResultHandler::OnError(BluetoothStatus aStatus)
+{
+  BT_WARNING("Received error code %d", (int)aStatus);
+}
+
+void
+BluetoothHidResultHandler::Connect()
+{ }
+
+void
+BluetoothHidResultHandler::Disconnect()
+{ }
+
+void
+BluetoothHidResultHandler::VirtualUnplug()
+{ }
+
+void
+BluetoothHidResultHandler::SetInfo()
+{ }
+
+void
+BluetoothHidResultHandler::GetProtocol()
+{ }
+
+void
+BluetoothHidResultHandler::SetProtocol()
+{ }
+
+void
+BluetoothHidResultHandler::GetReport()
+{ }
+
+void
+BluetoothHidResultHandler::SetReport()
+{ }
+
+void
+BluetoothHidResultHandler::SendData()
+{ }
+
+// Interface
+//
+
+BluetoothHidInterface::BluetoothHidInterface()
+{ }
+
+BluetoothHidInterface::~BluetoothHidInterface()
+{ }
+
+//
 // Handsfree Interface
 //
 
 // Notification handling
 //
 
 BluetoothHandsfreeNotificationHandler::BluetoothHandsfreeNotificationHandler()
 { }
--- a/dom/bluetooth/common/BluetoothInterface.h
+++ b/dom/bluetooth/common/BluetoothInterface.h
@@ -272,16 +272,140 @@ public:
 
   virtual void Close(BluetoothSocketResultHandler* aRes) = 0;
 
 protected:
   virtual ~BluetoothSocketInterface();
 };
 
 //
+// HID Interface
+//
+
+class BluetoothHidNotificationHandler
+{
+public:
+  virtual void
+  ConnectionStateNotification(const BluetoothAddress& aBdAddr,
+                              BluetoothHidConnectionState aState);
+
+  virtual void
+  HidInfoNotification(
+    const BluetoothAddress& aBdAddr,
+    const BluetoothHidInfoParam& aHidInfoParam);
+
+  virtual void
+  ProtocolModeNotification(const BluetoothAddress& aBdAddr,
+                           BluetoothHidStatus aStatus,
+                           BluetoothHidProtocolMode aProtocolMode);
+
+  virtual void
+  IdleTimeNotification(const BluetoothAddress& aBdAddr,
+                       BluetoothHidStatus aStatus,
+                       uint16_t aIdleTime);
+
+  virtual void
+  GetReportNotification(const BluetoothAddress& aBdAddr,
+                        BluetoothHidStatus aStatus,
+                        const BluetoothHidReport& aReport);
+
+  virtual void
+  VirtualUnplugNotification(const BluetoothAddress& aBdAddr,
+                            BluetoothHidStatus aStatus);
+
+  virtual void
+  HandshakeNotification(const BluetoothAddress& aBdAddr,
+                        BluetoothHidStatus aStatus);
+
+protected:
+  BluetoothHidNotificationHandler();
+  virtual ~BluetoothHidNotificationHandler();
+};
+
+class BluetoothHidResultHandler
+  : public mozilla::ipc::DaemonSocketResultHandler
+{
+public:
+  virtual void OnError(BluetoothStatus aStatus);
+
+  virtual void Connect();
+  virtual void Disconnect();
+
+  virtual void VirtualUnplug();
+
+  virtual void SetInfo();
+
+  virtual void GetProtocol();
+  virtual void SetProtocol();
+
+  virtual void GetReport();
+  virtual void SetReport();
+
+  virtual void SendData();
+
+protected:
+  virtual ~BluetoothHidResultHandler() { }
+};
+
+class BluetoothHidInterface
+{
+public:
+  virtual void SetNotificationHandler(
+    BluetoothHidNotificationHandler* aNotificationHandler) = 0;
+
+  /* Connect / Disconnect */
+
+  virtual void Connect(const BluetoothAddress& aBdAddr,
+                       BluetoothHidResultHandler* aRes) = 0;
+  virtual void Disconnect(const BluetoothAddress& aBdAddr,
+                          BluetoothHidResultHandler* aRes) = 0;
+
+  /* Virtual Unplug */
+  virtual void VirtualUnplug(const BluetoothAddress& aBdAddr,
+                             BluetoothHidResultHandler* aRes) = 0;
+
+  /* Set Info */
+
+  virtual void SetInfo(const BluetoothAddress& aBdAddr,
+                       const BluetoothHidInfoParam& aHidInfoParam,
+                       BluetoothHidResultHandler* aRes) = 0;
+
+  /* Protocol */
+
+  virtual void GetProtocol(const BluetoothAddress& aBdAddr,
+                           BluetoothHidProtocolMode aHidProtoclMode,
+                           BluetoothHidResultHandler* aRes) = 0;
+  virtual void SetProtocol(const BluetoothAddress& aBdAddr,
+                           BluetoothHidProtocolMode aHidProtocolMode,
+                           BluetoothHidResultHandler* aRes) = 0;
+
+  /* Report */
+
+  virtual void GetReport(const BluetoothAddress& aBdAddr,
+                         BluetoothHidReportType aType,
+                         uint8_t aReportId,
+                         uint16_t aBuffSize,
+                         BluetoothHidResultHandler* aRes) = 0;
+  virtual void SetReport(const BluetoothAddress& aBdAddr,
+                         BluetoothHidReportType aType,
+                         const BluetoothHidReport& aReport,
+                         BluetoothHidResultHandler* aRes) = 0;
+
+  /* Send Data */
+
+  virtual void SendData(const BluetoothAddress& aBdAddr,
+                        uint16_t aDataLen, const uint8_t* aData,
+                        BluetoothHidResultHandler* aRes) = 0;
+
+protected:
+  BluetoothHidInterface();
+  virtual ~BluetoothHidInterface();
+};
+
+//
 // Handsfree Interface
 //
 
 class BluetoothHandsfreeNotificationHandler
 {
 public:
   virtual void
   ConnectionStateNotification(BluetoothHandsfreeConnectionState aState,
@@ -1149,16 +1273,17 @@ public:
 
   virtual BluetoothSetupInterface* GetBluetoothSetupInterface() = 0;
   virtual BluetoothCoreInterface* GetBluetoothCoreInterface() = 0;
   virtual BluetoothSocketInterface* GetBluetoothSocketInterface() = 0;
   virtual BluetoothHandsfreeInterface* GetBluetoothHandsfreeInterface() = 0;
   virtual BluetoothA2dpInterface* GetBluetoothA2dpInterface() = 0;
   virtual BluetoothAvrcpInterface* GetBluetoothAvrcpInterface() = 0;
   virtual BluetoothGattInterface* GetBluetoothGattInterface() = 0;
+  virtual BluetoothHidInterface* GetBluetoothHidInterface() = 0;
 
 protected:
   BluetoothInterface();
   virtual ~BluetoothInterface();
 };
 
 END_BLUETOOTH_NAMESPACE
 
--- a/dom/bluetooth/common/BluetoothProfileController.cpp
+++ b/dom/bluetooth/common/BluetoothProfileController.cpp
@@ -183,16 +183,17 @@ BluetoothProfileController::SetupProfile
   // The value of CoD is invalid. Since the device didn't declare its class of
   // device properly, we assume the device may support all of these profiles.
   // Note the invalid CoD from bluedroid callback usually results from
   // NFC-triggered direct pairing for no EIR query records.
   if (isInvalid) {
     AddProfile(BluetoothHfpManager::Get());
     AddProfile(BluetoothA2dpManager::Get());
     AddProfile(BluetoothAvrcpManager::Get()); // register after A2DP
+    AddProfile(BluetoothHidManager::Get());
     return;
   }
 
   NS_ENSURE_TRUE_VOID(hasAudio || hasRendering || isPeripheral);
 
   // Audio bit should be set if remote device supports HFP/HSP.
   if (hasAudio) {
     AddProfile(BluetoothHfpManager::Get());
--- a/dom/bluetooth/common/webapi/BluetoothAdapter.cpp
+++ b/dom/bluetooth/common/webapi/BluetoothAdapter.cpp
@@ -534,16 +534,17 @@ BluetoothAdapter::Notify(const Bluetooth
       HandleLeDeviceFound(v);
     }
   } else if (aData.name().EqualsLiteral(DEVICE_PAIRED_ID)) {
     HandleDevicePaired(aData.value());
   } else if (aData.name().EqualsLiteral(DEVICE_UNPAIRED_ID)) {
     HandleDeviceUnpaired(aData.value());
   } else if (aData.name().EqualsLiteral(HFP_STATUS_CHANGED_ID) ||
              aData.name().EqualsLiteral(SCO_STATUS_CHANGED_ID) ||
+             aData.name().EqualsLiteral(HID_STATUS_CHANGED_ID) ||
              aData.name().EqualsLiteral(A2DP_STATUS_CHANGED_ID)) {
     MOZ_ASSERT(v.type() == BluetoothValue::TArrayOfBluetoothNamedValue);
     const InfallibleTArray<BluetoothNamedValue>& arr =
       v.get_ArrayOfBluetoothNamedValue();
 
     MOZ_ASSERT(arr.Length() == 2 &&
                arr[0].value().type() == BluetoothValue::TBluetoothAddress &&
                arr[1].value().type() == BluetoothValue::Tbool);
--- a/dom/bluetooth/common/webapi/BluetoothAdapter.h
+++ b/dom/bluetooth/common/webapi/BluetoothAdapter.h
@@ -85,19 +85,20 @@ public:
   /****************************************************************************
    * Event Handlers
    ***************************************************************************/
   IMPL_EVENT_HANDLER(attributechanged);
   // PAIRING
   IMPL_EVENT_HANDLER(devicepaired);
   IMPL_EVENT_HANDLER(deviceunpaired);
   IMPL_EVENT_HANDLER(pairingaborted);
-  // HFP/A2DP/AVRCP
+  // HFP/A2DP/AVRCP/HID
   IMPL_EVENT_HANDLER(a2dpstatuschanged);
   IMPL_EVENT_HANDLER(hfpstatuschanged);
+  IMPL_EVENT_HANDLER(hidstatuschanged);
   IMPL_EVENT_HANDLER(scostatuschanged);
   IMPL_EVENT_HANDLER(requestmediaplaystatus);
   // PBAP
   IMPL_EVENT_HANDLER(obexpasswordreq);
   IMPL_EVENT_HANDLER(pullphonebookreq);
   IMPL_EVENT_HANDLER(pullvcardentryreq);
   IMPL_EVENT_HANDLER(pullvcardlistingreq);
   // MAP
--- a/dom/bluetooth/moz.build
+++ b/dom/bluetooth/moz.build
@@ -12,17 +12,16 @@ if CONFIG['MOZ_B2G_BT']:
 
     if CONFIG['MOZ_B2G_RIL']:
         SOURCES += [
             'common/BluetoothRilListener.cpp'
         ]
 
     SOURCES += [
         'common/BluetoothGattReplyRunnable.cpp',
-        'common/BluetoothHidManager.cpp',
         'common/BluetoothInterface.cpp',
         'common/BluetoothProfileController.cpp',
         'common/BluetoothReplyRunnable.cpp',
         'common/BluetoothService.cpp',
         'common/BluetoothUtils.cpp',
         'common/BluetoothUuidHelper.cpp',
         'common/ObexBase.cpp',
         'common/webapi/BluetoothAdapter.cpp',
@@ -60,16 +59,17 @@ if CONFIG['MOZ_B2G_BT']:
     if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
         if CONFIG['MOZ_B2G_BT_BLUEZ']:
             CXXFLAGS += CONFIG['MOZ_DBUS_CFLAGS']
             SOURCES += [
                 'bluez/BluetoothA2dpManager.cpp',
                 'bluez/BluetoothAvrcpManager.cpp',
                 'bluez/BluetoothDBusService.cpp',
                 'bluez/BluetoothHfpManager.cpp',
+                'bluez/BluetoothHidManager.cpp',
                 'bluez/BluetoothOppManager.cpp',
                 'bluez/BluetoothSocket.cpp',
                 'bluez/BluetoothUnixSocketConnector.cpp'
             ]
             LOCAL_INCLUDES += [
                 'bluez',
             ]
             DEFINES['MOZ_B2G_BT_BLUEZ'] = True
@@ -78,20 +78,22 @@ if CONFIG['MOZ_B2G_BT']:
                 'bluedroid/BluetoothA2dpManager.cpp',
                 'bluedroid/BluetoothAvrcpManager.cpp',
                 'bluedroid/BluetoothDaemonA2dpInterface.cpp',
                 'bluedroid/BluetoothDaemonAvrcpInterface.cpp',
                 'bluedroid/BluetoothDaemonCoreInterface.cpp',
                 'bluedroid/BluetoothDaemonGattInterface.cpp',
                 'bluedroid/BluetoothDaemonHandsfreeInterface.cpp',
                 'bluedroid/BluetoothDaemonHelpers.cpp',
+                'bluedroid/BluetoothDaemonHidInterface.cpp',
                 'bluedroid/BluetoothDaemonInterface.cpp',
                 'bluedroid/BluetoothDaemonSetupInterface.cpp',
                 'bluedroid/BluetoothDaemonSocketInterface.cpp',
                 'bluedroid/BluetoothGattManager.cpp',
+                'bluedroid/BluetoothHidManager.cpp',
                 'bluedroid/BluetoothMapBMessage.cpp',
                 'bluedroid/BluetoothMapFolder.cpp',
                 'bluedroid/BluetoothMapSmsManager.cpp',
                 'bluedroid/BluetoothOppManager.cpp',
                 'bluedroid/BluetoothPbapManager.cpp',
                 'bluedroid/BluetoothServiceBluedroid.cpp',
                 'bluedroid/BluetoothSocket.cpp',
                 'bluedroid/BluetoothSocketMessageWatcher.cpp'
--- a/dom/webidl/BluetoothAdapter.webidl
+++ b/dom/webidl/BluetoothAdapter.webidl
@@ -58,16 +58,19 @@ interface BluetoothAdapter : EventTarget
            attribute EventHandler   onpairingaborted;
 
   // Fired when a2dp connection status changed
            attribute EventHandler   ona2dpstatuschanged;
 
   // Fired when handsfree connection status changed
            attribute EventHandler   onhfpstatuschanged;
 
+  // Fired when handsfree connection status changed
+           attribute EventHandler   onhidstatuschanged;
+
   // Fired when sco connection status changed
            attribute EventHandler   onscostatuschanged;
 
   // Fired when remote devices query current media play status
            attribute EventHandler   onrequestmediaplaystatus;
 
   // Fired when remote devices request password for OBEX authentication
            attribute EventHandler   onobexpasswordreq;