Merge m-c to f-t, a=merge
authorPhil Ringnalda <philringnalda@gmail.com>
Mon, 01 Sep 2014 19:30:31 -0700
changeset 224566 f8f3a9b2f9ed0feedde6c98fda7d5f0fc04f375b
parent 224565 b3e9dee0a79e3fe8fde7304c70575683fd5871e6 (current diff)
parent 224462 96d70813ce16a9e05e4c0d3d5bb26a690ef21d5b (diff)
child 224567 c360f3d1c00d73b0c1fb0a2c0da525cb55e58b83
push id3979
push userraliiev@mozilla.com
push dateMon, 13 Oct 2014 16:35:44 +0000
treeherdermozilla-beta@30f2cc610691 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone34.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
Merge m-c to f-t, a=merge
--- a/accessible/base/TreeWalker.cpp
+++ b/accessible/base/TreeWalker.cpp
@@ -7,98 +7,135 @@
 
 #include "Accessible.h"
 #include "nsAccessibilityService.h"
 #include "DocAccessible.h"
 
 #include "mozilla/dom/ChildIterator.h"
 #include "mozilla/dom/Element.h"
 
-using namespace mozilla;
 using namespace mozilla::a11y;
 
 ////////////////////////////////////////////////////////////////////////////////
+// WalkState
+////////////////////////////////////////////////////////////////////////////////
+
+namespace mozilla {
+namespace a11y {
+
+struct WalkState
+{
+  WalkState(nsIContent *aContent, uint32_t aFilter) :
+    content(aContent), prevState(nullptr), iter(aContent, aFilter) {}
+
+  nsCOMPtr<nsIContent> content;
+  WalkState *prevState;
+  dom::AllChildrenIterator iter;
+};
+
+} // namespace a11y
+} // namespace mozilla
+
+////////////////////////////////////////////////////////////////////////////////
 // TreeWalker
 ////////////////////////////////////////////////////////////////////////////////
 
 TreeWalker::
   TreeWalker(Accessible* aContext, nsIContent* aContent, uint32_t aFlags) :
-  mDoc(aContext->Document()), mContext(aContext), mAnchorNode(aContent),
-  mFlags(aFlags)
+  mDoc(aContext->Document()), mContext(aContext),
+  mFlags(aFlags), mState(nullptr)
 {
   NS_ASSERTION(aContent, "No node for the accessible tree walker!");
 
   mChildFilter = mContext->CanHaveAnonChildren() ?
     nsIContent::eAllChildren : nsIContent::eAllButXBL;
   mChildFilter |= nsIContent::eSkipPlaceholderContent;
 
   if (aContent)
-    PushState(aContent);
+    mState = new WalkState(aContent, mChildFilter);
 
   MOZ_COUNT_CTOR(TreeWalker);
 }
 
 TreeWalker::~TreeWalker()
 {
+  // Clear state stack from memory
+  while (mState)
+    PopState();
+
   MOZ_COUNT_DTOR(TreeWalker);
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // TreeWalker: private
 
 Accessible*
-TreeWalker::NextChild()
+TreeWalker::NextChildInternal(bool aNoWalkUp)
 {
-  if (mStateStack.IsEmpty())
+  if (!mState || !mState->content)
     return nullptr;
 
-  dom::AllChildrenIterator* top = &mStateStack[mStateStack.Length() - 1];
-  while (top) {
-    while (nsIContent* childNode = top->GetNextChild()) {
-      bool isSubtreeHidden = false;
-      Accessible* accessible = mFlags & eWalkCache ?
-        mDoc->GetAccessible(childNode) :
-        GetAccService()->GetOrCreateAccessible(childNode, mContext,
-                                               &isSubtreeHidden);
+  while (nsIContent* childNode = mState->iter.GetNextChild()) {
+    bool isSubtreeHidden = false;
+    Accessible* accessible = mFlags & eWalkCache ?
+      mDoc->GetAccessible(childNode) :
+      GetAccService()->GetOrCreateAccessible(childNode, mContext,
+                                             &isSubtreeHidden);
 
+    if (accessible)
+      return accessible;
+
+    // Walk down into subtree to find accessibles.
+    if (!isSubtreeHidden && childNode->IsElement()) {
+      PushState(childNode);
+      accessible = NextChildInternal(true);
       if (accessible)
         return accessible;
+    }
+  }
 
-      // Walk down into subtree to find accessibles.
-      if (!isSubtreeHidden && childNode->IsElement())
-        top = PushState(childNode);
-    }
+  // No more children, get back to the parent.
+  nsIContent* anchorNode = mState->content;
+  PopState();
+  if (aNoWalkUp)
+    return nullptr;
 
-    top = PopState();
-  }
+  if (mState)
+    return NextChildInternal(false);
 
   // If we traversed the whole subtree of the anchor node. Move to next node
   // relative anchor node within the context subtree if possible.
   if (mFlags != eWalkContextTree)
     return nullptr;
 
-  nsINode* contextNode = mContext->GetNode();
-  while (mAnchorNode != contextNode) {
-    nsINode* parentNode = mAnchorNode->GetFlattenedTreeParent();
+  while (anchorNode != mContext->GetNode()) {
+    nsINode* parentNode = anchorNode->GetFlattenedTreeParent();
     if (!parentNode || !parentNode->IsElement())
       return nullptr;
 
-    nsIContent* parent = parentNode->AsElement();
-    top = mStateStack.AppendElement(dom::AllChildrenIterator(parent,
-                                                             mChildFilter));
-    while (nsIContent* childNode = top->GetNextChild()) {
-      if (childNode == mAnchorNode) {
-        mAnchorNode = parent;
-        return NextChild();
-      }
+    PushState(parentNode->AsElement());
+    while (nsIContent* childNode = mState->iter.GetNextChild()) {
+      if (childNode == anchorNode)
+        return NextChildInternal(false);
     }
+    PopState();
+
+    anchorNode = parentNode->AsElement();
   }
 
   return nullptr;
 }
 
-dom::AllChildrenIterator*
+void
 TreeWalker::PopState()
 {
-  size_t length = mStateStack.Length();
-  mStateStack.RemoveElementAt(length - 1);
-  return mStateStack.IsEmpty() ? nullptr : &mStateStack[mStateStack.Length() - 1];
+  WalkState* prevToLastState = mState->prevState;
+  delete mState;
+  mState = prevToLastState;
 }
+
+void
+TreeWalker::PushState(nsIContent* aContent)
+{
+  WalkState* nextToLastState = new WalkState(aContent, mChildFilter);
+  nextToLastState->prevState = mState;
+  mState = nextToLastState;
+}
--- a/accessible/base/TreeWalker.h
+++ b/accessible/base/TreeWalker.h
@@ -3,27 +3,27 @@
  * 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_a11y_TreeWalker_h_
 #define mozilla_a11y_TreeWalker_h_
 
 #include "mozilla/Attributes.h"
 #include <stdint.h>
-#include "mozilla/dom/ChildIterator.h"
-#include "nsCOMPtr.h"
 
 class nsIContent;
 
 namespace mozilla {
 namespace a11y {
 
 class Accessible;
 class DocAccessible;
 
+struct WalkState;
+
 /**
  * This class is used to walk the DOM tree to create accessible tree.
  */
 class TreeWalker MOZ_FINAL
 {
 public:
   enum {
     // used to walk the existing tree of the given node
@@ -45,44 +45,51 @@ public:
 
   /**
    * Return the next child accessible.
    *
    * @note Returned accessible is bound to the document, if the accessible is
    *       rejected during tree creation then the caller should be unbind it
    *       from the document.
    */
-  Accessible* NextChild();
+  Accessible* NextChild()
+  {
+    return NextChildInternal(false);
+  }
 
 private:
   TreeWalker();
   TreeWalker(const TreeWalker&);
   TreeWalker& operator =(const TreeWalker&);
 
   /**
+   * Return the next child accessible.
+   *
+   * @param  aNoWalkUp  [in] specifies the walk direction, true means we
+   *                     shouldn't go up through the tree if we failed find
+   *                     accessible children.
+   */
+  Accessible* NextChildInternal(bool aNoWalkUp);
+
+  /**
    * Create new state for the given node and push it on top of stack.
    *
    * @note State stack is used to navigate up/down the DOM subtree during
    *        accessible children search.
    */
-  dom::AllChildrenIterator* PushState(nsIContent* aContent)
-  {
-    return mStateStack.AppendElement(dom::AllChildrenIterator(aContent,
-                                                              mChildFilter));
-  }
+  void PushState(nsIContent* aNode);
 
   /**
    * Pop state from stack.
    */
-  dom::AllChildrenIterator* PopState();
+  void PopState();
 
   DocAccessible* mDoc;
   Accessible* mContext;
-  nsIContent* mAnchorNode;
-  nsAutoTArray<dom::AllChildrenIterator, 20> mStateStack;
   int32_t mChildFilter;
   uint32_t mFlags;
+  WalkState* mState;
 };
 
 } // namespace a11y
 } // namespace mozilla
 
 #endif // mozilla_a11y_TreeWalker_h_
--- a/b2g/config/dolphin/sources.xml
+++ b/b2g/config/dolphin/sources.xml
@@ -10,25 +10,25 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="4b4336c73c081b39776d399835ce4853aee5cc1c">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="e7d31f0e9b6b19d9b484eeec8fb980718bc40d79"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="44bf2e3bc5ddea9db9a8c851bd353cb234aa883c"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="320650844ec7cba40a70317b761b88b47a8dca0e"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="7ddb07033043613303061416882c9b02ac3d76b6"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="95bb5b66b3ec5769c3de8d3f25d681787418e7d2"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="ebdad82e61c16772f6cd47e9f11936bf6ebe9aa0"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="8b880805d454664b3eed11d0f053cdeafa1ff06e"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" revision="a1e239a0bb5cd1d69680bf1075883aa9a7bf2429"/>
   <project groups="linux,x86" name="platform/prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" path="prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" revision="c7931763d41be602407ed9d71e2c0292c6597e00"/>
   <project groups="linux,x86" name="platform/prebuilts/python/linux-x86/2.7.5" path="prebuilts/python/linux-x86/2.7.5" revision="83760d213fb3bec7b4117d266fcfbf6fe2ba14ab"/>
   <project name="device/common" path="device/common" revision="6a2995683de147791e516aae2ccb31fdfbe2ad30"/>
--- a/b2g/config/emulator-ics/sources.xml
+++ b/b2g/config/emulator-ics/sources.xml
@@ -14,23 +14,23 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="0d616942c300d9fb142483210f1dda9096c9a9fc">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="e7d31f0e9b6b19d9b484eeec8fb980718bc40d79"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="44bf2e3bc5ddea9db9a8c851bd353cb234aa883c"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="c058843242068d0df7c107e09da31b53d2e08fa6"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="320650844ec7cba40a70317b761b88b47a8dca0e"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="7ddb07033043613303061416882c9b02ac3d76b6"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
   <project name="platform/bionic" path="bionic" revision="c72b8f6359de7ed17c11ddc9dfdde3f615d188a9"/>
   <project name="platform/bootable/recovery" path="bootable/recovery" revision="425f8b5fadf5889834c5acd27d23c9e0b2129c28"/>
   <project name="device/common" path="device/common" revision="42b808b7e93d0619286ae8e59110b176b7732389"/>
   <project name="device/sample" path="device/sample" revision="237bd668d0f114d801a8d6455ef5e02cc3577587"/>
   <project name="platform_external_apriori" path="external/apriori" remote="b2g" revision="11816ad0406744f963537b23d68ed9c2afb412bd"/>
   <project name="platform/external/bluetooth/bluez" path="external/bluetooth/bluez" revision="52a1a862a8bac319652b8f82d9541ba40bfa45ce"/>
--- a/b2g/config/emulator-jb/sources.xml
+++ b/b2g/config/emulator-jb/sources.xml
@@ -12,20 +12,20 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="74465af039d2809454afdfef285285bb63146e1b">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="e7d31f0e9b6b19d9b484eeec8fb980718bc40d79"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="44bf2e3bc5ddea9db9a8c851bd353cb234aa883c"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="320650844ec7cba40a70317b761b88b47a8dca0e"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="7ddb07033043613303061416882c9b02ac3d76b6"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="9025e50b9d29b3cabbbb21e1dd94d0d13121a17e"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="b89fda71fcd0fa0cf969310e75be3ea33e048b44"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="2e7d5348f35575870b3c7e567a9a9f6d66f8d6c5"/>
--- a/b2g/config/emulator-kk/sources.xml
+++ b/b2g/config/emulator-kk/sources.xml
@@ -10,25 +10,25 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="4b4336c73c081b39776d399835ce4853aee5cc1c">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="e7d31f0e9b6b19d9b484eeec8fb980718bc40d79"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="44bf2e3bc5ddea9db9a8c851bd353cb234aa883c"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="320650844ec7cba40a70317b761b88b47a8dca0e"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="7ddb07033043613303061416882c9b02ac3d76b6"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="f92a936f2aa97526d4593386754bdbf02db07a12"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="6e47ff2790f5656b5b074407829ceecf3e6188c4"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="1950e4760fa14688b83cdbb5acaa1af9f82ef434"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" revision="ac6eb97a37035c09fb5ede0852f0881e9aadf9ad"/>
   <project groups="linux,x86" name="platform/prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" path="prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" revision="737f591c5f95477148d26602c7be56cbea0cdeb9"/>
   <project groups="linux,x86" name="platform/prebuilts/python/linux-x86/2.7.5" path="prebuilts/python/linux-x86/2.7.5" revision="51da9b1981be481b92a59a826d4d78dc73d0989a"/>
   <project name="device/common" path="device/common" revision="798a3664597e6041985feab9aef42e98d458bc3d"/>
--- a/b2g/config/emulator/sources.xml
+++ b/b2g/config/emulator/sources.xml
@@ -14,23 +14,23 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="0d616942c300d9fb142483210f1dda9096c9a9fc">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="e7d31f0e9b6b19d9b484eeec8fb980718bc40d79"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="44bf2e3bc5ddea9db9a8c851bd353cb234aa883c"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>
   <project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="c058843242068d0df7c107e09da31b53d2e08fa6"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="320650844ec7cba40a70317b761b88b47a8dca0e"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="7ddb07033043613303061416882c9b02ac3d76b6"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="dd924f92906085b831bf1cbbc7484d3c043d613c"/>
   <project name="platform/bionic" path="bionic" revision="c72b8f6359de7ed17c11ddc9dfdde3f615d188a9"/>
   <project name="platform/bootable/recovery" path="bootable/recovery" revision="425f8b5fadf5889834c5acd27d23c9e0b2129c28"/>
   <project name="device/common" path="device/common" revision="42b808b7e93d0619286ae8e59110b176b7732389"/>
   <project name="device/sample" path="device/sample" revision="237bd668d0f114d801a8d6455ef5e02cc3577587"/>
   <project name="platform_external_apriori" path="external/apriori" remote="b2g" revision="11816ad0406744f963537b23d68ed9c2afb412bd"/>
   <project name="platform/external/bluetooth/bluez" path="external/bluetooth/bluez" revision="52a1a862a8bac319652b8f82d9541ba40bfa45ce"/>
--- a/b2g/config/flame-kk/sources.xml
+++ b/b2g/config/flame-kk/sources.xml
@@ -10,25 +10,25 @@
   <!--original fetch url was git://codeaurora.org/-->
   <remote fetch="https://git.mozilla.org/external/caf" name="caf"/>
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="4b4336c73c081b39776d399835ce4853aee5cc1c">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="e7d31f0e9b6b19d9b484eeec8fb980718bc40d79"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="44bf2e3bc5ddea9db9a8c851bd353cb234aa883c"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="320650844ec7cba40a70317b761b88b47a8dca0e"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="7ddb07033043613303061416882c9b02ac3d76b6"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="95bb5b66b3ec5769c3de8d3f25d681787418e7d2"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="ebdad82e61c16772f6cd47e9f11936bf6ebe9aa0"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="8b880805d454664b3eed11d0f053cdeafa1ff06e"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-linux-androideabi-4.7" revision="a1e239a0bb5cd1d69680bf1075883aa9a7bf2429"/>
   <project groups="linux,x86" name="platform/prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" path="prebuilts/gcc/linux-x86/x86/i686-linux-android-4.7" revision="c7931763d41be602407ed9d71e2c0292c6597e00"/>
   <project groups="linux,x86" name="platform/prebuilts/python/linux-x86/2.7.5" path="prebuilts/python/linux-x86/2.7.5" revision="a32003194f707f66a2d8cdb913ed1869f1926c5d"/>
   <project name="device/common" path="device/common" revision="96d4d2006c4fcb2f19a3fa47ab10cb409faa017b"/>
--- a/b2g/config/flame/sources.xml
+++ b/b2g/config/flame/sources.xml
@@ -12,20 +12,20 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="74465af039d2809454afdfef285285bb63146e1b">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="e7d31f0e9b6b19d9b484eeec8fb980718bc40d79"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="44bf2e3bc5ddea9db9a8c851bd353cb234aa883c"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="320650844ec7cba40a70317b761b88b47a8dca0e"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="7ddb07033043613303061416882c9b02ac3d76b6"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="e95b4ce22c825da44d14299e1190ea39a5260bde"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="471afab478649078ad7c75ec6b252481a59e19b8"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="95bb5b66b3ec5769c3de8d3f25d681787418e7d2"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="ebdad82e61c16772f6cd47e9f11936bf6ebe9aa0"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="8b880805d454664b3eed11d0f053cdeafa1ff06e"/>
@@ -117,17 +117,17 @@
   <project name="platform/system/security" path="system/security" revision="360f51f7af191316cd739f229db1c5f7233be063"/>
   <project name="platform/system/vold" path="system/vold" revision="153df4d067a4149c7d78f1c92fed2ce2bd6a272e"/>
   <!--original fetch url was git://github.com/t2m-foxfone/-->
   <remote fetch="https://git.mozilla.org/external/t2m-foxfone" name="t2m"/>
   <default remote="caf" revision="jb_3.2" sync-j="4"/>
   <!-- Flame specific things -->
   <project name="device/generic/armv7-a-neon" path="device/generic/armv7-a-neon" revision="e8a318f7690092e639ba88891606f4183e846d3f"/>
   <project name="device/qcom/common" path="device/qcom/common" revision="878804e0becfe5635bb8ccbf2671333d546c6fb6"/>
-  <project name="device-flame" path="device/t2m/flame" remote="b2g" revision="7dfad27ab7119ce820fc12f9e8029f0b73df4011"/>
+  <project name="device-flame" path="device/t2m/flame" remote="b2g" revision="f686fa63e8766a4799cffab0b072c7b80194c4fc"/>
   <project name="codeaurora_kernel_msm" path="kernel" remote="b2g" revision="ebb14165369f5edc3f335d5bde6eef8439073589"/>
   <project name="kernel_lk" path="bootable/bootloader/lk" remote="b2g" revision="9eb619d2efdf4bd121587d8296f5c10481f750b8"/>
   <project name="platform_bootable_recovery" path="bootable/recovery" remote="b2g" revision="e81502511cda303c803e63f049574634bc96f9f2"/>
   <project name="platform/external/bluetooth/bluedroid" path="external/bluetooth/bluedroid" revision="81c4a859d75d413ad688067829d21b7ba9205f81"/>
   <project name="platform/external/bluetooth/bluez" path="external/bluetooth/bluez" revision="f0689ac1914cdbc59e53bdc9edd9013dc157c299"/>
   <project name="platform/external/bluetooth/glib" path="external/bluetooth/glib" revision="dd925f76e4f149c3d5571b80e12f7e24bbe89c59"/>
   <project name="platform/external/dbus" path="external/dbus" revision="ea87119c843116340f5df1d94eaf8275e1055ae8"/>
   <project name="platform_external_libnfc-nci" path="external/libnfc-nci" remote="t2m" revision="4186bdecb4dae911b39a8202252cc2310d91b0be"/>
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,9 +1,9 @@
 {
     "git": {
         "git_revision": "", 
         "remote": "", 
         "branch": ""
     }, 
-    "revision": "bce92f813f48346b36ce9dffc16b0c93d0ac8330", 
+    "revision": "14400ee07e836d74039e2317feebc0a13fcb60c8", 
     "repo_path": "/integration/gaia-central"
 }
--- a/b2g/config/hamachi/sources.xml
+++ b/b2g/config/hamachi/sources.xml
@@ -12,22 +12,22 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="0d616942c300d9fb142483210f1dda9096c9a9fc">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="e7d31f0e9b6b19d9b484eeec8fb980718bc40d79"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="44bf2e3bc5ddea9db9a8c851bd353cb234aa883c"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="320650844ec7cba40a70317b761b88b47a8dca0e"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="7ddb07033043613303061416882c9b02ac3d76b6"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
   <project name="platform/bootable/recovery" path="bootable/recovery" revision="746bc48f34f5060f90801925dcdd964030c1ab6d"/>
   <project name="platform/development" path="development" revision="2460485184bc8535440bb63876d4e63ec1b4770c"/>
   <project name="device/common" path="device/common" revision="0dcc1e03659db33b77392529466f9eb685cdd3c7"/>
   <project name="device/sample" path="device/sample" revision="68b1cb978a20806176123b959cb05d4fa8adaea4"/>
   <project name="platform_external_apriori" path="external/apriori" remote="b2g" revision="11816ad0406744f963537b23d68ed9c2afb412bd"/>
--- a/b2g/config/helix/sources.xml
+++ b/b2g/config/helix/sources.xml
@@ -10,17 +10,17 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="0d616942c300d9fb142483210f1dda9096c9a9fc">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="e7d31f0e9b6b19d9b484eeec8fb980718bc40d79"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="44bf2e3bc5ddea9db9a8c851bd353cb234aa883c"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
   <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform/bionic" path="bionic" revision="d2eb6c7b6e1bc7643c17df2d9d9bcb1704d0b9ab"/>
--- a/b2g/config/nexus-4/sources.xml
+++ b/b2g/config/nexus-4/sources.xml
@@ -12,20 +12,20 @@
   <!--original fetch url was https://git.mozilla.org/releases-->
   <remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
   <!-- B2G specific things. -->
   <project name="platform_build" path="build" remote="b2g" revision="74465af039d2809454afdfef285285bb63146e1b">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
-  <project name="gaia" path="gaia" remote="mozillaorg" revision="e7d31f0e9b6b19d9b484eeec8fb980718bc40d79"/>
+  <project name="gaia" path="gaia" remote="mozillaorg" revision="44bf2e3bc5ddea9db9a8c851bd353cb234aa883c"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="320650844ec7cba40a70317b761b88b47a8dca0e"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="7ddb07033043613303061416882c9b02ac3d76b6"/>
   <project name="valgrind" path="external/valgrind" remote="b2g" revision="daa61633c32b9606f58799a3186395fd2bbb8d8c"/>
   <project name="vex" path="external/VEX" remote="b2g" revision="47f031c320888fe9f3e656602588565b52d43010"/>
   <!-- Stock Android things -->
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.1" path="prebuilts/clang/linux-x86/3.1" revision="5c45f43419d5582949284eee9cef0c43d866e03b"/>
   <project groups="linux" name="platform/prebuilts/clang/linux-x86/3.2" path="prebuilts/clang/linux-x86/3.2" revision="3748b4168e7bd8d46457d4b6786003bc6a5223ce"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/i686-linux-glibc2.7-4.6" revision="9025e50b9d29b3cabbbb21e1dd94d0d13121a17e"/>
   <project groups="linux" name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="b89fda71fcd0fa0cf969310e75be3ea33e048b44"/>
   <project groups="linux,arm" name="platform/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" path="prebuilts/gcc/linux-x86/arm/arm-eabi-4.7" revision="2e7d5348f35575870b3c7e567a9a9f6d66f8d6c5"/>
--- a/b2g/config/wasabi/sources.xml
+++ b/b2g/config/wasabi/sources.xml
@@ -12,22 +12,22 @@
   <!--original fetch url was git://github.com/apitrace/-->
   <remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
   <default remote="caf" revision="ics_chocolate_rb4.2" sync-j="4"/>
   <!-- Gonk specific things and forks -->
   <project name="platform_build" path="build" remote="b2g" revision="0d616942c300d9fb142483210f1dda9096c9a9fc">
     <copyfile dest="Makefile" src="core/root.mk"/>
   </project>
   <project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
-  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="e7d31f0e9b6b19d9b484eeec8fb980718bc40d79"/>
+  <project name="gaia.git" path="gaia" remote="mozillaorg" revision="44bf2e3bc5ddea9db9a8c851bd353cb234aa883c"/>
   <project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3bb61a27cd2941b2ba9b616a11aaa44269210396"/>
   <project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
   <project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
   <project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
-  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="320650844ec7cba40a70317b761b88b47a8dca0e"/>
+  <project name="apitrace" path="external/apitrace" remote="apitrace" revision="7ddb07033043613303061416882c9b02ac3d76b6"/>
   <project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
   <!-- Stock Android things -->
   <project name="platform/abi/cpp" path="abi/cpp" revision="6426040f1be4a844082c9769171ce7f5341a5528"/>
   <project name="platform/bionic" path="bionic" revision="cd5dfce80bc3f0139a56b58aca633202ccaee7f8"/>
   <project name="platform/bootable/recovery" path="bootable/recovery" revision="e0a9ac010df3afaa47ba107192c05ac8b5516435"/>
   <project name="platform/development" path="development" revision="a384622f5fcb1d2bebb9102591ff7ae91fe8ed2d"/>
   <project name="device/common" path="device/common" revision="7c65ea240157763b8ded6154a17d3c033167afb7"/>
   <project name="device/sample" path="device/sample" revision="c328f3d4409db801628861baa8d279fb8855892f"/>
--- a/dom/bluetooth/BluetoothCommon.h
+++ b/dom/bluetooth/BluetoothCommon.h
@@ -334,26 +334,49 @@ typedef mozilla::Observer<BluetoothSigna
 enum BluetoothObjectType {
   TYPE_MANAGER = 0,
   TYPE_ADAPTER = 1,
   TYPE_DEVICE = 2,
 
   TYPE_INVALID
 };
 
+enum BluetoothA2dpAudioState {
+  A2DP_AUDIO_STATE_REMOTE_SUSPEND,
+  A2DP_AUDIO_STATE_STOPPED,
+  A2DP_AUDIO_STATE_STARTED,
+};
+
+enum BluetoothA2dpConnectionState {
+  A2DP_CONNECTION_STATE_DISCONNECTED,
+  A2DP_CONNECTION_STATE_CONNECTING,
+  A2DP_CONNECTION_STATE_CONNECTED,
+  A2DP_CONNECTION_STATE_DISCONNECTING
+};
+
 enum ControlPlayStatus {
   PLAYSTATUS_STOPPED  = 0x00,
   PLAYSTATUS_PLAYING  = 0x01,
   PLAYSTATUS_PAUSED   = 0x02,
   PLAYSTATUS_FWD_SEEK = 0x03,
   PLAYSTATUS_REV_SEEK = 0x04,
   PLAYSTATUS_UNKNOWN,
   PLAYSTATUS_ERROR    = 0xFF,
 };
 
+enum BluetoothAvrcpMediaAttribute {
+  AVRCP_MEDIA_ATTRIBUTE_TITLE,
+  AVRCP_MEDIA_ATTRIBUTE_ARTIST,
+  AVRCP_MEDIA_ATTRIBUTE_ALBUM,
+  AVRCP_MEDIA_ATTRIBUTE_TRACK_NUM,
+  AVRCP_MEDIA_ATTRIBUTE_NUM_TRACKS,
+  AVRCP_MEDIA_ATTRIBUTE_GENRE,
+  AVRCP_MEDIA_ATTRIBUTE_PLAYING_TIME
+};
+
 enum BluetoothAvrcpPlayerAttribute {
   AVRCP_PLAYER_ATTRIBUTE_EQUALIZER,
   AVRCP_PLAYER_ATTRIBUTE_REPEAT,
   AVRCP_PLAYER_ATTRIBUTE_SHUFFLE,
   AVRCP_PLAYER_ATTRIBUTE_SCAN
 };
 
 enum BluetoothAvrcpStatus {
@@ -373,25 +396,38 @@ enum BluetoothAvrcpEvent {
   AVRCP_EVENT_APP_SETTINGS_CHANGED
 };
 
 enum BluetoothAvrcpNotification {
   AVRCP_NTF_INTERIM,
   AVRCP_NTF_CHANGED
 };
 
+enum BluetoothAvrcpRemoteFeature {
+  AVRCP_REMOTE_FEATURE_NONE,
+  AVRCP_REMOTE_FEATURE_METADATA,
+  AVRCP_REMOTE_FEATURE_ABSOLUTE_VOLUME,
+  AVRCP_REMOTE_FEATURE_BROWSE
+};
+
 struct BluetoothAvrcpElementAttribute {
   uint32_t mId;
   nsString mValue;
 };
 
 struct BluetoothAvrcpNotificationParam {
   ControlPlayStatus mPlayStatus;
   uint8_t mTrack[8];
   uint32_t mSongPos;
   uint8_t mNumAttr;
   uint8_t mIds[256];
   uint8_t mValues[256];
 };
 
+struct BluetoothAvrcpPlayerSettings {
+  uint8_t mNumAttr;
+  uint8_t mIds[256];
+  uint8_t mValues[256];
+};
+
 END_BLUETOOTH_NAMESPACE
 
 #endif // mozilla_dom_bluetooth_bluetoothcommon_h__
--- a/dom/bluetooth/bluedroid/BluetoothA2dpManager.cpp
+++ b/dom/bluetooth/bluedroid/BluetoothA2dpManager.cpp
@@ -2,17 +2,16 @@
 /* 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 "base/basictypes.h"
 
 #include "BluetoothA2dpManager.h"
-#include "BluetoothInterface.h"
 #include "BluetoothCommon.h"
 #include "BluetoothService.h"
 #include "BluetoothSocket.h"
 #include "BluetoothUtils.h"
 
 #include "mozilla/dom/bluetooth/BluetoothTypes.h"
 #include "mozilla/Services.h"
 #include "mozilla/StaticPtr.h"
@@ -32,181 +31,52 @@ namespace {
   StaticRefPtr<BluetoothA2dpManager> sBluetoothA2dpManager;
   bool sInShutdown = false;
   static BluetoothA2dpInterface* sBtA2dpInterface;
 #if ANDROID_VERSION > 17
   static BluetoothAvrcpInterface* sBtAvrcpInterface;
 #endif
 } // anonymous namespace
 
-class SinkPropertyChangedHandler : public nsRunnable
-{
-public:
-  SinkPropertyChangedHandler(const BluetoothSignal& aSignal)
-    : mSignal(aSignal)
-  {
-  }
-
-  NS_IMETHOD
-  Run()
-  {
-    MOZ_ASSERT(NS_IsMainThread());
-
-    BluetoothA2dpManager* a2dp = BluetoothA2dpManager::Get();
-    NS_ENSURE_TRUE(a2dp, NS_ERROR_FAILURE);
-    a2dp->HandleSinkPropertyChanged(mSignal);
-
-    return NS_OK;
-  }
-
-private:
-  BluetoothSignal mSignal;
-};
-
-class RequestPlayStatusTask : public nsRunnable
-{
-public:
-  RequestPlayStatusTask()
-  {
-    MOZ_ASSERT(!NS_IsMainThread());
-  }
-
-  nsresult Run()
-  {
-    MOZ_ASSERT(NS_IsMainThread());
-
-    BluetoothSignal signal(NS_LITERAL_STRING(REQUEST_MEDIA_PLAYSTATUS_ID),
-                           NS_LITERAL_STRING(KEY_ADAPTER),
-                           InfallibleTArray<BluetoothNamedValue>());
-
-    BluetoothService* bs = BluetoothService::Get();
-    NS_ENSURE_TRUE(bs, NS_ERROR_FAILURE);
-    bs->DistributeSignal(signal);
-
-    return NS_OK;
-  }
-};
-
 #if ANDROID_VERSION > 17
-class UpdateRegisterNotificationTask : public nsRunnable
-{
-public:
-  UpdateRegisterNotificationTask(BluetoothAvrcpEvent aEvent, uint32_t aParam)
-    : mEvent(aEvent)
-    , mParam(aParam)
-  {
-    MOZ_ASSERT(!NS_IsMainThread());
-  }
-
-  nsresult Run()
-  {
-    MOZ_ASSERT(NS_IsMainThread());
-
-    BluetoothA2dpManager* a2dp = BluetoothA2dpManager::Get();
-    NS_ENSURE_TRUE(a2dp, NS_OK);
-    a2dp->UpdateRegisterNotification(mEvent, mParam);
-    return NS_OK;
-  }
-private:
-  BluetoothAvrcpEvent mEvent;
-  uint32_t mParam;
-};
-
 /*
  * This function maps attribute id and returns corresponding values
- * Attribute id refers to btrc_media_attr_t in bt_rc.h
  */
 static void
-ConvertAttributeString(int aAttrId, nsAString& aAttrStr)
+ConvertAttributeString(BluetoothAvrcpMediaAttribute aAttrId,
+                       nsAString& aAttrStr)
 {
   BluetoothA2dpManager* a2dp = BluetoothA2dpManager::Get();
   NS_ENSURE_TRUE_VOID(a2dp);
 
   switch (aAttrId) {
-    case BTRC_MEDIA_ATTR_TITLE:
+    case AVRCP_MEDIA_ATTRIBUTE_TITLE:
       a2dp->GetTitle(aAttrStr);
       break;
-    case BTRC_MEDIA_ATTR_ARTIST:
+    case AVRCP_MEDIA_ATTRIBUTE_ARTIST:
       a2dp->GetArtist(aAttrStr);
       break;
-    case BTRC_MEDIA_ATTR_ALBUM:
+    case AVRCP_MEDIA_ATTRIBUTE_ALBUM:
       a2dp->GetAlbum(aAttrStr);
       break;
-    case BTRC_MEDIA_ATTR_TRACK_NUM:
+    case AVRCP_MEDIA_ATTRIBUTE_TRACK_NUM:
       aAttrStr.AppendInt(a2dp->GetMediaNumber());
       break;
-    case BTRC_MEDIA_ATTR_NUM_TRACKS:
+    case AVRCP_MEDIA_ATTRIBUTE_NUM_TRACKS:
       aAttrStr.AppendInt(a2dp->GetTotalMediaNumber());
       break;
-    case BTRC_MEDIA_ATTR_GENRE:
+    case AVRCP_MEDIA_ATTRIBUTE_GENRE:
       // TODO: we currently don't support genre from music player
       aAttrStr.Truncate();
       break;
-    case BTRC_MEDIA_ATTR_PLAYING_TIME:
+    case AVRCP_MEDIA_ATTRIBUTE_PLAYING_TIME:
       aAttrStr.AppendInt(a2dp->GetDuration());
       break;
   }
 }
-
-class UpdateElementAttrsTask : public nsRunnable
-{
-public:
-  UpdateElementAttrsTask(uint8_t aNumAttr, const btrc_media_attr_t* aPlayerAttrs)
-  : mNumAttr(aNumAttr)
-  {
-    MOZ_ASSERT(!NS_IsMainThread());
-
-    mAttrs = new BluetoothAvrcpElementAttribute[mNumAttr];
-
-    for (uint8_t i = 0; i < mNumAttr; ++i) {
-      mAttrs[i].mId = aPlayerAttrs[i];
-    }
-  }
-
-  nsresult Run()
-  {
-    MOZ_ASSERT(NS_IsMainThread());
-
-    for (uint8_t i = 0; i < mNumAttr; ++i) {
-      ConvertAttributeString(mAttrs[i].mId, mAttrs[i].mValue);
-    }
-
-    NS_ENSURE_TRUE(sBtAvrcpInterface, NS_OK);
-    sBtAvrcpInterface->GetElementAttrRsp(mNumAttr, mAttrs, nullptr);
-
-    return NS_OK;
-  }
-
-private:
-  uint8_t mNumAttr;
-  nsAutoArrayPtr<BluetoothAvrcpElementAttribute> mAttrs;
-};
-
-class UpdatePassthroughCmdTask : public nsRunnable
-{
-public:
-  UpdatePassthroughCmdTask(const nsAString& aName)
-    : mName(aName)
-  {
-    MOZ_ASSERT(!NS_IsMainThread());
-  }
-
-  nsresult Run()
-  {
-    MOZ_ASSERT(NS_IsMainThread());
-
-    NS_NAMED_LITERAL_STRING(type, "media-button");
-    BroadcastSystemMessage(type, BluetoothValue(mName));
-
-    return NS_OK;
-  }
-private:
-  nsString mName;
-};
-
 #endif
 
 NS_IMETHODIMP
 BluetoothA2dpManager::Observe(nsISupports* aSubject,
                               const char* aTopic,
                               const char16_t* aData)
 {
   MOZ_ASSERT(sBluetoothA2dpManager);
@@ -228,298 +98,31 @@ BluetoothA2dpManager::BluetoothA2dpManag
 void
 BluetoothA2dpManager::Reset()
 {
   ResetA2dp();
   ResetAvrcp();
 }
 
 static void
-AvStatusToSinkString(btav_connection_state_t aStatus, nsAString& aState)
-{
-  nsAutoString state;
-  if (aStatus == BTAV_CONNECTION_STATE_DISCONNECTED) {
-    aState = NS_LITERAL_STRING("disconnected");
-  } else if (aStatus == BTAV_CONNECTION_STATE_CONNECTING) {
-    aState = NS_LITERAL_STRING("connecting");
-  } else if (aStatus == BTAV_CONNECTION_STATE_CONNECTED) {
-    aState = NS_LITERAL_STRING("connected");
-  } else if (aStatus == BTAV_CONNECTION_STATE_DISCONNECTING) {
-    aState = NS_LITERAL_STRING("disconnecting");
-  } else {
-    BT_WARNING("Unknown sink state");
-  }
-}
-
-static void
-A2dpConnectionStateCallback(btav_connection_state_t aState,
-                            bt_bdaddr_t* aBdAddress)
+AvStatusToSinkString(BluetoothA2dpConnectionState aState, nsAString& aString)
 {
-  MOZ_ASSERT(!NS_IsMainThread());
-
-  nsString remoteDeviceBdAddress;
-  BdAddressTypeToString(aBdAddress, remoteDeviceBdAddress);
-
-  nsString a2dpState;
-  AvStatusToSinkString(aState, a2dpState);
-
-  InfallibleTArray<BluetoothNamedValue> props;
-  BT_APPEND_NAMED_VALUE(props, "State", a2dpState);
-
-  BluetoothSignal signal(NS_LITERAL_STRING("AudioSink"),
-                         remoteDeviceBdAddress, props);
-  NS_DispatchToMainThread(new SinkPropertyChangedHandler(signal));
-}
-
-static void
-A2dpAudioStateCallback(btav_audio_state_t aState,
-                       bt_bdaddr_t* aBdAddress)
-{
-  MOZ_ASSERT(!NS_IsMainThread());
-
-  nsString remoteDeviceBdAddress;
-  BdAddressTypeToString(aBdAddress, remoteDeviceBdAddress);
-
-  nsString a2dpState;
-
-  if (aState == BTAV_AUDIO_STATE_STARTED) {
-    a2dpState = NS_LITERAL_STRING("playing");
-  } else if (aState == BTAV_AUDIO_STATE_STOPPED) {
-    // for avdtp state stop stream
-    a2dpState = NS_LITERAL_STRING("connected");
-  } else if (aState == BTAV_AUDIO_STATE_REMOTE_SUSPEND) {
-    // for avdtp state suspend stream from remote side
-    a2dpState = NS_LITERAL_STRING("connected");
+  static const nsLiteralString sString[] = {
+    [A2DP_CONNECTION_STATE_DISCONNECTED] = NS_LITERAL_STRING("disconnected"),
+    [A2DP_CONNECTION_STATE_CONNECTING] = NS_LITERAL_STRING("connecting"),
+    [A2DP_CONNECTION_STATE_CONNECTED] = NS_LITERAL_STRING("connected"),
+    [A2DP_CONNECTION_STATE_DISCONNECTING] = NS_LITERAL_STRING("disconnecting")
+  };
+  if (aState >= MOZ_ARRAY_LENGTH(sString)) {
+    BT_WARNING("Unknown sink state %d", static_cast<int>(aState));
+    return;
   }
-
-  InfallibleTArray<BluetoothNamedValue> props;
-  BT_APPEND_NAMED_VALUE(props, "State", a2dpState);
-
-  BluetoothSignal signal(NS_LITERAL_STRING("AudioSink"),
-                         remoteDeviceBdAddress, props);
-  NS_DispatchToMainThread(new SinkPropertyChangedHandler(signal));
-}
-
-#if ANDROID_VERSION > 17
-/*
- * Avrcp 1.3 callbacks
- */
-
-/*
- * This function is to request Gaia player application to update
- * current play status.
- * Callback for play status request
- */
-static void
-AvrcpGetPlayStatusCallback()
-{
-  MOZ_ASSERT(!NS_IsMainThread());
-
-  NS_DispatchToMainThread(new RequestPlayStatusTask());
-}
-
-/*
- * This function is trying to get element attributes, which request from CT
- * Unlike BlueZ only calls UpdateMetaData, bluedroid does not cache meta data
- * information, but instead uses callback AvrcpGetElementAttrCallback and
- * call get_element_attr_rsp() to reply request.
- *
- * Callback to fetch the get element attributes of the current song
- * aNumAttr: It represents the number of attributes requested in aPlayerAttrs
- * aPlayerAttrs: It represents Attribute Ids
- */
-static void
-AvrcpGetElementAttrCallback(uint8_t aNumAttr, btrc_media_attr_t* aPlayerAttrs)
-{
-  MOZ_ASSERT(!NS_IsMainThread());
-
-  NS_DispatchToMainThread(new UpdateElementAttrsTask(aNumAttr, aPlayerAttrs));
-}
-
-/*
- * Callback for register notification (Play state change/track change/...)
- * To reply RegisterNotification INTERIM response
- * See AVRCP 1.3 Spec 25.2
- * aParam: It only valids if event_id is BTRC_EVT_PLAY_POS_CHANGED,
- * which is playback interval time
- */
-static void
-AvrcpRegisterNotificationCallback(btrc_event_id_t aEventId, uint32_t aParam)
-{
-  BluetoothAvrcpEvent event;
-
-  MOZ_ASSERT(!NS_IsMainThread());
-
-  switch (aEventId) {
-    case BTRC_EVT_PLAY_STATUS_CHANGED:
-      event = AVRCP_EVENT_PLAY_STATUS_CHANGED;
-    case BTRC_EVT_TRACK_CHANGE:
-      event = AVRCP_EVENT_TRACK_CHANGE;
-    case BTRC_EVT_TRACK_REACHED_END:
-      event = AVRCP_EVENT_TRACK_REACHED_END;
-    case BTRC_EVT_TRACK_REACHED_START:
-      event = AVRCP_EVENT_TRACK_REACHED_START;
-    case BTRC_EVT_PLAY_POS_CHANGED:
-      event = AVRCP_EVENT_PLAY_POS_CHANGED;
-    case BTRC_EVT_APP_SETTINGS_CHANGED:
-      event = AVRCP_EVENT_APP_SETTINGS_CHANGED;
-      break;
-    default:
-      BT_LOGR("Unknown event 0x%x", aEventId);
-      return;
-  }
-
-  NS_DispatchToMainThread(new UpdateRegisterNotificationTask(event, aParam));
+  aString = sString[aState];
 }
 
-/*
- * Player application settings is optional for Avrcp 1.3
- * B2G 1.3 currently does not support Player application setting
- * related functions. Support Player Setting in the future version
- */
-static void
-AvrcpListPlayerAppAttributeCallback()
-{
-  MOZ_ASSERT(!NS_IsMainThread());
-
-// TODO: Support avrcp application setting related functions
-}
-
-static void
-AvrcpListPlayerAppValuesCallback(btrc_player_attr_t aAttrId)
-{
-  MOZ_ASSERT(!NS_IsMainThread());
-
-// TODO: Support avrcp application setting related functions
-}
-
-static void
-AvrcpGetPlayerAppValueCallback(uint8_t aNumAttr,
-                               btrc_player_attr_t* aPlayerAttrs)
-{
-  MOZ_ASSERT(!NS_IsMainThread());
-
-// TODO: Support avrcp application setting related functions
-}
-
-static void
-AvrcpGetPlayerAppAttrsTextCallback(uint8_t aNumAttr,
-                                   btrc_player_attr_t* PlayerAttrs)
-{
-  MOZ_ASSERT(!NS_IsMainThread());
-
-// TODO: Support avrcp application setting related functions
-}
-
-static void
-AvrcpGetPlayerAppValuesTextCallback(uint8_t aAttrId, uint8_t aNumVal,
-                                    uint8_t* PlayerVals)
-{
-  MOZ_ASSERT(!NS_IsMainThread());
-
-// TODO: Support avrcp application setting related functions
-}
-
-static void
-AvrcpSetPlayerAppValueCallback(btrc_player_settings_t* aPlayerVals)
-{
-  MOZ_ASSERT(!NS_IsMainThread());
-
-// TODO: Support avrcp application setting related functions
-}
-#endif
-
-#if ANDROID_VERSION > 18
-/*
- * This callback function is to get CT features from Feature Bit Mask.
- * If Advanced Control Player bit is set, CT supports
- * volume sync (absolute volume feature). If Browsing bit is set, Avrcp 1.4
- * Browse feature will be supported
- */
-static void
-AvrcpRemoteFeaturesCallback(bt_bdaddr_t* aBdAddress,
-                            btrc_remote_features_t aFeatures)
-{
-// TODO: Support avrcp 1.4 absolute volume/browse
-}
-
-/*
- * This callback function is to get notification that volume changed on the
- * remote car kit (if it supports Avrcp 1.4), not notification from phone.
- */
-static void
-AvrcpRemoteVolumeChangedCallback(uint8_t aVolume, uint8_t aCType)
-{
-// TODO: Support avrcp 1.4 absolute volume/browse
-}
-
-/*
- * This callback function is to handle passthrough commands.
- */
-static void
-AvrcpPassThroughCallback(int aId, int aKeyState)
-{
-  // Fast-forward and rewind key events won't be generated from bluedroid
-  // stack after ANDROID_VERSION > 18, but via passthrough callback.
-  nsAutoString name;
-  NS_ENSURE_TRUE_VOID(aKeyState == AVRC_KEY_PRESS_STATE ||
-                      aKeyState == AVRC_KEY_RELEASE_STATE);
-  switch (aId) {
-    case AVRC_ID_FAST_FOR:
-      if (aKeyState == AVRC_KEY_PRESS_STATE) {
-        name.AssignLiteral("media-fast-forward-button-press");
-      } else {
-        name.AssignLiteral("media-fast-forward-button-release");
-      }
-      break;
-    case AVRC_ID_REWIND:
-      if (aKeyState == AVRC_KEY_PRESS_STATE) {
-        name.AssignLiteral("media-rewind-button-press");
-      } else {
-        name.AssignLiteral("media-rewind-button-release");
-      }
-      break;
-    default:
-      BT_WARNING("Unable to handle the unknown PassThrough command %d", aId);
-      break;
-  }
-  if (!name.IsEmpty()) {
-    NS_DispatchToMainThread(new UpdatePassthroughCmdTask(name));
-  }
-}
-#endif
-
-static btav_callbacks_t sBtA2dpCallbacks = {
-  sizeof(sBtA2dpCallbacks),
-  A2dpConnectionStateCallback,
-  A2dpAudioStateCallback
-};
-
-#if ANDROID_VERSION > 17
-static btrc_callbacks_t sBtAvrcpCallbacks = {
-  sizeof(sBtAvrcpCallbacks),
-#if ANDROID_VERSION > 18
-  AvrcpRemoteFeaturesCallback,
-#endif
-  AvrcpGetPlayStatusCallback,
-  AvrcpListPlayerAppAttributeCallback,
-  AvrcpListPlayerAppValuesCallback,
-  AvrcpGetPlayerAppValueCallback,
-  AvrcpGetPlayerAppAttrsTextCallback,
-  AvrcpGetPlayerAppValuesTextCallback,
-  AvrcpSetPlayerAppValueCallback,
-  AvrcpGetElementAttrCallback,
-  AvrcpRegisterNotificationCallback,
-#if ANDROID_VERSION > 18
-  AvrcpRemoteVolumeChangedCallback,
-  AvrcpPassThroughCallback
-#endif
-};
-#endif
-
 #if ANDROID_VERSION > 17
 class InitAvrcpResultHandler MOZ_FINAL : public BluetoothAvrcpResultHandler
 {
 public:
   InitAvrcpResultHandler(BluetoothProfileResultHandler* aRes)
   : mRes(aRes)
   { }
 
@@ -565,18 +168,18 @@ public:
 #if ANDROID_VERSION > 17
     /* Also init AVRCP if it's available, ... */
     BluetoothInterface* btInf = BluetoothInterface::GetInstance();
     NS_ENSURE_TRUE_VOID(btInf);
 
     sBtAvrcpInterface = btInf->GetBluetoothAvrcpInterface();
     NS_ENSURE_TRUE_VOID(sBtAvrcpInterface);
 
-    sBtAvrcpInterface->Init(&sBtAvrcpCallbacks,
-                            new InitAvrcpResultHandler(mRes));
+    BluetoothA2dpManager* a2dpManager = BluetoothA2dpManager::Get();
+    sBtAvrcpInterface->Init(a2dpManager, new InitAvrcpResultHandler(mRes));
 #else
     /* ...or signal success otherwise. */
     if (mRes) {
       mRes->Init();
     }
 #endif
   }
 
@@ -595,17 +198,18 @@ void
 BluetoothA2dpManager::InitA2dpInterface(BluetoothProfileResultHandler* aRes)
 {
   BluetoothInterface* btInf = BluetoothInterface::GetInstance();
   NS_ENSURE_TRUE_VOID(btInf);
 
   sBtA2dpInterface = btInf->GetBluetoothA2dpInterface();
   NS_ENSURE_TRUE_VOID(sBtA2dpInterface);
 
-  sBtA2dpInterface->Init(&sBtA2dpCallbacks, new InitA2dpResultHandler(aRes));
+  BluetoothA2dpManager* a2dpManager = BluetoothA2dpManager::Get();
+  sBtA2dpInterface->Init(a2dpManager, new InitA2dpResultHandler(aRes));
 }
 
 BluetoothA2dpManager::~BluetoothA2dpManager()
 {
   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!");
@@ -1300,10 +904,235 @@ BluetoothA2dpManager::GetTitle(nsAString
 }
 
 void
 BluetoothA2dpManager::GetArtist(nsAString& aArtist)
 {
   aArtist.Assign(mArtist);
 }
 
+/*
+ * A2DP Notifications
+ */
+
+void
+BluetoothA2dpManager::ConnectionStateNotification(BluetoothA2dpConnectionState aState,
+                                                  const nsAString& aBdAddr)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  nsString a2dpState;
+  AvStatusToSinkString(aState, a2dpState);
+
+  InfallibleTArray<BluetoothNamedValue> props;
+  BT_APPEND_NAMED_VALUE(props, "State", a2dpState);
+
+  HandleSinkPropertyChanged(BluetoothSignal(NS_LITERAL_STRING("AudioSink"),
+                                            nsString(aBdAddr), props));
+}
+
+void
+BluetoothA2dpManager::AudioStateNotification(BluetoothA2dpAudioState aState,
+                                             const nsAString& aBdAddr)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  nsString a2dpState;
+
+  if (aState == A2DP_AUDIO_STATE_STARTED) {
+    a2dpState = NS_LITERAL_STRING("playing");
+  } else if (aState == A2DP_AUDIO_STATE_STOPPED) {
+    // for avdtp state stop stream
+    a2dpState = NS_LITERAL_STRING("connected");
+  } else if (aState == A2DP_AUDIO_STATE_REMOTE_SUSPEND) {
+    // for avdtp state suspend stream from remote side
+    a2dpState = NS_LITERAL_STRING("connected");
+  }
+
+  InfallibleTArray<BluetoothNamedValue> props;
+  BT_APPEND_NAMED_VALUE(props, "State", a2dpState);
+
+  HandleSinkPropertyChanged(BluetoothSignal(NS_LITERAL_STRING("AudioSink"),
+                                            nsString(aBdAddr), props));
+}
+
+/*
+ * AVRCP Notifications
+ */
+
+void
+BluetoothA2dpManager::GetPlayStatusNotification()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  BluetoothService* bs = BluetoothService::Get();
+  if (!bs) {
+    return;
+  }
+
+  bs->DistributeSignal(
+    BluetoothSignal(NS_LITERAL_STRING(REQUEST_MEDIA_PLAYSTATUS_ID),
+                    NS_LITERAL_STRING(KEY_ADAPTER),
+                    InfallibleTArray<BluetoothNamedValue>()));
+}
+
+/* Player application settings is optional for AVRCP 1.3. B2G
+ * currently does not support player-application-setting related
+ * functionality.
+ */
+void
+BluetoothA2dpManager::ListPlayerAppAttrNotification()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  // TODO: Support AVRCP application-setting-related functions
+}
+
+void
+BluetoothA2dpManager::ListPlayerAppValuesNotification(
+  BluetoothAvrcpPlayerAttribute aAttrId)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  // TODO: Support AVRCP application-setting-related functions
+}
+
+void
+BluetoothA2dpManager::GetPlayerAppValueNotification(
+  uint8_t aNumAttrs, const BluetoothAvrcpPlayerAttribute* aAttrs)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  // TODO: Support AVRCP application-setting-related functions
+}
+
+void
+BluetoothA2dpManager::GetPlayerAppAttrsTextNotification(
+  uint8_t aNumAttrs, const BluetoothAvrcpPlayerAttribute* aAttrs)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  // TODO: Support AVRCP application-setting-related functions
+}
+
+void
+BluetoothA2dpManager::GetPlayerAppValuesTextNotification(
+  uint8_t aAttrId, uint8_t aNumVals, const uint8_t* aValues)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  // TODO: Support AVRCP application-setting-related functions
+}
+
+void
+BluetoothA2dpManager::SetPlayerAppValueNotification(
+  const BluetoothAvrcpPlayerSettings& aSettings)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  // TODO: Support AVRCP application-setting-related functions
+}
+
+/* This method returns element attributes, which are requested from
+ * CT. Unlike BlueZ it calls only UpdateMetaData. Bluedroid does not cache
+ * meta-data information, but instead uses |GetElementAttrNotifications|
+ * and |GetElementAttrRsp| request them.
+ */
+void
+BluetoothA2dpManager::GetElementAttrNotification(
+  uint8_t aNumAttrs, const BluetoothAvrcpMediaAttribute* aAttrs)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  nsAutoArrayPtr<BluetoothAvrcpElementAttribute> attrs(
+    new BluetoothAvrcpElementAttribute[aNumAttrs]);
+
+  for (uint8_t i = 0; i < aNumAttrs; ++i) {
+    attrs[i].mId = aAttrs[i];
+    ConvertAttributeString(
+      static_cast<BluetoothAvrcpMediaAttribute>(attrs[i].mId),
+      attrs[i].mValue);
+  }
+
+#if ANDROID_VERSION >= 18
+  MOZ_ASSERT(sBtAvrcpInterface);
+  sBtAvrcpInterface->GetElementAttrRsp(aNumAttrs, attrs, nullptr);
+#endif // ANDROID_VERSION >= 18
+}
+
+void
+BluetoothA2dpManager::RegisterNotificationNotification(
+  BluetoothAvrcpEvent aEvent, uint32_t aParam)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  BluetoothA2dpManager* a2dp = BluetoothA2dpManager::Get();
+  if (!a2dp) {
+    return;
+  }
+
+#if ANDROID_VERSION >= 18
+  a2dp->UpdateRegisterNotification(aEvent, aParam);
+#endif // ANDROID_VERSION >= 18
+}
+
+/* This method is used to get CT features from the Feature Bit Mask. If
+ * Advanced Control Player bit is set, the CT supports volume sync (absolute
+ * volume feature). If Browsing bit is set, AVRCP 1.4 Browse feature will be
+ * supported.
+ */
+void
+BluetoothA2dpManager::RemoteFeatureNotification(
+    const nsAString& aBdAddr, unsigned long aFeatures)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  // TODO: Support AVRCP 1.4 absolute volume/browse
+}
+
+/* This method is used to get notifications about volume changes on the
+ * remote car kit (if it supports AVRCP 1.4), not notification from phone.
+ */
+void
+BluetoothA2dpManager::VolumeChangeNotification(uint8_t aVolume,
+                                               uint8_t aCType)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  // TODO: Support AVRCP 1.4 absolute volume/browse
+}
+
+void
+BluetoothA2dpManager::PassthroughCmdNotification(int aId, int aKeyState)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  // Fast-forward and rewind key events won't be generated from bluedroid
+  // stack after ANDROID_VERSION > 18, but via passthrough callback.
+  nsAutoString name;
+  NS_ENSURE_TRUE_VOID(aKeyState == AVRC_KEY_PRESS_STATE ||
+                      aKeyState == AVRC_KEY_RELEASE_STATE);
+  switch (aId) {
+    case AVRC_ID_FAST_FOR:
+      if (aKeyState == AVRC_KEY_PRESS_STATE) {
+        name.AssignLiteral("media-fast-forward-button-press");
+      } else {
+        name.AssignLiteral("media-fast-forward-button-release");
+      }
+      break;
+    case AVRC_ID_REWIND:
+      if (aKeyState == AVRC_KEY_PRESS_STATE) {
+        name.AssignLiteral("media-rewind-button-press");
+      } else {
+        name.AssignLiteral("media-rewind-button-release");
+      }
+      break;
+    default:
+      BT_WARNING("Unable to handle the unknown PassThrough command %d", aId);
+      return;
+  }
+
+  NS_NAMED_LITERAL_STRING(type, "media-button");
+  BroadcastSystemMessage(type, BluetoothValue(name));
+}
+
 NS_IMPL_ISUPPORTS(BluetoothA2dpManager, nsIObserver)
 
--- a/dom/bluetooth/bluedroid/BluetoothA2dpManager.h
+++ b/dom/bluetooth/bluedroid/BluetoothA2dpManager.h
@@ -3,21 +3,24 @@
 /* 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_bluetootha2dpmanager_h__
 #define mozilla_dom_bluetooth_bluetootha2dpmanager_h__
 
 #include "BluetoothCommon.h"
+#include "BluetoothInterface.h"
 #include "BluetoothProfileController.h"
 #include "BluetoothProfileManagerBase.h"
 
 BEGIN_BLUETOOTH_NAMESPACE
 class BluetoothA2dpManager : public BluetoothProfileManagerBase
+                           , public BluetoothA2dpNotificationHandler
+                           , public BluetoothAvrcpNotificationHandler
 {
 public:
   BT_DECL_PROFILE_MGR_BASE
   virtual void GetName(nsACString& aName)
   {
     aName.AssignLiteral("A2DP");
   }
 
@@ -58,24 +61,63 @@ public:
   ControlPlayStatus GetPlayStatus();
   uint32_t GetPosition();
   uint64_t GetMediaNumber();
   uint64_t GetTotalMediaNumber();
   void GetTitle(nsAString& aTitle);
   void GetArtist(nsAString& aArtist);
 
 private:
-  class SinkPropertyChangedHandler;
   BluetoothA2dpManager();
   void ResetA2dp();
   void ResetAvrcp();
 
   void HandleShutdown();
   void NotifyConnectionStatusChanged();
 
+  void ConnectionStateNotification(BluetoothA2dpConnectionState aState,
+                                   const nsAString& aBdAddr) MOZ_OVERRIDE;
+  void AudioStateNotification(BluetoothA2dpAudioState aState,
+                              const nsAString& aBdAddr) MOZ_OVERRIDE;
+
+  void GetPlayStatusNotification() MOZ_OVERRIDE;
+
+  void ListPlayerAppAttrNotification() MOZ_OVERRIDE;
+
+  void ListPlayerAppValuesNotification(
+    BluetoothAvrcpPlayerAttribute aAttrId) MOZ_OVERRIDE;
+
+  void GetPlayerAppValueNotification(
+    uint8_t aNumAttrs,
+    const BluetoothAvrcpPlayerAttribute* aAttrs) MOZ_OVERRIDE;
+
+  void GetPlayerAppAttrsTextNotification(
+    uint8_t aNumAttrs,
+    const BluetoothAvrcpPlayerAttribute* aAttrs) MOZ_OVERRIDE;
+
+  void GetPlayerAppValuesTextNotification(
+    uint8_t aAttrId, uint8_t aNumVals, const uint8_t* aValues) MOZ_OVERRIDE;
+
+  void SetPlayerAppValueNotification(
+    const BluetoothAvrcpPlayerSettings& aSettings) MOZ_OVERRIDE;
+
+  void GetElementAttrNotification(
+    uint8_t aNumAttrs,
+    const BluetoothAvrcpMediaAttribute* aAttrs) MOZ_OVERRIDE;
+
+  void RegisterNotificationNotification(
+    BluetoothAvrcpEvent aEvent, uint32_t aParam) MOZ_OVERRIDE;
+
+  void RemoteFeatureNotification(
+    const nsAString& aBdAddr, unsigned long aFeatures) MOZ_OVERRIDE;
+
+  void VolumeChangeNotification(uint8_t aVolume, uint8_t aCType) MOZ_OVERRIDE;
+
+  void PassthroughCmdNotification(int aId, int aKeyState) MOZ_OVERRIDE;
+
   nsString mDeviceAddress;
   nsRefPtr<BluetoothProfileController> mController;
 
   // A2DP data member
   bool mA2dpConnected;
   SinkState mSinkState;
 
   // AVRCP data member
--- a/dom/bluetooth/bluedroid/BluetoothInterface.cpp
+++ b/dom/bluetooth/bluedroid/BluetoothInterface.cpp
@@ -431,28 +431,16 @@ Convert(bt_device_type_t aIn, BluetoothD
   };
   if (aIn >= MOZ_ARRAY_LENGTH(sDeviceType)) {
     return NS_ERROR_ILLEGAL_VALUE;
   }
   aOut = sDeviceType[aIn];
   return NS_OK;
 }
 
-#if ANDROID_VERSION >= 18
-static nsresult
-Convert(const bt_remote_version_t& aIn, BluetoothRemoteInfo& aOut)
-{
-  aOut.mVerMajor = aIn.version;
-  aOut.mVerMinor = aIn.sub_ver;
-  aOut.mManufacturer = aIn.manufacturer;
-
-  return NS_OK;
-}
-#endif
-
 static nsresult
 Convert(const bt_service_record_t& aIn, BluetoothServiceRecord& aOut)
 {
   nsresult rv = Convert(aIn.uuid, aOut.mUuid);
   if (NS_FAILED(rv)) {
     return rv;
   }
 
@@ -710,18 +698,63 @@ Convert(bthf_volume_type_t aIn, Bluetoot
   };
   if (aIn >= MOZ_ARRAY_LENGTH(sVolumeType)) {
     return NS_ERROR_ILLEGAL_VALUE;
   }
   aOut = sVolumeType[aIn];
   return NS_OK;
 }
 
+static nsresult
+Convert(btav_connection_state_t aIn, BluetoothA2dpConnectionState& aOut)
+{
+  static const BluetoothA2dpConnectionState sConnectionState[] = {
+    CONVERT(BTAV_CONNECTION_STATE_DISCONNECTED,
+      A2DP_CONNECTION_STATE_DISCONNECTED),
+    CONVERT(BTAV_CONNECTION_STATE_CONNECTING,
+      A2DP_CONNECTION_STATE_CONNECTING),
+    CONVERT(BTAV_CONNECTION_STATE_CONNECTED,
+      A2DP_CONNECTION_STATE_CONNECTED),
+    CONVERT(BTAV_CONNECTION_STATE_DISCONNECTING,
+      A2DP_CONNECTION_STATE_DISCONNECTING),
+  };
+  if (aIn >= MOZ_ARRAY_LENGTH(sConnectionState)) {
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
+  aOut = sConnectionState[aIn];
+  return NS_OK;
+}
+
+static nsresult
+Convert(btav_audio_state_t aIn, BluetoothA2dpAudioState& aOut)
+{
+  static const BluetoothA2dpAudioState sAudioState[] = {
+    CONVERT(BTAV_AUDIO_STATE_REMOTE_SUSPEND, A2DP_AUDIO_STATE_REMOTE_SUSPEND),
+    CONVERT(BTAV_AUDIO_STATE_STOPPED, A2DP_AUDIO_STATE_STOPPED),
+    CONVERT(BTAV_AUDIO_STATE_STARTED, A2DP_AUDIO_STATE_STARTED),
+  };
+  if (aIn >= MOZ_ARRAY_LENGTH(sAudioState)) {
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
+  aOut = sAudioState[aIn];
+  return NS_OK;
+}
+
 #if ANDROID_VERSION >= 18
 static nsresult
+Convert(const bt_remote_version_t& aIn, BluetoothRemoteInfo& aOut)
+{
+  aOut.mVerMajor = aIn.version;
+  aOut.mVerMinor = aIn.sub_ver;
+  aOut.mManufacturer = aIn.manufacturer;
+
+  return NS_OK;
+}
+
+static nsresult
 Convert(ControlPlayStatus aIn, btrc_play_status_t& aOut)
 {
   static const btrc_play_status_t sPlayStatus[] = {
     CONVERT(PLAYSTATUS_STOPPED, BTRC_PLAYSTATE_STOPPED),
     CONVERT(PLAYSTATUS_PLAYING, BTRC_PLAYSTATE_PLAYING),
     CONVERT(PLAYSTATUS_PAUSED, BTRC_PLAYSTATE_PAUSED),
     CONVERT(PLAYSTATUS_FWD_SEEK, BTRC_PLAYSTATE_FWD_SEEK),
     CONVERT(PLAYSTATUS_REV_SEEK, BTRC_PLAYSTATE_REV_SEEK)
@@ -745,16 +778,33 @@ Convert(enum BluetoothAvrcpPlayerAttribu
   if (aIn >= MOZ_ARRAY_LENGTH(sPlayerAttr)) {
     return NS_ERROR_ILLEGAL_VALUE;
   }
   aOut = sPlayerAttr[aIn];
   return NS_OK;
 }
 
 static nsresult
+Convert(btrc_player_attr_t aIn, enum BluetoothAvrcpPlayerAttribute& aOut)
+{
+  static const BluetoothAvrcpPlayerAttribute sPlayerAttr[] = {
+    CONVERT(0, static_cast<BluetoothAvrcpPlayerAttribute>(0)), // invalid, [0] required by gcc
+    CONVERT(BTRC_PLAYER_ATTR_EQUALIZER, AVRCP_PLAYER_ATTRIBUTE_EQUALIZER),
+    CONVERT(BTRC_PLAYER_ATTR_REPEAT, AVRCP_PLAYER_ATTRIBUTE_REPEAT),
+    CONVERT(BTRC_PLAYER_ATTR_SHUFFLE, AVRCP_PLAYER_ATTRIBUTE_SHUFFLE),
+    CONVERT(BTRC_PLAYER_ATTR_SCAN, AVRCP_PLAYER_ATTRIBUTE_SCAN)
+  };
+  if (!aIn || aIn >= MOZ_ARRAY_LENGTH(sPlayerAttr)) {
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
+  aOut = sPlayerAttr[aIn];
+  return NS_OK;
+}
+
+static nsresult
 Convert(enum BluetoothAvrcpStatus aIn, btrc_status_t& aOut)
 {
   static const btrc_status_t sStatus[] = {
     CONVERT(AVRCP_STATUS_BAD_COMMAND, BTRC_STS_BAD_CMD),
     CONVERT(AVRCP_STATUS_BAD_PARAMETER, BTRC_STS_BAD_PARAM),
     CONVERT(AVRCP_STATUS_NOT_FOUND, BTRC_STS_NOT_FOUND),
     CONVERT(AVRCP_STATUS_INTERNAL_ERROR, BTRC_STS_INTERNAL_ERR),
     CONVERT(AVRCP_STATUS_SUCCESS, BTRC_STS_NO_ERROR)
@@ -780,16 +830,57 @@ Convert(enum BluetoothAvrcpEvent aIn, bt
   if (aIn >= MOZ_ARRAY_LENGTH(sEventId)) {
     return NS_ERROR_ILLEGAL_VALUE;
   }
   aOut = sEventId[aIn];
   return NS_OK;
 }
 
 static nsresult
+Convert(btrc_event_id_t aIn, enum BluetoothAvrcpEvent& aOut)
+{
+  static const BluetoothAvrcpEvent sEventId[] = {
+    CONVERT(0, static_cast<BluetoothAvrcpEvent>(0)), // invalid, [0] required by gcc
+    CONVERT(BTRC_EVT_PLAY_STATUS_CHANGED, AVRCP_EVENT_PLAY_STATUS_CHANGED),
+    CONVERT(BTRC_EVT_TRACK_CHANGE, AVRCP_EVENT_TRACK_CHANGE),
+    CONVERT(BTRC_EVT_TRACK_REACHED_END, AVRCP_EVENT_TRACK_REACHED_END),
+    CONVERT(BTRC_EVT_TRACK_REACHED_START, AVRCP_EVENT_TRACK_REACHED_START),
+    CONVERT(BTRC_EVT_PLAY_POS_CHANGED, AVRCP_EVENT_PLAY_POS_CHANGED),
+    CONVERT(6, static_cast<BluetoothAvrcpEvent>(0)), // invalid, [6] required by gcc
+    CONVERT(7, static_cast<BluetoothAvrcpEvent>(0)), // invalid, [7] required by gcc
+    CONVERT(BTRC_EVT_APP_SETTINGS_CHANGED, AVRCP_EVENT_APP_SETTINGS_CHANGED)
+  };
+  if (!aIn || aIn >= MOZ_ARRAY_LENGTH(sEventId)) {
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
+  aOut = sEventId[aIn];
+  return NS_OK;
+}
+
+static nsresult
+Convert(btrc_media_attr_t aIn, enum BluetoothAvrcpMediaAttribute& aOut)
+{
+  static const BluetoothAvrcpMediaAttribute sEventId[] = {
+    CONVERT(0, static_cast<BluetoothAvrcpMediaAttribute>(0)), // invalid, [0] required by gcc
+    CONVERT(BTRC_MEDIA_ATTR_TITLE, AVRCP_MEDIA_ATTRIBUTE_TITLE),
+    CONVERT(BTRC_MEDIA_ATTR_ARTIST, AVRCP_MEDIA_ATTRIBUTE_ARTIST),
+    CONVERT(BTRC_MEDIA_ATTR_ALBUM, AVRCP_MEDIA_ATTRIBUTE_ALBUM),
+    CONVERT(BTRC_MEDIA_ATTR_TRACK_NUM, AVRCP_MEDIA_ATTRIBUTE_TRACK_NUM),
+    CONVERT(BTRC_MEDIA_ATTR_NUM_TRACKS, AVRCP_MEDIA_ATTRIBUTE_NUM_TRACKS),
+    CONVERT(BTRC_MEDIA_ATTR_GENRE, AVRCP_MEDIA_ATTRIBUTE_GENRE),
+    CONVERT(BTRC_MEDIA_ATTR_PLAYING_TIME, AVRCP_MEDIA_ATTRIBUTE_PLAYING_TIME)
+  };
+  if (!aIn || aIn >= MOZ_ARRAY_LENGTH(sEventId)) {
+    return NS_ERROR_ILLEGAL_VALUE;
+  }
+  aOut = sEventId[aIn];
+  return NS_OK;
+}
+
+static nsresult
 Convert(enum BluetoothAvrcpNotification aIn, btrc_notification_type_t& aOut)
 {
   static const btrc_notification_type_t sNotificationType[] = {
     CONVERT(AVRCP_NTF_INTERIM, BTRC_NOTIFICATION_TYPE_INTERIM),
     CONVERT(AVRCP_NTF_CHANGED, BTRC_NOTIFICATION_TYPE_CHANGED)
   };
   if (aIn >= MOZ_ARRAY_LENGTH(sNotificationType)) {
     return NS_ERROR_ILLEGAL_VALUE;
@@ -806,17 +897,38 @@ Convert(const BluetoothAvrcpElementAttri
 
   memcpy(aOut.text, value.get(), len);
   aOut.text[len] = '\0';
   aOut.attr_id = aIn.mId;
 
   return NS_OK;
 }
 
-#endif
+static nsresult
+Convert(const btrc_player_settings_t& aIn, BluetoothAvrcpPlayerSettings& aOut)
+{
+  aOut.mNumAttr = aIn.num_attr;
+  memcpy(aOut.mIds, aIn.attr_ids, aIn.num_attr);
+  memcpy(aOut.mValues, aIn.attr_values, aIn.num_attr);
+
+  return NS_OK;
+}
+#endif // ANDROID_VERSION >= 18
+
+#if ANDROID_VERSION >= 19
+static nsresult
+Convert(btrc_remote_features_t aIn, unsigned long& aOut)
+{
+  /* The input type's name is misleading. The converted value is
+   * actually a bitmask.
+   */
+  aOut = static_cast<unsigned long>(aIn);
+  return NS_OK;
+}
+#endif // ANDROID_VERSION >= 19
 
 /* |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
@@ -2711,31 +2823,103 @@ DispatchBluetoothA2dpResult(
   }
   nsresult rv = NS_DispatchToMainThread(runnable);
   if (NS_FAILED(rv)) {
     BT_WARNING("NS_DispatchToMainThread failed: %X", rv);
   }
   return rv;
 }
 
+// Notification handling
+//
+
+BluetoothA2dpNotificationHandler::~BluetoothA2dpNotificationHandler()
+{ }
+
+static BluetoothA2dpNotificationHandler* sA2dpNotificationHandler;
+
+struct BluetoothA2dpCallback
+{
+  class A2dpNotificationHandlerWrapper
+  {
+  public:
+    typedef BluetoothA2dpNotificationHandler ObjectType;
+
+    static ObjectType* GetInstance()
+    {
+      MOZ_ASSERT(NS_IsMainThread());
+
+      return sA2dpNotificationHandler;
+    }
+  };
+
+  // Notifications
+
+  typedef BluetoothNotificationRunnable2<A2dpNotificationHandlerWrapper,
+                                         void,
+                                         BluetoothA2dpConnectionState,
+                                         nsString,
+                                         BluetoothA2dpConnectionState,
+                                         const nsAString&>
+    ConnectionStateNotification;
+
+  typedef BluetoothNotificationRunnable2<A2dpNotificationHandlerWrapper,
+                                         void,
+                                         BluetoothA2dpAudioState,
+                                         nsString,
+                                         BluetoothA2dpAudioState,
+                                         const nsAString&>
+    AudioStateNotification;
+
+  // Bluedroid A2DP callbacks
+
+  static void
+  ConnectionState(btav_connection_state_t aState, bt_bdaddr_t* aBdAddr)
+  {
+    ConnectionStateNotification::Dispatch(
+      &BluetoothA2dpNotificationHandler::ConnectionStateNotification,
+      aState, aBdAddr);
+  }
+
+  static void
+  AudioState(btav_audio_state_t aState, bt_bdaddr_t* aBdAddr)
+  {
+    AudioStateNotification::Dispatch(
+      &BluetoothA2dpNotificationHandler::AudioStateNotification,
+      aState, aBdAddr);
+  }
+};
+
+// Interface
+//
+
 BluetoothA2dpInterface::BluetoothA2dpInterface(
   const btav_interface_t* aInterface)
 : mInterface(aInterface)
 {
   MOZ_ASSERT(mInterface);
 }
 
 BluetoothA2dpInterface::~BluetoothA2dpInterface()
 { }
 
 void
-BluetoothA2dpInterface::Init(btav_callbacks_t* aCallbacks,
-                             BluetoothA2dpResultHandler* aRes)
+BluetoothA2dpInterface::Init(
+  BluetoothA2dpNotificationHandler* aNotificationHandler,
+  BluetoothA2dpResultHandler* aRes)
 {
-  bt_status_t status = mInterface->init(aCallbacks);
+  static btav_callbacks_t sCallbacks = {
+    sizeof(sCallbacks),
+    BluetoothA2dpCallback::ConnectionState,
+    BluetoothA2dpCallback::AudioState
+  };
+
+  sA2dpNotificationHandler = aNotificationHandler;
+
+  bt_status_t status = mInterface->init(&sCallbacks);
 
   if (aRes) {
     DispatchBluetoothA2dpResult(aRes, &BluetoothA2dpResultHandler::Init,
                                 ConvertDefault(status, STATUS_FAIL));
   }
 }
 
 void
@@ -2829,32 +3013,249 @@ DispatchBluetoothAvrcpResult(
       &BluetoothAvrcpResultHandler::OnError, aStatus);
   }
   nsresult rv = NS_DispatchToMainThread(runnable);
   if (NS_FAILED(rv)) {
     BT_WARNING("NS_DispatchToMainThread failed: %X", rv);
   }
   return rv;
 }
+#endif
+
+// Notification handling
+//
+
+BluetoothAvrcpNotificationHandler::~BluetoothAvrcpNotificationHandler()
+{ }
+
+#if ANDROID_VERSION >= 18
+static BluetoothAvrcpNotificationHandler* sAvrcpNotificationHandler;
+
+struct BluetoothAvrcpCallback
+{
+  class AvrcpNotificationHandlerWrapper
+  {
+  public:
+    typedef BluetoothAvrcpNotificationHandler ObjectType;
+
+    static ObjectType* GetInstance()
+    {
+      MOZ_ASSERT(NS_IsMainThread());
+
+      return sAvrcpNotificationHandler;
+    }
+  };
+
+  // Notifications
+
+  typedef BluetoothNotificationRunnable0<AvrcpNotificationHandlerWrapper,
+                                         void>
+    GetPlayStatusNotification;
+
+  typedef BluetoothNotificationRunnable0<AvrcpNotificationHandlerWrapper,
+                                         void>
+    ListPlayerAppAttrNotification;
+
+  typedef BluetoothNotificationRunnable1<AvrcpNotificationHandlerWrapper,
+                                         void,
+                                         BluetoothAvrcpPlayerAttribute>
+    ListPlayerAppValuesNotification;
+
+  typedef BluetoothNotificationRunnable2<AvrcpNotificationHandlerWrapper, void,
+    uint8_t, nsAutoArrayPtr<BluetoothAvrcpPlayerAttribute>,
+    uint8_t, const BluetoothAvrcpPlayerAttribute*>
+    GetPlayerAppValueNotification;
+
+  typedef BluetoothNotificationRunnable2<AvrcpNotificationHandlerWrapper, void,
+    uint8_t, nsAutoArrayPtr<BluetoothAvrcpPlayerAttribute>,
+    uint8_t, const BluetoothAvrcpPlayerAttribute*>
+    GetPlayerAppAttrsTextNotification;
+
+  typedef BluetoothNotificationRunnable3<AvrcpNotificationHandlerWrapper,
+                                         void,
+                                         uint8_t, uint8_t,
+                                         nsAutoArrayPtr<uint8_t>,
+                                         uint8_t, uint8_t, const uint8_t*>
+    GetPlayerAppValuesTextNotification;
+
+  typedef BluetoothNotificationRunnable1<AvrcpNotificationHandlerWrapper,
+                                         void,
+                                         BluetoothAvrcpPlayerSettings,
+                                         const BluetoothAvrcpPlayerSettings&>
+    SetPlayerAppValueNotification;
+
+  typedef BluetoothNotificationRunnable2<AvrcpNotificationHandlerWrapper, void,
+    uint8_t, nsAutoArrayPtr<BluetoothAvrcpMediaAttribute>,
+    uint8_t, const BluetoothAvrcpMediaAttribute*>
+    GetElementAttrNotification;
+
+  typedef BluetoothNotificationRunnable2<AvrcpNotificationHandlerWrapper,
+                                         void,
+                                         BluetoothAvrcpEvent, uint32_t>
+    RegisterNotificationNotification;
+
+#if ANDROID_VERSION >= 19
+  typedef BluetoothNotificationRunnable2<AvrcpNotificationHandlerWrapper,
+                                         void,
+                                         nsString, unsigned long,
+                                         const nsAString&>
+    RemoteFeatureNotification;
+
+  typedef BluetoothNotificationRunnable2<AvrcpNotificationHandlerWrapper,
+                                         void,
+                                         uint8_t, uint8_t>
+    VolumeChangeNotification;
+
+  typedef BluetoothNotificationRunnable2<AvrcpNotificationHandlerWrapper,
+                                         void,
+                                         int, int>
+    PassthroughCmdNotification;
+#endif // ANDROID_VERSION >= 19
+
+  // Bluedroid AVRCP callbacks
+
+  static void
+  GetPlayStatus()
+  {
+    GetPlayStatusNotification::Dispatch(
+      &BluetoothAvrcpNotificationHandler::GetPlayStatusNotification);
+  }
+
+  static void
+  ListPlayerAppAttr()
+  {
+    ListPlayerAppAttrNotification::Dispatch(
+      &BluetoothAvrcpNotificationHandler::ListPlayerAppAttrNotification);
+  }
+
+  static void
+  ListPlayerAppValues(btrc_player_attr_t aAttrId)
+  {
+    ListPlayerAppValuesNotification::Dispatch(
+      &BluetoothAvrcpNotificationHandler::ListPlayerAppValuesNotification,
+      aAttrId);
+  }
+
+  static void
+  GetPlayerAppValue(uint8_t aNumAttrs, btrc_player_attr_t* aAttrs)
+  {
+    GetPlayerAppValueNotification::Dispatch(
+      &BluetoothAvrcpNotificationHandler::GetPlayerAppValueNotification,
+      aNumAttrs, ConvertArray<btrc_player_attr_t>(aAttrs, aNumAttrs));
+  }
+
+  static void
+  GetPlayerAppAttrsText(uint8_t aNumAttrs, btrc_player_attr_t* aAttrs)
+  {
+    GetPlayerAppAttrsTextNotification::Dispatch(
+      &BluetoothAvrcpNotificationHandler::GetPlayerAppAttrsTextNotification,
+      aNumAttrs, ConvertArray<btrc_player_attr_t>(aAttrs, aNumAttrs));
+  }
+
+  static void
+  GetPlayerAppValuesText(uint8_t aAttrId, uint8_t aNumVals, uint8_t* aVals)
+  {
+    GetPlayerAppValuesTextNotification::Dispatch(
+      &BluetoothAvrcpNotificationHandler::GetPlayerAppValuesTextNotification,
+      aAttrId, aNumVals, ConvertArray<uint8_t>(aVals, aNumVals));
+  }
+
+  static void
+  SetPlayerAppValue(btrc_player_settings_t* aVals)
+  {
+    SetPlayerAppValueNotification::Dispatch(
+      &BluetoothAvrcpNotificationHandler::SetPlayerAppValueNotification,
+      *aVals);
+  }
+
+  static void
+  GetElementAttr(uint8_t aNumAttrs, btrc_media_attr_t* aAttrs)
+  {
+    GetElementAttrNotification::Dispatch(
+      &BluetoothAvrcpNotificationHandler::GetElementAttrNotification,
+      aNumAttrs, ConvertArray<btrc_media_attr_t>(aAttrs, aNumAttrs));
+  }
+
+  static void
+  RegisterNotification(btrc_event_id_t aEvent, uint32_t aParam)
+  {
+    RegisterNotificationNotification::Dispatch(
+      &BluetoothAvrcpNotificationHandler::RegisterNotificationNotification,
+      aEvent, aParam);
+  }
+
+#if ANDROID_VERSION >= 19
+  static void
+  RemoteFeature(bt_bdaddr_t* aBdAddr, btrc_remote_features_t aFeatures)
+  {
+    RemoteFeatureNotification::Dispatch(
+      &BluetoothAvrcpNotificationHandler::RemoteFeatureNotification,
+      aBdAddr, aFeatures);
+  }
+
+  static void
+  VolumeChange(uint8_t aVolume, uint8_t aCType)
+  {
+    VolumeChangeNotification::Dispatch(
+      &BluetoothAvrcpNotificationHandler::VolumeChangeNotification,
+      aVolume, aCType);
+  }
+
+  static void
+  PassthroughCmd(int aId, int aKeyState)
+  {
+    PassthroughCmdNotification::Dispatch(
+      &BluetoothAvrcpNotificationHandler::PassthroughCmdNotification,
+      aId, aKeyState);
+  }
+#endif // ANDROID_VERSION >= 19
+};
+
+// Interface
+//
 
 BluetoothAvrcpInterface::BluetoothAvrcpInterface(
   const btrc_interface_t* aInterface)
 : mInterface(aInterface)
 {
   MOZ_ASSERT(mInterface);
 }
 
 BluetoothAvrcpInterface::~BluetoothAvrcpInterface()
 { }
 
 void
-BluetoothAvrcpInterface::Init(btrc_callbacks_t* aCallbacks,
-                              BluetoothAvrcpResultHandler* aRes)
+BluetoothAvrcpInterface::Init(
+  BluetoothAvrcpNotificationHandler* aNotificationHandler,
+  BluetoothAvrcpResultHandler* aRes)
 {
-  bt_status_t status = mInterface->init(aCallbacks);
+  static btrc_callbacks_t sCallbacks = {
+    sizeof(sCallbacks),
+#if ANDROID_VERSION >= 19
+    BluetoothAvrcpCallback::RemoteFeature,
+#endif
+    BluetoothAvrcpCallback::GetPlayStatus,
+    BluetoothAvrcpCallback::ListPlayerAppAttr,
+    BluetoothAvrcpCallback::ListPlayerAppValues,
+    BluetoothAvrcpCallback::GetPlayerAppValue,
+    BluetoothAvrcpCallback::GetPlayerAppAttrsText,
+    BluetoothAvrcpCallback::GetPlayerAppValuesText,
+    BluetoothAvrcpCallback::SetPlayerAppValue,
+    BluetoothAvrcpCallback::GetElementAttr,
+    BluetoothAvrcpCallback::RegisterNotification
+#if ANDROID_VERSION >= 19
+    ,
+    BluetoothAvrcpCallback::VolumeChange,
+    BluetoothAvrcpCallback::PassthroughCmd
+#endif
+  };
+
+  sAvrcpNotificationHandler = aNotificationHandler;
+
+  bt_status_t status = mInterface->init(&sCallbacks);
 
   if (aRes) {
     DispatchBluetoothAvrcpResult(aRes, &BluetoothAvrcpResultHandler::Init,
                                  ConvertDefault(status, STATUS_FAIL));
   }
 }
 
 void
--- a/dom/bluetooth/bluedroid/BluetoothInterface.h
+++ b/dom/bluetooth/bluedroid/BluetoothInterface.h
@@ -260,16 +260,36 @@ protected:
 private:
   const bthf_interface_t* mInterface;
 };
 
 //
 // Bluetooth Advanced Audio Interface
 //
 
+class BluetoothA2dpNotificationHandler
+{
+public:
+  virtual ~BluetoothA2dpNotificationHandler();
+
+  virtual void
+  ConnectionStateNotification(BluetoothA2dpConnectionState aState,
+                              const nsAString& aBdAddr)
+  { }
+
+  virtual void
+  AudioStateNotification(BluetoothA2dpAudioState aState,
+                         const nsAString& aBdAddr)
+  { }
+
+protected:
+  BluetoothA2dpNotificationHandler()
+  { }
+};
+
 class BluetoothA2dpResultHandler
 {
 public:
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(BluetoothA2dpResultHandler)
 
   virtual ~BluetoothA2dpResultHandler() { }
 
   virtual void OnError(BluetoothStatus aStatus)
@@ -283,17 +303,17 @@ public:
   virtual void Disconnect() { }
 };
 
 class BluetoothA2dpInterface
 {
 public:
   friend class BluetoothInterface;
 
-  void Init(btav_callbacks_t *aCallbacks,
+  void Init(BluetoothA2dpNotificationHandler* aNotificationHandler,
             BluetoothA2dpResultHandler* aRes);
   void Cleanup(BluetoothA2dpResultHandler* aRes);
 
   void Connect(const nsAString& aBdAddr,
                BluetoothA2dpResultHandler* aRes);
   void Disconnect(const nsAString& aBdAddr,
                   BluetoothA2dpResultHandler* aRes);
 
@@ -304,16 +324,79 @@ protected:
 private:
   const btav_interface_t* mInterface;
 };
 
 //
 // Bluetooth AVRCP Interface
 //
 
+class BluetoothAvrcpNotificationHandler
+{
+public:
+  virtual ~BluetoothAvrcpNotificationHandler();
+
+  virtual void
+  GetPlayStatusNotification()
+  { }
+
+  virtual void
+  ListPlayerAppAttrNotification()
+  { }
+
+  virtual void
+  ListPlayerAppValuesNotification(BluetoothAvrcpPlayerAttribute aAttrId)
+  { }
+
+  virtual void
+  GetPlayerAppValueNotification(uint8_t aNumAttrs,
+                                const BluetoothAvrcpPlayerAttribute* aAttrs)
+  { }
+
+  virtual void
+  GetPlayerAppAttrsTextNotification(uint8_t aNumAttrs,
+                                    const BluetoothAvrcpPlayerAttribute* aAttrs)
+  { }
+
+  virtual void
+  GetPlayerAppValuesTextNotification(uint8_t aAttrId, uint8_t aNumVals,
+                                     const uint8_t* aValues)
+  { }
+
+  virtual void
+  SetPlayerAppValueNotification(const BluetoothAvrcpPlayerSettings& aSettings)
+  { }
+
+  virtual void
+  GetElementAttrNotification(uint8_t aNumAttrs,
+                             const BluetoothAvrcpMediaAttribute* aAttrs)
+  { }
+
+  virtual void
+  RegisterNotificationNotification(BluetoothAvrcpEvent aEvent,
+                                   uint32_t aParam)
+  { }
+
+  virtual void
+  RemoteFeatureNotification(const nsAString& aBdAddr, unsigned long aFeatures)
+  { }
+
+  virtual void
+  VolumeChangeNotification(uint8_t aVolume, uint8_t aCType)
+  { }
+
+  virtual void
+  PassthroughCmdNotification(int aId, int aKeyState)
+  { }
+
+protected:
+  BluetoothAvrcpNotificationHandler()
+  { }
+};
+
 class BluetoothAvrcpResultHandler
 {
 public:
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(BluetoothAvrcpResultHandler)
 
   virtual ~BluetoothAvrcpResultHandler() { }
 
   virtual void OnError(BluetoothStatus aStatus)
@@ -343,17 +426,17 @@ public:
 };
 
 class BluetoothAvrcpInterface
 {
 #if ANDROID_VERSION >= 18
 public:
   friend class BluetoothInterface;
 
-  void Init(btrc_callbacks_t* aCallbacks,
+  void Init(BluetoothAvrcpNotificationHandler* aNotificationHandler,
             BluetoothAvrcpResultHandler* aRes);
   void Cleanup(BluetoothAvrcpResultHandler* aRes);
 
   void GetPlayStatusRsp(ControlPlayStatus aPlayStatus,
                         uint32_t aSongLen, uint32_t aSongPos,
                         BluetoothAvrcpResultHandler* aRes);
 
   void ListPlayerAppAttrRsp(int aNumAttr,
--- a/dom/bluetooth/bluedroid/BluetoothUtils.cpp
+++ b/dom/bluetooth/bluedroid/BluetoothUtils.cpp
@@ -17,29 +17,16 @@
 #include "nsIScriptContext.h"
 #include "nsISystemMessagesInternal.h"
 #include "nsString.h"
 #include "nsTArray.h"
 #include "nsServiceManagerUtils.h"
 
 BEGIN_BLUETOOTH_NAMESPACE
 
-void
-BdAddressTypeToString(bt_bdaddr_t* aBdAddressType, nsAString& aRetBdAddress)
-{
-  uint8_t* addr = aBdAddressType->address;
-  char bdstr[18];
-
-  sprintf(bdstr, "%02x:%02x:%02x:%02x:%02x:%02x",
-          (int)addr[0],(int)addr[1],(int)addr[2],
-          (int)addr[3],(int)addr[4],(int)addr[5]);
-
-  aRetBdAddress = NS_ConvertUTF8toUTF16(bdstr);
-}
-
 uint16_t
 UuidToServiceClassInt(const BluetoothUuid& mUuid)
 {
   // extract short UUID 0000xxxx-0000-1000-8000-00805f9b34fb
   uint16_t shortUuid;
   memcpy(&shortUuid, mUuid.mUuid + 2, sizeof(uint16_t));
   return ntohs(shortUuid);
 }
--- a/dom/bluetooth/bluedroid/BluetoothUtils.h
+++ b/dom/bluetooth/bluedroid/BluetoothUtils.h
@@ -2,31 +2,25 @@
 /* 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_bluetoothutils_h__
 #define mozilla_dom_bluetooth_bluetoothutils_h__
 
-#include <hardware/bluetooth.h>
-
 #include "BluetoothCommon.h"
 #include "js/TypeDecls.h"
 
 BEGIN_BLUETOOTH_NAMESPACE
 
 class BluetoothNamedValue;
 class BluetoothValue;
 class BluetoothReplyRunnable;
 
-void
-BdAddressTypeToString(bt_bdaddr_t* aBdAddressType,
-                      nsAString& aRetBdAddress);
-
 uint16_t
 UuidToServiceClassInt(const BluetoothUuid& mUuid);
 
 bool
 SetJsObject(JSContext* aContext,
             const BluetoothValue& aValue,
             JS::Handle<JSObject*> aObj);
 
--- a/dom/system/gonk/ril_worker.js
+++ b/dom/system/gonk/ril_worker.js
@@ -2378,19 +2378,25 @@ RilObject.prototype = {
    */
   setDataRegistration: function(options) {
     this._attachDataRegistration = options.attach;
 
     if (RILQUIRKS_DATA_REGISTRATION_ON_DEMAND) {
       let request = options.attach ? RIL_REQUEST_GPRS_ATTACH :
                                      RIL_REQUEST_GPRS_DETACH;
       this.context.Buf.simpleRequest(request, options);
+      return;
     } else if (RILQUIRKS_SUBSCRIPTION_CONTROL && options.attach) {
       this.context.Buf.simpleRequest(REQUEST_SET_DATA_SUBSCRIPTION, options);
-    }
+      return;
+    }
+
+    // We don't really send a request to rild, so instantly reply success to
+    // RadioInterfaceLayer.
+    this.sendChromeMessage(options);
   },
 
   /**
    * Get failure casue code for the most recently failed PDP context.
    */
   getFailCauseCode: function(callback) {
     this.context.Buf.simpleRequest(REQUEST_LAST_CALL_FAIL_CAUSE,
                                    {callback: callback});