Merge b2g-inbound to m-c
authorWes Kocher <wkocher@mozilla.com>
Tue, 26 Nov 2013 19:34:07 -0600
changeset 157634 a6a046acc881af9e4879f6d6e180f9e27a3e13ab
parent 157599 d822990ba9ee8e9c8747ba4fb0fdebd74a903b2c (current diff)
parent 157633 a7db5760c6cfcd4d4959033cf2debcc8da167e0e (diff)
child 157658 77b5c6edfe9611b2090adbc9eb8b54cd656c51f1
push id25717
push userkwierso@gmail.com
push dateWed, 27 Nov 2013 01:34:26 +0000
treeherdermozilla-central@a6a046acc881 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone28.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 b2g-inbound to m-c
CLOBBER
dom/base/nsDOMWindowUtils.cpp
dom/ipc/ContentParent.cpp
widget/windows/winrt/APZController.cpp
--- a/b2g/components/PaymentGlue.js
+++ b/b2g/components/PaymentGlue.js
@@ -61,30 +61,32 @@ PaymentUI.prototype = {
       id: id,
       requestId: aRequestId,
       paymentRequests: aRequests
     };
 
     // Once the user confirm the payment request and makes his choice, we get
     // back to the DOM part to get the appropriate payment flow information
     // based on the selected payment provider.
-    content.addEventListener("mozContentEvent", function handleSelection(evt) {
+    this._handleSelection = (function _handleSelection(evt) {
       let msg = evt.detail;
       if (msg.id != id) {
         return;
       }
 
       if (msg.userSelection && aSuccessCb) {
         aSuccessCb.onresult(aRequestId, msg.userSelection);
       } else if (msg.errorMsg) {
         _error(msg.errorMsg);
       }
 
-      content.removeEventListener("mozContentEvent", handleSelection);
-    });
+      content.removeEventListener("mozContentEvent", this._handleSelection);
+      this._handleSelection = null;
+    }).bind(this);
+    content.addEventListener("mozContentEvent", this._handleSelection);
 
     browser.shell.sendChromeEvent(detail);
   },
 
   showPaymentFlow: function showPaymentFlow(aRequestId,
                                             aPaymentFlowInfo,
                                             aErrorCb) {
     let _error = function _error(errorMsg) {
@@ -109,72 +111,104 @@ PaymentUI.prototype = {
       uri: aPaymentFlowInfo.uri,
       method: aPaymentFlowInfo.requestMethod,
       jwt: aPaymentFlowInfo.jwt
     };
 
     // At some point the UI would send the created iframe back so the
     // callbacks for firing DOMRequest events can be loaded on its
     // content.
-    content.addEventListener("mozContentEvent", (function loadPaymentShim(evt) {
-      if (evt.detail.id != id) {
-        content.removeEventListener("mozContentEvent", loadPaymentShim);
+    this._loadPaymentShim = (function _loadPaymentShim(evt) {
+      let msg = evt.detail;
+      if (msg.id != id) {
+        return;
+      }
+
+      if (msg.errorMsg) {
+        content.removeEventListener("mozContentEvent", this._loadPaymentShim);
+        this._loadPaymentShim = null;
+        _error("ERROR_LOADING_PAYMENT_SHIM: " + msg.errorMsg);
+        return;
+      }
+
+      if (!msg.frame) {
+        content.removeEventListener("mozContentEvent", this._loadPaymentShim);
+        this._loadPaymentShim = null;
+        _error("ERROR_LOADING_PAYMENT_SHIM");
         return;
       }
 
       // Try to load the payment shim file containing the payment callbacks
       // in the content script.
-      if (!evt.detail.frame && !evt.detail.errorMsg) {
-        _error("ERROR_LOADING_PAYMENT_SHIM");
-        return;
-      }
-      let frame = evt.detail.frame;
+      let frame = msg.frame;
       let frameLoader = frame.QueryInterface(Ci.nsIFrameLoaderOwner)
-                        .frameLoader;
+                             .frameLoader;
       let mm = frameLoader.messageManager;
       try {
         mm.loadFrameScript(kPaymentShimFile, true);
         mm.sendAsyncMessage("Payment:LoadShim", { requestId: aRequestId });
       } catch (e) {
         if (this._debug) {
           this.LOG("Error loading " + kPaymentShimFile + " as a frame script: "
                     + e);
         }
         _error("ERROR_LOADING_PAYMENT_SHIM");
       } finally {
-        content.removeEventListener("mozContentEvent", loadPaymentShim);
+        content.removeEventListener("mozContentEvent", this._loadPaymentShim);
+        this._loadPaymentShim = null;
       }
-    }).bind(this));
+    }).bind(this);
+    content.addEventListener("mozContentEvent", this._loadPaymentShim);
 
     // We also listen for UI notifications about a closed payment flow. The UI
     // should provide the reason of the closure within the 'errorMsg' parameter
-    this._notifyPayFlowClosed = function _notifyPayFlowClosed (evt) {
-      if (evt.detail.id != id) {
+    this._notifyPayFlowClosed = (function _notifyPayFlowClosed(evt) {
+      let msg = evt.detail;
+      if (msg.id != id) {
+        return;
+      }
+
+      if (msg.type != 'cancel') {
         return;
       }
-      if (evt.detail.errorMsg) {
-        _error(evt.detail.errorMsg);
-        content.removeEventListener("mozContentEvent",
-                                    this._notifyPayFlowClosed);
-        return;
+
+      if (msg.errorMsg) {
+        _error(msg.errorMsg);
       }
-    };
+      content.removeEventListener("mozContentEvent",
+                                  this._notifyPayFlowClosed);
+      this._notifyPayFlowClosed = null;
+    }).bind(this);
     content.addEventListener("mozContentEvent",
-                             this._notifyPayFlowClosed.bind(this));
+                             this._notifyPayFlowClosed);
 
     browser.shell.sendChromeEvent(detail);
   },
 
   cleanup: function cleanup() {
     let browser = Services.wm.getMostRecentWindow("navigator:browser");
     let content = browser.getContentWindow();
     if (!content) {
       return;
     }
-    content.removeEventListener("mozContentEvent", this._notifyPayFlowClosed);
+
+    if (this._handleSelection) {
+      content.removeEventListener("mozContentEvent", this._handleSelection);
+      this._handleSelection = null;
+    }
+
+    if (this._notifyPayFlowClosed) {
+      content.removeEventListener("mozContentEvent", this._notifyPayFlowClosed);
+      this._notifyPayFlowClosed = null;
+    }
+
+    if (this._loadPaymentShim) {
+      content.removeEventListener("mozContentEvent", this._loadPaymentShim);
+      this._loadPaymentShim = null;
+    }
   },
 
   getRandomId: function getRandomId() {
     return uuidgen.generateUUID().toString();
   },
 
   LOG: function LOG(s) {
     if (!this._debug) {
--- a/b2g/config/gaia.json
+++ b/b2g/config/gaia.json
@@ -1,4 +1,4 @@
 {
-    "revision": "fefcf4aab784c6e9a0c8b3f4b282c21fb0e0ac6e", 
+    "revision": "70f416f866858cb2068bffa31118fc4b15b482c9", 
     "repo_path": "/integration/gaia-central"
 }
--- a/content/base/src/nsGkAtomList.h
+++ b/content/base/src/nsGkAtomList.h
@@ -707,16 +707,17 @@ GK_ATOM(ondragover, "ondragover")
 GK_ATOM(ondragstart, "ondragstart")
 GK_ATOM(ondrop, "ondrop")
 GK_ATOM(onenabled, "onenabled")
 GK_ATOM(onemergencycbmodechange, "onemergencycbmodechange")
 GK_ATOM(onerror, "onerror")
 GK_ATOM(onfailed, "onfailed")
 GK_ATOM(onfocus, "onfocus")
 GK_ATOM(onfrequencychange, "onfrequencychange")
+GK_ATOM(onspeakerforcedchange, "onspeakerforcedchange")
 GK_ATOM(onget, "onget")
 GK_ATOM(ongroupchange, "ongroupchange")
 GK_ATOM(onhashchange, "onhashchange")
 GK_ATOM(onheadphoneschange, "onheadphoneschange")
 GK_ATOM(onheld, "onheld")
 GK_ATOM(onhfpstatuschanged, "onhfpstatuschanged")
 GK_ATOM(onholding, "onholding")
 GK_ATOM(oniccchange, "oniccchange")
--- a/content/events/public/nsEventNameList.h
+++ b/content/events/public/nsEventNameList.h
@@ -649,16 +649,21 @@ NON_IDL_EVENT(stop,
               EventNameType_None,
               NS_EVENT)
 
 NON_IDL_EVENT(warning,
               NS_MEDIARECORDER_WARNING,
               EventNameType_None,
               NS_EVENT)
 
+NON_IDL_EVENT(speakerforcedchange,
+              NS_SPEAKERMANAGER_SPEAKERFORCEDCHANGE,
+              EventNameType_None,
+              NS_EVENT)
+
 // Events that only have on* attributes on XUL elements
 NON_IDL_EVENT(text,
               NS_TEXT_TEXT,
               EventNameType_XUL,
               NS_EVENT)
 NON_IDL_EVENT(compositionstart,
               NS_COMPOSITION_START,
               EventNameType_XUL,
--- a/dom/apps/src/PermissionsTable.jsm
+++ b/dom/apps/src/PermissionsTable.jsm
@@ -308,16 +308,21 @@ this.PermissionsTable =  { geolocation: 
                              certified: ALLOW_ACTION,
                              access: ["read", "write"]
                            },
                            "nfc-manager": {
                              app: DENY_ACTION,
                              privileged: DENY_ACTION,
                              certified: ALLOW_ACTION
                            },
+                           "speaker-control": {
+                             app: DENY_ACTION,
+                             privileged: ALLOW_ACTION,
+                             certified: ALLOW_ACTION
+                           },
                          };
 
 /**
  * Append access modes to the permission name as suffixes.
  *   e.g. permission name 'contacts' with ['read', 'write'] =
  *   ['contacts-read', contacts-write']
  * @param string aPermName
  * @param array aAccess
--- a/dom/audiochannel/AudioChannelService.cpp
+++ b/dom/audiochannel/AudioChannelService.cpp
@@ -20,16 +20,17 @@
 #include "nsHashPropertyBag.h"
 #include "nsComponentManagerUtils.h"
 #include "nsServiceManagerUtils.h"
 
 #ifdef MOZ_WIDGET_GONK
 #include "nsJSUtils.h"
 #include "nsCxPusher.h"
 #include "nsIAudioManager.h"
+#include "SpeakerManagerService.h"
 #define NS_AUDIOMANAGER_CONTRACTID "@mozilla.org/telephony/audiomanager;1"
 #endif
 
 using namespace mozilla;
 using namespace mozilla::dom;
 using namespace mozilla::hal;
 
 StaticRefPtr<AudioChannelService> gAudioChannelService;
@@ -165,16 +166,22 @@ AudioChannelService::UnregisterAudioChan
 
   nsAutoPtr<AudioChannelAgentData> data;
   mAgents.RemoveAndForget(aAgent, data);
 
   if (data) {
     UnregisterType(data->mType, data->mElementHidden,
                    CONTENT_PROCESS_ID_MAIN, data->mWithVideo);
   }
+#ifdef MOZ_WIDGET_GONK
+  bool active = AnyAudioChannelIsActive();
+  for (uint32_t i = 0; i < mSpeakerManager.Length(); i++) {
+    mSpeakerManager[i]->SetAudioChannelActive(active);
+  }
+#endif
 }
 
 void
 AudioChannelService::UnregisterType(AudioChannelType aType,
                                     bool aElementHidden,
                                     uint64_t aChildID,
                                     bool aWithVideo)
 {
@@ -555,16 +562,29 @@ NS_IMETHODIMP
 AudioChannelService::Notify(nsITimer* aTimer)
 {
   UnregisterTypeInternal(AUDIO_CHANNEL_TELEPHONY, mTimerElementHidden, mTimerChildID, false);
   mDeferTelChannelTimer = nullptr;
   return NS_OK;
 }
 
 bool
+AudioChannelService::AnyAudioChannelIsActive()
+{
+  for (int i = AUDIO_CHANNEL_INT_LAST - 1;
+       i >= AUDIO_CHANNEL_INT_NORMAL; --i) {
+    if (!mChannelCounters[i].IsEmpty()) {
+      return true;
+    }
+  }
+
+  return false;
+}
+
+bool
 AudioChannelService::ChannelsActiveWithHigherPriorityThan(
   AudioChannelInternalType aType)
 {
   for (int i = AUDIO_CHANNEL_INT_LAST - 1;
        i != AUDIO_CHANNEL_INT_CONTENT_HIDDEN; --i) {
     if (i == aType) {
       return false;
     }
--- a/dom/audiochannel/AudioChannelService.h
+++ b/dom/audiochannel/AudioChannelService.h
@@ -13,17 +13,19 @@
 #include "nsITimer.h"
 
 #include "AudioChannelCommon.h"
 #include "AudioChannelAgent.h"
 #include "nsClassHashtable.h"
 
 namespace mozilla {
 namespace dom {
-
+#ifdef MOZ_WIDGET_GONK
+class SpeakerManagerService;
+#endif
 class AudioChannelService
 : public nsIObserver
 , public nsITimerCallback
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIOBSERVER
   NS_DECL_NSITIMERCALLBACK
@@ -76,16 +78,31 @@ public:
 
   /***
    * AudioChannelManager calls this function to notify the default channel used
    * to adjust volume when there is no any active channel.
    */
   virtual void SetDefaultVolumeControlChannel(AudioChannelType aType,
                                               bool aHidden);
 
+  bool AnyAudioChannelIsActive();
+
+#ifdef MOZ_WIDGET_GONK
+  void RegisterSpeakerManager(SpeakerManagerService* aSpeakerManager)
+  {
+    if (!mSpeakerManager.Contains(aSpeakerManager)) {
+      mSpeakerManager.AppendElement(aSpeakerManager);
+    }
+  }
+
+  void UnregisterSpeakerManager(SpeakerManagerService* aSpeakerManager)
+  {
+    mSpeakerManager.RemoveElement(aSpeakerManager);
+  }
+#endif
 protected:
   void Notify();
 
   /**
    * Send the audio-channel-changed notification for the given process ID if
    * needed.
    */
   void SendAudioChannelChangedNotification(uint64_t aChildID);
@@ -158,17 +175,19 @@ protected:
     const bool mWithVideo;
   };
 
   static PLDHashOperator
   NotifyEnumerator(AudioChannelAgent* aAgent,
                    AudioChannelAgentData* aData, void *aUnused);
 
   nsClassHashtable< nsPtrHashKey<AudioChannelAgent>, AudioChannelAgentData > mAgents;
-
+#ifdef MOZ_WIDGET_GONK
+  nsTArray<SpeakerManagerService*>  mSpeakerManager;
+#endif
   nsTArray<uint64_t> mChannelCounters[AUDIO_CHANNEL_INT_LAST];
 
   AudioChannelType mCurrentHigherChannel;
   AudioChannelType mCurrentVisibleHigherChannel;
 
   nsTArray<uint64_t> mWithVideoChildIDs;
 
   // mPlayableHiddenContentChildID stores the ChildID of the process which can
--- a/dom/audiochannel/AudioChannelServiceChild.cpp
+++ b/dom/audiochannel/AudioChannelServiceChild.cpp
@@ -12,16 +12,20 @@
 #include "mozilla/StaticPtr.h"
 #include "mozilla/unused.h"
 #include "mozilla/Util.h"
 #include "mozilla/dom/ContentChild.h"
 #include "mozilla/dom/ContentParent.h"
 #include "nsIObserverService.h"
 #include "nsThreadUtils.h"
 
+#ifdef MOZ_WIDGET_GONK
+#include "SpeakerManagerService.h"
+#endif
+
 using namespace mozilla;
 using namespace mozilla::dom;
 using namespace mozilla::hal;
 
 StaticRefPtr<AudioChannelServiceChild> gAudioChannelServiceChild;
 
 // static
 AudioChannelService*
@@ -115,16 +119,22 @@ AudioChannelServiceChild::UnregisterAudi
 
   ContentChild::GetSingleton()->SendAudioChannelUnregisterType(
       data.mType, data.mElementHidden, data.mWithVideo);
 
   nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
   if (obs) {
     obs->NotifyObservers(nullptr, "audio-channel-agent-changed", nullptr);
   }
+#ifdef MOZ_WIDGET_GONK
+  bool active = AnyAudioChannelIsActive();
+  for (uint32_t i = 0; i < mSpeakerManager.Length(); i++) {
+    mSpeakerManager[i]->SetAudioChannelActive(active);
+  }
+#endif
 }
 
 void
 AudioChannelServiceChild::SetDefaultVolumeControlChannel(
   AudioChannelType aType, bool aHidden)
 {
   ContentChild *cc = ContentChild::GetSingleton();
   if (cc) {
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -797,16 +797,21 @@ DOMInterfaces = {
     'nativeType': 'mozilla::dom::network::MobileConnectionArray',
     'resultNotAddRefed': [ 'item' ]
 },
 
 'MozNamedAttrMap': {
     'nativeType': 'nsDOMAttributeMap',
 },
 
+'MozSpeakerManager': {
+    'nativeType': 'mozilla::dom::SpeakerManager',
+    'headerFile': 'SpeakerManager.h'
+},
+
 'MozPowerManager': {
     'nativeType': 'mozilla::dom::PowerManager',
 },
 
 'MozTimeManager': {
     'nativeType': 'mozilla::dom::time::TimeManager',
 },
 
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -76,16 +76,17 @@
 
 #if defined(MOZ_WIDGET_ANDROID)
 #include "APKOpen.h"
 #endif
 
 #if defined(MOZ_WIDGET_GONK)
 #include "nsVolume.h"
 #include "nsVolumeService.h"
+#include "SpeakerManagerService.h"
 #endif
 
 #ifdef XP_WIN
 #include <process.h>
 #define getpid _getpid
 #endif
 
 #ifdef ACCESSIBILITY
@@ -581,16 +582,30 @@ ContentChild::RecvSetProcessPrivileges(c
   // time if/when possible. SetCurrentProcessPrivileges should probably be
   // moved as well. Right now this is set ONLY if we receive the
   // RecvSetProcessPrivileges message. See bug 880808.
   SetCurrentProcessSandbox();
 #endif
   return true;
 }
 
+bool
+ContentChild::RecvSpeakerManagerNotify()
+{
+#ifdef MOZ_WIDGET_GONK
+  nsRefPtr<SpeakerManagerService> service =
+    SpeakerManagerService::GetSpeakerManagerService();
+  if (service) {
+    service->Notify();
+  }
+  return true;
+#endif
+  return false;
+}
+
 static CancelableTask* sFirstIdleTask;
 
 static void FirstIdle(void)
 {
     MOZ_ASSERT(sFirstIdleTask);
     sFirstIdleTask = nullptr;
     ContentChild::GetSingleton()->SendFirstIdle();
 }
--- a/dom/ipc/ContentChild.h
+++ b/dom/ipc/ContentChild.h
@@ -173,16 +173,18 @@ public:
                                     const InfallibleTArray<OverrideMapping>& overrides,
                                     const nsCString& locale);
 
     virtual mozilla::jsipc::PJavaScriptChild* AllocPJavaScriptChild();
     virtual bool DeallocPJavaScriptChild(mozilla::jsipc::PJavaScriptChild*);
 
     virtual bool RecvSetOffline(const bool& offline);
 
+    virtual bool RecvSpeakerManagerNotify();
+
     virtual bool RecvNotifyVisited(const URIParams& aURI);
     // auto remove when alertfinished is received.
     nsresult AddRemoteAlertObserver(const nsString& aData, nsIObserver* aObserver);
 
     virtual bool RecvPreferenceUpdate(const PrefSetting& aPref);
 
     virtual bool RecvNotifyAlertsObserver(const nsCString& aType, const nsString& aData);
 
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -108,16 +108,17 @@
 
 #ifdef MOZ_WIDGET_ANDROID
 # include "AndroidBridge.h"
 #endif
 
 #ifdef MOZ_WIDGET_GONK
 #include "nsIVolume.h"
 #include "nsIVolumeService.h"
+#include "SpeakerManagerService.h"
 using namespace mozilla::system;
 #endif
 
 #ifdef MOZ_B2G_BT
 #include "BluetoothParent.h"
 #include "BluetoothService.h"
 #endif
 
@@ -2474,16 +2475,45 @@ ContentParent::RecvPSpeechSynthesisConst
 #ifdef MOZ_WEBSPEECH
     return true;
 #else
     return false;
 #endif
 }
 
 bool
+ContentParent::RecvSpeakerManagerGetSpeakerStatus(bool* aValue)
+{
+#ifdef MOZ_WIDGET_GONK
+  *aValue = false;
+  nsRefPtr<SpeakerManagerService> service =
+    SpeakerManagerService::GetSpeakerManagerService();
+  if (service) {
+    *aValue = service->GetSpeakerStatus();
+  }
+  return true;
+#endif
+  return false;
+}
+
+bool
+ContentParent::RecvSpeakerManagerForceSpeaker(const bool& aEnable)
+{
+#ifdef MOZ_WIDGET_GONK
+  nsRefPtr<SpeakerManagerService> service =
+    SpeakerManagerService::GetSpeakerManagerService();
+  if (service) {
+    service->ForceSpeaker(aEnable, mChildID);
+  }
+  return true;
+#endif
+  return false;
+}
+
+bool
 ContentParent::RecvStartVisitedQuery(const URIParams& aURI)
 {
     nsCOMPtr<nsIURI> newURI = DeserializeURI(aURI);
     if (!newURI) {
         return false;
     }
     nsCOMPtr<IHistory> history = services::GetHistoryService();
     if (history) {
@@ -2795,16 +2825,18 @@ static int32_t
 AddGeolocationListener(nsIDOMGeoPositionCallback* watcher, bool highAccuracy)
 {
   nsCOMPtr<nsIDOMGeoGeolocation> geo = do_GetService("@mozilla.org/geolocation;1");
   if (!geo) {
     return -1;
   }
 
   PositionOptions* options = new PositionOptions();
+  options->mTimeout = 0;
+  options->mMaximumAge = 0;
   options->mEnableHighAccuracy = highAccuracy;
   int32_t retval = 1;
   geo->WatchPosition(watcher, nullptr, options, &retval);
   return retval;
 }
 
 bool
 ContentParent::RecvAddGeolocationListener(const IPC::Principal& aPrincipal,
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -469,16 +469,20 @@ private:
 
     virtual bool RecvAudioChannelChangedNotification();
 
     virtual bool RecvAudioChannelChangeDefVolChannel(
       const AudioChannelType& aType, const bool& aHidden);
 
     virtual bool RecvBroadcastVolume(const nsString& aVolumeName);
 
+    virtual bool RecvSpeakerManagerGetSpeakerStatus(bool* aValue);
+
+    virtual bool RecvSpeakerManagerForceSpeaker(const bool& aEnable);
+
     virtual bool RecvSystemMessageHandled() MOZ_OVERRIDE;
 
     virtual bool RecvNuwaReady() MOZ_OVERRIDE;
 
     virtual bool RecvAddNewProcess(const uint32_t& aPid,
                                    const InfallibleTArray<ProtocolFdMapping>& aFds) MOZ_OVERRIDE;
 
     virtual bool RecvCreateFakeVolume(const nsString& fsName, const nsString& mountPoint) MOZ_OVERRIDE;
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -233,26 +233,27 @@ child:
 
     PMemoryReportRequest(uint32_t generation);
 
     /**
      * Notify the AudioChannelService in the child processes.
      */
     async AudioChannelNotify();
 
+    async SpeakerManagerNotify();
+
     /**
      * Do a memory info dump to a file in our temp directory.
      *
      * For documentation on the args, see
      * MemoryInfoDumper::dumpMemoryInfoToTempDir.
      */
     async DumpMemoryInfoToTempDir(nsString identifier,
                                   bool minimizeMemoryUsage,
                                   bool dumpChildProcesses);
-
     /**
      * Dump this process's GC and CC logs.
      *
      * For documentation on the args, see
      * MemoryInfoDumper::dumpGCAndCCLogsToFile.
      */
     async DumpGCAndCCLogsToFile(nsString identifier,
                                 bool dumpAllTraces,
@@ -466,15 +467,20 @@ parent:
 
     // called by the child (test code only) to propagate volume changes to the parent
     async CreateFakeVolume(nsString fsName, nsString mountPoint);
     async SetFakeVolumeState(nsString fsName, int32_t fsState);
 
     sync KeywordToURI(nsCString keyword)
         returns (OptionalInputStreamParams postData, OptionalURIParams uri);
 
+    sync SpeakerManagerForceSpeaker(bool aEnable);
+
+    sync SpeakerManagerGetSpeakerStatus()
+        returns (bool value);
+
 both:
      AsyncMessage(nsString aMessage, ClonedMessageData aData,
                   CpowEntry[] aCpows, Principal aPrincipal);
 };
 
 }
 }
--- a/dom/mobilemessage/src/gonk/MobileMessageDatabaseService.js
+++ b/dom/mobilemessage/src/gonk/MobileMessageDatabaseService.js
@@ -1776,25 +1776,31 @@ MobileMessageDatabaseService.prototype =
         insertMessageRecord(threadId);
       };
     });
   },
 
   forEachMatchedMmsDeliveryInfo:
     function forEachMatchedMmsDeliveryInfo(aDeliveryInfo, aNeedle, aCallback) {
 
-    let typedAddress = MMS.Address.resolveType(aNeedle);
+    let typedAddress = {
+      type: MMS.Address.resolveType(aNeedle),
+      address: aNeedle
+    };
     let normalizedAddress, parsedAddress;
     if (typedAddress.type === "PLMN") {
       normalizedAddress = PhoneNumberUtils.normalize(aNeedle, false);
       parsedAddress = PhoneNumberUtils.parse(normalizedAddress);
     }
 
     for (let element of aDeliveryInfo) {
-      let typedStoredAddress = MMS.Address.resolveType(element.receiver);
+      let typedStoredAddress = {
+        type: MMS.Address.resolveType(element.receiver),
+        address: element.receiver
+      };
       if (typedAddress.type !== typedStoredAddress.type) {
         // Not even my type.  Skip.
         continue;
       }
 
       if (typedAddress.address == typedStoredAddress.address) {
         // Have a direct match.
         aCallback(element);
--- a/dom/moz.build
+++ b/dom/moz.build
@@ -76,17 +76,20 @@ PARALLEL_DIRS += [
     'inputmethod',
     'webidl',
 ]
 
 if CONFIG['OS_ARCH'] == 'WINNT':
     PARALLEL_DIRS += ['plugins/ipc/hangui']
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
-    PARALLEL_DIRS += ['wifi']
+    PARALLEL_DIRS += [
+        'speakermanager',
+        'wifi',
+    ]
 
 if CONFIG['MOZ_B2G_RIL']:
     PARALLEL_DIRS += [
         'icc',
         'cellbroadcast',
         'voicemail',
         'wappush',
     ]
new file mode 100644
--- /dev/null
+++ b/dom/speakermanager/SpeakerManager.cpp
@@ -0,0 +1,219 @@
+/* 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 "SpeakerManager.h"
+#include "nsIDOMClassInfo.h"
+#include "nsIDOMEventListener.h"
+#include "SpeakerManagerService.h"
+#include "nsIPermissionManager.h"
+#include "nsIInterfaceRequestorUtils.h"
+#include "nsIDocShell.h"
+#include "nsDOMEvent.h"
+#include "AudioChannelService.h"
+
+using namespace mozilla::dom;
+
+NS_IMPL_QUERY_INTERFACE_INHERITED1(SpeakerManager, nsDOMEventTargetHelper,
+                                   nsIDOMEventListener)
+NS_IMPL_ADDREF_INHERITED(SpeakerManager, nsDOMEventTargetHelper)
+NS_IMPL_RELEASE_INHERITED(SpeakerManager, nsDOMEventTargetHelper)
+
+SpeakerManager::SpeakerManager()
+  : mForcespeaker(false)
+  , mVisible(false)
+{
+  SetIsDOMBinding();
+  SpeakerManagerService *service =
+    SpeakerManagerService::GetSpeakerManagerService();
+  if (service) {
+    service->RegisterSpeakerManager(this);
+  }
+}
+
+SpeakerManager::~SpeakerManager()
+{
+  SpeakerManagerService *service = SpeakerManagerService::GetSpeakerManagerService();
+  if (service) {
+    service->UnRegisterSpeakerManager(this);
+  }
+  nsCOMPtr<EventTarget> target = do_QueryInterface(GetOwner());
+  NS_ENSURE_TRUE_VOID(target);
+
+  target->RemoveSystemEventListener(NS_LITERAL_STRING("visibilitychange"),
+                                    this,
+                                    /* useCapture = */ true);
+}
+
+bool
+SpeakerManager::Speakerforced()
+{
+  // If a background app calls forcespeaker=true that doesn't change anything.
+  // 'speakerforced' remains false everywhere.
+  if (mForcespeaker && !mVisible) {
+    return false;
+  }
+  SpeakerManagerService *service = SpeakerManagerService::GetSpeakerManagerService();
+  if (service) {
+    return service->GetSpeakerStatus();
+  }
+  return false;
+}
+
+bool
+SpeakerManager::Forcespeaker()
+{
+  return mForcespeaker;
+}
+
+void
+SpeakerManager::SetForcespeaker(bool aEnable)
+{
+  SpeakerManagerService *service = SpeakerManagerService::GetSpeakerManagerService();
+  if (service) {
+    service->ForceSpeaker(aEnable, mVisible);
+  }
+  mForcespeaker = aEnable;
+}
+
+void
+SpeakerManager::DispatchSimpleEvent(const nsAString& aStr)
+{
+  NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread");
+  nsresult rv = CheckInnerWindowCorrectness();
+  if (NS_FAILED(rv)) {
+    return;
+  }
+
+  nsCOMPtr<nsIDOMEvent> event;
+  rv = NS_NewDOMEvent(getter_AddRefs(event), this, nullptr, nullptr);
+  if (NS_FAILED(rv)) {
+    NS_WARNING("Failed to create the error event!!!");
+    return;
+  }
+  rv = event->InitEvent(aStr, false, false);
+
+  if (NS_FAILED(rv)) {
+    NS_WARNING("Failed to init the error event!!!");
+    return;
+  }
+
+  event->SetTrusted(true);
+
+  rv = DispatchDOMEvent(nullptr, event, nullptr, nullptr);
+  if (NS_FAILED(rv)) {
+    NS_ERROR("Failed to dispatch the event!!!");
+    return;
+  }
+}
+
+void
+SpeakerManager::Init(nsPIDOMWindow* aWindow)
+{
+  BindToOwner(aWindow->IsOuterWindow() ?
+    aWindow->GetCurrentInnerWindow() : aWindow);
+
+  mVisible = !GetOwner()->IsBackground();
+  nsCOMPtr<nsIDOMEventTarget> target = do_QueryInterface(GetOwner());
+  NS_ENSURE_TRUE_VOID(target);
+
+  target->AddSystemEventListener(NS_LITERAL_STRING("visibilitychange"),
+                                 this,
+                                 /* useCapture = */ true,
+                                 /* wantsUntrusted = */ false);
+}
+
+nsPIDOMWindow*
+SpeakerManager::GetParentObject() const
+{
+  return GetOwner();
+}
+
+/* static */ already_AddRefed<SpeakerManager>
+SpeakerManager::Constructor(const GlobalObject& aGlobal, ErrorResult& aRv)
+{
+  nsCOMPtr<nsIScriptGlobalObject> sgo = do_QueryInterface(aGlobal.GetAsSupports());
+  if (!sgo) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
+  }
+
+  nsCOMPtr<nsPIDOMWindow> ownerWindow = do_QueryInterface(aGlobal.GetAsSupports());
+  if (!ownerWindow) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return nullptr;
+  }
+
+  nsCOMPtr<nsIPermissionManager> permMgr =
+    do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
+  NS_ENSURE_TRUE(permMgr, nullptr);
+
+  uint32_t permission = nsIPermissionManager::DENY_ACTION;
+  nsresult rv =
+    permMgr->TestPermissionFromWindow(ownerWindow, "speaker-control",
+                                      &permission);
+  NS_ENSURE_SUCCESS(rv, nullptr);
+
+  if (permission != nsIPermissionManager::ALLOW_ACTION) {
+    aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
+    return nullptr;
+  }
+
+  nsRefPtr<SpeakerManager> object = new SpeakerManager();
+  object->Init(ownerWindow);
+  return object.forget();
+}
+
+JSObject*
+SpeakerManager::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope)
+{
+  return MozSpeakerManagerBinding::Wrap(aCx, aScope, this);
+}
+
+NS_IMETHODIMP
+SpeakerManager::HandleEvent(nsIDOMEvent* aEvent)
+{
+  nsAutoString type;
+  aEvent->GetType(type);
+
+  if (!type.EqualsLiteral("visibilitychange")) {
+    return NS_ERROR_FAILURE;
+  }
+
+  nsCOMPtr<nsIDocShell> docshell = do_GetInterface(GetOwner());
+  NS_ENSURE_TRUE(docshell, NS_ERROR_FAILURE);
+  docshell->GetIsActive(&mVisible);
+
+  // If an app that has called forcespeaker=true is switched
+  // from the background to the foreground 'speakerforced'
+  // switches to true in all apps. I.e. the app doesn't have to
+  // call forcespeaker=true again when it comes into foreground.
+  SpeakerManagerService *service =
+    SpeakerManagerService::GetSpeakerManagerService();
+  if (service && mVisible && mForcespeaker) {
+    service->ForceSpeaker(mForcespeaker, mVisible);
+  }
+  // If an application that has called forcespeaker=true, but no audio is
+  // currently playing in the app itself, if application switch to
+  // the background, we switch 'speakerforced' to false.
+  if (!mVisible && mForcespeaker) {
+    AudioChannelService* audioChannelService =
+      AudioChannelService::GetAudioChannelService();
+    if (audioChannelService && !audioChannelService->AnyAudioChannelIsActive()) {
+      service->ForceSpeaker(false, mVisible);
+    }
+  }
+  return NS_OK;
+}
+
+void
+SpeakerManager::SetAudioChannelActive(bool isActive)
+{
+  if (!isActive && !mVisible) {
+    SpeakerManagerService *service =
+      SpeakerManagerService::GetSpeakerManagerService();
+    if (service) {
+      service->ForceSpeaker(false, mVisible);
+    }
+  }
+}
new file mode 100644
--- /dev/null
+++ b/dom/speakermanager/SpeakerManager.h
@@ -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/. */
+
+#ifndef mozilla_dom_SpeakerManager_h
+#define mozilla_dom_SpeakerManager_h
+
+#include "nsDOMEventTargetHelper.h"
+#include "mozilla/dom/MozSpeakerManagerBinding.h"
+
+namespace mozilla {
+namespace dom {
+/* This class is used for UA to control devices's speaker status.
+ * After UA set the speaker status, the UA should handle the
+ * forcespeakerchange event and change the speaker status in UI.
+ * The device's speaker status would set back to normal when UA close the application.
+ */
+class SpeakerManager MOZ_FINAL
+  : public nsDOMEventTargetHelper
+  , public nsIDOMEventListener
+{
+  friend class SpeakerManagerService;
+  friend class SpeakerManagerServiceChild;
+
+  NS_DECL_ISUPPORTS_INHERITED
+  NS_DECL_NSIDOMEVENTLISTENER
+
+public:
+  void Init(nsPIDOMWindow* aWindow);
+
+  nsPIDOMWindow* GetParentObject() const;
+
+  virtual JSObject* WrapObject(JSContext* aCx,
+                               JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
+  /**
+   * WebIDL Interface
+   */
+  // Get this api's force speaker setting.
+  bool Forcespeaker();
+  // Force acoustic sound go through speaker. Don't force to speaker if application
+  // stay in the background and re-force when application
+  // go to foreground
+  void SetForcespeaker(bool aEnable);
+  // Get the device's speaker forced setting.
+  bool Speakerforced();
+
+  void SetAudioChannelActive(bool aIsActive);
+  IMPL_EVENT_HANDLER(speakerforcedchange)
+
+  static already_AddRefed<SpeakerManager>
+  Constructor(const GlobalObject& aGlobal, ErrorResult& aRv);
+
+protected:
+  SpeakerManager();
+  ~SpeakerManager();
+  void DispatchSimpleEvent(const nsAString& aStr);
+  // This api's force speaker setting
+  bool mForcespeaker;
+  bool mVisible;
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_SpeakerManager_h
new file mode 100644
--- /dev/null
+++ b/dom/speakermanager/SpeakerManagerService.cpp
@@ -0,0 +1,199 @@
+/* -*- 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 "SpeakerManagerService.h"
+#include "SpeakerManagerServiceChild.h"
+#include "mozilla/Services.h"
+#include "mozilla/StaticPtr.h"
+#include "mozilla/unused.h"
+#include "mozilla/Util.h"
+#include "mozilla/dom/ContentParent.h"
+#include "nsIPropertyBag2.h"
+#include "nsThreadUtils.h"
+#include "nsServiceManagerUtils.h"
+#include "AudioChannelService.h"
+#include <cutils/properties.h>
+
+#define NS_AUDIOMANAGER_CONTRACTID "@mozilla.org/telephony/audiomanager;1"
+#include "nsIAudioManager.h"
+
+using namespace mozilla;
+using namespace mozilla::dom;
+
+StaticRefPtr<SpeakerManagerService> gSpeakerManagerService;
+
+// static
+SpeakerManagerService*
+SpeakerManagerService::GetSpeakerManagerService()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  if (XRE_GetProcessType() != GeckoProcessType_Default) {
+    return SpeakerManagerServiceChild::GetSpeakerManagerService();
+  }
+
+  // If we already exist, exit early
+  if (gSpeakerManagerService) {
+    return gSpeakerManagerService;
+  }
+
+  // Create new instance, register, return
+  nsRefPtr<SpeakerManagerService> service = new SpeakerManagerService();
+  NS_ENSURE_TRUE(service, nullptr);
+
+  gSpeakerManagerService = service;
+  return gSpeakerManagerService;
+}
+
+void
+SpeakerManagerService::Shutdown()
+{
+  if (XRE_GetProcessType() != GeckoProcessType_Default) {
+    return SpeakerManagerServiceChild::Shutdown();
+  }
+
+  if (gSpeakerManagerService) {
+    gSpeakerManagerService = nullptr;
+  }
+}
+
+NS_IMPL_ISUPPORTS1(SpeakerManagerService, nsIObserver)
+
+void
+SpeakerManagerService::ForceSpeaker(bool aEnable, uint64_t aChildId)
+{
+  TuruOnSpeaker(aEnable);
+  if (aEnable) {
+    mSpeakerStatusSet.Put(aChildId);
+  }
+  Notify();
+  return;
+}
+
+void
+SpeakerManagerService::ForceSpeaker(bool aEnable, bool aVisible)
+{
+  // b2g main process without oop
+  TuruOnSpeaker(aEnable && aVisible);
+  mVisible = aVisible;
+  mOrgSpeakerStatus = aEnable;
+  Notify();
+}
+
+void
+SpeakerManagerService::TuruOnSpeaker(bool aOn)
+{
+  nsCOMPtr<nsIAudioManager> audioManager = do_GetService(NS_AUDIOMANAGER_CONTRACTID);
+  NS_ENSURE_TRUE_VOID(audioManager);
+  int32_t phoneState;
+  audioManager->GetPhoneState(&phoneState);
+  int32_t forceuse = (phoneState == nsIAudioManager::PHONE_STATE_IN_CALL ||
+    phoneState == nsIAudioManager::PHONE_STATE_IN_COMMUNICATION)
+    ? nsIAudioManager::USE_COMMUNICATION : nsIAudioManager::USE_MEDIA;
+  if (aOn) {
+    audioManager->SetForceForUse(forceuse, nsIAudioManager::FORCE_SPEAKER);
+  } else {
+    audioManager->SetForceForUse(forceuse, nsIAudioManager::FORCE_NONE);
+  }
+}
+
+bool
+SpeakerManagerService::GetSpeakerStatus()
+{
+  char propQemu[PROPERTY_VALUE_MAX];
+  property_get("ro.kernel.qemu", propQemu, "");
+  if (!strncmp(propQemu, "1", 1)) {
+    return mOrgSpeakerStatus;
+  }
+  nsCOMPtr<nsIAudioManager> audioManager = do_GetService(NS_AUDIOMANAGER_CONTRACTID);
+  NS_ENSURE_TRUE(audioManager, false);
+  int32_t usage;
+  audioManager->GetForceForUse(nsIAudioManager::USE_MEDIA, &usage);
+  return usage == nsIAudioManager::FORCE_SPEAKER;
+}
+
+void
+SpeakerManagerService::Notify()
+{
+  // Parent Notify to all the child processes.
+  nsTArray<ContentParent*> children;
+  ContentParent::GetAll(children);
+  for (uint32_t i = 0; i < children.Length(); i++) {
+    unused << children[i]->SendSpeakerManagerNotify();
+  }
+
+  for (uint32_t i = 0; i < mRegisteredSpeakerManagers.Length(); i++) {
+    mRegisteredSpeakerManagers[i]->
+      DispatchSimpleEvent(NS_LITERAL_STRING("speakerforcedchange"));
+  }
+}
+
+void
+SpeakerManagerService::SetAudioChannelActive(bool aIsActive)
+{
+  if (!aIsActive && !mVisible) {
+    ForceSpeaker(!mOrgSpeakerStatus, mVisible);
+  }
+}
+
+NS_IMETHODIMP
+SpeakerManagerService::Observe(nsISupports* aSubject, const char* 
+                               aTopic, const PRUnichar* aData)
+{
+  if (!strcmp(aTopic, "ipc:content-shutdown")) {
+    nsCOMPtr<nsIPropertyBag2> props = do_QueryInterface(aSubject);
+    if (!props) {
+      NS_WARNING("ipc:content-shutdown message without property bag as subject");
+      return NS_OK;
+    }
+
+    uint64_t childID = 0;
+    nsresult rv = props->GetPropertyAsUint64(NS_LITERAL_STRING("childID"),
+                                             &childID);
+    if (NS_SUCCEEDED(rv)) {
+        // If the audio has paused by audiochannel,
+        // the enable flag should be false and don't need to handle.
+        if (mSpeakerStatusSet.Contains(childID)) {
+          TuruOnSpeaker(false);
+          mSpeakerStatusSet.Remove(childID);
+        }
+        if (mOrgSpeakerStatus) {
+          TuruOnSpeaker(!mOrgSpeakerStatus);
+          mOrgSpeakerStatus = false;
+        }
+    } else {
+      NS_WARNING("ipc:content-shutdown message without childID property");
+    }
+  }
+  return NS_OK;
+}
+
+SpeakerManagerService::SpeakerManagerService()
+  : mOrgSpeakerStatus(false),
+    mVisible(false)
+{
+  MOZ_COUNT_CTOR(SpeakerManagerService);
+  if (XRE_GetProcessType() == GeckoProcessType_Default) {
+    nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
+    if (obs) {
+      obs->AddObserver(this, "ipc:content-shutdown", false);
+    }
+  }
+  AudioChannelService* audioChannelService =
+    AudioChannelService::GetAudioChannelService();
+  if (audioChannelService) {
+    audioChannelService->RegisterSpeakerManager(this);
+  }
+}
+
+SpeakerManagerService::~SpeakerManagerService()
+{
+  MOZ_COUNT_DTOR(SpeakerManagerService);
+  AudioChannelService* audioChannelService =
+    AudioChannelService::GetAudioChannelService();
+  if (audioChannelService)
+    audioChannelService->UnregisterSpeakerManager(this);
+}
new file mode 100644
--- /dev/null
+++ b/dom/speakermanager/SpeakerManagerService.h
@@ -0,0 +1,72 @@
+/* -*- 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_SpeakerManagerService_h__
+#define mozilla_dom_SpeakerManagerService_h__
+
+#include "nsAutoPtr.h"
+#include "nsIObserver.h"
+#include "nsTArray.h"
+#include "SpeakerManager.h"
+#include "nsIAudioManager.h"
+#include "nsCheapSets.h"
+#include "nsHashKeys.h"
+
+namespace mozilla {
+namespace dom {
+
+class SpeakerManagerService : public nsIObserver
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIOBSERVER
+
+  static SpeakerManagerService* GetSpeakerManagerService();
+  virtual void ForceSpeaker(bool aEnable, bool aVisible);
+  virtual bool GetSpeakerStatus();
+  virtual void SetAudioChannelActive(bool aIsActive);
+  // Called by child
+  void ForceSpeaker(bool enable, uint64_t aChildid);
+  // Register the SpeakerManager to service for notify the speakerforcedchange event
+  void RegisterSpeakerManager(SpeakerManager* aSpeakerManager)
+  {
+    mRegisteredSpeakerManagers.AppendElement(aSpeakerManager);
+  }
+  void UnRegisterSpeakerManager(SpeakerManager* aSpeakerManager)
+  {
+    mRegisteredSpeakerManagers.RemoveElement(aSpeakerManager);
+  }
+  /**
+   * Shutdown the singleton.
+   */
+  static void Shutdown();
+
+protected:
+  SpeakerManagerService();
+
+  virtual ~SpeakerManagerService();
+  // Notify to UA if device speaker status changed
+  virtual void Notify();
+
+  void TuruOnSpeaker(bool aEnable);
+
+  nsTArray<nsRefPtr<SpeakerManager> > mRegisteredSpeakerManagers;
+  // Set for remember all the child speaker status
+  nsCheapSet<nsUint64HashKey> mSpeakerStatusSet;
+  // The Speaker status assign by UA
+  bool mOrgSpeakerStatus;
+
+  bool mVisible;
+  // This is needed for IPC communication between
+  // SpeakerManagerServiceChild and this class.
+  friend class ContentParent;
+  friend class ContentChild;
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif
new file mode 100644
--- /dev/null
+++ b/dom/speakermanager/SpeakerManagerServiceChild.cpp
@@ -0,0 +1,113 @@
+/* -*- 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 "SpeakerManagerServiceChild.h"
+#include "mozilla/Services.h"
+#include "mozilla/StaticPtr.h"
+#include "mozilla/unused.h"
+#include "mozilla/Util.h"
+#include "mozilla/dom/ContentChild.h"
+#include "mozilla/dom/ContentParent.h"
+#include "nsIObserverService.h"
+#include "nsThreadUtils.h"
+#include "AudioChannelService.h"
+#include <cutils/properties.h>
+
+using namespace mozilla;
+using namespace mozilla::dom;
+
+StaticRefPtr<SpeakerManagerServiceChild> gSpeakerManagerServiceChild;
+
+// static
+SpeakerManagerService*
+SpeakerManagerServiceChild::GetSpeakerManagerService()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  // If we already exist, exit early
+  if (gSpeakerManagerServiceChild) {
+    return gSpeakerManagerServiceChild;
+  }
+
+  // Create new instance, register, return
+  nsRefPtr<SpeakerManagerServiceChild> service = new SpeakerManagerServiceChild();
+  NS_ENSURE_TRUE(service, nullptr);
+
+  gSpeakerManagerServiceChild = service;
+  return gSpeakerManagerServiceChild;
+}
+
+void
+SpeakerManagerServiceChild::ForceSpeaker(bool aEnable, bool aVisible)
+{
+  mVisible = aVisible;
+  mOrgSpeakerStatus = aEnable;
+  ContentChild *cc = ContentChild::GetSingleton();
+  if (cc) {
+    cc->SendSpeakerManagerForceSpeaker(aEnable && aVisible);
+  }
+}
+
+bool
+SpeakerManagerServiceChild::GetSpeakerStatus()
+{
+  ContentChild *cc = ContentChild::GetSingleton();
+  bool status = false;
+  if (cc) {
+    cc->SendSpeakerManagerGetSpeakerStatus(&status);
+  }
+  char propQemu[PROPERTY_VALUE_MAX];
+  property_get("ro.kernel.qemu", propQemu, "");
+  if (!strncmp(propQemu, "1", 1)) {
+    return mOrgSpeakerStatus;
+  }
+  return status;
+}
+
+void
+SpeakerManagerServiceChild::Shutdown()
+{
+  if (gSpeakerManagerServiceChild) {
+    gSpeakerManagerServiceChild = nullptr;
+  }
+}
+
+void
+SpeakerManagerServiceChild::SetAudioChannelActive(bool aIsActive)
+{
+  // Content process and switch to background with no audio and speaker forced.
+  // Then disable speaker
+  for (uint32_t i = 0; i < mRegisteredSpeakerManagers.Length(); i++) {
+    mRegisteredSpeakerManagers[i]->SetAudioChannelActive(aIsActive);
+  }
+}
+
+SpeakerManagerServiceChild::SpeakerManagerServiceChild()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  AudioChannelService* audioChannelService = AudioChannelService::GetAudioChannelService();
+  if (audioChannelService) {
+    audioChannelService->RegisterSpeakerManager(this);
+  }
+  MOZ_COUNT_CTOR(SpeakerManagerServiceChild);
+}
+
+SpeakerManagerServiceChild::~SpeakerManagerServiceChild()
+{
+  AudioChannelService* audioChannelService = AudioChannelService::GetAudioChannelService();
+  if (audioChannelService) {
+    audioChannelService->UnregisterSpeakerManager(this);
+  }
+  MOZ_COUNT_DTOR(SpeakerManagerServiceChild);
+}
+
+void
+SpeakerManagerServiceChild::Notify()
+{
+  for (uint32_t i = 0; i < mRegisteredSpeakerManagers.Length(); i++) {
+    mRegisteredSpeakerManagers[i]->DispatchSimpleEvent(NS_LITERAL_STRING("speakerforcedchange"));
+  }
+}
new file mode 100644
--- /dev/null
+++ b/dom/speakermanager/SpeakerManagerServiceChild.h
@@ -0,0 +1,37 @@
+/* -*- 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_SpeakerManagerServicechild_h__
+#define mozilla_dom_SpeakerManagerServicechild_h__
+
+#include "nsAutoPtr.h"
+#include "nsISupports.h"
+#include "SpeakerManagerService.h"
+
+namespace mozilla {
+namespace dom {
+/* This class is used to do the IPC to enable/disable speaker status
+   Also handle the application speaker competition problem
+*/
+class SpeakerManagerServiceChild : public SpeakerManagerService
+{
+public:
+  static SpeakerManagerService* GetSpeakerManagerService();
+  static void Shutdown();
+  virtual void ForceSpeaker(bool aEnable, bool aVisible) MOZ_OVERRIDE;
+  virtual bool GetSpeakerStatus() MOZ_OVERRIDE;
+  virtual void SetAudioChannelActive(bool aIsActive) MOZ_OVERRIDE;
+  virtual void Notify() MOZ_OVERRIDE;
+protected:
+  SpeakerManagerServiceChild();
+  virtual ~SpeakerManagerServiceChild();
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif
+
new file mode 100644
--- /dev/null
+++ b/dom/speakermanager/moz.build
@@ -0,0 +1,27 @@
+# -*- 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/.
+
+MOCHITEST_MANIFESTS += ['tests/mochitest.ini']
+
+XPIDL_MODULE = 'dom_speakermanager'
+
+EXPORTS += [
+    'SpeakerManager.h',
+    'SpeakerManagerService.h',
+    'SpeakerManagerServiceChild.h',
+]
+
+SOURCES += [
+    'SpeakerManager.cpp',
+    'SpeakerManagerService.cpp',
+    'SpeakerManagerServiceChild.cpp',
+]
+
+FAIL_ON_WARNINGS = True
+
+include('/ipc/chromium/chromium-config.mozbuild')
+
+FINAL_LIBRARY = 'gklayout'
new file mode 100644
--- /dev/null
+++ b/dom/speakermanager/tests/mochitest.ini
@@ -0,0 +1,3 @@
+[DEFAULT]
+
+[test_speakermanager.html]
new file mode 100644
--- /dev/null
+++ b/dom/speakermanager/tests/test_speakermanager.html
@@ -0,0 +1,53 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <meta charset="utf-8">
+  <title>Test MozSpeakerManager API</title>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+</head>
+<body>
+<p id="display"></p>
+<div id="content" style="display: none"></div>
+<pre id="test">
+  <script type="application/javascript">
+
+  "use strict";
+
+  function testObject() {
+    var mgr = new MozSpeakerManager();
+    var spkforced = false;
+    mgr.onspeakerforcedchange = function() {
+      if (spkforced) {
+        is(mgr.speakerforced, true, 'speaker should be true');
+        spkforced = false;
+        mgr.forcespeaker = false;
+      } else {
+        is(mgr.speakerforced, false, 'speaker should be false');
+        SimpleTest.finish();
+      }
+    }
+    spkforced = true;
+    mgr.forcespeaker = true;
+  }
+
+  function startTests() {
+    // Currently applicable only on FxOS
+    if (navigator.userAgent.indexOf("Mobile") != -1 &&
+        navigator.appVersion.indexOf("Android") == -1) {
+      testObject();
+    } else {
+      ok(true, "mozAlarms on Firefox OS only.");
+      SimpleTest.finish();
+    }
+  }
+
+  SimpleTest.waitForExplicitFinish();
+  SpecialPowers.pushPermissions(
+    [{ "type": "speaker-control", "allow": 1, "context": document }],
+    startTests);
+
+  </script>
+</pre>
+</body>
+</html>
--- a/dom/system/gonk/RadioInterfaceLayer.js
+++ b/dom/system/gonk/RadioInterfaceLayer.js
@@ -1608,22 +1608,16 @@ RadioInterface.prototype = {
     }
 
     let status = RIL.CDMA_OTA_PROVISION_STATUS_TO_GECKO[message.status];
 
     gMessageManager.sendMobileConnectionMessage("RIL:OtaStatusChanged",
                                                 this.clientId, status);
   },
 
-  _isRadioChanging: function _isRadioChanging() {
-    let state = this.rilContext.detailedRadioState;
-    return state == RIL.GECKO_DETAILED_RADIOSTATE_ENABLING ||
-      state == RIL.GECKO_DETAILED_RADIOSTATE_DISABLING;
-  },
-
   _convertRadioState: function _converRadioState(state) {
     switch (state) {
       case RIL.GECKO_RADIOSTATE_OFF:
         return RIL.GECKO_DETAILED_RADIOSTATE_DISABLED;
       case RIL.GECKO_RADIOSTATE_READY:
         return RIL.GECKO_DETAILED_RADIOSTATE_ENABLED;
       default:
         return RIL.GECKO_DETAILED_RADIOSTATE_UNKNOWN;
@@ -1853,17 +1847,21 @@ RadioInterface.prototype = {
     if (dataInfo.roaming && !this.dataCallSettings.roamingEnabled) {
       if (DEBUG) this.debug("We're roaming, but data roaming is disabled.");
       return;
     }
     if (wifi_active) {
       if (DEBUG) this.debug("Don't connect data call when Wifi is connected.");
       return;
     }
-    if (this._isRadioChanging()) {
+
+    let detailedRadioState = this.rilContext.detailedRadioState;
+    if (gRadioEnabledController.isDeactivatingDataCalls() ||
+        detailedRadioState == RIL.GECKO_DETAILED_RADIOSTATE_ENABLING ||
+        detailedRadioState == RIL.GECKO_DETAILED_RADIOSTATE_DISABLING) {
       // We're changing the radio power currently, ignore any changes.
       return;
     }
 
     if (DEBUG) this.debug("Data call settings: connect data call.");
     this.setupDataCallByType("default");
   },
 
@@ -2060,28 +2058,28 @@ RadioInterface.prototype = {
         result: (success ? RIL.PDU_FCS_OK
                          : RIL.PDU_FCS_MEMORY_CAPACITY_EXCEEDED)
       });
 
       if (!success) {
         // At this point we could send a message to content to notify the user
         // that storing an incoming SMS failed, most likely due to a full disk.
         if (DEBUG) {
-          this.debug("Could not store SMS " + message.id + ", error code " + rv);
+          this.debug("Could not store SMS, error code " + rv);
         }
         return;
       }
 
       this.broadcastSmsSystemMessage(kSmsReceivedObserverTopic, domMessage);
       Services.obs.notifyObservers(domMessage, kSmsReceivedObserverTopic, null);
     }.bind(this);
 
     if (message.messageClass != RIL.GECKO_SMS_MESSAGE_CLASSES[RIL.PDU_DCS_MSG_CLASS_0]) {
-      message.id = gMobileMessageDatabaseService.saveReceivedMessage(message,
-                                                                     notifyReceived);
+      gMobileMessageDatabaseService.saveReceivedMessage(message,
+                                                        notifyReceived);
     } else {
       message.id = -1;
       message.threadId = 0;
       message.delivery = DOM_MOBILE_MESSAGE_DELIVERY_RECEIVED;
       message.deliveryStatus = RIL.GECKO_SMS_DELIVERY_STATUS_SUCCESS;
       message.read = false;
 
       let domMessage =
@@ -2633,28 +2631,25 @@ RadioInterface.prototype = {
         clientId: this.clientId,
         data: response
       });
       return false;
     }).bind(this));
   },
 
   isValidStateForSetRadioEnabled: function() {
-    let state = this.rilContext.radioState;
-
-    return !this._isRadioChanging() &&
-        (state == RIL.GECKO_RADIOSTATE_READY ||
-         state == RIL.GECKO_RADIOSTATE_OFF);
+    let state = this.rilContext.detailedRadioState;
+    return state == RIL.GECKO_DETAILED_RADIOSTATE_ENABLED ||
+      state == RIL.GECKO_DETAILED_RADIOSTATE_DISABLED;
   },
 
   isDummyForSetRadioEnabled: function(message) {
-    let state = this.rilContext.radioState;
-
-    return (state == RIL.GECKO_RADIOSTATE_READY && message.enabled) ||
-        (state == RIL.GECKO_RADIOSTATE_OFF && !message.enabled);
+    let state = this.rilContext.detailedRadioState;
+    return (state == RIL.GECKO_DETAILED_RADIOSTATE_ENABLED && message.enabled) ||
+      (state == RIL.GECKO_DETAILED_RADIOSTATE_DISABLED && !message.enabled);
   },
 
   setRadioEnabledResponse: function(target, message, errorMsg) {
     if (errorMsg) {
       message.errorMsg = errorMsg;
     }
 
     target.sendAsyncMessage("RIL:SetRadioEnabled", {
--- a/dom/tests/mochitest/general/test_interfaces.html
+++ b/dom/tests/mochitest/general/test_interfaces.html
@@ -369,16 +369,17 @@ var interfaceNamesInGlobalScope =
     {name: "mozRTCIceCandidate", pref: "media.peerconnection.enabled"},
     {name: "mozRTCPeerConnection", pref: "media.peerconnection.enabled"},
     {name: "mozRTCSessionDescription", pref: "media.peerconnection.enabled"},
     "MozSettingsEvent",
     "MozSmsEvent",
     "MozSmsFilter",
     "MozSmsMessage",
     "MozSmsSegmentInfo",
+    {name: "MozSpeakerManager", b2g: true},
     {name: "MozStkCommandEvent", b2g: true, pref: "dom.icc.enabled"},
     {name: "MozTimeManager", b2g: true},
     {name: "MozVoicemail", b2g: true, pref: "dom.voicemail.enabled"},
     {name: "MozVoicemailEvent", b2g: true, pref: "dom.voicemail.enabled"},
     "MozWakeLock",
     {name: "MozWifiConnectionInfoEvent", b2g: true},
     {name: "MozWifiStatusChangeEvent", b2g: true},
     "MutationEvent",
new file mode 100644
--- /dev/null
+++ b/dom/webidl/MozSpeakerManager.webidl
@@ -0,0 +1,18 @@
+/* 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/.
+ */
+
+/*
+ * Allow application can control acoustic sound output through speaker.
+ * Reference https://wiki.mozilla.org/WebAPI/SpeakerManager
+ */
+[Constructor()]
+interface MozSpeakerManager : EventTarget {
+  /* query the speaker status */
+  readonly attribute boolean speakerforced;
+  /* force device device's acoustic sound output through speaker */
+  attribute boolean forcespeaker;
+  /* this event will be fired when device's speaker forced status change */
+  attribute EventHandler onspeakerforcedchange;
+};
--- a/dom/webidl/moz.build
+++ b/dom/webidl/moz.build
@@ -527,16 +527,17 @@ if CONFIG['MOZ_NFC']:
          'MozNdefRecord.webidl',
          'MozNfc.webidl',
          'MozNFCPeer.webidl',
          'MozNFCTag.webidl',
     ]
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
     WEBIDL_FILES += [
+        'MozSpeakerManager.webidl',
         'MozWifiConnectionInfoEvent.webidl',
         'MozWifiStatusChangeEvent.webidl',
     ]
 
 if CONFIG['MOZ_WEBSPEECH']:
     WEBIDL_FILES += [
         'SpeechRecognitionError.webidl',
         'SpeechRecognitionEvent.webidl',
--- a/hal/gonk/GonkFMRadio.cpp
+++ b/hal/gonk/GonkFMRadio.cpp
@@ -31,18 +31,18 @@ namespace mozilla {
 namespace hal_impl {
 
 uint32_t GetFMRadioFrequency();
 
 static int sRadioFD;
 static bool sRadioEnabled;
 static pthread_t sRadioThread;
 static hal::FMRadioSettings sRadioSettings;
-static int sTavaruaVersion;
-static bool sTavaruaMode;
+static int sMsmFMVersion;
+static bool sMsmFMMode;
 
 static int
 setControl(uint32_t id, int32_t value)
 {
   struct v4l2_control control;
   control.id = id;
   control.value = value;
   return ioctl(sRadioFD, VIDIOC_S_CTRL, &control);
@@ -64,22 +64,22 @@ public:
     info.frequency() = GetFMRadioFrequency();
     hal::NotifyFMRadioStatus(info);
     return NS_OK;
   }
 };
 
 /* Runs on the radio thread */
 static void
-initTavaruaRadio(hal::FMRadioSettings &aInfo)
+initMsmFMRadio(hal::FMRadioSettings &aInfo)
 {
   mozilla::ScopedClose fd(sRadioFD);
   char version[64];
   int rc;
-  snprintf(version, sizeof(version), "%d", sTavaruaVersion);
+  snprintf(version, sizeof(version), "%d", sMsmFMVersion);
   property_set("hw.fm.version", version);
 
   /* Set the mode for soc downloader */
   property_set("hw.fm.mode", "normal");
   /* start fm_dl service */
   property_set("ctl.start", "fm_dl");
 
   /*
@@ -194,19 +194,19 @@ initTavaruaRadio(hal::FMRadioSettings &a
   }
 
   fd.forget();
   sRadioEnabled = true;
 }
 
 /* Runs on the radio thread */
 static void *
-runTavaruaRadio(void *)
+runMsmFMRadio(void *)
 {
-  initTavaruaRadio(sRadioSettings);
+  initMsmFMRadio(sRadioSettings);
   if (!sRadioEnabled) {
     NS_DispatchToMainThread(new RadioUpdate(hal::FM_RADIO_OPERATION_ENABLE,
                                             hal::FM_RADIO_OPERATION_STATUS_FAIL));
     return nullptr;
   }
 
   uint8_t buf[128];
   struct v4l2_buffer buffer = {0};
@@ -270,34 +270,35 @@ EnableFMRadio(const hal::FMRadioSettings
 
   struct v4l2_capability cap;
   int rc = ioctl(fd, VIDIOC_QUERYCAP, &cap);
   if (rc < 0) {
     HAL_LOG(("Unable to query radio device"));
     return;
   }
 
-  sTavaruaMode = !strcmp((char *)cap.driver, "radio-tavarua");
+  sMsmFMMode = !strcmp((char *)cap.driver, "radio-tavarua") ||
+      !strcmp((char *)cap.driver, "radio-iris");
   HAL_LOG(("Radio: %s (%s)\n", cap.driver, cap.card));
 
   if (!(cap.capabilities & V4L2_CAP_RADIO)) {
     HAL_LOG(("/dev/radio0 isn't a radio"));
     return;
   }
 
   if (!(cap.capabilities & V4L2_CAP_TUNER)) {
     HAL_LOG(("/dev/radio0 doesn't support the tuner interface"));
     return;
   }
   sRadioSettings = aInfo;
 
-  if (sTavaruaMode) {
+  if (sMsmFMMode) {
     sRadioFD = fd.forget();
-    sTavaruaVersion = cap.version;
-    pthread_create(&sRadioThread, nullptr, runTavaruaRadio, nullptr);
+    sMsmFMVersion = cap.version;
+    pthread_create(&sRadioThread, nullptr, runMsmFMRadio, nullptr);
     return;
   }
 
   struct v4l2_tuner tuner = {0};
   tuner.type = V4L2_TUNER_RADIO;
   tuner.rangelow = (aInfo.lowerLimit() * 10000) / 625;
   tuner.rangehigh = (aInfo.upperLimit() * 10000) / 625;
   tuner.audmode = V4L2_TUNER_MODE_STEREO;
@@ -318,17 +319,17 @@ EnableFMRadio(const hal::FMRadioSettings
 void
 DisableFMRadio()
 {
   if (!sRadioEnabled)
     return;
 
   sRadioEnabled = false;
 
-  if (sTavaruaMode) {
+  if (sMsmFMMode) {
     int rc = setControl(V4L2_CID_PRIVATE_TAVARUA_STATE, FM_OFF);
     if (rc < 0) {
       HAL_LOG(("Unable to turn off radio"));
     }
 
     pthread_join(sRadioThread, nullptr);
   }
 
@@ -350,17 +351,17 @@ FMRadioSeek(const hal::FMRadioSeekDirect
   /* ICS and older don't have the spacing field */
 #if ANDROID_VERSION == 15
   seek.reserved[0] = sRadioSettings.spaceType() * 1000;
 #else
   seek.spacing = sRadioSettings.spaceType() * 1000;
 #endif
 
   int rc = ioctl(sRadioFD, VIDIOC_S_HW_FREQ_SEEK, &seek);
-  if (sTavaruaMode && rc >= 0)
+  if (sMsmFMMode && rc >= 0)
     return;
 
   hal::FMRadioOperationInformation info;
   info.operation() = hal::FM_RADIO_OPERATION_SEEK;
   info.status() = rc < 0 ? hal::FM_RADIO_OPERATION_STATUS_FAIL :
                            hal::FM_RADIO_OPERATION_STATUS_SUCCESS;
   hal::NotifyFMRadioStatus(info);
 
@@ -398,17 +399,17 @@ SetFMRadioFrequency(const uint32_t frequ
   struct v4l2_frequency freq = {0};
   freq.type = V4L2_TUNER_RADIO;
   freq.frequency = (frequency * 10000) / 625;
 
   int rc = ioctl(sRadioFD, VIDIOC_S_FREQUENCY, &freq);
   if (rc < 0)
     HAL_LOG(("Could not set radio frequency"));
 
-  if (sTavaruaMode && rc >= 0)
+  if (sMsmFMMode && rc >= 0)
     return;
 
   hal::FMRadioOperationInformation info;
   info.operation() = hal::FM_RADIO_OPERATION_TUNE;
   info.status() = rc < 0 ? hal::FM_RADIO_OPERATION_STATUS_FAIL :
                            hal::FM_RADIO_OPERATION_STATUS_SUCCESS;
   hal::NotifyFMRadioStatus(info);
 }
--- a/hal/gonk/GonkSensor.cpp
+++ b/hal/gonk/GonkSensor.cpp
@@ -181,16 +181,24 @@ PollSensors()
       break;
     }
 
     for (int i = 0; i < n; ++i) {
       // FIXME: bug 802004, add proper support for the magnetic field sensor.
       if (buffer[i].type == SENSOR_TYPE_MAGNETIC_FIELD)
         continue;
 
+      // Bug 938035, transfer HAL data for orientation sensor to meet w3c spec
+      // ex: HAL report alpha=90 means East but alpha=90 means West in w3c spec
+      if (buffer[i].type == SENSOR_TYPE_ORIENTATION) {
+        buffer[i].orientation.azimuth = 360 - buffer[i].orientation.azimuth;
+        buffer[i].orientation.pitch = -buffer[i].orientation.pitch;
+        buffer[i].orientation.roll = -buffer[i].orientation.roll;
+      }
+
       if (HardwareSensorToHalSensor(buffer[i].type) == SENSOR_UNKNOWN) {
         // Emulator is broken and gives us events without types set
         int index;
         for (index = 0; index < size; index++) {
           if (sensors[index].handle == buffer[i].sensor) {
             break;
           }
         }
--- a/layout/build/Makefile.in
+++ b/layout/build/Makefile.in
@@ -73,16 +73,17 @@ LOCAL_INCLUDES	+= -I$(srcdir)/../base \
 		   -I$(topsrcdir)/dom/src/json \
 		   -I$(topsrcdir)/dom/src/jsurl \
 		   -I$(topsrcdir)/dom/src/storage \
 		   -I$(topsrcdir)/dom/src/offline \
 		   -I$(topsrcdir)/dom/src/geolocation \
 		   -I$(topsrcdir)/dom/audiochannel \
 		   -I$(topsrcdir)/dom/telephony \
 		   -I$(topsrcdir)/dom/media \
+		   -I$(topsrcdir)/dom/speakermanager \
 		   -I. \
 		   -I$(topsrcdir)/editor/libeditor/base \
 		   -I$(topsrcdir)/editor/libeditor/text \
 		   -I$(topsrcdir)/editor/libeditor/html \
 		   -I$(topsrcdir)/editor/txmgr/src \
 		   -I$(topsrcdir)/editor/txtsvc/src \
 		   -I$(topsrcdir)/editor/composer/src \
 		   -I$(topsrcdir)/js/xpconnect/src \
@@ -95,16 +96,17 @@ LOCAL_INCLUDES	+= -I$(srcdir)/../base \
 		   $(NULL)
 
 ifdef MOZ_GSTREAMER
 LOCAL_INCLUDES	+= $(GSTREAMER_CFLAGS)
 endif
 
 ifeq (gonk,$(MOZ_WIDGET_TOOLKIT))
 LOCAL_INCLUDES	+= -I$(topsrcdir)/dom/system/gonk
+LOCAL_INCLUDES	+= -I$(topsrcdir)/dom/speakermanager
 endif #}
 
 ifdef MOZ_B2G_FM #{
 LOCAL_INCLUDES	+= -I$(topsrcdir)/dom/fmradio
 endif #}
 
 ifdef MOZ_B2G_BT #{
 LOCAL_INCLUDES	+= -I$(topsrcdir)/dom/bluetooth
--- a/layout/build/nsLayoutStatics.cpp
+++ b/layout/build/nsLayoutStatics.cpp
@@ -95,16 +95,17 @@
 #endif
 
 #include "AudioStream.h"
 #include "Latency.h"
 #include "WebAudioUtils.h"
 
 #ifdef MOZ_WIDGET_GONK
 #include "nsVolumeService.h"
+#include "SpeakerManagerService.h"
 using namespace mozilla::system;
 #endif
 
 #include "nsError.h"
 
 #include "nsJSEnvironment.h"
 #include "nsContentSink.h"
 #include "nsFrameMessageManager.h"
@@ -367,16 +368,17 @@ nsLayoutStatics::Shutdown()
   WebAudioUtils::Shutdown();
 
 #ifdef MOZ_WMF
   WMFDecoder::UnloadDLLs();
 #endif
 
 #ifdef MOZ_WIDGET_GONK
   nsVolumeService::Shutdown();
+  SpeakerManagerService::Shutdown();
 #endif
 
 #ifdef MOZ_WEBSPEECH
   nsSynthVoiceRegistry::Shutdown();
 #endif
 
   nsCORSListenerProxy::Shutdown();
 
--- a/widget/BasicEvents.h
+++ b/widget/BasicEvents.h
@@ -455,16 +455,20 @@ enum nsEventStructType
 #define NS_NETWORK_DOWNLOAD_EVENT    (NS_NETWORK_EVENT_START + 2)
 
 // MediaRecorder events.
 #define NS_MEDIARECORDER_EVENT_START 5700
 #define NS_MEDIARECORDER_DATAAVAILABLE  (NS_MEDIARECORDER_EVENT_START + 1)
 #define NS_MEDIARECORDER_WARNING        (NS_MEDIARECORDER_EVENT_START + 2)
 #define NS_MEDIARECORDER_STOP           (NS_MEDIARECORDER_EVENT_START + 3)
 
+// SpeakerManager events
+#define NS_SPEAKERMANAGER_EVENT_START 5800
+#define NS_SPEAKERMANAGER_SPEAKERFORCEDCHANGE (NS_SPEAKERMANAGER_EVENT_START + 1)
+
 #ifdef MOZ_GAMEPAD
 // Gamepad input events
 #define NS_GAMEPAD_START         6000
 #define NS_GAMEPAD_BUTTONDOWN    (NS_GAMEPAD_START)
 #define NS_GAMEPAD_BUTTONUP      (NS_GAMEPAD_START+1)
 #define NS_GAMEPAD_AXISMOVE      (NS_GAMEPAD_START+2)
 #define NS_GAMEPAD_CONNECTED     (NS_GAMEPAD_START+3)
 #define NS_GAMEPAD_DISCONNECTED  (NS_GAMEPAD_START+4)
--- a/widget/android/nsAppShell.cpp
+++ b/widget/android/nsAppShell.cpp
@@ -307,17 +307,24 @@ nsAppShell::ProcessNextNativeEvent(bool 
         break;
 
     case AndroidGeckoEvent::SENSOR_EVENT:
       {
         InfallibleTArray<float> values;
         mozilla::hal::SensorType type = (mozilla::hal::SensorType) curEvent->Flags();
 
         switch (type) {
+          // Bug 938035, transfer HAL data for orientation sensor to meet w3c
+          // spec, ex: HAL report alpha=90 means East but alpha=90 means West
+          // in w3c spec
           case hal::SENSOR_ORIENTATION:
+            values.AppendElement(360 -curEvent->X());
+            values.AppendElement(-curEvent->Y()); 
+            values.AppendElement(-curEvent->Z());
+            break;
           case hal::SENSOR_LINEAR_ACCELERATION:
           case hal::SENSOR_ACCELERATION:
           case hal::SENSOR_GYROSCOPE:
           case hal::SENSOR_PROXIMITY:
             values.AppendElement(curEvent->X());
             values.AppendElement(curEvent->Y()); 
             values.AppendElement(curEvent->Z());
             break;