Merge mozilla-central and b2g-inbound
authorEd Morley <emorley@mozilla.com>
Fri, 02 Aug 2013 13:51:22 +0100
changeset 153401 09a8e6c3e1e294f880198e25fbb76718ed74bcb0
parent 153396 d3a0ac52d5d44452afc354567dc4ed527dd9d393 (current diff)
parent 153400 739e82b9a88463c4e2251ca04279019b70bab1ea (diff)
child 153402 e1f57799c92fa59be8aa7f53460213a30e737a66
push id2859
push userakeybl@mozilla.com
push dateMon, 16 Sep 2013 19:14:59 +0000
treeherdermozilla-beta@87d3c51cd2bf [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone25.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 mozilla-central and b2g-inbound
dom/bluetooth/BluetoothAdapter.cpp
dom/webidl/WebIDL.mk
--- a/content/base/src/nsGkAtomList.h
+++ b/content/base/src/nsGkAtomList.h
@@ -626,16 +626,17 @@ GK_ATOM(null, "null")
 GK_ATOM(object, "object")
 GK_ATOM(objectType, "object-type")
 GK_ATOM(observer, "observer")
 GK_ATOM(observes, "observes")
 GK_ATOM(odd, "odd")
 GK_ATOM(OFF, "OFF")
 GK_ATOM(ol, "ol")
 GK_ATOM(omitXmlDeclaration, "omit-xml-declaration")
+GK_ATOM(ona2dpstatuschanged, "ona2dpstatuschanged")
 GK_ATOM(onabort, "onabort")
 GK_ATOM(onadapteradded, "onadapteradded")
 GK_ATOM(onafterprint, "onafterprint")
 GK_ATOM(onafterscriptexecute, "onafterscriptexecute")
 GK_ATOM(onalerting, "onalerting")
 GK_ATOM(onanimationend, "onanimationend")
 GK_ATOM(onanimationiteration, "onanimationiteration")
 GK_ATOM(onanimationstart, "onanimationstart")
@@ -708,16 +709,17 @@ GK_ATOM(ondrop, "ondrop")
 GK_ATOM(onenabled, "onenabled")
 GK_ATOM(onerror, "onerror")
 GK_ATOM(onfailed, "onfailed")
 GK_ATOM(onfocus, "onfocus")
 GK_ATOM(onget, "onget")
 GK_ATOM(onhashchange, "onhashchange")
 GK_ATOM(onheadphoneschange, "onheadphoneschange")
 GK_ATOM(onheld, "onheld")
+GK_ATOM(onhfpstatuschanged, "onhfpstatuschanged")
 GK_ATOM(onholding, "onholding")
 GK_ATOM(oniccinfochange, "oniccinfochange")
 GK_ATOM(onicccardlockerror, "onicccardlockerror")
 GK_ATOM(onincoming, "onincoming")
 GK_ATOM(oninput, "oninput")
 GK_ATOM(oninvalid, "oninvalid")
 GK_ATOM(onkeydown, "onkeydown")
 GK_ATOM(onkeypress, "onkeypress")
@@ -751,29 +753,31 @@ GK_ATOM(onobsolete, "onobsolete")
 GK_ATOM(ononline, "ononline")
 GK_ATOM(onoffline, "onoffline")
 GK_ATOM(onopen, "onopen")
 GK_ATOM(onoverflow, "onoverflow")
 GK_ATOM(onoverflowchanged, "onoverflowchanged")
 GK_ATOM(onpagehide, "onpagehide")
 GK_ATOM(onpageshow, "onpageshow")
 GK_ATOM(onpaint, "onpaint")
+GK_ATOM(onpairedstatuschanged, "onpairedstatuschanged")
 GK_ATOM(onpaste, "onpaste")
 GK_ATOM(onpopuphidden, "onpopuphidden")
 GK_ATOM(onpopuphiding, "onpopuphiding")
 GK_ATOM(onpopupshowing, "onpopupshowing")
 GK_ATOM(onpopupshown, "onpopupshown")
 GK_ATOM(onreadystatechange, "onreadystatechange")
 GK_ATOM(onreceived, "onreceived")
 GK_ATOM(onretrieving, "onretrieving")
 GK_ATOM(onRequest, "onRequest")
 GK_ATOM(onreset, "onreset")
 GK_ATOM(onresuming, "onresuming")
 GK_ATOM(onMozBeforeResize, "onMozBeforeResize")
 GK_ATOM(onresize, "onresize")
+GK_ATOM(onscostatuschanged, "onscostatuschanged")
 GK_ATOM(onscroll, "onscroll")
 GK_ATOM(onselect, "onselect")
 GK_ATOM(onsending, "onsending")
 GK_ATOM(onsent, "onsent")
 GK_ATOM(onset, "onset")
 GK_ATOM(onshow, "onshow")
 GK_ATOM(onstatechange, "onstatechange")
 GK_ATOM(onstatuschanged, "onstatuschanged")
--- a/dom/bluetooth/BluetoothA2dpManager.cpp
+++ b/dom/bluetooth/BluetoothA2dpManager.cpp
@@ -199,17 +199,18 @@ BluetoothA2dpManager::HandleSinkProperty
   MOZ_ASSERT(arr.Length() == 1);
 
   const nsString& name = arr[0].name();
   const BluetoothValue& value = arr[0].value();
   if (name.EqualsLiteral("Connected")) {
     // Indicates if a stream is setup to a A2DP sink on the remote device.
     MOZ_ASSERT(value.type() == BluetoothValue::Tbool);
     mA2dpConnected = value.get_bool();
-    NotifyStatusChanged();
+    NotifyConnectionStatusChanged();
+    DispatchConnectionStatusChanged();
   } else if (name.EqualsLiteral("Playing")) {
     // Indicates if a stream is active to a A2DP sink on the remote device.
     MOZ_ASSERT(value.type() == BluetoothValue::Tbool);
     mPlaying = value.get_bool();
   } else if (name.EqualsLiteral("State")) {
     MOZ_ASSERT(value.type() == BluetoothValue::TnsString);
     HandleSinkStateChanged(StatusStringToSinkState(value.get_nsString()));
   } else {
@@ -249,17 +250,26 @@ BluetoothA2dpManager::HandleSinkStateCha
   if (aState == SinkState::SINK_DISCONNECTED) {
     mDeviceAddress.Truncate();
   }
 
   mSinkState = aState;
 }
 
 void
-BluetoothA2dpManager::NotifyStatusChanged()
+BluetoothA2dpManager::DispatchConnectionStatusChanged()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  DispatchStatusChangedEvent(
+    NS_LITERAL_STRING(A2DP_STATUS_CHANGED_ID), mDeviceAddress, mA2dpConnected);
+}
+
+void
+BluetoothA2dpManager::NotifyConnectionStatusChanged()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   // Broadcast system message to Gaia
   NS_NAMED_LITERAL_STRING(type, BLUETOOTH_A2DP_STATUS_CHANGED_ID);
   InfallibleTArray<BluetoothNamedValue> parameters;
 
   BluetoothValue v = mA2dpConnected;
--- a/dom/bluetooth/BluetoothA2dpManager.h
+++ b/dom/bluetooth/BluetoothA2dpManager.h
@@ -67,22 +67,24 @@ public:
 
 private:
   BluetoothA2dpManager();
   bool Init();
 
   void HandleSinkStateChanged(SinkState aState);
   void HandleShutdown();
 
-  void NotifyStatusChanged();
+  void DispatchConnectionStatusChanged();
+  void NotifyConnectionStatusChanged();
+
+  nsString mDeviceAddress;
 
   // A2DP data member
   bool mA2dpConnected;
   bool mPlaying;
-  nsString mDeviceAddress;
   SinkState mSinkState;
 
   // AVRCP data member
   bool mAvrcpConnected;
   nsString mAlbum;
   nsString mArtist;
   nsString mTitle;
   uint32_t mDuration;
--- a/dom/bluetooth/BluetoothAdapter.cpp
+++ b/dom/bluetooth/BluetoothAdapter.cpp
@@ -5,16 +5,17 @@
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "base/basictypes.h"
 #include "GeneratedEvents.h"
 #include "nsContentUtils.h"
 #include "nsCxPusher.h"
 #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/ContentChild.h"
 #include "mozilla/LazyIdleThread.h"
 #include "mozilla/Util.h"
@@ -328,24 +329,44 @@ BluetoothAdapter::Notify(const Bluetooth
     nsCOMPtr<nsIDOMEvent> event;
     NS_NewDOMBluetoothDeviceEvent(getter_AddRefs(event), this, nullptr, nullptr);
 
     nsCOMPtr<nsIDOMBluetoothDeviceEvent> e = do_QueryInterface(event);
     e->InitBluetoothDeviceEvent(NS_LITERAL_STRING("devicefound"),
                                 false, false, device);
     DispatchTrustedEvent(event);
   } else if (aData.name().EqualsLiteral("PropertyChanged")) {
-    NS_ASSERTION(v.type() == BluetoothValue::TArrayOfBluetoothNamedValue,
-                 "PropertyChanged: Invalid value type");
+    MOZ_ASSERT(v.type() == BluetoothValue::TArrayOfBluetoothNamedValue);
+    const InfallibleTArray<BluetoothNamedValue>& arr =
+      v.get_ArrayOfBluetoothNamedValue();
+
+    MOZ_ASSERT(arr.Length() == 1);
+    SetPropertyByValue(arr[0]);
+  } else if (aData.name().EqualsLiteral(PAIRED_STATUS_CHANGED_ID) ||
+             aData.name().EqualsLiteral(HFP_STATUS_CHANGED_ID) ||
+             aData.name().EqualsLiteral(SCO_STATUS_CHANGED_ID) ||
+             aData.name().EqualsLiteral(A2DP_STATUS_CHANGED_ID)) {
+    MOZ_ASSERT(v.type() == BluetoothValue::TArrayOfBluetoothNamedValue);
     const InfallibleTArray<BluetoothNamedValue>& arr =
       v.get_ArrayOfBluetoothNamedValue();
 
-    NS_ASSERTION(arr.Length() == 1,
-                 "Got more than one property in a change message!");
-    SetPropertyByValue(arr[0]);
+    MOZ_ASSERT(arr.Length() == 2 &&
+               arr[0].value().type() == BluetoothValue::TnsString &&
+               arr[1].value().type() == BluetoothValue::Tbool);
+    nsString address = arr[0].value().get_nsString();
+    bool status = arr[1].value().get_bool();
+
+    nsCOMPtr<nsIDOMEvent> event;
+    NS_NewDOMBluetoothStatusChangedEvent(
+      getter_AddRefs(event), this, nullptr, nullptr);
+
+    nsCOMPtr<nsIDOMBluetoothStatusChangedEvent> e = do_QueryInterface(event);
+    e->InitBluetoothStatusChangedEvent(aData.name(), false, false,
+                                       address, status);
+    DispatchTrustedEvent(event);
   } else {
 #ifdef DEBUG
     nsCString warningMsg;
     warningMsg.AssignLiteral("Not handling adapter signal: ");
     warningMsg.Append(NS_ConvertUTF16toUTF8(aData.name()));
     NS_WARNING(warningMsg.get());
 #endif
   }
@@ -900,8 +921,12 @@ BluetoothAdapter::SendMediaPlayStatus(co
                      status.mPlayStatus,
                      results);
 
   req.forget(aRequest);
   return NS_OK;
 }
 
 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)
--- a/dom/bluetooth/BluetoothCommon.h
+++ b/dom/bluetooth/BluetoothCommon.h
@@ -47,22 +47,36 @@ extern bool gBluetoothDebugFlag;
   using namespace mozilla::dom::bluetooth;
 
 #define KEY_LOCAL_AGENT  "/B2G/bluetooth/agent"
 #define KEY_REMOTE_AGENT "/B2G/bluetooth/remote_device_agent"
 #define KEY_MANAGER      "/B2G/bluetooth/manager"
 #define KEY_ADAPTER      "/B2G/bluetooth/adapter"
 
 /**
- * When connection status of Bluetooth profiles change, we'll notify observers
- * of following topics.
+ * When the connection status of a Bluetooth profile is changed, we'll notify
+ * observers which register the following topics.
  */
-#define BLUETOOTH_HFP_STATUS_CHANGED_ID      "bluetooth-hfp-status-changed"
-#define BLUETOOTH_SCO_STATUS_CHANGED_ID      "bluetooth-sco-status-changed"
-#define BLUETOOTH_A2DP_STATUS_CHANGED_ID     "bluetooth-a2dp-status-changed"
+#define BLUETOOTH_A2DP_STATUS_CHANGED_ID "bluetooth-a2dp-status-changed"
+#define BLUETOOTH_HFP_STATUS_CHANGED_ID  "bluetooth-hfp-status-changed"
+#define BLUETOOTH_SCO_STATUS_CHANGED_ID  "bluetooth-sco-status-changed"
+
+/**
+ * When the connection status of a Bluetooth profile is changed, we'll
+ * distribute one of the following events.
+ */
+#define A2DP_STATUS_CHANGED_ID               "a2dpstatuschanged"
+#define HFP_STATUS_CHANGED_ID                "hfpstatuschanged"
+#define SCO_STATUS_CHANGED_ID                "scostatuschanged"
+
+/**
+ * When the pair status of a Bluetooth device is changed, we'll distribute an
+ * event.
+ */
+#define PAIRED_STATUS_CHANGED_ID             "pairedstatuschanged"
 
 // Bluetooth address format: xx:xx:xx:xx:xx:xx (or xx_xx_xx_xx_xx_xx)
 #define BLUETOOTH_ADDRESS_LENGTH 17
 #define BLUETOOTH_ADDRESS_NONE   "00:00:00:00:00:00"
 
 BEGIN_BLUETOOTH_NAMESPACE
 
 enum BluetoothSocketType {
--- a/dom/bluetooth/BluetoothHfpManager.cpp
+++ b/dom/bluetooth/BluetoothHfpManager.cpp
@@ -449,50 +449,67 @@ BluetoothHfpManager::Get()
   BluetoothHfpManager* manager = new BluetoothHfpManager();
   NS_ENSURE_TRUE(manager->Init(), nullptr);
 
   sBluetoothHfpManager = manager;
   return sBluetoothHfpManager;
 }
 
 void
-BluetoothHfpManager::NotifyStatusChanged(const char* aType)
+BluetoothHfpManager::DispatchConnectionStatusChanged(const nsAString& aType)
 {
-  // Broadcast system message to Gaia
+  MOZ_ASSERT(NS_IsMainThread());
+
+  bool status = false;
+  if (aType.EqualsLiteral(HFP_STATUS_CHANGED_ID)) {
+    status = IsConnected();
+  } else if (aType.EqualsLiteral(SCO_STATUS_CHANGED_ID)) {
+    status = IsScoConnected();
+  } else {
+    BT_WARNING("Wrong type for DispatchConnectionStatusChanged");
+    return;
+  }
+
+  DispatchStatusChangedEvent(aType, mDeviceAddress, status);
+}
+
+void
+BluetoothHfpManager::NotifyConnectionStatusChanged(const nsAString& aType)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
   BluetoothValue v;
   InfallibleTArray<BluetoothNamedValue> parameters;
-  nsAutoString type, name;
-  type = NS_ConvertUTF8toUTF16(aType);
-  name.AssignLiteral("connected");
-
-  if (type.EqualsLiteral(BLUETOOTH_HFP_STATUS_CHANGED_ID)) {
+  nsString name = NS_LITERAL_STRING("connected");
+  if (aType.EqualsLiteral(BLUETOOTH_HFP_STATUS_CHANGED_ID)) {
     v = IsConnected();
-  } else if (type.EqualsLiteral(BLUETOOTH_SCO_STATUS_CHANGED_ID)) {
+  } else if (aType.EqualsLiteral(BLUETOOTH_SCO_STATUS_CHANGED_ID)) {
     v = IsScoConnected();
   } else {
-    NS_WARNING("Wrong type for NotifyStatusChanged");
+    BT_WARNING("Wrong type for NotifyConnectionStatusChanged");
     return;
   }
   parameters.AppendElement(BluetoothNamedValue(name, v));
 
   name.AssignLiteral("address");
   v = mDeviceAddress;
   parameters.AppendElement(BluetoothNamedValue(name, v));
 
-  if (!BroadcastSystemMessage(type, parameters)) {
+  if (!BroadcastSystemMessage(aType, parameters)) {
     NS_WARNING("Failed to broadcast system message to settings");
   }
 
   // Notify Gecko observers
   nsCOMPtr<nsIObserverService> obs =
     do_GetService("@mozilla.org/observer-service;1");
   NS_ENSURE_TRUE_VOID(obs);
 
-  if (NS_FAILED(obs->NotifyObservers(this, aType, mDeviceAddress.get()))) {
-    NS_WARNING("Failed to notify bluetooth-sco-status-changed observsers!");
+  if (NS_FAILED(obs->NotifyObservers(this, NS_ConvertUTF16toUTF8(aType).get(),
+                                     mDeviceAddress.get()))) {
+    NS_WARNING("Failed to notify observsers!");
   }
 }
 
 void
 BluetoothHfpManager::NotifyDialer(const nsAString& aCommand)
 {
   nsString type, name;
   BluetoothValue v;
@@ -1477,17 +1494,18 @@ BluetoothHfpManager::OnConnectSuccess(Bl
     mRunnable = nullptr;
   }
 
   mFirstCKPD = true;
 
   // Cache device path for NotifySettings() since we can't get socket address
   // when a headset disconnect with us
   mSocket->GetAddress(mDeviceAddress);
-  NotifyStatusChanged(BLUETOOTH_HFP_STATUS_CHANGED_ID);
+  NotifyConnectionStatusChanged(NS_LITERAL_STRING(BLUETOOTH_HFP_STATUS_CHANGED_ID));
+  DispatchConnectionStatusChanged(NS_LITERAL_STRING(HFP_STATUS_CHANGED_ID));
 
   ListenSco();
 
   BluetoothA2dpManager* a2dp = BluetoothA2dpManager::Get();
   NS_ENSURE_TRUE_VOID(a2dp);
   a2dp->Connect(mDeviceAddress);
 }
 
@@ -1532,17 +1550,18 @@ BluetoothHfpManager::OnDisconnect(Blueto
     // Do nothing when a listening server socket is closed.
     return;
   }
 
   mSocket = nullptr;
   DisconnectSco();
 
   Listen();
-  NotifyStatusChanged(BLUETOOTH_HFP_STATUS_CHANGED_ID);
+  NotifyConnectionStatusChanged(NS_LITERAL_STRING(BLUETOOTH_HFP_STATUS_CHANGED_ID));
+  DispatchConnectionStatusChanged(NS_LITERAL_STRING(HFP_STATUS_CHANGED_ID));
   Reset();
 }
 
 void
 BluetoothHfpManager::OnUpdateSdpRecords(const nsAString& aDeviceAddress)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(!aDeviceAddress.IsEmpty());
@@ -1612,17 +1631,18 @@ BluetoothHfpManager::OnScoConnectSuccess
 {
   // For active connection request, we need to reply the DOMRequest
   if (mScoRunnable) {
     DispatchBluetoothReply(mScoRunnable,
                            BluetoothValue(true), EmptyString());
     mScoRunnable = nullptr;
   }
 
-  NotifyStatusChanged(BLUETOOTH_SCO_STATUS_CHANGED_ID);
+  NotifyConnectionStatusChanged(NS_LITERAL_STRING(BLUETOOTH_SCO_STATUS_CHANGED_ID));
+  DispatchConnectionStatusChanged(NS_LITERAL_STRING(SCO_STATUS_CHANGED_ID));
 
   mScoSocketStatus = mScoSocket->GetConnectionStatus();
 }
 
 void
 BluetoothHfpManager::OnScoConnectError()
 {
   if (mScoRunnable) {
@@ -1635,17 +1655,18 @@ BluetoothHfpManager::OnScoConnectError()
   ListenSco();
 }
 
 void
 BluetoothHfpManager::OnScoDisconnect()
 {
   if (mScoSocketStatus == SocketConnectionStatus::SOCKET_CONNECTED) {
     ListenSco();
-    NotifyStatusChanged(BLUETOOTH_SCO_STATUS_CHANGED_ID);
+    NotifyConnectionStatusChanged(NS_LITERAL_STRING(BLUETOOTH_SCO_STATUS_CHANGED_ID));
+    DispatchConnectionStatusChanged(NS_LITERAL_STRING(SCO_STATUS_CHANGED_ID));
   }
 }
 
 bool
 BluetoothHfpManager::IsConnected()
 {
   if (mSocket) {
     return mSocket->GetConnectionStatus() ==
--- a/dom/bluetooth/BluetoothHfpManager.h
+++ b/dom/bluetooth/BluetoothHfpManager.h
@@ -112,18 +112,19 @@ private:
 
   bool Init();
   void Notify(const hal::BatteryInformation& aBatteryInfo);
   void Reset();
   void ResetCallArray();
   uint32_t FindFirstCall(uint16_t aState);
   uint32_t GetNumberOfCalls(uint16_t aState);
 
+  void DispatchConnectionStatusChanged(const nsAString& aType);
   void NotifyDialer(const nsAString& aCommand);
-  void NotifyStatusChanged(const char* aType);
+  void NotifyConnectionStatusChanged(const nsAString& aType);
 
   bool SendCommand(const char* aCommand, uint32_t aValue = 0);
   bool SendLine(const char* aMessage);
   void UpdateCIND(uint8_t aType, uint8_t aValue, bool aSend = true);
   void OnScoConnectSuccess();
   void OnScoConnectError();
   void OnScoDisconnect();
 
--- a/dom/bluetooth/BluetoothService.cpp
+++ b/dom/bluetooth/BluetoothService.cpp
@@ -783,19 +783,19 @@ BluetoothService::Notify(const Bluetooth
   } else if (aData.name().EqualsLiteral("Authorize")) {
     MOZ_ASSERT(aData.value().get_ArrayOfBluetoothNamedValue().Length() == 2,
       "Authorize: Wrong length of parameters");
     type.AssignLiteral("bluetooth-authorize");
   } else if (aData.name().EqualsLiteral("Cancel")) {
     MOZ_ASSERT(aData.value().get_ArrayOfBluetoothNamedValue().Length() == 0,
       "Cancel: Wrong length of parameters");
     type.AssignLiteral("bluetooth-cancel");
-  } else if (aData.name().EqualsLiteral("PairedStatusChanged")) {
+  } else if (aData.name().EqualsLiteral(PAIRED_STATUS_CHANGED_ID)) {
     MOZ_ASSERT(aData.value().get_ArrayOfBluetoothNamedValue().Length() == 1,
-      "PairedStatusChagned: Wrong length of parameters");
+      "pairedstatuschanged: Wrong length of parameters");
     type.AssignLiteral("bluetooth-pairedstatuschanged");
   } else {
     nsCString warningMsg;
     warningMsg.AssignLiteral("Not handling service signal: ");
     warningMsg.Append(NS_ConvertUTF16toUTF8(aData.name()));
     NS_WARNING(warningMsg.get());
     return;
   }
--- a/dom/bluetooth/BluetoothUtils.cpp
+++ b/dom/bluetooth/BluetoothUtils.cpp
@@ -2,16 +2,17 @@
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "base/basictypes.h"
 
 #include "BluetoothReplyRunnable.h"
+#include "BluetoothService.h"
 #include "BluetoothUtils.h"
 #include "jsapi.h"
 #include "mozilla/Scoped.h"
 #include "mozilla/dom/bluetooth/BluetoothTypes.h"
 #include "nsContentUtils.h"
 #include "nsCxPusher.h"
 #include "nsIScriptContext.h"
 #include "nsISystemMessagesInternal.h"
@@ -168,9 +169,29 @@ ParseAtCommand(const nsACString& aAtComm
       begin = i + 1;
     }
   }
 
   nsCString tmp(nsDependentCSubstring(aAtCommand, begin));
   aRetValues.AppendElement(tmp);
 }
 
+void
+DispatchStatusChangedEvent(const nsAString& aType,
+                           const nsAString& aAddress,
+                           bool aStatus)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  InfallibleTArray<BluetoothNamedValue> data;
+  data.AppendElement(
+    BluetoothNamedValue(NS_LITERAL_STRING("address"), nsString(aAddress)));
+  data.AppendElement(
+    BluetoothNamedValue(NS_LITERAL_STRING("status"), aStatus));
+
+  BluetoothSignal signal(nsString(aType), NS_LITERAL_STRING(KEY_ADAPTER), data);
+
+  BluetoothService* bs = BluetoothService::Get();
+  NS_ENSURE_TRUE_VOID(bs);
+  bs->DistributeSignal(signal);
+}
+
 END_BLUETOOTH_NAMESPACE
--- a/dom/bluetooth/BluetoothUtils.h
+++ b/dom/bluetooth/BluetoothUtils.h
@@ -38,11 +38,16 @@ void
 DispatchBluetoothReply(BluetoothReplyRunnable* aRunnable,
                        const BluetoothValue& aValue,
                        const nsAString& aErrorStr);
 
 void
 ParseAtCommand(const nsACString& aAtCommand, const int aStart,
                nsTArray<nsCString>& aRetValues);
 
+void
+DispatchStatusChangedEvent(const nsAString& aType,
+                           const nsAString& aDeviceAddress,
+                           bool aStatus);
+
 END_BLUETOOTH_NAMESPACE
 
 #endif
--- a/dom/bluetooth/linux/BluetoothDBusService.cpp
+++ b/dom/bluetooth/linux/BluetoothDBusService.cpp
@@ -462,16 +462,18 @@ GetIntCallback(DBusMessage* aMsg, void* 
   RunDBusCallback(aMsg, aBluetoothReplyRunnable,
                   UnpackIntMessage);
 }
 
 #ifdef DEBUG
 static void
 CheckForError(DBusMessage* aMsg, void *aParam, const nsAString& aError)
 {
+  NS_ENSURE_TRUE_VOID(aMsg);
+
   BluetoothValue v;
   nsAutoString replyError;
   UnpackVoidMessage(aMsg, nullptr, v, replyError);
   if (!v.get_bool()) {
     BT_WARNING(NS_ConvertUTF16toUTF8(aError).get());
   }
 }
 #endif
@@ -1479,26 +1481,37 @@ EventFilter(DBusConnection* aConn, DBusM
   } else if (dbus_message_is_signal(aMsg, DBUS_DEVICE_IFACE,
                                     "PropertyChanged")) {
     ParsePropertyChange(aMsg,
                         v,
                         errorStr,
                         sDeviceProperties,
                         ArrayLength(sDeviceProperties));
 
-    // Fire another task for sending system message of
-    // "bluetooth-pairedstatuschanged"
     BluetoothNamedValue& property = v.get_ArrayOfBluetoothNamedValue()[0];
     if (property.name().EqualsLiteral("Paired")) {
+      // Original approach: Broadcast system message of
+      // "bluetooth-pairedstatuschanged" from BluetoothService.
       BluetoothValue newValue(v);
       ToLowerCase(newValue.get_ArrayOfBluetoothNamedValue()[0].name());
-      BluetoothSignal signal(NS_LITERAL_STRING("PairedStatusChanged"),
+      BluetoothSignal signal(NS_LITERAL_STRING(PAIRED_STATUS_CHANGED_ID),
                              NS_LITERAL_STRING(KEY_LOCAL_AGENT),
                              newValue);
       NS_DispatchToMainThread(new DistributeBluetoothSignalTask(signal));
+
+      // New approach: Dispatch event from BluetoothAdapter
+      bool status = property.value();
+      InfallibleTArray<BluetoothNamedValue> parameters;
+      parameters.AppendElement(
+        BluetoothNamedValue(NS_LITERAL_STRING("address"), signalPath));
+      parameters.AppendElement(
+        BluetoothNamedValue(NS_LITERAL_STRING("status"), status));
+      signal.path() = NS_LITERAL_STRING(KEY_ADAPTER);
+      signal.value() = parameters;
+      NS_DispatchToMainThread(new DistributeBluetoothSignalTask(signal));
     }
   } else if (dbus_message_is_signal(aMsg, DBUS_MANAGER_IFACE, "AdapterAdded")) {
     const char* str;
     if (!dbus_message_get_args(aMsg, &err,
                                DBUS_TYPE_OBJECT_PATH, &str,
                                DBUS_TYPE_INVALID)) {
       LOG_AND_FREE_DBUS_ERROR_WITH_MSG(&err, aMsg);
       errorStr.AssignLiteral("Cannot parse manager path!");
--- a/dom/bluetooth/moz.build
+++ b/dom/bluetooth/moz.build
@@ -17,16 +17,17 @@
 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',
         'BluetoothReplyRunnable.cpp',
--- a/dom/bluetooth/nsIDOMBluetoothAdapter.idl
+++ b/dom/bluetooth/nsIDOMBluetoothAdapter.idl
@@ -38,17 +38,17 @@ dictionary MediaPlayStatus
   unsigned long  position;
   DOMString  playStatus;
 };
 
 interface nsIDOMDOMRequest;
 interface nsIDOMBlob;
 interface nsIDOMBluetoothDevice;
 
-[scriptable, builtinclass, uuid(1a0c6c90-23e3-4f4c-8076-98e4341c2024)]
+[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;
@@ -97,9 +97,21 @@ interface nsIDOMBluetoothAdapter : nsIDO
 
   // 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;
 };
new file mode 100644
--- /dev/null
+++ b/dom/bluetooth/nsIDOMBluetoothStatusChangedEvent.idl
@@ -0,0 +1,24 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsIDOMEvent.idl"
+
+[scriptable, builtinclass, uuid(07f6d8d0-d364-4033-92e2-d69de323d7b7)]
+interface nsIDOMBluetoothStatusChangedEvent : nsIDOMEvent
+{
+  readonly attribute DOMString address;
+  readonly attribute boolean status;
+
+  [noscript] void initBluetoothStatusChangedEvent(in DOMString aType,
+                                                  in boolean aCanBubble,
+                                                  in boolean aCancelable,
+                                                  in DOMString aAddress,
+                                                  in boolean aStatus);
+};
+
+dictionary BluetoothStatusChangedEventInit : EventInit
+{
+  DOMString address;
+  bool status;
+};
new file mode 100644
--- /dev/null
+++ b/dom/webidl/BluetoothStatusChangedEvent.webidl
@@ -0,0 +1,18 @@
+/* -*- 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/.
+ */
+
+[Constructor(DOMString type, optional BluetoothStatusChangedEventInit eventInitDict), HeaderFile="GeneratedEventClasses.h"]
+interface BluetoothStatusChangedEvent : Event
+{
+  readonly attribute DOMString address;
+  readonly attribute boolean status;
+};
+
+dictionary BluetoothStatusChangedEventInit : EventInit
+{
+  DOMString address = "";
+  boolean status = false;
+};
--- a/dom/webidl/WebIDL.mk
+++ b/dom/webidl/WebIDL.mk
@@ -464,16 +464,17 @@ webidl_files += \
   StyleSheetApplicableStateChangeEvent.webidl \
   StyleSheetChangeEvent.webidl \
   UserProximityEvent.webidl \
   $(NULL)
 
 ifdef MOZ_B2G_BT
 webidl_files += \
   BluetoothDeviceEvent.webidl \
+  BluetoothStatusChangedEvent.webidl \
   $(NULL)
 endif
 
 ifdef MOZ_B2G_RIL
 webidl_files += \
   CallEvent.webidl \
   CFStateChangeEvent.webidl \
   DataErrorEvent.webidl \
--- a/js/xpconnect/src/event_impl_gen.conf.in
+++ b/js/xpconnect/src/event_impl_gen.conf.in
@@ -24,16 +24,17 @@ simple_events = [
     'DeviceLightEvent',
     'MozApplicationEvent',
     'SmartCardEvent',
     'StyleRuleChangeEvent',
     'StyleSheetChangeEvent',
     'StyleSheetApplicableStateChangeEvent',
 #ifdef MOZ_B2G_BT
     'BluetoothDeviceEvent',
+    'BluetoothStatusChangedEvent',
 #endif
 #ifdef MOZ_B2G_RIL
     'CallEvent',
     'CFStateChangeEvent',
     'DataErrorEvent',
     'IccCardLockErrorEvent',
     'MozWifiStatusChangeEvent',
     'MozWifiConnectionInfoEvent',
new file mode 100644
--- /dev/null
+++ b/testing/marionette/client/marionette/tests/unit/test_switch_remote_frame.py
@@ -0,0 +1,65 @@
+# 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/.
+
+from marionette_test import MarionetteTestCase
+
+
+class TestSwitchRemoteFrame(MarionetteTestCase):
+    def setUp(self):
+        super(TestSwitchRemoteFrame, self).setUp()
+        self.oop_by_default = self.marionette.execute_script("""
+            try {
+              return SpecialPowers.getBoolPref('dom.ipc.browser_frames.oop_by_default');
+            }
+            catch(e) {}
+            """)
+        self.mozBrowserFramesEnabled = self.marionette.execute_script("""
+            try {
+              return SpecialPowers.getBoolPref('dom.mozBrowserFramesEnabled');
+            }
+            catch(e) {}
+            """)
+        self.marionette.execute_script("""
+            SpecialPowers.setBoolPref('dom.ipc.browser_frames.oop_by_default', true);
+            """)
+        self.marionette.execute_script("""
+            SpecialPowers.setBoolPref('dom.mozBrowserFramesEnabled', true);
+            """)
+
+    def test_remote_frame(self):
+        self.marionette.navigate(self.marionette.absolute_url("test.html"))
+        self.marionette.execute_script("SpecialPowers.addPermission('browser', true, document)")
+        self.marionette.execute_script("""
+            let iframe = document.createElement("iframe");
+            SpecialPowers.wrap(iframe).mozbrowser = true;
+            SpecialPowers.wrap(iframe).remote = true;
+            iframe.id = "remote_iframe";
+            iframe.style.height = "100px";
+            iframe.style.width = "100%%";
+            iframe.src = "%s";
+            document.body.appendChild(iframe);
+            """ % self.marionette.absolute_url("test.html"))
+        self.marionette.switch_to_frame("remote_iframe")
+        main_process = self.marionette.execute_script("""
+            return SpecialPowers.isMainProcess();
+            """)
+        self.assertFalse(main_process)
+
+    def tearDown(self):
+        if self.oop_by_default is None:
+            self.marionette.execute_script("""
+                SpecialPowers.clearUserPref('dom.ipc.browser_frames.oop_by_default');
+                """)
+        else:
+            self.marionette.execute_script("""
+                SpecialPowers.setBoolPref('dom.ipc.browser_frames.oop_by_default', %s);
+                """ % 'true' if self.oop_by_default else 'false')
+        if self.mozBrowserFramesEnabled is None:
+            self.marionette.execute_script("""
+                SpecialPowers.clearUserPref('dom.mozBrowserFramesEnabled');
+                """)
+        else:
+            self.marionette.execute_script("""
+                SpecialPowers.setBoolPref('dom.mozBrowserFramesEnabled', %s);
+                """ % 'true' if self.mozBrowserFramesEnabled else 'false')
--- a/testing/marionette/client/marionette/tests/unit/unit-tests.ini
+++ b/testing/marionette/client/marionette/tests/unit/unit-tests.ini
@@ -65,16 +65,18 @@ browser = false
 [test_simpletest_sanity.py]
 [test_simpletest_chrome.js]
 [test_simpletest_timeout.js]
 [test_specialpowers.py]
 [test_switch_frame.py]
 [test_switch_frame_chrome.py]
 b2g = false
 
+[test_switch_remote_frame.py]
+
 [test_window_management.py]
 b2g = false
 
 [test_appcache.py]
 [test_screenshot.py]
 [test_cookies.py]
 b2g = false
 [test_window_title.py]
--- a/toolkit/content/devicestorage.properties
+++ b/toolkit/content/devicestorage.properties
@@ -1,4 +1,4 @@
 # Extensions we recognize for DeviceStorage storage areas
 pictures=*.jpe; *.jpg; *.jpeg; *.gif; *.png; *.bmp;
-music=*.mp3; *.ogg; *.m4a; *.m4b; *.m4p; *.m4r; *.3gp; *.mp4; *.m3u; *.pls; *.opus; *.amr;
+music=*.mp3; *.ogg; *.m4a; *.m4b; *.m4p; *.m4r; *.3gp; *.mp4; *.m3u; *.pls; *.opus; *.amr; *.wav;
 videos=*.mp4; *.mpeg; *.mpg; *.ogv; *.ogx; *.webm; *.3gp; *.ogg; *.m4v;