Bug 1103872: Add Handsfree module for Bluetooth daemon (under bluetooth2/), r=btian
authorThomas Zimmermann <tdz@users.sourceforge.net>
Fri, 28 Nov 2014 11:37:47 +0100
changeset 243872 b9b07db1e846a5b712400762f11fd2d580e85e4d
parent 243871 cb9fb4a16519ae36b39df3272a15d94d31038076
child 243873 6708343dd7eeb0743f9c82e5c0e53cf1f4a0d1a6
push id4489
push userraliiev@mozilla.com
push dateMon, 23 Feb 2015 15:17:55 +0000
treeherdermozilla-beta@fd7c3dc24146 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbtian
bugs1103872
milestone36.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1103872: Add Handsfree module for Bluetooth daemon (under bluetooth2/), r=btian
dom/bluetooth2/bluedroid/BluetoothDaemonHandsfreeInterface.cpp
dom/bluetooth2/bluedroid/BluetoothDaemonHandsfreeInterface.h
dom/bluetooth2/moz.build
new file mode 100644
--- /dev/null
+++ b/dom/bluetooth2/bluedroid/BluetoothDaemonHandsfreeInterface.cpp
@@ -0,0 +1,956 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=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 "BluetoothDaemonHandsfreeInterface.h"
+#include "mozilla/unused.h"
+
+BEGIN_BLUETOOTH_NAMESPACE
+
+//
+// Handsfree module
+//
+
+BluetoothHandsfreeNotificationHandler*
+  BluetoothDaemonHandsfreeModule::sNotificationHandler;
+
+void
+BluetoothDaemonHandsfreeModule::SetNotificationHandler(
+  BluetoothHandsfreeNotificationHandler* aNotificationHandler)
+{
+  sNotificationHandler = aNotificationHandler;
+}
+
+nsresult
+BluetoothDaemonHandsfreeModule::Send(BluetoothDaemonPDU* aPDU,
+                                     BluetoothHandsfreeResultHandler* aRes)
+{
+  aRes->AddRef(); // Keep reference for response
+  return Send(aPDU, static_cast<void*>(aRes));
+}
+
+void
+BluetoothDaemonHandsfreeModule::HandleSvc(const BluetoothDaemonPDUHeader& aHeader,
+                                          BluetoothDaemonPDU& aPDU, void* aUserData)
+{
+  static void (BluetoothDaemonHandsfreeModule::* const HandleOp[])(
+    const BluetoothDaemonPDUHeader&, BluetoothDaemonPDU&, void*) = {
+    INIT_ARRAY_AT(0, &BluetoothDaemonHandsfreeModule::HandleRsp),
+    INIT_ARRAY_AT(1, &BluetoothDaemonHandsfreeModule::HandleNtf),
+  };
+
+  MOZ_ASSERT(!NS_IsMainThread());
+
+  // Negate twice to map bit to 0/1
+  unsigned long isNtf = !!(aHeader.mOpcode & 0x80);
+
+  (this->*(HandleOp[isNtf]))(aHeader, aPDU, aUserData);
+}
+
+// Commands
+//
+
+nsresult
+BluetoothDaemonHandsfreeModule::ConnectCmd(
+  const nsAString& aRemoteAddr, BluetoothHandsfreeResultHandler* aRes)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  nsAutoPtr<BluetoothDaemonPDU> pdu(
+    new BluetoothDaemonPDU(SERVICE_ID, OPCODE_CONNECT,
+                           6)); // Address
+
+  nsresult rv = PackPDU(
+    PackConversion<nsAString, BluetoothAddress>(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
+BluetoothDaemonHandsfreeModule::DisconnectCmd(
+  const nsAString& aRemoteAddr, BluetoothHandsfreeResultHandler* aRes)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  nsAutoPtr<BluetoothDaemonPDU> pdu(
+    new BluetoothDaemonPDU(SERVICE_ID, OPCODE_DISCONNECT,
+                           6)); // Address
+
+  nsresult rv = PackPDU(
+    PackConversion<nsAString, BluetoothAddress>(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
+BluetoothDaemonHandsfreeModule::ConnectAudioCmd(
+  const nsAString& aRemoteAddr, BluetoothHandsfreeResultHandler* aRes)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  nsAutoPtr<BluetoothDaemonPDU> pdu(
+    new BluetoothDaemonPDU(SERVICE_ID, OPCODE_CONNECT_AUDIO,
+                           6)); // Address
+
+  nsresult rv = PackPDU(
+    PackConversion<nsAString, BluetoothAddress>(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
+BluetoothDaemonHandsfreeModule::DisconnectAudioCmd(
+  const nsAString& aRemoteAddr, BluetoothHandsfreeResultHandler* aRes)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  nsAutoPtr<BluetoothDaemonPDU> pdu(
+    new BluetoothDaemonPDU(SERVICE_ID, OPCODE_DISCONNECT_AUDIO,
+                           6)); // Address
+
+  nsresult rv = PackPDU(
+    PackConversion<nsAString, BluetoothAddress>(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
+BluetoothDaemonHandsfreeModule::StartVoiceRecognitionCmd(
+  BluetoothHandsfreeResultHandler* aRes)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  nsAutoPtr<BluetoothDaemonPDU> pdu(
+    new BluetoothDaemonPDU(SERVICE_ID, OPCODE_START_VOICE_RECOGNITION,
+                           0)); // No payload
+
+  nsresult rv = Send(pdu, aRes);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  unused << pdu.forget();
+  return NS_OK;
+}
+
+nsresult
+BluetoothDaemonHandsfreeModule::StopVoiceRecognitionCmd(
+  BluetoothHandsfreeResultHandler* aRes)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  nsAutoPtr<BluetoothDaemonPDU> pdu(
+    new BluetoothDaemonPDU(SERVICE_ID, OPCODE_STOP_VOICE_RECOGNITION,
+                           0)); // No payload
+
+  nsresult rv = Send(pdu, aRes);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  unused << pdu.forget();
+  return NS_OK;
+}
+
+nsresult
+BluetoothDaemonHandsfreeModule::VolumeControlCmd(
+  BluetoothHandsfreeVolumeType aType, int aVolume,
+  BluetoothHandsfreeResultHandler* aRes)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  nsAutoPtr<BluetoothDaemonPDU> pdu(
+    new BluetoothDaemonPDU(SERVICE_ID, OPCODE_VOLUME_CONTROL,
+                           1 + // Volume type
+                           1)); // Volume
+
+  nsresult rv = PackPDU(aType, PackConversion<int, uint8_t>(aVolume), *pdu);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  rv = Send(pdu, aRes);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  unused << pdu.forget();
+  return NS_OK;
+}
+
+nsresult
+BluetoothDaemonHandsfreeModule::DeviceStatusNotificationCmd(
+  BluetoothHandsfreeNetworkState aNtkState,
+  BluetoothHandsfreeServiceType aSvcType, int aSignal, int aBattChg,
+  BluetoothHandsfreeResultHandler* aRes)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  nsAutoPtr<BluetoothDaemonPDU> pdu(
+    new BluetoothDaemonPDU(SERVICE_ID, OPCODE_DEVICE_STATUS_NOTIFICATION,
+                           1 + // Network state
+                           1 + // Service type
+                           1 + // Signal strength
+                           1)); // Battery level
+
+  nsresult rv = PackPDU(aNtkState, aSvcType,
+                        PackConversion<int, uint8_t>(aSignal),
+                        PackConversion<int, uint8_t>(aBattChg), *pdu);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  rv = Send(pdu, aRes);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  unused << pdu.forget();
+  return NS_OK;
+}
+
+nsresult
+BluetoothDaemonHandsfreeModule::CopsResponseCmd(
+  const char* aCops, BluetoothHandsfreeResultHandler* aRes)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  nsAutoPtr<BluetoothDaemonPDU> pdu(
+    new BluetoothDaemonPDU(SERVICE_ID, OPCODE_COPS_RESPONSE,
+                           0)); // Dynamically allocated
+
+  nsresult rv = PackPDU(PackCString0(nsDependentCString(aCops)), *pdu);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  rv = Send(pdu, aRes);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  unused << pdu.forget();
+  return NS_OK;
+}
+
+nsresult
+BluetoothDaemonHandsfreeModule::CindResponseCmd(
+  int aSvc, int aNumActive, int aNumHeld,
+  BluetoothHandsfreeCallState aCallSetupState,
+  int aSignal, int aRoam, int aBattChg,
+  BluetoothHandsfreeResultHandler* aRes)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  nsAutoPtr<BluetoothDaemonPDU> pdu(
+    new BluetoothDaemonPDU(SERVICE_ID, OPCODE_CIND_RESPONSE,
+                           1 + // Service
+                           1 + // # Active
+                           1 + // # Held
+                           1 + // Call state
+                           1 + // Signal strength
+                           1 + // Roaming
+                           1)); // Battery level
+
+  nsresult rv = PackPDU(PackConversion<int, uint8_t>(aSvc),
+                        PackConversion<int, uint8_t>(aNumActive),
+                        PackConversion<int, uint8_t>(aNumHeld),
+                        aCallSetupState,
+                        PackConversion<int, uint8_t>(aSignal),
+                        PackConversion<int, uint8_t>(aRoam),
+                        PackConversion<int, uint8_t>(aBattChg), *pdu);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  rv = Send(pdu, aRes);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  unused << pdu.forget();
+  return NS_OK;
+}
+
+nsresult
+BluetoothDaemonHandsfreeModule::FormattedAtResponseCmd(
+  const char* aRsp, BluetoothHandsfreeResultHandler* aRes)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  nsAutoPtr<BluetoothDaemonPDU> pdu(
+    new BluetoothDaemonPDU(SERVICE_ID, OPCODE_FORMATTED_AT_RESPONSE,
+                           0)); // Dynamically allocated
+
+  nsresult rv = PackPDU(PackCString0(nsDependentCString(aRsp)), *pdu);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  rv = Send(pdu, aRes);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  unused << pdu.forget();
+  return NS_OK;
+}
+
+nsresult
+BluetoothDaemonHandsfreeModule::AtResponseCmd(
+  BluetoothHandsfreeAtResponse aResponseCode, int aErrorCode,
+  BluetoothHandsfreeResultHandler* aRes)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  nsAutoPtr<BluetoothDaemonPDU> pdu(
+    new BluetoothDaemonPDU(SERVICE_ID, OPCODE_AT_RESPONSE,
+                           1 + // AT Response code
+                           1)); // Error code
+
+  nsresult rv = PackPDU(aResponseCode,
+                        PackConversion<int, uint8_t>(aErrorCode), *pdu);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  rv = Send(pdu, aRes);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  unused << pdu.forget();
+  return NS_OK;
+}
+
+nsresult
+BluetoothDaemonHandsfreeModule::ClccResponseCmd(
+  int aIndex,
+  BluetoothHandsfreeCallDirection aDir, BluetoothHandsfreeCallState aState,
+  BluetoothHandsfreeCallMode aMode, BluetoothHandsfreeCallMptyType aMpty,
+  const nsAString& aNumber, BluetoothHandsfreeCallAddressType aType,
+  BluetoothHandsfreeResultHandler* aRes)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  NS_ConvertUTF16toUTF8 number(aNumber);
+
+  nsAutoPtr<BluetoothDaemonPDU> pdu(
+    new BluetoothDaemonPDU(SERVICE_ID, OPCODE_CLCC_RESPONSE,
+                           1 + // Call index
+                           1 + // Call direction
+                           1 + // Call state
+                           1 + // Call mode
+                           1 + // Call MPTY
+                           1 + // Address type
+                           number.Length() + 1)); // Number string + \0
+
+  nsresult rv = PackPDU(PackConversion<int, uint8_t>(aIndex),
+                        aDir, aState, aMode, aMpty, aType,
+                        PackCString0(number), *pdu);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  rv = Send(pdu, aRes);
+  if (NS_FAILED(rv)) {
+    return rv;
+  }
+  unused << pdu.forget();
+  return NS_OK;
+}
+
+nsresult
+BluetoothDaemonHandsfreeModule::PhoneStateChangeCmd(
+  int aNumActive, int aNumHeld, BluetoothHandsfreeCallState aCallSetupState,
+  const nsAString& aNumber, BluetoothHandsfreeCallAddressType aType,
+  BluetoothHandsfreeResultHandler* aRes)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  NS_ConvertUTF16toUTF8 number(aNumber);
+
+  nsAutoPtr<BluetoothDaemonPDU> pdu(
+    new BluetoothDaemonPDU(SERVICE_ID, OPCODE_PHONE_STATE_CHANGE,
+                           1 + // # Active
+                           1 + // # Held
+                           1 + // Call state
+                           1 + // Address type
+                           number.Length() + 1)); // Number string + \0
+
+  nsresult rv = PackPDU(PackConversion<int, uint8_t>(aNumActive),
+                        PackConversion<int, uint8_t>(aNumHeld),
+                        aCallSetupState, aType,
+                        PackCString0(NS_ConvertUTF16toUTF8(aNumber)), *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
+BluetoothDaemonHandsfreeModule::ErrorRsp(
+  const BluetoothDaemonPDUHeader& aHeader,
+  BluetoothDaemonPDU& aPDU, BluetoothHandsfreeResultHandler* aRes)
+{
+  ErrorRunnable::Dispatch(
+    aRes, &BluetoothHandsfreeResultHandler::OnError, UnpackPDUInitOp(aPDU));
+}
+
+void
+BluetoothDaemonHandsfreeModule::ConnectRsp(
+  const BluetoothDaemonPDUHeader& aHeader, BluetoothDaemonPDU& aPDU,
+  BluetoothHandsfreeResultHandler* aRes)
+{
+  ResultRunnable::Dispatch(
+    aRes, &BluetoothHandsfreeResultHandler::Connect, UnpackPDUInitOp(aPDU));
+}
+
+void
+BluetoothDaemonHandsfreeModule::DisconnectRsp(
+  const BluetoothDaemonPDUHeader& aHeader, BluetoothDaemonPDU& aPDU,
+  BluetoothHandsfreeResultHandler* aRes)
+{
+  ResultRunnable::Dispatch(
+    aRes, &BluetoothHandsfreeResultHandler::Disconnect, UnpackPDUInitOp(aPDU));
+}
+
+void
+BluetoothDaemonHandsfreeModule::ConnectAudioRsp(
+  const BluetoothDaemonPDUHeader& aHeader, BluetoothDaemonPDU& aPDU,
+  BluetoothHandsfreeResultHandler* aRes)
+{
+  ResultRunnable::Dispatch(
+    aRes, &BluetoothHandsfreeResultHandler::ConnectAudio,
+    UnpackPDUInitOp(aPDU));
+}
+
+void
+BluetoothDaemonHandsfreeModule::DisconnectAudioRsp(
+  const BluetoothDaemonPDUHeader& aHeader, BluetoothDaemonPDU& aPDU,
+  BluetoothHandsfreeResultHandler* aRes)
+{
+  ResultRunnable::Dispatch(
+    aRes, &BluetoothHandsfreeResultHandler::DisconnectAudio,
+    UnpackPDUInitOp(aPDU));
+}
+
+void
+BluetoothDaemonHandsfreeModule::StartVoiceRecognitionRsp(
+  const BluetoothDaemonPDUHeader& aHeader, BluetoothDaemonPDU& aPDU,
+  BluetoothHandsfreeResultHandler* aRes)
+{
+  ResultRunnable::Dispatch(
+    aRes, &BluetoothHandsfreeResultHandler::StartVoiceRecognition,
+    UnpackPDUInitOp(aPDU));
+}
+
+void
+BluetoothDaemonHandsfreeModule::StopVoiceRecognitionRsp(
+  const BluetoothDaemonPDUHeader& aHeader, BluetoothDaemonPDU& aPDU,
+  BluetoothHandsfreeResultHandler* aRes)
+{
+  ResultRunnable::Dispatch(
+    aRes, &BluetoothHandsfreeResultHandler::StopVoiceRecognition,
+    UnpackPDUInitOp(aPDU));
+}
+
+void
+BluetoothDaemonHandsfreeModule::VolumeControlRsp(
+  const BluetoothDaemonPDUHeader& aHeader, BluetoothDaemonPDU& aPDU,
+  BluetoothHandsfreeResultHandler* aRes)
+{
+  ResultRunnable::Dispatch(
+    aRes, &BluetoothHandsfreeResultHandler::VolumeControl,
+    UnpackPDUInitOp(aPDU));
+}
+
+void
+BluetoothDaemonHandsfreeModule::DeviceStatusNotificationRsp(
+  const BluetoothDaemonPDUHeader& aHeader, BluetoothDaemonPDU& aPDU,
+  BluetoothHandsfreeResultHandler* aRes)
+{
+  ResultRunnable::Dispatch(
+    aRes, &BluetoothHandsfreeResultHandler::DeviceStatusNotification,
+    UnpackPDUInitOp(aPDU));
+}
+
+void
+BluetoothDaemonHandsfreeModule::CopsResponseRsp(
+  const BluetoothDaemonPDUHeader& aHeader, BluetoothDaemonPDU& aPDU,
+  BluetoothHandsfreeResultHandler* aRes)
+{
+  ResultRunnable::Dispatch(
+    aRes, &BluetoothHandsfreeResultHandler::CopsResponse,
+    UnpackPDUInitOp(aPDU));
+}
+
+void
+BluetoothDaemonHandsfreeModule::CindResponseRsp(
+  const BluetoothDaemonPDUHeader& aHeader, BluetoothDaemonPDU& aPDU,
+  BluetoothHandsfreeResultHandler* aRes)
+{
+  ResultRunnable::Dispatch(
+    aRes, &BluetoothHandsfreeResultHandler::CindResponse,
+    UnpackPDUInitOp(aPDU));
+}
+
+void
+BluetoothDaemonHandsfreeModule::FormattedAtResponseRsp(
+  const BluetoothDaemonPDUHeader& aHeader, BluetoothDaemonPDU& aPDU,
+  BluetoothHandsfreeResultHandler* aRes)
+{
+  ResultRunnable::Dispatch(
+    aRes, &BluetoothHandsfreeResultHandler::FormattedAtResponse,
+    UnpackPDUInitOp(aPDU));
+}
+
+void
+BluetoothDaemonHandsfreeModule::AtResponseRsp(
+  const BluetoothDaemonPDUHeader& aHeader, BluetoothDaemonPDU& aPDU,
+  BluetoothHandsfreeResultHandler* aRes)
+{
+  ResultRunnable::Dispatch(
+    aRes, &BluetoothHandsfreeResultHandler::AtResponse,
+    UnpackPDUInitOp(aPDU));
+}
+
+void
+BluetoothDaemonHandsfreeModule::ClccResponseRsp(
+  const BluetoothDaemonPDUHeader& aHeader, BluetoothDaemonPDU& aPDU,
+  BluetoothHandsfreeResultHandler* aRes)
+{
+  ResultRunnable::Dispatch(
+    aRes, &BluetoothHandsfreeResultHandler::ClccResponse,
+    UnpackPDUInitOp(aPDU));
+}
+
+void
+BluetoothDaemonHandsfreeModule::PhoneStateChangeRsp(
+  const BluetoothDaemonPDUHeader& aHeader, BluetoothDaemonPDU& aPDU,
+  BluetoothHandsfreeResultHandler* aRes)
+{
+  ResultRunnable::Dispatch(
+    aRes, &BluetoothHandsfreeResultHandler::PhoneStateChange,
+    UnpackPDUInitOp(aPDU));
+}
+
+void
+BluetoothDaemonHandsfreeModule::HandleRsp(
+  const BluetoothDaemonPDUHeader& aHeader, BluetoothDaemonPDU& aPDU,
+  void* aUserData)
+{
+  static void (BluetoothDaemonHandsfreeModule::* const HandleRsp[])(
+    const BluetoothDaemonPDUHeader&,
+    BluetoothDaemonPDU&,
+    BluetoothHandsfreeResultHandler*) = {
+    INIT_ARRAY_AT(OPCODE_ERROR,
+      &BluetoothDaemonHandsfreeModule::ErrorRsp),
+    INIT_ARRAY_AT(OPCODE_CONNECT,
+      &BluetoothDaemonHandsfreeModule::ConnectRsp),
+    INIT_ARRAY_AT(OPCODE_DISCONNECT,
+      &BluetoothDaemonHandsfreeModule::DisconnectRsp),
+    INIT_ARRAY_AT(OPCODE_CONNECT_AUDIO,
+      &BluetoothDaemonHandsfreeModule::ConnectAudioRsp),
+    INIT_ARRAY_AT(OPCODE_DISCONNECT_AUDIO,
+      &BluetoothDaemonHandsfreeModule::DisconnectAudioRsp),
+    INIT_ARRAY_AT(OPCODE_START_VOICE_RECOGNITION,
+      &BluetoothDaemonHandsfreeModule::StartVoiceRecognitionRsp),
+    INIT_ARRAY_AT(OPCODE_STOP_VOICE_RECOGNITION,
+      &BluetoothDaemonHandsfreeModule::StopVoiceRecognitionRsp),
+    INIT_ARRAY_AT(OPCODE_VOLUME_CONTROL,
+      &BluetoothDaemonHandsfreeModule::VolumeControlRsp),
+    INIT_ARRAY_AT(OPCODE_DEVICE_STATUS_NOTIFICATION,
+      &BluetoothDaemonHandsfreeModule::DeviceStatusNotificationRsp),
+    INIT_ARRAY_AT(OPCODE_COPS_RESPONSE,
+      &BluetoothDaemonHandsfreeModule::CopsResponseRsp),
+    INIT_ARRAY_AT(OPCODE_CIND_RESPONSE,
+      &BluetoothDaemonHandsfreeModule::CindResponseRsp),
+    INIT_ARRAY_AT(OPCODE_FORMATTED_AT_RESPONSE,
+      &BluetoothDaemonHandsfreeModule::FormattedAtResponseRsp),
+    INIT_ARRAY_AT(OPCODE_AT_RESPONSE,
+      &BluetoothDaemonHandsfreeModule::AtResponseRsp),
+    INIT_ARRAY_AT(OPCODE_CLCC_RESPONSE,
+      &BluetoothDaemonHandsfreeModule::ClccResponseRsp),
+    INIT_ARRAY_AT(OPCODE_PHONE_STATE_CHANGE,
+      &BluetoothDaemonHandsfreeModule::PhoneStateChangeRsp)
+  };
+
+  MOZ_ASSERT(!NS_IsMainThread()); // I/O thread
+
+  if (NS_WARN_IF(!(aHeader.mOpcode < MOZ_ARRAY_LENGTH(HandleRsp))) ||
+      NS_WARN_IF(!HandleRsp[aHeader.mOpcode])) {
+    return;
+  }
+
+  nsRefPtr<BluetoothHandsfreeResultHandler> res =
+    already_AddRefed<BluetoothHandsfreeResultHandler>(
+      static_cast<BluetoothHandsfreeResultHandler*>(aUserData));
+
+  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 BluetoothDaemonHandsfreeModule::NotificationHandlerWrapper MOZ_FINAL
+{
+public:
+  typedef BluetoothHandsfreeNotificationHandler ObjectType;
+
+  static ObjectType* GetInstance()
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+
+    return sNotificationHandler;
+  }
+};
+
+// Init operator class for ConnectionStateNotification
+class BluetoothDaemonHandsfreeModule::ConnectionStateInitOp MOZ_FINAL
+  : private PDUInitOp
+{
+public:
+  ConnectionStateInitOp(BluetoothDaemonPDU& aPDU)
+    : PDUInitOp(aPDU)
+  { }
+
+  nsresult
+  operator () (BluetoothHandsfreeConnectionState& aArg1,
+               nsString& aArg2) const
+  {
+    BluetoothDaemonPDU& pdu = GetPDU();
+
+    /* Read state */
+    nsresult rv = UnpackPDU(pdu, aArg1);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+
+    /* Read address */
+    rv = UnpackPDU(
+      pdu, UnpackConversion<BluetoothAddress, nsAString>(aArg2));
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+    WarnAboutTrailingData();
+    return NS_OK;
+  }
+};
+
+void
+BluetoothDaemonHandsfreeModule::ConnectionStateNtf(
+  const BluetoothDaemonPDUHeader& aHeader, BluetoothDaemonPDU& aPDU)
+{
+  ConnectionStateNotification::Dispatch(
+    &BluetoothHandsfreeNotificationHandler::ConnectionStateNotification,
+    ConnectionStateInitOp(aPDU));
+}
+
+// Init operator class for AudioStateNotification
+class BluetoothDaemonHandsfreeModule::AudioStateInitOp MOZ_FINAL
+  : private PDUInitOp
+{
+public:
+  AudioStateInitOp(BluetoothDaemonPDU& aPDU)
+    : PDUInitOp(aPDU)
+  { }
+
+  nsresult
+  operator () (BluetoothHandsfreeAudioState& aArg1,
+               nsString& aArg2) const
+  {
+    BluetoothDaemonPDU& pdu = GetPDU();
+
+    /* Read state */
+    nsresult rv = UnpackPDU(pdu, aArg1);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+
+    /* Read address */
+    rv = UnpackPDU(
+      pdu, UnpackConversion<BluetoothAddress, nsAString>(aArg2));
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+    WarnAboutTrailingData();
+    return NS_OK;
+  }
+};
+
+void
+BluetoothDaemonHandsfreeModule::AudioStateNtf(
+  const BluetoothDaemonPDUHeader& aHeader, BluetoothDaemonPDU& aPDU)
+{
+  AudioStateNotification::Dispatch(
+    &BluetoothHandsfreeNotificationHandler::AudioStateNotification,
+    AudioStateInitOp(aPDU));
+}
+
+void
+BluetoothDaemonHandsfreeModule::VoiceRecognitionNtf(
+  const BluetoothDaemonPDUHeader& aHeader, BluetoothDaemonPDU& aPDU)
+{
+  VoiceRecognitionNotification::Dispatch(
+    &BluetoothHandsfreeNotificationHandler::VoiceRecognitionNotification,
+    UnpackPDUInitOp(aPDU));
+}
+
+void
+BluetoothDaemonHandsfreeModule::AnswerCallNtf(
+  const BluetoothDaemonPDUHeader& aHeader, BluetoothDaemonPDU& aPDU)
+{
+  AnswerCallNotification::Dispatch(
+    &BluetoothHandsfreeNotificationHandler::AnswerCallNotification,
+    UnpackPDUInitOp(aPDU));
+}
+
+void
+BluetoothDaemonHandsfreeModule::HangupCallNtf(
+  const BluetoothDaemonPDUHeader& aHeader, BluetoothDaemonPDU& aPDU)
+{
+  HangupCallNotification::Dispatch(
+    &BluetoothHandsfreeNotificationHandler::HangupCallNotification,
+    UnpackPDUInitOp(aPDU));
+}
+
+// Init operator class for VolumeNotification
+class BluetoothDaemonHandsfreeModule::VolumeInitOp MOZ_FINAL
+  : private PDUInitOp
+{
+public:
+  VolumeInitOp(BluetoothDaemonPDU& aPDU)
+    : PDUInitOp(aPDU)
+  { }
+
+  nsresult
+  operator () (BluetoothHandsfreeVolumeType& aArg1, int& aArg2) const
+  {
+    BluetoothDaemonPDU& pdu = GetPDU();
+
+    /* Read volume type */
+    nsresult rv = UnpackPDU(pdu, aArg1);
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+
+    /* Read volume */
+    rv = UnpackPDU(pdu, UnpackConversion<uint8_t, int>(aArg2));
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+    WarnAboutTrailingData();
+    return NS_OK;
+  }
+};
+
+void
+BluetoothDaemonHandsfreeModule::VolumeNtf(
+  const BluetoothDaemonPDUHeader& aHeader, BluetoothDaemonPDU& aPDU)
+{
+  VolumeNotification::Dispatch(
+    &BluetoothHandsfreeNotificationHandler::VolumeNotification,
+    VolumeInitOp(aPDU));
+}
+
+// Init operator class for DialCallNotification
+class BluetoothDaemonHandsfreeModule::DialCallInitOp MOZ_FINAL
+  : private PDUInitOp
+{
+public:
+  DialCallInitOp(BluetoothDaemonPDU& aPDU)
+    : PDUInitOp(aPDU)
+  { }
+
+  nsresult
+  operator () (nsString& aArg1) const
+  {
+    /* Read number */
+    nsresult rv = UnpackPDU(GetPDU(), UnpackString0(aArg1));
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+    WarnAboutTrailingData();
+    return NS_OK;
+  }
+};
+
+void
+BluetoothDaemonHandsfreeModule::DialCallNtf(
+  const BluetoothDaemonPDUHeader& aHeader, BluetoothDaemonPDU& aPDU)
+{
+  DialCallNotification::Dispatch(
+    &BluetoothHandsfreeNotificationHandler::DialCallNotification,
+    DialCallInitOp(aPDU));
+}
+
+void
+BluetoothDaemonHandsfreeModule::DtmfNtf(
+  const BluetoothDaemonPDUHeader& aHeader, BluetoothDaemonPDU& aPDU)
+{
+  DtmfNotification::Dispatch(
+    &BluetoothHandsfreeNotificationHandler::DtmfNotification,
+    UnpackPDUInitOp(aPDU));
+}
+
+void
+BluetoothDaemonHandsfreeModule::NRECNtf(
+  const BluetoothDaemonPDUHeader& aHeader, BluetoothDaemonPDU& aPDU)
+{
+  NRECNotification::Dispatch(
+    &BluetoothHandsfreeNotificationHandler::NRECNotification,
+    UnpackPDUInitOp(aPDU));
+}
+
+void
+BluetoothDaemonHandsfreeModule::CallHoldNtf(
+  const BluetoothDaemonPDUHeader& aHeader, BluetoothDaemonPDU& aPDU)
+{
+  CallHoldNotification::Dispatch(
+    &BluetoothHandsfreeNotificationHandler::CallHoldNotification,
+    UnpackPDUInitOp(aPDU));
+}
+
+void
+BluetoothDaemonHandsfreeModule::CnumNtf(
+  const BluetoothDaemonPDUHeader& aHeader, BluetoothDaemonPDU& aPDU)
+{
+  CnumNotification::Dispatch(
+    &BluetoothHandsfreeNotificationHandler::CnumNotification,
+    UnpackPDUInitOp(aPDU));
+}
+
+void
+BluetoothDaemonHandsfreeModule::CindNtf(
+  const BluetoothDaemonPDUHeader& aHeader, BluetoothDaemonPDU& aPDU)
+{
+  CindNotification::Dispatch(
+    &BluetoothHandsfreeNotificationHandler::CindNotification,
+    UnpackPDUInitOp(aPDU));
+}
+
+void
+BluetoothDaemonHandsfreeModule::CopsNtf(
+  const BluetoothDaemonPDUHeader& aHeader, BluetoothDaemonPDU& aPDU)
+{
+  CopsNotification::Dispatch(
+    &BluetoothHandsfreeNotificationHandler::CopsNotification,
+    UnpackPDUInitOp(aPDU));
+}
+
+void
+BluetoothDaemonHandsfreeModule::ClccNtf(
+  const BluetoothDaemonPDUHeader& aHeader, BluetoothDaemonPDU& aPDU)
+{
+  ClccNotification::Dispatch(
+    &BluetoothHandsfreeNotificationHandler::ClccNotification,
+    UnpackPDUInitOp(aPDU));
+}
+
+// Init operator class for UnknownAtNotification
+class BluetoothDaemonHandsfreeModule::UnknownAtInitOp MOZ_FINAL
+  : private PDUInitOp
+{
+public:
+  UnknownAtInitOp(BluetoothDaemonPDU& aPDU)
+    : PDUInitOp(aPDU)
+  { }
+
+  nsresult
+  operator () (nsCString& aArg1) const
+  {
+    /* Read string */
+    nsresult rv = UnpackPDU(GetPDU(), UnpackCString0(aArg1));
+    if (NS_FAILED(rv)) {
+      return rv;
+    }
+    WarnAboutTrailingData();
+    return NS_OK;
+  }
+};
+
+void
+BluetoothDaemonHandsfreeModule::UnknownAtNtf(
+  const BluetoothDaemonPDUHeader& aHeader, BluetoothDaemonPDU& aPDU)
+{
+  UnknownAtNotification::Dispatch(
+    &BluetoothHandsfreeNotificationHandler::UnknownAtNotification,
+    UnknownAtInitOp(aPDU));
+}
+
+void
+BluetoothDaemonHandsfreeModule::KeyPressedNtf(
+  const BluetoothDaemonPDUHeader& aHeader, BluetoothDaemonPDU& aPDU)
+{
+  KeyPressedNotification::Dispatch(
+    &BluetoothHandsfreeNotificationHandler::KeyPressedNotification,
+    UnpackPDUInitOp(aPDU));
+}
+
+void
+BluetoothDaemonHandsfreeModule::HandleNtf(
+  const BluetoothDaemonPDUHeader& aHeader, BluetoothDaemonPDU& aPDU,
+  void* aUserData)
+{
+  static void (BluetoothDaemonHandsfreeModule::* const HandleNtf[])(
+    const BluetoothDaemonPDUHeader&, BluetoothDaemonPDU&) = {
+    INIT_ARRAY_AT(0, &BluetoothDaemonHandsfreeModule::ConnectionStateNtf),
+    INIT_ARRAY_AT(1, &BluetoothDaemonHandsfreeModule::AudioStateNtf),
+    INIT_ARRAY_AT(2, &BluetoothDaemonHandsfreeModule::VoiceRecognitionNtf),
+    INIT_ARRAY_AT(3, &BluetoothDaemonHandsfreeModule::AnswerCallNtf),
+    INIT_ARRAY_AT(4, &BluetoothDaemonHandsfreeModule::HangupCallNtf),
+    INIT_ARRAY_AT(5, &BluetoothDaemonHandsfreeModule::VolumeNtf),
+    INIT_ARRAY_AT(6, &BluetoothDaemonHandsfreeModule::DialCallNtf),
+    INIT_ARRAY_AT(7, &BluetoothDaemonHandsfreeModule::DtmfNtf),
+    INIT_ARRAY_AT(8, &BluetoothDaemonHandsfreeModule::NRECNtf),
+    INIT_ARRAY_AT(9, &BluetoothDaemonHandsfreeModule::CallHoldNtf),
+    INIT_ARRAY_AT(10, &BluetoothDaemonHandsfreeModule::CnumNtf),
+    INIT_ARRAY_AT(11, &BluetoothDaemonHandsfreeModule::CindNtf),
+    INIT_ARRAY_AT(12, &BluetoothDaemonHandsfreeModule::CopsNtf),
+    INIT_ARRAY_AT(13, &BluetoothDaemonHandsfreeModule::ClccNtf),
+    INIT_ARRAY_AT(14, &BluetoothDaemonHandsfreeModule::UnknownAtNtf),
+    INIT_ARRAY_AT(15, &BluetoothDaemonHandsfreeModule::KeyPressedNtf)
+  };
+
+  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);
+}
+
+END_BLUETOOTH_NAMESPACE
new file mode 100644
--- /dev/null
+++ b/dom/bluetooth2/bluedroid/BluetoothDaemonHandsfreeInterface.h
@@ -0,0 +1,328 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=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_bluetoothdaemonhandsfreeinterface_h
+#define mozilla_dom_bluetooth_bluetoothdaemonhandsfreeinterface_h
+
+#include "BluetoothDaemonHelpers.h"
+#include "BluetoothInterface.h"
+#include "BluetoothInterfaceHelpers.h"
+
+BEGIN_BLUETOOTH_NAMESPACE
+
+class BluetoothSetupResultHandler;
+
+class BluetoothDaemonHandsfreeModule
+{
+public:
+  enum {
+    SERVICE_ID = 0x05
+  };
+
+  enum {
+    OPCODE_ERROR = 0x00,
+    OPCODE_CONNECT = 0x01,
+    OPCODE_DISCONNECT = 0x02,
+    OPCODE_CONNECT_AUDIO = 0x03,
+    OPCODE_DISCONNECT_AUDIO = 0x04,
+    OPCODE_START_VOICE_RECOGNITION = 0x05,
+    OPCODE_STOP_VOICE_RECOGNITION =0x06,
+    OPCODE_VOLUME_CONTROL = 0x07,
+    OPCODE_DEVICE_STATUS_NOTIFICATION = 0x08,
+    OPCODE_COPS_RESPONSE = 0x09,
+    OPCODE_CIND_RESPONSE = 0x0a,
+    OPCODE_FORMATTED_AT_RESPONSE = 0x0b,
+    OPCODE_AT_RESPONSE = 0x0c,
+    OPCODE_CLCC_RESPONSE = 0x0d,
+    OPCODE_PHONE_STATE_CHANGE = 0x0e
+  };
+
+  virtual nsresult Send(BluetoothDaemonPDU* aPDU, void* aUserData) = 0;
+
+  virtual nsresult RegisterModule(uint8_t aId, uint8_t aMode,
+                                  BluetoothSetupResultHandler* aRes) = 0;
+
+  virtual nsresult UnregisterModule(uint8_t aId,
+                                    BluetoothSetupResultHandler* aRes) = 0;
+
+  void SetNotificationHandler(
+    BluetoothHandsfreeNotificationHandler* aNotificationHandler);
+
+  //
+  // Commands
+  //
+
+  nsresult ConnectCmd(const nsAString& aBdAddr,
+                      BluetoothHandsfreeResultHandler* aRes);
+  nsresult DisconnectCmd(const nsAString& aBdAddr,
+                         BluetoothHandsfreeResultHandler* aRes);
+  nsresult ConnectAudioCmd(const nsAString& aBdAddr,
+                           BluetoothHandsfreeResultHandler* aRes);
+  nsresult DisconnectAudioCmd(const nsAString& aBdAddr,
+                              BluetoothHandsfreeResultHandler* aRes);
+
+  /* Voice Recognition */
+
+  nsresult StartVoiceRecognitionCmd(BluetoothHandsfreeResultHandler* aRes);
+  nsresult StopVoiceRecognitionCmd(BluetoothHandsfreeResultHandler* aRes);
+
+  /* Volume */
+
+  nsresult VolumeControlCmd(BluetoothHandsfreeVolumeType aType, int aVolume,
+                            BluetoothHandsfreeResultHandler* aRes);
+
+  /* Device status */
+
+  nsresult DeviceStatusNotificationCmd(
+    BluetoothHandsfreeNetworkState aNtkState,
+    BluetoothHandsfreeServiceType aSvcType,
+    int aSignal, int aBattChg,
+    BluetoothHandsfreeResultHandler* aRes);
+
+  /* Responses */
+
+  nsresult CopsResponseCmd(const char* aCops,
+                           BluetoothHandsfreeResultHandler* aRes);
+  nsresult CindResponseCmd(int aSvc, int aNumActive, int aNumHeld,
+                           BluetoothHandsfreeCallState aCallSetupState,
+                           int aSignal, int aRoam, int aBattChg,
+                           BluetoothHandsfreeResultHandler* aRes);
+  nsresult FormattedAtResponseCmd(const char* aRsp,
+                                  BluetoothHandsfreeResultHandler* aRes);
+  nsresult AtResponseCmd(BluetoothHandsfreeAtResponse aResponseCode,
+                         int aErrorCode,
+                         BluetoothHandsfreeResultHandler* aRes);
+  nsresult ClccResponseCmd(int aIndex, BluetoothHandsfreeCallDirection aDir,
+                           BluetoothHandsfreeCallState aState,
+                           BluetoothHandsfreeCallMode aMode,
+                           BluetoothHandsfreeCallMptyType aMpty,
+                           const nsAString& aNumber,
+                           BluetoothHandsfreeCallAddressType aType,
+                           BluetoothHandsfreeResultHandler* aRes);
+
+  /* Phone State */
+
+  nsresult PhoneStateChangeCmd(int aNumActive, int aNumHeld,
+                               BluetoothHandsfreeCallState aCallSetupState,
+                               const nsAString& aNumber,
+                               BluetoothHandsfreeCallAddressType aType,
+                               BluetoothHandsfreeResultHandler* aRes);
+
+protected:
+  nsresult Send(BluetoothDaemonPDU* aPDU,
+                BluetoothHandsfreeResultHandler* aRes);
+
+  void HandleSvc(const BluetoothDaemonPDUHeader& aHeader,
+                 BluetoothDaemonPDU& aPDU, void* aUserData);
+
+  //
+  // Responses
+  //
+
+  typedef BluetoothResultRunnable0<BluetoothHandsfreeResultHandler, void>
+    ResultRunnable;
+
+  typedef BluetoothResultRunnable1<BluetoothHandsfreeResultHandler, void,
+                                   BluetoothStatus, BluetoothStatus>
+    ErrorRunnable;
+
+  void ErrorRsp(const BluetoothDaemonPDUHeader& aHeader,
+                BluetoothDaemonPDU& aPDU,
+                BluetoothHandsfreeResultHandler* aRes);
+
+  void ConnectRsp(const BluetoothDaemonPDUHeader& aHeader,
+                  BluetoothDaemonPDU& aPDU,
+                  BluetoothHandsfreeResultHandler* aRes);
+
+  void DisconnectRsp(const BluetoothDaemonPDUHeader& aHeader,
+                     BluetoothDaemonPDU& aPDU,
+                     BluetoothHandsfreeResultHandler* aRes);
+
+  void ConnectAudioRsp(const BluetoothDaemonPDUHeader& aHeader,
+                       BluetoothDaemonPDU& aPDU,
+                       BluetoothHandsfreeResultHandler* aRes);
+
+  void DisconnectAudioRsp(const BluetoothDaemonPDUHeader& aHeader,
+                          BluetoothDaemonPDU& aPDU,
+                          BluetoothHandsfreeResultHandler* aRes);
+
+  void StartVoiceRecognitionRsp(const BluetoothDaemonPDUHeader& aHeader,
+                                BluetoothDaemonPDU& aPDU,
+                                BluetoothHandsfreeResultHandler* aRes);
+
+  void StopVoiceRecognitionRsp(const BluetoothDaemonPDUHeader& aHeader,
+                               BluetoothDaemonPDU& aPDU,
+                               BluetoothHandsfreeResultHandler* aRes);
+
+  void VolumeControlRsp(const BluetoothDaemonPDUHeader& aHeader,
+                        BluetoothDaemonPDU& aPDU,
+                        BluetoothHandsfreeResultHandler* aRes);
+
+  void DeviceStatusNotificationRsp(const BluetoothDaemonPDUHeader& aHeader,
+                                   BluetoothDaemonPDU& aPDU,
+                                   BluetoothHandsfreeResultHandler* aRes);
+
+  void CopsResponseRsp(const BluetoothDaemonPDUHeader& aHeader,
+                       BluetoothDaemonPDU& aPDU,
+                       BluetoothHandsfreeResultHandler* aRes);
+
+  void CindResponseRsp(const BluetoothDaemonPDUHeader& aHeader,
+                       BluetoothDaemonPDU& aPDU,
+                       BluetoothHandsfreeResultHandler* aRes);
+
+  void FormattedAtResponseRsp(const BluetoothDaemonPDUHeader& aHeader,
+                              BluetoothDaemonPDU& aPDU,
+                              BluetoothHandsfreeResultHandler* aRes);
+
+  void AtResponseRsp(const BluetoothDaemonPDUHeader& aHeader,
+                     BluetoothDaemonPDU& aPDU,
+                     BluetoothHandsfreeResultHandler* aRes);
+
+  void ClccResponseRsp(const BluetoothDaemonPDUHeader& aHeader,
+                       BluetoothDaemonPDU& aPDU,
+                       BluetoothHandsfreeResultHandler* aRes);
+
+  void PhoneStateChangeRsp(const BluetoothDaemonPDUHeader& aHeader,
+                           BluetoothDaemonPDU& aPDU,
+                           BluetoothHandsfreeResultHandler* aRes);
+
+  void HandleRsp(const BluetoothDaemonPDUHeader& aHeader,
+                 BluetoothDaemonPDU& aPDU,
+                 void* aUserData);
+
+  //
+  // Notifications
+  //
+
+  class NotificationHandlerWrapper;
+
+  typedef BluetoothNotificationRunnable2<NotificationHandlerWrapper, void,
+                                         BluetoothHandsfreeConnectionState,
+                                         nsString,
+                                         BluetoothHandsfreeConnectionState,
+                                         const nsAString&>
+    ConnectionStateNotification;
+
+  typedef BluetoothNotificationRunnable2<NotificationHandlerWrapper, void,
+                                         BluetoothHandsfreeAudioState,
+                                         nsString,
+                                         BluetoothHandsfreeAudioState,
+                                         const nsAString&>
+    AudioStateNotification;
+
+  typedef BluetoothNotificationRunnable1<NotificationHandlerWrapper, void,
+    BluetoothHandsfreeVoiceRecognitionState>
+    VoiceRecognitionNotification;
+
+  typedef BluetoothNotificationRunnable0<NotificationHandlerWrapper, void>
+    AnswerCallNotification;
+
+  typedef BluetoothNotificationRunnable0<NotificationHandlerWrapper, void>
+    HangupCallNotification;
+
+  typedef BluetoothNotificationRunnable2<NotificationHandlerWrapper, void,
+                                         BluetoothHandsfreeVolumeType, int>
+    VolumeNotification;
+
+  typedef BluetoothNotificationRunnable1<NotificationHandlerWrapper, void,
+                                         nsString, const nsAString&>
+    DialCallNotification;
+
+  typedef BluetoothNotificationRunnable1<NotificationHandlerWrapper, void,
+                                         char>
+    DtmfNotification;
+
+  typedef BluetoothNotificationRunnable1<NotificationHandlerWrapper, void,
+                                         BluetoothHandsfreeNRECState>
+    NRECNotification;
+
+  typedef BluetoothNotificationRunnable1<NotificationHandlerWrapper, void,
+                                         BluetoothHandsfreeCallHoldType>
+    CallHoldNotification;
+
+  typedef BluetoothNotificationRunnable0<NotificationHandlerWrapper, void>
+    CnumNotification;
+
+  typedef BluetoothNotificationRunnable0<NotificationHandlerWrapper, void>
+    CindNotification;
+
+  typedef BluetoothNotificationRunnable0<NotificationHandlerWrapper, void>
+    CopsNotification;
+
+  typedef BluetoothNotificationRunnable0<NotificationHandlerWrapper, void>
+    ClccNotification;
+
+  typedef BluetoothNotificationRunnable1<NotificationHandlerWrapper, void,
+                                         nsCString, const nsACString&>
+    UnknownAtNotification;
+
+  typedef BluetoothNotificationRunnable0<NotificationHandlerWrapper, void>
+    KeyPressedNotification;
+
+  class AudioStateInitOp;
+  class ConnectionStateInitOp;
+  class DialCallInitOp;
+  class VolumeInitOp;
+  class UnknownAtInitOp;
+
+  void ConnectionStateNtf(const BluetoothDaemonPDUHeader& aHeader,
+                          BluetoothDaemonPDU& aPDU);
+
+  void AudioStateNtf(const BluetoothDaemonPDUHeader& aHeader,
+                     BluetoothDaemonPDU& aPDU);
+
+  void VoiceRecognitionNtf(const BluetoothDaemonPDUHeader& aHeader,
+                           BluetoothDaemonPDU& aPDU);
+
+  void AnswerCallNtf(const BluetoothDaemonPDUHeader& aHeader,
+                     BluetoothDaemonPDU& aPDU);
+
+  void HangupCallNtf(const BluetoothDaemonPDUHeader& aHeader,
+                     BluetoothDaemonPDU& aPDU);
+
+  void VolumeNtf(const BluetoothDaemonPDUHeader& aHeader,
+                 BluetoothDaemonPDU& aPDU);
+
+  void DialCallNtf(const BluetoothDaemonPDUHeader& aHeader,
+                   BluetoothDaemonPDU& aPDU);
+
+  void DtmfNtf(const BluetoothDaemonPDUHeader& aHeader,
+               BluetoothDaemonPDU& aPDU);
+
+  void NRECNtf(const BluetoothDaemonPDUHeader& aHeader,
+               BluetoothDaemonPDU& aPDU);
+
+  void CallHoldNtf(const BluetoothDaemonPDUHeader& aHeader,
+                   BluetoothDaemonPDU& aPDU);
+
+  void CnumNtf(const BluetoothDaemonPDUHeader& aHeader,
+               BluetoothDaemonPDU& aPDU);
+
+  void CindNtf(const BluetoothDaemonPDUHeader& aHeader,
+               BluetoothDaemonPDU& aPDU);
+
+  void CopsNtf(const BluetoothDaemonPDUHeader& aHeader,
+               BluetoothDaemonPDU& aPDU);
+
+  void ClccNtf(const BluetoothDaemonPDUHeader& aHeader,
+               BluetoothDaemonPDU& aPDU);
+
+  void UnknownAtNtf(const BluetoothDaemonPDUHeader& aHeader,
+                    BluetoothDaemonPDU& aPDU);
+
+  void KeyPressedNtf(const BluetoothDaemonPDUHeader& aHeader,
+                     BluetoothDaemonPDU& aPDU);
+
+  void HandleNtf(const BluetoothDaemonPDUHeader& aHeader,
+                 BluetoothDaemonPDU& aPDU,
+                 void* aUserData);
+
+  static BluetoothHandsfreeNotificationHandler* sNotificationHandler;
+};
+
+END_BLUETOOTH_NAMESPACE
+
+#endif
--- a/dom/bluetooth2/moz.build
+++ b/dom/bluetooth2/moz.build
@@ -46,16 +46,17 @@ if CONFIG['MOZ_B2G_BT']:
                 'bluez',
             ]
             DEFINES['MOZ_B2G_BT_BLUEZ'] = True
         elif CONFIG['MOZ_B2G_BT_BLUEDROID']:
             SOURCES += [
                 'bluedroid/BluetoothA2dpHALInterface.cpp',
                 'bluedroid/BluetoothA2dpManager.cpp',
                 'bluedroid/BluetoothAvrcpHALInterface.cpp',
+                'bluedroid/BluetoothDaemonHandsfreeInterface.cpp',
                 'bluedroid/BluetoothDaemonHelpers.cpp',
                 'bluedroid/BluetoothDaemonInterface.cpp',
                 'bluedroid/BluetoothDaemonSetupInterface.cpp',
                 'bluedroid/BluetoothDaemonSocketInterface.cpp',
                 'bluedroid/BluetoothGattHALInterface.cpp',
                 'bluedroid/BluetoothGattManager.cpp',
                 'bluedroid/BluetoothHALHelpers.cpp',
                 'bluedroid/BluetoothHALInterface.cpp',