Merge m-c to inbound.
authorRyan VanderMeulen <ryanvm@gmail.com>
Mon, 12 Aug 2013 21:59:20 -0400
changeset 142349 86b6480829c866a7b217a9dc8a92e13835273d36
parent 142299 714f45588ae889ff1f93751872f339ad7c511060 (current diff)
parent 142348 c146d402a55fbaceda6313b5cd45b3a44bf5878e (diff)
child 142350 2900a53981346f53491b7f4296f4d761b31ffc4f
push id32372
push userryanvm@gmail.com
push dateTue, 13 Aug 2013 01:59:20 +0000
treeherdermozilla-inbound@86b6480829c8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone26.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 inbound.
dom/bluetooth/MediaMetaData.cpp
dom/bluetooth/MediaMetaData.h
dom/bluetooth/MediaPlayStatus.cpp
dom/bluetooth/MediaPlayStatus.h
dom/bluetooth/nsIDOMBluetoothAdapter.idl
dom/bluetooth/nsIDOMBluetoothManager.idl
--- a/b2g/chrome/content/forms.js
+++ b/b2g/chrome/content/forms.js
@@ -195,17 +195,18 @@ let FormAssistant = {
     addMessageListener("Forms:SetSelectionRange", this);
     addMessageListener("Forms:ReplaceSurroundingText", this);
     addMessageListener("Forms:GetText", this);
     addMessageListener("Forms:Input:SendKey", this);
     addMessageListener("Forms:GetContext", this);
   },
 
   ignoredInputTypes: new Set([
-    'button', 'file', 'checkbox', 'radio', 'reset', 'submit', 'image'
+    'button', 'file', 'checkbox', 'radio', 'reset', 'submit', 'image',
+    'range'
   ]),
 
   isKeyboardOpened: false,
   selectionStart: -1,
   selectionEnd: -1,
   textBeforeCursor: "",
   textAfterCursor: "",
   scrollIntoViewTimeout: null,
@@ -369,18 +370,20 @@ let FormAssistant = {
             if (this.focusedElement && !FormVisibility.isVisible(this.focusedElement)) {
               this.focusedElement.scrollIntoView(false);
             }
           }.bind(this), RESIZE_SCROLL_DELAY);
         }
         break;
 
       case "input":
-        // When the text content changes, notify the keyboard
-        this.updateSelection();
+        if (this.focusedElement) {
+          // When the text content changes, notify the keyboard
+          this.updateSelection();
+        }
         break;
 
       case "keydown":
         // Don't monitor the text change resulting from key event.
         this._ignoreEditActionOnce = true;
 
         // We use 'setTimeout' to wait until the input element accomplishes the
         // change in selection range.
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,4 +1,4 @@
 {
-    "revision": "cc6b6bcc278e02d1e23c78cc41fcc21c074a82db", 
+    "revision": "3a5bfe8c6e0738750ff4e674a2235fee90cc0ba4", 
     "repo_path": "/integration/gaia-central"
 }
--- a/b2g/installer/package-manifest.in
+++ b/b2g/installer/package-manifest.in
@@ -343,16 +343,18 @@
 
 ; JavaScript components
 @BINPATH@/components/ConsoleAPI.manifest
 @BINPATH@/components/ConsoleAPI.js
 @BINPATH@/components/BrowserElementParent.manifest
 @BINPATH@/components/BrowserElementParent.js
 @BINPATH@/components/ContactManager.js
 @BINPATH@/components/ContactManager.manifest
+@BINPATH@/components/PhoneNumberService.js
+@BINPATH@/components/PhoneNumberService.manifest
 @BINPATH@/components/PermissionSettings.js
 @BINPATH@/components/PermissionSettings.manifest
 @BINPATH@/components/PermissionPromptService.js
 @BINPATH@/components/PermissionPromptService.manifest
 @BINPATH@/components/AlarmsManager.js
 @BINPATH@/components/AlarmsManager.manifest
 @BINPATH@/components/FeedProcessor.manifest
 @BINPATH@/components/FeedProcessor.js
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -515,16 +515,18 @@
 @BINPATH@/components/Identity.manifest
 @BINPATH@/components/recording-cmdline.js
 @BINPATH@/components/recording-cmdline.manifest
 
 @BINPATH@/components/PermissionSettings.js
 @BINPATH@/components/PermissionSettings.manifest
 @BINPATH@/components/ContactManager.js
 @BINPATH@/components/ContactManager.manifest
+@BINPATH@/components/PhoneNumberService.js
+@BINPATH@/components/PhoneNumberService.manifest
 @BINPATH@/components/AlarmsManager.js
 @BINPATH@/components/AlarmsManager.manifest
 @BINPATH@/components/Push.js
 @BINPATH@/components/Push.manifest
 @BINPATH@/components/PushServiceLauncher.js
 @BINPATH@/components/TCPSocket.js
 @BINPATH@/components/TCPServerSocket.js
 @BINPATH@/components/TCPSocketParentIntermediary.js
--- a/content/base/test/test_bug475156.html
+++ b/content/base/test/test_bug475156.html
@@ -12,17 +12,17 @@ https://bugzilla.mozilla.org/show_bug.cg
 <script class="testbody" type="text/javascript">
 
 SimpleTest.waitForExplicitFinish();
 
 var path = "http://mochi.test:8888/tests/content/base/test/";
 
 function fromCache(xhr)
 {
-  var ch = SpecialPowers.wrap(xhr).channel.QueryInterface(SpecialPowers.Ci.nsICachingChannel);
+  var ch = SpecialPowers.wrap(xhr).channel.QueryInterface(SpecialPowers.Ci.nsICacheInfoChannel);
   return ch.isFromCache();  
 }
 
 var tests = [
   // First just init the file with an ETag
   {
     init: function(xhr) 
     {
--- a/content/media/EncodedBufferCache.cpp
+++ b/content/media/EncodedBufferCache.cpp
@@ -8,17 +8,17 @@
 #include "nsAnonymousTemporaryFile.h"
 #include "nsLocalFile.h"
 
 namespace mozilla {
 
 void
 EncodedBufferCache::AppendBuffer(nsTArray<uint8_t> & aBuf)
 {
-  ReentrantMonitorAutoEnter mon(mReentrantMonitor);
+  MutexAutoLock lock(mMutex);
   mDataSize += aBuf.Length();
 
   mEncodedBuffers.AppendElement()->SwapElements(aBuf);
 
   if (!mTempFileEnabled && mDataSize > mMaxMemoryStorage) {
     nsresult rv = NS_OpenAnonymousTemporaryFile(&mFD);
     if (!NS_FAILED(rv)) {
       mTempFileEnabled = true;
@@ -36,17 +36,17 @@ EncodedBufferCache::AppendBuffer(nsTArra
     mEncodedBuffers.Clear();
   }
 
 }
 
 already_AddRefed<nsIDOMBlob>
 EncodedBufferCache::ExtractBlob(const nsAString &aContentType)
 {
-  ReentrantMonitorAutoEnter mon(mReentrantMonitor);
+  MutexAutoLock lock(mMutex);
   nsCOMPtr<nsIDOMBlob> blob;
   if (mTempFileEnabled) {
     // generate new temporary file to write
     blob = new nsDOMTemporaryFileBlob(mFD, 0, mDataSize, aContentType);
     // fallback to memory blob
     mTempFileEnabled = false;
     mDataSize = 0;
     mFD = nullptr;
--- a/content/media/EncodedBufferCache.h
+++ b/content/media/EncodedBufferCache.h
@@ -3,17 +3,17 @@
 /* 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 EncodedBufferCache_h_
 #define EncodedBufferCache_h_
 
 #include "nsTArray.h"
-#include "mozilla/ReentrantMonitor.h"
+#include "mozilla/Mutex.h"
 #include "prio.h"
 #include "nsDOMFile.h"
 
 namespace mozilla {
 
 class ReentrantMonitor;
 /**
  * Data is moved into a temporary file when it grows beyond
@@ -21,17 +21,17 @@ class ReentrantMonitor;
  * The AppendBuffer and ExtractBlob methods are thread-safe and can be called on
  * different threads at the same time.
  */
 class EncodedBufferCache
 {
 public:
   EncodedBufferCache(uint32_t aMaxMemoryStorage)
   : mFD(nullptr),
-    mReentrantMonitor("EncodedBufferCache.Data.Monitor"),
+    mMutex("EncodedBufferCache.Data.Mutex"),
     mDataSize(0),
     mMaxMemoryStorage(aMaxMemoryStorage),
     mTempFileEnabled(false) { }
   ~EncodedBufferCache()
   {
   }
   // Append buffers in cache, check if the queue is too large then switch to write buffer to file system
   // aBuf will append to mEncodedBuffers or temporary File, aBuf also be cleared
@@ -40,17 +40,17 @@ public:
   already_AddRefed<nsIDOMBlob> ExtractBlob(const nsAString &aContentType);
 
 private:
   //array for storing the encoded data.
   nsTArray<nsTArray<uint8_t> > mEncodedBuffers;
   // File handle for the temporary file
   PRFileDesc* mFD;
   // Used to protect the mEncodedBuffer for avoiding AppendBuffer/Consume on different thread at the same time.
-  ReentrantMonitor mReentrantMonitor;
+  Mutex mMutex;;
   // the current buffer size can be read
   uint64_t mDataSize;
   // The maximal buffer allowed in memory
   uint32_t mMaxMemoryStorage;
   // indicate the buffer is stored on temporary file or not
   bool mTempFileEnabled;
 };
 
--- a/content/media/MediaRecorder.cpp
+++ b/content/media/MediaRecorder.cpp
@@ -223,16 +223,17 @@ MediaRecorder::Start(const Optional<int3
 
 void
 MediaRecorder::Stop(ErrorResult& aResult)
 {
   if (mState == RecordingState::Inactive) {
     aResult.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     return;
   }
+  mState = RecordingState::Inactive;
   mTrackUnionStream->RemoveListener(mEncoder);
 }
 
 void
 MediaRecorder::Pause(ErrorResult& aResult)
 {
   if (mState != RecordingState::Recording) {
     aResult.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
@@ -256,22 +257,18 @@ MediaRecorder::Resume(ErrorResult& aResu
 
 void
 MediaRecorder::RequestData(ErrorResult& aResult)
 {
   if (mState != RecordingState::Recording) {
     aResult.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     return;
   }
-
-  nsresult rv = CreateAndDispatchBlobEvent();
-  if (NS_FAILED(rv)) {
-    aResult.Throw(rv);
-    return;
-  }
+  NS_DispatchToMainThread(NS_NewRunnableMethod(this, &MediaRecorder::CreateAndDispatchBlobEvent),
+                                               NS_DISPATCH_NORMAL);
 }
 
 JSObject*
 MediaRecorder::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope)
 {
   return MediaRecorderBinding::Wrap(aCx, aScope, this);
 }
 
--- a/content/media/test/Makefile.in
+++ b/content/media/test/Makefile.in
@@ -111,16 +111,17 @@ MOCHITEST_FILES = \
 		test_source.html \
 		test_source_write.html \
 		test_source_null.html \
 		test_standalone.html \
 		test_volume.html \
 		test_video_to_canvas.html \
 		test_audiowrite.html \
 		test_mediarecorder_creation.html \
+		test_mediarecorder_avoid_recursion.html \
 		test_mediarecorder_record_audiocontext.html \
 		test_mediarecorder_record_stopms.html \
 		test_mozHasAudio.html \
 		test_source_media.html \
 		test_autoplay_contentEditable.html \
 		test_bug448534.html \
 		test_bug463162.xhtml \
 		test_decoder_disable.html \
new file mode 100644
--- /dev/null
+++ b/content/media/test/test_mediarecorder_avoid_recursion.html
@@ -0,0 +1,44 @@
+<html>
+<head>
+  <title>MediaRecorder infinite recursion with requestData() calls in "dataavailable" event</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+  <script type="text/javascript" src="manifest.js"></script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=897776">Mozill
+a Bug 897776</a>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+function startTest() {
+  navigator.mozGetUserMedia({audio: true, fake: true}, function(stream) {
+    var mediaRecorder = new MediaRecorder(stream);
+    var count = 0;
+    mediaRecorder.start();
+    mediaRecorder.ondataavailable = function (e) {
+      if (count++ == 30) {
+        stream.stop();
+      }
+      if (mediaRecorder.state == 'recording') {
+        mediaRecorder.requestData();
+      }
+    }
+    mediaRecorder.requestData();
+    mediaRecorder.onstop = function () {
+      ok(true, "requestData within ondataavailable successfully avoided infinite recursion");
+      SimpleTest.finish();
+    }
+  }, function(err) {
+    ok(false, 'Unexpected error fired with: ' + err);
+    SimpleTest.finish();
+  });
+}
+
+SimpleTest.waitForExplicitFinish();
+startTest();
+
+</script>
+</pre>
+</body>
+</html>
+
--- a/dom/apps/src/PermissionsTable.jsm
+++ b/dom/apps/src/PermissionsTable.jsm
@@ -140,16 +140,21 @@ this.PermissionsTable =  { geolocation: 
                              access: ["read", "write"],
                              additional: ["indexedDB-chrome-settings"]
                            },
                            permissions: {
                              app: DENY_ACTION,
                              privileged: DENY_ACTION,
                              certified: ALLOW_ACTION
                            },
+                           phonenumberservice: {
+                             app: DENY_ACTION,
+                             privileged: DENY_ACTION,
+                             certified: ALLOW_ACTION
+                           },
                            fmradio: {
                              app: DENY_ACTION,
                              privileged: ALLOW_ACTION,
                              certified: ALLOW_ACTION
                            },
                            attention: {
                              app: DENY_ACTION,
                              privileged: DENY_ACTION,
--- a/dom/base/Navigator.cpp
+++ b/dom/base/Navigator.cpp
@@ -54,17 +54,16 @@
 
 #ifdef MOZ_MEDIA_NAVIGATOR
 #include "MediaManager.h"
 #endif
 #ifdef MOZ_B2G_RIL
 #include "Telephony.h"
 #endif
 #ifdef MOZ_B2G_BT
-#include "nsIDOMBluetoothManager.h"
 #include "BluetoothManager.h"
 #endif
 #include "nsIDOMCameraManager.h"
 #include "DOMCameraManager.h"
 
 #ifdef MOZ_AUDIO_CHANNEL_MANAGER
 #include "AudioChannelManager.h"
 #endif
@@ -1244,17 +1243,17 @@ Navigator::GetMozMobileConnection(ErrorR
     mMobileConnection->Init(mWindow);
   }
 
   return mMobileConnection;
 }
 #endif // MOZ_B2G_RIL
 
 #ifdef MOZ_B2G_BT
-nsIDOMBluetoothManager*
+bluetooth::BluetoothManager*
 Navigator::GetMozBluetooth(ErrorResult& aRv)
 {
   if (!mBluetooth) {
     if (!mWindow) {
       aRv.Throw(NS_ERROR_UNEXPECTED);
       return nullptr;
     }
     mBluetooth = bluetooth::BluetoothManager::Create(mWindow);
@@ -1271,17 +1270,17 @@ Navigator::EnsureMessagesManager()
     return NS_OK;
   }
 
   NS_ENSURE_STATE(mWindow);
 
   nsresult rv;
   nsCOMPtr<nsIDOMNavigatorSystemMessages> messageManager =
     do_CreateInstance("@mozilla.org/system-message-manager;1", &rv);
-  
+
   nsCOMPtr<nsIDOMGlobalPropertyInitializer> gpi =
     do_QueryInterface(messageManager);
   NS_ENSURE_TRUE(gpi, NS_ERROR_FAILURE);
 
   // We don't do anything with the return value.
   AutoJSContext cx;
   JS::Rooted<JS::Value> prop_val(cx);
   rv = gpi->Init(mWindow, prop_val.address());
@@ -1600,16 +1599,24 @@ bool
 Navigator::HasPowerSupport(JSContext* /* unused */, JSObject* aGlobal)
 {
   nsCOMPtr<nsPIDOMWindow> win = GetWindowFromGlobal(aGlobal);
   return win && PowerManager::CheckPermission(win);
 }
 
 /* static */
 bool
+Navigator::HasPhoneNumberSupport(JSContext* /* unused */, JSObject* aGlobal)
+{
+  nsCOMPtr<nsPIDOMWindow> win = GetWindowFromGlobal(aGlobal);
+  return CheckPermission(win, "phonenumberservice");
+}
+
+/* static */
+bool
 Navigator::HasIdleSupport(JSContext*  /* unused */, JSObject* aGlobal)
 {
   if (!nsContentUtils::IsIdleObserverAPIEnabled()) {
     return false;
   }
 
   nsCOMPtr<nsPIDOMWindow> win = GetWindowFromGlobal(aGlobal);
   return CheckPermission(win, "idle");
--- a/dom/base/Navigator.h
+++ b/dom/base/Navigator.h
@@ -34,20 +34,16 @@ class systemMessageCallback;
 
 #ifdef MOZ_B2G_RIL
 class nsIDOMMozMobileConnection;
 class nsIDOMMozCellBroadcast;
 class nsIDOMMozVoicemail;
 class nsIDOMMozIccManager;
 #endif // MOZ_B2G_RIL
 
-#ifdef MOZ_B2G_BT
-class nsIDOMBluetoothManager;
-#endif // MOZ_B2G_BT
-
 #include "nsIDOMNavigatorSystemMessages.h"
 
 #include "DOMCameraManager.h"
 
 //*****************************************************************************
 // Navigator: Script "navigator" object
 //*****************************************************************************
 
@@ -86,16 +82,22 @@ class MobileConnection;
 } // namespace Connection;
 
 #ifdef MOZ_B2G_RIL
 namespace telephony {
 class Telephony;
 } // namespace Telephony;
 #endif
 
+#ifdef MOZ_B2G_BT
+namespace bluetooth {
+class BluetoothManager;
+} // namespace bluetooth
+#endif // MOZ_B2G_BT
+
 namespace power {
 class PowerManager;
 } // namespace power
 
 namespace time {
 class TimeManager;
 } // namespace time
 
@@ -224,17 +226,17 @@ public:
   nsIDOMMozCellBroadcast* GetMozCellBroadcast(ErrorResult& aRv);
   nsIDOMMozVoicemail* GetMozVoicemail(ErrorResult& aRv);
   nsIDOMMozIccManager* GetMozIccManager(ErrorResult& aRv);
 #endif // MOZ_B2G_RIL
 #ifdef MOZ_GAMEPAD
   void GetGamepads(nsTArray<nsRefPtr<Gamepad> >& aGamepads, ErrorResult& aRv);
 #endif // MOZ_GAMEPAD
 #ifdef MOZ_B2G_BT
-  nsIDOMBluetoothManager* GetMozBluetooth(ErrorResult& aRv);
+  bluetooth::BluetoothManager* GetMozBluetooth(ErrorResult& aRv);
 #endif // MOZ_B2G_BT
 #ifdef MOZ_TIME_MANAGER
   time::TimeManager* GetMozTime(ErrorResult& aRv);
 #endif // MOZ_TIME_MANAGER
 #ifdef MOZ_AUDIO_CHANNEL_MANAGER
   system::AudioChannelManager* GetMozAudioChannelManager(ErrorResult& aRv);
 #endif // MOZ_AUDIO_CHANNEL_MANAGER
 #ifdef MOZ_MEDIA_NAVIGATOR
@@ -249,16 +251,17 @@ public:
   bool DoNewResolve(JSContext* aCx, JS::Handle<JSObject*> aObject,
                     JS::Handle<jsid> aId, JS::MutableHandle<JS::Value> aValue);
   void GetOwnPropertyNames(JSContext* aCx, nsTArray<nsString>& aNames,
                            ErrorResult& aRv);
 
   // WebIDL helper methods
   static bool HasBatterySupport(JSContext* /* unused*/, JSObject* /*unused */);
   static bool HasPowerSupport(JSContext* /* unused */, JSObject* aGlobal);
+  static bool HasPhoneNumberSupport(JSContext* /* unused */, JSObject* aGlobal);
   static bool HasIdleSupport(JSContext* /* unused */, JSObject* aGlobal);
   static bool HasWakeLockSupport(JSContext* /* unused*/, JSObject* /*unused */);
   static bool HasDesktopNotificationSupport(JSContext* /* unused*/,
                                             JSObject* /*unused */)
   {
     return HasDesktopNotificationSupport();
   }
   static bool HasMobileMessageSupport(JSContext* /* unused */,
@@ -319,17 +322,17 @@ private:
 #endif
   nsRefPtr<network::Connection> mConnection;
 #ifdef MOZ_B2G_RIL
   nsRefPtr<network::MobileConnection> mMobileConnection;
   nsCOMPtr<nsIDOMMozCellBroadcast> mCellBroadcast;
   nsRefPtr<icc::IccManager> mIccManager;
 #endif
 #ifdef MOZ_B2G_BT
-  nsCOMPtr<nsIDOMBluetoothManager> mBluetooth;
+  nsCOMPtr<bluetooth::BluetoothManager> mBluetooth;
 #endif
 #ifdef MOZ_AUDIO_CHANNEL_MANAGER
   nsRefPtr<system::AudioChannelManager> mAudioChannelManager;
 #endif
   nsRefPtr<nsDOMCameraManager> mCameraManager;
   nsCOMPtr<nsIDOMNavigatorSystemMessages> mMessagesManager;
   nsTArray<nsRefPtr<nsDOMDeviceStorage> > mDeviceStorageStores;
   nsRefPtr<time::TimeManager> mTimeManager;
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -227,18 +227,16 @@ using mozilla::dom::workers::ResolveWork
 #include "nsIDOMMobileConnection.h"
 #endif // MOZ_B2G_RIL
 
 #ifdef MOZ_B2G_FM
 #include "FMRadio.h"
 #endif
 
 #ifdef MOZ_B2G_BT
-#include "BluetoothManager.h"
-#include "BluetoothAdapter.h"
 #include "BluetoothDevice.h"
 #endif
 
 #include "DOMCameraManager.h"
 #include "DOMCameraControl.h"
 #include "DOMCameraCapabilities.h"
 #include "nsIOpenWindowEventDetail.h"
 #include "nsIAsyncScrollEventDetail.h"
@@ -628,20 +626,16 @@ static nsDOMClassInfoData sClassInfoData
 #endif
 
 #ifdef MOZ_B2G_FM
   NS_DEFINE_CLASSINFO_DATA(FMRadio, nsEventTargetSH,
                            EVENTTARGET_SCRIPTABLE_FLAGS)
 #endif
 
 #ifdef MOZ_B2G_BT
-  NS_DEFINE_CLASSINFO_DATA(BluetoothManager, nsEventTargetSH,
-                           EVENTTARGET_SCRIPTABLE_FLAGS)
-  NS_DEFINE_CLASSINFO_DATA(BluetoothAdapter, nsEventTargetSH,
-                           EVENTTARGET_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(BluetoothDevice, nsEventTargetSH,
                            EVENTTARGET_SCRIPTABLE_FLAGS)
 #endif
 
   NS_DEFINE_CLASSINFO_DATA(CameraControl, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(CameraCapabilities, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
@@ -1522,24 +1516,16 @@ nsDOMClassInfo::Init()
 #ifdef MOZ_B2G_FM
   DOM_CLASSINFO_MAP_BEGIN(FMRadio, nsIFMRadio)
     DOM_CLASSINFO_MAP_ENTRY(nsIFMRadio)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget)
   DOM_CLASSINFO_MAP_END
 #endif
 
 #ifdef MOZ_B2G_BT
-  DOM_CLASSINFO_MAP_BEGIN(BluetoothManager, nsIDOMBluetoothManager)
-    DOM_CLASSINFO_MAP_ENTRY(nsIDOMBluetoothManager)
-  DOM_CLASSINFO_MAP_END
-
-  DOM_CLASSINFO_MAP_BEGIN(BluetoothAdapter, nsIDOMBluetoothAdapter)
-    DOM_CLASSINFO_MAP_ENTRY(nsIDOMBluetoothAdapter)
-  DOM_CLASSINFO_MAP_END
-
   DOM_CLASSINFO_MAP_BEGIN(BluetoothDevice, nsIDOMBluetoothDevice)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMBluetoothDevice)
   DOM_CLASSINFO_MAP_END
 #endif
 
   DOM_CLASSINFO_MAP_BEGIN(CameraControl, nsICameraControl)
     DOM_CLASSINFO_MAP_ENTRY(nsICameraControl)
   DOM_CLASSINFO_MAP_END
--- a/dom/base/nsDOMClassInfoClasses.h
+++ b/dom/base/nsDOMClassInfoClasses.h
@@ -131,18 +131,16 @@ DOMCI_CLASS(MozVoicemail)
 DOMCI_CLASS(MozIccManager)
 #endif
 
 #ifdef MOZ_B2G_FM
 DOMCI_CLASS(FMRadio)
 #endif
 
 #ifdef MOZ_B2G_BT
-DOMCI_CLASS(BluetoothManager)
-DOMCI_CLASS(BluetoothAdapter)
 DOMCI_CLASS(BluetoothDevice)
 #endif
 
 DOMCI_CLASS(CameraControl)
 DOMCI_CLASS(CameraCapabilities)
 
 DOMCI_CLASS(OpenWindowEventDetail)
 DOMCI_CLASS(AsyncScrollEventDetail)
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -145,16 +145,31 @@ DOMInterfaces = {
     'workers': True,
 }],
 
 'BatteryManager': {
     'nativeType': 'mozilla::dom::battery::BatteryManager',
     'headerFile': 'BatteryManager.h'
 },
 
+'BluetoothAdapter': {
+    'nativeType': 'mozilla::dom::bluetooth::BluetoothAdapter',
+    'headerFile': 'BluetoothAdapter.h'
+},
+
+'BluetoothDevice': {
+    'nativeType': 'mozilla::dom::bluetooth::BluetoothDevice',
+    'headerFile': 'BluetoothDevice.h'
+},
+
+'BluetoothManager': {
+    'nativeType': 'mozilla::dom::bluetooth::BluetoothManager',
+    'headerFile': 'BluetoothManager.h'
+},
+
 'CallEvent': {
     'nativeType': 'mozilla::dom::telephony::CallEvent',
     'headerFile': 'CallEvent.h',
 },
 
 'CallsList': {
     'nativeType': 'mozilla::dom::telephony::CallsList',
     'headerFile': 'CallsList.h',
@@ -1739,24 +1754,23 @@ addExternalIface('File')
 addExternalIface('FileCallback', nativeType='nsIFileCallback',
                  headerFile='nsIDOMHTMLCanvasElement.h')
 addExternalIface('HitRegionOptions', nativeType='nsISupports')
 addExternalIface('imgINotificationObserver', nativeType='imgINotificationObserver')
 addExternalIface('imgIRequest', nativeType='imgIRequest', notflattened=True)
 addExternalIface('LockedFile')
 addExternalIface('MediaList')
 addExternalIface('MenuBuilder', nativeType='nsIMenuBuilder', notflattened=True)
-addExternalIface('MozBluetoothManager', nativeType='nsIDOMBluetoothManager')
 addExternalIface('MozBoxObject', nativeType='nsIBoxObject')
 addExternalIface('MozCellBroadcast')
 addExternalIface('MozConnection', headerFile='nsIDOMConnection.h')
 addExternalIface('MozControllers', nativeType='nsIControllers')
 addExternalIface('MozFrameLoader', nativeType='nsIFrameLoader', notflattened=True)
 addExternalIface('MozIccManager', headerFile='nsIDOMIccManager.h')
-addExternalIface('MozMediaStreamOptions', nativeType='nsIMediaStreamOptions',	
+addExternalIface('MozMediaStreamOptions', nativeType='nsIMediaStreamOptions',
                  headerFile='nsIDOMNavigatorUserMedia.h')
 addExternalIface('MozMobileConnection', headerFile='nsIDOMMobileConnection.h')
 addExternalIface('MozMobileMessageManager', headerFile='nsIDOMMobileMessageManager.h')
 addExternalIface('MozObserver', nativeType='nsIObserver', notflattened=True)
 addExternalIface('MozPowerManager', headerFile='nsIDOMPowerManager.h')
 addExternalIface('MozRDFCompositeDataSource', nativeType='nsIRDFCompositeDataSource',
                  notflattened=True)
 addExternalIface('MozRDFResource', nativeType='nsIRDFResource', notflattened=True)
--- a/dom/bindings/Makefile.in
+++ b/dom/bindings/Makefile.in
@@ -200,17 +200,17 @@ globalgen_dependencies := \
 # Running GlobalGen.py updates ParserResults.pkl as a side-effect
 ParserResults.pkl: $(globalgen_dependencies)
 	PYTHONDONTWRITEBYTECODE=1 $(PYTHON) $(topsrcdir)/config/pythonpath.py \
 	  $(PLY_INCLUDE) -I$(srcdir)/parser \
 	  $(srcdir)/GlobalGen.py $(srcdir)/Bindings.conf . \
 	  --cachedir=$(CACHE_DIR) \
 	  $(all_webidl_files)
 
-# Make sure .deps actually exists, since we'll try to write to it from 
+# Make sure .deps actually exists, since we'll try to write to it from
 # BindingGen.py but we're typically running in the export phase, which is
 # before anyone has bothered creating .deps.
 # Then, pass our long lists through files to try to avoid blowing out the
 # command line.
 # Next, BindingGen.py will examine the changed dependency list to figure out
 # what it really needs to regenerate.
 # Finally, touch the .BindingGen file so that we don't have to keep redoing
 # all that until something else actually changes.
--- a/dom/bluetooth/BluetoothAdapter.cpp
+++ b/dom/bluetooth/BluetoothAdapter.cpp
@@ -11,55 +11,52 @@
 #include "nsDOMClassInfo.h"
 #include "nsIDOMBluetoothDeviceEvent.h"
 #include "nsIDOMBluetoothStatusChangedEvent.h"
 #include "nsTArrayHelpers.h"
 #include "DOMRequest.h"
 #include "nsThreadUtils.h"
 
 #include "mozilla/dom/bluetooth/BluetoothTypes.h"
+#include "mozilla/dom/BluetoothAdapterBinding.h"
 #include "mozilla/dom/ContentChild.h"
 #include "mozilla/LazyIdleThread.h"
 #include "mozilla/Util.h"
 
 #include "BluetoothAdapter.h"
 #include "BluetoothDevice.h"
 #include "BluetoothReplyRunnable.h"
 #include "BluetoothService.h"
 #include "BluetoothUtils.h"
-#include "MediaMetaData.h"
-#include "MediaPlayStatus.h"
 
 using namespace mozilla;
+using namespace mozilla::dom;
 
 USING_BLUETOOTH_NAMESPACE
 
-DOMCI_DATA(BluetoothAdapter, BluetoothAdapter)
-
 NS_IMPL_CYCLE_COLLECTION_CLASS(BluetoothAdapter)
 
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(BluetoothAdapter,
                                                nsDOMEventTargetHelper)
   NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mJsUuids)
   NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mJsDeviceAddresses)
 NS_IMPL_CYCLE_COLLECTION_TRACE_END
 
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(BluetoothAdapter, 
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(BluetoothAdapter,
                                                   nsDOMEventTargetHelper)
   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
-NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(BluetoothAdapter, 
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(BluetoothAdapter,
                                                 nsDOMEventTargetHelper)
   tmp->Unroot();
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
+// QueryInterface implementation for BluetoothAdapter
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(BluetoothAdapter)
-  NS_INTERFACE_MAP_ENTRY(nsIDOMBluetoothAdapter)
-  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(BluetoothAdapter)
 NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetHelper)
 
 NS_IMPL_ADDREF_INHERITED(BluetoothAdapter, nsDOMEventTargetHelper)
 NS_IMPL_RELEASE_INHERITED(BluetoothAdapter, nsDOMEventTargetHelper)
 
 class GetDevicesTask : public BluetoothReplyRunnable
 {
 public:
@@ -159,43 +156,30 @@ public:
   ReleaseMembers()
   {
     BluetoothReplyRunnable::ReleaseMembers();
   }
 };
 
 static int kCreatePairedDeviceTimeout = 50000; // unit: msec
 
-nsresult
-PrepareDOMRequest(nsIDOMWindow* aWindow, nsIDOMDOMRequest** aRequest)
-{
-  MOZ_ASSERT(aWindow);
-
-  nsCOMPtr<nsIDOMRequestService> rs =
-    do_GetService(DOMREQUEST_SERVICE_CONTRACTID);
-  NS_ENSURE_TRUE(rs, NS_ERROR_FAILURE);
-
-  nsresult rv = rs->CreateRequest(aWindow, aRequest);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  return NS_OK;
-}
-
 BluetoothAdapter::BluetoothAdapter(nsPIDOMWindow* aWindow,
                                    const BluetoothValue& aValue)
-  : BluetoothPropertyContainer(BluetoothObjectType::TYPE_ADAPTER)
+  : nsDOMEventTargetHelper(aWindow)
+  , BluetoothPropertyContainer(BluetoothObjectType::TYPE_ADAPTER)
+  , mJsUuids(nullptr)
+  , mJsDeviceAddresses(nullptr)
   , mDiscoverable(false)
   , mDiscovering(false)
   , mPairable(false)
   , mPowered(false)
-  , mJsUuids(nullptr)
-  , mJsDeviceAddresses(nullptr)
   , mIsRooted(false)
 {
   MOZ_ASSERT(aWindow);
+  MOZ_ASSERT(IsDOMBinding());
 
   BindToOwner(aWindow);
   const InfallibleTArray<BluetoothNamedValue>& values =
     aValue.get_ArrayOfBluetoothNamedValue();
   for (uint32_t i = 0; i < values.Length(); ++i) {
     SetPropertyByValue(values[i]);
   }
 
@@ -367,566 +351,590 @@ BluetoothAdapter::Notify(const Bluetooth
     nsCString warningMsg;
     warningMsg.AssignLiteral("Not handling adapter signal: ");
     warningMsg.Append(NS_ConvertUTF16toUTF8(aData.name()));
     NS_WARNING(warningMsg.get());
 #endif
   }
 }
 
-nsresult
-BluetoothAdapter::StartStopDiscovery(bool aStart, nsIDOMDOMRequest** aRequest)
+already_AddRefed<DOMRequest>
+BluetoothAdapter::StartStopDiscovery(bool aStart, ErrorResult& aRv)
 {
-  nsCOMPtr<nsIDOMDOMRequest> req;
-  nsresult rv;
-  rv = PrepareDOMRequest(GetOwner(), getter_AddRefs(req));
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
+  nsCOMPtr<nsPIDOMWindow> win = GetOwner();
+  if (!win) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
+  }
 
+  nsRefPtr<DOMRequest> request = new DOMRequest(win);
   nsRefPtr<BluetoothVoidReplyRunnable> results =
-    new BluetoothVoidReplyRunnable(req);
+    new BluetoothVoidReplyRunnable(request);
 
   BluetoothService* bs = BluetoothService::Get();
-  NS_ENSURE_TRUE(bs, NS_ERROR_FAILURE);
+  if (!bs) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
+  }
+  nsresult rv;
   if (aStart) {
     rv = bs->StartDiscoveryInternal(results);
   } else {
     rv = bs->StopDiscoveryInternal(results);
   }
-  if(NS_FAILED(rv)) {
+  if (NS_FAILED(rv)) {
     NS_WARNING("Start/Stop Discovery failed!");
-    return NS_ERROR_FAILURE;
+    aRv.Throw(rv);
+    return nullptr;
   }
 
   // mDiscovering is not set here, we'll get a Property update from our external
   // protocol to tell us that it's been set.
 
-  req.forget(aRequest);
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-BluetoothAdapter::StartDiscovery(nsIDOMDOMRequest** aRequest)
-{
-  return StartStopDiscovery(true, aRequest);
-}
-
-NS_IMETHODIMP
-BluetoothAdapter::StopDiscovery(nsIDOMDOMRequest** aRequest)
-{
-  return StartStopDiscovery(false, aRequest);
+  return request.forget();
 }
 
-NS_IMETHODIMP
-BluetoothAdapter::GetAddress(nsAString& aAddress)
+already_AddRefed<DOMRequest>
+BluetoothAdapter::StartDiscovery(ErrorResult& aRv)
 {
-  aAddress = mAddress;
-  return NS_OK;
+  return StartStopDiscovery(true, aRv);
 }
 
-NS_IMETHODIMP
-BluetoothAdapter::GetAdapterClass(uint32_t* aClass)
-{
-  *aClass = mClass;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-BluetoothAdapter::GetDiscovering(bool* aDiscovering)
+already_AddRefed<DOMRequest>
+BluetoothAdapter::StopDiscovery(ErrorResult& aRv)
 {
-  *aDiscovering = mDiscovering;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-BluetoothAdapter::GetName(nsAString& aName)
-{
-  aName = mName;
-  return NS_OK;
+  return StartStopDiscovery(false, aRv);
 }
 
-NS_IMETHODIMP
-BluetoothAdapter::GetDiscoverable(bool* aDiscoverable)
+JS::Value
+BluetoothAdapter::GetDevices(JSContext* aContext, ErrorResult& aRv)
 {
-  *aDiscoverable = mDiscoverable;
-  return NS_OK;
-}
+  if (!mJsDeviceAddresses) {
+    NS_WARNING("Devices not yet set!\n");
+    aRv.Throw(NS_ERROR_FAILURE);
+    return JS::NullValue();
+  }
 
-NS_IMETHODIMP
-BluetoothAdapter::GetDiscoverableTimeout(uint32_t* aDiscoverableTimeout)
-{
-  *aDiscoverableTimeout = mDiscoverableTimeout;
-  return NS_OK;
+  return JS::ObjectValue(*xpc_UnmarkGrayObject(mJsDeviceAddresses));
 }
 
-NS_IMETHODIMP
-BluetoothAdapter::GetDevices(JSContext* aCx, JS::Value* aDevices)
+JS::Value
+BluetoothAdapter::GetUuids(JSContext* aContext, ErrorResult& aRv)
 {
-  if (mJsDeviceAddresses) {
-    aDevices->setObject(*mJsDeviceAddresses);
+  if (!mJsUuids) {
+    NS_WARNING("UUIDs not yet set!\n");
+    aRv.Throw(NS_ERROR_FAILURE);
+    return JS::NullValue();
   }
-  else {
-    NS_WARNING("Devices not yet set!\n");
-    return NS_ERROR_FAILURE;
-  }
-  return NS_OK;
+
+  return JS::ObjectValue(*xpc_UnmarkGrayObject(mJsUuids));
 }
 
-NS_IMETHODIMP
-BluetoothAdapter::GetUuids(JSContext* aCx, JS::Value* aValue)
-{
-  if (mJsUuids) {
-    aValue->setObject(*mJsUuids);
-  }
-  else {
-    NS_WARNING("UUIDs not yet set!\n");
-    return NS_ERROR_FAILURE;
-  }    
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-BluetoothAdapter::SetName(const nsAString& aName,
-                          nsIDOMDOMRequest** aRequest)
+already_AddRefed<DOMRequest>
+BluetoothAdapter::SetName(const nsAString& aName, ErrorResult& aRv)
 {
   if (mName.Equals(aName)) {
-    return FirePropertyAlreadySet(GetOwner(), aRequest);
+    return FirePropertyAlreadySet(GetOwner(), aRv);
   }
   nsString name(aName);
   BluetoothValue value(name);
   BluetoothNamedValue property(NS_LITERAL_STRING("Name"), value);
-  return SetProperty(GetOwner(), property, aRequest);
+  return SetProperty(GetOwner(), property, aRv);
 }
 
-NS_IMETHODIMP
-BluetoothAdapter::SetDiscoverable(const bool aDiscoverable,
-                                  nsIDOMDOMRequest** aRequest)
+already_AddRefed<DOMRequest>
+BluetoothAdapter::SetDiscoverable(bool aDiscoverable, ErrorResult& aRv)
 {
   if (aDiscoverable == mDiscoverable) {
-    return FirePropertyAlreadySet(GetOwner(), aRequest);
+    return FirePropertyAlreadySet(GetOwner(), aRv);
   }
   BluetoothValue value(aDiscoverable);
   BluetoothNamedValue property(NS_LITERAL_STRING("Discoverable"), value);
-  return SetProperty(GetOwner(), property, aRequest);
+  return SetProperty(GetOwner(), property, aRv);
 }
- 
-NS_IMETHODIMP
-BluetoothAdapter::SetDiscoverableTimeout(const uint32_t aDiscoverableTimeout,
-                                         nsIDOMDOMRequest** aRequest)
+
+already_AddRefed<DOMRequest>
+BluetoothAdapter::SetDiscoverableTimeout(uint32_t aDiscoverableTimeout, ErrorResult& aRv)
 {
   if (aDiscoverableTimeout == mDiscoverableTimeout) {
-    return FirePropertyAlreadySet(GetOwner(), aRequest);
+    return FirePropertyAlreadySet(GetOwner(), aRv);
   }
   BluetoothValue value(aDiscoverableTimeout);
   BluetoothNamedValue property(NS_LITERAL_STRING("DiscoverableTimeout"), value);
-  return SetProperty(GetOwner(), property, aRequest);
+  return SetProperty(GetOwner(), property, aRv);
 }
 
-NS_IMETHODIMP
-BluetoothAdapter::GetConnectedDevices(uint16_t aProfileId,
-                                      nsIDOMDOMRequest** aRequest)
+already_AddRefed<DOMRequest>
+BluetoothAdapter::GetConnectedDevices(uint16_t aProfileId, ErrorResult& aRv)
 {
   MOZ_ASSERT(NS_IsMainThread());
-  nsCOMPtr<nsIDOMDOMRequest> req;
-  nsresult rv = PrepareDOMRequest(GetOwner(), getter_AddRefs(req));
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
 
+  nsCOMPtr<nsPIDOMWindow> win = GetOwner();
+  if (!win) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
+  }
+
+  nsRefPtr<DOMRequest> request = new DOMRequest(win);
   nsRefPtr<BluetoothReplyRunnable> results =
-    new GetDevicesTask(this, req);
+    new GetDevicesTask(this, request);
 
   BluetoothService* bs = BluetoothService::Get();
-  NS_ENSURE_TRUE(bs, NS_ERROR_FAILURE);
-  rv = bs->GetConnectedDevicePropertiesInternal(aProfileId, results);
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
+  if (!bs) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
+  }
+  nsresult rv = bs->GetConnectedDevicePropertiesInternal(aProfileId, results);
+  if (NS_FAILED(rv)) {
+    aRv.Throw(rv);
+    return nullptr;
+  }
 
-  req.forget(aRequest);
-  return NS_OK;
+  return request.forget();
 }
 
-NS_IMETHODIMP
-BluetoothAdapter::GetPairedDevices(nsIDOMDOMRequest** aRequest)
+already_AddRefed<DOMRequest>
+BluetoothAdapter::GetPairedDevices(ErrorResult& aRv)
 {
-  nsCOMPtr<nsIDOMDOMRequest> req;
-  nsresult rv = PrepareDOMRequest(GetOwner(), getter_AddRefs(req));
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
+  nsCOMPtr<nsPIDOMWindow> win = GetOwner();
+  if (!win) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
+  }
 
+  nsRefPtr<DOMRequest> request = new DOMRequest(win);
   nsRefPtr<BluetoothReplyRunnable> results =
-    new GetDevicesTask(this, req);
+    new GetDevicesTask(this, request);
 
   BluetoothService* bs = BluetoothService::Get();
-  NS_ENSURE_TRUE(bs, NS_ERROR_FAILURE);
-  rv = bs->GetPairedDevicePropertiesInternal(mDeviceAddresses, results);
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
+  if (!bs) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
+  }
+  nsresult rv = bs->GetPairedDevicePropertiesInternal(mDeviceAddresses, results);
+  if (NS_FAILED(rv)) {
+    aRv.Throw(rv);
+    return nullptr;
+  }
 
-  req.forget(aRequest);
-  return NS_OK;
+  return request.forget();
 }
 
-nsresult
-BluetoothAdapter::PairUnpair(bool aPair,
-                             nsIDOMBluetoothDevice* aDevice,
-                             nsIDOMDOMRequest** aRequest)
+already_AddRefed<DOMRequest>
+BluetoothAdapter::PairUnpair(bool aPair, BluetoothDevice& aDevice,
+                             ErrorResult& aRv)
 {
-  nsCOMPtr<nsIDOMDOMRequest> req;
-  nsresult rv = PrepareDOMRequest(GetOwner(), getter_AddRefs(req));
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
+  nsCOMPtr<nsPIDOMWindow> win = GetOwner();
+  if (!win) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
+  }
 
+  nsRefPtr<DOMRequest> request = new DOMRequest(win);
   nsRefPtr<BluetoothVoidReplyRunnable> results =
-    new BluetoothVoidReplyRunnable(req);
+    new BluetoothVoidReplyRunnable(request);
 
   nsAutoString addr;
-  aDevice->GetAddress(addr);
+  aDevice.GetAddress(addr);
 
   BluetoothService* bs = BluetoothService::Get();
-  NS_ENSURE_TRUE(bs, NS_ERROR_FAILURE);
+  if (!bs) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
+  }
+  nsresult rv;
   if (aPair) {
     rv = bs->CreatePairedDeviceInternal(addr,
                                         kCreatePairedDeviceTimeout,
                                         results);
   } else {
     rv = bs->RemoveDeviceInternal(addr, results);
   }
-
   if (NS_FAILED(rv)) {
     NS_WARNING("Pair/Unpair failed!");
-    return NS_ERROR_FAILURE;
+    aRv.Throw(rv);
+    return nullptr;
   }
 
-  req.forget(aRequest);
-  return NS_OK;
+  return request.forget();
 }
 
-nsresult
-BluetoothAdapter::Pair(nsIDOMBluetoothDevice* aDevice,
-                       nsIDOMDOMRequest** aRequest)
+already_AddRefed<DOMRequest>
+BluetoothAdapter::Pair(BluetoothDevice& aDevice, ErrorResult& aRv)
 {
-  return PairUnpair(true, aDevice, aRequest);
+  return PairUnpair(true, aDevice, aRv);
 }
 
-nsresult
-BluetoothAdapter::Unpair(nsIDOMBluetoothDevice* aDevice,
-                         nsIDOMDOMRequest** aRequest)
+already_AddRefed<DOMRequest>
+BluetoothAdapter::Unpair(BluetoothDevice& aDevice, ErrorResult& aRv)
 {
-  return PairUnpair(false, aDevice, aRequest);
+  return PairUnpair(false, aDevice, aRv);
 }
 
-nsresult
+already_AddRefed<DOMRequest>
 BluetoothAdapter::SetPinCode(const nsAString& aDeviceAddress,
-                             const nsAString& aPinCode,
-                             nsIDOMDOMRequest** aRequest)
+                             const nsAString& aPinCode, ErrorResult& aRv)
 {
-  nsCOMPtr<nsIDOMDOMRequest> req;
-  nsresult rv = PrepareDOMRequest(GetOwner(), getter_AddRefs(req));
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
+  nsCOMPtr<nsPIDOMWindow> win = GetOwner();
+  if (!win) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
+  }
 
+  nsRefPtr<DOMRequest> request = new DOMRequest(win);
   nsRefPtr<BluetoothVoidReplyRunnable> results =
-    new BluetoothVoidReplyRunnable(req);
+    new BluetoothVoidReplyRunnable(request);
 
   BluetoothService* bs = BluetoothService::Get();
-  NS_ENSURE_TRUE(bs, NS_ERROR_FAILURE);
-  if(!bs->SetPinCodeInternal(aDeviceAddress, aPinCode, results)) {
+  if (!bs) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
+  }
+  if (!bs->SetPinCodeInternal(aDeviceAddress, aPinCode, results)) {
     NS_WARNING("SetPinCode failed!");
-    return NS_ERROR_FAILURE;
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
   }
 
-  req.forget(aRequest);
-  return NS_OK;
+  return request.forget();
 }
 
-nsresult
+already_AddRefed<DOMRequest>
 BluetoothAdapter::SetPasskey(const nsAString& aDeviceAddress, uint32_t aPasskey,
-                             nsIDOMDOMRequest** aRequest)
+                             ErrorResult& aRv)
 {
-  nsCOMPtr<nsIDOMDOMRequest> req;
-  nsresult rv = PrepareDOMRequest(GetOwner(), getter_AddRefs(req));
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
+  nsCOMPtr<nsPIDOMWindow> win = GetOwner();
+  if (!win) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
+  }
 
+  nsRefPtr<DOMRequest> request = new DOMRequest(win);
   nsRefPtr<BluetoothVoidReplyRunnable> results =
-    new BluetoothVoidReplyRunnable(req);
+    new BluetoothVoidReplyRunnable(request);
 
   BluetoothService* bs = BluetoothService::Get();
-  NS_ENSURE_TRUE(bs, NS_ERROR_FAILURE);
-  if(bs->SetPasskeyInternal(aDeviceAddress, aPasskey, results)) {
+  if (!bs) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
+  }
+  if (bs->SetPasskeyInternal(aDeviceAddress, aPasskey, results)) {
     NS_WARNING("SetPasskeyInternal failed!");
-    return NS_ERROR_FAILURE;
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
   }
 
-  req.forget(aRequest);
-  return NS_OK;
+  return request.forget();
 }
 
-nsresult
+already_AddRefed<DOMRequest>
 BluetoothAdapter::SetPairingConfirmation(const nsAString& aDeviceAddress,
-                                         bool aConfirmation,
-                                         nsIDOMDOMRequest** aRequest)
+                                         bool aConfirmation, ErrorResult& aRv)
 {
-  nsCOMPtr<nsIDOMDOMRequest> req;
-  nsresult rv = PrepareDOMRequest(GetOwner(), getter_AddRefs(req));
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
+  nsCOMPtr<nsPIDOMWindow> win = GetOwner();
+  if (!win) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
+  }
 
+  nsRefPtr<DOMRequest> request = new DOMRequest(win);
   nsRefPtr<BluetoothVoidReplyRunnable> results =
-    new BluetoothVoidReplyRunnable(req);
+    new BluetoothVoidReplyRunnable(request);
 
   BluetoothService* bs = BluetoothService::Get();
-  NS_ENSURE_TRUE(bs, NS_ERROR_FAILURE);
-  if(!bs->SetPairingConfirmationInternal(aDeviceAddress,
-                                         aConfirmation,
-                                         results)) {
+  if (!bs) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
+  }
+  if (!bs->SetPairingConfirmationInternal(aDeviceAddress,
+                                          aConfirmation,
+                                          results)) {
     NS_WARNING("SetPairingConfirmation failed!");
-    return NS_ERROR_FAILURE;
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
   }
 
-  req.forget(aRequest);
-  return NS_OK;
+  return request.forget();
 }
 
-nsresult
+already_AddRefed<DOMRequest>
 BluetoothAdapter::SetAuthorization(const nsAString& aDeviceAddress, bool aAllow,
-                                   nsIDOMDOMRequest** aRequest)
+                                   ErrorResult& aRv)
 {
-  nsCOMPtr<nsIDOMDOMRequest> req;
-  nsresult rv = PrepareDOMRequest(GetOwner(), getter_AddRefs(req));
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
-
-  nsRefPtr<BluetoothVoidReplyRunnable> results =
-    new BluetoothVoidReplyRunnable(req);
-
-  BluetoothService* bs = BluetoothService::Get();
-  NS_ENSURE_TRUE(bs, NS_ERROR_FAILURE);
-  if(!bs->SetAuthorizationInternal(aDeviceAddress, aAllow, results)) {
-    NS_WARNING("SetAuthorization failed!");
-    return NS_ERROR_FAILURE;
+  nsCOMPtr<nsPIDOMWindow> win = GetOwner();
+  if (!win) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
   }
 
-  req.forget(aRequest);
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-BluetoothAdapter::Connect(const nsAString& aDeviceAddress,
-                          uint16_t aProfileId,
-                          nsIDOMDOMRequest** aRequest)
-{
-  nsCOMPtr<nsIDOMDOMRequest> req;
-  nsresult rv = PrepareDOMRequest(GetOwner(), getter_AddRefs(req));
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
+  nsRefPtr<DOMRequest> request = new DOMRequest(win);
+  nsRefPtr<BluetoothVoidReplyRunnable> results =
+    new BluetoothVoidReplyRunnable(request);
 
   BluetoothService* bs = BluetoothService::Get();
-  NS_ENSURE_TRUE(bs, NS_ERROR_FAILURE);
+  if (!bs) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
+  }
+  if (!bs->SetAuthorizationInternal(aDeviceAddress, aAllow, results)) {
+    NS_WARNING("SetAuthorization failed!");
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
+  }
 
-  nsRefPtr<BluetoothVoidReplyRunnable> results =
-    new BluetoothVoidReplyRunnable(req);
-  bs->Connect(aDeviceAddress, aProfileId, results);
-
-  req.forget(aRequest);
-  return NS_OK;
+  return request.forget();
 }
 
-NS_IMETHODIMP
-BluetoothAdapter::Disconnect(uint16_t aProfileId,
-                             nsIDOMDOMRequest** aRequest)
+already_AddRefed<DOMRequest>
+BluetoothAdapter::Connect(const nsAString& aDeviceAddress,
+                          uint16_t aProfileId, ErrorResult& aRv)
 {
-  nsCOMPtr<nsIDOMDOMRequest> req;
-  nsresult rv = PrepareDOMRequest(GetOwner(), getter_AddRefs(req));
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
+  nsCOMPtr<nsPIDOMWindow> win = GetOwner();
+  if (!win) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
+  }
 
+  nsRefPtr<DOMRequest> request = new DOMRequest(win);
   nsRefPtr<BluetoothVoidReplyRunnable> results =
-    new BluetoothVoidReplyRunnable(req);
+    new BluetoothVoidReplyRunnable(request);
 
   BluetoothService* bs = BluetoothService::Get();
-  NS_ENSURE_TRUE(bs, NS_ERROR_FAILURE);
-  bs->Disconnect(aProfileId, results);
+  if (!bs) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
+  }
+  bs->Connect(aDeviceAddress, aProfileId, results);
 
-  req.forget(aRequest);
-  return NS_OK;
+  return request.forget();
 }
 
-NS_IMETHODIMP
-BluetoothAdapter::SendFile(const nsAString& aDeviceAddress,
-                           nsIDOMBlob* aBlob,
-                           nsIDOMDOMRequest** aRequest)
+already_AddRefed<DOMRequest>
+BluetoothAdapter::Disconnect(uint16_t aProfileId, ErrorResult& aRv)
 {
-  nsCOMPtr<nsIDOMDOMRequest> req;
-  nsresult rv = PrepareDOMRequest(GetOwner(), getter_AddRefs(req));
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
+  nsCOMPtr<nsPIDOMWindow> win = GetOwner();
+  if (!win) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
+  }
+
+  nsRefPtr<DOMRequest> request = new DOMRequest(win);
+  nsRefPtr<BluetoothVoidReplyRunnable> results =
+    new BluetoothVoidReplyRunnable(request);
+
+  BluetoothService* bs = BluetoothService::Get();
+  if (!bs) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
+  }
+  bs->Disconnect(aProfileId, results);
 
+  return request.forget();
+}
+
+already_AddRefed<DOMRequest>
+BluetoothAdapter::SendFile(const nsAString& aDeviceAddress,
+                           nsIDOMBlob* aBlob, ErrorResult& aRv)
+{
+  nsCOMPtr<nsPIDOMWindow> win = GetOwner();
+  if (!win) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
+  }
+
+  nsRefPtr<DOMRequest> request = new DOMRequest(win);
   nsRefPtr<BluetoothVoidReplyRunnable> results =
-    new BluetoothVoidReplyRunnable(req);
+    new BluetoothVoidReplyRunnable(request);
 
   BlobChild* actor =
-    mozilla::dom::ContentChild::GetSingleton()->GetOrCreateActorForBlob(aBlob);
+    ContentChild::GetSingleton()->GetOrCreateActorForBlob(aBlob);
   if (!actor) {
     NS_WARNING("Can't create actor");
-    return NS_ERROR_FAILURE;
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
   }
 
   BluetoothService* bs = BluetoothService::Get();
-  NS_ENSURE_TRUE(bs, NS_ERROR_FAILURE);
+  if (!bs) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
+  }
   bs->SendFile(aDeviceAddress, nullptr, actor, results);
 
-  req.forget(aRequest);
-  return NS_OK;
+  return request.forget();
 }
 
-NS_IMETHODIMP
-BluetoothAdapter::StopSendingFile(const nsAString& aDeviceAddress,
-                                  nsIDOMDOMRequest** aRequest)
+already_AddRefed<DOMRequest>
+BluetoothAdapter::StopSendingFile(const nsAString& aDeviceAddress, ErrorResult& aRv)
 {
-  nsCOMPtr<nsIDOMDOMRequest> req;
-  nsresult rv = PrepareDOMRequest(GetOwner(), getter_AddRefs(req));
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
-
-  nsRefPtr<BluetoothVoidReplyRunnable> results =
-    new BluetoothVoidReplyRunnable(req);
-
-  BluetoothService* bs = BluetoothService::Get();
-  NS_ENSURE_TRUE(bs, NS_ERROR_FAILURE);
-  bs->StopSendingFile(aDeviceAddress, results);
+  nsCOMPtr<nsPIDOMWindow> win = GetOwner();
+  if (!win) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
+  }
 
-  req.forget(aRequest);
-  return NS_OK;
-}
-
-nsresult
-BluetoothAdapter::ConfirmReceivingFile(const nsAString& aDeviceAddress,
-                                       bool aConfirmation,
-                                       nsIDOMDOMRequest** aRequest)
-{
-  nsCOMPtr<nsIDOMDOMRequest> req;
-  nsresult rv = PrepareDOMRequest(GetOwner(), getter_AddRefs(req));
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
-
+  nsRefPtr<DOMRequest> request = new DOMRequest(win);
   nsRefPtr<BluetoothVoidReplyRunnable> results =
-    new BluetoothVoidReplyRunnable(req);
+    new BluetoothVoidReplyRunnable(request);
 
   BluetoothService* bs = BluetoothService::Get();
-  NS_ENSURE_TRUE(bs, NS_ERROR_FAILURE);
-  bs->ConfirmReceivingFile(aDeviceAddress, aConfirmation, results);
+  if (!bs) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
+  }
+  bs->StopSendingFile(aDeviceAddress, results);
 
-  req.forget(aRequest);
-  return NS_OK;
+  return request.forget();
 }
 
-NS_IMETHODIMP
-BluetoothAdapter::ConnectSco(nsIDOMDOMRequest** aRequest)
+already_AddRefed<DOMRequest>
+BluetoothAdapter::ConfirmReceivingFile(const nsAString& aDeviceAddress,
+                                       bool aConfirmation, ErrorResult& aRv)
 {
-  nsCOMPtr<nsIDOMDOMRequest> req;
-  nsresult rv = PrepareDOMRequest(GetOwner(), getter_AddRefs(req));
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
+  nsCOMPtr<nsPIDOMWindow> win = GetOwner();
+  if (!win) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
+  }
 
+  nsRefPtr<DOMRequest> request = new DOMRequest(win);
   nsRefPtr<BluetoothVoidReplyRunnable> results =
-    new BluetoothVoidReplyRunnable(req);
+    new BluetoothVoidReplyRunnable(request);
 
   BluetoothService* bs = BluetoothService::Get();
-  NS_ENSURE_TRUE(bs, NS_ERROR_FAILURE);
+  if (!bs) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
+  }
+  bs->ConfirmReceivingFile(aDeviceAddress, aConfirmation, results);
+
+  return request.forget();
+}
+
+already_AddRefed<DOMRequest>
+BluetoothAdapter::ConnectSco(ErrorResult& aRv)
+{
+  nsCOMPtr<nsPIDOMWindow> win = GetOwner();
+  if (!win) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
+  }
+
+  nsRefPtr<DOMRequest> request = new DOMRequest(win);
+  nsRefPtr<BluetoothVoidReplyRunnable> results =
+    new BluetoothVoidReplyRunnable(request);
+
+  BluetoothService* bs = BluetoothService::Get();
+  if (!bs) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
+  }
   bs->ConnectSco(results);
 
-  req.forget(aRequest);
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-BluetoothAdapter::DisconnectSco(nsIDOMDOMRequest** aRequest)
-{
-  nsCOMPtr<nsIDOMDOMRequest> req;
-  nsresult rv = PrepareDOMRequest(GetOwner(), getter_AddRefs(req));
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
-
-  nsRefPtr<BluetoothVoidReplyRunnable> results =
-    new BluetoothVoidReplyRunnable(req);
-
-  BluetoothService* bs = BluetoothService::Get();
-  NS_ENSURE_TRUE(bs, NS_ERROR_FAILURE);
-  bs->DisconnectSco(results);
-
-  req.forget(aRequest);
-  return NS_OK;
+  return request.forget();
 }
 
-NS_IMETHODIMP
-BluetoothAdapter::IsScoConnected(nsIDOMDOMRequest** aRequest)
+already_AddRefed<DOMRequest>
+BluetoothAdapter::DisconnectSco(ErrorResult& aRv)
 {
-  nsCOMPtr<nsIDOMDOMRequest> req;
-  nsresult rv = PrepareDOMRequest(GetOwner(), getter_AddRefs(req));
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
+  nsCOMPtr<nsPIDOMWindow> win = GetOwner();
+  if (!win) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
+  }
 
-  nsRefPtr<BluetoothReplyRunnable> results =
-    new GetScoConnectionStatusTask(req);
+  nsRefPtr<DOMRequest> request = new DOMRequest(win);
+  nsRefPtr<BluetoothVoidReplyRunnable> results =
+    new BluetoothVoidReplyRunnable(request);
 
   BluetoothService* bs = BluetoothService::Get();
-  NS_ENSURE_TRUE(bs, NS_ERROR_FAILURE);
-  bs->IsScoConnected(results);
+  if (!bs) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
+  }
+  bs->DisconnectSco(results);
 
-  req.forget(aRequest);
-  return NS_OK;
+  return request.forget();
 }
 
-NS_IMETHODIMP
-BluetoothAdapter::SendMediaMetaData(const JS::Value& aOptions,
-                                    nsIDOMDOMRequest** aRequest)
+already_AddRefed<DOMRequest>
+BluetoothAdapter::IsScoConnected(ErrorResult& aRv)
 {
-  MediaMetaData metadata;
-
-  nsresult rv;
-  nsIScriptContext* sc = GetContextForEventHandlers(&rv);
-  NS_ENSURE_SUCCESS(rv, rv);
+  nsCOMPtr<nsPIDOMWindow> win = GetOwner();
+  if (!win) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
+  }
 
-  AutoPushJSContext cx(sc->GetNativeContext());
-  rv = metadata.Init(cx, &aOptions);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  nsCOMPtr<nsIDOMDOMRequest> req;
-  rv = PrepareDOMRequest(GetOwner(), getter_AddRefs(req));
-  NS_ENSURE_SUCCESS(rv, rv);
-
+  nsRefPtr<DOMRequest> request = new DOMRequest(win);
   nsRefPtr<BluetoothReplyRunnable> results =
-    new BluetoothVoidReplyRunnable(req);
+    new GetScoConnectionStatusTask(request);
 
   BluetoothService* bs = BluetoothService::Get();
-  NS_ENSURE_TRUE(bs, NS_ERROR_FAILURE);
-  bs->SendMetaData(metadata.mTitle,
-                   metadata.mArtist,
-                   metadata.mAlbum,
-                   metadata.mMediaNumber,
-                   metadata.mTotalMediaCount,
-                   metadata.mDuration,
-                   results);
+  if (!bs) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
+  }
+  bs->IsScoConnected(results);
 
-  req.forget(aRequest);
-  return NS_OK;
+  return request.forget();
 }
 
-NS_IMETHODIMP
-BluetoothAdapter::SendMediaPlayStatus(const JS::Value& aOptions,
-                                      nsIDOMDOMRequest** aRequest)
+already_AddRefed<DOMRequest>
+BluetoothAdapter::SendMediaMetaData(const MediaMetaData& aMediaMetaData, ErrorResult& aRv)
 {
-  MediaPlayStatus status;
-
-  nsresult rv;
-  nsIScriptContext* sc = GetContextForEventHandlers(&rv);
-  NS_ENSURE_SUCCESS(rv, rv);
+  nsCOMPtr<nsPIDOMWindow> win = GetOwner();
+  if (!win) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
+  }
 
-  AutoPushJSContext cx(sc->GetNativeContext());
-  rv = status.Init(cx, &aOptions);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  nsCOMPtr<nsIDOMDOMRequest> req;
-  rv = PrepareDOMRequest(GetOwner(), getter_AddRefs(req));
-  NS_ENSURE_SUCCESS(rv, rv);
-
+  nsRefPtr<DOMRequest> request = new DOMRequest(win);
   nsRefPtr<BluetoothReplyRunnable> results =
-    new BluetoothVoidReplyRunnable(req);
+    new BluetoothVoidReplyRunnable(request);
 
   BluetoothService* bs = BluetoothService::Get();
-  NS_ENSURE_TRUE(bs, NS_ERROR_FAILURE);
-  bs->SendPlayStatus(status.mDuration,
-                     status.mPosition,
-                     status.mPlayStatus,
+  if (!bs) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
+  }
+  bs->SendMetaData(aMediaMetaData.mTitle,
+                   aMediaMetaData.mArtist,
+                   aMediaMetaData.mAlbum,
+                   aMediaMetaData.mMediaNumber,
+                   aMediaMetaData.mTotalMediaCount,
+                   aMediaMetaData.mDuration,
+                   results);
+
+  return request.forget();
+}
+
+already_AddRefed<DOMRequest>
+BluetoothAdapter::SendMediaPlayStatus(const MediaPlayStatus& aMediaPlayStatus, ErrorResult& aRv)
+{
+  nsCOMPtr<nsPIDOMWindow> win = GetOwner();
+  if (!win) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
+  }
+
+  nsRefPtr<DOMRequest> request = new DOMRequest(win);
+  nsRefPtr<BluetoothReplyRunnable> results =
+    new BluetoothVoidReplyRunnable(request);
+
+  BluetoothService* bs = BluetoothService::Get();
+  if (!bs) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
+  }
+  bs->SendPlayStatus(aMediaPlayStatus.mDuration,
+                     aMediaPlayStatus.mPosition,
+                     aMediaPlayStatus.mPlayStatus,
                      results);
 
-  req.forget(aRequest);
-  return NS_OK;
+  return request.forget();
 }
 
-NS_IMPL_EVENT_HANDLER(BluetoothAdapter, devicefound)
-NS_IMPL_EVENT_HANDLER(BluetoothAdapter, a2dpstatuschanged)
-NS_IMPL_EVENT_HANDLER(BluetoothAdapter, hfpstatuschanged)
-NS_IMPL_EVENT_HANDLER(BluetoothAdapter, pairedstatuschanged)
-NS_IMPL_EVENT_HANDLER(BluetoothAdapter, scostatuschanged)
+JSObject*
+BluetoothAdapter::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope)
+{
+  return BluetoothAdapterBinding::Wrap(aCx, aScope, this);
+}
--- a/dom/bluetooth/BluetoothAdapter.h
+++ b/dom/bluetooth/BluetoothAdapter.h
@@ -7,76 +7,180 @@
 #ifndef mozilla_dom_bluetooth_bluetoothadapter_h__
 #define mozilla_dom_bluetooth_bluetoothadapter_h__
 
 #include "mozilla/Attributes.h"
 #include "BluetoothCommon.h"
 #include "BluetoothPropertyContainer.h"
 #include "nsCOMPtr.h"
 #include "nsDOMEventTargetHelper.h"
-#include "nsIDOMBluetoothAdapter.h"
+#include "nsIDOMBluetoothDevice.h"
 
-class nsIEventTarget;
-class nsIDOMDOMRequest;
+namespace mozilla {
+namespace dom {
+class DOMRequest;
+struct MediaMetaData;
+struct MediaPlayStatus;
+}
+}
 
 BEGIN_BLUETOOTH_NAMESPACE
 
+class BluetoothDevice;
 class BluetoothSignal;
 class BluetoothNamedValue;
 class BluetoothValue;
 
 class BluetoothAdapter : public nsDOMEventTargetHelper
-                       , public nsIDOMBluetoothAdapter
                        , public BluetoothSignalObserver
                        , public BluetoothPropertyContainer
 {
 public:
   NS_DECL_ISUPPORTS_INHERITED
-  NS_DECL_NSIDOMBLUETOOTHADAPTER
-
-  NS_REALLY_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper)
 
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(BluetoothAdapter,
                                                          nsDOMEventTargetHelper)
 
   static already_AddRefed<BluetoothAdapter>
   Create(nsPIDOMWindow* aOwner, const BluetoothValue& aValue);
 
   void Notify(const BluetoothSignal& aParam);
 
-  nsISupports*
-  ToISupports()
+  void Unroot();
+  virtual void SetPropertyByValue(const BluetoothNamedValue& aValue) MOZ_OVERRIDE;
+
+  void GetAddress(nsString& aAddress) const
+  {
+    aAddress = mAddress;
+  }
+
+  uint32_t
+  Class() const
+  {
+    return mClass;
+  }
+
+  void
+  GetName(nsString& aName) const
   {
-    return static_cast<EventTarget*>(this);
+    aName = mName;
+  }
+
+  bool
+  Discovering() const
+  {
+    return mDiscovering;
+  }
+
+  bool
+  Discoverable() const
+  {
+    return mDiscoverable;
+  }
+
+  uint32_t
+  DiscoverableTimeout() const
+  {
+    return mDiscoverableTimeout;
   }
 
-  void Unroot();
-  virtual void SetPropertyByValue(const BluetoothNamedValue& aValue) MOZ_OVERRIDE;  
+  JS::Value GetDevices(JSContext* aContext, ErrorResult& aRv);
+  JS::Value GetUuids(JSContext* aContext, ErrorResult& aRv);
+
+  already_AddRefed<mozilla::dom::DOMRequest>
+    SetName(const nsAString& aName, ErrorResult& aRv);
+
+  already_AddRefed<DOMRequest>
+    SetDiscoverable(bool aDiscoverable, ErrorResult& aRv);
+  already_AddRefed<DOMRequest>
+    SetDiscoverableTimeout(uint32_t aTimeout, ErrorResult& aRv);
+  already_AddRefed<DOMRequest> StartDiscovery(ErrorResult& aRv);
+  already_AddRefed<DOMRequest> StopDiscovery(ErrorResult& aRv);
+
+  already_AddRefed<DOMRequest>
+    Pair(BluetoothDevice& aDevice, ErrorResult& aRv);
+  already_AddRefed<DOMRequest>
+    Unpair(BluetoothDevice& aDevice, ErrorResult& aRv);
+  already_AddRefed<DOMRequest>
+    GetPairedDevices(ErrorResult& aRv);
+  already_AddRefed<DOMRequest>
+    SetPinCode(const nsAString& aDeviceAddress, const nsAString& aPinCode,
+               ErrorResult& aRv);
+  already_AddRefed<DOMRequest>
+    SetPasskey(const nsAString& aDeviceAddress, uint32_t aPasskey,
+               ErrorResult& aRv);
+  already_AddRefed<DOMRequest>
+    SetPairingConfirmation(const nsAString& aDeviceAddress, bool aConfirmation,
+                           ErrorResult& aRv);
+  already_AddRefed<DOMRequest>
+    SetAuthorization(const nsAString& aDeviceAddress, bool aAllow,
+                     ErrorResult& aRv);
+
+  already_AddRefed<DOMRequest>
+    Connect(const nsAString& aDeviceAddress, uint16_t aProfile,
+            ErrorResult& aRv);
+  already_AddRefed<DOMRequest>
+    Disconnect(uint16_t aProfile, ErrorResult& aRv);
+  already_AddRefed<DOMRequest>
+    GetConnectedDevices(uint16_t aProfile, ErrorResult& aRv);
+
+  already_AddRefed<DOMRequest>
+    SendFile(const nsAString& aDeviceAddress, nsIDOMBlob* aBlob,
+             ErrorResult& aRv);
+  already_AddRefed<DOMRequest>
+    StopSendingFile(const nsAString& aDeviceAddress, ErrorResult& aRv);
+  already_AddRefed<DOMRequest>
+    ConfirmReceivingFile(const nsAString& aDeviceAddress, bool aConfirmation,
+                         ErrorResult& aRv);
+
+  already_AddRefed<DOMRequest> ConnectSco(ErrorResult& aRv);
+  already_AddRefed<DOMRequest> DisconnectSco(ErrorResult& aRv);
+  already_AddRefed<DOMRequest> IsScoConnected(ErrorResult& aRv);
+
+  already_AddRefed<DOMRequest>
+    SendMediaMetaData(const MediaMetaData& aMediaMetaData, ErrorResult& aRv);
+  already_AddRefed<DOMRequest>
+    SendMediaPlayStatus(const MediaPlayStatus& aMediaPlayStatus, ErrorResult& aRv);
+
+  IMPL_EVENT_HANDLER(devicefound);
+  IMPL_EVENT_HANDLER(a2dpstatuschanged);
+  IMPL_EVENT_HANDLER(hfpstatuschanged);
+  IMPL_EVENT_HANDLER(pairedstatuschanged);
+  IMPL_EVENT_HANDLER(scostatuschanged);
+
+  nsPIDOMWindow* GetParentObject() const
+  {
+     return GetOwner();
+  }
+
+  virtual JSObject*
+    WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
+
 private:
-
   BluetoothAdapter(nsPIDOMWindow* aOwner, const BluetoothValue& aValue);
   ~BluetoothAdapter();
 
   void Root();
-  nsresult StartStopDiscovery(bool aStart, nsIDOMDOMRequest** aRequest);
-  nsresult PairUnpair(bool aPair,
-                      nsIDOMBluetoothDevice* aDevice,
-                      nsIDOMDOMRequest** aRequest);
-  
+
+  already_AddRefed<mozilla::dom::DOMRequest>
+    StartStopDiscovery(bool aStart, ErrorResult& aRv);
+  already_AddRefed<mozilla::dom::DOMRequest>
+    PairUnpair(bool aPair, BluetoothDevice& aDevice, ErrorResult& aRv);
+
+  JS::Heap<JSObject*> mJsUuids;
+  JS::Heap<JSObject*> mJsDeviceAddresses;
   nsString mAddress;
   nsString mName;
   bool mDiscoverable;
   bool mDiscovering;
   bool mPairable;
   bool mPowered;
   uint32_t mPairableTimeout;
   uint32_t mDiscoverableTimeout;
   uint32_t mClass;
   nsTArray<nsString> mDeviceAddresses;
   nsTArray<nsString> mUuids;
-  JS::Heap<JSObject*> mJsUuids;
-  JS::Heap<JSObject*> mJsDeviceAddresses;
   bool mIsRooted;
 };
 
 END_BLUETOOTH_NAMESPACE
 
 #endif
--- a/dom/bluetooth/BluetoothDevice.cpp
+++ b/dom/bluetooth/BluetoothDevice.cpp
@@ -10,16 +10,17 @@
 #include "BluetoothService.h"
 #include "BluetoothUtils.h"
 
 #include "nsDOMClassInfo.h"
 #include "nsContentUtils.h"
 #include "nsTArrayHelpers.h"
 
 #include "mozilla/dom/bluetooth/BluetoothTypes.h"
+#include "mozilla/dom/BluetoothDeviceBinding.h"
 
 USING_BLUETOOTH_NAMESPACE
 
 DOMCI_DATA(BluetoothDevice, BluetoothDevice)
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(BluetoothDevice)
 
 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(BluetoothDevice,
@@ -43,24 +44,26 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(BluetoothDevice)
 NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetHelper)
 
 NS_IMPL_ADDREF_INHERITED(BluetoothDevice, nsDOMEventTargetHelper)
 NS_IMPL_RELEASE_INHERITED(BluetoothDevice, nsDOMEventTargetHelper)
 
 BluetoothDevice::BluetoothDevice(nsPIDOMWindow* aWindow,
                                  const nsAString& aAdapterPath,
-                                 const BluetoothValue& aValue) :
-  BluetoothPropertyContainer(BluetoothObjectType::TYPE_DEVICE),
-  mJsUuids(nullptr),
-  mJsServices(nullptr),
-  mAdapterPath(aAdapterPath),
-  mIsRooted(false)
+                                 const BluetoothValue& aValue)
+  : nsDOMEventTargetHelper(aWindow)
+  , BluetoothPropertyContainer(BluetoothObjectType::TYPE_DEVICE)
+  , mJsUuids(nullptr)
+  , mJsServices(nullptr)
+  , mAdapterPath(aAdapterPath)
+  , mIsRooted(false)
 {
   MOZ_ASSERT(aWindow);
+  MOZ_ASSERT(IsDOMBinding());
 
   BindToOwner(aWindow);
   const InfallibleTArray<BluetoothNamedValue>& values =
     aValue.get_ArrayOfBluetoothNamedValue();
   for (uint32_t i = 0; i < values.Length(); ++i) {
     SetPropertyByValue(values[i]);
   }
 
@@ -190,73 +193,37 @@ BluetoothDevice::Notify(const BluetoothS
     nsCString warningMsg;
     warningMsg.AssignLiteral("Not handling device signal: ");
     warningMsg.Append(NS_ConvertUTF16toUTF8(aData.name()));
     NS_WARNING(warningMsg.get());
 #endif
   }
 }
 
-NS_IMETHODIMP
-BluetoothDevice::GetAddress(nsAString& aAddress)
-{
-  aAddress = mAddress;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-BluetoothDevice::GetName(nsAString& aName)
+JS::Value
+BluetoothDevice::GetUuids(JSContext* aCx, ErrorResult& aRv)
 {
-  aName = mName;
-  return NS_OK;
-}
+  if (!mJsUuids) {
+    NS_WARNING("UUIDs not yet set!\n");
+    aRv.Throw(NS_ERROR_FAILURE);
+    return JS::NullValue();
+  }
 
-NS_IMETHODIMP
-BluetoothDevice::GetIcon(nsAString& aIcon)
-{
-  aIcon = mIcon;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-BluetoothDevice::GetDeviceClass(uint32_t* aClass)
-{
-  *aClass = mClass;
-  return NS_OK;
+  return JS::ObjectValue(*xpc_UnmarkGrayObject(mJsUuids));
 }
 
-NS_IMETHODIMP
-BluetoothDevice::GetPaired(bool* aPaired)
+JS::Value
+BluetoothDevice::GetServices(JSContext* aCx, ErrorResult& aRv)
 {
-  *aPaired = mPaired;
-  return NS_OK;
-}
+  if (!mJsServices) {
+    NS_WARNING("Services not yet set!\n");
+    aRv.Throw(NS_ERROR_FAILURE);
+    return JS::Value(JSVAL_NULL);
+  }
 
-NS_IMETHODIMP
-BluetoothDevice::GetConnected(bool* aConnected)
-{
-  *aConnected = mConnected;
-  return NS_OK;
+  return JS::ObjectValue(*xpc_UnmarkGrayObject(mJsServices));
 }
 
-NS_IMETHODIMP
-BluetoothDevice::GetUuids(JSContext* aCx, JS::Value* aUuids)
+JSObject*
+BluetoothDevice::WrapObject(JSContext* aContext, JS::Handle<JSObject*> aScope)
 {
-  if (mJsUuids) {
-    aUuids->setObject(*mJsUuids);
-  } else {
-    NS_WARNING("UUIDs not yet set!\n");
-    return NS_ERROR_FAILURE;
-  }
-  return NS_OK;
+  return BluetoothDeviceBinding::Wrap(aContext, aScope, this);
 }
-
-NS_IMETHODIMP
-BluetoothDevice::GetServices(JSContext* aCx, JS::Value* aServices)
-{
-  if (mJsServices) {
-    aServices->setObject(*mJsServices);
-  } else {
-    NS_WARNING("Services not yet set!\n");
-  }
-  return NS_OK;
-}
-
--- a/dom/bluetooth/BluetoothDevice.h
+++ b/dom/bluetooth/BluetoothDevice.h
@@ -38,25 +38,67 @@ public:
                                                          nsDOMEventTargetHelper)
 
   static already_AddRefed<BluetoothDevice>
   Create(nsPIDOMWindow* aOwner, const nsAString& aAdapterPath,
          const BluetoothValue& aValue);
 
   void Notify(const BluetoothSignal& aParam);
 
+  void GetAddress(nsString& aAddress) const
+  {
+    aAddress = mAddress;
+  }
+
+  void GetName(nsString& aName) const
+  {
+    aName = mName;
+  }
+
+  void GetIcon(nsString& aIcon) const
+  {
+    aIcon = mIcon;
+  }
+
+  uint32_t Class() const
+  {
+    return mClass;
+  }
+
+  bool Paired() const
+  {
+    return mPaired;
+  }
+
+  bool Connected() const
+  {
+    return mConnected;
+  }
+
+  JS::Value GetUuids(JSContext* aContext, ErrorResult& aRv);
+  JS::Value GetServices(JSContext* aContext, ErrorResult& aRv);
+
   nsISupports*
   ToISupports()
   {
     return static_cast<EventTarget*>(this);
   }
 
   void SetPropertyByValue(const BluetoothNamedValue& aValue) MOZ_OVERRIDE;
 
   void Unroot();
+
+  nsPIDOMWindow* GetParentObject() const
+  {
+     return GetOwner();
+  }
+
+  virtual JSObject*
+    WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
+
 private:
   BluetoothDevice(nsPIDOMWindow* aOwner, const nsAString& aAdapterPath,
                   const BluetoothValue& aValue);
   ~BluetoothDevice();
   void Root();
 
   JS::Heap<JSObject*> mJsUuids;
   JS::Heap<JSObject*> mJsServices;
--- a/dom/bluetooth/BluetoothManager.cpp
+++ b/dom/bluetooth/BluetoothManager.cpp
@@ -13,26 +13,24 @@
 
 #include "DOMRequest.h"
 #include "nsContentUtils.h"
 #include "nsDOMClassInfo.h"
 #include "nsIPermissionManager.h"
 #include "nsThreadUtils.h"
 #include "mozilla/Util.h"
 #include "mozilla/dom/bluetooth/BluetoothTypes.h"
+#include "mozilla/dom/BluetoothManagerBinding.h"
 
 using namespace mozilla;
 
 USING_BLUETOOTH_NAMESPACE
 
-DOMCI_DATA(BluetoothManager, BluetoothManager)
-
-NS_INTERFACE_MAP_BEGIN(BluetoothManager)
-  NS_INTERFACE_MAP_ENTRY(nsIDOMBluetoothManager)
-  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(BluetoothManager)
+// QueryInterface implementation for BluetoothManager
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(BluetoothManager)
 NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetHelper)
 
 NS_IMPL_ADDREF_INHERITED(BluetoothManager, nsDOMEventTargetHelper)
 NS_IMPL_RELEASE_INHERITED(BluetoothManager, nsDOMEventTargetHelper)
 
 class GetAdapterTask : public BluetoothReplyRunnable
 {
 public:
@@ -52,18 +50,18 @@ public:
     if (v.type() != BluetoothValue::TArrayOfBluetoothNamedValue) {
       NS_WARNING("Not a BluetoothNamedValue array!");
       SetError(NS_LITERAL_STRING("BluetoothReplyTypeError"));
       return false;
     }
 
     const InfallibleTArray<BluetoothNamedValue>& values =
       v.get_ArrayOfBluetoothNamedValue();
-    nsCOMPtr<nsIDOMBluetoothAdapter> adapter;
-    adapter = BluetoothAdapter::Create(mManagerPtr->GetOwner(), values);
+    nsRefPtr<BluetoothAdapter> adapter =
+      BluetoothAdapter::Create(mManagerPtr->GetOwner(), values);
 
     nsresult rv;
     nsIScriptContext* sc = mManagerPtr->GetContextForEventHandlers(&rv);
     if (!sc) {
       NS_WARNING("Cannot create script context!");
       SetError(NS_LITERAL_STRING("BluetoothScriptContextError"));
       return false;
     }
@@ -88,19 +86,21 @@ public:
     mManagerPtr = nullptr;
   }
 
 private:
   nsRefPtr<BluetoothManager> mManagerPtr;
 };
 
 BluetoothManager::BluetoothManager(nsPIDOMWindow *aWindow)
-  : BluetoothPropertyContainer(BluetoothObjectType::TYPE_MANAGER)
+  : nsDOMEventTargetHelper(aWindow)
+  , BluetoothPropertyContainer(BluetoothObjectType::TYPE_MANAGER)
 {
   MOZ_ASSERT(aWindow);
+  MOZ_ASSERT(IsDOMBinding());
 
   BindToOwner(aWindow);
   mPath.AssignLiteral("/");
 
   BluetoothService* bs = BluetoothService::Get();
   NS_ENSURE_TRUE_VOID(bs);
   bs->RegisterBluetoothSignalHandler(NS_LITERAL_STRING(KEY_MANAGER), this);
 }
@@ -119,47 +119,54 @@ BluetoothManager::SetPropertyByValue(con
     const nsString& name = aValue.name();
     nsCString warningMsg;
     warningMsg.AssignLiteral("Not handling manager property: ");
     warningMsg.Append(NS_ConvertUTF16toUTF8(name));
     NS_WARNING(warningMsg.get());
 #endif
 }
 
-NS_IMETHODIMP
-BluetoothManager::GetEnabled(bool* aEnabled)
+bool
+BluetoothManager::GetEnabled(ErrorResult& aRv)
 {
   BluetoothService* bs = BluetoothService::Get();
-  NS_ENSURE_TRUE(bs, NS_ERROR_FAILURE);
+  if (!bs) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return false;
+  }
 
-  *aEnabled = bs->IsEnabled();
-  return NS_OK;
+  return bs->IsEnabled();
 }
 
-NS_IMETHODIMP
-BluetoothManager::GetDefaultAdapter(nsIDOMDOMRequest** aAdapter)
+already_AddRefed<dom::DOMRequest>
+BluetoothManager::GetDefaultAdapter(ErrorResult& aRv)
 {
-  nsCOMPtr<nsIDOMRequestService> rs =
-    do_GetService(DOMREQUEST_SERVICE_CONTRACTID);
-  NS_ENSURE_TRUE(rs, NS_ERROR_FAILURE);
+  nsCOMPtr<nsPIDOMWindow> win = GetOwner();
+  if (!win) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
+  }
 
-  nsCOMPtr<nsIDOMDOMRequest> request;
-  nsresult rv = rs->CreateRequest(GetOwner(), getter_AddRefs(request));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  nsRefPtr<BluetoothReplyRunnable> results = new GetAdapterTask(this, request);
+  nsRefPtr<DOMRequest> request = new DOMRequest(win);
+  nsRefPtr<BluetoothReplyRunnable> results =
+    new GetAdapterTask(this, request);
 
   BluetoothService* bs = BluetoothService::Get();
-  NS_ENSURE_TRUE(bs, NS_ERROR_FAILURE);
-  if (NS_FAILED(bs->GetDefaultAdapterPathInternal(results))) {
-    return NS_ERROR_FAILURE;
+  if (!bs) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
   }
 
-  request.forget(aAdapter);
-  return NS_OK;
+  nsresult rv = bs->GetDefaultAdapterPathInternal(results);
+  if (NS_FAILED(rv)) {
+    aRv.Throw(rv);
+    return nullptr;
+  }
+
+  return request.forget();
 }
 
 // static
 already_AddRefed<BluetoothManager>
 BluetoothManager::Create(nsPIDOMWindow* aWindow)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aWindow);
@@ -203,24 +210,25 @@ BluetoothManager::Notify(const Bluetooth
     nsCString warningMsg;
     warningMsg.AssignLiteral("Not handling manager signal: ");
     warningMsg.Append(NS_ConvertUTF16toUTF8(aData.name()));
     NS_WARNING(warningMsg.get());
 #endif
   }
 }
 
-NS_IMETHODIMP
-BluetoothManager::IsConnected(uint16_t aProfileId, bool* aConnected)
+bool
+BluetoothManager::IsConnected(uint16_t aProfileId, ErrorResult& aRv)
 {
   BluetoothService* bs = BluetoothService::Get();
   if (!bs) {
-    NS_WARNING("BluetoothService not available!");
-    return NS_ERROR_FAILURE;
+    aRv.Throw(NS_ERROR_FAILURE);
+    return false;
   }
 
-  *aConnected = bs->IsConnected(aProfileId);
-  return NS_OK;
+  return bs->IsConnected(aProfileId);
 }
-NS_IMPL_EVENT_HANDLER(BluetoothManager, enabled)
-NS_IMPL_EVENT_HANDLER(BluetoothManager, disabled)
-NS_IMPL_EVENT_HANDLER(BluetoothManager, adapteradded)
 
+JSObject*
+BluetoothManager::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope)
+{
+  return BluetoothManagerBinding::Wrap(aCx, aScope, this);
+}
--- a/dom/bluetooth/BluetoothManager.h
+++ b/dom/bluetooth/BluetoothManager.h
@@ -6,40 +6,60 @@
 
 #ifndef mozilla_dom_bluetooth_bluetoothmanager_h__
 #define mozilla_dom_bluetooth_bluetoothmanager_h__
 
 #include "mozilla/Attributes.h"
 #include "BluetoothCommon.h"
 #include "BluetoothPropertyContainer.h"
 #include "nsDOMEventTargetHelper.h"
-#include "nsIDOMBluetoothManager.h"
 #include "mozilla/Observer.h"
+#include "nsISupportsImpl.h"
+
+namespace mozilla {
+namespace dom {
+class DOMRequest;
+}
+}
 
 BEGIN_BLUETOOTH_NAMESPACE
 
 class BluetoothNamedValue;
 
 class BluetoothManager : public nsDOMEventTargetHelper
-                       , public nsIDOMBluetoothManager
                        , public BluetoothSignalObserver
                        , public BluetoothPropertyContainer
 {
 public:
   NS_DECL_ISUPPORTS_INHERITED
-  NS_DECL_NSIDOMBLUETOOTHMANAGER
-
-  NS_REALLY_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper)
 
   // Never returns null
   static already_AddRefed<BluetoothManager>
     Create(nsPIDOMWindow* aWindow);
   static bool CheckPermission(nsPIDOMWindow* aWindow);
   void Notify(const BluetoothSignal& aData);
   virtual void SetPropertyByValue(const BluetoothNamedValue& aValue) MOZ_OVERRIDE;
+
+  bool GetEnabled(ErrorResult& aRv);
+  bool IsConnected(uint16_t aProfileId, ErrorResult& aRv);
+
+  already_AddRefed<DOMRequest> GetDefaultAdapter(ErrorResult& aRv);
+
+  IMPL_EVENT_HANDLER(enabled);
+  IMPL_EVENT_HANDLER(disabled);
+  IMPL_EVENT_HANDLER(adapteradded);
+
+  nsPIDOMWindow* GetParentObject() const
+  {
+     return GetOwner();
+  }
+
+  virtual JSObject*
+    WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
+
 private:
   BluetoothManager(nsPIDOMWindow* aWindow);
   ~BluetoothManager();
 };
 
 END_BLUETOOTH_NAMESPACE
 
 #endif
--- a/dom/bluetooth/BluetoothPropertyContainer.cpp
+++ b/dom/bluetooth/BluetoothPropertyContainer.cpp
@@ -3,62 +3,54 @@
 /* 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 "BluetoothPropertyContainer.h"
 #include "BluetoothService.h"
 #include "DOMRequest.h"
+#include "mozilla/ErrorResult.h"
 #include "mozilla/dom/bluetooth/BluetoothTypes.h"
 
 USING_BLUETOOTH_NAMESPACE
 
-nsresult
+already_AddRefed<mozilla::dom::DOMRequest>
 BluetoothPropertyContainer::FirePropertyAlreadySet(nsIDOMWindow* aOwner,
-                                                   nsIDOMDOMRequest** aRequest)
+                                                   ErrorResult& aRv)
 {
   nsCOMPtr<nsIDOMRequestService> rs =
     do_GetService(DOMREQUEST_SERVICE_CONTRACTID);
-  NS_ENSURE_TRUE(rs, NS_ERROR_FAILURE);
+  if (!rs) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
+  }
 
-  nsCOMPtr<nsIDOMDOMRequest> req;
-  nsresult rv = rs->CreateRequest(aOwner, getter_AddRefs(req));
-  if (NS_FAILED(rv)) {
-    NS_WARNING("Can't create DOMRequest!");
-    return NS_ERROR_FAILURE;
-  }
-  rs->FireSuccess(req, JSVAL_VOID);
-  req.forget(aRequest);
+  nsRefPtr<mozilla::dom::DOMRequest> request = new DOMRequest(aOwner);
+  rs->FireSuccess(request, JS::UndefinedValue());
 
-  return NS_OK;
+  return request.forget();
 }
 
-nsresult
+already_AddRefed<mozilla::dom::DOMRequest>
 BluetoothPropertyContainer::SetProperty(nsIDOMWindow* aOwner,
                                         const BluetoothNamedValue& aProperty,
-                                        nsIDOMDOMRequest** aRequest)
+                                        ErrorResult& aRv)
 {
+  nsRefPtr<mozilla::dom::DOMRequest> request = new DOMRequest(aOwner);
+  nsRefPtr<BluetoothReplyRunnable> task =
+    new BluetoothVoidReplyRunnable(request);
+
   BluetoothService* bs = BluetoothService::Get();
   if (!bs) {
     NS_WARNING("Bluetooth service not available!");
-    return NS_ERROR_FAILURE;
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
   }
 
-  nsCOMPtr<nsIDOMRequestService> rs =
-    do_GetService(DOMREQUEST_SERVICE_CONTRACTID);
-  NS_ENSURE_TRUE(rs, NS_ERROR_FAILURE);
-
-  nsCOMPtr<nsIDOMDOMRequest> req;
-  nsresult rv = rs->CreateRequest(aOwner, getter_AddRefs(req));
+  nsresult rv = bs->SetProperty(mObjectType, aProperty, task);
   if (NS_FAILED(rv)) {
-    NS_WARNING("Can't create DOMRequest!");
-    return NS_ERROR_FAILURE;
+    aRv.Throw(rv);
+    return nullptr;
   }
 
-  nsRefPtr<BluetoothReplyRunnable> task = new BluetoothVoidReplyRunnable(req);
-
-  rv = bs->SetProperty(mObjectType, aProperty, task);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  req.forget(aRequest);
-  return NS_OK;
+  return request.forget();
 }
--- a/dom/bluetooth/BluetoothPropertyContainer.h
+++ b/dom/bluetooth/BluetoothPropertyContainer.h
@@ -8,28 +8,35 @@
 #define mozilla_dom_bluetooth_bluetoothpropertyobject_h__
 
 #include "BluetoothCommon.h"
 #include "BluetoothReplyRunnable.h"
 
 class nsIDOMDOMRequest;
 class nsIDOMWindow;
 
+namespace mozilla {
+class ErrorResult;
+namespace dom {
+class DOMRequest;
+}
+}
+
 BEGIN_BLUETOOTH_NAMESPACE
 
 class BluetoothNamedValue;
 
 class BluetoothPropertyContainer
 {
 public:
-  nsresult FirePropertyAlreadySet(nsIDOMWindow* aOwner,
-                                  nsIDOMDOMRequest** aRequest);
-  nsresult SetProperty(nsIDOMWindow* aOwner,
-                       const BluetoothNamedValue& aProperty,
-                       nsIDOMDOMRequest** aRequest);
+  already_AddRefed<mozilla::dom::DOMRequest>
+    FirePropertyAlreadySet(nsIDOMWindow* aOwner, ErrorResult& aRv);
+  already_AddRefed<mozilla::dom::DOMRequest>
+    SetProperty(nsIDOMWindow* aOwner, const BluetoothNamedValue& aProperty,
+                ErrorResult& aRv);
   virtual void SetPropertyByValue(const BluetoothNamedValue& aValue) = 0;
   nsString GetPath()
   {
     return mPath;
   }
 
   // Compatibility with nsRefPtr to make sure we don't hold a weakptr to
   // ourselves
deleted file mode 100644
--- a/dom/bluetooth/MediaMetaData.cpp
+++ /dev/null
@@ -1,83 +0,0 @@
-/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
-/* vim: set ts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/ */
-
-#include "BluetoothCommon.h"
-#include "MediaMetaData.h"
-
-#include "nsCxPusher.h"
-#include "nsContentUtils.h"
-#include "nsJSUtils.h"
-#include "nsThreadUtils.h"
-
-using namespace mozilla;
-USING_BLUETOOTH_NAMESPACE
-
-MediaMetaData::MediaMetaData() : mDuration(-1)
-                               , mMediaNumber(-1)
-                               , mTotalMediaCount(-1)
-{
-}
-
-nsresult
-MediaMetaData::Init(JSContext* aCx, const jsval* aVal)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-
-  if (!aCx || !aVal) {
-    return NS_OK;
-  }
-
-  if (!aVal->isObject()) {
-    return aVal->isNullOrUndefined() ? NS_OK : NS_ERROR_TYPE_ERR;
-  }
-
-  JS::RootedObject obj(aCx, &aVal->toObject());
-  nsCxPusher pusher;
-  pusher.Push(aCx);
-  JSAutoCompartment ac(aCx, obj);
-
-  JS::Rooted<JS::Value> value(aCx);
-  NS_ENSURE_STATE(JS_GetProperty(aCx, obj, "mAlbum", &value));
-  if (JSVAL_IS_STRING(value)) {
-    nsDependentJSString jsString;
-    NS_ENSURE_STATE(jsString.init(aCx, value.toString()));
-    mAlbum = jsString;
-  }
-
-  NS_ENSURE_STATE(JS_GetProperty(aCx, obj, "mArtist", &value));
-  if (JSVAL_IS_STRING(value)) {
-    nsDependentJSString jsString;
-    NS_ENSURE_STATE(JSVAL_IS_STRING(value));
-    NS_ENSURE_STATE(jsString.init(aCx, value.toString()));
-    mArtist = jsString;
-  }
-
-  NS_ENSURE_STATE(JS_GetProperty(aCx, obj, "mDuration", &value));
-  if (JSVAL_IS_INT(value)) {
-    NS_ENSURE_STATE(JS_ValueToInt64(aCx, value, &mDuration));
-  }
-
-  NS_ENSURE_STATE(JS_GetProperty(aCx, obj, "mMediaNumber", &value));
-  if (JSVAL_IS_INT(value)) {
-    NS_ENSURE_STATE(JS_ValueToInt64(aCx, value, &mMediaNumber));
-  }
-
-  NS_ENSURE_STATE(JS_GetProperty(aCx, obj, "mTitle", &value));
-  if (JSVAL_IS_STRING(value)) {
-    nsDependentJSString jsString;
-    NS_ENSURE_STATE(JSVAL_IS_STRING(value));
-    NS_ENSURE_STATE(jsString.init(aCx, value.toString()));
-    mTitle = jsString;
-  }
-
-  NS_ENSURE_STATE(JS_GetProperty(aCx, obj, "mTotalMediaCount", &value));
-  if (JSVAL_IS_INT(value)) {
-    NS_ENSURE_STATE(JS_ValueToInt64(aCx, value, &mTotalMediaCount));
-  }
-
-  return NS_OK;
-}
-
deleted file mode 100644
--- a/dom/bluetooth/MediaMetaData.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
-/* vim: set ts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef mozilla_dom_bluetooth_mediametadata_h__
-#define mozilla_dom_bluetooth_mediametadata_h__
-
-#include "jsapi.h"
-#include "nsString.h"
-
-BEGIN_BLUETOOTH_NAMESPACE
-
-class MediaMetaData
-{
-public:
-  MediaMetaData();
-
-  nsresult Init(JSContext* aCx, const jsval* aVal);
-
-  nsString mAlbum;
-  nsString mArtist;
-  int64_t mDuration;
-  int64_t mMediaNumber;
-  nsString mTitle;
-  int64_t mTotalMediaCount;
-};
-
-END_BLUETOOTH_NAMESPACE
-
-#endif
deleted file mode 100644
--- a/dom/bluetooth/MediaPlayStatus.cpp
+++ /dev/null
@@ -1,62 +0,0 @@
-/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
-/* vim: set ts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/ */
-
-#include "BluetoothCommon.h"
-#include "MediaPlayStatus.h"
-
-#include "nsContentUtils.h"
-#include "nsCxPusher.h"
-#include "nsJSUtils.h"
-#include "nsThreadUtils.h"
-
-using namespace mozilla;
-USING_BLUETOOTH_NAMESPACE
-
-MediaPlayStatus::MediaPlayStatus() : mDuration(-1)
-                                     , mPosition(-1)
-{
-}
-
-nsresult
-MediaPlayStatus::Init(JSContext* aCx, const jsval* aVal)
-{
-  MOZ_ASSERT(NS_IsMainThread());
-
-  if (!aCx || !aVal) {
-    return NS_OK;
-  }
-
-  if (!aVal->isObject()) {
-    return aVal->isNullOrUndefined() ? NS_OK : NS_ERROR_TYPE_ERR;
-  }
-
-  JS::RootedObject obj(aCx, &aVal->toObject());
-  nsCxPusher pusher;
-  pusher.Push(aCx);
-  JSAutoCompartment ac(aCx, obj);
-
-  JS::Rooted<JS::Value> value(aCx);
-  NS_ENSURE_STATE(JS_GetProperty(aCx, obj, "mDuration", &value));
-  if (JSVAL_IS_INT(value)) {
-    NS_ENSURE_STATE(JS_ValueToInt64(aCx, value, &mDuration));
-  }
-
-  NS_ENSURE_STATE(JS_GetProperty(aCx, obj, "mPlayStatus", &value));
-  if (JSVAL_IS_STRING(value)) {
-    nsDependentJSString jsString;
-    NS_ENSURE_STATE(JSVAL_IS_STRING(value));
-    NS_ENSURE_STATE(jsString.init(aCx, value.toString()));
-    mPlayStatus = jsString;
-  }
-
-  NS_ENSURE_STATE(JS_GetProperty(aCx, obj, "mPosition", &value));
-  if (JSVAL_IS_INT(value)) {
-    NS_ENSURE_STATE(JS_ValueToInt64(aCx, value, &mPosition));
-  }
-
-  return NS_OK;
-}
-
deleted file mode 100644
--- a/dom/bluetooth/MediaPlayStatus.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
-/* vim: set ts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef mozilla_dom_bluetooth_mediaplaystatus_h__
-#define mozilla_dom_bluetooth_mediaplaystatus_h__
-
-#include "jsapi.h"
-#include "nsString.h"
-
-BEGIN_BLUETOOTH_NAMESPACE
-
-class MediaPlayStatus
-{
-public:
-  MediaPlayStatus();
-
-  nsresult Init(JSContext* aCx, const jsval* aVal);
-
-  int64_t mDuration;
-  nsString mPlayStatus;
-  int64_t mPosition;
-};
-
-END_BLUETOOTH_NAMESPACE
-
-#endif
--- a/dom/bluetooth/linux/BluetoothDBusService.cpp
+++ b/dom/bluetooth/linux/BluetoothDBusService.cpp
@@ -1282,17 +1282,17 @@ public:
     };
 
     MOZ_ASSERT(NS_IsMainThread());
 
     nsRefPtr<RawDBusConnection> threadConnection = gThreadConnection;
 
     if (!threadConnection.get()) {
       BT_WARNING("%s: DBus connection has been closed.", __FUNCTION__);
-      return false;
+      return NS_ERROR_FAILURE;
     }
 
     sAdapterPath = mAdapterPath;
 
     nsRefPtr<DBusReplyHandler> handler =
       new AddReservedServiceRecordsReplyHandler();
 
     const dbus_uint32_t* services = sServices;
--- a/dom/bluetooth/moz.build
+++ b/dom/bluetooth/moz.build
@@ -13,20 +13,18 @@
 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
 if CONFIG['MOZ_B2G_BT']:
     MODULE = 'dom'
     XPIDL_MODULE = 'dom_bluetooth'
     XPIDL_SOURCES += [
-        'nsIDOMBluetoothAdapter.idl',
         'nsIDOMBluetoothDevice.idl',
         'nsIDOMBluetoothDeviceEvent.idl',
-        'nsIDOMBluetoothManager.idl',
         'nsIDOMBluetoothStatusChangedEvent.idl',
     ]
 
     CPP_SOURCES += [
         'BluetoothService.cpp',
         'BluetoothManager.cpp',
         'BluetoothAdapter.cpp',
         'BluetoothDevice.cpp',
@@ -38,18 +36,16 @@ if CONFIG['MOZ_B2G_BT']:
         'BluetoothServiceChildProcess.cpp',
         'BluetoothUnixSocketConnector.cpp',
         'BluetoothA2dpManager.cpp',
         'BluetoothHfpManager.cpp',
         'BluetoothOppManager.cpp',
         'ObexBase.cpp',
         'BluetoothUuid.cpp',
         'BluetoothSocket.cpp',
-        'MediaMetaData.cpp',
-        'MediaPlayStatus.cpp'
     ]
 
     if CONFIG['MOZ_B2G_RIL']:
         CPP_SOURCES += [
             'BluetoothTelephonyListener.cpp',
         ]
 
     if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
deleted file mode 100644
--- a/dom/bluetooth/nsIDOMBluetoothAdapter.idl
+++ /dev/null
@@ -1,117 +0,0 @@
-/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
-/* vim: set ts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "nsIDOMEventTarget.idl"
-
-/**
- * MediaMetadata and MediaPlayStatus are used to keep data from Applications.
- * Please see specification of AVRCP 1.3 for more details.
- *
- * @title:           track title
- * @artist:          artist name
- * @album:           album name
- * @mediaNumber:     track number
- * @totalMediaCount: number of tracks in the album
- * @duration:        playing time (ms)
- */
-dictionary MediaMetaData
-{
-  DOMString  title;
-  DOMString  artist;
-  DOMString  album;
-  unsigned long  mediaNumber;
-  unsigned long  totalMediaCount;
-  unsigned long  duration;
-};
-
-/**
- * @duration:   current track length (ms)
- * @position:   playing time (ms)
- * @playStatus: STOPPED/PLAYING/PAUSED/FWD_SEEK/REV_SEEK/ERROR
- */
-dictionary MediaPlayStatus
-{
-  unsigned long  duration;
-  unsigned long  position;
-  DOMString  playStatus;
-};
-
-interface nsIDOMDOMRequest;
-interface nsIDOMBlob;
-interface nsIDOMBluetoothDevice;
-
-[scriptable, builtinclass, uuid(54bf9aa2-1208-47ab-ac96-c7df349fcf0e)]
-interface nsIDOMBluetoothAdapter : nsIDOMEventTarget
-{
-  readonly attribute DOMString address;
-  [binaryname(AdapterClass)] readonly attribute unsigned long class;
-  readonly attribute bool discovering;
-
-  [implicit_jscontext]
-  readonly attribute jsval devices;
-
-  [implicit_jscontext]
-  readonly attribute jsval uuids;
-  
-  readonly attribute DOMString name;
-  readonly attribute bool discoverable;
-  // Unit: sec
-  readonly attribute unsigned long discoverableTimeout;
-
-  nsIDOMDOMRequest setName(in DOMString name);
-  nsIDOMDOMRequest setDiscoverable(in bool discoverable);
-  nsIDOMDOMRequest setDiscoverableTimeout(in unsigned long timeout);
-  nsIDOMDOMRequest startDiscovery();
-  nsIDOMDOMRequest stopDiscovery();
-  nsIDOMDOMRequest pair(in nsIDOMBluetoothDevice aDevice);
-  nsIDOMDOMRequest unpair(in nsIDOMBluetoothDevice aDevice);
-  nsIDOMDOMRequest getPairedDevices();
-  nsIDOMDOMRequest getConnectedDevices(in unsigned short aProfile);
-  nsIDOMDOMRequest setPinCode(in DOMString aDeviceAddress, in DOMString aPinCode);
-  nsIDOMDOMRequest setPasskey(in DOMString aDeviceAddress, in unsigned long aPasskey);
-  nsIDOMDOMRequest setPairingConfirmation(in DOMString aDeviceAddress, in bool aConfirmation);
-  nsIDOMDOMRequest setAuthorization(in DOMString aDeviceAddress, in bool aAllow);
-
-  /** 
-   * Connect/Disconnect to a specific service of a target remote device. 
-   * To check the value of service UUIDs, please check "Bluetooth Assigned 
-   * Numbers" / "Service Discovery Protocol" for more information.
-   *  
-   * @param aDeviceAddress Remote device address
-   * @param aProfile 2-octets service UUID
-   */
-  nsIDOMDOMRequest connect(in DOMString aDeviceAddress, in unsigned short aProfile);
-  nsIDOMDOMRequest disconnect(in unsigned short aProfile);
-
-  // One device can only send one file at a time
-  nsIDOMDOMRequest sendFile(in DOMString aDeviceAddress, in nsIDOMBlob aBlob);
-  nsIDOMDOMRequest stopSendingFile(in DOMString aDeviceAddress);
-  nsIDOMDOMRequest confirmReceivingFile(in DOMString aDeviceAddress, in bool aConfirmation);
-
-  // AVRCP 1.3 methods
-  nsIDOMDOMRequest sendMediaMetaData(in jsval aOptions);
-  nsIDOMDOMRequest sendMediaPlayStatus(in jsval aOptions);
-
-  // Connect/Disconnect SCO (audio) connection
-  nsIDOMDOMRequest connectSco();
-  nsIDOMDOMRequest disconnectSco();
-  nsIDOMDOMRequest isScoConnected();
-
-  // Fired when discoverying and any device is discovered.
-  [implicit_jscontext] attribute jsval ondevicefound;
-
-  // Fired when pairing process is completed
-  [implicit_jscontext] attribute jsval onpairedstatuschanged;
-
-  // Fired when a2dp connection status changed
-  [implicit_jscontext] attribute jsval ona2dpstatuschanged;
-
-  // Fired when handsfree connection status changed
-  [implicit_jscontext] attribute jsval onhfpstatuschanged;
-
-  // Fired when sco connection status changed
-  [implicit_jscontext] attribute jsval onscostatuschanged;
-};
--- a/dom/bluetooth/nsIDOMBluetoothDevice.idl
+++ b/dom/bluetooth/nsIDOMBluetoothDevice.idl
@@ -1,20 +1,14 @@
 /* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsIDOMEventTarget.idl"
 
-[scriptable, builtinclass, uuid(7297ef65-db38-45f1-a5dc-b7347aaa223d)]
+// XPIDL interfaces might need this definition; so we keep it in place
+// until we completely switched to WebIDL. See bug 900904.
+[scriptable, builtinclass, uuid(291fdda9-4f96-4f2f-857f-900f89fb0412)]
 interface nsIDOMBluetoothDevice : nsIDOMEventTarget
 {
-  readonly attribute DOMString address;
-  readonly attribute DOMString name;
-  readonly attribute DOMString icon;
-  [binaryname(DeviceClass)] readonly attribute unsigned long class;
-  [implicit_jscontext] readonly attribute jsval uuids;
-  [implicit_jscontext] readonly attribute jsval services;
-  readonly attribute bool connected;
-  readonly attribute bool paired;
 };
deleted file mode 100644
--- a/dom/bluetooth/nsIDOMBluetoothManager.idl
+++ /dev/null
@@ -1,24 +0,0 @@
-/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
-/* vim: set ts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "nsIDOMEventTarget.idl"
-
-interface nsIDOMDOMRequest;
-interface nsIDOMBluetoothAdapter;
-
-[scriptable, builtinclass, uuid(303a262a-1dd1-486d-a108-d8c582e86765)]
-interface nsIDOMBluetoothManager : nsIDOMEventTarget
-{
-  readonly attribute bool enabled;
-
-  nsIDOMDOMRequest getDefaultAdapter();
-
-  bool isConnected(in unsigned short aProfile);
-
-  [implicit_jscontext] attribute jsval onenabled;
-  [implicit_jscontext] attribute jsval ondisabled;
-  [implicit_jscontext] attribute jsval onadapteradded;
-};
--- a/dom/icc/tests/marionette/test_icc_contact.js
+++ b/dom/icc/tests/marionette/test_icc_contact.js
@@ -36,17 +36,18 @@ function testReadContacts(type) {
   };
 };
 
 function testAddContact(type, pin2) {
   let contact = new mozContact();
 
   contact.init({
     name: "add",
-    tel: [{value: "0912345678"}]
+    tel: [{value: "0912345678"}],
+    email:[]
   });
 
   let updateRequest = icc.updateContact(type, contact, pin2);
 
   updateRequest.onsuccess = function onsuccess() {
     // Get ICC contact for checking new contact
 
     let getRequest = icc.readContacts(type);
--- a/dom/permission/tests/test_bluetooth.html
+++ b/dom/permission/tests/test_bluetooth.html
@@ -15,16 +15,16 @@ https://bugzilla.mozilla.org/show_bug.cg
 <div id="content" style="display: none"></div>
 <pre id="test">
 <script type="application/javascript;version=1.8" src="file_framework.js"></script>
 <script type="application/javascript;version=1.8">
 var gData = [
   {
     perm: ["bluetooth"],
     obj: "mozBluetooth",
-    idl: "nsIDOMBluetoothManager",
+    webidl: "BluetoothManager",
   },
 ]
 </script>
 </pre>
 </body>
 </html>
 
--- a/dom/phonenumberutils/PhoneNumber.jsm
+++ b/dom/phonenumberutils/PhoneNumber.jsm
@@ -4,29 +4,28 @@
 // Don't modify this code. Please use:
 // https://github.com/andreasgal/PhoneNumber.js
 
 "use strict";
 
 this.EXPORTED_SYMBOLS = ["PhoneNumber"];
 
 Components.utils.import("resource://gre/modules/PhoneNumberMetaData.jsm");
+Components.utils.import("resource://gre/modules/PhoneNumberNormalizer.jsm");
 
 this.PhoneNumber = (function (dataBase) {
   // Use strict in our context only - users might not want it
   'use strict';
 
   const MAX_PHONE_NUMBER_LENGTH = 50;
-  const UNICODE_DIGITS = /[\uFF10-\uFF19\u0660-\u0669\u06F0-\u06F9]/g;
   const NON_ALPHA_CHARS = /[^a-zA-Z]/g;
   const NON_DIALABLE_CHARS = /[^,#+\*\d]/g;
   const NON_DIALABLE_CHARS_ONCE = new RegExp(NON_DIALABLE_CHARS.source);
   const BACKSLASH = /\\/g;
   const SPLIT_FIRST_GROUP = /^(\d+)(.*)$/;
-  const VALID_ALPHA_PATTERN = /[a-zA-Z]/g;
   const LEADING_PLUS_CHARS_PATTERN = /^[+\uFF0B]+/g;
 
   // Format of the string encoded meta data. If the name contains "^" or "$"
   // we will generate a regular expression from the value, with those special
   // characters as prefix/suffix.
   const META_DATA_ENCODING = ["region",
                               "^(?:internationalPrefix)",
                               "nationalPrefix",
@@ -220,50 +219,16 @@ this.PhoneNumber = (function (dataBase) 
     get internationalNumber() {
       var value = this.internationalFormat ? this.internationalFormat.replace(NON_DIALABLE_CHARS, "")
                                            : null;
       Object.defineProperty(this, "internationalNumber", { value: value, enumerable: true });
       return value;
     }
   };
 
-  // Map letters to numbers according to the ITU E.161 standard
-  var E161 = {
-    'a': 2, 'b': 2, 'c': 2,
-    'd': 3, 'e': 3, 'f': 3,
-    'g': 4, 'h': 4, 'i': 4,
-    'j': 5, 'k': 5, 'l': 5,
-    'm': 6, 'n': 6, 'o': 6,
-    'p': 7, 'q': 7, 'r': 7, 's': 7,
-    't': 8, 'u': 8, 'v': 8,
-    'w': 9, 'x': 9, 'y': 9, 'z': 9
-  };
-
-  // Normalize a number by converting unicode numbers and symbols to their
-  // ASCII equivalents and removing all non-dialable characters.
-  function NormalizeNumber(number, numbersOnly) {
-    if (typeof number !== 'string') {
-      return '';
-    }
-
-    number = number.replace(UNICODE_DIGITS,
-                            function (ch) {
-                              return String.fromCharCode(48 + (ch.charCodeAt(0) & 0xf));
-                            });
-    if (!numbersOnly) {
-      number = number.replace(VALID_ALPHA_PATTERN,
-                              function (ch) {
-                                return String(E161[ch.toLowerCase()] || 0);
-                              });
-    }
-    number = number.replace(LEADING_PLUS_CHARS_PATTERN, "+");
-    number = number.replace(NON_DIALABLE_CHARS, "");
-    return number;
-  }
-
   // Check whether the number is valid for the given region.
   function IsValidNumber(number, md) {
     return md.possiblePattern.test(number);
   }
 
   // Check whether the number is a valid national number for the given region.
   function IsNationalNumber(number, md) {
     return IsValidNumber(number, md) && md.nationalPattern.test(number);
@@ -324,17 +289,17 @@ this.PhoneNumber = (function (dataBase) 
   }
 
   // Parse a number and transform it into the national format, removing any
   // international dial prefixes and country codes.
   function ParseNumber(number, defaultRegion) {
     var ret;
 
     // Remove formating characters and whitespace.
-    number = NormalizeNumber(number);
+    number = PhoneNumberNormalizer.Normalize(number);
 
     // If there is no defaultRegion, we can't parse international access codes.
     if (!defaultRegion && number[0] !== '+')
       return null;
 
     // Detect and strip leading '+'.
     if (number[0] === '+')
       return ParseInternationalNumber(number.replace(LEADING_PLUS_CHARS_PATTERN, ""));
@@ -399,11 +364,10 @@ this.PhoneNumber = (function (dataBase) 
     var isTooLong = (length > MAX_PHONE_NUMBER_LENGTH);
     var isEmpty = (length === 0);
     return !(isTooLong || isEmpty || NON_DIALABLE_CHARS_ONCE.test(number));
   }
 
   return {
     IsPlain: IsPlainPhoneNumber,
     Parse: ParseNumber,
-    Normalize: NormalizeNumber
   };
 })(PHONE_NUMBER_META_DATA);
new file mode 100644
--- /dev/null
+++ b/dom/phonenumberutils/PhoneNumberNormalizer.jsm
@@ -0,0 +1,55 @@
+/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
+
+// Don't modify this code. Please use:
+// https://github.com/andreasgal/PhoneNumber.js
+
+"use strict";
+
+this.EXPORTED_SYMBOLS = ["PhoneNumberNormalizer"];
+
+this.PhoneNumberNormalizer = (function() {
+  const UNICODE_DIGITS = /[\uFF10-\uFF19\u0660-\u0669\u06F0-\u06F9]/g;
+  const VALID_ALPHA_PATTERN = /[a-zA-Z]/g;
+  const LEADING_PLUS_CHARS_PATTERN = /^[+\uFF0B]+/g;
+  const NON_DIALABLE_CHARS = /[^,#+\*\d]/g;
+
+  // Map letters to numbers according to the ITU E.161 standard
+  var E161 = {
+    'a': 2, 'b': 2, 'c': 2,
+    'd': 3, 'e': 3, 'f': 3,
+    'g': 4, 'h': 4, 'i': 4,
+    'j': 5, 'k': 5, 'l': 5,
+    'm': 6, 'n': 6, 'o': 6,
+    'p': 7, 'q': 7, 'r': 7, 's': 7,
+    't': 8, 'u': 8, 'v': 8,
+    'w': 9, 'x': 9, 'y': 9, 'z': 9
+  };
+
+  // Normalize a number by converting unicode numbers and symbols to their
+  // ASCII equivalents and removing all non-dialable characters.
+  function NormalizeNumber(number, numbersOnly) {
+    if (typeof number !== 'string') {
+      return '';
+    }
+
+    number = number.replace(UNICODE_DIGITS,
+                            function (ch) {
+                              return String.fromCharCode(48 + (ch.charCodeAt(0) & 0xf));
+                            });
+    if (!numbersOnly) {
+      number = number.replace(VALID_ALPHA_PATTERN,
+                              function (ch) {
+                                return String(E161[ch.toLowerCase()] || 0);
+                              });
+    }
+    number = number.replace(LEADING_PLUS_CHARS_PATTERN, "+");
+    number = number.replace(NON_DIALABLE_CHARS, "");
+    return number;
+  };
+
+
+  return {
+    Normalize: NormalizeNumber
+  };
+})();
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/dom/phonenumberutils/PhoneNumberService.js
@@ -0,0 +1,97 @@
+/* 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/. */
+
+"use strict";
+
+const DEBUG = false;
+function debug(s) { dump("-*- PhoneNumberService.js: " + s + "\n"); }
+
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+const Cu = Components.utils;
+
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/DOMRequestHelper.jsm");
+Cu.import("resource://gre/modules/PhoneNumberUtils.jsm");
+Cu.import("resource://gre/modules/PhoneNumberNormalizer.jsm");
+
+XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
+                                   "@mozilla.org/childprocessmessagemanager;1",
+                                   "nsIMessageSender");
+
+// PhoneNumberService
+
+function PhoneNumberService()
+{
+  if (DEBUG) debug("Constructor");
+}
+
+PhoneNumberService.prototype = {
+  __proto__: DOMRequestIpcHelper.prototype,
+
+  receiveMessage: function(aMessage) {
+    if (DEBUG) debug("receiveMessage: " + aMessage.name);
+    let msg = aMessage.json;
+
+    let req = this.getRequest(msg.requestID);
+    if (!req) {
+      return;
+    }
+
+    switch (aMessage.name) {
+      case "PhoneNumberService:FuzzyMatch:Return:KO":
+        Services.DOMRequest.fireError(req.request, msg.errorMsg);
+        break;
+      case "PhoneNumberService:FuzzyMatch:Return:OK":
+        Services.DOMRequest.fireSuccess(req.request, msg.result);
+        break;
+      default:
+        if (DEBUG) debug("Wrong message: " + aMessage.name);
+    }
+    this.removeRequest(msg.requestID);
+  },
+
+  fuzzyMatch: function(aNumber1, aNumber2) {
+    if (DEBUG) debug("fuzzyMatch: " + aNumber1 + ", " + aNumber2);
+    let request = this.createRequest();
+
+    if ((aNumber1 && !aNumber2) || (aNumber2 && !aNumber1)) {
+      // if only one of the numbers is empty/null/undefined and the other
+      // number is not, we can fire false result in next tick
+      Services.DOMRequest.fireSuccessAsync(request, false);
+    } else if ((aNumber1 === aNumber2) ||
+        (PhoneNumberNormalizer.Normalize(aNumber1) === PhoneNumberNormalizer.Normalize(aNumber2))) {
+      // if we have a simple match fire successful request in next tick
+      Services.DOMRequest.fireSuccessAsync(request, true);
+    } else {
+      // invoke fuzzy matching in the parent
+      let options = { number1: aNumber1, number2: aNumber2 };
+      cpmm.sendAsyncMessage("PhoneNumberService:FuzzyMatch",
+                           {requestID: this.getRequestId({request: request}),
+                            options: options});
+    }
+
+    return request;
+  },
+
+  normalize: function(aNumber) {
+    if (DEBUG) debug("normalize: " + aNumber);
+    return PhoneNumberNormalizer.Normalize(aNumber);
+  },
+
+  init: function(aWindow) {
+    if (DEBUG) debug("init call");
+    this.initDOMRequestHelper(aWindow, [
+      "PhoneNumberService:FuzzyMatch:Return:OK",
+      "PhoneNumberService:FuzzyMatch:Return:KO"
+    ]);
+  },
+
+  classID : Components.ID("{e2768710-eb17-11e2-91e2-0800200c9a66}"),
+  contractID : "@mozilla.org/phoneNumberService;1",
+  QueryInterface : XPCOMUtils.generateQI([Ci.nsIDOMGlobalPropertyInitializer]),
+}
+
+this.NSGetFactory = XPCOMUtils.generateNSGetFactory([PhoneNumberService]);
new file mode 100644
--- /dev/null
+++ b/dom/phonenumberutils/PhoneNumberService.manifest
@@ -0,0 +1,2 @@
+component {e2768710-eb17-11e2-91e2-0800200c9a66} PhoneNumberService.js
+contract @mozilla.org/phoneNumberService;1 {e2768710-eb17-11e2-91e2-0800200c9a66}
\ No newline at end of file
--- a/dom/phonenumberutils/PhoneNumberUtils.jsm
+++ b/dom/phonenumberutils/PhoneNumberUtils.jsm
@@ -4,29 +4,34 @@
 "use strict";
 
 this.EXPORTED_SYMBOLS = ["PhoneNumberUtils"];
 
 const DEBUG = false;
 function debug(s) { if(DEBUG) dump("-*- PhoneNumberutils: " + s + "\n"); }
 
 const Cu = Components.utils;
+const Cc = Components.classes;
+const Ci = Components.interfaces;
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import('resource://gre/modules/XPCOMUtils.jsm');
-Cu.import("resource://gre/modules/PhoneNumber.jsm");
+Cu.import("resource://gre/modules/PhoneNumberNormalizer.jsm");
 Cu.import("resource://gre/modules/mcc_iso3166_table.jsm");
 
 #ifdef MOZ_B2G_RIL
 XPCOMUtils.defineLazyServiceGetter(this, "mobileConnection",
                                    "@mozilla.org/ril/content-helper;1",
                                    "nsIMobileConnectionProvider");
 #endif
 
 this.PhoneNumberUtils = {
+  init: function() {
+    ppmm.addMessageListener(["PhoneNumberService:FuzzyMatch"], this);
+  },
   //  1. See whether we have a network mcc
   //  2. If we don't have that, look for the simcard mcc
   //  3. If we don't have that or its 0 (not activated), pick up the last used mcc
   //  4. If we don't have, default to some mcc
 
   // mcc for Brasil
   _mcc: '724',
 
@@ -91,13 +96,67 @@ this.PhoneNumberUtils = {
 
   isPlainPhoneNumber: function isPlainPhoneNumber(aNumber) {
     var isPlain = PhoneNumber.IsPlain(aNumber);
     if (DEBUG) debug("isPlain(" + aNumber + ") " + isPlain);
     return isPlain;
   },
 
   normalize: function Normalize(aNumber, aNumbersOnly) {
-    var normalized = PhoneNumber.Normalize(aNumber, aNumbersOnly);
+    let normalized = PhoneNumberNormalizer.Normalize(aNumber, aNumbersOnly);
     if (DEBUG) debug("normalize(" + aNumber + "): " + normalized + ", " + aNumbersOnly);
     return normalized;
+  },
+
+  fuzzyMatch: function fuzzyMatch(aNumber1, aNumber2) {
+    let normalized1 = this.normalize(aNumber1);
+    let normalized2 = this.normalize(aNumber2);
+    if (DEBUG) debug("Normalized Number1: " + normalized1 + ", Number2: " + normalized2);
+    if (normalized1 === normalized2) {
+      return true;
+    }
+    let parsed1 = this.parse(aNumber1);
+    let parsed2 = this.parse(aNumber2);
+    if (parsed1 && parsed2) {
+      if (parsed1.internationalNumber === parsed2.internationalNumber
+          || parsed1.nationalNumber === parsed2.nationalNumber) {
+        return true;
+      }
+    }
+    let countryName = this.getCountryName();
+    let ssPref = "dom.phonenumber.substringmatching." + countryName;
+    if (Services.prefs.getPrefType(ssPref) == Ci.nsIPrefBranch.PREF_INT) {
+      let val = Services.prefs.getIntPref(ssPref);
+      if (normalized1.slice(-val) === normalized2.slice(-val)) {
+        return true;
+      }
+    }
+    return false;
+  },
+
+  receiveMessage: function(aMessage) {
+    if (DEBUG) debug("receiveMessage " + aMessage.name);
+    let mm = aMessage.target;
+    let msg = aMessage.data;
+
+    switch (aMessage.name) {
+      case "PhoneNumberService:FuzzyMatch":
+        mm.sendAsyncMessage("PhoneNumberService:FuzzyMatch:Return:OK", {
+          requestID: msg.requestID,
+          result: this.fuzzyMatch(msg.options.number1, msg.options.number2)
+        });
+        break;
+      default:
+        if (DEBUG) debug("WRONG MESSAGE NAME: " + aMessage.name);
+    }
   }
 };
+
+let inParent = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime)
+                 .processType == Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT;
+if (inParent) {
+  Cu.import("resource://gre/modules/PhoneNumber.jsm");
+  XPCOMUtils.defineLazyServiceGetter(this, "ppmm",
+                                     "@mozilla.org/parentprocessmessagemanager;1",
+                                     "nsIMessageListenerManager");
+  PhoneNumberUtils.init();
+}
+
--- a/dom/phonenumberutils/moz.build
+++ b/dom/phonenumberutils/moz.build
@@ -1,18 +1,23 @@
 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # 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/.
 
 TEST_DIRS += ['tests']
 
+EXTRA_COMPONENTS += [
+    'PhoneNumberService.js',
+    'PhoneNumberService.manifest',
+]
+
 EXTRA_JS_MODULES += [
     'PhoneNumber.jsm',
     'PhoneNumberMetaData.jsm',
+    'PhoneNumberNormalizer.jsm',
     'mcc_iso3166_table.jsm',
 ]
 
 EXTRA_PP_JS_MODULES += [
     'PhoneNumberUtils.jsm',
 ]
-
--- a/dom/phonenumberutils/tests/Makefile.in
+++ b/dom/phonenumberutils/tests/Makefile.in
@@ -6,14 +6,19 @@ DEPTH            = @DEPTH@
 topsrcdir        = @top_srcdir@
 srcdir           = @srcdir@
 VPATH            = @srcdir@
 
 relativesrcdir   = @relativesrcdir@
 
 include $(DEPTH)/config/autoconf.mk
 
+MOCHITEST_FILES = \
+  test_phonenumberutils_basics.html \
+  $(NULL)
+
 MOCHITEST_CHROME_FILES = \
   test_phonenumber.xul \
   test_phonenumberutils.xul \
+  test_phonenumberservice.xul \
   $(NULL)
 
 include $(topsrcdir)/config/rules.mk
--- a/dom/phonenumberutils/tests/test_phonenumber.xul
+++ b/dom/phonenumberutils/tests/test_phonenumber.xul
@@ -16,37 +16,38 @@
      target="_blank">Mozilla Bug 809213</a>
   </body>
 
 <script type="application/javascript;version=1.8">
 
 "use strict";
 
 Components.utils.import("resource://gre/modules/PhoneNumber.jsm");
+Components.utils.import("resource://gre/modules/PhoneNumberNormalizer.jsm");
 
 function IsPlain(dial, expected) {
   var result = PhoneNumber.IsPlain(dial);
   if (result != expected) {
     ok(false, dial + " is " + (result ? "" : "not ") + "plain, expects otherwise.");
   } else {
     ok(true, dial + " is " + (result ? "" : "not ") + "plain as expected.");
   }
 }
 
 function Normalize(dial, expected) {
-  var result = PhoneNumber.Normalize(dial);
+  var result = PhoneNumberNormalizer.Normalize(dial);
   if (result !== expected) {
     ok(false, "normalized " + dial + " to " + result + ", expected " + expected + " instead.");
   } else {
     ok(true, "normalized " + dial + " to " + result + " as expected.");
   }
 }
 
 function Normalize(dial, expected) {
-  var result = PhoneNumber.Normalize(dial);
+  var result = PhoneNumberNormalizer.Normalize(dial);
   if (result != expected) {
     ok(false, "Normalize error!\n");
     print("expected: " + expected);
     print("got: " + result);
   } else {
     ok(true, "Normalization OK");
   }
 }
new file mode 100644
--- /dev/null
+++ b/dom/phonenumberutils/tests/test_phonenumberservice.xul
@@ -0,0 +1,158 @@
+<?xml version="1.0"?>
+
+<!-- Any copyright is dedicated to the Public Domain.
+   - http://creativecommons.org/publicdomain/zero/1.0/ -->
+
+<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
+<?xml-stylesheet type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?>
+
+<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+        title="Mozilla Bug 781379">
+  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
+  <!-- test results are displayed in the html:body -->
+  <body xmlns="http://www.w3.org/1999/xhtml">
+  <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=809213"
+     target="_blank">Mozilla Bug 809213</a>
+  </body>
+
+<script type="application/javascript;version=1.8">
+
+"use strict";
+
+Components.utils.import("resource://gre/modules/Services.jsm");
+Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
+
+Services.prefs.setIntPref("dom.phonenumber.substringmatching.BR", 8);
+Services.prefs.setCharPref("ril.lastKnownSimMcc", "310");
+
+var pm = SpecialPowers.Cc["@mozilla.org/permissionmanager;1"]
+                      .getService(SpecialPowers.Ci.nsIPermissionManager);
+
+pm.addFromPrincipal(window.document.nodePrincipal, "phonenumberservice",
+                    SpecialPowers.Ci.nsIPermissionManager.ALLOW_ACTION);
+
+function onUnwantedSuccess() {
+  ok(false, "onUnwantedSuccess: shouldn't get here");
+}
+
+function onFailure() {
+  ok(false, "in on Failure!");
+}
+
+var req;
+var index = 0;
+var mozPhoneNumberService = window.navigator.mozPhoneNumberService;
+ok(mozPhoneNumberService, "mozPhoneNumberService exists");
+var steps = [
+  function() {
+    req = mozPhoneNumberService.fuzzyMatch("123", "123");
+    req.onsuccess = function(e) {
+      is(req.result, true, "same number");
+      next();
+    };
+    req.onerror = onFailure;
+  },
+  function() {
+    req = mozPhoneNumberService.fuzzyMatch("abcdef", "222333");
+    req.onsuccess = function(e) {
+      is(req.result, true, "normalize first number");
+      next();
+    };
+    req.onerror = onFailure;
+  },
+  function() {
+    req = mozPhoneNumberService.fuzzyMatch("abc333", "222def");
+    req.onsuccess = function(e) {
+      is(req.result, true, "normalize first and second number");
+      next();
+    };
+    req.onerror = onFailure;
+  },
+  function() {
+    req = mozPhoneNumberService.fuzzyMatch("1234567", "1234568");
+    req.onsuccess = function(e) {
+      is(req.result, false, "different numbers should not match");
+      next();
+    };
+    req.onerror = onFailure;
+  },
+  function() {
+    req = mozPhoneNumberService.fuzzyMatch("1234567", "123456");
+    req.onsuccess = function(e) {
+      is(req.result, false, "different length numbers should not match");
+      next();
+    };
+    req.onerror = onFailure;
+  },
+  function() {
+    req = mozPhoneNumberService.fuzzyMatch("1234567", "123456---");
+    req.onsuccess = function(e) {
+      is(req.result, false, "invalid number should not match valid number");
+      next();
+    };
+    req.onerror = onFailure;
+  },
+  function() {
+    req = mozPhoneNumberService.fuzzyMatch("111", undefined);
+    req.onsuccess = function(e) {
+      is(req.result, false, "missing second argument should not match");
+      next();
+    };
+    req.onerror = onFailure;
+  },
+  function() {
+    req = mozPhoneNumberService.fuzzyMatch(undefined, "111");
+    req.onsuccess = function(e) {
+      is(req.result, false, "missing first argument should not match");
+      next();
+    };
+    req.onerror = onFailure;
+  },
+  function() {
+    req = mozPhoneNumberService.fuzzyMatch(null, "");
+    req.onsuccess = function(e) {
+      is(req.result, true, "missing first argument should fuzzy match empty string");
+      next();
+    };
+    req.onerror = onFailure;
+  },
+  function() {
+    req = mozPhoneNumberService.fuzzyMatch("+552155555555", "2155555555");
+    req.onsuccess = function(e) {
+      is(req.result, true, "test internationalization of number");
+      next();
+    };
+    req.onerror = onFailure;
+  },
+  function() {
+    req = mozPhoneNumberService.fuzzyMatch("aaa123456789", "zzzzz123456789");
+    req.onsuccess = function(e) {
+      is(req.result, true, "substring matching should be in effect");
+      next();
+    };
+    req.onerror = onFailure;
+  },
+  function () {
+    ok(true, "all done!\n");
+    SimpleTest.finish();
+  }
+];
+
+function next() {
+  ok(true, "Begin!");
+  if (index >= steps.length) {
+    ok(false, "Shouldn't get here!");
+    return;
+  }
+  try {
+    var i = index++;
+    steps[i]();
+  } catch(ex) {
+    ok(false, "Caught exception", ex);
+  }
+}
+
+SimpleTest.waitForExplicitFinish();
+addLoadEvent(next);
+</script>
+</window>
--- a/dom/phonenumberutils/tests/test_phonenumberutils.xul
+++ b/dom/phonenumberutils/tests/test_phonenumberutils.xul
@@ -15,18 +15,22 @@
   <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=809213"
      target="_blank">Mozilla Bug 809213</a>
   </body>
 
 <script type="application/javascript;version=1.8">
 
 "use strict";
 
+Components.utils.import("resource://gre/modules/Services.jsm");
 Components.utils.import("resource://gre/modules/PhoneNumberUtils.jsm");
 
+Services.prefs.setIntPref("dom.phonenumber.substringmatching.BR", 8);
+Services.prefs.setCharPref("ril.lastKnownSimMcc", "310");
+
 function CantParseWithMcc(dial, mcc) {
   var result = PhoneNumberUtils.parseWithMCC(dial, mcc);
   if (result) {
     ok(false, "Shouldn't parse!\n");
     dump("expected: does not parse");
     dump("got: " + dial + " " + mcc);
   } else {
     ok(true, "Parses");
@@ -38,17 +42,27 @@ function ParseWithMcc(dial, mcc) {
   if (result) {
     ok(true, "Parses!\n");
   } else {
     ok(false, "Should Parse");
     dump("expected: parses");
   }
 }
 
+function FuzzyMatch(number1, number2, expect) {
+  var result = PhoneNumberUtils.fuzzyMatch(number1, number2);
+  is(result, expect, "FuzzyMatch OK!");
+}
+
 // Unknown mcc
 CantParseWithMcc("1234", 123);
 ParseWithMcc("4165555555", 302);
 
 is(PhoneNumberUtils.normalize("123abc", true), "123", "NumbersOnly");
 is(PhoneNumberUtils.normalize("123abc", false), "123222", "NumbersOnly");
 
+FuzzyMatch("123abc", "123222", true);
+FuzzyMatch("123456789", "123456789", true);
+FuzzyMatch("111", null, false);
+FuzzyMatch("+552155555555", "2155555555", true);
+FuzzyMatch("aaa123456789", "zzzzz123456789", true);
 </script>
 </window>
new file mode 100644
--- /dev/null
+++ b/dom/phonenumberutils/tests/test_phonenumberutils_basics.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=674720
+-->
+<head>
+  <title>Test for Bug 883923 PhoneNumberUtils FuzzyMatch</title>
+  <script type="text/javascript" src="/MochiKit/MochiKit.js"></script>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=883923">Mozilla Bug 883923</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+"use strict";
+
+var mozPhoneNumberService = window.navigator.mozPhoneNumberService;
+if (mozPhoneNumberService) {
+  is(mozPhoneNumberService.fuzzyMatch, undefined, "Fuzzy Match should not be accesible");
+  is(mozPhoneNumberService.normalize, undefined, "Normalize should not be accessible");
+}
+</script>
+</pre>
+</body>
+</html>
--- a/dom/push/src/PushService.jsm
+++ b/dom/push/src/PushService.jsm
@@ -290,16 +290,18 @@ this.PushService = {
         this.uninit();
       case "network-active-changed":         /* On B2G. */
       case "network:offline-status-changed": /* On desktop. */
         // In case of network-active-changed, always disconnect existing
         // connections. In case of offline-status changing from offline to
         // online, it is likely that these statements will be no-ops.
         if (this._udpServer) {
           this._udpServer.close();
+          // Set to null since this is checked in _listenForUDPWakeup()
+          this._udpServer = null;
         }
 
         this._shutdownWS();
 
         // Try to connect if network-active-changed or the offline-status
         // changed to online.
         if (aTopic === "network-active-changed" || aData === "online") {
           this._startListeningIfChannelsPresent();
@@ -499,16 +501,17 @@ this.PushService = {
 
     if (this._db) {
       this._db.close();
       this._db = null;
     }
 
     if (this._udpServer) {
       this._udpServer.close();
+      this._udpServer = null;
     }
 
     // All pending requests (ideally none) are dropped at this point. We
     // shouldn't have any applications performing registration/unregistration
     // or receiving notifications.
     this._shutdownWS();
 
     // At this point, profile-change-net-teardown has already fired, so the
--- a/dom/system/gonk/RILContentHelper.js
+++ b/dom/system/gonk/RILContentHelper.js
@@ -917,32 +917,36 @@ RILContentHelper.prototype = {
     }
 
     let request = Services.DOMRequest.createRequest(window);
     let requestId = this.getRequestId(request);
 
     // Parsing nsDOMContact to Icc Contact format
     let iccContact = {};
 
-    if (contact.name) {
+    if (Array.isArray(contact.name) && contact.name[0]) {
       iccContact.alphaId = contact.name[0];
     }
 
-    if (contact.tel) {
-      iccContact.number = contact.tel[0].value;
+    if (Array.isArray(contact.tel)) {
+      iccContact.number = contact.tel[0] && contact.tel[0].value;
+      let telArray = contact.tel.slice(1);
+      let length = telArray.length;
+      if (length > 0) {
+        iccContact.anr = [];
+      }
+      for (let i = 0; i < telArray.length; i++) {
+        iccContact.anr.push(telArray[i].value);
+      }
     }
 
-    if (contact.email) {
+    if (Array.isArray(contact.email) && contact.email[0]) {
       iccContact.email = contact.email[0].value;
     }
 
-    if (contact.tel.length > 1) {
-      iccContact.anr = contact.tel.slice(1);
-    }
-
     cpmm.sendAsyncMessage("RIL:UpdateIccContact", {
       clientId: 0,
       data: {
         requestId: requestId,
         contactType: contactType,
         contact: iccContact,
         pin2: pin2
       }
--- a/dom/system/gonk/ril_worker.js
+++ b/dom/system/gonk/ril_worker.js
@@ -1287,17 +1287,17 @@ let RIL = {
    *        Password for the facility, or "" if not required.
    * @param serviceClass
    *        One of ICC_SERVICE_CLASS_*.
    * @param [optional] aid
    *        AID value.
    */
   setICCFacilityLock: function setICCFacilityLock(options) {
     Buf.newParcel(REQUEST_SET_FACILITY_LOCK, options);
-    Buf.writeUint32(RILQUIRKS_V5_LEGACY ? 3 : 4);
+    Buf.writeUint32(RILQUIRKS_V5_LEGACY ? 4 : 5);
     Buf.writeString(options.facility);
     Buf.writeString(options.enabled ? "1" : "0");
     Buf.writeString(options.password);
     Buf.writeString(options.serviceClass.toString());
     if (!RILQUIRKS_V5_LEGACY) {
       Buf.writeString(options.aid || this.aid);
     }
     Buf.sendParcel();
@@ -2088,20 +2088,20 @@ let RIL = {
     this._mergeAllCellBroadcastConfigs();
   },
 
   updateCellBroadcastConfig: function updateCellBroadcastConfig() {
     let activate = !this.cellBroadcastDisabled &&
                    (this.mergedCellBroadcastConfig != null) &&
                    (this.mergedCellBroadcastConfig.length > 0);
     if (activate) {
-      this.setGsmSmsBroadcastConfig(this.mergedCellBroadcastConfig);
+      this.setSmsBroadcastConfig(this.mergedCellBroadcastConfig);
     } else {
       // It's unnecessary to set config first if we're deactivating.
-      this.setGsmSmsBroadcastActivation(false);
+      this.setSmsBroadcastActivation(false);
     }
   },
 
   setGsmSmsBroadcastConfig: function setGsmSmsBroadcastConfig(config) {
     Buf.newParcel(REQUEST_GSM_SET_BROADCAST_SMS_CONFIG);
 
     let numConfigs = config ? config.length / 2 : 0;
     Buf.writeUint32(numConfigs);
@@ -2111,18 +2111,58 @@ let RIL = {
       Buf.writeUint32(0x00);
       Buf.writeUint32(0xFF);
       Buf.writeUint32(1);
     }
 
     Buf.sendParcel();
   },
 
-  setGsmSmsBroadcastActivation: function setGsmSmsBroadcastActivation(activate) {
-    Buf.newParcel(REQUEST_GSM_SMS_BROADCAST_ACTIVATION);
+  /**
+   * Send CDMA SMS broadcast config.
+   *
+   * @see 3GPP2 C.R1001 Sec. 9.2 and 9.3
+   */
+  setCdmaSmsBroadcastConfig: function setCdmaSmsBroadcastConfig(config) {
+    // |config| is an array of half-closed range: [[from, to), [from, to), ...].
+    // It will be further decomposed, ex: [1, 4) => 1, 2, 3.
+    Buf.newParcel(REQUEST_CDMA_SET_BROADCAST_SMS_CONFIG);
+
+    let numConfigs = 0;
+    for (let i = 0; i < config.length; i += 2) {
+      numConfigs += (config[i+1] - config[i]);
+    }
+
+    Buf.writeUint32(numConfigs);
+    for (let i = 0; i < config.length;) {
+      let begin = config[i++];
+      let end = config[i++];
+
+      for (let j = begin; j < end; ++j) {
+        Buf.writeUint32(j);
+        Buf.writeUint32(0);  // Language Indicator: Unknown or unspecified.
+        Buf.writeUint32(1);
+      }
+    }
+
+    Buf.sendParcel();
+  },
+
+  setSmsBroadcastConfig: function setSmsBroadcastConfig(config) {
+    if (this._isCdma) {
+      this.setCdmaSmsBroadcastConfig(config);
+    } else {
+      this.setGsmSmsBroadcastConfig(config);
+    }
+  },
+
+  setSmsBroadcastActivation: function setSmsBroadcastActivation(activate) {
+    let parcelType = this._isCdma ? REQUEST_CDMA_SMS_BROADCAST_ACTIVATION :
+                                    REQUEST_GSM_SMS_BROADCAST_ACTIVATION;
+    Buf.newParcel(parcelType);
     Buf.writeUint32(1);
     // See hardware/ril/include/telephony/ril.h, 0 - Activate, 1 - Turn off.
     Buf.writeUint32(activate ? 0 : 1);
     Buf.sendParcel();
   },
 
   /**
    * Start a DTMF Tone.
@@ -4664,35 +4704,57 @@ let RIL = {
 
     // Append to the end.
     list.push(from);
     list.push(to);
 
     return list;
   },
 
+  _isCellBroadcastConfigReady: function() {
+    if (!("MMI" in this.cellBroadcastConfigs)) {
+      return false;
+    }
+
+    // CBMI should be ready in GSM.
+    if (!this._isCdma &&
+        (!("CBMI" in this.cellBroadcastConfigs) ||
+         !("CBMID" in this.cellBroadcastConfigs) ||
+         !("CBMIR" in this.cellBroadcastConfigs))) {
+      return false;
+    }
+
+    return true;
+  },
+
   /**
    * Merge all members of cellBroadcastConfigs into mergedCellBroadcastConfig.
    */
   _mergeAllCellBroadcastConfigs: function _mergeAllCellBroadcastConfigs() {
-    if (!("CBMI" in this.cellBroadcastConfigs)
-        || !("CBMID" in this.cellBroadcastConfigs)
-        || !("CBMIR" in this.cellBroadcastConfigs)
-        || !("MMI" in this.cellBroadcastConfigs)) {
+    if (!this._isCellBroadcastConfigReady()) {
       if (DEBUG) {
         debug("cell broadcast configs not ready, waiting ...");
       }
       return;
     }
+
+    // Prepare cell broadcast config. CBMI* are only used in GSM.
+    let usedCellBroadcastConfigs = {MMI: this.cellBroadcastConfigs.MMI};
+    if (!this._isCdma) {
+      usedCellBroadcastConfigs.CBMI = this.cellBroadcastConfigs.CBMI;
+      usedCellBroadcastConfigs.CBMID = this.cellBroadcastConfigs.CBMID;
+      usedCellBroadcastConfigs.CBMIR = this.cellBroadcastConfigs.CBMIR;
+    }
+
     if (DEBUG) {
-      debug("Cell Broadcast search lists: " + JSON.stringify(this.cellBroadcastConfigs));
+      debug("Cell Broadcast search lists: " + JSON.stringify(usedCellBroadcastConfigs));
     }
 
     let list = null;
-    for each (let ll in this.cellBroadcastConfigs) {
+    for each (let ll in usedCellBroadcastConfigs) {
       if (ll == null) {
         continue;
       }
 
       for (let i = 0; i < ll.length; i += 2) {
         list = this._mergeCellBroadcastConfigs(list, ll[i], ll[i + 1]);
       }
     }
@@ -4708,22 +4770,25 @@ let RIL = {
    * Check whether search list from settings is settable by MMI, that is,
    * whether the range is bounded in any entries of CB_NON_MMI_SETTABLE_RANGES.
    */
   _checkCellBroadcastMMISettable: function _checkCellBroadcastMMISettable(from, to) {
     if ((to <= from) || (from >= 65536) || (from < 0)) {
       return false;
     }
 
-    for (let i = 0, f, t; i < CB_NON_MMI_SETTABLE_RANGES.length;) {
-      f = CB_NON_MMI_SETTABLE_RANGES[i++];
-      t = CB_NON_MMI_SETTABLE_RANGES[i++];
-      if ((from < t) && (to > f)) {
-        // Have overlap.
-        return false;
+    if (!this._isCdma) {
+      // GSM not settable ranges.
+      for (let i = 0, f, t; i < CB_NON_MMI_SETTABLE_RANGES.length;) {
+        f = CB_NON_MMI_SETTABLE_RANGES[i++];
+        t = CB_NON_MMI_SETTABLE_RANGES[i++];
+        if ((from < t) && (to > f)) {
+          // Have overlap.
+          return false;
+        }
       }
     }
 
     return true;
   },
 
   /**
    * Convert Cell Broadcast settings string into search list.
@@ -5846,17 +5911,17 @@ RIL[REQUEST_CDMA_BURST_DTMF] = null;
 RIL[REQUEST_CDMA_VALIDATE_AND_WRITE_AKEY] = null;
 RIL[REQUEST_CDMA_SEND_SMS] = function REQUEST_CDMA_SEND_SMS(length, options) {
   this._processSmsSendResult(length, options);
 };
 RIL[REQUEST_CDMA_SMS_ACKNOWLEDGE] = null;
 RIL[REQUEST_GSM_GET_BROADCAST_SMS_CONFIG] = null;
 RIL[REQUEST_GSM_SET_BROADCAST_SMS_CONFIG] = function REQUEST_GSM_SET_BROADCAST_SMS_CONFIG(length, options) {
   if (options.rilRequestError == ERROR_SUCCESS) {
-    this.setGsmSmsBroadcastActivation(true);
+    this.setSmsBroadcastActivation(true);
   }
 };
 RIL[REQUEST_GSM_SMS_BROADCAST_ACTIVATION] = null;
 RIL[REQUEST_CDMA_GET_BROADCAST_SMS_CONFIG] = null;
 RIL[REQUEST_CDMA_SET_BROADCAST_SMS_CONFIG] = null;
 RIL[REQUEST_CDMA_SMS_BROADCAST_ACTIVATION] = null;
 RIL[REQUEST_CDMA_SUBSCRIPTION] = null;
 RIL[REQUEST_CDMA_WRITE_SMS_TO_RUIM] = null;
new file mode 100644
--- /dev/null
+++ b/dom/system/gonk/tests/test_ril_worker_cellbroadcast_config.js
@@ -0,0 +1,136 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this);
+
+function run_test() {
+  run_next_test();
+}
+
+add_test(function test_ril_worker_cellbroadcast_activate() {
+  let worker = newWorker({
+    postRILMessage: function fakePostRILMessage(id, parcel) {
+      // Do nothing
+    },
+    postMessage: function fakePostMessage(message) {
+      // Do nothing
+    }
+  });
+
+  let parcelTypes = [];
+  let org_newParcel = worker.Buf.newParcel;
+  worker.Buf.newParcel = function(type, options) {
+    parcelTypes.push(type);
+    org_newParcel.apply(this, arguments);
+  };
+
+  function setup(isCdma) {
+    worker.RIL._isCdma = isCdma;
+    worker.RIL.cellBroadcastDisabled = false;
+    worker.RIL.mergedCellBroadcastConfig = [1, 2, 4, 7];  // 1, 4-6
+    parcelTypes = [];
+  }
+
+  function test(isCdma, expectedRequest) {
+    setup(isCdma);
+    worker.RIL.setCellBroadcastDisabled({disabled: true});
+    // Makesure that request parcel is sent out.
+    do_check_neq(parcelTypes.indexOf(expectedRequest), -1);
+    do_check_eq(worker.RIL.cellBroadcastDisabled, true);
+  }
+
+  test(false, REQUEST_GSM_SMS_BROADCAST_ACTIVATION);
+  test(true, REQUEST_CDMA_SMS_BROADCAST_ACTIVATION);
+
+  run_next_test();
+});
+
+add_test(function test_ril_worker_cellbroadcast_config() {
+  let currentParcel;
+  let worker = newWorker({
+    postRILMessage: function fakePostRILMessage(id, parcel) {
+      currentParcel = parcel;
+    },
+    postMessage: function fakePostMessage(message) {
+      // Do nothing
+    }
+  });
+
+  function U32ArrayFromParcelArray(pa) {
+    do_print(pa);
+    let out = [];
+    for (let i = 0; i < pa.length; i += 4) {
+      let data = pa[i] + (pa[i+1] << 8) + (pa[i+2] << 16) + (pa[i+3] << 24);
+      out.push(data);
+    }
+    return out;
+  }
+
+  function test(isCdma, configs, expected) {
+    let parcelType = isCdma ? REQUEST_CDMA_SET_BROADCAST_SMS_CONFIG
+                            : REQUEST_GSM_SET_BROADCAST_SMS_CONFIG;
+
+    let found = false;
+    worker.postRILMessage = function (id, parcel) {
+      u32Parcel = U32ArrayFromParcelArray(Array.slice(parcel));
+      if (u32Parcel[1] != parcelType) {
+        return;
+      }
+
+      found = true;
+      // Check parcel. Data start from 4th word (32bit)
+      do_check_eq(u32Parcel.slice(3).toString(), expected);
+    };
+
+    worker.RIL._isCdma = isCdma;
+    worker.RIL.setSmsBroadcastConfig(configs);
+
+    // Makesure that request parcel is sent out.
+    do_check_true(found);
+  }
+
+  // (GSM) RIL writes the following data to outgoing parcel:
+  //   nums [(from, to, 0, 0xFF, 1), ... ]
+  test(false,
+       [1, 2, 4, 7]  /* 1, 4-6 */,
+       ["2", "1,2,0,255,1", "4,7,0,255,1"].join());
+
+  // (CDMA) RIL writes the following data to outgoing parcel:
+  //   nums [(id, 0, 1), ... ]
+  test(true,
+       [1, 2, 4, 7]  /* 1, 4-6 */,
+       ["4", "1,0,1", "4,0,1", "5,0,1", "6,0,1"].join());
+
+  run_next_test();
+});
+
+add_test(function test_ril_worker_cellbroadcast_merge_config() {
+  let worker = newWorker({
+    postRILMessage: function fakePostRILMessage(id, parcel) {
+      // Do nothing
+    },
+    postMessage: function fakePostMessage(message) {
+      // Do nothing
+    }
+  });
+
+  function test(isCdma, configs, expected) {
+    worker.RIL._isCdma = isCdma;
+    worker.RIL.cellBroadcastConfigs = configs;
+    worker.RIL._mergeAllCellBroadcastConfigs();
+    do_check_eq(worker.RIL.mergedCellBroadcastConfig.toString(), expected);
+  }
+
+  let configs = {
+    MMI:    [1, 2, 4, 7],   // 1, 4-6
+    CBMI:   [6, 9],         // 6-8
+    CBMID:  [8, 11],        // 8-10
+    CBMIR:  [10, 13]        // 10-12
+  };
+
+  test(false, configs, "1,2,4,13");
+  test(true, configs, "1,2,4,7");
+
+  run_next_test();
+});
+
--- a/dom/system/gonk/tests/test_ril_worker_icc.js
+++ b/dom/system/gonk/tests/test_ril_worker_icc.js
@@ -2706,56 +2706,121 @@ add_test(function test_personalization_s
                       GECKO_CARDSTATE_CORPORATE_PUK_REQUIRED);
   testPersonalization(CARD_PERSOSUBSTATE_SIM_SERVICE_PROVIDER_PUK,
                       GECKO_CARDSTATE_SERVICE_PROVIDER_PUK_REQUIRED);
 
   run_next_test();
 });
 
 /**
+ * Verify iccSetCardLock - Facility Lock.
+ */
+add_test(function test_set_icc_card_lock_facility_lock() {
+  let worker = newUint8Worker();
+  worker.RILQUIRKS_V5_LEGACY = false;
+  let aid = "123456789";
+  let ril = worker.RIL;
+  ril.aid = aid;
+  let buf = worker.Buf;
+
+  let GECKO_CARDLOCK_TO_FACILITIY_LOCK = {};
+  GECKO_CARDLOCK_TO_FACILITIY_LOCK[GECKO_CARDLOCK_PIN] = ICC_CB_FACILITY_SIM;
+  GECKO_CARDLOCK_TO_FACILITIY_LOCK[GECKO_CARDLOCK_FDN] = ICC_CB_FACILITY_FDN;
+
+  let GECKO_CARDLOCK_TO_PASSWORD_TYPE = {};
+  GECKO_CARDLOCK_TO_PASSWORD_TYPE[GECKO_CARDLOCK_PIN] = "pin";
+  GECKO_CARDLOCK_TO_PASSWORD_TYPE[GECKO_CARDLOCK_FDN] = "pin2";
+
+  const pin = "1234";
+  const pin2 = "4321";
+  let GECKO_CARDLOCK_TO_PASSWORD = {};
+  GECKO_CARDLOCK_TO_PASSWORD[GECKO_CARDLOCK_PIN] = pin;
+  GECKO_CARDLOCK_TO_PASSWORD[GECKO_CARDLOCK_FDN] = pin2;
+
+  const serviceClass = ICC_SERVICE_CLASS_VOICE |
+                       ICC_SERVICE_CLASS_DATA  |
+                       ICC_SERVICE_CLASS_FAX;
+
+  function do_test(aLock, aPassword, aEnabled) {
+    buf.sendParcel = function fakeSendParcel () {
+      // Request Type.
+      do_check_eq(this.readUint32(), REQUEST_SET_FACILITY_LOCK);
+
+      // Token : we don't care
+      this.readUint32();
+
+      let parcel = this.readStringList();
+      do_check_eq(parcel.length, 5);
+      do_check_eq(parcel[0], GECKO_CARDLOCK_TO_FACILITIY_LOCK[aLock]);
+      do_check_eq(parcel[1], aEnabled ? "1" : "0");
+      do_check_eq(parcel[2], GECKO_CARDLOCK_TO_PASSWORD[aLock]);
+      do_check_eq(parcel[3], serviceClass.toString());
+      do_check_eq(parcel[4], aid);
+    };
+
+    let lock = {lockType: aLock,
+                enabled: aEnabled};
+    lock[GECKO_CARDLOCK_TO_PASSWORD_TYPE[aLock]] = aPassword;
+
+    ril.iccSetCardLock(lock);
+  }
+
+  do_test(GECKO_CARDLOCK_PIN, pin, true);
+  do_test(GECKO_CARDLOCK_PIN, pin, false);
+  do_test(GECKO_CARDLOCK_FDN, pin2, true);
+  do_test(GECKO_CARDLOCK_FDN, pin2, false);
+
+  run_next_test();
+});
+
+/**
  * Verify iccUnlockCardLock.
  */
 add_test(function test_unlock_card_lock_corporateLocked() {
   let worker = newUint8Worker();
   let ril = worker.RIL;
   let buf = worker.Buf;
   const pin = "12345678";
   const puk = "12345678";
 
+  let GECKO_CARDLOCK_TO_PASSWORD_TYPE = {};
+  GECKO_CARDLOCK_TO_PASSWORD_TYPE[GECKO_CARDLOCK_NCK] = "pin";
+  GECKO_CARDLOCK_TO_PASSWORD_TYPE[GECKO_CARDLOCK_CCK] = "pin";
+  GECKO_CARDLOCK_TO_PASSWORD_TYPE[GECKO_CARDLOCK_SPCK] = "pin";
+  GECKO_CARDLOCK_TO_PASSWORD_TYPE[GECKO_CARDLOCK_NCK_PUK] = "puk";
+  GECKO_CARDLOCK_TO_PASSWORD_TYPE[GECKO_CARDLOCK_CCK_PUK] = "puk";
+  GECKO_CARDLOCK_TO_PASSWORD_TYPE[GECKO_CARDLOCK_SPCK_PUK] = "puk";
+
   function do_test(aLock, aPassword) {
     buf.sendParcel = function fakeSendParcel () {
       // Request Type.
       do_check_eq(this.readUint32(), REQUEST_ENTER_NETWORK_DEPERSONALIZATION_CODE);
 
       // Token : we don't care
       this.readUint32();
 
       let lockType = GECKO_PERSO_LOCK_TO_CARD_PERSO_LOCK[aLock];
       // Lock Type
       do_check_eq(this.readUint32(), lockType);
 
       // Pin/Puk.
       do_check_eq(this.readString(), aPassword);
     };
 
-    if (aLock.endsWith("Puk")) {
-      ril.iccUnlockCardLock({lockType: aLock,
-                             puk: aPassword});
-    } else {
-      ril.iccUnlockCardLock({lockType: aLock,
-                             pin: aPassword});
-    }
+    let lock = {lockType: aLock};
+    lock[GECKO_CARDLOCK_TO_PASSWORD_TYPE[aLock]] = aPassword;
+    ril.iccUnlockCardLock(lock);
   }
 
-  do_test("nck", pin);
-  do_test("cck", pin);
-  do_test("spck", pin);
-  do_test("nckPuk", puk);
-  do_test("cckPuk", puk);
-  do_test("spckPuk", puk);
+  do_test(GECKO_CARDLOCK_NCK, pin);
+  do_test(GECKO_CARDLOCK_CCK, pin);
+  do_test(GECKO_CARDLOCK_SPCK, pin);
+  do_test(GECKO_CARDLOCK_NCK_PUK, puk);
+  do_test(GECKO_CARDLOCK_CCK_PUK, puk);
+  do_test(GECKO_CARDLOCK_SPCK_PUK, puk);
 
   run_next_test();
 });
 
 /**
  * Verify MCC and MNC parsing
  */
 add_test(function test_mcc_mnc_parsing() {
--- a/dom/system/gonk/tests/xpcshell.ini
+++ b/dom/system/gonk/tests/xpcshell.ini
@@ -2,14 +2,15 @@
 head = header_helpers.js
 tail =
 
 [test_ril_worker_buf.js]
 [test_ril_worker_icc.js]
 [test_ril_worker_sms.js]
 [test_ril_worker_mmi.js]
 [test_ril_worker_cf.js]
+[test_ril_worker_cellbroadcast_config.js]
 [test_ril_worker_cellbroadcast.js]
 [test_ril_worker_ruim.js]
 [test_ril_worker_cw.js]
 [test_ril_worker_clir.js]
 [test_ril_worker_clip.js]
 [test_ril_worker_ssn.js]
new file mode 100644
--- /dev/null
+++ b/dom/webidl/BluetoothAdapter.webidl
@@ -0,0 +1,131 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+// MediaMetadata and MediaPlayStatus are used to keep data from Applications.
+// Please see specification of AVRCP 1.3 for more details.
+dictionary MediaMetaData
+{
+  // track title
+  DOMString   title = "";
+  // artist name
+  DOMString   artist = "";
+  // album name
+  DOMString   album = "";
+  // track number
+  long long   mediaNumber = -1;
+  // number of tracks in the album
+  long long   totalMediaCount = -1;
+  // playing time (ms)
+  long long   duration = -1;
+};
+
+dictionary MediaPlayStatus
+{
+  // current track length (ms)
+  long long   duration = -1;
+  // playing time (ms)
+  long long   position = -1;
+  // one of 'STOPPED'/'PLAYING'/'PAUSED'/'FWD_SEEK'/'REV_SEEK'/'ERROR'
+  DOMString   playStatus = "";
+};
+
+interface BluetoothAdapter : EventTarget {
+  readonly attribute DOMString      address;
+  readonly attribute unsigned long  class;
+  readonly attribute boolean        discovering;
+  readonly attribute DOMString      name;
+  readonly attribute boolean        discoverable;
+  readonly attribute unsigned long  discoverableTimeout; // in seconds
+
+  // array of type BluetoothDevice[]
+  [GetterThrows]
+  readonly attribute any            devices;
+
+  // array of type DOMString[]
+  [GetterThrows]
+  readonly attribute any            uuids;
+
+  [SetterThrows]
+           attribute EventHandler   ondevicefound;
+
+  // Fired when pairing process is completed
+  [SetterThrows]
+           attribute EventHandler   onpairedstatuschanged;
+
+  // Fired when a2dp connection status changed
+  [SetterThrows]
+           attribute EventHandler   ona2dpstatuschanged;
+
+  // Fired when handsfree connection status changed
+  [SetterThrows]
+           attribute EventHandler   onhfpstatuschanged;
+
+  // Fired when sco connection status changed
+  [SetterThrows]
+           attribute EventHandler   onscostatuschanged;
+
+  [Creator, Throws]
+  DOMRequest setName(DOMString name);
+  [Creator, Throws]
+  DOMRequest setDiscoverable(boolean discoverable);
+  [Creator, Throws]
+  DOMRequest setDiscoverableTimeout(unsigned long timeout);
+  [Creator, Throws]
+  DOMRequest startDiscovery();
+  [Creator, Throws]
+  DOMRequest stopDiscovery();
+  [Creator, Throws]
+  DOMRequest pair(BluetoothDevice device);
+  [Creator, Throws]
+  DOMRequest unpair(BluetoothDevice device);
+  [Creator, Throws]
+  DOMRequest getPairedDevices();
+  [Creator, Throws]
+  DOMRequest getConnectedDevices(unsigned short profile);
+  [Creator, Throws]
+  DOMRequest setPinCode(DOMString deviceAddress, DOMString pinCode);
+  [Creator, Throws]
+  DOMRequest setPasskey(DOMString deviceAddress, unsigned long passkey);
+  [Creator, Throws]
+  DOMRequest setPairingConfirmation(DOMString deviceAddress, boolean confirmation);
+  [Creator, Throws]
+  DOMRequest setAuthorization(DOMString deviceAddress, boolean allow);
+
+  /**
+   * Connect/Disconnect to a specific service of a target remote device.
+   * To check the value of service UUIDs, please check "Bluetooth Assigned
+   * Numbers" / "Service Discovery Protocol" for more information.
+   *
+   * @param deviceAddress Remote device address
+   * @param profile 2-octets service UUID
+   */
+  [Creator, Throws]
+  DOMRequest connect(DOMString deviceAddress, unsigned short profile);
+  [Creator, Throws]
+  DOMRequest disconnect(unsigned short profile);
+
+  // One device can only send one file at a time
+  [Creator, Throws]
+  DOMRequest sendFile(DOMString deviceAddress, Blob blob);
+  [Creator, Throws]
+  DOMRequest stopSendingFile(DOMString deviceAddress);
+  [Creator, Throws]
+  DOMRequest confirmReceivingFile(DOMString deviceAddress, boolean confirmation);
+
+  // Connect/Disconnect SCO (audio) connection
+  [Creator, Throws]
+  DOMRequest connectSco();
+  [Creator, Throws]
+  DOMRequest disconnectSco();
+  [Creator, Throws]
+  DOMRequest isScoConnected();
+
+  // AVRCP 1.3 methods
+  [Creator,Throws]
+  DOMRequest sendMediaMetaData(optional MediaMetaData mediaMetaData);
+  [Creator,Throws]
+  DOMRequest sendMediaPlayStatus(optional MediaPlayStatus mediaPlayStatus);
+};
new file mode 100644
--- /dev/null
+++ b/dom/webidl/BluetoothDevice.webidl
@@ -0,0 +1,22 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+interface BluetoothDevice : EventTarget {
+  readonly attribute DOMString      address;
+  readonly attribute DOMString      name;
+  readonly attribute DOMString      icon;
+  readonly attribute boolean        connected;
+  readonly attribute boolean        paired;
+  readonly attribute unsigned long  class;
+
+  // array of type DOMString[]
+  [Throws]
+  readonly attribute any            uuids;
+
+  // array of type DOMString[]
+  [Throws]
+  readonly attribute any            services;
+};
--- a/dom/webidl/BluetoothDeviceEvent.webidl
+++ b/dom/webidl/BluetoothDeviceEvent.webidl
@@ -1,14 +1,13 @@
 /* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* 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/.
  */
-interface BluetoothDevice;
 
 [Constructor(DOMString type, optional BluetoothDeviceEventInit eventInitDict), HeaderFile="GeneratedEventClasses.h"]
 interface BluetoothDeviceEvent : Event
 {
   readonly attribute BluetoothDevice? device;
 };
 
 dictionary BluetoothDeviceEventInit : EventInit
new file mode 100644
--- /dev/null
+++ b/dom/webidl/BluetoothManager.webidl
@@ -0,0 +1,21 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/. */
+
+interface BluetoothManager : EventTarget {
+  [Throws]
+  readonly attribute boolean      enabled;
+
+  [SetterThrows]
+           attribute EventHandler onenabled;
+  [SetterThrows]
+           attribute EventHandler ondisabled;
+  [SetterThrows]
+           attribute EventHandler onadapteradded;
+
+  [Throws]
+  boolean     isConnected(unsigned short aProfile);
+  [Creator, Throws]
+  DOMRequest? getDefaultAdapter();
+};
--- a/dom/webidl/Navigator.webidl
+++ b/dom/webidl/Navigator.webidl
@@ -290,21 +290,19 @@ partial interface Navigator {
 // https://dvcs.w3.org/hg/gamepad/raw-file/default/gamepad.html#navigator-interface-extension
 partial interface Navigator {
   [Throws, Pref="dom.gamepad.enabled"]
   sequence<Gamepad?> getGamepads();
 };
 #endif // MOZ_GAMEPAD
 
 #ifdef MOZ_B2G_BT
-// nsIDOMNavigatorBluetooth
-interface MozBluetoothManager;
 partial interface Navigator {
   [Throws, Func="Navigator::HasBluetoothSupport"]
-  readonly attribute MozBluetoothManager mozBluetooth;
+  readonly attribute BluetoothManager mozBluetooth;
 };
 #endif // MOZ_B2G_BT
 
 #ifdef MOZ_TIME_MANAGER
 // nsIDOMMozNavigatorTime
 partial interface Navigator {
   [Throws, Func="Navigator::HasTimeSupport"]
   readonly attribute MozTimeManager mozTime;
new file mode 100644
--- /dev/null
+++ b/dom/webidl/PhoneNumberService.webidl
@@ -0,0 +1,15 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/.
+ */
+
+[JSImplementation="@mozilla.org/phoneNumberService;1", NavigatorProperty="mozPhoneNumberService"]
+interface PhoneNumberService {
+
+  [Func="Navigator::HasPhoneNumberSupport"]
+  DOMRequest fuzzyMatch([TreatNullAs=EmptyString, TreatUndefinedAs=EmptyString] DOMString number1, [TreatNullAs=EmptyString, TreatUndefinedAs=EmptyString] DOMString number2);
+
+  [Func="Navigator::HasPhoneNumberSupport"]
+  DOMString normalize(DOMString number);
+};
--- a/dom/webidl/WebIDL.mk
+++ b/dom/webidl/WebIDL.mk
@@ -219,16 +219,17 @@ webidl_files = \
   PaintRequest.webidl \
   PaintRequestList.webidl \
   PannerNode.webidl \
   ParentNode.webidl \
   Performance.webidl \
   PerformanceNavigation.webidl \
   PerformanceTiming.webidl \
   PeriodicWave.webidl \
+  PhoneNumberService.webidl \
   Plugin.webidl \
   PluginArray.webidl \
   Position.webidl \
   PositionError.webidl \
   ProcessingInstruction.webidl \
   Promise.webidl \
   PushManager.webidl \
   Range.webidl \
@@ -471,17 +472,20 @@ webidl_files += \
   StyleRuleChangeEvent.webidl \
   StyleSheetApplicableStateChangeEvent.webidl \
   StyleSheetChangeEvent.webidl \
   UserProximityEvent.webidl \
   $(NULL)
 
 ifdef MOZ_B2G_BT
 webidl_files += \
+  BluetoothAdapter.webidl \
+  BluetoothDevice.webidl \
   BluetoothDeviceEvent.webidl \
+  BluetoothManager.webidl \
   BluetoothStatusChangedEvent.webidl \
   $(NULL)
 endif
 
 ifdef MOZ_B2G_RIL
 webidl_files += \
   CallEvent.webidl \
   CFStateChangeEvent.webidl \
--- a/js/xpconnect/src/Makefile.in
+++ b/js/xpconnect/src/Makefile.in
@@ -29,16 +29,22 @@ LOCAL_INCLUDES = \
 		-I$(topsrcdir)/content/svg/content/src \
 		-I$(topsrcdir)/layout/style \
 		-I$(topsrcdir)/layout/base \
 		-I$(topsrcdir)/dom/base \
 		-I$(topsrcdir)/xpcom/ds \
 		-I$(topsrcdir)/js/ipc \
 		$(NULL)
 
+ifdef MOZ_B2G_BT
+LOCAL_INCLUDES += \
+    -I$(topsrcdir)/dom/bluetooth \
+    $(NULL)
+endif
+
 SHARED_LIBRARY_LIBS = \
   ../loader/$(LIB_PREFIX)jsloader_s.$(LIB_SUFFIX) \
   ../wrappers/$(LIB_PREFIX)xpcwrappers_s.$(LIB_SUFFIX) \
   $(NULL)
 
 EXTRA_MDDEPEND_FILES = dom_qsgen.pp dictionary_helper_gen.pp event_impl_gen.pp
 
 include $(topsrcdir)/config/rules.mk
--- a/js/xpconnect/src/event_impl_gen.conf.in
+++ b/js/xpconnect/src/event_impl_gen.conf.in
@@ -72,14 +72,15 @@ special_includes = [
 exclude_automatic_type_include = [
     'nsISupports',
     'mozIDOMApplication',
     'nsIDOMBlob'
   ]
 
 """ Map xpidl interface names to implementation classes. The third column is the canonical interface. """
 xpidl_to_native = [
+    ['nsIDOMBluetoothDevice', 'bluetooth::BluetoothDevice', 'nsIDOMBluetoothDevice'],
     ['nsIDOMDocument', 'nsIDocument', 'nsIDocument'],
     ['nsIDOMElement', 'mozilla::dom::Element', 'mozilla::dom::Element'],
     ['nsIDOMCSSStyleSheet', 'nsCSSStyleSheet', 'nsIStyleSheet'],
     ['nsIDOMGamepad', 'Gamepad', 'nsIDOMGamepad']
   ]
 
--- a/mobile/android/installer/package-manifest.in
+++ b/mobile/android/installer/package-manifest.in
@@ -278,16 +278,18 @@
 @BINPATH@/components/xultmpl.xpt
 @BINPATH@/components/zipwriter.xpt
 
 ; JavaScript components
 @BINPATH@/components/ConsoleAPI.manifest
 @BINPATH@/components/ConsoleAPI.js
 @BINPATH@/components/ContactManager.js
 @BINPATH@/components/ContactManager.manifest
+@BINPATH@/components/PhoneNumberService.js
+@BINPATH@/components/PhoneNumberService.manifest
 @BINPATH@/components/SettingsManager.js
 @BINPATH@/components/SettingsManager.manifest
 @BINPATH@/components/SettingsService.js
 @BINPATH@/components/SettingsService.manifest
 @BINPATH@/components/BrowserElementParent.manifest
 @BINPATH@/components/BrowserElementParent.js
 @BINPATH@/components/FeedProcessor.manifest
 @BINPATH@/components/FeedProcessor.js
--- a/testing/mochitest/b2g.json
+++ b/testing/mochitest/b2g.json
@@ -27,16 +27,17 @@
     "content/media/test/test_delay_load.html": "6 failures",
     "content/media/test/test_error_on_404.html": "timed out",
     "content/media/test/test_framebuffer.html": "timed out",
     "content/media/test/test_info_leak.html": "2 failures",
     "content/media/test/test_load.html": "Timed out after gizmo.mp4",
     "content/media/test/test_load_candidates.html": "timed out",
     "content/media/test/test_load_same_resource.html": "",
     "content/media/test/test_media_selection.html": "timed out",
+    "content/media/test/test_mediarecorder_avoid_recursion.html": "guM isn't ready on b2g, bug 903765",
     "content/media/test/test_metadata.html": "",
     "content/media/test/test_mozHasAudio.html": "",
     "content/media/test/test_play_events.html": "Last event should be canplaythrough for gizmo.mp4 - got playing, expected canplaythrough",
     "content/media/test/test_play_events_2.html": "Last event should be canplaythrough for gizmo.mp4 - got playing, expected canplaythrough",
     "content/media/test/test_playback.html": "Test timed out, bug 668973?",
     "content/media/test/test_playback_rate_playpause.html": "",
     "content/media/test/test_progress.html": "bug 901716 - timeouts",
     "content/media/test/test_reactivate.html": "timed out in small-shot.mp3",
@@ -77,17 +78,16 @@
     "content/base/test/test_CSP_inlinestyle.html":"",
     "content/base/test/test_XHRSendData.html":"",
     "content/base/test/test_XHR_parameters.html":"",
     "content/base/test/test_XHR_system.html":"",
     "content/base/test/test_base.xhtml":"",
     "content/base/test/test_bug338583.html":"",
     "content/base/test/test_bug372086.html":"",
     "content/base/test/test_bug466080.html":"",
-    "content/base/test/test_bug475156.html":"",
     "content/base/test/test_bug590870.html":"",
     "content/base/test/test_bug666604.html":"",
     "content/base/test/test_bug675121.html":"",
     "content/base/test/test_classList.html":"",
     "content/base/test/test_title.html":"",
     "content/canvas/test/crossorigin/test_video_crossorigin.html":"",
     "content/events/test/test_bug422132.html":"",
     "content/events/test/test_bug426082.html":"",